commit f23e97c10cd292f3727dc70caa7e9a643138af8b Author: crypro.zoidberg Date: Thu Dec 27 18:50:45 2018 +0300 Moved sources to public repo diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..6afd357c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +.git* export-ignore +/CMakeLists.txt export-subst \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..bf6dbac1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +/build* +/tags +.DS_Store +._.DS_Store +Thumbs.db +._* diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..ab48b4c6 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,216 @@ +cmake_minimum_required(VERSION 2.8.6) + +PROJECT(Zano) + + +set(VERSION "1.0") + + if(POLICY CMP0043) + cmake_policy(SET CMP0043 OLD) + endif() + + if(POLICY CMP0020) + cmake_policy(SET CMP0020 OLD) + endif() + + +set_property(GLOBAL PROPERTY USE_FOLDERS ON) +set(CMAKE_CONFIGURATION_TYPES "Debug;Release") +#set(CMAKE_BUILD_TYPE "Debug") + +enable_testing() + + +if(APPLE) + set(CMAKE_OSX_DEPLOYMENT_TARGET 10.10.5) +endif() + +set(USE_PCH FALSE CACHE BOOL "Use shared precompiled headers for MSVC") + +include_directories(src contrib/eos_portable_archive contrib/db/liblmdb contrib contrib/epee/include "${CMAKE_BINARY_DIR}/version" "${CMAKE_BINARY_DIR}/contrib/zlib") +add_definitions(-DSTATICLIB) + +set(TESTNET FALSE CACHE BOOL "Compile for testnet") +if(TESTNET) + message("!!!!!! NOTICE: Project is building for TESTNET !!!!!!") + add_definitions(-DTESTNET) +endif() + +set(BUILD_GUI FALSE CACHE BOOL "Build qt-daemon") +set(USE_OPENCL FALSE CACHE BOOL "Build with opencl miner") + + +set(STATIC ${MSVC} CACHE BOOL "Link libraries statically") +if (UNIX AND NOT APPLE) + # Note that at the time of this writing the -Wstrict-prototypes flag added below will make this fail + find_package(Threads REQUIRED) +endif() + + +if(MSVC) + add_definitions("/bigobj /Zm1000 /Z7 /MP /W3 /GS- /D_CRT_SECURE_NO_WARNINGS /wd4996 /wd4503 /wd4345 /wd4091 /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0 /FIinline_c.h /D__SSE4_1__") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:10485760 /DEBUG dbghelp.lib") + if(STATIC) + foreach(VAR CMAKE_C_FLAGS_DEBUG CMAKE_CXX_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE) + string(REPLACE "/MD" "/MT" ${VAR} "${${VAR}}") + endforeach() + endif() + include_directories(SYSTEM src/platform/msc) +else() + set(ARCH default CACHE STRING "CPU to build for: -march value or default") + if("${ARCH}" STREQUAL "default") + set(ARCH_FLAG "") + else() + set(ARCH_FLAG "-march=${ARCH}") + endif() + set(WARNINGS "-Wall -Wextra -Wpointer-arith -Wvla -Wwrite-strings -Wno-error=extra -Wno-error=deprecated-declarations -Wno-error=sign-compare -Wno-error=strict-aliasing -Wno-error=type-limits -Wno-unused-parameter -Wno-error=unused-variable -Wno-aggregate-return") +# if(NOT APPLE) +# set(WARNINGS "${WARNINGS} -Werror") +# endif() + + if(CMAKE_C_COMPILER_ID STREQUAL "Clang") + set(WARNINGS "${WARNINGS} -Wno-shift-count-overflow -Wno-error=mismatched-tags -Wno-error=null-conversion -Wno-overloaded-shift-op-parentheses -Wno-error=shift-count-overflow -Wno-error=tautological-constant-out-of-range-compare -Wno-error=unused-private-field -Wno-error=unneeded-internal-declaration") + else() + set(WARNINGS "${WARNINGS} -Wno-error=write-strings -Wlogical-op -Wno-error=maybe-uninitialized") + endif() + + # Since gcc 4.9 the LTO format is non-standard (slim), so we need the gcc-specific ar and ranlib binaries + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9.0)) + set(CMAKE_AR "gcc-ar") + set(CMAKE_RANLIB "gcc-ranlib") + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT APPLE) + set(CMAKE_AR "llvm-ar") + set(CMAKE_RANLIB "llvm-ranlib") + endif() + + + if(MINGW) + set(WARNINGS "${WARNINGS} -Wno-error=unused-value") + set(MINGW_FLAG "-DWIN32_LEAN_AND_MEAN") + include_directories(SYSTEM src/platform/mingw) + else() + set(MINGW_FLAG "") + endif() + if(APPLE) + set(APPLE_FLAG "-DGTEST_USE_OWN_TR1_TUPLE=1") + else() + set(APPLE_FLAG "") + endif() + set(C_WARNINGS "-Waggregate-return -Wnested-externs -Wstrict-prototypes") + set(CXX_WARNINGS "-Wno-reorder -Wno-missing-field-initializers") + try_compile(STATIC_ASSERT_RES "${CMAKE_CURRENT_BINARY_DIR}/static-assert" "${CMAKE_CURRENT_SOURCE_DIR}/utils/test-static-assert.c" COMPILE_DEFINITIONS "-std=c11") + if(STATIC_ASSERT_RES) + set(STATIC_ASSERT_FLAG "") + else() + set(STATIC_ASSERT_FLAG "-Dstatic_assert=_Static_assert") + endif() + set(LINUX_LD_GOLD "") + set(LINUX_STATIC_ICU "") + if((NOT APPLE) AND (NOT MSVC)) + set(LINUX_LD_GOLD "-fuse-ld=gold") + endif() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${LINUX_LD_GOLD} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${ARCH_FLAG}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LINUX_LD_GOLD} -fpermissive -ftemplate-depth-1024 -std=c++11 -D_GNU_SOURCE ${APPLE_FLAG} ${MINGW_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG}") + if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT (CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8)) + set(DEBUG_FLAGS "-g3 -O0") #set(DEBUG_FLAGS "-g3 -Og") + else() + set(DEBUG_FLAGS "-g3 -O0") + endif() + set(RELEASE_FLAGS "-Ofast -DNDEBUG -Wno-unused-variable") + if(NOT APPLE) + set(RELEASE_FLAGS "${RELEASE_FLAGS} -flto") + endif() + #if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT MINGW) + # set(RELEASE_FLAGS "${RELEASE_FLAGS} -fno-fat-lto-objects") + #endif() + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${DEBUG_FLAGS}") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEBUG_FLAGS}") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${RELEASE_FLAGS}") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${RELEASE_FLAGS}") + if(STATIC) + if(APPLE) + message(SEND_ERROR "Static build is not supported on MacOS X") + else() + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++") + endif() + endif() +endif() + + +if(MSVC) + set(Boost_USE_STATIC_LIBS ON) +endif() + +if(STATIC) + set(Boost_USE_STATIC_LIBS ON) + set(Boost_USE_STATIC_RUNTIME ON) +endif() +find_package(Boost 1.53 REQUIRED COMPONENTS system filesystem thread date_time chrono regex serialization atomic program_options locale) +if(MSVC AND (${Boost_MAJOR_VERSION} EQUAL 1) AND (${Boost_MINOR_VERSION} EQUAL 54)) + message(SEND_ERROR "Boost version 1.54 is unsupported, more details are available here http://goo.gl/RrCFmA") +endif() + +message(STATUS "Boost: ${Boost_VERSION} from ${Boost_LIBRARY_DIRS}") + + +include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) +if(MINGW) + set(Boost_LIBRARIES "${Boost_LIBRARIES};ws2_32;mswsock") +elseif(NOT MSVC) + if(NOT APPLE) + set(Boost_LIBRARIES "${Boost_LIBRARIES};rt") + if(STATIC) + message("NOTICE: Including static ICU libraries") + set(Boost_LIBRARIES "${Boost_LIBRARIES};icui18n.a;icuuc.a;icudata.a;dl") + endif() + endif() +endif() + +if(BUILD_GUI) + cmake_minimum_required(VERSION 2.8.11) + find_package(Qt5Widgets REQUIRED) +endif() + +if(USE_OPENCL) + find_package( OpenCL ) + if(NOT OpenCL_FOUND) + # add some Opencl + endif() + + include_directories( ${OpenCL_INCLUDE_DIRS} ) + include_directories( ${OpenCL_INCLUDE_DIR} ) + add_definitions(-DUSE_OPENCL) +endif() + + +set(COMMIT_ID_IN_VERSION ON CACHE BOOL "Include commit ID in version") +file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/version") +if (NOT COMMIT_ID_IN_VERSION) + set(VERSION "${VERSION}-unknown") + configure_file("src/version.h.in" "version/version.h") + add_custom_target(version ALL) +elseif(DEFINED COMMIT) + string(REPLACE "." "\\." VERSION_RE "${VERSION}") + if(NOT REFS MATCHES "(\\(|, )tag: v${VERSION_RE}(\\)|, )") + set(VERSION "${VERSION}-g${COMMIT}") + endif() + configure_file("src/version.h.in" "version/version.h") + add_custom_target(version ALL) +else() + find_package(Git QUIET) + if(Git_FOUND OR GIT_FOUND) + message(STATUS "Found Git: ${GIT_EXECUTABLE}") + add_custom_target(version ALL "${CMAKE_COMMAND}" "-D" "VERSION=${VERSION}" "-D" "GIT=${GIT_EXECUTABLE}" "-D" "TO=${CMAKE_BINARY_DIR}/version/version.h" "-P" "src/version.cmake" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}") + else() + message(STATUS "WARNING: Git was not found!") + set(VERSION "${VERSION}-unknown") + configure_file("src/version.h.in" "version/version.h") + add_custom_target(version ALL) + endif() +endif() + + +add_subdirectory(contrib) +add_subdirectory(src) +add_subdirectory(tests) + diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..451319b0 --- /dev/null +++ b/Makefile @@ -0,0 +1,33 @@ +all: all-release + +cmake-debug: + mkdir -p build/debug + cd build/debug && cmake -D CMAKE_BUILD_TYPE=Debug ../.. + +build-debug: cmake-debug + cd build/debug && $(MAKE) + +test-debug: build-debug + cd build/debug && $(MAKE) test + +all-debug: build-debug + +cmake-release: + mkdir -p build/release + cd build/release && cmake -D CMAKE_BUILD_TYPE=Release ../.. + +build-release: cmake-release + cd build/release && $(MAKE) + +test-release: build-release + cd build/release && $(MAKE) test + +all-release: build-release + +clean: + rm -rf build + +tags: + ctags -R --sort=1 --c++-kinds=+p --fields=+iaS --extra=+q --language-force=C++ src contrib tests/gtest + +.PHONY: all cmake-debug build-debug test-debug all-debug cmake-release build-release test-release all-release clean tags diff --git a/README.md b/README.md new file mode 100644 index 00000000..ee524731 --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +Building +-------- + +### Dependencies +| component / version | minimum
(not recommended but may work) | recommended | most recent of what we have ever tested | +|--|--|--|--| +| gcc (Linux) | 5.4.0 | 7.2.0 | 7.2.0 | +| [MSVC](https://visualstudio.microsoft.com/downloads/) (Windows) | 2015 (14.0 update 1) | 2015 (14.0 update 3) | 2017 (15.5.7) | +| [XCode](https://developer.apple.com/downloads/) (macOS) | 7.3.1 | 9.2 | 9.2 | +| [CMake](https://cmake.org/download/) | 2.8.6 | 3.4.1 | 3.11.0 | +| [Boost](https://www.boost.org/users/download/) | 1.56 | 1.60 | 1.66 | +| [Qt](https://download.qt.io/archive/qt/) (only for GUI) | 5.8.0 | 5.9.1 | 5.10.1 | + +### Linux +Recommended OS version: Ubuntu 17.04 LTS. + 1. Install dependencies: `sudo apt-get install build-essential git cmake unzip libicu-dev ocl-icd-opencl-dev mesa-common-dev libglu1-mesa-dev` + 2. Install Qt and Boost + 3. Set `BOOST_ROOT` and `QT_PREFIX_PATH` environment variables + 4. `mkdir build`
`cd build`
`cmake -DBUILD_GUI=FALSE -DSTATIC=TRUE ..`
`make` +5. In order to build GUI, revise and run script at `/utils/build_script_linux.sh` + +### Windows +Recommended OS version: Windows 7 x64. +1. Install required prerequisites. +2. Edit paths in `utils/configure_local_paths.cmd`. +3. Run `utils/configure_win64_msvs2015_gui.cmd` or `utils/configure_win64_msvs2017_gui.cmd` according to your MSVC version. +4. Go to the build folder and open generated Zano.sln in MSVC. +5. Build. + +In order to correctly deploy Qt GUI application you also need to do the following: +6. Copy Zano.exe to a folder (e.g. `depoy`). +7. Run `PATH_TO_QT\bin\windeployqt.exe deploy/Zano.exe`. +8. Copy folder `\src\gui\qt-daemon\html` to `deploy\html`. + +### macOS +Recommended OS version: macOS Sierra 10.12.6 x64. +1. Install required prerequisites. +2. Set environment variables as stated in `utils/macosx_build_config.command`. +3. `mkdir build`
`cd build`
`cmake ..`
`make` + +To build GUI application: + +1. Create self-signing certificate via Keychain Access: + a. Run Keychain Access. + b. Choose Keychain Access > Certificate Assistant > Create a Certificate. + c. Use “Zano” (without quotes) as certificate name. + d. Choose “Code Signing” in “Certificate Type” field. + e. Press “Create”, then “Done”. + f. Make sure the certificate was added to keychain "System". If not—move it to "System". + g. Double click the certificate you've just added, enter the trust section and under "When using this certificate" select "Always trust". + h. Unfold the certificate in Keychain Access window and double click underlying private key "Zano". Select "Access Control" tab, then select "Allow all applications to access this item". Click "Save Changes". +2. Revise building script, comment out unwanted steps and run it: `utils/build_script_mac_osx.sh` +3. The application should be here: `/buid_mac_osx_64/release/src` + + +Good luck! diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt new file mode 100644 index 00000000..46ed7497 --- /dev/null +++ b/contrib/CMakeLists.txt @@ -0,0 +1,20 @@ +set(UPNPC_BUILD_STATIC ON CACHE BOOL "Build static library") +set(UPNPC_BUILD_SHARED OFF CACHE BOOL "Build shared library") +set(UPNPC_BUILD_TESTS OFF CACHE BOOL "Build test executables") +add_subdirectory(miniupnpc) +add_subdirectory(zlib) +add_subdirectory(db) + + + +set_property(TARGET upnpc-static PROPERTY FOLDER "contrib") +set_property(TARGET zlibstatic PROPERTY FOLDER "contrib") +set_property(TARGET lmdb PROPERTY FOLDER "contrib") + + + +if(MSVC) + set_property(TARGET upnpc-static APPEND_STRING PROPERTY COMPILE_FLAGS " -wd4244 -wd4267") +else() + set_property(TARGET upnpc-static APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-undef -Wno-unused-result -Wno-unused-value") +endif() diff --git a/contrib/db/CMakeLists.txt b/contrib/db/CMakeLists.txt new file mode 100644 index 00000000..bdd4381b --- /dev/null +++ b/contrib/db/CMakeLists.txt @@ -0,0 +1,7 @@ +add_subdirectory(liblmdb) +if(MSVC) + target_compile_options(lmdb PRIVATE /wd4996 /wd4503 /wd4345 /wd4267 /wd4244 /wd4146 /wd4333 /wd4172) +else() + target_compile_options(lmdb PRIVATE -Wno-discarded-qualifiers -Wno-empty-body -Wno-unused-but-set-variable) +endif() + diff --git a/contrib/db/liblmdb/.gitignore b/contrib/db/liblmdb/.gitignore new file mode 100644 index 00000000..d5102a87 --- /dev/null +++ b/contrib/db/liblmdb/.gitignore @@ -0,0 +1,23 @@ +mtest +mtest[23456] +testdb +mdb_copy +mdb_stat +mdb_dump +mdb_load +*.lo +*.[ao] +*.so +*.exe +*[~#] +*.bak +*.orig +*.rej +*.gcov +*.gcda +*.gcno +core +core.* +valgrind.* +man/ +html/ diff --git a/contrib/db/liblmdb/CHANGES b/contrib/db/liblmdb/CHANGES new file mode 100644 index 00000000..aabb1adf --- /dev/null +++ b/contrib/db/liblmdb/CHANGES @@ -0,0 +1,192 @@ +LMDB 0.9 Change Log + +LMDB 0.9.18 Release Engineering + Fix robust mutex detection on glibc 2.10-11 (ITS#8330) + Check for utf8_to_utf16 failures (ITS#7992) + Catch strdup failure in mdb_dbi_open + Build + Additional makefile var tweaks (ITS#8169) + Documentation + Add Getting Started page + + +LMDB 0.9.17 Release (2015/11/30) + Fix ITS#7377 catch calloc failure + Fix ITS#8237 regression from ITS#7589 + Fix ITS#8238 page_split for DUPFIXED pages + Fix ITS#8221 MDB_PAGE_FULL on delete/rebalance + Fix ITS#8258 rebalance/split assert + Fix ITS#8263 cursor_put cursor tracking + Fix ITS#8264 cursor_del cursor tracking + Fix ITS#8310 cursor_del cursor tracking + Fix ITS#8299 mdb_del cursor tracking + Fix ITS#8300 mdb_del cursor tracking + Fix ITS#8304 mdb_del cursor tracking + Fix ITS#7771 fakepage cursor tracking + Fix ITS#7789 ensure mapsize >= pages in use + Fix ITS#7971 mdb_txn_renew0() new reader slots + Fix ITS#7969 use __sync_synchronize on non-x86 + Fix ITS#8311 page_split from update_key + Fix ITS#8312 loose pages in nested txn + Fix ITS#8313 mdb_rebalance dummy cursor + Fix ITS#8315 dirty_room in nested txn + Fix ITS#8323 dirty_list in nested txn + Fix ITS#8316 page_merge cursor tracking + Fix ITS#8321 cursor tracking + Fix ITS#8319 mdb_load error messages + Fix ITS#8320 mdb_load plaintext input + Added mdb_txn_id() (ITS#7994) + Added robust mutex support + Miscellaneous cleanup/simplification + Build + Create install dirs if needed (ITS#8256) + Fix ThreadProc decl on Win32/MSVC (ITS#8270) + Added ssize_t typedef for MSVC (ITS#8067) + Use ANSI apis on Windows (ITS#8069) + Use O_SYNC if O_DSYNC,MDB_DSYNC are not defined (ITS#7209) + Allow passing AR to make (ITS#8168) + Allow passing mandir to make install (ITS#8169) + +LMDB 0.9.16 Release (2015/08/14) + Fix cursor EOF bug (ITS#8190) + Fix handling of subDB records (ITS#8181) + Fix mdb_midl_shrink() usage (ITS#8200) + +LMDB 0.9.15 Release (2015/06/19) + Fix txn init (ITS#7961,#7987) + Fix MDB_PREV_DUP (ITS#7955,#7671) + Fix compact of empty env (ITS#7956) + Fix mdb_copy file mode + Fix mdb_env_close() after failed mdb_env_open() + Fix mdb_rebalance collapsing root (ITS#8062) + Fix mdb_load with large values (ITS#8066) + Fix to retry writes on EINTR (ITS#8106) + Fix mdb_cursor_del on empty DB (ITS#8109) + Fix MDB_INTEGERDUP key compare (ITS#8117) + Fix error handling (ITS#7959,#8157,etc.) + Fix race conditions (ITS#7969,7970) + Added workaround for fdatasync bug in ext3fs + Build + Don't use -fPIC for static lib + Update .gitignore (ITS#7952,#7953) + Cleanup for "make test" (ITS#7841), "make clean", mtest*.c + Misc. Android/Windows cleanup + Documentation + Fix MDB_APPEND doc + Fix MDB_MAXKEYSIZE doc (ITS#8156) + Fix mdb_cursor_put,mdb_cursor_del EACCES description + Fix mdb_env_sync(MDB_RDONLY env) doc (ITS#8021) + Clarify MDB_WRITEMAP doc (ITS#8021) + Clarify mdb_env_open doc + Clarify mdb_dbi_open doc + +LMDB 0.9.14 Release (2014/09/20) + Fix to support 64K page size (ITS#7713) + Fix to persist decreased as well as increased mapsizes (ITS#7789) + Fix cursor bug when deleting last node of a DUPSORT key + Fix mdb_env_info to return FIXEDMAP address + Fix ambiguous error code from writing to closed DBI (ITS#7825) + Fix mdb_copy copying past end of file (ITS#7886) + Fix cursor bugs from page_merge/rebalance + Fix to dirty fewer pages in deletes (mdb_page_loose()) + Fix mdb_dbi_open creating subDBs (ITS#7917) + Fix mdb_cursor_get(_DUP) with single value (ITS#7913) + Fix Windows compat issues in mtests (ITS#7879) + Add compacting variant of mdb_copy + Add BigEndian integer key compare code + Add mdb_dump/mdb_load utilities + +LMDB 0.9.13 Release (2014/06/18) + Fix mdb_page_alloc unlimited overflow page search + Documentation + Re-fix MDB_CURRENT doc (ITS#7793) + Fix MDB_GET_MULTIPLE/MDB_NEXT_MULTIPLE doc + +LMDB 0.9.12 Release (2014/06/13) + Fix MDB_GET_BOTH regression (ITS#7875,#7681) + Fix MDB_MULTIPLE writing multiple keys (ITS#7834) + Fix mdb_rebalance (ITS#7829) + Fix mdb_page_split (ITS#7815) + Fix md_entries count (ITS#7861,#7828,#7793) + Fix MDB_CURRENT (ITS#7793) + Fix possible crash on Windows DLL detach + Misc code cleanup + Documentation + mdb_cursor_put: cursor moves on error (ITS#7771) + + +LMDB 0.9.11 Release (2014/01/15) + Add mdb_env_set_assert() (ITS#7775) + Fix: invalidate txn on page allocation errors (ITS#7377) + Fix xcursor tracking in mdb_cursor_del0() (ITS#7771) + Fix corruption from deletes (ITS#7756) + Fix Windows/MSVC build issues + Raise safe limit of max MDB_MAXKEYSIZE + Misc code cleanup + Documentation + Remove spurious note about non-overlapping flags (ITS#7665) + +LMDB 0.9.10 Release (2013/11/12) + Add MDB_NOMEMINIT option + Fix mdb_page_split() again (ITS#7589) + Fix MDB_NORDAHEAD definition (ITS#7734) + Fix mdb_cursor_del() positioning (ITS#7733) + Partial fix for larger page sizes (ITS#7713) + Fix Windows64/MSVC build issues + +LMDB 0.9.9 Release (2013/10/24) + Add mdb_env_get_fd() + Add MDB_NORDAHEAD option + Add MDB_NOLOCK option + Avoid wasting space in mdb_page_split() (ITS#7589) + Fix mdb_page_merge() cursor fixup (ITS#7722) + Fix mdb_cursor_del() on last delete (ITS#7718) + Fix adding WRITEMAP on existing env (ITS#7715) + Fix nested txns (ITS#7515) + Fix mdb_env_copy() O_DIRECT bug (ITS#7682) + Fix mdb_cursor_set(SET_RANGE) return code (ITS#7681) + Fix mdb_rebalance() cursor fixup (ITS#7701) + Misc code cleanup + Documentation + Note that by default, readers need write access + + +LMDB 0.9.8 Release (2013/09/09) + Allow mdb_env_set_mapsize() on an open environment + Fix mdb_dbi_flags() (ITS#7672) + Fix mdb_page_unspill() in nested txns + Fix mdb_cursor_get(CURRENT|NEXT) after a delete + Fix mdb_cursor_get(DUP) to always return key (ITS#7671) + Fix mdb_cursor_del() to always advance to next item (ITS#7670) + Fix mdb_cursor_set(SET_RANGE) for tree with single page (ITS#7681) + Fix mdb_env_copy() retry open if O_DIRECT fails (ITS#7682) + Tweak mdb_page_spill() to be less aggressive + Documentation + Update caveats since mdb_reader_check() added in 0.9.7 + +LMDB 0.9.7 Release (2013/08/17) + Don't leave stale lockfile on failed RDONLY open (ITS#7664) + Fix mdb_page_split() ref beyond cursor depth + Fix read txn data race (ITS#7635) + Fix mdb_rebalance (ITS#7536, #7538) + Fix mdb_drop() (ITS#7561) + Misc DEBUG macro fixes + Add MDB_NOTLS envflag + Add mdb_env_copyfd() + Add mdb_txn_env() (ITS#7660) + Add mdb_dbi_flags() (ITS#7661) + Add mdb_env_get_maxkeysize() + Add mdb_env_reader_list()/mdb_env_reader_check() + Add mdb_page_spill/unspill, remove hard txn size limit + Use shorter names for semaphores (ITS#7615) + Build + Fix install target (ITS#7656) + Documentation + Misc updates for cursors, DB handles, data lifetime + +LMDB 0.9.6 Release (2013/02/25) + Many fixes/enhancements + +LMDB 0.9.5 Release (2012/11/30) + Renamed from libmdb to liblmdb + Many fixes/enhancements diff --git a/contrib/db/liblmdb/CMakeLists.txt b/contrib/db/liblmdb/CMakeLists.txt new file mode 100644 index 00000000..4a60e07c --- /dev/null +++ b/contrib/db/liblmdb/CMakeLists.txt @@ -0,0 +1,19 @@ + +set (lmdb_sources mdb.c midl.c) + +include_directories("${CMAKE_CURRENT_SOURCE_DIR}") + +if(NOT MSVC) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-missing-field-initializers -Wno-missing-braces -Wno-aggregate-return") +endif() +if(FREEBSD) + add_definitions(-DMDB_DSYNC=O_SYNC) +endif() + +add_library(lmdb ${lmdb_sources}) + +target_link_libraries(lmdb PRIVATE ${CMAKE_THREAD_LIBS_INIT}) + +if(WIN32) + target_link_libraries(lmdb ntdll) +endif() diff --git a/contrib/db/liblmdb/COPYRIGHT b/contrib/db/liblmdb/COPYRIGHT new file mode 100644 index 00000000..722d1a51 --- /dev/null +++ b/contrib/db/liblmdb/COPYRIGHT @@ -0,0 +1,20 @@ +Copyright 2011-2015 Howard Chu, Symas Corp. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + +A copy of this license is available in the file LICENSE in the +top-level directory of the distribution or, alternatively, at +. + +OpenLDAP is a registered trademark of the OpenLDAP Foundation. + +Individual files and/or contributed packages may be copyright by +other parties and/or subject to additional restrictions. + +This work also contains materials derived from public sources. + +Additional information about OpenLDAP can be obtained at +. diff --git a/contrib/db/liblmdb/Doxyfile b/contrib/db/liblmdb/Doxyfile new file mode 100644 index 00000000..5047c0bb --- /dev/null +++ b/contrib/db/liblmdb/Doxyfile @@ -0,0 +1,1631 @@ +# Doxyfile 1.7.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = LMDB + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +INLINE_GROUPED_CLASSES = YES +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = YES + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = NO + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = lmdb.h midl.h mdb.c midl.c intro.doc + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the stylesheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvances is that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = YES + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = DEBUG=2 __GNUC__=1 + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = tooltag=./man1 + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans.ttf + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/contrib/db/liblmdb/LICENSE b/contrib/db/liblmdb/LICENSE new file mode 100644 index 00000000..05ad7571 --- /dev/null +++ b/contrib/db/liblmdb/LICENSE @@ -0,0 +1,47 @@ +The OpenLDAP Public License + Version 2.8, 17 August 2003 + +Redistribution and use of this software and associated documentation +("Software"), with or without modification, are permitted provided +that the following conditions are met: + +1. Redistributions in source form must retain copyright statements + and notices, + +2. Redistributions in binary form must reproduce applicable copyright + statements and notices, this list of conditions, and the following + disclaimer in the documentation and/or other materials provided + with the distribution, and + +3. Redistributions must contain a verbatim copy of this document. + +The OpenLDAP Foundation may revise this license from time to time. +Each revision is distinguished by a version number. You may use +this Software under terms of this license revision or under the +terms of any subsequent revision of the license. + +THIS SOFTWARE IS PROVIDED BY THE OPENLDAP FOUNDATION AND ITS +CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE OPENLDAP FOUNDATION, ITS CONTRIBUTORS, OR THE AUTHOR(S) +OR OWNER(S) OF THE SOFTWARE 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 names of the authors and copyright holders must not be used in +advertising or otherwise to promote the sale, use or other dealing +in this Software without specific, written prior permission. Title +to copyright in this Software shall at all times remain with copyright +holders. + +OpenLDAP is a registered trademark of the OpenLDAP Foundation. + +Copyright 1999-2003 The OpenLDAP Foundation, Redwood City, +California, USA. All Rights Reserved. Permission to copy and +distribute verbatim copies of this document is granted. diff --git a/contrib/db/liblmdb/Makefile b/contrib/db/liblmdb/Makefile new file mode 100644 index 00000000..f3c93a2f --- /dev/null +++ b/contrib/db/liblmdb/Makefile @@ -0,0 +1,116 @@ +# Makefile for liblmdb (Lightning memory-mapped database library). + +######################################################################## +# Configuration. The compiler options must enable threaded compilation. +# +# Preprocessor macros (for CPPFLAGS) of interest... +# Note that the defaults should already be correct for most +# platforms; you should not need to change any of these. +# Read their descriptions in mdb.c if you do: +# +# - MDB_USE_POSIX_MUTEX, MDB_USE_POSIX_SEM, MDB_USE_SYSV_SEM +# - MDB_DSYNC +# - MDB_FDATASYNC +# - MDB_FDATASYNC_WORKS +# - MDB_USE_PWRITEV +# - MDB_USE_ROBUST +# +# There may be other macros in mdb.c of interest. You should +# read mdb.c before changing any of them. +# +CC = gcc +AR = ar +W = -W -Wall -Wno-unused-parameter -Wbad-function-cast -Wuninitialized +THREADS = -pthread +OPT = -O2 -g +CFLAGS = $(THREADS) $(OPT) $(W) $(XCFLAGS) +LDLIBS = # -lntdll # Windows needs ntdll +SOLIBS = # -lntdll +prefix = /usr/local +exec_prefix = $(prefix) +bindir = $(exec_prefix)/bin +libdir = $(exec_prefix)/lib +includedir = $(prefix)/include +datarootdir = $(prefix)/share +mandir = $(datarootdir)/man + +######################################################################## + +IHDRS = lmdb.h +ILIBS = liblmdb.a liblmdb.so +IPROGS = mdb_stat mdb_copy mdb_dump mdb_load +IDOCS = mdb_stat.1 mdb_copy.1 mdb_dump.1 mdb_load.1 +PROGS = $(IPROGS) mtest mtest2 mtest3 mtest4 mtest5 +all: $(ILIBS) $(PROGS) + +install: $(ILIBS) $(IPROGS) $(IHDRS) + mkdir -p $(DESTDIR)$(bindir) + mkdir -p $(DESTDIR)$(libdir) + mkdir -p $(DESTDIR)$(includedir) + mkdir -p $(DESTDIR)$(mandir)/man1 + for f in $(IPROGS); do cp $$f $(DESTDIR)$(bindir); done + for f in $(ILIBS); do cp $$f $(DESTDIR)$(libdir); done + for f in $(IHDRS); do cp $$f $(DESTDIR)$(includedir); done + for f in $(IDOCS); do cp $$f $(DESTDIR)$(mandir)/man1; done + +clean: + rm -rf $(PROGS) *.[ao] *.[ls]o *~ testdb + +test: all + rm -rf testdb && mkdir testdb + ./mtest && ./mdb_stat testdb + +liblmdb.a: mdb.o midl.o + $(AR) rs $@ mdb.o midl.o + +liblmdb.so: mdb.lo midl.lo +# $(CC) $(LDFLAGS) -pthread -shared -Wl,-Bsymbolic -o $@ mdb.o midl.o $(SOLIBS) + $(CC) $(LDFLAGS) -pthread -shared -o $@ mdb.lo midl.lo $(SOLIBS) + +mdb_stat: mdb_stat.o liblmdb.a +mdb_copy: mdb_copy.o liblmdb.a +mdb_dump: mdb_dump.o liblmdb.a +mdb_load: mdb_load.o liblmdb.a +mtest: mtest.o liblmdb.a +mtest2: mtest2.o liblmdb.a +mtest3: mtest3.o liblmdb.a +mtest4: mtest4.o liblmdb.a +mtest5: mtest5.o liblmdb.a +mtest6: mtest6.o liblmdb.a + +mdb.o: mdb.c lmdb.h midl.h + $(CC) $(CFLAGS) $(CPPFLAGS) -c mdb.c + +midl.o: midl.c midl.h + $(CC) $(CFLAGS) $(CPPFLAGS) -c midl.c + +mdb.lo: mdb.c lmdb.h midl.h + $(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -c mdb.c -o $@ + +midl.lo: midl.c midl.h + $(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -c midl.c -o $@ + +%: %.o + $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@ + +%.o: %.c lmdb.h + $(CC) $(CFLAGS) $(CPPFLAGS) -c $< + +COV_FLAGS=-fprofile-arcs -ftest-coverage +COV_OBJS=xmdb.o xmidl.o + +coverage: xmtest + for i in mtest*.c [0-9]*.c; do j=`basename \$$i .c`; $(MAKE) $$j.o; \ + gcc -o x$$j $$j.o $(COV_OBJS) -pthread $(COV_FLAGS); \ + rm -rf testdb; mkdir testdb; ./x$$j; done + gcov xmdb.c + gcov xmidl.c + +xmtest: mtest.o xmdb.o xmidl.o + gcc -o xmtest mtest.o xmdb.o xmidl.o -pthread $(COV_FLAGS) + +xmdb.o: mdb.c lmdb.h midl.h + $(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -O0 $(COV_FLAGS) -c mdb.c -o $@ + +xmidl.o: midl.c midl.h + $(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -O0 $(COV_FLAGS) -c midl.c -o $@ diff --git a/contrib/db/liblmdb/intro.doc b/contrib/db/liblmdb/intro.doc new file mode 100644 index 00000000..870c7bb8 --- /dev/null +++ b/contrib/db/liblmdb/intro.doc @@ -0,0 +1,192 @@ +/* + * Copyright 2015 Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +/** @page starting Getting Started + +LMDB is compact, fast, powerful, and robust and implements a simplified +variant of the BerkeleyDB (BDB) API. (BDB is also very powerful, and verbosely +documented in its own right.) After reading this page, the main +\ref mdb documentation should make sense. Thanks to Bert Hubert +for creating the + +initial version of this writeup. + +Everything starts with an environment, created by #mdb_env_create(). +Once created, this environment must also be opened with #mdb_env_open(). + +#mdb_env_open() gets passed a name which is interpreted as a directory +path. Note that this directory must exist already, it is not created +for you. Within that directory, a lock file and a storage file will be +generated. If you don't want to use a directory, you can pass the +#MDB_NOSUBDIR option, in which case the path you provided is used +directly as the data file, and another file with a "-lock" suffix +added will be used for the lock file. + +Once the environment is open, a transaction can be created within it +using #mdb_txn_begin(). Transactions may be read-write or read-only, +and read-write transactions may be nested. A transaction must only +be used by one thread at a time. Transactions are always required, +even for read-only access. The transaction provides a consistent +view of the data. + +Once a transaction has been created, a database can be opened within it +using #mdb_dbi_open(). If only one database will ever be used in the +environment, a NULL can be passed as the database name. For named +databases, the #MDB_CREATE flag must be used to create the database +if it doesn't already exist. Also, #mdb_env_set_maxdbs() must be +called after #mdb_env_create() and before #mdb_env_open() to set the +maximum number of named databases you want to support. + +Note: a single transaction can open multiple databases. Generally +databases should only be opened once, by the first transaction in +the process. After the first transaction completes, the database +handles can freely be used by all subsequent transactions. + +Within a transaction, #mdb_get() and #mdb_put() can store single +key/value pairs if that is all you need to do (but see \ref Cursors +below if you want to do more). + +A key/value pair is expressed as two #MDB_val structures. This struct +has two fields, \c mv_size and \c mv_data. The data is a \c void pointer to +an array of \c mv_size bytes. + +Because LMDB is very efficient (and usually zero-copy), the data returned +in an #MDB_val structure may be memory-mapped straight from disk. In +other words look but do not touch (or free() for that matter). +Once a transaction is closed, the values can no longer be used, so +make a copy if you need to keep them after that. + +@section Cursors Cursors + +To do more powerful things, we must use a cursor. + +Within the transaction, a cursor can be created with #mdb_cursor_open(). +With this cursor we can store/retrieve/delete (multiple) values using +#mdb_cursor_get(), #mdb_cursor_put(), and #mdb_cursor_del(). + +#mdb_cursor_get() positions itself depending on the cursor operation +requested, and for some operations, on the supplied key. For example, +to list all key/value pairs in a database, use operation #MDB_FIRST for +the first call to #mdb_cursor_get(), and #MDB_NEXT on subsequent calls, +until the end is hit. + +To retrieve all keys starting from a specified key value, use #MDB_SET. +For more cursor operations, see the \ref mdb docs. + +When using #mdb_cursor_put(), either the function will position the +cursor for you based on the \b key, or you can use operation +#MDB_CURRENT to use the current position of the cursor. Note that +\b key must then match the current position's key. + +@subsection summary Summarizing the Opening + +So we have a cursor in a transaction which opened a database in an +environment which is opened from a filesystem after it was +separately created. + +Or, we create an environment, open it from a filesystem, create a +transaction within it, open a database within that transaction, +and create a cursor within all of the above. + +Got it? + +@section thrproc Threads and Processes + +LMDB uses POSIX locks on files, and these locks have issues if one +process opens a file multiple times. Because of this, do not +#mdb_env_open() a file multiple times from a single process. Instead, +share the LMDB environment that has opened the file across all threads. +Otherwise, if a single process opens the same environment multiple times, +closing it once will remove all the locks held on it, and the other +instances will be vulnerable to corruption from other processes. + +Also note that a transaction is tied to one thread by default using +Thread Local Storage. If you want to pass read-only transactions across +threads, you can use the #MDB_NOTLS option on the environment. + +@section txns Transactions, Rollbacks, etc. + +To actually get anything done, a transaction must be committed using +#mdb_txn_commit(). Alternatively, all of a transaction's operations +can be discarded using #mdb_txn_abort(). In a read-only transaction, +any cursors will \b not automatically be freed. In a read-write +transaction, all cursors will be freed and must not be used again. + +For read-only transactions, obviously there is nothing to commit to +storage. The transaction still must eventually be aborted to close +any database handle(s) opened in it, or committed to keep the +database handles around for reuse in new transactions. + +In addition, as long as a transaction is open, a consistent view of +the database is kept alive, which requires storage. A read-only +transaction that no longer requires this consistent view should +be terminated (committed or aborted) when the view is no longer +needed (but see below for an optimization). + +There can be multiple simultaneously active read-only transactions +but only one that can write. Once a single read-write transaction +is opened, all further attempts to begin one will block until the +first one is committed or aborted. This has no effect on read-only +transactions, however, and they may continue to be opened at any time. + +@section dupkeys Duplicate Keys + +#mdb_get() and #mdb_put() respectively have no and only some support +for multiple key/value pairs with identical keys. If there are multiple +values for a key, #mdb_get() will only return the first value. + +When multiple values for one key are required, pass the #MDB_DUPSORT +flag to #mdb_dbi_open(). In an #MDB_DUPSORT database, by default +#mdb_put() will not replace the value for a key if the key existed +already. Instead it will add the new value to the key. In addition, +#mdb_del() will pay attention to the value field too, allowing for +specific values of a key to be deleted. + +Finally, additional cursor operations become available for +traversing through and retrieving duplicate values. + +@section optim Some Optimization + +If you frequently begin and abort read-only transactions, as an +optimization, it is possible to only reset and renew a transaction. + +#mdb_txn_reset() releases any old copies of data kept around for +a read-only transaction. To reuse this reset transaction, call +#mdb_txn_renew() on it. Any cursors in this transaction must also +be renewed using #mdb_cursor_renew(). + +Note that #mdb_txn_reset() is similar to #mdb_txn_abort() and will +close any databases you opened within the transaction. + +To permanently free a transaction, reset or not, use #mdb_txn_abort(). + +@section cleanup Cleaning Up + +For read-only transactions, any cursors created within it must +be closed using #mdb_cursor_close(). + +It is very rarely necessary to close a database handle, and in +general they should just be left open. + +@section onward The Full API + +The full \ref mdb documentation lists further details, like how to: + + \li size a database (the default limits are intentionally small) + \li drop and clean a database + \li detect and report errors + \li optimize (bulk) loading speed + \li (temporarily) reduce robustness to gain even more speed + \li gather statistics about the database + \li define custom sort orders + +*/ diff --git a/contrib/db/liblmdb/lmdb.h b/contrib/db/liblmdb/lmdb.h new file mode 100644 index 00000000..0bca3eb7 --- /dev/null +++ b/contrib/db/liblmdb/lmdb.h @@ -0,0 +1,1618 @@ +/** @file lmdb.h + * @brief Lightning memory-mapped database library + * + * @mainpage Lightning Memory-Mapped Database Manager (LMDB) + * + * @section intro_sec Introduction + * LMDB is a Btree-based database management library modeled loosely on the + * BerkeleyDB API, but much simplified. The entire database is exposed + * in a memory map, and all data fetches return data directly + * from the mapped memory, so no malloc's or memcpy's occur during + * data fetches. As such, the library is extremely simple because it + * requires no page caching layer of its own, and it is extremely high + * performance and memory-efficient. It is also fully transactional with + * full ACID semantics, and when the memory map is read-only, the + * database integrity cannot be corrupted by stray pointer writes from + * application code. + * + * The library is fully thread-aware and supports concurrent read/write + * access from multiple processes and threads. Data pages use a copy-on- + * write strategy so no active data pages are ever overwritten, which + * also provides resistance to corruption and eliminates the need of any + * special recovery procedures after a system crash. Writes are fully + * serialized; only one write transaction may be active at a time, which + * guarantees that writers can never deadlock. The database structure is + * multi-versioned so readers run with no locks; writers cannot block + * readers, and readers don't block writers. + * + * Unlike other well-known database mechanisms which use either write-ahead + * transaction logs or append-only data writes, LMDB requires no maintenance + * during operation. Both write-ahead loggers and append-only databases + * require periodic checkpointing and/or compaction of their log or database + * files otherwise they grow without bound. LMDB tracks free pages within + * the database and re-uses them for new write operations, so the database + * size does not grow without bound in normal use. + * + * The memory map can be used as a read-only or read-write map. It is + * read-only by default as this provides total immunity to corruption. + * Using read-write mode offers much higher write performance, but adds + * the possibility for stray application writes thru pointers to silently + * corrupt the database. Of course if your application code is known to + * be bug-free (...) then this is not an issue. + * + * If this is your first time using a transactional embedded key/value + * store, you may find the \ref starting page to be helpful. + * + * @section caveats_sec Caveats + * Troubleshooting the lock file, plus semaphores on BSD systems: + * + * - A broken lockfile can cause sync issues. + * Stale reader transactions left behind by an aborted program + * cause further writes to grow the database quickly, and + * stale locks can block further operation. + * + * Fix: Check for stale readers periodically, using the + * #mdb_reader_check function or the \ref mdb_stat_1 "mdb_stat" tool. + * Stale writers will be cleared automatically on most systems: + * - Windows - automatic + * - BSD, systems using SysV semaphores - automatic + * - Linux, systems using POSIX mutexes with Robust option - automatic + * Otherwise just make all programs using the database close it; + * the lockfile is always reset on first open of the environment. + * + * - On BSD systems or others configured with MDB_USE_SYSV_SEM or + * MDB_USE_POSIX_SEM, + * startup can fail due to semaphores owned by another userid. + * + * Fix: Open and close the database as the user which owns the + * semaphores (likely last user) or as root, while no other + * process is using the database. + * + * Restrictions/caveats (in addition to those listed for some functions): + * + * - Only the database owner should normally use the database on + * BSD systems or when otherwise configured with MDB_USE_POSIX_SEM. + * Multiple users can cause startup to fail later, as noted above. + * + * - There is normally no pure read-only mode, since readers need write + * access to locks and lock file. Exceptions: On read-only filesystems + * or with the #MDB_NOLOCK flag described under #mdb_env_open(). + * + * - An LMDB configuration will often reserve considerable \b unused + * memory address space and maybe file size for future growth. + * This does not use actual memory or disk space, but users may need + * to understand the difference so they won't be scared off. + * + * - By default, in versions before 0.9.10, unused portions of the data + * file might receive garbage data from memory freed by other code. + * (This does not happen when using the #MDB_WRITEMAP flag.) As of + * 0.9.10 the default behavior is to initialize such memory before + * writing to the data file. Since there may be a slight performance + * cost due to this initialization, applications may disable it using + * the #MDB_NOMEMINIT flag. Applications handling sensitive data + * which must not be written should not use this flag. This flag is + * irrelevant when using #MDB_WRITEMAP. + * + * - A thread can only use one transaction at a time, plus any child + * transactions. Each transaction belongs to one thread. See below. + * The #MDB_NOTLS flag changes this for read-only transactions. + * + * - Use an MDB_env* in the process which opened it, without fork()ing. + * + * - Do not have open an LMDB database twice in the same process at + * the same time. Not even from a plain open() call - close()ing it + * breaks flock() advisory locking. + * + * - Avoid long-lived transactions. Read transactions prevent + * reuse of pages freed by newer write transactions, thus the + * database can grow quickly. Write transactions prevent + * other write transactions, since writes are serialized. + * + * - Avoid suspending a process with active transactions. These + * would then be "long-lived" as above. Also read transactions + * suspended when writers commit could sometimes see wrong data. + * + * ...when several processes can use a database concurrently: + * + * - Avoid aborting a process with an active transaction. + * The transaction becomes "long-lived" as above until a check + * for stale readers is performed or the lockfile is reset, + * since the process may not remove it from the lockfile. + * + * This does not apply to write transactions if the system clears + * stale writers, see above. + * + * - If you do that anyway, do a periodic check for stale readers. Or + * close the environment once in a while, so the lockfile can get reset. + * + * - Do not use LMDB databases on remote filesystems, even between + * processes on the same host. This breaks flock() on some OSes, + * possibly memory map sync, and certainly sync between programs + * on different hosts. + * + * - Opening a database can fail if another process is opening or + * closing it at exactly the same time. + * + * @author Howard Chu, Symas Corporation. + * + * @copyright Copyright 2011-2016 Howard Chu, Symas Corp. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + * + * @par Derived From: + * This code is derived from btree.c written by Martin Hedenfalk. + * + * Copyright (c) 2009, 2010 Martin Hedenfalk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef _LMDB_H_ +#define _LMDB_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Unix permissions for creating files, or dummy definition for Windows */ +#ifdef _MSC_VER +typedef int mdb_mode_t; +#else +typedef mode_t mdb_mode_t; +#endif + +#ifdef MDB_VL32 +typedef uint64_t mdb_size_t; +#define mdb_env_create mdb_env_create_vl32 /**< Prevent mixing with non-VL32 builds */ +#else +typedef size_t mdb_size_t; +#endif + +/** An abstraction for a file handle. + * On POSIX systems file handles are small integers. On Windows + * they're opaque pointers. + */ +#ifdef _WIN32 +typedef void *mdb_filehandle_t; +#else +typedef int mdb_filehandle_t; +#endif + +/** @defgroup mdb LMDB API + * @{ + * @brief OpenLDAP Lightning Memory-Mapped Database Manager + */ +/** @defgroup Version Version Macros + * @{ + */ +/** Library major version */ +#define MDB_VERSION_MAJOR 0 +/** Library minor version */ +#define MDB_VERSION_MINOR 9 +/** Library patch version */ +#define MDB_VERSION_PATCH 70 + +/** Combine args a,b,c into a single integer for easy version comparisons */ +#define MDB_VERINT(a,b,c) (((a) << 24) | ((b) << 16) | (c)) + +/** The full library version as a single integer */ +#define MDB_VERSION_FULL \ + MDB_VERINT(MDB_VERSION_MAJOR,MDB_VERSION_MINOR,MDB_VERSION_PATCH) + +/** The release date of this library version */ +#define MDB_VERSION_DATE "December 19, 2015" + +/** A stringifier for the version info */ +#define MDB_VERSTR(a,b,c,d) "LMDB " #a "." #b "." #c ": (" d ")" + +/** A helper for the stringifier macro */ +#define MDB_VERFOO(a,b,c,d) MDB_VERSTR(a,b,c,d) + +/** The full library version as a C string */ +#define MDB_VERSION_STRING \ + MDB_VERFOO(MDB_VERSION_MAJOR,MDB_VERSION_MINOR,MDB_VERSION_PATCH,MDB_VERSION_DATE) +/** @} */ + +/** @brief Opaque structure for a database environment. + * + * A DB environment supports multiple databases, all residing in the same + * shared-memory map. + */ +typedef struct MDB_env MDB_env; + +/** @brief Opaque structure for a transaction handle. + * + * All database operations require a transaction handle. Transactions may be + * read-only or read-write. + */ +typedef struct MDB_txn MDB_txn; + +/** @brief A handle for an individual database in the DB environment. */ +typedef unsigned int MDB_dbi; + +/** @brief Opaque structure for navigating through a database */ +typedef struct MDB_cursor MDB_cursor; + +/** @brief Generic structure used for passing keys and data in and out + * of the database. + * + * Values returned from the database are valid only until a subsequent + * update operation, or the end of the transaction. Do not modify or + * free them, they commonly point into the database itself. + * + * Key sizes must be between 1 and #mdb_env_get_maxkeysize() inclusive. + * The same applies to data sizes in databases with the #MDB_DUPSORT flag. + * Other data items can in theory be from 0 to 0xffffffff bytes long. + */ +typedef struct MDB_val { + size_t mv_size; /**< size of the data item */ + void *mv_data; /**< address of the data item */ +} MDB_val; + +/** @brief A callback function used to compare two keys in a database */ +typedef int (MDB_cmp_func)(const MDB_val *a, const MDB_val *b); + +/** @brief A callback function used to relocate a position-dependent data item + * in a fixed-address database. + * + * The \b newptr gives the item's desired address in + * the memory map, and \b oldptr gives its previous address. The item's actual + * data resides at the address in \b item. This callback is expected to walk + * through the fields of the record in \b item and modify any + * values based at the \b oldptr address to be relative to the \b newptr address. + * @param[in,out] item The item that is to be relocated. + * @param[in] oldptr The previous address. + * @param[in] newptr The new address to relocate to. + * @param[in] relctx An application-provided context, set by #mdb_set_relctx(). + * @todo This feature is currently unimplemented. + */ +typedef void (MDB_rel_func)(MDB_val *item, void *oldptr, void *newptr, void *relctx); + +/** @defgroup mdb_env Environment Flags + * @{ + */ + /** mmap at a fixed address (experimental) */ +#define MDB_FIXEDMAP 0x01 + /** no environment directory */ +#define MDB_NOSUBDIR 0x4000 + /** don't fsync after commit */ +#define MDB_NOSYNC 0x10000 + /** read only */ +#define MDB_RDONLY 0x20000 + /** don't fsync metapage after commit */ +#define MDB_NOMETASYNC 0x40000 + /** use writable mmap */ +#define MDB_WRITEMAP 0x80000 + /** use asynchronous msync when #MDB_WRITEMAP is used */ +#define MDB_MAPASYNC 0x100000 + /** tie reader locktable slots to #MDB_txn objects instead of to threads */ +#define MDB_NOTLS 0x200000 + /** don't do any locking, caller must manage their own locks */ +#define MDB_NOLOCK 0x400000 + /** don't do readahead (no effect on Windows) */ +#define MDB_NORDAHEAD 0x800000 + /** don't initialize malloc'd memory before writing to datafile */ +#define MDB_NOMEMINIT 0x1000000 + /** use the previous snapshot rather than the latest one */ +#define MDB_PREVSNAPSHOT 0x2000000 +/** @} */ + +/** @defgroup mdb_dbi_open Database Flags + * @{ + */ + /** use reverse string keys */ +#define MDB_REVERSEKEY 0x02 + /** use sorted duplicates */ +#define MDB_DUPSORT 0x04 + /** numeric keys in native byte order: either unsigned int or size_t. + * The keys must all be of the same size. */ +#define MDB_INTEGERKEY 0x08 + /** with #MDB_DUPSORT, sorted dup items have fixed size */ +#define MDB_DUPFIXED 0x10 + /** with #MDB_DUPSORT, dups are #MDB_INTEGERKEY-style integers */ +#define MDB_INTEGERDUP 0x20 + /** with #MDB_DUPSORT, use reverse string dups */ +#define MDB_REVERSEDUP 0x40 + /** create DB if not already existing */ +#define MDB_CREATE 0x40000 +/** @} */ + +/** @defgroup mdb_put Write Flags + * @{ + */ +/** For put: Don't write if the key already exists. */ +#define MDB_NOOVERWRITE 0x10 +/** Only for #MDB_DUPSORT
+ * For put: don't write if the key and data pair already exist.
+ * For mdb_cursor_del: remove all duplicate data items. + */ +#define MDB_NODUPDATA 0x20 +/** For mdb_cursor_put: overwrite the current key/data pair */ +#define MDB_CURRENT 0x40 +/** For put: Just reserve space for data, don't copy it. Return a + * pointer to the reserved space. + */ +#define MDB_RESERVE 0x10000 +/** Data is being appended, don't split full pages. */ +#define MDB_APPEND 0x20000 +/** Duplicate data is being appended, don't split full pages. */ +#define MDB_APPENDDUP 0x40000 +/** Store multiple data items in one call. Only for #MDB_DUPFIXED. */ +#define MDB_MULTIPLE 0x80000 +/* @} */ + +/** @defgroup mdb_copy Copy Flags + * @{ + */ +/** Compacting copy: Omit free space from copy, and renumber all + * pages sequentially. + */ +#define MDB_CP_COMPACT 0x01 +/* @} */ + +/** @brief Cursor Get operations. + * + * This is the set of all operations for retrieving data + * using a cursor. + */ +typedef enum MDB_cursor_op { + MDB_FIRST, /**< Position at first key/data item */ + MDB_FIRST_DUP, /**< Position at first data item of current key. + Only for #MDB_DUPSORT */ + MDB_GET_BOTH, /**< Position at key/data pair. Only for #MDB_DUPSORT */ + MDB_GET_BOTH_RANGE, /**< position at key, nearest data. Only for #MDB_DUPSORT */ + MDB_GET_CURRENT, /**< Return key/data at current cursor position */ + MDB_GET_MULTIPLE, /**< Return key and up to a page of duplicate data items + from current cursor position. Move cursor to prepare + for #MDB_NEXT_MULTIPLE. Only for #MDB_DUPFIXED */ + MDB_LAST, /**< Position at last key/data item */ + MDB_LAST_DUP, /**< Position at last data item of current key. + Only for #MDB_DUPSORT */ + MDB_NEXT, /**< Position at next data item */ + MDB_NEXT_DUP, /**< Position at next data item of current key. + Only for #MDB_DUPSORT */ + MDB_NEXT_MULTIPLE, /**< Return key and up to a page of duplicate data items + from next cursor position. Move cursor to prepare + for #MDB_NEXT_MULTIPLE. Only for #MDB_DUPFIXED */ + MDB_NEXT_NODUP, /**< Position at first data item of next key */ + MDB_PREV, /**< Position at previous data item */ + MDB_PREV_DUP, /**< Position at previous data item of current key. + Only for #MDB_DUPSORT */ + MDB_PREV_NODUP, /**< Position at last data item of previous key */ + MDB_SET, /**< Position at specified key */ + MDB_SET_KEY, /**< Position at specified key, return key + data */ + MDB_SET_RANGE, /**< Position at first key greater than or equal to specified key. */ + MDB_PREV_MULTIPLE /**< Position at previous page and return key and up to + a page of duplicate data items. Only for #MDB_DUPFIXED */ +} MDB_cursor_op; + +/** @defgroup errors Return Codes + * + * BerkeleyDB uses -30800 to -30999, we'll go under them + * @{ + */ + /** Successful result */ +#define MDB_SUCCESS 0 + /** key/data pair already exists */ +#define MDB_KEYEXIST (-30799) + /** key/data pair not found (EOF) */ +#define MDB_NOTFOUND (-30798) + /** Requested page not found - this usually indicates corruption */ +#define MDB_PAGE_NOTFOUND (-30797) + /** Located page was wrong type */ +#define MDB_CORRUPTED (-30796) + /** Update of meta page failed or environment had fatal error */ +#define MDB_PANIC (-30795) + /** Environment version mismatch */ +#define MDB_VERSION_MISMATCH (-30794) + /** File is not a valid LMDB file */ +#define MDB_INVALID (-30793) + /** Environment mapsize reached */ +#define MDB_MAP_FULL (-30792) + /** Environment maxdbs reached */ +#define MDB_DBS_FULL (-30791) + /** Environment maxreaders reached */ +#define MDB_READERS_FULL (-30790) + /** Too many TLS keys in use - Windows only */ +#define MDB_TLS_FULL (-30789) + /** Txn has too many dirty pages */ +#define MDB_TXN_FULL (-30788) + /** Cursor stack too deep - internal error */ +#define MDB_CURSOR_FULL (-30787) + /** Page has not enough space - internal error */ +#define MDB_PAGE_FULL (-30786) + /** Database contents grew beyond environment mapsize */ +#define MDB_MAP_RESIZED (-30785) + /** Operation and DB incompatible, or DB type changed. This can mean: + *
    + *
  • The operation expects an #MDB_DUPSORT / #MDB_DUPFIXED database. + *
  • Opening a named DB when the unnamed DB has #MDB_DUPSORT / #MDB_INTEGERKEY. + *
  • Accessing a data record as a database, or vice versa. + *
  • The database was dropped and recreated with different flags. + *
+ */ +#define MDB_INCOMPATIBLE (-30784) + /** Invalid reuse of reader locktable slot */ +#define MDB_BAD_RSLOT (-30783) + /** Transaction must abort, has a child, or is invalid */ +#define MDB_BAD_TXN (-30782) + /** Unsupported size of key/DB name/data, or wrong DUPFIXED size */ +#define MDB_BAD_VALSIZE (-30781) + /** The specified DBI was changed unexpectedly */ +#define MDB_BAD_DBI (-30780) + /** The last defined error code */ +#define MDB_LAST_ERRCODE MDB_BAD_DBI +/** @} */ + +/** @brief Statistics for a database in the environment */ +typedef struct MDB_stat { + unsigned int ms_psize; /**< Size of a database page. + This is currently the same for all databases. */ + unsigned int ms_depth; /**< Depth (height) of the B-tree */ + mdb_size_t ms_branch_pages; /**< Number of internal (non-leaf) pages */ + mdb_size_t ms_leaf_pages; /**< Number of leaf pages */ + mdb_size_t ms_overflow_pages; /**< Number of overflow pages */ + mdb_size_t ms_entries; /**< Number of data items */ +} MDB_stat; + +/** @brief Information about the environment */ +typedef struct MDB_envinfo { + void *me_mapaddr; /**< Address of map, if fixed */ + mdb_size_t me_mapsize; /**< Size of the data memory map */ + mdb_size_t me_last_pgno; /**< ID of the last used page */ + mdb_size_t me_last_txnid; /**< ID of the last committed transaction */ + unsigned int me_maxreaders; /**< max reader slots in the environment */ + unsigned int me_numreaders; /**< max reader slots used in the environment */ +} MDB_envinfo; + + /** @brief Return the LMDB library version information. + * + * @param[out] major if non-NULL, the library major version number is copied here + * @param[out] minor if non-NULL, the library minor version number is copied here + * @param[out] patch if non-NULL, the library patch version number is copied here + * @retval "version string" The library version as a string + */ +char *mdb_version(int *major, int *minor, int *patch); + + /** @brief Return a string describing a given error code. + * + * This function is a superset of the ANSI C X3.159-1989 (ANSI C) strerror(3) + * function. If the error code is greater than or equal to 0, then the string + * returned by the system function strerror(3) is returned. If the error code + * is less than 0, an error string corresponding to the LMDB library error is + * returned. See @ref errors for a list of LMDB-specific error codes. + * @param[in] err The error code + * @retval "error message" The description of the error + */ +char *mdb_strerror(int err); + + /** @brief Create an LMDB environment handle. + * + * This function allocates memory for a #MDB_env structure. To release + * the allocated memory and discard the handle, call #mdb_env_close(). + * Before the handle may be used, it must be opened using #mdb_env_open(). + * Various other options may also need to be set before opening the handle, + * e.g. #mdb_env_set_mapsize(), #mdb_env_set_maxreaders(), #mdb_env_set_maxdbs(), + * depending on usage requirements. + * @param[out] env The address where the new handle will be stored + * @return A non-zero error value on failure and 0 on success. + */ +int mdb_env_create(MDB_env **env); + + /** @brief Open an environment handle. + * + * If this function fails, #mdb_env_close() must be called to discard the #MDB_env handle. + * @param[in] env An environment handle returned by #mdb_env_create() + * @param[in] path The directory in which the database files reside. This + * directory must already exist and be writable. + * @param[in] flags Special options for this environment. This parameter + * must be set to 0 or by bitwise OR'ing together one or more of the + * values described here. + * Flags set by mdb_env_set_flags() are also used. + *
    + *
  • #MDB_FIXEDMAP + * use a fixed address for the mmap region. This flag must be specified + * when creating the environment, and is stored persistently in the environment. + * If successful, the memory map will always reside at the same virtual address + * and pointers used to reference data items in the database will be constant + * across multiple invocations. This option may not always work, depending on + * how the operating system has allocated memory to shared libraries and other uses. + * The feature is highly experimental. + *
  • #MDB_NOSUBDIR + * By default, LMDB creates its environment in a directory whose + * pathname is given in \b path, and creates its data and lock files + * under that directory. With this option, \b path is used as-is for + * the database main data file. The database lock file is the \b path + * with "-lock" appended. + *
  • #MDB_RDONLY + * Open the environment in read-only mode. No write operations will be + * allowed. LMDB will still modify the lock file - except on read-only + * filesystems, where LMDB does not use locks. + *
  • #MDB_WRITEMAP + * Use a writeable memory map unless MDB_RDONLY is set. This uses + * fewer mallocs but loses protection from application bugs + * like wild pointer writes and other bad updates into the database. + * This may be slightly faster for DBs that fit entirely in RAM, but + * is slower for DBs larger than RAM. + * Incompatible with nested transactions. + * Do not mix processes with and without MDB_WRITEMAP on the same + * environment. This can defeat durability (#mdb_env_sync etc). + *
  • #MDB_NOMETASYNC + * Flush system buffers to disk only once per transaction, omit the + * metadata flush. Defer that until the system flushes files to disk, + * or next non-MDB_RDONLY commit or #mdb_env_sync(). This optimization + * maintains database integrity, but a system crash may undo the last + * committed transaction. I.e. it preserves the ACI (atomicity, + * consistency, isolation) but not D (durability) database property. + * This flag may be changed at any time using #mdb_env_set_flags(). + *
  • #MDB_NOSYNC + * Don't flush system buffers to disk when committing a transaction. + * This optimization means a system crash can corrupt the database or + * lose the last transactions if buffers are not yet flushed to disk. + * The risk is governed by how often the system flushes dirty buffers + * to disk and how often #mdb_env_sync() is called. However, if the + * filesystem preserves write order and the #MDB_WRITEMAP flag is not + * used, transactions exhibit ACI (atomicity, consistency, isolation) + * properties and only lose D (durability). I.e. database integrity + * is maintained, but a system crash may undo the final transactions. + * Note that (#MDB_NOSYNC | #MDB_WRITEMAP) leaves the system with no + * hint for when to write transactions to disk, unless #mdb_env_sync() + * is called. (#MDB_MAPASYNC | #MDB_WRITEMAP) may be preferable. + * This flag may be changed at any time using #mdb_env_set_flags(). + *
  • #MDB_MAPASYNC + * When using #MDB_WRITEMAP, use asynchronous flushes to disk. + * As with #MDB_NOSYNC, a system crash can then corrupt the + * database or lose the last transactions. Calling #mdb_env_sync() + * ensures on-disk database integrity until next commit. + * This flag may be changed at any time using #mdb_env_set_flags(). + *
  • #MDB_NOTLS + * Don't use Thread-Local Storage. Tie reader locktable slots to + * #MDB_txn objects instead of to threads. I.e. #mdb_txn_reset() keeps + * the slot reseved for the #MDB_txn object. A thread may use parallel + * read-only transactions. A read-only transaction may span threads if + * the user synchronizes its use. Applications that multiplex many + * user threads over individual OS threads need this option. Such an + * application must also serialize the write transactions in an OS + * thread, since LMDB's write locking is unaware of the user threads. + *
  • #MDB_NOLOCK + * Don't do any locking. If concurrent access is anticipated, the + * caller must manage all concurrency itself. For proper operation + * the caller must enforce single-writer semantics, and must ensure + * that no readers are using old transactions while a writer is + * active. The simplest approach is to use an exclusive lock so that + * no readers may be active at all when a writer begins. + *
  • #MDB_NORDAHEAD + * Turn off readahead. Most operating systems perform readahead on + * read requests by default. This option turns it off if the OS + * supports it. Turning it off may help random read performance + * when the DB is larger than RAM and system RAM is full. + * The option is not implemented on Windows. + *
  • #MDB_NOMEMINIT + * Don't initialize malloc'd memory before writing to unused spaces + * in the data file. By default, memory for pages written to the data + * file is obtained using malloc. While these pages may be reused in + * subsequent transactions, freshly malloc'd pages will be initialized + * to zeroes before use. This avoids persisting leftover data from other + * code (that used the heap and subsequently freed the memory) into the + * data file. Note that many other system libraries may allocate + * and free memory from the heap for arbitrary uses. E.g., stdio may + * use the heap for file I/O buffers. This initialization step has a + * modest performance cost so some applications may want to disable + * it using this flag. This option can be a problem for applications + * which handle sensitive data like passwords, and it makes memory + * checkers like Valgrind noisy. This flag is not needed with #MDB_WRITEMAP, + * which writes directly to the mmap instead of using malloc for pages. The + * initialization is also skipped if #MDB_RESERVE is used; the + * caller is expected to overwrite all of the memory that was + * reserved in that case. + * This flag may be changed at any time using #mdb_env_set_flags(). + *
  • #MDB_PREVSNAPSHOT + * Open the environment with the previous snapshot rather than the latest + * one. This loses the latest transaction, but may help work around some + * types of corruption. If opened with write access, this must be the + * only process using the environment. This flag is automatically reset + * after a write transaction is successfully committed. + *
+ * @param[in] mode The UNIX permissions to set on created files and semaphores. + * This parameter is ignored on Windows. + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • #MDB_VERSION_MISMATCH - the version of the LMDB library doesn't match the + * version that created the database environment. + *
  • #MDB_INVALID - the environment file headers are corrupted. + *
  • ENOENT - the directory specified by the path parameter doesn't exist. + *
  • EACCES - the user didn't have permission to access the environment files. + *
  • EAGAIN - the environment was locked by another process. + *
+ */ +int mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode); + + /** @brief Copy an LMDB environment to the specified path. + * + * This function may be used to make a backup of an existing environment. + * No lockfile is created, since it gets recreated at need. + * @note This call can trigger significant file size growth if run in + * parallel with write transactions, because it employs a read-only + * transaction. See long-lived transactions under @ref caveats_sec. + * @param[in] env An environment handle returned by #mdb_env_create(). It + * must have already been opened successfully. + * @param[in] path The directory in which the copy will reside. This + * directory must already exist and be writable but must otherwise be + * empty. + * @return A non-zero error value on failure and 0 on success. + */ +int mdb_env_copy(MDB_env *env, const char *path); + + /** @brief Copy an LMDB environment to the specified file descriptor. + * + * This function may be used to make a backup of an existing environment. + * No lockfile is created, since it gets recreated at need. + * @note This call can trigger significant file size growth if run in + * parallel with write transactions, because it employs a read-only + * transaction. See long-lived transactions under @ref caveats_sec. + * @param[in] env An environment handle returned by #mdb_env_create(). It + * must have already been opened successfully. + * @param[in] fd The filedescriptor to write the copy to. It must + * have already been opened for Write access. + * @return A non-zero error value on failure and 0 on success. + */ +int mdb_env_copyfd(MDB_env *env, mdb_filehandle_t fd); + + /** @brief Copy an LMDB environment to the specified path, with options. + * + * This function may be used to make a backup of an existing environment. + * No lockfile is created, since it gets recreated at need. + * @note This call can trigger significant file size growth if run in + * parallel with write transactions, because it employs a read-only + * transaction. See long-lived transactions under @ref caveats_sec. + * @param[in] env An environment handle returned by #mdb_env_create(). It + * must have already been opened successfully. + * @param[in] path The directory in which the copy will reside. This + * directory must already exist and be writable but must otherwise be + * empty. + * @param[in] flags Special options for this operation. This parameter + * must be set to 0 or by bitwise OR'ing together one or more of the + * values described here. + *
    + *
  • #MDB_CP_COMPACT - Perform compaction while copying: omit free + * pages and sequentially renumber all pages in output. This option + * consumes more CPU and runs more slowly than the default. + *
+ * @return A non-zero error value on failure and 0 on success. + */ +int mdb_env_copy2(MDB_env *env, const char *path, unsigned int flags); + + /** @brief Copy an LMDB environment to the specified file descriptor, + * with options. + * + * This function may be used to make a backup of an existing environment. + * No lockfile is created, since it gets recreated at need. See + * #mdb_env_copy2() for further details. + * @note This call can trigger significant file size growth if run in + * parallel with write transactions, because it employs a read-only + * transaction. See long-lived transactions under @ref caveats_sec. + * @param[in] env An environment handle returned by #mdb_env_create(). It + * must have already been opened successfully. + * @param[in] fd The filedescriptor to write the copy to. It must + * have already been opened for Write access. + * @param[in] flags Special options for this operation. + * See #mdb_env_copy2() for options. + * @return A non-zero error value on failure and 0 on success. + */ +int mdb_env_copyfd2(MDB_env *env, mdb_filehandle_t fd, unsigned int flags); + + /** @brief Return statistics about the LMDB environment. + * + * @param[in] env An environment handle returned by #mdb_env_create() + * @param[out] stat The address of an #MDB_stat structure + * where the statistics will be copied + */ +int mdb_env_stat(MDB_env *env, MDB_stat *stat); + + /** @brief Return information about the LMDB environment. + * + * @param[in] env An environment handle returned by #mdb_env_create() + * @param[out] stat The address of an #MDB_envinfo structure + * where the information will be copied + */ +int mdb_env_info(MDB_env *env, MDB_envinfo *stat); + + /** @brief Flush the data buffers to disk. + * + * Data is always written to disk when #mdb_txn_commit() is called, + * but the operating system may keep it buffered. LMDB always flushes + * the OS buffers upon commit as well, unless the environment was + * opened with #MDB_NOSYNC or in part #MDB_NOMETASYNC. This call is + * not valid if the environment was opened with #MDB_RDONLY. + * @param[in] env An environment handle returned by #mdb_env_create() + * @param[in] force If non-zero, force a synchronous flush. Otherwise + * if the environment has the #MDB_NOSYNC flag set the flushes + * will be omitted, and with #MDB_MAPASYNC they will be asynchronous. + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • EACCES - the environment is read-only. + *
  • EINVAL - an invalid parameter was specified. + *
  • EIO - an error occurred during synchronization. + *
+ */ +int mdb_env_sync(MDB_env *env, int force); + + /** @brief Close the environment and release the memory map. + * + * Only a single thread may call this function. All transactions, databases, + * and cursors must already be closed before calling this function. Attempts to + * use any such handles after calling this function will cause a SIGSEGV. + * The environment handle will be freed and must not be used again after this call. + * @param[in] env An environment handle returned by #mdb_env_create() + */ +void mdb_env_close(MDB_env *env); + + /** @brief Set environment flags. + * + * This may be used to set some flags in addition to those from + * #mdb_env_open(), or to unset these flags. If several threads + * change the flags at the same time, the result is undefined. + * @param[in] env An environment handle returned by #mdb_env_create() + * @param[in] flags The flags to change, bitwise OR'ed together + * @param[in] onoff A non-zero value sets the flags, zero clears them. + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • EINVAL - an invalid parameter was specified. + *
+ */ +int mdb_env_set_flags(MDB_env *env, unsigned int flags, int onoff); + + /** @brief Get environment flags. + * + * @param[in] env An environment handle returned by #mdb_env_create() + * @param[out] flags The address of an integer to store the flags + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • EINVAL - an invalid parameter was specified. + *
+ */ +int mdb_env_get_flags(MDB_env *env, unsigned int *flags); + + /** @brief Return the path that was used in #mdb_env_open(). + * + * @param[in] env An environment handle returned by #mdb_env_create() + * @param[out] path Address of a string pointer to contain the path. This + * is the actual string in the environment, not a copy. It should not be + * altered in any way. + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • EINVAL - an invalid parameter was specified. + *
+ */ +int mdb_env_get_path(MDB_env *env, const char **path); + + /** @brief Return the filedescriptor for the given environment. + * + * @param[in] env An environment handle returned by #mdb_env_create() + * @param[out] fd Address of a mdb_filehandle_t to contain the descriptor. + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • EINVAL - an invalid parameter was specified. + *
+ */ +int mdb_env_get_fd(MDB_env *env, mdb_filehandle_t *fd); + + /** @brief Set the size of the memory map to use for this environment. + * + * The size should be a multiple of the OS page size. The default is + * 10485760 bytes. The size of the memory map is also the maximum size + * of the database. The value should be chosen as large as possible, + * to accommodate future growth of the database. + * This function should be called after #mdb_env_create() and before #mdb_env_open(). + * It may be called at later times if no transactions are active in + * this process. Note that the library does not check for this condition, + * the caller must ensure it explicitly. + * + * The new size takes effect immediately for the current process but + * will not be persisted to any others until a write transaction has been + * committed by the current process. Also, only mapsize increases are + * persisted into the environment. + * + * If the mapsize is increased by another process, and data has grown + * beyond the range of the current mapsize, #mdb_txn_begin() will + * return #MDB_MAP_RESIZED. This function may be called with a size + * of zero to adopt the new size. + * + * Any attempt to set a size smaller than the space already consumed + * by the environment will be silently changed to the current size of the used space. + * @param[in] env An environment handle returned by #mdb_env_create() + * @param[in] size The size in bytes + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • EINVAL - an invalid parameter was specified, or the environment has + * an active write transaction. + *
+ */ +int mdb_env_set_mapsize(MDB_env *env, mdb_size_t size); + + /** @brief Set the maximum number of threads/reader slots for the environment. + * + * This defines the number of slots in the lock table that is used to track readers in the + * the environment. The default is 126. + * Starting a read-only transaction normally ties a lock table slot to the + * current thread until the environment closes or the thread exits. If + * MDB_NOTLS is in use, #mdb_txn_begin() instead ties the slot to the + * MDB_txn object until it or the #MDB_env object is destroyed. + * This function may only be called after #mdb_env_create() and before #mdb_env_open(). + * @param[in] env An environment handle returned by #mdb_env_create() + * @param[in] readers The maximum number of reader lock table slots + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • EINVAL - an invalid parameter was specified, or the environment is already open. + *
+ */ +int mdb_env_set_maxreaders(MDB_env *env, unsigned int readers); + + /** @brief Get the maximum number of threads/reader slots for the environment. + * + * @param[in] env An environment handle returned by #mdb_env_create() + * @param[out] readers Address of an integer to store the number of readers + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • EINVAL - an invalid parameter was specified. + *
+ */ +int mdb_env_get_maxreaders(MDB_env *env, unsigned int *readers); + + /** @brief Set the maximum number of named databases for the environment. + * + * This function is only needed if multiple databases will be used in the + * environment. Simpler applications that use the environment as a single + * unnamed database can ignore this option. + * This function may only be called after #mdb_env_create() and before #mdb_env_open(). + * + * Currently a moderate number of slots are cheap but a huge number gets + * expensive: 7-120 words per transaction, and every #mdb_dbi_open() + * does a linear search of the opened slots. + * @param[in] env An environment handle returned by #mdb_env_create() + * @param[in] dbs The maximum number of databases + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • EINVAL - an invalid parameter was specified, or the environment is already open. + *
+ */ +int mdb_env_set_maxdbs(MDB_env *env, MDB_dbi dbs); + + /** @brief Get the maximum size of keys and #MDB_DUPSORT data we can write. + * + * Depends on the compile-time constant #MDB_MAXKEYSIZE. Default 511. + * See @ref MDB_val. + * @param[in] env An environment handle returned by #mdb_env_create() + * @return The maximum size of a key we can write + */ +int mdb_env_get_maxkeysize(MDB_env *env); + + /** @brief Set application information associated with the #MDB_env. + * + * @param[in] env An environment handle returned by #mdb_env_create() + * @param[in] ctx An arbitrary pointer for whatever the application needs. + * @return A non-zero error value on failure and 0 on success. + */ +int mdb_env_set_userctx(MDB_env *env, void *ctx); + + /** @brief Get the application information associated with the #MDB_env. + * + * @param[in] env An environment handle returned by #mdb_env_create() + * @return The pointer set by #mdb_env_set_userctx(). + */ +void *mdb_env_get_userctx(MDB_env *env); + + /** @brief A callback function for most LMDB assert() failures, + * called before printing the message and aborting. + * + * @param[in] env An environment handle returned by #mdb_env_create(). + * @param[in] msg The assertion message, not including newline. + */ +typedef void MDB_assert_func(MDB_env *env, const char *msg); + + /** Set or reset the assert() callback of the environment. + * Disabled if liblmdb is buillt with NDEBUG. + * @note This hack should become obsolete as lmdb's error handling matures. + * @param[in] env An environment handle returned by #mdb_env_create(). + * @param[in] func An #MDB_assert_func function, or 0. + * @return A non-zero error value on failure and 0 on success. + */ +int mdb_env_set_assert(MDB_env *env, MDB_assert_func *func); + + /** @brief Create a transaction for use with the environment. + * + * The transaction handle may be discarded using #mdb_txn_abort() or #mdb_txn_commit(). + * @note A transaction and its cursors must only be used by a single + * thread, and a thread may only have a single transaction at a time. + * If #MDB_NOTLS is in use, this does not apply to read-only transactions. + * @note Cursors may not span transactions. + * @param[in] env An environment handle returned by #mdb_env_create() + * @param[in] parent If this parameter is non-NULL, the new transaction + * will be a nested transaction, with the transaction indicated by \b parent + * as its parent. Transactions may be nested to any level. A parent + * transaction and its cursors may not issue any other operations than + * mdb_txn_commit and mdb_txn_abort while it has active child transactions. + * @param[in] flags Special options for this transaction. This parameter + * must be set to 0 or by bitwise OR'ing together one or more of the + * values described here. + *
    + *
  • #MDB_RDONLY + * This transaction will not perform any write operations. + *
  • #MDB_NOSYNC + * Don't flush system buffers to disk when committing this transaction. + *
  • #MDB_NOMETASYNC + * Flush system buffers but omit metadata flush when committing this transaction. + *
+ * @param[out] txn Address where the new #MDB_txn handle will be stored + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • #MDB_PANIC - a fatal error occurred earlier and the environment + * must be shut down. + *
  • #MDB_MAP_RESIZED - another process wrote data beyond this MDB_env's + * mapsize and this environment's map must be resized as well. + * See #mdb_env_set_mapsize(). + *
  • #MDB_READERS_FULL - a read-only transaction was requested and + * the reader lock table is full. See #mdb_env_set_maxreaders(). + *
  • ENOMEM - out of memory. + *
+ */ +int mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **txn); + + /** @brief Returns the transaction's #MDB_env + * + * @param[in] txn A transaction handle returned by #mdb_txn_begin() + */ +MDB_env *mdb_txn_env(MDB_txn *txn); + + /** @brief Return the transaction's ID. + * + * This returns the identifier associated with this transaction. For a + * read-only transaction, this corresponds to the snapshot being read; + * concurrent readers will frequently have the same transaction ID. + * + * @param[in] txn A transaction handle returned by #mdb_txn_begin() + * @return A transaction ID, valid if input is an active transaction. + */ +mdb_size_t mdb_txn_id(MDB_txn *txn); + + /** @brief Commit all the operations of a transaction into the database. + * + * The transaction handle is freed. It and its cursors must not be used + * again after this call, except with #mdb_cursor_renew(). + * @note Earlier documentation incorrectly said all cursors would be freed. + * Only write-transactions free cursors. + * @param[in] txn A transaction handle returned by #mdb_txn_begin() + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • EINVAL - an invalid parameter was specified. + *
  • ENOSPC - no more disk space. + *
  • EIO - a low-level I/O error occurred while writing. + *
  • ENOMEM - out of memory. + *
+ */ +int mdb_txn_commit(MDB_txn *txn); + + /** @brief Abandon all the operations of the transaction instead of saving them. + * + * The transaction handle is freed. It and its cursors must not be used + * again after this call, except with #mdb_cursor_renew(). + * @note Earlier documentation incorrectly said all cursors would be freed. + * Only write-transactions free cursors. + * @param[in] txn A transaction handle returned by #mdb_txn_begin() + */ +void mdb_txn_abort(MDB_txn *txn); + + /** @brief Reset a read-only transaction. + * + * Abort the transaction like #mdb_txn_abort(), but keep the transaction + * handle. #mdb_txn_renew() may reuse the handle. This saves allocation + * overhead if the process will start a new read-only transaction soon, + * and also locking overhead if #MDB_NOTLS is in use. The reader table + * lock is released, but the table slot stays tied to its thread or + * #MDB_txn. Use mdb_txn_abort() to discard a reset handle, and to free + * its lock table slot if MDB_NOTLS is in use. + * Cursors opened within the transaction must not be used + * again after this call, except with #mdb_cursor_renew(). + * Reader locks generally don't interfere with writers, but they keep old + * versions of database pages allocated. Thus they prevent the old pages + * from being reused when writers commit new data, and so under heavy load + * the database size may grow much more rapidly than otherwise. + * @param[in] txn A transaction handle returned by #mdb_txn_begin() + */ +void mdb_txn_reset(MDB_txn *txn); + + /** @brief Renew a read-only transaction. + * + * This acquires a new reader lock for a transaction handle that had been + * released by #mdb_txn_reset(). It must be called before a reset transaction + * may be used again. + * @param[in] txn A transaction handle returned by #mdb_txn_begin() + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • #MDB_PANIC - a fatal error occurred earlier and the environment + * must be shut down. + *
  • EINVAL - an invalid parameter was specified. + *
+ */ +int mdb_txn_renew(MDB_txn *txn); + +/** Compat with version <= 0.9.4, avoid clash with libmdb from MDB Tools project */ +#define mdb_open(txn,name,flags,dbi) mdb_dbi_open(txn,name,flags,dbi) +/** Compat with version <= 0.9.4, avoid clash with libmdb from MDB Tools project */ +#define mdb_close(env,dbi) mdb_dbi_close(env,dbi) + + /** @brief Open a database in the environment. + * + * A database handle denotes the name and parameters of a database, + * independently of whether such a database exists. + * The database handle may be discarded by calling #mdb_dbi_close(). + * The old database handle is returned if the database was already open. + * The handle may only be closed once. + * + * The database handle will be private to the current transaction until + * the transaction is successfully committed. If the transaction is + * aborted the handle will be closed automatically. + * After a successful commit the handle will reside in the shared + * environment, and may be used by other transactions. + * + * This function must not be called from multiple concurrent + * transactions in the same process. A transaction that uses + * this function must finish (either commit or abort) before + * any other transaction in the process may use this function. + * + * To use named databases (with name != NULL), #mdb_env_set_maxdbs() + * must be called before opening the environment. Database names are + * keys in the unnamed database, and may be read but not written. + * + * @param[in] txn A transaction handle returned by #mdb_txn_begin() + * @param[in] name The name of the database to open. If only a single + * database is needed in the environment, this value may be NULL. + * @param[in] flags Special options for this database. This parameter + * must be set to 0 or by bitwise OR'ing together one or more of the + * values described here. + *
    + *
  • #MDB_REVERSEKEY + * Keys are strings to be compared in reverse order, from the end + * of the strings to the beginning. By default, Keys are treated as strings and + * compared from beginning to end. + *
  • #MDB_DUPSORT + * Duplicate keys may be used in the database. (Or, from another perspective, + * keys may have multiple data items, stored in sorted order.) By default + * keys must be unique and may have only a single data item. + *
  • #MDB_INTEGERKEY + * Keys are binary integers in native byte order, either unsigned int + * or size_t, and will be sorted as such. + * The keys must all be of the same size. + *
  • #MDB_DUPFIXED + * This flag may only be used in combination with #MDB_DUPSORT. This option + * tells the library that the data items for this database are all the same + * size, which allows further optimizations in storage and retrieval. When + * all data items are the same size, the #MDB_GET_MULTIPLE and #MDB_NEXT_MULTIPLE + * cursor operations may be used to retrieve multiple items at once. + *
  • #MDB_INTEGERDUP + * This option specifies that duplicate data items are binary integers, + * similar to #MDB_INTEGERKEY keys. + *
  • #MDB_REVERSEDUP + * This option specifies that duplicate data items should be compared as + * strings in reverse order. + *
  • #MDB_CREATE + * Create the named database if it doesn't exist. This option is not + * allowed in a read-only transaction or a read-only environment. + *
+ * @param[out] dbi Address where the new #MDB_dbi handle will be stored + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • #MDB_NOTFOUND - the specified database doesn't exist in the environment + * and #MDB_CREATE was not specified. + *
  • #MDB_DBS_FULL - too many databases have been opened. See #mdb_env_set_maxdbs(). + *
+ */ +int mdb_dbi_open(MDB_txn *txn, const char *name, unsigned int flags, MDB_dbi *dbi); + + /** @brief Retrieve statistics for a database. + * + * @param[in] txn A transaction handle returned by #mdb_txn_begin() + * @param[in] dbi A database handle returned by #mdb_dbi_open() + * @param[out] stat The address of an #MDB_stat structure + * where the statistics will be copied + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • EINVAL - an invalid parameter was specified. + *
+ */ +int mdb_stat(MDB_txn *txn, MDB_dbi dbi, MDB_stat *stat); + + /** @brief Retrieve the DB flags for a database handle. + * + * @param[in] txn A transaction handle returned by #mdb_txn_begin() + * @param[in] dbi A database handle returned by #mdb_dbi_open() + * @param[out] flags Address where the flags will be returned. + * @return A non-zero error value on failure and 0 on success. + */ +int mdb_dbi_flags(MDB_txn *txn, MDB_dbi dbi, unsigned int *flags); + + /** @brief Close a database handle. Normally unnecessary. Use with care: + * + * This call is not mutex protected. Handles should only be closed by + * a single thread, and only if no other threads are going to reference + * the database handle or one of its cursors any further. Do not close + * a handle if an existing transaction has modified its database. + * Doing so can cause misbehavior from database corruption to errors + * like MDB_BAD_VALSIZE (since the DB name is gone). + * + * Closing a database handle is not necessary, but lets #mdb_dbi_open() + * reuse the handle value. Usually it's better to set a bigger + * #mdb_env_set_maxdbs(), unless that value would be large. + * + * @param[in] env An environment handle returned by #mdb_env_create() + * @param[in] dbi A database handle returned by #mdb_dbi_open() + */ +void mdb_dbi_close(MDB_env *env, MDB_dbi dbi); + + /** @brief Empty or delete+close a database. + * + * See #mdb_dbi_close() for restrictions about closing the DB handle. + * @param[in] txn A transaction handle returned by #mdb_txn_begin() + * @param[in] dbi A database handle returned by #mdb_dbi_open() + * @param[in] del 0 to empty the DB, 1 to delete it from the + * environment and close the DB handle. + * @return A non-zero error value on failure and 0 on success. + */ +int mdb_drop(MDB_txn *txn, MDB_dbi dbi, int del); + + /** @brief Set a custom key comparison function for a database. + * + * The comparison function is called whenever it is necessary to compare a + * key specified by the application with a key currently stored in the database. + * If no comparison function is specified, and no special key flags were specified + * with #mdb_dbi_open(), the keys are compared lexically, with shorter keys collating + * before longer keys. + * @warning This function must be called before any data access functions are used, + * otherwise data corruption may occur. The same comparison function must be used by every + * program accessing the database, every time the database is used. + * @param[in] txn A transaction handle returned by #mdb_txn_begin() + * @param[in] dbi A database handle returned by #mdb_dbi_open() + * @param[in] cmp A #MDB_cmp_func function + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • EINVAL - an invalid parameter was specified. + *
+ */ +int mdb_set_compare(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp); + + /** @brief Set a custom data comparison function for a #MDB_DUPSORT database. + * + * This comparison function is called whenever it is necessary to compare a data + * item specified by the application with a data item currently stored in the database. + * This function only takes effect if the database was opened with the #MDB_DUPSORT + * flag. + * If no comparison function is specified, and no special key flags were specified + * with #mdb_dbi_open(), the data items are compared lexically, with shorter items collating + * before longer items. + * @warning This function must be called before any data access functions are used, + * otherwise data corruption may occur. The same comparison function must be used by every + * program accessing the database, every time the database is used. + * @param[in] txn A transaction handle returned by #mdb_txn_begin() + * @param[in] dbi A database handle returned by #mdb_dbi_open() + * @param[in] cmp A #MDB_cmp_func function + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • EINVAL - an invalid parameter was specified. + *
+ */ +int mdb_set_dupsort(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp); + + /** @brief Set a relocation function for a #MDB_FIXEDMAP database. + * + * @todo The relocation function is called whenever it is necessary to move the data + * of an item to a different position in the database (e.g. through tree + * balancing operations, shifts as a result of adds or deletes, etc.). It is + * intended to allow address/position-dependent data items to be stored in + * a database in an environment opened with the #MDB_FIXEDMAP option. + * Currently the relocation feature is unimplemented and setting + * this function has no effect. + * @param[in] txn A transaction handle returned by #mdb_txn_begin() + * @param[in] dbi A database handle returned by #mdb_dbi_open() + * @param[in] rel A #MDB_rel_func function + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • EINVAL - an invalid parameter was specified. + *
+ */ +int mdb_set_relfunc(MDB_txn *txn, MDB_dbi dbi, MDB_rel_func *rel); + + /** @brief Set a context pointer for a #MDB_FIXEDMAP database's relocation function. + * + * See #mdb_set_relfunc and #MDB_rel_func for more details. + * @param[in] txn A transaction handle returned by #mdb_txn_begin() + * @param[in] dbi A database handle returned by #mdb_dbi_open() + * @param[in] ctx An arbitrary pointer for whatever the application needs. + * It will be passed to the callback function set by #mdb_set_relfunc + * as its \b relctx parameter whenever the callback is invoked. + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • EINVAL - an invalid parameter was specified. + *
+ */ +int mdb_set_relctx(MDB_txn *txn, MDB_dbi dbi, void *ctx); + + /** @brief Get items from a database. + * + * This function retrieves key/data pairs from the database. The address + * and length of the data associated with the specified \b key are returned + * in the structure to which \b data refers. + * If the database supports duplicate keys (#MDB_DUPSORT) then the + * first data item for the key will be returned. Retrieval of other + * items requires the use of #mdb_cursor_get(). + * + * @note The memory pointed to by the returned values is owned by the + * database. The caller need not dispose of the memory, and may not + * modify it in any way. For values returned in a read-only transaction + * any modification attempts will cause a SIGSEGV. + * @note Values returned from the database are valid only until a + * subsequent update operation, or the end of the transaction. + * @param[in] txn A transaction handle returned by #mdb_txn_begin() + * @param[in] dbi A database handle returned by #mdb_dbi_open() + * @param[in] key The key to search for in the database + * @param[out] data The data corresponding to the key + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • #MDB_NOTFOUND - the key was not in the database. + *
  • EINVAL - an invalid parameter was specified. + *
+ */ +int mdb_get(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data); + + /** @brief Store items into a database. + * + * This function stores key/data pairs in the database. The default behavior + * is to enter the new key/data pair, replacing any previously existing key + * if duplicates are disallowed, or adding a duplicate data item if + * duplicates are allowed (#MDB_DUPSORT). + * @param[in] txn A transaction handle returned by #mdb_txn_begin() + * @param[in] dbi A database handle returned by #mdb_dbi_open() + * @param[in] key The key to store in the database + * @param[in,out] data The data to store + * @param[in] flags Special options for this operation. This parameter + * must be set to 0 or by bitwise OR'ing together one or more of the + * values described here. + *
    + *
  • #MDB_NODUPDATA - enter the new key/data pair only if it does not + * already appear in the database. This flag may only be specified + * if the database was opened with #MDB_DUPSORT. The function will + * return #MDB_KEYEXIST if the key/data pair already appears in the + * database. + *
  • #MDB_NOOVERWRITE - enter the new key/data pair only if the key + * does not already appear in the database. The function will return + * #MDB_KEYEXIST if the key already appears in the database, even if + * the database supports duplicates (#MDB_DUPSORT). The \b data + * parameter will be set to point to the existing item. + *
  • #MDB_RESERVE - reserve space for data of the given size, but + * don't copy the given data. Instead, return a pointer to the + * reserved space, which the caller can fill in later - before + * the next update operation or the transaction ends. This saves + * an extra memcpy if the data is being generated later. + * LMDB does nothing else with this memory, the caller is expected + * to modify all of the space requested. This flag must not be + * specified if the database was opened with #MDB_DUPSORT. + *
  • #MDB_APPEND - append the given key/data pair to the end of the + * database. This option allows fast bulk loading when keys are + * already known to be in the correct order. Loading unsorted keys + * with this flag will cause a #MDB_KEYEXIST error. + *
  • #MDB_APPENDDUP - as above, but for sorted dup data. + *
+ * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • #MDB_MAP_FULL - the database is full, see #mdb_env_set_mapsize(). + *
  • #MDB_TXN_FULL - the transaction has too many dirty pages. + *
  • EACCES - an attempt was made to write in a read-only transaction. + *
  • EINVAL - an invalid parameter was specified. + *
+ */ +int mdb_put(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data, + unsigned int flags); + + /** @brief Delete items from a database. + * + * This function removes key/data pairs from the database. + * If the database does not support sorted duplicate data items + * (#MDB_DUPSORT) the data parameter is ignored. + * If the database supports sorted duplicates and the data parameter + * is NULL, all of the duplicate data items for the key will be + * deleted. Otherwise, if the data parameter is non-NULL + * only the matching data item will be deleted. + * This function will return #MDB_NOTFOUND if the specified key/data + * pair is not in the database. + * @param[in] txn A transaction handle returned by #mdb_txn_begin() + * @param[in] dbi A database handle returned by #mdb_dbi_open() + * @param[in] key The key to delete from the database + * @param[in] data The data to delete + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • EACCES - an attempt was made to write in a read-only transaction. + *
  • EINVAL - an invalid parameter was specified. + *
+ */ +int mdb_del(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data); + + /** @brief Create a cursor handle. + * + * A cursor is associated with a specific transaction and database. + * A cursor cannot be used when its database handle is closed. Nor + * when its transaction has ended, except with #mdb_cursor_renew(). + * It can be discarded with #mdb_cursor_close(). + * A cursor in a write-transaction can be closed before its transaction + * ends, and will otherwise be closed when its transaction ends. + * A cursor in a read-only transaction must be closed explicitly, before + * or after its transaction ends. It can be reused with + * #mdb_cursor_renew() before finally closing it. + * @note Earlier documentation said that cursors in every transaction + * were closed when the transaction committed or aborted. + * @param[in] txn A transaction handle returned by #mdb_txn_begin() + * @param[in] dbi A database handle returned by #mdb_dbi_open() + * @param[out] cursor Address where the new #MDB_cursor handle will be stored + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • EINVAL - an invalid parameter was specified. + *
+ */ +int mdb_cursor_open(MDB_txn *txn, MDB_dbi dbi, MDB_cursor **cursor); + + /** @brief Close a cursor handle. + * + * The cursor handle will be freed and must not be used again after this call. + * Its transaction must still be live if it is a write-transaction. + * @param[in] cursor A cursor handle returned by #mdb_cursor_open() + */ +void mdb_cursor_close(MDB_cursor *cursor); + + /** @brief Renew a cursor handle. + * + * A cursor is associated with a specific transaction and database. + * Cursors that are only used in read-only + * transactions may be re-used, to avoid unnecessary malloc/free overhead. + * The cursor may be associated with a new read-only transaction, and + * referencing the same database handle as it was created with. + * This may be done whether the previous transaction is live or dead. + * @param[in] txn A transaction handle returned by #mdb_txn_begin() + * @param[in] cursor A cursor handle returned by #mdb_cursor_open() + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • EINVAL - an invalid parameter was specified. + *
+ */ +int mdb_cursor_renew(MDB_txn *txn, MDB_cursor *cursor); + + /** @brief Return the cursor's transaction handle. + * + * @param[in] cursor A cursor handle returned by #mdb_cursor_open() + */ +MDB_txn *mdb_cursor_txn(MDB_cursor *cursor); + + /** @brief Return the cursor's database handle. + * + * @param[in] cursor A cursor handle returned by #mdb_cursor_open() + */ +MDB_dbi mdb_cursor_dbi(MDB_cursor *cursor); + + /** @brief Retrieve by cursor. + * + * This function retrieves key/data pairs from the database. The address and length + * of the key are returned in the object to which \b key refers (except for the + * case of the #MDB_SET option, in which the \b key object is unchanged), and + * the address and length of the data are returned in the object to which \b data + * refers. + * See #mdb_get() for restrictions on using the output values. + * @param[in] cursor A cursor handle returned by #mdb_cursor_open() + * @param[in,out] key The key for a retrieved item + * @param[in,out] data The data of a retrieved item + * @param[in] op A cursor operation #MDB_cursor_op + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • #MDB_NOTFOUND - no matching key found. + *
  • EINVAL - an invalid parameter was specified. + *
+ */ +int mdb_cursor_get(MDB_cursor *cursor, MDB_val *key, MDB_val *data, + MDB_cursor_op op); + + /** @brief Store by cursor. + * + * This function stores key/data pairs into the database. + * The cursor is positioned at the new item, or on failure usually near it. + * @note Earlier documentation incorrectly said errors would leave the + * state of the cursor unchanged. + * @param[in] cursor A cursor handle returned by #mdb_cursor_open() + * @param[in] key The key operated on. + * @param[in] data The data operated on. + * @param[in] flags Options for this operation. This parameter + * must be set to 0 or one of the values described here. + *
    + *
  • #MDB_CURRENT - replace the item at the current cursor position. + * The \b key parameter must still be provided, and must match it. + * If using sorted duplicates (#MDB_DUPSORT) the data item must still + * sort into the same place. This is intended to be used when the + * new data is the same size as the old. Otherwise it will simply + * perform a delete of the old record followed by an insert. + *
  • #MDB_NODUPDATA - enter the new key/data pair only if it does not + * already appear in the database. This flag may only be specified + * if the database was opened with #MDB_DUPSORT. The function will + * return #MDB_KEYEXIST if the key/data pair already appears in the + * database. + *
  • #MDB_NOOVERWRITE - enter the new key/data pair only if the key + * does not already appear in the database. The function will return + * #MDB_KEYEXIST if the key already appears in the database, even if + * the database supports duplicates (#MDB_DUPSORT). + *
  • #MDB_RESERVE - reserve space for data of the given size, but + * don't copy the given data. Instead, return a pointer to the + * reserved space, which the caller can fill in later - before + * the next update operation or the transaction ends. This saves + * an extra memcpy if the data is being generated later. This flag + * must not be specified if the database was opened with #MDB_DUPSORT. + *
  • #MDB_APPEND - append the given key/data pair to the end of the + * database. No key comparisons are performed. This option allows + * fast bulk loading when keys are already known to be in the + * correct order. Loading unsorted keys with this flag will cause + * a #MDB_KEYEXIST error. + *
  • #MDB_APPENDDUP - as above, but for sorted dup data. + *
  • #MDB_MULTIPLE - store multiple contiguous data elements in a + * single request. This flag may only be specified if the database + * was opened with #MDB_DUPFIXED. The \b data argument must be an + * array of two MDB_vals. The mv_size of the first MDB_val must be + * the size of a single data element. The mv_data of the first MDB_val + * must point to the beginning of the array of contiguous data elements. + * The mv_size of the second MDB_val must be the count of the number + * of data elements to store. On return this field will be set to + * the count of the number of elements actually written. The mv_data + * of the second MDB_val is unused. + *
+ * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • #MDB_MAP_FULL - the database is full, see #mdb_env_set_mapsize(). + *
  • #MDB_TXN_FULL - the transaction has too many dirty pages. + *
  • EACCES - an attempt was made to write in a read-only transaction. + *
  • EINVAL - an invalid parameter was specified. + *
+ */ +int mdb_cursor_put(MDB_cursor *cursor, MDB_val *key, MDB_val *data, + unsigned int flags); + + /** @brief Delete current key/data pair + * + * This function deletes the key/data pair to which the cursor refers. + * @param[in] cursor A cursor handle returned by #mdb_cursor_open() + * @param[in] flags Options for this operation. This parameter + * must be set to 0 or one of the values described here. + *
    + *
  • #MDB_NODUPDATA - delete all of the data items for the current key. + * This flag may only be specified if the database was opened with #MDB_DUPSORT. + *
+ * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • EACCES - an attempt was made to write in a read-only transaction. + *
  • EINVAL - an invalid parameter was specified. + *
+ */ +int mdb_cursor_del(MDB_cursor *cursor, unsigned int flags); + + /** @brief Return count of duplicates for current key. + * + * This call is only valid on databases that support sorted duplicate + * data items #MDB_DUPSORT. + * @param[in] cursor A cursor handle returned by #mdb_cursor_open() + * @param[out] countp Address where the count will be stored + * @return A non-zero error value on failure and 0 on success. Some possible + * errors are: + *
    + *
  • EINVAL - cursor is not initialized, or an invalid parameter was specified. + *
+ */ +int mdb_cursor_count(MDB_cursor *cursor, mdb_size_t *countp); + + /** @brief Compare two data items according to a particular database. + * + * This returns a comparison as if the two data items were keys in the + * specified database. + * @param[in] txn A transaction handle returned by #mdb_txn_begin() + * @param[in] dbi A database handle returned by #mdb_dbi_open() + * @param[in] a The first item to compare + * @param[in] b The second item to compare + * @return < 0 if a < b, 0 if a == b, > 0 if a > b + */ +int mdb_cmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b); + + /** @brief Compare two data items according to a particular database. + * + * This returns a comparison as if the two items were data items of + * the specified database. The database must have the #MDB_DUPSORT flag. + * @param[in] txn A transaction handle returned by #mdb_txn_begin() + * @param[in] dbi A database handle returned by #mdb_dbi_open() + * @param[in] a The first item to compare + * @param[in] b The second item to compare + * @return < 0 if a < b, 0 if a == b, > 0 if a > b + */ +int mdb_dcmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b); + + /** @brief A callback function used to print a message from the library. + * + * @param[in] msg The string to be printed. + * @param[in] ctx An arbitrary context pointer for the callback. + * @return < 0 on failure, >= 0 on success. + */ +typedef int (MDB_msg_func)(const char *msg, void *ctx); + + /** @brief Dump the entries in the reader lock table. + * + * @param[in] env An environment handle returned by #mdb_env_create() + * @param[in] func A #MDB_msg_func function + * @param[in] ctx Anything the message function needs + * @return < 0 on failure, >= 0 on success. + */ +int mdb_reader_list(MDB_env *env, MDB_msg_func *func, void *ctx); + + /** @brief Check for stale entries in the reader lock table. + * + * @param[in] env An environment handle returned by #mdb_env_create() + * @param[out] dead Number of stale slots that were cleared + * @return 0 on success, non-zero on failure. + */ +int mdb_reader_check(MDB_env *env, int *dead); +/** @} */ + +#ifdef __cplusplus +} +#endif +/** @page tools LMDB Command Line Tools + The following describes the command line tools that are available for LMDB. + \li \ref mdb_copy_1 + \li \ref mdb_dump_1 + \li \ref mdb_load_1 + \li \ref mdb_stat_1 +*/ + +#endif /* _LMDB_H_ */ diff --git a/contrib/db/liblmdb/mdb.c b/contrib/db/liblmdb/mdb.c new file mode 100644 index 00000000..ca9f3b12 --- /dev/null +++ b/contrib/db/liblmdb/mdb.c @@ -0,0 +1,10943 @@ +/** @file mdb.c + * @brief Lightning memory-mapped database library + * + * A Btree-based database management library modeled loosely on the + * BerkeleyDB API, but much simplified. + */ +/* + * Copyright 2011-2016 Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + * + * This code is derived from btree.c written by Martin Hedenfalk. + * + * Copyright (c) 2009, 2010 Martin Hedenfalk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif +#if defined(MDB_VL32) || defined(__WIN64__) +#define _FILE_OFFSET_BITS 64 +#endif +#ifdef _WIN32 +#include +#include +#include + +#ifndef _NTDEF_ +typedef _Return_type_success_(return >= 0) LONG NTSTATUS; +typedef NTSTATUS *PNTSTATUS; +#endif + +/** Visual studio big files support +*/ + +/* We use native NT APIs to setup the memory map, so that we can + * let the DB file grow incrementally instead of always preallocating + * the full size. These APIs are defined in and + * but those headers are meant for driver-level development and + * conflict with the regular user-level headers, so we explicitly + * declare them here. Using these APIs also means we must link to + * ntdll.dll, which is not linked by default in user code. + */ +NTSTATUS WINAPI +NtCreateSection(OUT PHANDLE sh, IN ACCESS_MASK acc, + IN void * oa OPTIONAL, + IN PLARGE_INTEGER ms OPTIONAL, + IN ULONG pp, IN ULONG aa, IN HANDLE fh OPTIONAL); + +typedef enum _SECTION_INHERIT { + ViewShare = 1, + ViewUnmap = 2 +} SECTION_INHERIT; + +NTSTATUS WINAPI +NtMapViewOfSection(IN PHANDLE sh, IN HANDLE ph, + IN OUT PVOID *addr, IN ULONG_PTR zbits, + IN SIZE_T cs, IN OUT PLARGE_INTEGER off OPTIONAL, + IN OUT PSIZE_T vs, IN SECTION_INHERIT ih, + IN ULONG at, IN ULONG pp); + +NTSTATUS WINAPI +NtClose(HANDLE h); + +/** getpid() returns int; MinGW defines pid_t but MinGW64 typedefs it + * as int64 which is wrong. MSVC doesn't define it at all, so just + * don't use it. + */ +#define MDB_PID_T int +#define MDB_THR_T DWORD +#include +#include +#ifdef __GNUC__ +# include +#else +# define LITTLE_ENDIAN 1234 +# define BIG_ENDIAN 4321 +# define BYTE_ORDER LITTLE_ENDIAN +# ifndef SSIZE_MAX +# define SSIZE_MAX INT_MAX +# endif +#endif +#else +#include +#include +#define MDB_PID_T pid_t +#define MDB_THR_T pthread_t +#include +#include +#include +#ifdef HAVE_SYS_FILE_H +#include +#endif +#include +#endif + +#if defined(__mips) && defined(__linux) +/* MIPS has cache coherency issues, requires explicit cache control */ +#include +extern int cacheflush(char *addr, int nbytes, int cache); +#define CACHEFLUSH(addr, bytes, cache) cacheflush(addr, bytes, cache) +#else +#define CACHEFLUSH(addr, bytes, cache) +#endif + +#if defined(__linux) && !defined(MDB_FDATASYNC_WORKS) +/** fdatasync is broken on ext3/ext4fs on older kernels, see + * description in #mdb_env_open2 comments. You can safely + * define MDB_FDATASYNC_WORKS if this code will only be run + * on kernels 3.6 and newer. + */ +#define BROKEN_FDATASYNC +#endif + +#ifdef _WIN32 +typedef int64_t off64_t; +#else +typedef off_t off64_t; +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#include +typedef SSIZE_T ssize_t; +#else +#include +#endif + +#if defined(__sun) || defined(__ANDROID__) +/* Most platforms have posix_memalign, older may only have memalign */ +#define HAVE_MEMALIGN 1 +#include +#endif + +#if !(defined(BYTE_ORDER) || defined(__BYTE_ORDER)) +#include +#include /* defines BYTE_ORDER on HPUX and Solaris */ +#endif + +#if defined(__APPLE__) || defined (BSD) +# if !(defined(MDB_USE_POSIX_MUTEX) || defined(MDB_USE_POSIX_SEM)) +# define MDB_USE_SYSV_SEM 1 +# endif +# define MDB_FDATASYNC fsync +#elif defined(__ANDROID__) +# define MDB_FDATASYNC fsync +#endif + +#ifndef _WIN32 +#include +#ifdef MDB_USE_POSIX_SEM +# define MDB_USE_HASH 1 +#include +#elif defined(MDB_USE_SYSV_SEM) +#include +#include +#ifdef _SEM_SEMUN_UNDEFINED +union semun { + int val; + struct semid_ds *buf; + unsigned short *array; +}; +#endif /* _SEM_SEMUN_UNDEFINED */ +#else +#define MDB_USE_POSIX_MUTEX 1 +#endif /* MDB_USE_POSIX_SEM */ +#endif /* !_WIN32 */ + +#if defined(_WIN32) + defined(MDB_USE_POSIX_SEM) + defined(MDB_USE_SYSV_SEM) \ + + defined(MDB_USE_POSIX_MUTEX) != 1 +# error "Ambiguous shared-lock implementation" +#endif + +#ifdef USE_VALGRIND +#include +#define VGMEMP_CREATE(h,r,z) VALGRIND_CREATE_MEMPOOL(h,r,z) +#define VGMEMP_ALLOC(h,a,s) VALGRIND_MEMPOOL_ALLOC(h,a,s) +#define VGMEMP_FREE(h,a) VALGRIND_MEMPOOL_FREE(h,a) +#define VGMEMP_DESTROY(h) VALGRIND_DESTROY_MEMPOOL(h) +#define VGMEMP_DEFINED(a,s) VALGRIND_MAKE_MEM_DEFINED(a,s) +#else +#define VGMEMP_CREATE(h,r,z) +#define VGMEMP_ALLOC(h,a,s) +#define VGMEMP_FREE(h,a) +#define VGMEMP_DESTROY(h) +#define VGMEMP_DEFINED(a,s) +#endif + +#ifndef BYTE_ORDER +# if (defined(_LITTLE_ENDIAN) || defined(_BIG_ENDIAN)) && !(defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)) +/* Solaris just defines one or the other */ +# define LITTLE_ENDIAN 1234 +# define BIG_ENDIAN 4321 +# ifdef _LITTLE_ENDIAN +# define BYTE_ORDER LITTLE_ENDIAN +# else +# define BYTE_ORDER BIG_ENDIAN +# endif +# else +# define BYTE_ORDER __BYTE_ORDER +# endif +#endif + +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN __LITTLE_ENDIAN +#endif +#ifndef BIG_ENDIAN +#define BIG_ENDIAN __BIG_ENDIAN +#endif + +#if defined(__i386) || defined(__x86_64) || defined(_M_IX86) +#define MISALIGNED_OK 1 +#endif + +#include "lmdb.h" +#include "midl.h" + +#if (BYTE_ORDER == LITTLE_ENDIAN) == (BYTE_ORDER == BIG_ENDIAN) +# error "Unknown or unsupported endianness (BYTE_ORDER)" +#elif (-6 & 5) || CHAR_BIT != 8 || UINT_MAX < 0xffffffff || ULONG_MAX % 0xFFFF +# error "Two's complement, reasonably sized integer types, please" +#endif + +#ifdef __GNUC__ +/** Put infrequently used env functions in separate section */ +# ifdef __APPLE__ +# define ESECT __attribute__ ((section("__TEXT,text_env"))) +# else +# define ESECT __attribute__ ((section("text_env"))) +# endif +#else +#define ESECT +#endif + +#ifdef _WIN32 +#define CALL_CONV WINAPI +#else +#define CALL_CONV +#endif + +/** @defgroup internal LMDB Internals + * @{ + */ +/** @defgroup compat Compatibility Macros + * A bunch of macros to minimize the amount of platform-specific ifdefs + * needed throughout the rest of the code. When the features this library + * needs are similar enough to POSIX to be hidden in a one-or-two line + * replacement, this macro approach is used. + * @{ + */ + + /** Features under development */ +#ifndef MDB_DEVEL +#define MDB_DEVEL 0 +#endif + + /** Wrapper around __func__, which is a C99 feature */ +#if __STDC_VERSION__ >= 199901L +# define mdb_func_ __func__ +#elif __GNUC__ >= 2 || _MSC_VER >= 1300 +# define mdb_func_ __FUNCTION__ +#else +/* If a debug message says (), update the #if statements above */ +# define mdb_func_ "" +#endif + +/* Internal error codes, not exposed outside liblmdb */ +#define MDB_NO_ROOT (MDB_LAST_ERRCODE + 10) +#ifdef _WIN32 +#define MDB_OWNERDEAD ((int) WAIT_ABANDONED) +#elif defined MDB_USE_SYSV_SEM +#define MDB_OWNERDEAD (MDB_LAST_ERRCODE + 11) +#elif defined(MDB_USE_POSIX_MUTEX) && defined(EOWNERDEAD) +#define MDB_OWNERDEAD EOWNERDEAD /**< #LOCK_MUTEX0() result if dead owner */ +#endif + +#ifdef __GLIBC__ +#define GLIBC_VER ((__GLIBC__ << 16 )| __GLIBC_MINOR__) +#endif +/** Some platforms define the EOWNERDEAD error code + * even though they don't support Robust Mutexes. + * Compile with -DMDB_USE_ROBUST=0, or use some other + * mechanism like -DMDB_USE_SYSV_SEM instead of + * -DMDB_USE_POSIX_MUTEX. (SysV semaphores are + * also Robust, but some systems don't support them + * either.) + */ +#ifndef MDB_USE_ROBUST +/* Android currently lacks Robust Mutex support. So does glibc < 2.4. */ +# if defined(MDB_USE_POSIX_MUTEX) && (defined(__ANDROID__) || \ + (defined(__GLIBC__) && GLIBC_VER < 0x020004)) +# define MDB_USE_ROBUST 0 +# else +# define MDB_USE_ROBUST 1 +/* glibc < 2.12 only provided _np API */ +# if defined(__GLIBC__) && GLIBC_VER < 0x02000c +# define PTHREAD_MUTEX_ROBUST PTHREAD_MUTEX_ROBUST_NP +# define pthread_mutexattr_setrobust(attr, flag) pthread_mutexattr_setrobust_np(attr, flag) +# define pthread_mutex_consistent(mutex) pthread_mutex_consistent_np(mutex) +# endif +# endif +#endif /* MDB_USE_ROBUST */ + +#if defined(MDB_OWNERDEAD) && MDB_USE_ROBUST +#define MDB_ROBUST_SUPPORTED 1 +#endif + +#ifdef _WIN32 +#define MDB_USE_HASH 1 +#define MDB_PIDLOCK 0 +#define THREAD_RET DWORD +#define pthread_t HANDLE +#define pthread_mutex_t HANDLE +#define pthread_cond_t HANDLE +typedef HANDLE mdb_mutex_t, mdb_mutexref_t; +#define pthread_key_t DWORD +#define pthread_self() GetCurrentThreadId() +#define pthread_key_create(x,y) \ + ((*(x) = TlsAlloc()) == TLS_OUT_OF_INDEXES ? ErrCode() : 0) +#define pthread_key_delete(x) TlsFree(x) +#define pthread_getspecific(x) TlsGetValue(x) +#define pthread_setspecific(x,y) (TlsSetValue(x,y) ? 0 : ErrCode()) +#define pthread_mutex_unlock(x) ReleaseMutex(*x) +#define pthread_mutex_lock(x) WaitForSingleObject(*x, INFINITE) +#define pthread_cond_signal(x) SetEvent(*x) +#define pthread_cond_wait(cond,mutex) do{SignalObjectAndWait(*mutex, *cond, INFINITE, FALSE); WaitForSingleObject(*mutex, INFINITE);}while(0) +#define THREAD_CREATE(thr,start,arg) thr=CreateThread(NULL,0,start,arg,0,NULL) +#define THREAD_FINISH(thr) WaitForSingleObject(thr, INFINITE) +#define LOCK_MUTEX0(mutex) WaitForSingleObject(mutex, INFINITE) +#define UNLOCK_MUTEX(mutex) ReleaseMutex(mutex) +#define mdb_mutex_consistent(mutex) 0 +#define getpid() GetCurrentProcessId() +#define MDB_FDATASYNC(fd) (!FlushFileBuffers(fd)) +#define MDB_MSYNC(addr,len,flags) (!FlushViewOfFile(addr,len)) +#define ErrCode() GetLastError() +#define GET_PAGESIZE(x) {SYSTEM_INFO si; GetSystemInfo(&si); (x) = si.dwPageSize;} +#define close(fd) (CloseHandle(fd) ? 0 : -1) +#define munmap(ptr,len) UnmapViewOfFile(ptr) +#ifdef PROCESS_QUERY_LIMITED_INFORMATION +#define MDB_PROCESS_QUERY_LIMITED_INFORMATION PROCESS_QUERY_LIMITED_INFORMATION +#else +#define MDB_PROCESS_QUERY_LIMITED_INFORMATION 0x1000 +#endif +#define Z "I" +#else +#define THREAD_RET void * +#define THREAD_CREATE(thr,start,arg) pthread_create(&thr,NULL,start,arg) +#define THREAD_FINISH(thr) pthread_join(thr,NULL) +#define Z "z" /**< printf format modifier for size_t */ + + /** For MDB_LOCK_FORMAT: True if readers take a pid lock in the lockfile */ +#define MDB_PIDLOCK 1 + +#ifdef MDB_USE_POSIX_SEM + +typedef sem_t *mdb_mutex_t, *mdb_mutexref_t; +#define LOCK_MUTEX0(mutex) mdb_sem_wait(mutex) +#define UNLOCK_MUTEX(mutex) sem_post(mutex) + +static int +mdb_sem_wait(sem_t *sem) +{ + int rc; + while ((rc = sem_wait(sem)) && (rc = errno) == EINTR) ; + return rc; +} + +#elif defined MDB_USE_SYSV_SEM + +typedef struct mdb_mutex { + int semid; + int semnum; + int *locked; +} mdb_mutex_t[1], *mdb_mutexref_t; + +#define LOCK_MUTEX0(mutex) mdb_sem_wait(mutex) +#define UNLOCK_MUTEX(mutex) do { \ + struct sembuf sb = { 0, 1, SEM_UNDO }; \ + sb.sem_num = (mutex)->semnum; \ + *(mutex)->locked = 0; \ + semop((mutex)->semid, &sb, 1); \ +} while(0) + +static int +mdb_sem_wait(mdb_mutexref_t sem) +{ + int rc, *locked = sem->locked; + struct sembuf sb = { 0, -1, SEM_UNDO }; + sb.sem_num = sem->semnum; + do { + if (!semop(sem->semid, &sb, 1)) { + rc = *locked ? MDB_OWNERDEAD : MDB_SUCCESS; + *locked = 1; + break; + } + } while ((rc = errno) == EINTR); + return rc; +} + +#define mdb_mutex_consistent(mutex) 0 + +#else /* MDB_USE_POSIX_MUTEX: */ + /** Shared mutex/semaphore as it is stored (mdb_mutex_t), and as + * local variables keep it (mdb_mutexref_t). + * + * An mdb_mutex_t can be assigned to an mdb_mutexref_t. They can + * be the same, or an array[size 1] and a pointer. + * @{ + */ +typedef pthread_mutex_t mdb_mutex_t[1], *mdb_mutexref_t; + /* @} */ + /** Lock the reader or writer mutex. + * Returns 0 or a code to give #mdb_mutex_failed(), as in #LOCK_MUTEX(). + */ +#define LOCK_MUTEX0(mutex) pthread_mutex_lock(mutex) + /** Unlock the reader or writer mutex. + */ +#define UNLOCK_MUTEX(mutex) pthread_mutex_unlock(mutex) + /** Mark mutex-protected data as repaired, after death of previous owner. + */ +#define mdb_mutex_consistent(mutex) pthread_mutex_consistent(mutex) +#endif /* MDB_USE_POSIX_SEM || MDB_USE_SYSV_SEM */ + + /** Get the error code for the last failed system function. + */ +#define ErrCode() errno + + /** An abstraction for a file handle. + * On POSIX systems file handles are small integers. On Windows + * they're opaque pointers. + */ +#define HANDLE int + + /** A value for an invalid file handle. + * Mainly used to initialize file variables and signify that they are + * unused. + */ +#define INVALID_HANDLE_VALUE (-1) + + /** Get the size of a memory page for the system. + * This is the basic size that the platform's memory manager uses, and is + * fundamental to the use of memory-mapped files. + */ +#define GET_PAGESIZE(x) ((x) = sysconf(_SC_PAGE_SIZE)) +#endif + +#ifdef MDB_VL32 +#ifdef _WIN32 +#define Y "I64" +#else +#define Y "ll" +#endif +#else +#define Y Z +#endif + +#if defined(_WIN32) || defined(MDB_USE_POSIX_SEM) +#define MNAME_LEN 32 +#elif defined(MDB_USE_SYSV_SEM) +#define MNAME_LEN (sizeof(int)) +#else +#define MNAME_LEN (sizeof(pthread_mutex_t)) +#endif + +#ifdef MDB_USE_SYSV_SEM +#define SYSV_SEM_FLAG 1 /**< SysV sems in lockfile format */ +#else +#define SYSV_SEM_FLAG 0 +#endif + +/** @} */ + +#ifdef MDB_ROBUST_SUPPORTED + /** Lock mutex, handle any error, set rc = result. + * Return 0 on success, nonzero (not rc) on error. + */ +#define LOCK_MUTEX(rc, env, mutex) \ + (((rc) = LOCK_MUTEX0(mutex)) && \ + ((rc) = mdb_mutex_failed(env, mutex, rc))) +static int mdb_mutex_failed(MDB_env *env, mdb_mutexref_t mutex, int rc); +#else +#define LOCK_MUTEX(rc, env, mutex) ((rc) = LOCK_MUTEX0(mutex)) +#define mdb_mutex_failed(env, mutex, rc) (rc) +#endif + +#ifndef _WIN32 +/** A flag for opening a file and requesting synchronous data writes. + * This is only used when writing a meta page. It's not strictly needed; + * we could just do a normal write and then immediately perform a flush. + * But if this flag is available it saves us an extra system call. + * + * @note If O_DSYNC is undefined but exists in /usr/include, + * preferably set some compiler flag to get the definition. + */ +#ifndef MDB_DSYNC +# ifdef O_DSYNC +# define MDB_DSYNC O_DSYNC +# else +# define MDB_DSYNC O_SYNC +# endif +#endif +#endif + +/** Function for flushing the data of a file. Define this to fsync + * if fdatasync() is not supported. + */ +#ifndef MDB_FDATASYNC +# define MDB_FDATASYNC fdatasync +#endif + +#ifndef MDB_MSYNC +# define MDB_MSYNC(addr,len,flags) msync(addr,len,flags) +#endif + +#ifndef MS_SYNC +#define MS_SYNC 1 +#endif + +#ifndef MS_ASYNC +#define MS_ASYNC 0 +#endif + + /** A page number in the database. + * Note that 64 bit page numbers are overkill, since pages themselves + * already represent 12-13 bits of addressable memory, and the OS will + * always limit applications to a maximum of 63 bits of address space. + * + * @note In the #MDB_node structure, we only store 48 bits of this value, + * which thus limits us to only 60 bits of addressable data. + */ +typedef MDB_ID pgno_t; + + /** A transaction ID. + * See struct MDB_txn.mt_txnid for details. + */ +typedef MDB_ID txnid_t; + +/** @defgroup debug Debug Macros + * @{ + */ +#ifndef MDB_DEBUG + /** Enable debug output. Needs variable argument macros (a C99 feature). + * Set this to 1 for copious tracing. Set to 2 to add dumps of all IDLs + * read from and written to the database (used for free space management). + */ +#define MDB_DEBUG 0 +#endif + +#if MDB_DEBUG +static int mdb_debug; +static txnid_t mdb_debug_start; + + /** Print a debug message with printf formatting. + * Requires double parenthesis around 2 or more args. + */ +# define DPRINTF(args) ((void) ((mdb_debug) && DPRINTF0 args)) +# define DPRINTF0(fmt, ...) \ + fprintf(stderr, "%s:%d " fmt "\n", mdb_func_, __LINE__, __VA_ARGS__) +#else +# define DPRINTF(args) ((void) 0) +#endif + /** Print a debug string. + * The string is printed literally, with no format processing. + */ +#define DPUTS(arg) DPRINTF(("%s", arg)) + /** Debuging output value of a cursor DBI: Negative in a sub-cursor. */ +#define DDBI(mc) \ + (((mc)->mc_flags & C_SUB) ? -(int)(mc)->mc_dbi : (int)(mc)->mc_dbi) +/** @} */ + + /** @brief The maximum size of a database page. + * + * It is 32k or 64k, since value-PAGEBASE must fit in + * #MDB_page.%mp_upper. + * + * LMDB will use database pages < OS pages if needed. + * That causes more I/O in write transactions: The OS must + * know (read) the whole page before writing a partial page. + * + * Note that we don't currently support Huge pages. On Linux, + * regular data files cannot use Huge pages, and in general + * Huge pages aren't actually pageable. We rely on the OS + * demand-pager to read our data and page it out when memory + * pressure from other processes is high. So until OSs have + * actual paging support for Huge pages, they're not viable. + */ +#define MAX_PAGESIZE (PAGEBASE ? 0x10000 : 0x8000) + + /** The minimum number of keys required in a database page. + * Setting this to a larger value will place a smaller bound on the + * maximum size of a data item. Data items larger than this size will + * be pushed into overflow pages instead of being stored directly in + * the B-tree node. This value used to default to 4. With a page size + * of 4096 bytes that meant that any item larger than 1024 bytes would + * go into an overflow page. That also meant that on average 2-3KB of + * each overflow page was wasted space. The value cannot be lower than + * 2 because then there would no longer be a tree structure. With this + * value, items larger than 2KB will go into overflow pages, and on + * average only 1KB will be wasted. + */ +#define MDB_MINKEYS 2 + + /** A stamp that identifies a file as an LMDB file. + * There's nothing special about this value other than that it is easily + * recognizable, and it will reflect any byte order mismatches. + */ +#define MDB_MAGIC 0xBEEFC0DE + + /** The version number for a database's datafile format. */ +#define MDB_DATA_VERSION ((MDB_DEVEL) ? 999 : 1) + /** The version number for a database's lockfile format. */ +#define MDB_LOCK_VERSION ((MDB_DEVEL) ? 999 : 1) + + /** @brief The max size of a key we can write, or 0 for computed max. + * + * This macro should normally be left alone or set to 0. + * Note that a database with big keys or dupsort data cannot be + * reliably modified by a liblmdb which uses a smaller max. + * The default is 511 for backwards compat, or 0 when #MDB_DEVEL. + * + * Other values are allowed, for backwards compat. However: + * A value bigger than the computed max can break if you do not + * know what you are doing, and liblmdb <= 0.9.10 can break when + * modifying a DB with keys/dupsort data bigger than its max. + * + * Data items in an #MDB_DUPSORT database are also limited to + * this size, since they're actually keys of a sub-DB. Keys and + * #MDB_DUPSORT data items must fit on a node in a regular page. + */ +#ifndef MDB_MAXKEYSIZE +#define MDB_MAXKEYSIZE ((MDB_DEVEL) ? 0 : 511) +#endif + + /** The maximum size of a key we can write to the environment. */ +#if MDB_MAXKEYSIZE +#define ENV_MAXKEY(env) (MDB_MAXKEYSIZE) +#else +#define ENV_MAXKEY(env) ((env)->me_maxkey) +#endif + + /** @brief The maximum size of a data item. + * + * We only store a 32 bit value for node sizes. + */ +#define MAXDATASIZE 0xffffffffUL + +#if MDB_DEBUG + /** Key size which fits in a #DKBUF. + * @ingroup debug + */ +#define DKBUF_MAXKEYSIZE ((MDB_MAXKEYSIZE) > 0 ? (MDB_MAXKEYSIZE) : 511) + /** A key buffer. + * @ingroup debug + * This is used for printing a hex dump of a key's contents. + */ +#define DKBUF char kbuf[DKBUF_MAXKEYSIZE*2+1] + /** Display a key in hex. + * @ingroup debug + * Invoke a function to display a key in hex. + */ +#define DKEY(x) mdb_dkey(x, kbuf) +#else +#define DKBUF +#define DKEY(x) 0 +#endif + + /** An invalid page number. + * Mainly used to denote an empty tree. + */ +#define P_INVALID (~(pgno_t)0) + + /** Test if the flags \b f are set in a flag word \b w. */ +#define F_ISSET(w, f) (((w) & (f)) == (f)) + + /** Round \b n up to an even number. */ +#define EVEN(n) (((n) + 1U) & -2) /* sign-extending -2 to match n+1U */ + + /** Used for offsets within a single page. + * Since memory pages are typically 4 or 8KB in size, 12-13 bits, + * this is plenty. + */ +typedef uint16_t indx_t; + + /** Default size of memory map. + * This is certainly too small for any actual applications. Apps should always set + * the size explicitly using #mdb_env_set_mapsize(). + */ +#define DEFAULT_MAPSIZE 1048576 + +/** @defgroup readers Reader Lock Table + * Readers don't acquire any locks for their data access. Instead, they + * simply record their transaction ID in the reader table. The reader + * mutex is needed just to find an empty slot in the reader table. The + * slot's address is saved in thread-specific data so that subsequent read + * transactions started by the same thread need no further locking to proceed. + * + * If #MDB_NOTLS is set, the slot address is not saved in thread-specific data. + * + * No reader table is used if the database is on a read-only filesystem, or + * if #MDB_NOLOCK is set. + * + * Since the database uses multi-version concurrency control, readers don't + * actually need any locking. This table is used to keep track of which + * readers are using data from which old transactions, so that we'll know + * when a particular old transaction is no longer in use. Old transactions + * that have discarded any data pages can then have those pages reclaimed + * for use by a later write transaction. + * + * The lock table is constructed such that reader slots are aligned with the + * processor's cache line size. Any slot is only ever used by one thread. + * This alignment guarantees that there will be no contention or cache + * thrashing as threads update their own slot info, and also eliminates + * any need for locking when accessing a slot. + * + * A writer thread will scan every slot in the table to determine the oldest + * outstanding reader transaction. Any freed pages older than this will be + * reclaimed by the writer. The writer doesn't use any locks when scanning + * this table. This means that there's no guarantee that the writer will + * see the most up-to-date reader info, but that's not required for correct + * operation - all we need is to know the upper bound on the oldest reader, + * we don't care at all about the newest reader. So the only consequence of + * reading stale information here is that old pages might hang around a + * while longer before being reclaimed. That's actually good anyway, because + * the longer we delay reclaiming old pages, the more likely it is that a + * string of contiguous pages can be found after coalescing old pages from + * many old transactions together. + * @{ + */ + /** Number of slots in the reader table. + * This value was chosen somewhat arbitrarily. 126 readers plus a + * couple mutexes fit exactly into 8KB on my development machine. + * Applications should set the table size using #mdb_env_set_maxreaders(). + */ +#define DEFAULT_READERS 126 + + /** The size of a CPU cache line in bytes. We want our lock structures + * aligned to this size to avoid false cache line sharing in the + * lock table. + * This value works for most CPUs. For Itanium this should be 128. + */ +#ifndef CACHELINE +#define CACHELINE 64 +#endif + + /** The information we store in a single slot of the reader table. + * In addition to a transaction ID, we also record the process and + * thread ID that owns a slot, so that we can detect stale information, + * e.g. threads or processes that went away without cleaning up. + * @note We currently don't check for stale records. We simply re-init + * the table when we know that we're the only process opening the + * lock file. + */ +typedef struct MDB_rxbody { + /** Current Transaction ID when this transaction began, or (txnid_t)-1. + * Multiple readers that start at the same time will probably have the + * same ID here. Again, it's not important to exclude them from + * anything; all we need to know is which version of the DB they + * started from so we can avoid overwriting any data used in that + * particular version. + */ + volatile txnid_t mrb_txnid; + /** The process ID of the process owning this reader txn. */ + volatile MDB_PID_T mrb_pid; + /** The thread ID of the thread owning this txn. */ + volatile MDB_THR_T mrb_tid; +} MDB_rxbody; + + /** The actual reader record, with cacheline padding. */ +typedef struct MDB_reader { + union { + MDB_rxbody mrx; + /** shorthand for mrb_txnid */ +#define mr_txnid mru.mrx.mrb_txnid +#define mr_pid mru.mrx.mrb_pid +#define mr_tid mru.mrx.mrb_tid + /** cache line alignment */ + char pad[(sizeof(MDB_rxbody)+CACHELINE-1) & ~(CACHELINE-1)]; + } mru; +} MDB_reader; + + /** The header for the reader table. + * The table resides in a memory-mapped file. (This is a different file + * than is used for the main database.) + * + * For POSIX the actual mutexes reside in the shared memory of this + * mapped file. On Windows, mutexes are named objects allocated by the + * kernel; we store the mutex names in this mapped file so that other + * processes can grab them. This same approach is also used on + * MacOSX/Darwin (using named semaphores) since MacOSX doesn't support + * process-shared POSIX mutexes. For these cases where a named object + * is used, the object name is derived from a 64 bit FNV hash of the + * environment pathname. As such, naming collisions are extremely + * unlikely. If a collision occurs, the results are unpredictable. + */ +typedef struct MDB_txbody { + /** Stamp identifying this as an LMDB file. It must be set + * to #MDB_MAGIC. */ + uint32_t mtb_magic; + /** Format of this lock file. Must be set to #MDB_LOCK_FORMAT. */ + uint32_t mtb_format; + /** The ID of the last transaction committed to the database. + * This is recorded here only for convenience; the value can always + * be determined by reading the main database meta pages. + */ + volatile txnid_t mtb_txnid; + /** The number of slots that have been used in the reader table. + * This always records the maximum count, it is not decremented + * when readers release their slots. + */ + volatile unsigned mtb_numreaders; +#if defined(_WIN32) || defined(MDB_USE_POSIX_SEM) + char mtb_rmname[MNAME_LEN]; +#elif defined(MDB_USE_SYSV_SEM) + int mtb_semid; + int mtb_rlocked; +#else + /** Mutex protecting access to this table. + * This is the reader table lock used with LOCK_MUTEX(). + */ + mdb_mutex_t mtb_rmutex; +#endif +} MDB_txbody; + + /** The actual reader table definition. */ +typedef struct MDB_txninfo { + union { + MDB_txbody mtb; +#define mti_magic mt1.mtb.mtb_magic +#define mti_format mt1.mtb.mtb_format +#define mti_rmutex mt1.mtb.mtb_rmutex +#define mti_rmname mt1.mtb.mtb_rmname +#define mti_txnid mt1.mtb.mtb_txnid +#define mti_numreaders mt1.mtb.mtb_numreaders +#ifdef MDB_USE_SYSV_SEM +#define mti_semid mt1.mtb.mtb_semid +#define mti_rlocked mt1.mtb.mtb_rlocked +#endif + char pad[(sizeof(MDB_txbody)+CACHELINE-1) & ~(CACHELINE-1)]; + } mt1; + union { +#if defined(_WIN32) || defined(MDB_USE_POSIX_SEM) + char mt2_wmname[MNAME_LEN]; +#define mti_wmname mt2.mt2_wmname +#elif defined MDB_USE_SYSV_SEM + int mt2_wlocked; +#define mti_wlocked mt2.mt2_wlocked +#else + mdb_mutex_t mt2_wmutex; +#define mti_wmutex mt2.mt2_wmutex +#endif + char pad[(MNAME_LEN+CACHELINE-1) & ~(CACHELINE-1)]; + } mt2; + MDB_reader mti_readers[1]; +} MDB_txninfo; + + /** Lockfile format signature: version, features and field layout */ +#define MDB_LOCK_FORMAT \ + ((uint32_t) \ + ((MDB_LOCK_VERSION) \ + /* Flags which describe functionality */ \ + + (SYSV_SEM_FLAG << 18) \ + + (((MDB_PIDLOCK) != 0) << 16))) +/** @} */ + +/** Common header for all page types. + * Overflow records occupy a number of contiguous pages with no + * headers on any page after the first. + */ +typedef struct MDB_page { +#define mp_pgno mp_p.p_pgno +#define mp_next mp_p.p_next + union { + pgno_t p_pgno; /**< page number */ + struct MDB_page *p_next; /**< for in-memory list of freed pages */ + } mp_p; + uint16_t mp_pad; +/** @defgroup mdb_page Page Flags + * @ingroup internal + * Flags for the page headers. + * @{ + */ +#define P_BRANCH 0x01 /**< branch page */ +#define P_LEAF 0x02 /**< leaf page */ +#define P_OVERFLOW 0x04 /**< overflow page */ +#define P_META 0x08 /**< meta page */ +#define P_DIRTY 0x10 /**< dirty page, also set for #P_SUBP pages */ +#define P_LEAF2 0x20 /**< for #MDB_DUPFIXED records */ +#define P_SUBP 0x40 /**< for #MDB_DUPSORT sub-pages */ +#define P_LOOSE 0x4000 /**< page was dirtied then freed, can be reused */ +#define P_KEEP 0x8000 /**< leave this page alone during spill */ +/** @} */ + uint16_t mp_flags; /**< @ref mdb_page */ +#define mp_lower mp_pb.pb.pb_lower +#define mp_upper mp_pb.pb.pb_upper +#define mp_pages mp_pb.pb_pages + union { + struct { + indx_t pb_lower; /**< lower bound of free space */ + indx_t pb_upper; /**< upper bound of free space */ + } pb; + uint32_t pb_pages; /**< number of overflow pages */ + } mp_pb; + indx_t mp_ptrs[1]; /**< dynamic size */ +} MDB_page; + + /** Size of the page header, excluding dynamic data at the end */ +#define PAGEHDRSZ ((unsigned) offsetof(MDB_page, mp_ptrs)) + + /** Address of first usable data byte in a page, after the header */ +#define METADATA(p) ((void *)((char *)(p) + PAGEHDRSZ)) + + /** ITS#7713, change PAGEBASE to handle 65536 byte pages */ +#define PAGEBASE ((MDB_DEVEL) ? PAGEHDRSZ : 0) + + /** Number of nodes on a page */ +#define NUMKEYS(p) (((p)->mp_lower - (PAGEHDRSZ-PAGEBASE)) >> 1) + + /** The amount of space remaining in the page */ +#define SIZELEFT(p) (indx_t)((p)->mp_upper - (p)->mp_lower) + + /** The percentage of space used in the page, in tenths of a percent. */ +#define PAGEFILL(env, p) (1000L * ((env)->me_psize - PAGEHDRSZ - SIZELEFT(p)) / \ + ((env)->me_psize - PAGEHDRSZ)) + /** The minimum page fill factor, in tenths of a percent. + * Pages emptier than this are candidates for merging. + */ +#define FILL_THRESHOLD 250 + + /** Test if a page is a leaf page */ +#define IS_LEAF(p) F_ISSET((p)->mp_flags, P_LEAF) + /** Test if a page is a LEAF2 page */ +#define IS_LEAF2(p) F_ISSET((p)->mp_flags, P_LEAF2) + /** Test if a page is a branch page */ +#define IS_BRANCH(p) F_ISSET((p)->mp_flags, P_BRANCH) + /** Test if a page is an overflow page */ +#define IS_OVERFLOW(p) F_ISSET((p)->mp_flags, P_OVERFLOW) + /** Test if a page is a sub page */ +#define IS_SUBP(p) F_ISSET((p)->mp_flags, P_SUBP) + + /** The number of overflow pages needed to store the given size. */ +#define OVPAGES(size, psize) ((PAGEHDRSZ-1 + (size)) / (psize) + 1) + + /** Link in #MDB_txn.%mt_loose_pgs list */ +#define NEXT_LOOSE_PAGE(p) (*(MDB_page **)((p) + 2)) + + /** Header for a single key/data pair within a page. + * Used in pages of type #P_BRANCH and #P_LEAF without #P_LEAF2. + * We guarantee 2-byte alignment for 'MDB_node's. + */ +typedef struct MDB_node { + /** lo and hi are used for data size on leaf nodes and for + * child pgno on branch nodes. On 64 bit platforms, flags + * is also used for pgno. (Branch nodes have no flags). + * They are in host byte order in case that lets some + * accesses be optimized into a 32-bit word access. + */ +#if BYTE_ORDER == LITTLE_ENDIAN + unsigned short mn_lo, mn_hi; /**< part of data size or pgno */ +#else + unsigned short mn_hi, mn_lo; +#endif +/** @defgroup mdb_node Node Flags + * @ingroup internal + * Flags for node headers. + * @{ + */ +#define F_BIGDATA 0x01 /**< data put on overflow page */ +#define F_SUBDATA 0x02 /**< data is a sub-database */ +#define F_DUPDATA 0x04 /**< data has duplicates */ + +/** valid flags for #mdb_node_add() */ +#define NODE_ADD_FLAGS (F_DUPDATA|F_SUBDATA|MDB_RESERVE|MDB_APPEND) + +/** @} */ + unsigned short mn_flags; /**< @ref mdb_node */ + unsigned short mn_ksize; /**< key size */ + char mn_data[1]; /**< key and data are appended here */ +} MDB_node; + + /** Size of the node header, excluding dynamic data at the end */ +#define NODESIZE offsetof(MDB_node, mn_data) + + /** Bit position of top word in page number, for shifting mn_flags */ +#define PGNO_TOPWORD ((pgno_t)-1 > 0xffffffffu ? 32 : 0) + + /** Size of a node in a branch page with a given key. + * This is just the node header plus the key, there is no data. + */ +#define INDXSIZE(k) (NODESIZE + ((k) == NULL ? 0 : (k)->mv_size)) + + /** Size of a node in a leaf page with a given key and data. + * This is node header plus key plus data size. + */ +#define LEAFSIZE(k, d) (NODESIZE + (k)->mv_size + (d)->mv_size) + + /** Address of node \b i in page \b p */ +#define NODEPTR(p, i) ((MDB_node *)((char *)(p) + (p)->mp_ptrs[i] + PAGEBASE)) + + /** Address of the key for the node */ +#define NODEKEY(node) (void *)((node)->mn_data) + + /** Address of the data for a node */ +#define NODEDATA(node) (void *)((char *)(node)->mn_data + (node)->mn_ksize) + + /** Get the page number pointed to by a branch node */ +#define NODEPGNO(node) \ + ((node)->mn_lo | ((pgno_t) (node)->mn_hi << 16) | \ + (PGNO_TOPWORD ? ((pgno_t) (node)->mn_flags << PGNO_TOPWORD) : 0)) + /** Set the page number in a branch node */ +#define SETPGNO(node,pgno) do { \ + (node)->mn_lo = (pgno) & 0xffff; (node)->mn_hi = (pgno) >> 16; \ + if (PGNO_TOPWORD) (node)->mn_flags = (pgno) >> PGNO_TOPWORD; } while(0) + + /** Get the size of the data in a leaf node */ +#define NODEDSZ(node) ((node)->mn_lo | ((unsigned)(node)->mn_hi << 16)) + /** Set the size of the data for a leaf node */ +#define SETDSZ(node,size) do { \ + (node)->mn_lo = (size) & 0xffff; (node)->mn_hi = (size) >> 16;} while(0) + /** The size of a key in a node */ +#define NODEKSZ(node) ((node)->mn_ksize) + + /** Copy a page number from src to dst */ +#ifdef MISALIGNED_OK +#define COPY_PGNO(dst,src) dst = src +#else +#if SIZE_MAX > 4294967295UL +#define COPY_PGNO(dst,src) do { \ + unsigned short *s, *d; \ + s = (unsigned short *)&(src); \ + d = (unsigned short *)&(dst); \ + *d++ = *s++; \ + *d++ = *s++; \ + *d++ = *s++; \ + *d = *s; \ +} while (0) +#else +#define COPY_PGNO(dst,src) do { \ + unsigned short *s, *d; \ + s = (unsigned short *)&(src); \ + d = (unsigned short *)&(dst); \ + *d++ = *s++; \ + *d = *s; \ +} while (0) +#endif +#endif + /** The address of a key in a LEAF2 page. + * LEAF2 pages are used for #MDB_DUPFIXED sorted-duplicate sub-DBs. + * There are no node headers, keys are stored contiguously. + */ +#define LEAF2KEY(p, i, ks) ((char *)(p) + PAGEHDRSZ + ((i)*(ks))) + + /** Set the \b node's key into \b keyptr, if requested. */ +#define MDB_GET_KEY(node, keyptr) { if ((keyptr) != NULL) { \ + (keyptr)->mv_size = NODEKSZ(node); (keyptr)->mv_data = NODEKEY(node); } } + + /** Set the \b node's key into \b key. */ +#define MDB_GET_KEY2(node, key) { key.mv_size = NODEKSZ(node); key.mv_data = NODEKEY(node); } + + /** Information about a single database in the environment. */ +typedef struct MDB_db { + uint32_t md_pad; /**< also ksize for LEAF2 pages */ + uint16_t md_flags; /**< @ref mdb_dbi_open */ + uint16_t md_depth; /**< depth of this tree */ + pgno_t md_branch_pages; /**< number of internal pages */ + pgno_t md_leaf_pages; /**< number of leaf pages */ + pgno_t md_overflow_pages; /**< number of overflow pages */ + mdb_size_t md_entries; /**< number of data items */ + pgno_t md_root; /**< the root page of this tree */ +} MDB_db; + + /** mdb_dbi_open flags */ +#define MDB_VALID 0x8000 /**< DB handle is valid, for me_dbflags */ +#define PERSISTENT_FLAGS (0xffff & ~(MDB_VALID)) +#define VALID_FLAGS (MDB_REVERSEKEY|MDB_DUPSORT|MDB_INTEGERKEY|MDB_DUPFIXED|\ + MDB_INTEGERDUP|MDB_REVERSEDUP|MDB_CREATE) + + /** Handle for the DB used to track free pages. */ +#define FREE_DBI 0 + /** Handle for the default DB. */ +#define MAIN_DBI 1 + /** Number of DBs in metapage (free and main) - also hardcoded elsewhere */ +#define CORE_DBS 2 + + /** Number of meta pages - also hardcoded elsewhere */ +#define NUM_METAS 2 + + /** Meta page content. + * A meta page is the start point for accessing a database snapshot. + * Pages 0-1 are meta pages. Transaction N writes meta page #(N % 2). + */ +typedef struct MDB_meta { + /** Stamp identifying this as an LMDB file. It must be set + * to #MDB_MAGIC. */ + uint32_t mm_magic; + /** Version number of this file. Must be set to #MDB_DATA_VERSION. */ + uint32_t mm_version; +#ifdef MDB_VL32 + union { /* always zero since we don't support fixed mapping in MDB_VL32 */ + MDB_ID mmun_ull; + void *mmun_address; + } mm_un; +#define mm_address mm_un.mmun_address +#else + void *mm_address; /**< address for fixed mapping */ +#endif + pgno_t mm_mapsize; /**< size of mmap region */ + MDB_db mm_dbs[CORE_DBS]; /**< first is free space, 2nd is main db */ + /** The size of pages used in this DB */ +#define mm_psize mm_dbs[FREE_DBI].md_pad + /** Any persistent environment flags. @ref mdb_env */ +#define mm_flags mm_dbs[FREE_DBI].md_flags + pgno_t mm_last_pg; /**< last used page in file */ + volatile txnid_t mm_txnid; /**< txnid that committed this page */ +} MDB_meta; + + /** Buffer for a stack-allocated meta page. + * The members define size and alignment, and silence type + * aliasing warnings. They are not used directly; that could + * mean incorrectly using several union members in parallel. + */ +typedef union MDB_metabuf { + MDB_page mb_page; + struct { + char mm_pad[PAGEHDRSZ]; + MDB_meta mm_meta; + } mb_metabuf; +} MDB_metabuf; + + /** Auxiliary DB info. + * The information here is mostly static/read-only. There is + * only a single copy of this record in the environment. + */ +typedef struct MDB_dbx { + MDB_val md_name; /**< name of the database */ + MDB_cmp_func *md_cmp; /**< function for comparing keys */ + MDB_cmp_func *md_dcmp; /**< function for comparing data items */ + MDB_rel_func *md_rel; /**< user relocate function */ + void *md_relctx; /**< user-provided context for md_rel */ +} MDB_dbx; + + /** A database transaction. + * Every operation requires a transaction handle. + */ +struct MDB_txn { + MDB_txn *mt_parent; /**< parent of a nested txn */ + /** Nested txn under this txn, set together with flag #MDB_TXN_HAS_CHILD */ + MDB_txn *mt_child; + pgno_t mt_next_pgno; /**< next unallocated page */ +#ifdef MDB_VL32 + pgno_t mt_last_pgno; /**< last written page */ +#endif + /** The ID of this transaction. IDs are integers incrementing from 1. + * Only committed write transactions increment the ID. If a transaction + * aborts, the ID may be re-used by the next writer. + */ + txnid_t mt_txnid; + MDB_env *mt_env; /**< the DB environment */ + /** The list of pages that became unused during this transaction. + */ + MDB_IDL mt_free_pgs; + /** The list of loose pages that became unused and may be reused + * in this transaction, linked through #NEXT_LOOSE_PAGE(page). + */ + MDB_page *mt_loose_pgs; + /* #Number of loose pages (#mt_loose_pgs) */ + int mt_loose_count; + /** The sorted list of dirty pages we temporarily wrote to disk + * because the dirty list was full. page numbers in here are + * shifted left by 1, deleted slots have the LSB set. + */ + MDB_IDL mt_spill_pgs; + union { + /** For write txns: Modified pages. Sorted when not MDB_WRITEMAP. */ + MDB_ID2L dirty_list; + /** For read txns: This thread/txn's reader table slot, or NULL. */ + MDB_reader *reader; + } mt_u; + /** Array of records for each DB known in the environment. */ + MDB_dbx *mt_dbxs; + /** Array of MDB_db records for each known DB */ + MDB_db *mt_dbs; + /** Array of sequence numbers for each DB handle */ + unsigned int *mt_dbiseqs; +/** @defgroup mt_dbflag Transaction DB Flags + * @ingroup internal + * @{ + */ +#define DB_DIRTY 0x01 /**< DB was modified or is DUPSORT data */ +#define DB_STALE 0x02 /**< Named-DB record is older than txnID */ +#define DB_NEW 0x04 /**< Named-DB handle opened in this txn */ +#define DB_VALID 0x08 /**< DB handle is valid, see also #MDB_VALID */ +#define DB_USRVALID 0x10 /**< As #DB_VALID, but not set for #FREE_DBI */ +/** @} */ + /** In write txns, array of cursors for each DB */ + MDB_cursor **mt_cursors; + /** Array of flags for each DB */ + unsigned char *mt_dbflags; +#ifdef MDB_VL32 + /** List of read-only pages (actually chunks) */ + MDB_ID3L mt_rpages; + /** We map chunks of 16 pages. Even though Windows uses 4KB pages, all + * mappings must begin on 64KB boundaries. So we round off all pgnos to + * a chunk boundary. We do the same on Linux for symmetry, and also to + * reduce the frequency of mmap/munmap calls. + */ +#define MDB_RPAGE_CHUNK 16 +#define MDB_TRPAGE_SIZE 4096 /**< size of #mt_rpages array of chunks */ +#define MDB_TRPAGE_MAX (MDB_TRPAGE_SIZE-1) /**< maximum chunk index */ + unsigned int mt_rpcheck; /**< threshold for reclaiming unref'd chunks */ +#endif + /** Number of DB records in use, or 0 when the txn is finished. + * This number only ever increments until the txn finishes; we + * don't decrement it when individual DB handles are closed. + */ + MDB_dbi mt_numdbs; + +/** @defgroup mdb_txn Transaction Flags + * @ingroup internal + * @{ + */ + /** #mdb_txn_begin() flags */ +#define MDB_TXN_BEGIN_FLAGS (MDB_NOMETASYNC|MDB_NOSYNC|MDB_RDONLY) +#define MDB_TXN_NOMETASYNC MDB_NOMETASYNC /**< don't sync meta for this txn on commit */ +#define MDB_TXN_NOSYNC MDB_NOSYNC /**< don't sync this txn on commit */ +#define MDB_TXN_RDONLY MDB_RDONLY /**< read-only transaction */ + /* internal txn flags */ +#define MDB_TXN_WRITEMAP MDB_WRITEMAP /**< copy of #MDB_env flag in writers */ +#define MDB_TXN_FINISHED 0x01 /**< txn is finished or never began */ +#define MDB_TXN_ERROR 0x02 /**< txn is unusable after an error */ +#define MDB_TXN_DIRTY 0x04 /**< must write, even if dirty list is empty */ +#define MDB_TXN_SPILLS 0x08 /**< txn or a parent has spilled pages */ +#define MDB_TXN_HAS_CHILD 0x10 /**< txn has an #MDB_txn.%mt_child */ + /** most operations on the txn are currently illegal */ +#define MDB_TXN_BLOCKED (MDB_TXN_FINISHED|MDB_TXN_ERROR|MDB_TXN_HAS_CHILD) +/** @} */ + unsigned int mt_flags; /**< @ref mdb_txn */ + /** #dirty_list room: Array size - \#dirty pages visible to this txn. + * Includes ancestor txns' dirty pages not hidden by other txns' + * dirty/spilled pages. Thus commit(nested txn) has room to merge + * dirty_list into mt_parent after freeing hidden mt_parent pages. + */ + unsigned int mt_dirty_room; +}; + +/** Enough space for 2^32 nodes with minimum of 2 keys per node. I.e., plenty. + * At 4 keys per node, enough for 2^64 nodes, so there's probably no need to + * raise this on a 64 bit machine. + */ +#define CURSOR_STACK 32 + +struct MDB_xcursor; + + /** Cursors are used for all DB operations. + * A cursor holds a path of (page pointer, key index) from the DB + * root to a position in the DB, plus other state. #MDB_DUPSORT + * cursors include an xcursor to the current data item. Write txns + * track their cursors and keep them up to date when data moves. + * Exception: An xcursor's pointer to a #P_SUBP page can be stale. + * (A node with #F_DUPDATA but no #F_SUBDATA contains a subpage). + */ +struct MDB_cursor { + /** Next cursor on this DB in this txn */ + MDB_cursor *mc_next; + /** Backup of the original cursor if this cursor is a shadow */ + MDB_cursor *mc_backup; + /** Context used for databases with #MDB_DUPSORT, otherwise NULL */ + struct MDB_xcursor *mc_xcursor; + /** The transaction that owns this cursor */ + MDB_txn *mc_txn; + /** The database handle this cursor operates on */ + MDB_dbi mc_dbi; + /** The database record for this cursor */ + MDB_db *mc_db; + /** The database auxiliary record for this cursor */ + MDB_dbx *mc_dbx; + /** The @ref mt_dbflag for this database */ + unsigned char *mc_dbflag; + unsigned short mc_snum; /**< number of pushed pages */ + unsigned short mc_top; /**< index of top page, normally mc_snum-1 */ +/** @defgroup mdb_cursor Cursor Flags + * @ingroup internal + * Cursor state flags. + * @{ + */ +#define C_INITIALIZED 0x01 /**< cursor has been initialized and is valid */ +#define C_EOF 0x02 /**< No more data */ +#define C_SUB 0x04 /**< Cursor is a sub-cursor */ +#define C_DEL 0x08 /**< last op was a cursor_del */ +#define C_UNTRACK 0x40 /**< Un-track cursor when closing */ +#define C_WRITEMAP MDB_TXN_WRITEMAP /**< Copy of txn flag */ +/** Read-only cursor into the txn's original snapshot in the map. + * Set for read-only txns, and in #mdb_page_alloc() for #FREE_DBI when + * #MDB_DEVEL & 2. Only implements code which is necessary for this. + */ +#define C_ORIG_RDONLY MDB_TXN_RDONLY +/** @} */ + unsigned int mc_flags; /**< @ref mdb_cursor */ + MDB_page *mc_pg[CURSOR_STACK]; /**< stack of pushed pages */ + indx_t mc_ki[CURSOR_STACK]; /**< stack of page indices */ +#ifdef MDB_VL32 + MDB_page *mc_ovpg; /**< a referenced overflow page */ +#endif +}; + + /** Context for sorted-dup records. + * We could have gone to a fully recursive design, with arbitrarily + * deep nesting of sub-databases. But for now we only handle these + * levels - main DB, optional sub-DB, sorted-duplicate DB. + */ +typedef struct MDB_xcursor { + /** A sub-cursor for traversing the Dup DB */ + MDB_cursor mx_cursor; + /** The database record for this Dup DB */ + MDB_db mx_db; + /** The auxiliary DB record for this Dup DB */ + MDB_dbx mx_dbx; + /** The @ref mt_dbflag for this Dup DB */ + unsigned char mx_dbflag; +} MDB_xcursor; + + /** State of FreeDB old pages, stored in the MDB_env */ +typedef struct MDB_pgstate { + pgno_t *mf_pghead; /**< Reclaimed freeDB pages, or NULL before use */ + txnid_t mf_pglast; /**< ID of last used record, or 0 if !mf_pghead */ +} MDB_pgstate; + + /** The database environment. */ +struct MDB_env { + HANDLE me_fd; /**< The main data file */ + HANDLE me_lfd; /**< The lock file */ + HANDLE me_mfd; /**< just for writing the meta pages */ +#if defined(MDB_VL32) && defined(_WIN32) + HANDLE me_fmh; /**< File Mapping handle */ +#endif + /** Failed to update the meta page. Probably an I/O error. */ +#define MDB_FATAL_ERROR 0x80000000U + /** Some fields are initialized. */ +#define MDB_ENV_ACTIVE 0x20000000U + /** me_txkey is set */ +#define MDB_ENV_TXKEY 0x10000000U + /** fdatasync is unreliable */ +#define MDB_FSYNCONLY 0x08000000U + uint32_t me_flags; /**< @ref mdb_env */ + unsigned int me_psize; /**< DB page size, inited from me_os_psize */ + unsigned int me_os_psize; /**< OS page size, from #GET_PAGESIZE */ + unsigned int me_maxreaders; /**< size of the reader table */ + /** Max #MDB_txninfo.%mti_numreaders of interest to #mdb_env_close() */ + volatile int me_close_readers; + MDB_dbi me_numdbs; /**< number of DBs opened */ + MDB_dbi me_maxdbs; /**< size of the DB table */ + MDB_PID_T me_pid; /**< process ID of this env */ + char *me_path; /**< path to the DB files */ + char *me_map; /**< the memory map of the data file */ + MDB_txninfo *me_txns; /**< the memory map of the lock file or NULL */ + MDB_meta *me_metas[NUM_METAS]; /**< pointers to the two meta pages */ + void *me_pbuf; /**< scratch area for DUPSORT put() */ + MDB_txn *me_txn; /**< current write transaction */ + MDB_txn *me_txn0; /**< prealloc'd write transaction */ + mdb_size_t me_mapsize; /**< size of the data memory map */ + off64_t me_size; /**< current file size */ + pgno_t me_maxpg; /**< me_mapsize / me_psize */ + MDB_dbx *me_dbxs; /**< array of static DB info */ + uint16_t *me_dbflags; /**< array of flags from MDB_db.md_flags */ + unsigned int *me_dbiseqs; /**< array of dbi sequence numbers */ + pthread_key_t me_txkey; /**< thread-key for readers */ + txnid_t me_pgoldest; /**< ID of oldest reader last time we looked */ + MDB_pgstate me_pgstate; /**< state of old pages from freeDB */ +# define me_pglast me_pgstate.mf_pglast +# define me_pghead me_pgstate.mf_pghead + MDB_page *me_dpages; /**< list of malloc'd blocks for re-use */ + /** IDL of pages that became unused in a write txn */ + MDB_IDL me_free_pgs; + /** ID2L of pages written during a write txn. Length MDB_IDL_UM_SIZE. */ + MDB_ID2L me_dirty_list; + /** Max number of freelist items that can fit in a single overflow page */ + int me_maxfree_1pg; + /** Max size of a node on a page */ + unsigned int me_nodemax; +#if !(MDB_MAXKEYSIZE) + unsigned int me_maxkey; /**< max size of a key */ +#endif + int me_live_reader; /**< have liveness lock in reader table */ +#ifdef _WIN32 + int me_pidquery; /**< Used in OpenProcess */ +#endif +#ifdef MDB_USE_POSIX_MUTEX /* Posix mutexes reside in shared mem */ +# define me_rmutex me_txns->mti_rmutex /**< Shared reader lock */ +# define me_wmutex me_txns->mti_wmutex /**< Shared writer lock */ +#else + mdb_mutex_t me_rmutex; + mdb_mutex_t me_wmutex; +#endif +#ifdef MDB_VL32 + MDB_ID3L me_rpages; /**< like #mt_rpages, but global to env */ + pthread_mutex_t me_rpmutex; /**< control access to #me_rpages */ +#define MDB_ERPAGE_SIZE 16384 +#define MDB_ERPAGE_MAX (MDB_ERPAGE_SIZE-1) + unsigned int me_rpcheck; +#endif + void *me_userctx; /**< User-settable context */ + MDB_assert_func *me_assert_func; /**< Callback for assertion failures */ +}; + + /** Nested transaction */ +typedef struct MDB_ntxn { + MDB_txn mnt_txn; /**< the transaction */ + MDB_pgstate mnt_pgstate; /**< parent transaction's saved freestate */ +} MDB_ntxn; + + /** max number of pages to commit in one writev() call */ +#define MDB_COMMIT_PAGES 64 +#if defined(IOV_MAX) && IOV_MAX < MDB_COMMIT_PAGES +#undef MDB_COMMIT_PAGES +#define MDB_COMMIT_PAGES IOV_MAX +#endif + + /** max bytes to write in one call */ +#define MAX_WRITE (0x40000000U >> (sizeof(ssize_t) == 4)) + + /** Check \b txn and \b dbi arguments to a function */ +#define TXN_DBI_EXIST(txn, dbi, validity) \ + ((txn) && (dbi)<(txn)->mt_numdbs && ((txn)->mt_dbflags[dbi] & (validity))) + + /** Check for misused \b dbi handles */ +#define TXN_DBI_CHANGED(txn, dbi) \ + ((txn)->mt_dbiseqs[dbi] != (txn)->mt_env->me_dbiseqs[dbi]) + +static int mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp); +static int mdb_page_new(MDB_cursor *mc, uint32_t flags, int num, MDB_page **mp); +static int mdb_page_touch(MDB_cursor *mc); + +#define MDB_END_NAMES {"committed", "empty-commit", "abort", "reset", \ + "reset-tmp", "fail-begin", "fail-beginchild"} +enum { + /* mdb_txn_end operation number, for logging */ + MDB_END_COMMITTED, MDB_END_EMPTY_COMMIT, MDB_END_ABORT, MDB_END_RESET, + MDB_END_RESET_TMP, MDB_END_FAIL_BEGIN, MDB_END_FAIL_BEGINCHILD +}; +#define MDB_END_OPMASK 0x0F /**< mask for #mdb_txn_end() operation number */ +#define MDB_END_UPDATE 0x10 /**< update env state (DBIs) */ +#define MDB_END_FREE 0x20 /**< free txn unless it is #MDB_env.%me_txn0 */ +#define MDB_END_SLOT MDB_NOTLS /**< release any reader slot if #MDB_NOTLS */ +static void mdb_txn_end(MDB_txn *txn, unsigned mode); + +static int mdb_page_get(MDB_cursor *mc, pgno_t pgno, MDB_page **mp, int *lvl); +static int mdb_page_search_root(MDB_cursor *mc, + MDB_val *key, int modify); +#define MDB_PS_MODIFY 1 +#define MDB_PS_ROOTONLY 2 +#define MDB_PS_FIRST 4 +#define MDB_PS_LAST 8 +static int mdb_page_search(MDB_cursor *mc, + MDB_val *key, int flags); +static int mdb_page_merge(MDB_cursor *csrc, MDB_cursor *cdst); + +#define MDB_SPLIT_REPLACE MDB_APPENDDUP /**< newkey is not new */ +static int mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, + pgno_t newpgno, unsigned int nflags); + +static int mdb_env_read_header(MDB_env *env, int prev, MDB_meta *meta); +static MDB_meta *mdb_env_pick_meta(const MDB_env *env); +static int mdb_env_write_meta(MDB_txn *txn); +#ifdef MDB_USE_POSIX_MUTEX /* Drop unused excl arg */ +# define mdb_env_close0(env, excl) mdb_env_close1(env) +#endif +static void mdb_env_close0(MDB_env *env, int excl); + +static MDB_node *mdb_node_search(MDB_cursor *mc, MDB_val *key, int *exactp); +static int mdb_node_add(MDB_cursor *mc, indx_t indx, + MDB_val *key, MDB_val *data, pgno_t pgno, unsigned int flags); +static void mdb_node_del(MDB_cursor *mc, int ksize); +static void mdb_node_shrink(MDB_page *mp, indx_t indx); +static int mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst, int fromleft); +static int mdb_node_read(MDB_cursor *mc, MDB_node *leaf, MDB_val *data); +static size_t mdb_leaf_size(MDB_env *env, MDB_val *key, MDB_val *data); +static size_t mdb_branch_size(MDB_env *env, MDB_val *key); + +static int mdb_rebalance(MDB_cursor *mc); +static int mdb_update_key(MDB_cursor *mc, MDB_val *key); + +static void mdb_cursor_pop(MDB_cursor *mc); +static int mdb_cursor_push(MDB_cursor *mc, MDB_page *mp); + +static int mdb_cursor_del0(MDB_cursor *mc); +static int mdb_del0(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data, unsigned flags); +static int mdb_cursor_sibling(MDB_cursor *mc, int move_right); +static int mdb_cursor_next(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op); +static int mdb_cursor_prev(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op); +static int mdb_cursor_set(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op, + int *exactp); +static int mdb_cursor_first(MDB_cursor *mc, MDB_val *key, MDB_val *data); +static int mdb_cursor_last(MDB_cursor *mc, MDB_val *key, MDB_val *data); + +static void mdb_cursor_init(MDB_cursor *mc, MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx); +static void mdb_xcursor_init0(MDB_cursor *mc); +static void mdb_xcursor_init1(MDB_cursor *mc, MDB_node *node); +static void mdb_xcursor_init2(MDB_cursor *mc, MDB_xcursor *src_mx, int force); + +static int mdb_drop0(MDB_cursor *mc, int subs); +static void mdb_default_cmp(MDB_txn *txn, MDB_dbi dbi); +static int mdb_reader_check0(MDB_env *env, int rlocked, int *dead); + +/** @cond */ +static MDB_cmp_func mdb_cmp_memn, mdb_cmp_memnr, mdb_cmp_int, mdb_cmp_cint, mdb_cmp_long; +/** @endcond */ + +/** Compare two items pointing at size_t's of unknown alignment. */ +#ifdef MISALIGNED_OK +# define mdb_cmp_clong mdb_cmp_long +#else +# define mdb_cmp_clong mdb_cmp_cint +#endif + +#ifdef _WIN32 +static SECURITY_DESCRIPTOR mdb_null_sd; +static SECURITY_ATTRIBUTES mdb_all_sa; +static int mdb_sec_inited; + +static int utf8_to_utf16(const char *src, int srcsize, wchar_t **dst, int *dstsize); +#endif + +/** Return the library version info. */ +char * ESECT +mdb_version(int *major, int *minor, int *patch) +{ + if (major) *major = MDB_VERSION_MAJOR; + if (minor) *minor = MDB_VERSION_MINOR; + if (patch) *patch = MDB_VERSION_PATCH; + return MDB_VERSION_STRING; +} + +/** Table of descriptions for LMDB @ref errors */ +static char *const mdb_errstr[] = { + "MDB_KEYEXIST: Key/data pair already exists", + "MDB_NOTFOUND: No matching key/data pair found", + "MDB_PAGE_NOTFOUND: Requested page not found", + "MDB_CORRUPTED: Located page was wrong type", + "MDB_PANIC: Update of meta page failed or environment had fatal error", + "MDB_VERSION_MISMATCH: Database environment version mismatch", + "MDB_INVALID: File is not an LMDB file", + "MDB_MAP_FULL: Environment mapsize limit reached", + "MDB_DBS_FULL: Environment maxdbs limit reached", + "MDB_READERS_FULL: Environment maxreaders limit reached", + "MDB_TLS_FULL: Thread-local storage keys full - too many environments open", + "MDB_TXN_FULL: Transaction has too many dirty pages - transaction too big", + "MDB_CURSOR_FULL: Internal error - cursor stack limit reached", + "MDB_PAGE_FULL: Internal error - page has no more space", + "MDB_MAP_RESIZED: Database contents grew beyond environment mapsize", + "MDB_INCOMPATIBLE: Operation and DB incompatible, or DB flags changed", + "MDB_BAD_RSLOT: Invalid reuse of reader locktable slot", + "MDB_BAD_TXN: Transaction must abort, has a child, or is invalid", + "MDB_BAD_VALSIZE: Unsupported size of key/DB name/data, or wrong DUPFIXED size", + "MDB_BAD_DBI: The specified DBI handle was closed/changed unexpectedly", +}; + +char * +mdb_strerror(int err) +{ +#ifdef _WIN32 + /** HACK: pad 4KB on stack over the buf. Return system msgs in buf. + * This works as long as no function between the call to mdb_strerror + * and the actual use of the message uses more than 4K of stack. + */ +#define MSGSIZE 1024 +#define PADSIZE 4096 + char buf[MSGSIZE+PADSIZE], *ptr = buf; +#endif + int i; + if (!err) + return ("Successful return: 0"); + + if (err >= MDB_KEYEXIST && err <= MDB_LAST_ERRCODE) { + i = err - MDB_KEYEXIST; + return mdb_errstr[i]; + } + +#ifdef _WIN32 + /* These are the C-runtime error codes we use. The comment indicates + * their numeric value, and the Win32 error they would correspond to + * if the error actually came from a Win32 API. A major mess, we should + * have used LMDB-specific error codes for everything. + */ + switch(err) { + case ENOENT: /* 2, FILE_NOT_FOUND */ + case EIO: /* 5, ACCESS_DENIED */ + case ENOMEM: /* 12, INVALID_ACCESS */ + case EACCES: /* 13, INVALID_DATA */ + case EBUSY: /* 16, CURRENT_DIRECTORY */ + case EINVAL: /* 22, BAD_COMMAND */ + case ENOSPC: /* 28, OUT_OF_PAPER */ + return strerror(err); + default: + ; + } + buf[0] = 0; + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, err, 0, ptr, MSGSIZE, (va_list *)buf+MSGSIZE); + return ptr; +#else + return strerror(err); +#endif +} + +/** assert(3) variant in cursor context */ +#define mdb_cassert(mc, expr) mdb_assert0((mc)->mc_txn->mt_env, expr, #expr) +/** assert(3) variant in transaction context */ +#define mdb_tassert(txn, expr) mdb_assert0((txn)->mt_env, expr, #expr) +/** assert(3) variant in environment context */ +#define mdb_eassert(env, expr) mdb_assert0(env, expr, #expr) + +#ifndef NDEBUG +# define mdb_assert0(env, expr, expr_txt) ((expr) ? (void)0 : \ + mdb_assert_fail(env, expr_txt, mdb_func_, __FILE__, __LINE__)) + +static void ESECT +mdb_assert_fail(MDB_env *env, const char *expr_txt, + const char *func, const char *file, int line) +{ + char buf[400]; + sprintf(buf, "%.100s:%d: Assertion '%.200s' failed in %.40s()", + file, line, expr_txt, func); + if (env->me_assert_func) + env->me_assert_func(env, buf); + fprintf(stderr, "%s\n", buf); + abort(); +} +#else +# define mdb_assert0(env, expr, expr_txt) ((void) 0) +#endif /* NDEBUG */ + +#if MDB_DEBUG +/** Return the page number of \b mp which may be sub-page, for debug output */ +static pgno_t +mdb_dbg_pgno(MDB_page *mp) +{ + pgno_t ret; + COPY_PGNO(ret, mp->mp_pgno); + return ret; +} + +/** Display a key in hexadecimal and return the address of the result. + * @param[in] key the key to display + * @param[in] buf the buffer to write into. Should always be #DKBUF. + * @return The key in hexadecimal form. + */ +char * +mdb_dkey(MDB_val *key, char *buf) +{ + char *ptr = buf; + unsigned char *c = key->mv_data; + unsigned int i; + + if (!key) + return ""; + + if (key->mv_size > DKBUF_MAXKEYSIZE) + return "MDB_MAXKEYSIZE"; + /* may want to make this a dynamic check: if the key is mostly + * printable characters, print it as-is instead of converting to hex. + */ +#if 1 + buf[0] = '\0'; + for (i=0; imv_size; i++) + ptr += sprintf(ptr, "%02x", *c++); +#else + sprintf(buf, "%.*s", key->mv_size, key->mv_data); +#endif + return buf; +} + +static const char * +mdb_leafnode_type(MDB_node *n) +{ + static char *const tp[2][2] = {{"", ": DB"}, {": sub-page", ": sub-DB"}}; + return F_ISSET(n->mn_flags, F_BIGDATA) ? ": overflow page" : + tp[F_ISSET(n->mn_flags, F_DUPDATA)][F_ISSET(n->mn_flags, F_SUBDATA)]; +} + +/** Display all the keys in the page. */ +void +mdb_page_list(MDB_page *mp) +{ + pgno_t pgno = mdb_dbg_pgno(mp); + const char *type, *state = (mp->mp_flags & P_DIRTY) ? ", dirty" : ""; + MDB_node *node; + unsigned int i, nkeys, nsize, total = 0; + MDB_val key; + DKBUF; + + switch (mp->mp_flags & (P_BRANCH|P_LEAF|P_LEAF2|P_META|P_OVERFLOW|P_SUBP)) { + case P_BRANCH: type = "Branch page"; break; + case P_LEAF: type = "Leaf page"; break; + case P_LEAF|P_SUBP: type = "Sub-page"; break; + case P_LEAF|P_LEAF2: type = "LEAF2 page"; break; + case P_LEAF|P_LEAF2|P_SUBP: type = "LEAF2 sub-page"; break; + case P_OVERFLOW: + fprintf(stderr, "Overflow page %"Y"u pages %u%s\n", + pgno, mp->mp_pages, state); + return; + case P_META: + fprintf(stderr, "Meta-page %"Y"u txnid %"Y"u\n", + pgno, ((MDB_meta *)METADATA(mp))->mm_txnid); + return; + default: + fprintf(stderr, "Bad page %"Y"u flags 0x%u\n", pgno, mp->mp_flags); + return; + } + + nkeys = NUMKEYS(mp); + fprintf(stderr, "%s %"Y"u numkeys %d%s\n", type, pgno, nkeys, state); + + for (i=0; imp_pad; + key.mv_data = LEAF2KEY(mp, i, nsize); + total += nsize; + fprintf(stderr, "key %d: nsize %d, %s\n", i, nsize, DKEY(&key)); + continue; + } + node = NODEPTR(mp, i); + key.mv_size = node->mn_ksize; + key.mv_data = node->mn_data; + nsize = NODESIZE + key.mv_size; + if (IS_BRANCH(mp)) { + fprintf(stderr, "key %d: page %"Y"u, %s\n", i, NODEPGNO(node), + DKEY(&key)); + total += nsize; + } else { + if (F_ISSET(node->mn_flags, F_BIGDATA)) + nsize += sizeof(pgno_t); + else + nsize += NODEDSZ(node); + total += nsize; + nsize += sizeof(indx_t); + fprintf(stderr, "key %d: nsize %d, %s%s\n", + i, nsize, DKEY(&key), mdb_leafnode_type(node)); + } + total = EVEN(total); + } + fprintf(stderr, "Total: header %d + contents %d + unused %d\n", + IS_LEAF2(mp) ? PAGEHDRSZ : PAGEBASE + mp->mp_lower, total, SIZELEFT(mp)); +} + +void +mdb_cursor_chk(MDB_cursor *mc) +{ + unsigned int i; + MDB_node *node; + MDB_page *mp; + + if (!mc->mc_snum || !(mc->mc_flags & C_INITIALIZED)) return; + for (i=0; imc_top; i++) { + mp = mc->mc_pg[i]; + node = NODEPTR(mp, mc->mc_ki[i]); + if (NODEPGNO(node) != mc->mc_pg[i+1]->mp_pgno) + printf("oops!\n"); + } + if (mc->mc_ki[i] >= NUMKEYS(mc->mc_pg[i])) + printf("ack!\n"); + if (mc->mc_xcursor && (mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED)) { + node = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]); + if (((node->mn_flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA) && + mc->mc_xcursor->mx_cursor.mc_pg[0] != NODEDATA(node)) { + printf("blah!\n"); + } + } +} +#endif + +#if (MDB_DEBUG) > 2 +/** Count all the pages in each DB and in the freelist + * and make sure it matches the actual number of pages + * being used. + * All named DBs must be open for a correct count. + */ +static void mdb_audit(MDB_txn *txn) +{ + MDB_cursor mc; + MDB_val key, data; + MDB_ID freecount, count; + MDB_dbi i; + int rc; + + freecount = 0; + mdb_cursor_init(&mc, txn, FREE_DBI, NULL); + while ((rc = mdb_cursor_get(&mc, &key, &data, MDB_NEXT)) == 0) + freecount += *(MDB_ID *)data.mv_data; + mdb_tassert(txn, rc == MDB_NOTFOUND); + + count = 0; + for (i = 0; imt_numdbs; i++) { + MDB_xcursor mx; + if (!(txn->mt_dbflags[i] & DB_VALID)) + continue; + mdb_cursor_init(&mc, txn, i, &mx); + if (txn->mt_dbs[i].md_root == P_INVALID) + continue; + count += txn->mt_dbs[i].md_branch_pages + + txn->mt_dbs[i].md_leaf_pages + + txn->mt_dbs[i].md_overflow_pages; + if (txn->mt_dbs[i].md_flags & MDB_DUPSORT) { + rc = mdb_page_search(&mc, NULL, MDB_PS_FIRST); + for (; rc == MDB_SUCCESS; rc = mdb_cursor_sibling(&mc, 1)) { + unsigned j; + MDB_page *mp; + mp = mc.mc_pg[mc.mc_top]; + for (j=0; jmn_flags & F_SUBDATA) { + MDB_db db; + memcpy(&db, NODEDATA(leaf), sizeof(db)); + count += db.md_branch_pages + db.md_leaf_pages + + db.md_overflow_pages; + } + } + } + mdb_tassert(txn, rc == MDB_NOTFOUND); + } + } + if (freecount + count + NUM_METAS != txn->mt_next_pgno) { + fprintf(stderr, "audit: %"Y"u freecount: %"Y"u count: %"Y"u total: %"Y"u next_pgno: %"Y"u\n", + txn->mt_txnid, freecount, count+NUM_METAS, + freecount+count+NUM_METAS, txn->mt_next_pgno); + } +} +#endif + +int +mdb_cmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b) +{ + return txn->mt_dbxs[dbi].md_cmp(a, b); +} + +int +mdb_dcmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b) +{ + MDB_cmp_func *dcmp = txn->mt_dbxs[dbi].md_dcmp; +#if UINT_MAX < SIZE_MAX || defined(MDB_VL32) + if (dcmp == mdb_cmp_int && a->mv_size == sizeof(mdb_size_t)) + dcmp = mdb_cmp_clong; +#endif + return dcmp(a, b); +} + +/** Allocate memory for a page. + * Re-use old malloc'd pages first for singletons, otherwise just malloc. + */ +static MDB_page * +mdb_page_malloc(MDB_txn *txn, unsigned num) +{ + MDB_env *env = txn->mt_env; + MDB_page *ret = env->me_dpages; + size_t psize = env->me_psize, sz = psize, off; + /* For ! #MDB_NOMEMINIT, psize counts how much to init. + * For a single page alloc, we init everything after the page header. + * For multi-page, we init the final page; if the caller needed that + * many pages they will be filling in at least up to the last page. + */ + if (num == 1) { + if (ret) { + VGMEMP_ALLOC(env, ret, sz); + VGMEMP_DEFINED(ret, sizeof(ret->mp_next)); + env->me_dpages = ret->mp_next; + return ret; + } + psize -= off = PAGEHDRSZ; + } else { + sz *= num; + off = sz - psize; + } + if ((ret = malloc(sz)) != NULL) { + VGMEMP_ALLOC(env, ret, sz); + if (!(env->me_flags & MDB_NOMEMINIT)) { + memset((char *)ret + off, 0, psize); + ret->mp_pad = 0; + } + } else { + txn->mt_flags |= MDB_TXN_ERROR; + } + return ret; +} +/** Free a single page. + * Saves single pages to a list, for future reuse. + * (This is not used for multi-page overflow pages.) + */ +static void +mdb_page_free(MDB_env *env, MDB_page *mp) +{ + mp->mp_next = env->me_dpages; + VGMEMP_FREE(env, mp); + env->me_dpages = mp; +} + +/** Free a dirty page */ +static void +mdb_dpage_free(MDB_env *env, MDB_page *dp) +{ + if (!IS_OVERFLOW(dp) || dp->mp_pages == 1) { + mdb_page_free(env, dp); + } else { + /* large pages just get freed directly */ + VGMEMP_FREE(env, dp); + free(dp); + } +} + +/** Return all dirty pages to dpage list */ +static void +mdb_dlist_free(MDB_txn *txn) +{ + MDB_env *env = txn->mt_env; + MDB_ID2L dl = txn->mt_u.dirty_list; + unsigned i, n = dl[0].mid; + + for (i = 1; i <= n; i++) { + mdb_dpage_free(env, dl[i].mptr); + } + dl[0].mid = 0; +} + +#ifdef MDB_VL32 +static void +mdb_page_unref(MDB_txn *txn, MDB_page *mp) +{ + pgno_t pgno; + MDB_ID3L tl = txn->mt_rpages; + unsigned x, rem; + if (mp->mp_flags & (P_SUBP|P_DIRTY)) + return; + rem = mp->mp_pgno & (MDB_RPAGE_CHUNK-1); + pgno = mp->mp_pgno ^ rem; + x = mdb_mid3l_search(tl, pgno); + if (x != tl[0].mid && tl[x+1].mid == mp->mp_pgno) + x++; + if (tl[x].mref) + tl[x].mref--; +} +#define MDB_PAGE_UNREF(txn, mp) mdb_page_unref(txn, mp) + +static void +mdb_cursor_unref(MDB_cursor *mc) +{ + int i; + if (mc->mc_txn->mt_rpages[0].mid) { + if (!mc->mc_snum || !mc->mc_pg[0] || IS_SUBP(mc->mc_pg[0])) + return; + for (i=0; imc_snum; i++) + mdb_page_unref(mc->mc_txn, mc->mc_pg[i]); + if (mc->mc_ovpg) { + mdb_page_unref(mc->mc_txn, mc->mc_ovpg); + mc->mc_ovpg = 0; + } + } + mc->mc_snum = mc->mc_top = 0; + mc->mc_pg[0] = NULL; + mc->mc_flags &= ~C_INITIALIZED; +} +#else +#define MDB_PAGE_UNREF(txn, mp) +#endif /* MDB_VL32 */ + +/** Loosen or free a single page. + * Saves single pages to a list for future reuse + * in this same txn. It has been pulled from the freeDB + * and already resides on the dirty list, but has been + * deleted. Use these pages first before pulling again + * from the freeDB. + * + * If the page wasn't dirtied in this txn, just add it + * to this txn's free list. + */ +static int +mdb_page_loose(MDB_cursor *mc, MDB_page *mp) +{ + int loose = 0; + pgno_t pgno = mp->mp_pgno; + MDB_txn *txn = mc->mc_txn; + + if ((mp->mp_flags & P_DIRTY) && mc->mc_dbi != FREE_DBI) { + if (txn->mt_parent) { + MDB_ID2 *dl = txn->mt_u.dirty_list; + /* If txn has a parent, make sure the page is in our + * dirty list. + */ + if (dl[0].mid) { + unsigned x = mdb_mid2l_search(dl, pgno); + if (x <= dl[0].mid && dl[x].mid == pgno) { + if (mp != dl[x].mptr) { /* bad cursor? */ + mc->mc_flags &= ~(C_INITIALIZED|C_EOF); + txn->mt_flags |= MDB_TXN_ERROR; + return MDB_CORRUPTED; + } + /* ok, it's ours */ + loose = 1; + } + } + } else { + /* no parent txn, so it's just ours */ + loose = 1; + } + } + if (loose) { + DPRINTF(("loosen db %d page %"Y"u", DDBI(mc), + mp->mp_pgno)); + NEXT_LOOSE_PAGE(mp) = txn->mt_loose_pgs; + txn->mt_loose_pgs = mp; + txn->mt_loose_count++; + mp->mp_flags |= P_LOOSE; + } else { + int rc = mdb_midl_append(&txn->mt_free_pgs, pgno); + if (rc) + return rc; + } + + return MDB_SUCCESS; +} + +/** Set or clear P_KEEP in dirty, non-overflow, non-sub pages watched by txn. + * @param[in] mc A cursor handle for the current operation. + * @param[in] pflags Flags of the pages to update: + * P_DIRTY to set P_KEEP, P_DIRTY|P_KEEP to clear it. + * @param[in] all No shortcuts. Needed except after a full #mdb_page_flush(). + * @return 0 on success, non-zero on failure. + */ +static int +mdb_pages_xkeep(MDB_cursor *mc, unsigned pflags, int all) +{ + enum { Mask = P_SUBP|P_DIRTY|P_LOOSE|P_KEEP }; + MDB_txn *txn = mc->mc_txn; + MDB_cursor *m3, *m0 = mc; + MDB_xcursor *mx; + MDB_page *dp, *mp; + MDB_node *leaf; + unsigned i, j; + int rc = MDB_SUCCESS, level; + + /* Mark pages seen by cursors */ + if (mc->mc_flags & C_UNTRACK) + mc = NULL; /* will find mc in mt_cursors */ + for (i = txn->mt_numdbs;; mc = txn->mt_cursors[--i]) { + for (; mc; mc=mc->mc_next) { + if (!(mc->mc_flags & C_INITIALIZED)) + continue; + for (m3 = mc;; m3 = &mx->mx_cursor) { + mp = NULL; + for (j=0; jmc_snum; j++) { + mp = m3->mc_pg[j]; + if ((mp->mp_flags & Mask) == pflags) + mp->mp_flags ^= P_KEEP; + } + mx = m3->mc_xcursor; + /* Proceed to mx if it is at a sub-database */ + if (! (mx && (mx->mx_cursor.mc_flags & C_INITIALIZED))) + break; + if (! (mp && (mp->mp_flags & P_LEAF))) + break; + leaf = NODEPTR(mp, m3->mc_ki[j-1]); + if (!(leaf->mn_flags & F_SUBDATA)) + break; + } + } + if (i == 0) + break; + } + + if (all) { + /* Mark dirty root pages */ + for (i=0; imt_numdbs; i++) { + if (txn->mt_dbflags[i] & DB_DIRTY) { + pgno_t pgno = txn->mt_dbs[i].md_root; + if (pgno == P_INVALID) + continue; + if ((rc = mdb_page_get(m0, pgno, &dp, &level)) != MDB_SUCCESS) + break; + if ((dp->mp_flags & Mask) == pflags && level <= 1) + dp->mp_flags ^= P_KEEP; + } + } + } + + return rc; +} + +static int mdb_page_flush(MDB_txn *txn, int keep); + +/** Spill pages from the dirty list back to disk. + * This is intended to prevent running into #MDB_TXN_FULL situations, + * but note that they may still occur in a few cases: + * 1) our estimate of the txn size could be too small. Currently this + * seems unlikely, except with a large number of #MDB_MULTIPLE items. + * 2) child txns may run out of space if their parents dirtied a + * lot of pages and never spilled them. TODO: we probably should do + * a preemptive spill during #mdb_txn_begin() of a child txn, if + * the parent's dirty_room is below a given threshold. + * + * Otherwise, if not using nested txns, it is expected that apps will + * not run into #MDB_TXN_FULL any more. The pages are flushed to disk + * the same way as for a txn commit, e.g. their P_DIRTY flag is cleared. + * If the txn never references them again, they can be left alone. + * If the txn only reads them, they can be used without any fuss. + * If the txn writes them again, they can be dirtied immediately without + * going thru all of the work of #mdb_page_touch(). Such references are + * handled by #mdb_page_unspill(). + * + * Also note, we never spill DB root pages, nor pages of active cursors, + * because we'll need these back again soon anyway. And in nested txns, + * we can't spill a page in a child txn if it was already spilled in a + * parent txn. That would alter the parent txns' data even though + * the child hasn't committed yet, and we'd have no way to undo it if + * the child aborted. + * + * @param[in] m0 cursor A cursor handle identifying the transaction and + * database for which we are checking space. + * @param[in] key For a put operation, the key being stored. + * @param[in] data For a put operation, the data being stored. + * @return 0 on success, non-zero on failure. + */ +static int +mdb_page_spill(MDB_cursor *m0, MDB_val *key, MDB_val *data) +{ + MDB_txn *txn = m0->mc_txn; + MDB_page *dp; + MDB_ID2L dl = txn->mt_u.dirty_list; + unsigned int i, j, need; + int rc; + + if (m0->mc_flags & C_SUB) + return MDB_SUCCESS; + + /* Estimate how much space this op will take */ + i = m0->mc_db->md_depth; + /* Named DBs also dirty the main DB */ + if (m0->mc_dbi >= CORE_DBS) + i += txn->mt_dbs[MAIN_DBI].md_depth; + /* For puts, roughly factor in the key+data size */ + if (key) + i += (LEAFSIZE(key, data) + txn->mt_env->me_psize) / txn->mt_env->me_psize; + i += i; /* double it for good measure */ + need = i; + + if (txn->mt_dirty_room > i) + return MDB_SUCCESS; + + if (!txn->mt_spill_pgs) { + txn->mt_spill_pgs = mdb_midl_alloc(MDB_IDL_UM_MAX); + if (!txn->mt_spill_pgs) + return ENOMEM; + } else { + /* purge deleted slots */ + MDB_IDL sl = txn->mt_spill_pgs; + unsigned int num = sl[0]; + j=0; + for (i=1; i<=num; i++) { + if (!(sl[i] & 1)) + sl[++j] = sl[i]; + } + sl[0] = j; + } + + /* Preserve pages which may soon be dirtied again */ + if ((rc = mdb_pages_xkeep(m0, P_DIRTY, 1)) != MDB_SUCCESS) + goto done; + + /* Less aggressive spill - we originally spilled the entire dirty list, + * with a few exceptions for cursor pages and DB root pages. But this + * turns out to be a lot of wasted effort because in a large txn many + * of those pages will need to be used again. So now we spill only 1/8th + * of the dirty pages. Testing revealed this to be a good tradeoff, + * better than 1/2, 1/4, or 1/10. + */ + if (need < MDB_IDL_UM_MAX / 8) + need = MDB_IDL_UM_MAX / 8; + + /* Save the page IDs of all the pages we're flushing */ + /* flush from the tail forward, this saves a lot of shifting later on. */ + for (i=dl[0].mid; i && need; i--) { + MDB_ID pn = dl[i].mid << 1; + dp = dl[i].mptr; + if (dp->mp_flags & (P_LOOSE|P_KEEP)) + continue; + /* Can't spill twice, make sure it's not already in a parent's + * spill list. + */ + if (txn->mt_parent) { + MDB_txn *tx2; + for (tx2 = txn->mt_parent; tx2; tx2 = tx2->mt_parent) { + if (tx2->mt_spill_pgs) { + j = mdb_midl_search(tx2->mt_spill_pgs, pn); + if (j <= tx2->mt_spill_pgs[0] && tx2->mt_spill_pgs[j] == pn) { + dp->mp_flags |= P_KEEP; + break; + } + } + } + if (tx2) + continue; + } + if ((rc = mdb_midl_append(&txn->mt_spill_pgs, pn))) + goto done; + need--; + } + mdb_midl_sort(txn->mt_spill_pgs); + + /* Flush the spilled part of dirty list */ + if ((rc = mdb_page_flush(txn, i)) != MDB_SUCCESS) + goto done; + + /* Reset any dirty pages we kept that page_flush didn't see */ + rc = mdb_pages_xkeep(m0, P_DIRTY|P_KEEP, i); + +done: + txn->mt_flags |= rc ? MDB_TXN_ERROR : MDB_TXN_SPILLS; + return rc; +} + +/** Find oldest txnid still referenced. Expects txn->mt_txnid > 0. */ +static txnid_t +mdb_find_oldest(MDB_txn *txn) +{ + int i; + txnid_t mr, oldest = txn->mt_txnid - 1; + if (txn->mt_env->me_txns) { + MDB_reader *r = txn->mt_env->me_txns->mti_readers; + for (i = txn->mt_env->me_txns->mti_numreaders; --i >= 0; ) { + if (r[i].mr_pid) { + mr = r[i].mr_txnid; + if (oldest > mr) + oldest = mr; + } + } + } + return oldest; +} + +/** Add a page to the txn's dirty list */ +static void +mdb_page_dirty(MDB_txn *txn, MDB_page *mp) +{ + MDB_ID2 mid; + int rc, (*insert)(MDB_ID2L, MDB_ID2 *); + + if (txn->mt_flags & MDB_TXN_WRITEMAP) { + insert = mdb_mid2l_append; + } else { + insert = mdb_mid2l_insert; + } + mid.mid = mp->mp_pgno; + mid.mptr = mp; + rc = insert(txn->mt_u.dirty_list, &mid); + mdb_tassert(txn, rc == 0); + txn->mt_dirty_room--; +} + +/** Allocate page numbers and memory for writing. Maintain me_pglast, + * me_pghead and mt_next_pgno. + * + * If there are free pages available from older transactions, they + * are re-used first. Otherwise allocate a new page at mt_next_pgno. + * Do not modify the freedB, just merge freeDB records into me_pghead[] + * and move me_pglast to say which records were consumed. Only this + * function can create me_pghead and move me_pglast/mt_next_pgno. + * When #MDB_DEVEL & 2, it is not affected by #mdb_freelist_save(): it + * then uses the transaction's original snapshot of the freeDB. + * @param[in] mc cursor A cursor handle identifying the transaction and + * database for which we are allocating. + * @param[in] num the number of pages to allocate. + * @param[out] mp Address of the allocated page(s). Requests for multiple pages + * will always be satisfied by a single contiguous chunk of memory. + * @return 0 on success, non-zero on failure. + */ +static int +mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp) +{ +#ifdef MDB_PARANOID /* Seems like we can ignore this now */ + /* Get at most more freeDB records once me_pghead + * has enough pages. If not enough, use new pages from the map. + * If and mc is updating the freeDB, only get new + * records if me_pghead is empty. Then the freelist cannot play + * catch-up with itself by growing while trying to save it. + */ + enum { Paranoid = 1, Max_retries = 500 }; +#else + enum { Paranoid = 0, Max_retries = INT_MAX /*infinite*/ }; +#endif + int rc, retry = num * 60; + MDB_txn *txn = mc->mc_txn; + MDB_env *env = txn->mt_env; + pgno_t pgno, *mop = env->me_pghead; + unsigned i, j, mop_len = mop ? mop[0] : 0, n2 = num-1; + MDB_page *np; + txnid_t oldest = 0, last; + MDB_cursor_op op; + MDB_cursor m2; + int found_old = 0; + + /* If there are any loose pages, just use them */ + if (num == 1 && txn->mt_loose_pgs) { + np = txn->mt_loose_pgs; + txn->mt_loose_pgs = NEXT_LOOSE_PAGE(np); + txn->mt_loose_count--; + DPRINTF(("db %d use loose page %"Y"u", DDBI(mc), + np->mp_pgno)); + *mp = np; + return MDB_SUCCESS; + } + + *mp = NULL; + + /* If our dirty list is already full, we can't do anything */ + if (txn->mt_dirty_room == 0) { + rc = MDB_TXN_FULL; + goto fail; + } + + for (op = MDB_FIRST;; op = MDB_NEXT) { + MDB_val key, data; + MDB_node *leaf; + pgno_t *idl; + + /* Seek a big enough contiguous page range. Prefer + * pages at the tail, just truncating the list. + */ + if (mop_len > n2) { + i = mop_len; + do { + pgno = mop[i]; + if (mop[i-n2] == pgno+n2) + goto search_done; + } while (--i > n2); + if (--retry < 0) + break; + } + + if (op == MDB_FIRST) { /* 1st iteration */ + /* Prepare to fetch more and coalesce */ + last = env->me_pglast; + oldest = env->me_pgoldest; + mdb_cursor_init(&m2, txn, FREE_DBI, NULL); +#if (MDB_DEVEL) & 2 /* "& 2" so MDB_DEVEL=1 won't hide bugs breaking freeDB */ + /* Use original snapshot. TODO: Should need less care in code + * which modifies the database. Maybe we can delete some code? + */ + m2.mc_flags |= C_ORIG_RDONLY; + m2.mc_db = &env->me_metas[(txn->mt_txnid-1) & 1]->mm_dbs[FREE_DBI]; + m2.mc_dbflag = (unsigned char *)""; /* probably unnecessary */ +#endif + if (last) { + op = MDB_SET_RANGE; + key.mv_data = &last; /* will look up last+1 */ + key.mv_size = sizeof(last); + } + if (Paranoid && mc->mc_dbi == FREE_DBI) + retry = -1; + } + if (Paranoid && retry < 0 && mop_len) + break; + + last++; + /* Do not fetch more if the record will be too recent */ + if (oldest <= last) { + if (!found_old) { + oldest = mdb_find_oldest(txn); + env->me_pgoldest = oldest; + found_old = 1; + } + if (oldest <= last) + break; + } + rc = mdb_cursor_get(&m2, &key, NULL, op); + if (rc) { + if (rc == MDB_NOTFOUND) + break; + goto fail; + } + last = *(txnid_t*)key.mv_data; + if (oldest <= last) { + if (!found_old) { + oldest = mdb_find_oldest(txn); + env->me_pgoldest = oldest; + found_old = 1; + } + if (oldest <= last) + break; + } + np = m2.mc_pg[m2.mc_top]; + leaf = NODEPTR(np, m2.mc_ki[m2.mc_top]); + if ((rc = mdb_node_read(&m2, leaf, &data)) != MDB_SUCCESS) + return rc; + + idl = (MDB_ID *) data.mv_data; + i = idl[0]; + if (!mop) { + if (!(env->me_pghead = mop = mdb_midl_alloc(i))) { + rc = ENOMEM; + goto fail; + } + } else { + if ((rc = mdb_midl_need(&env->me_pghead, i)) != 0) + goto fail; + mop = env->me_pghead; + } + env->me_pglast = last; +#if (MDB_DEBUG) > 1 + DPRINTF(("IDL read txn %"Y"u root %"Y"u num %u", + last, txn->mt_dbs[FREE_DBI].md_root, i)); + for (j = i; j; j--) + DPRINTF(("IDL %"Y"u", idl[j])); +#endif + /* Merge in descending sorted order */ + mdb_midl_xmerge(mop, idl); + mop_len = mop[0]; + } + + /* Use new pages from the map when nothing suitable in the freeDB */ + i = 0; + pgno = txn->mt_next_pgno; + if (pgno + num >= env->me_maxpg) { + DPUTS("DB size maxed out"); + rc = MDB_MAP_FULL; + goto fail; + } +#if defined(_WIN32) && !defined(MDB_VL32) + if (!(env->me_flags & MDB_RDONLY)) { + void *p; + p = (MDB_page *)(env->me_map + env->me_psize * pgno); + p = VirtualAlloc(p, env->me_psize * num, MEM_COMMIT, + (env->me_flags & MDB_WRITEMAP) ? PAGE_READWRITE: + PAGE_READONLY); + if (!p) { + DPUTS("VirtualAlloc failed"); + rc = ErrCode(); + goto fail; + } + } +#endif + +search_done: + if (env->me_flags & MDB_WRITEMAP) { + np = (MDB_page *)(env->me_map + env->me_psize * pgno); + } else { + if (!(np = mdb_page_malloc(txn, num))) { + rc = ENOMEM; + goto fail; + } + } + if (i) { + mop[0] = mop_len -= num; + /* Move any stragglers down */ + for (j = i-num; j < mop_len; ) + mop[++j] = mop[++i]; + } else { + txn->mt_next_pgno = pgno + num; + } + np->mp_pgno = pgno; + mdb_page_dirty(txn, np); + *mp = np; + + return MDB_SUCCESS; + +fail: + txn->mt_flags |= MDB_TXN_ERROR; + return rc; +} + +/** Copy the used portions of a non-overflow page. + * @param[in] dst page to copy into + * @param[in] src page to copy from + * @param[in] psize size of a page + */ +static void +mdb_page_copy(MDB_page *dst, MDB_page *src, unsigned int psize) +{ + enum { Align = sizeof(pgno_t) }; + indx_t upper = src->mp_upper, lower = src->mp_lower, unused = upper-lower; + + /* If page isn't full, just copy the used portion. Adjust + * alignment so memcpy may copy words instead of bytes. + */ + if ((unused &= -Align) && !IS_LEAF2(src)) { + upper = (upper + PAGEBASE) & -Align; + memcpy(dst, src, (lower + PAGEBASE + (Align-1)) & -Align); + memcpy((pgno_t *)((char *)dst+upper), (pgno_t *)((char *)src+upper), + psize - upper); + } else { + memcpy(dst, src, psize - unused); + } +} + +/** Pull a page off the txn's spill list, if present. + * If a page being referenced was spilled to disk in this txn, bring + * it back and make it dirty/writable again. + * @param[in] txn the transaction handle. + * @param[in] mp the page being referenced. It must not be dirty. + * @param[out] ret the writable page, if any. ret is unchanged if + * mp wasn't spilled. + */ +static int +mdb_page_unspill(MDB_txn *txn, MDB_page *mp, MDB_page **ret) +{ + MDB_env *env = txn->mt_env; + const MDB_txn *tx2; + unsigned x; + pgno_t pgno = mp->mp_pgno, pn = pgno << 1; + + for (tx2 = txn; tx2; tx2=tx2->mt_parent) { + if (!tx2->mt_spill_pgs) + continue; + x = mdb_midl_search(tx2->mt_spill_pgs, pn); + if (x <= tx2->mt_spill_pgs[0] && tx2->mt_spill_pgs[x] == pn) { + MDB_page *np; + int num; + if (txn->mt_dirty_room == 0) + return MDB_TXN_FULL; + if (IS_OVERFLOW(mp)) + num = mp->mp_pages; + else + num = 1; + if (env->me_flags & MDB_WRITEMAP) { + np = mp; + } else { + np = mdb_page_malloc(txn, num); + if (!np) + return ENOMEM; + if (num > 1) + memcpy(np, mp, num * env->me_psize); + else + mdb_page_copy(np, mp, env->me_psize); + } + if (tx2 == txn) { + /* If in current txn, this page is no longer spilled. + * If it happens to be the last page, truncate the spill list. + * Otherwise mark it as deleted by setting the LSB. + */ + if (x == txn->mt_spill_pgs[0]) + txn->mt_spill_pgs[0]--; + else + txn->mt_spill_pgs[x] |= 1; + } /* otherwise, if belonging to a parent txn, the + * page remains spilled until child commits + */ + + mdb_page_dirty(txn, np); + np->mp_flags |= P_DIRTY; + *ret = np; + break; + } + } + return MDB_SUCCESS; +} + +/** Touch a page: make it dirty and re-insert into tree with updated pgno. + * @param[in] mc cursor pointing to the page to be touched + * @return 0 on success, non-zero on failure. + */ +static int +mdb_page_touch(MDB_cursor *mc) +{ + MDB_page *mp = mc->mc_pg[mc->mc_top], *np; + MDB_txn *txn = mc->mc_txn; + MDB_cursor *m2, *m3; + pgno_t pgno; + int rc; + + if (!F_ISSET(mp->mp_flags, P_DIRTY)) { + if (txn->mt_flags & MDB_TXN_SPILLS) { + np = NULL; + rc = mdb_page_unspill(txn, mp, &np); + if (rc) + goto fail; + if (np) + goto done; + } + if ((rc = mdb_midl_need(&txn->mt_free_pgs, 1)) || + (rc = mdb_page_alloc(mc, 1, &np))) + goto fail; + pgno = np->mp_pgno; + DPRINTF(("touched db %d page %"Y"u -> %"Y"u", DDBI(mc), + mp->mp_pgno, pgno)); + mdb_cassert(mc, mp->mp_pgno != pgno); + mdb_midl_xappend(txn->mt_free_pgs, mp->mp_pgno); + /* Update the parent page, if any, to point to the new page */ + if (mc->mc_top) { + MDB_page *parent = mc->mc_pg[mc->mc_top-1]; + MDB_node *node = NODEPTR(parent, mc->mc_ki[mc->mc_top-1]); + SETPGNO(node, pgno); + } else { + mc->mc_db->md_root = pgno; + } + } else if (txn->mt_parent && !IS_SUBP(mp)) { + MDB_ID2 mid, *dl = txn->mt_u.dirty_list; + pgno = mp->mp_pgno; + /* If txn has a parent, make sure the page is in our + * dirty list. + */ + if (dl[0].mid) { + unsigned x = mdb_mid2l_search(dl, pgno); + if (x <= dl[0].mid && dl[x].mid == pgno) { + if (mp != dl[x].mptr) { /* bad cursor? */ + mc->mc_flags &= ~(C_INITIALIZED|C_EOF); + txn->mt_flags |= MDB_TXN_ERROR; + return MDB_CORRUPTED; + } + return 0; + } + } + mdb_cassert(mc, dl[0].mid < MDB_IDL_UM_MAX); + /* No - copy it */ + np = mdb_page_malloc(txn, 1); + if (!np) + return ENOMEM; + mid.mid = pgno; + mid.mptr = np; + rc = mdb_mid2l_insert(dl, &mid); + mdb_cassert(mc, rc == 0); + } else { + return 0; + } + + mdb_page_copy(np, mp, txn->mt_env->me_psize); + np->mp_pgno = pgno; + np->mp_flags |= P_DIRTY; + +done: + /* Adjust cursors pointing to mp */ + mc->mc_pg[mc->mc_top] = np; + m2 = txn->mt_cursors[mc->mc_dbi]; + if (mc->mc_flags & C_SUB) { + for (; m2; m2=m2->mc_next) { + m3 = &m2->mc_xcursor->mx_cursor; + if (m3->mc_snum < mc->mc_snum) continue; + if (m3->mc_pg[mc->mc_top] == mp) + m3->mc_pg[mc->mc_top] = np; + } + } else { + for (; m2; m2=m2->mc_next) { + if (m2->mc_snum < mc->mc_snum) continue; + if (m2 == mc) continue; + if (m2->mc_pg[mc->mc_top] == mp) { + m2->mc_pg[mc->mc_top] = np; + if ((mc->mc_db->md_flags & MDB_DUPSORT) && + IS_LEAF(np) && + (m2->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED)) + { + MDB_node *leaf = NODEPTR(np, m2->mc_ki[mc->mc_top]); + if ((leaf->mn_flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA) + m2->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(leaf); + } + } + } + } + MDB_PAGE_UNREF(mc->mc_txn, mp); + return 0; + +fail: + txn->mt_flags |= MDB_TXN_ERROR; + return rc; +} + +int +mdb_env_sync0(MDB_env *env, int force, pgno_t numpgs) +{ + int rc = 0; + if (env->me_flags & MDB_RDONLY) + return EACCES; + if (force || !F_ISSET(env->me_flags, MDB_NOSYNC)) { + if (env->me_flags & MDB_WRITEMAP) { + int flags = ((env->me_flags & MDB_MAPASYNC) && !force) + ? MS_ASYNC : MS_SYNC; + if (MDB_MSYNC(env->me_map, env->me_psize * numpgs, flags)) + rc = ErrCode(); +#ifdef _WIN32 + else if (flags == MS_SYNC && MDB_FDATASYNC(env->me_fd)) + rc = ErrCode(); +#endif + } else { +#ifdef BROKEN_FDATASYNC + if (env->me_flags & MDB_FSYNCONLY) { + if (fsync(env->me_fd)) + rc = ErrCode(); + } else +#endif + if (MDB_FDATASYNC(env->me_fd)) + rc = ErrCode(); + } + } + return rc; +} + +int +mdb_env_sync(MDB_env *env, int force) +{ + MDB_meta *m = mdb_env_pick_meta(env); + return mdb_env_sync0(env, force, m->mm_last_pg+1); +} + +/** Back up parent txn's cursors, then grab the originals for tracking */ +static int +mdb_cursor_shadow(MDB_txn *src, MDB_txn *dst) +{ + MDB_cursor *mc, *bk; + MDB_xcursor *mx; + size_t size; + int i; + + for (i = src->mt_numdbs; --i >= 0; ) { + if ((mc = src->mt_cursors[i]) != NULL) { + size = sizeof(MDB_cursor); + if (mc->mc_xcursor) + size += sizeof(MDB_xcursor); + for (; mc; mc = bk->mc_next) { + bk = malloc(size); + if (!bk) + return ENOMEM; + *bk = *mc; + mc->mc_backup = bk; + mc->mc_db = &dst->mt_dbs[i]; + /* Kill pointers into src to reduce abuse: The + * user may not use mc until dst ends. But we need a valid + * txn pointer here for cursor fixups to keep working. + */ + mc->mc_txn = dst; + mc->mc_dbflag = &dst->mt_dbflags[i]; + if ((mx = mc->mc_xcursor) != NULL) { + *(MDB_xcursor *)(bk+1) = *mx; + mx->mx_cursor.mc_txn = dst; + } + mc->mc_next = dst->mt_cursors[i]; + dst->mt_cursors[i] = mc; + } + } + } + return MDB_SUCCESS; +} + +/** Close this write txn's cursors, give parent txn's cursors back to parent. + * @param[in] txn the transaction handle. + * @param[in] merge true to keep changes to parent cursors, false to revert. + * @return 0 on success, non-zero on failure. + */ +static void +mdb_cursors_close(MDB_txn *txn, unsigned merge) +{ + MDB_cursor **cursors = txn->mt_cursors, *mc, *next, *bk; + MDB_xcursor *mx; + int i; + + for (i = txn->mt_numdbs; --i >= 0; ) { + for (mc = cursors[i]; mc; mc = next) { + next = mc->mc_next; + if ((bk = mc->mc_backup) != NULL) { + if (merge) { + /* Commit changes to parent txn */ + mc->mc_next = bk->mc_next; + mc->mc_backup = bk->mc_backup; + mc->mc_txn = bk->mc_txn; + mc->mc_db = bk->mc_db; + mc->mc_dbflag = bk->mc_dbflag; + if ((mx = mc->mc_xcursor) != NULL) + mx->mx_cursor.mc_txn = bk->mc_txn; + } else { + /* Abort nested txn */ + *mc = *bk; + if ((mx = mc->mc_xcursor) != NULL) + *mx = *(MDB_xcursor *)(bk+1); + } + mc = bk; + } + /* Only malloced cursors are permanently tracked. */ + free(mc); + } + cursors[i] = NULL; + } +} + +#if !(MDB_PIDLOCK) /* Currently the same as defined(_WIN32) */ +enum Pidlock_op { + Pidset, Pidcheck +}; +#else +enum Pidlock_op { + Pidset = F_SETLK, Pidcheck = F_GETLK +}; +#endif + +/** Set or check a pid lock. Set returns 0 on success. + * Check returns 0 if the process is certainly dead, nonzero if it may + * be alive (the lock exists or an error happened so we do not know). + * + * On Windows Pidset is a no-op, we merely check for the existence + * of the process with the given pid. On POSIX we use a single byte + * lock on the lockfile, set at an offset equal to the pid. + */ +static int +mdb_reader_pid(MDB_env *env, enum Pidlock_op op, MDB_PID_T pid) +{ +#if !(MDB_PIDLOCK) /* Currently the same as defined(_WIN32) */ + int ret = 0; + HANDLE h; + if (op == Pidcheck) { + h = OpenProcess(env->me_pidquery, FALSE, pid); + /* No documented "no such process" code, but other program use this: */ + if (!h) + return ErrCode() != ERROR_INVALID_PARAMETER; + /* A process exists until all handles to it close. Has it exited? */ + ret = WaitForSingleObject(h, 0) != 0; + CloseHandle(h); + } + return ret; +#else + for (;;) { + int rc; + struct flock lock_info; + memset(&lock_info, 0, sizeof(lock_info)); + lock_info.l_type = F_WRLCK; + lock_info.l_whence = SEEK_SET; + lock_info.l_start = pid; + lock_info.l_len = 1; + if ((rc = fcntl(env->me_lfd, op, &lock_info)) == 0) { + if (op == F_GETLK && lock_info.l_type != F_UNLCK) + rc = -1; + } else if ((rc = ErrCode()) == EINTR) { + continue; + } + return rc; + } +#endif +} + +/** Common code for #mdb_txn_begin() and #mdb_txn_renew(). + * @param[in] txn the transaction handle to initialize + * @return 0 on success, non-zero on failure. + */ +static int +mdb_txn_renew0(MDB_txn *txn) +{ + MDB_env *env = txn->mt_env; + MDB_txninfo *ti = env->me_txns; + MDB_meta *meta; + unsigned int i, nr, flags = txn->mt_flags; + uint16_t x; + int rc, new_notls = 0; + + if ((flags &= MDB_TXN_RDONLY) != 0) { + if (!ti) { + meta = mdb_env_pick_meta(env); + txn->mt_txnid = meta->mm_txnid; + txn->mt_u.reader = NULL; + } else { + MDB_reader *r = (env->me_flags & MDB_NOTLS) ? txn->mt_u.reader : + pthread_getspecific(env->me_txkey); + if (r) { + if (r->mr_pid != env->me_pid || r->mr_txnid != (txnid_t)-1) + return MDB_BAD_RSLOT; + } else { + MDB_PID_T pid = env->me_pid; + MDB_THR_T tid = pthread_self(); + mdb_mutexref_t rmutex = env->me_rmutex; + + if (!env->me_live_reader) { + rc = mdb_reader_pid(env, Pidset, pid); + if (rc) + return rc; + env->me_live_reader = 1; + } + + if (LOCK_MUTEX(rc, env, rmutex)) + return rc; + nr = ti->mti_numreaders; + for (i=0; imti_readers[i].mr_pid == 0) + break; + if (i == env->me_maxreaders) { + UNLOCK_MUTEX(rmutex); + return MDB_READERS_FULL; + } + r = &ti->mti_readers[i]; + /* Claim the reader slot, carefully since other code + * uses the reader table un-mutexed: First reset the + * slot, next publish it in mti_numreaders. After + * that, it is safe for mdb_env_close() to touch it. + * When it will be closed, we can finally claim it. + */ + r->mr_pid = 0; + r->mr_txnid = (txnid_t)-1; + r->mr_tid = tid; + if (i == nr) + ti->mti_numreaders = ++nr; + env->me_close_readers = nr; + r->mr_pid = pid; + UNLOCK_MUTEX(rmutex); + + new_notls = (env->me_flags & MDB_NOTLS); + if (!new_notls && (rc=pthread_setspecific(env->me_txkey, r))) { + r->mr_pid = 0; + return rc; + } + } + do /* LY: Retry on a race, ITS#7970. */ + r->mr_txnid = ti->mti_txnid; + while(r->mr_txnid != ti->mti_txnid); + txn->mt_txnid = r->mr_txnid; + txn->mt_u.reader = r; + meta = env->me_metas[txn->mt_txnid & 1]; + } + + } else { + /* Not yet touching txn == env->me_txn0, it may be active */ + if (ti) { + if (LOCK_MUTEX(rc, env, env->me_wmutex)) + return rc; + txn->mt_txnid = ti->mti_txnid; + meta = env->me_metas[txn->mt_txnid & 1]; + } else { + meta = mdb_env_pick_meta(env); + txn->mt_txnid = meta->mm_txnid; + } + txn->mt_txnid++; +#if MDB_DEBUG + if (txn->mt_txnid == mdb_debug_start) + mdb_debug = 1; +#endif + txn->mt_child = NULL; + txn->mt_loose_pgs = NULL; + txn->mt_loose_count = 0; + txn->mt_dirty_room = MDB_IDL_UM_MAX; + txn->mt_u.dirty_list = env->me_dirty_list; + txn->mt_u.dirty_list[0].mid = 0; + txn->mt_free_pgs = env->me_free_pgs; + txn->mt_free_pgs[0] = 0; + txn->mt_spill_pgs = NULL; + env->me_txn = txn; + memcpy(txn->mt_dbiseqs, env->me_dbiseqs, env->me_maxdbs * sizeof(unsigned int)); + } + + /* Copy the DB info and flags */ + memcpy(txn->mt_dbs, meta->mm_dbs, CORE_DBS * sizeof(MDB_db)); + + /* Moved to here to avoid a data race in read TXNs */ + txn->mt_next_pgno = meta->mm_last_pg+1; +#ifdef MDB_VL32 + txn->mt_last_pgno = txn->mt_next_pgno - 1; +#endif + + txn->mt_flags = flags; + + /* Setup db info */ + txn->mt_numdbs = env->me_numdbs; + for (i=CORE_DBS; imt_numdbs; i++) { + x = env->me_dbflags[i]; + txn->mt_dbs[i].md_flags = x & PERSISTENT_FLAGS; + txn->mt_dbflags[i] = (x & MDB_VALID) ? DB_VALID|DB_USRVALID|DB_STALE : 0; + } + txn->mt_dbflags[MAIN_DBI] = DB_VALID|DB_USRVALID; + txn->mt_dbflags[FREE_DBI] = DB_VALID; + + if (env->me_flags & MDB_FATAL_ERROR) { + DPUTS("environment had fatal error, must shutdown!"); + rc = MDB_PANIC; + } else if (env->me_maxpg < txn->mt_next_pgno) { + rc = MDB_MAP_RESIZED; + } else { + return MDB_SUCCESS; + } + mdb_txn_end(txn, new_notls /*0 or MDB_END_SLOT*/ | MDB_END_FAIL_BEGIN); + return rc; +} + +int +mdb_txn_renew(MDB_txn *txn) +{ + int rc; + + if (!txn || !F_ISSET(txn->mt_flags, MDB_TXN_RDONLY|MDB_TXN_FINISHED)) + return EINVAL; + + rc = mdb_txn_renew0(txn); + if (rc == MDB_SUCCESS) { + DPRINTF(("renew txn %"Y"u%c %p on mdbenv %p, root page %"Y"u", + txn->mt_txnid, (txn->mt_flags & MDB_TXN_RDONLY) ? 'r' : 'w', + (void *)txn, (void *)txn->mt_env, txn->mt_dbs[MAIN_DBI].md_root)); + } + return rc; +} + +int +mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **ret) +{ + MDB_txn *txn; + MDB_ntxn *ntxn; + int rc, size, tsize; + + flags &= MDB_TXN_BEGIN_FLAGS; + flags |= env->me_flags & MDB_WRITEMAP; + + if (env->me_flags & MDB_RDONLY & ~flags) /* write txn in RDONLY env */ + return EACCES; + + if (parent) { + /* Nested transactions: Max 1 child, write txns only, no writemap */ + flags |= parent->mt_flags; + if (flags & (MDB_RDONLY|MDB_WRITEMAP|MDB_TXN_BLOCKED)) { + return (parent->mt_flags & MDB_TXN_RDONLY) ? EINVAL : MDB_BAD_TXN; + } + /* Child txns save MDB_pgstate and use own copy of cursors */ + size = env->me_maxdbs * (sizeof(MDB_db)+sizeof(MDB_cursor *)+1); + size += tsize = sizeof(MDB_ntxn); + } else if (flags & MDB_RDONLY) { + size = env->me_maxdbs * (sizeof(MDB_db)+1); + size += tsize = sizeof(MDB_txn); + } else { + /* Reuse preallocated write txn. However, do not touch it until + * mdb_txn_renew0() succeeds, since it currently may be active. + */ + txn = env->me_txn0; + goto renew; + } + if ((txn = calloc(1, size)) == NULL) { + DPRINTF(("calloc: %s", strerror(errno))); + return ENOMEM; + } +#ifdef MDB_VL32 + if (!parent) { + txn->mt_rpages = malloc(MDB_TRPAGE_SIZE * sizeof(MDB_ID3)); + if (!txn->mt_rpages) { + free(txn); + return ENOMEM; + } + txn->mt_rpages[0].mid = 0; + txn->mt_rpcheck = MDB_TRPAGE_SIZE/2; + } +#endif + txn->mt_dbxs = env->me_dbxs; /* static */ + txn->mt_dbs = (MDB_db *) ((char *)txn + tsize); + txn->mt_dbflags = (unsigned char *)txn + size - env->me_maxdbs; + txn->mt_flags = flags; + txn->mt_env = env; + + if (parent) { + unsigned int i; + txn->mt_cursors = (MDB_cursor **)(txn->mt_dbs + env->me_maxdbs); + txn->mt_dbiseqs = parent->mt_dbiseqs; + txn->mt_u.dirty_list = malloc(sizeof(MDB_ID2)*MDB_IDL_UM_SIZE); + if (!txn->mt_u.dirty_list || + !(txn->mt_free_pgs = mdb_midl_alloc(MDB_IDL_UM_MAX))) + { + free(txn->mt_u.dirty_list); + free(txn); + return ENOMEM; + } + txn->mt_txnid = parent->mt_txnid; + txn->mt_dirty_room = parent->mt_dirty_room; + txn->mt_u.dirty_list[0].mid = 0; + txn->mt_spill_pgs = NULL; + txn->mt_next_pgno = parent->mt_next_pgno; + parent->mt_flags |= MDB_TXN_HAS_CHILD; + parent->mt_child = txn; + txn->mt_parent = parent; + txn->mt_numdbs = parent->mt_numdbs; +#ifdef MDB_VL32 + txn->mt_rpages = parent->mt_rpages; +#endif + memcpy(txn->mt_dbs, parent->mt_dbs, txn->mt_numdbs * sizeof(MDB_db)); + /* Copy parent's mt_dbflags, but clear DB_NEW */ + for (i=0; imt_numdbs; i++) + txn->mt_dbflags[i] = parent->mt_dbflags[i] & ~DB_NEW; + rc = 0; + ntxn = (MDB_ntxn *)txn; + ntxn->mnt_pgstate = env->me_pgstate; /* save parent me_pghead & co */ + if (env->me_pghead) { + size = MDB_IDL_SIZEOF(env->me_pghead); + env->me_pghead = mdb_midl_alloc(env->me_pghead[0]); + if (env->me_pghead) + memcpy(env->me_pghead, ntxn->mnt_pgstate.mf_pghead, size); + else + rc = ENOMEM; + } + if (!rc) + rc = mdb_cursor_shadow(parent, txn); + if (rc) + mdb_txn_end(txn, MDB_END_FAIL_BEGINCHILD); + } else { /* MDB_RDONLY */ + txn->mt_dbiseqs = env->me_dbiseqs; +renew: + rc = mdb_txn_renew0(txn); + } + if (rc) { + if (txn != env->me_txn0) { +#ifdef MDB_VL32 + free(txn->mt_rpages); +#endif + free(txn); + } + } else { + txn->mt_flags |= flags; /* could not change txn=me_txn0 earlier */ + *ret = txn; + DPRINTF(("begin txn %"Y"u%c %p on mdbenv %p, root page %"Y"u", + txn->mt_txnid, (flags & MDB_RDONLY) ? 'r' : 'w', + (void *) txn, (void *) env, txn->mt_dbs[MAIN_DBI].md_root)); + } + + return rc; +} + +MDB_env * +mdb_txn_env(MDB_txn *txn) +{ + if(!txn) return NULL; + return txn->mt_env; +} + +mdb_size_t +mdb_txn_id(MDB_txn *txn) +{ + if(!txn) return 0; + return txn->mt_txnid; +} + +/** Export or close DBI handles opened in this txn. */ +static void +mdb_dbis_update(MDB_txn *txn, int keep) +{ + int i; + MDB_dbi n = txn->mt_numdbs; + MDB_env *env = txn->mt_env; + unsigned char *tdbflags = txn->mt_dbflags; + + for (i = n; --i >= CORE_DBS;) { + if (tdbflags[i] & DB_NEW) { + if (keep) { + env->me_dbflags[i] = txn->mt_dbs[i].md_flags | MDB_VALID; + } else { + char *ptr = env->me_dbxs[i].md_name.mv_data; + if (ptr) { + env->me_dbxs[i].md_name.mv_data = NULL; + env->me_dbxs[i].md_name.mv_size = 0; + env->me_dbflags[i] = 0; + env->me_dbiseqs[i]++; + free(ptr); + } + } + } + } + if (keep && env->me_numdbs < n) + env->me_numdbs = n; +} + +/** End a transaction, except successful commit of a nested transaction. + * May be called twice for readonly txns: First reset it, then abort. + * @param[in] txn the transaction handle to end + * @param[in] mode why and how to end the transaction + */ +static void +mdb_txn_end(MDB_txn *txn, unsigned mode) +{ + MDB_env *env = txn->mt_env; +#if MDB_DEBUG + static const char *const names[] = MDB_END_NAMES; +#endif + + /* Export or close DBI handles opened in this txn */ + mdb_dbis_update(txn, mode & MDB_END_UPDATE); + + DPRINTF(("%s txn %"Y"u%c %p on mdbenv %p, root page %"Y"u", + names[mode & MDB_END_OPMASK], + txn->mt_txnid, (txn->mt_flags & MDB_TXN_RDONLY) ? 'r' : 'w', + (void *) txn, (void *)env, txn->mt_dbs[MAIN_DBI].md_root)); + + if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)) { + if (txn->mt_u.reader) { + txn->mt_u.reader->mr_txnid = (txnid_t)-1; + if (!(env->me_flags & MDB_NOTLS)) { + txn->mt_u.reader = NULL; /* txn does not own reader */ + } else if (mode & MDB_END_SLOT) { + txn->mt_u.reader->mr_pid = 0; + txn->mt_u.reader = NULL; + } /* else txn owns the slot until it does MDB_END_SLOT */ + } + txn->mt_numdbs = 0; /* prevent further DBI activity */ + txn->mt_flags |= MDB_TXN_FINISHED; + + } else if (!F_ISSET(txn->mt_flags, MDB_TXN_FINISHED)) { + pgno_t *pghead = env->me_pghead; + + if (!(mode & MDB_END_UPDATE)) /* !(already closed cursors) */ + mdb_cursors_close(txn, 0); + if (!(env->me_flags & MDB_WRITEMAP)) { + mdb_dlist_free(txn); + } + + txn->mt_numdbs = 0; + txn->mt_flags = MDB_TXN_FINISHED; + + if (!txn->mt_parent) { + mdb_midl_shrink(&txn->mt_free_pgs); + env->me_free_pgs = txn->mt_free_pgs; + /* me_pgstate: */ + env->me_pghead = NULL; + env->me_pglast = 0; + + env->me_txn = NULL; + mode = 0; /* txn == env->me_txn0, do not free() it */ + + /* The writer mutex was locked in mdb_txn_begin. */ + if (env->me_txns) + UNLOCK_MUTEX(env->me_wmutex); + } else { + txn->mt_parent->mt_child = NULL; + txn->mt_parent->mt_flags &= ~MDB_TXN_HAS_CHILD; + env->me_pgstate = ((MDB_ntxn *)txn)->mnt_pgstate; + mdb_midl_free(txn->mt_free_pgs); + mdb_midl_free(txn->mt_spill_pgs); + free(txn->mt_u.dirty_list); + } + + mdb_midl_free(pghead); + } +#ifdef MDB_VL32 + if (!txn->mt_parent) { + MDB_ID3L el = env->me_rpages, tl = txn->mt_rpages; + unsigned i, x, n = tl[0].mid; + pthread_mutex_lock(&env->me_rpmutex); + for (i = 1; i <= n; i++) { + if (tl[i].mid & (MDB_RPAGE_CHUNK-1)) { + /* tmp overflow pages that we didn't share in env */ + munmap(tl[i].mptr, tl[i].mcnt * env->me_psize); + } else { + x = mdb_mid3l_search(el, tl[i].mid); + if (tl[i].mptr == el[x].mptr) { + el[x].mref--; + } else { + /* another tmp overflow page */ + munmap(tl[i].mptr, tl[i].mcnt * env->me_psize); + } + } + } + pthread_mutex_unlock(&env->me_rpmutex); + tl[0].mid = 0; + if (mode & MDB_END_FREE) + free(tl); + } +#endif + if (mode & MDB_END_FREE) + free(txn); +} + +void +mdb_txn_reset(MDB_txn *txn) +{ + if (txn == NULL) + return; + + /* This call is only valid for read-only txns */ + if (!(txn->mt_flags & MDB_TXN_RDONLY)) + return; + + mdb_txn_end(txn, MDB_END_RESET); +} + +void +mdb_txn_abort(MDB_txn *txn) +{ + if (txn == NULL) + return; + + if (txn->mt_child) + mdb_txn_abort(txn->mt_child); + + mdb_txn_end(txn, MDB_END_ABORT|MDB_END_SLOT|MDB_END_FREE); +} + +/** Save the freelist as of this transaction to the freeDB. + * This changes the freelist. Keep trying until it stabilizes. + * + * When (MDB_DEVEL) & 2, the changes do not affect #mdb_page_alloc(), + * it then uses the transaction's original snapshot of the freeDB. + */ +static int +mdb_freelist_save(MDB_txn *txn) +{ + /* env->me_pghead[] can grow and shrink during this call. + * env->me_pglast and txn->mt_free_pgs[] can only grow. + * Page numbers cannot disappear from txn->mt_free_pgs[]. + */ + MDB_cursor mc; + MDB_env *env = txn->mt_env; + int rc, maxfree_1pg = env->me_maxfree_1pg, more = 1; + txnid_t pglast = 0, head_id = 0; + pgno_t freecnt = 0, *free_pgs, *mop; + ssize_t head_room = 0, total_room = 0, mop_len, clean_limit; + + mdb_cursor_init(&mc, txn, FREE_DBI, NULL); + + if (env->me_pghead) { + /* Make sure first page of freeDB is touched and on freelist */ + rc = mdb_page_search(&mc, NULL, MDB_PS_FIRST|MDB_PS_MODIFY); + if (rc && rc != MDB_NOTFOUND) + return rc; + } + + if (!env->me_pghead && txn->mt_loose_pgs) { + /* Put loose page numbers in mt_free_pgs, since + * we may be unable to return them to me_pghead. + */ + MDB_page *mp = txn->mt_loose_pgs; + if ((rc = mdb_midl_need(&txn->mt_free_pgs, txn->mt_loose_count)) != 0) + return rc; + for (; mp; mp = NEXT_LOOSE_PAGE(mp)) + mdb_midl_xappend(txn->mt_free_pgs, mp->mp_pgno); + txn->mt_loose_pgs = NULL; + txn->mt_loose_count = 0; + } + + /* MDB_RESERVE cancels meminit in ovpage malloc (when no WRITEMAP) */ + clean_limit = (env->me_flags & (MDB_NOMEMINIT|MDB_WRITEMAP)) + ? SSIZE_MAX : maxfree_1pg; + + for (;;) { + /* Come back here after each Put() in case freelist changed */ + MDB_val key, data; + pgno_t *pgs; + ssize_t j; + + /* If using records from freeDB which we have not yet + * deleted, delete them and any we reserved for me_pghead. + */ + while (pglast < env->me_pglast) { + rc = mdb_cursor_first(&mc, &key, NULL); + if (rc) + return rc; + pglast = head_id = *(txnid_t *)key.mv_data; + total_room = head_room = 0; + mdb_tassert(txn, pglast <= env->me_pglast); + rc = mdb_cursor_del(&mc, 0); + if (rc) + return rc; + } + + /* Save the IDL of pages freed by this txn, to a single record */ + if (freecnt < txn->mt_free_pgs[0]) { + if (!freecnt) { + /* Make sure last page of freeDB is touched and on freelist */ + rc = mdb_page_search(&mc, NULL, MDB_PS_LAST|MDB_PS_MODIFY); + if (rc && rc != MDB_NOTFOUND) + return rc; + } + free_pgs = txn->mt_free_pgs; + /* Write to last page of freeDB */ + key.mv_size = sizeof(txn->mt_txnid); + key.mv_data = &txn->mt_txnid; + do { + freecnt = free_pgs[0]; + data.mv_size = MDB_IDL_SIZEOF(free_pgs); + rc = mdb_cursor_put(&mc, &key, &data, MDB_RESERVE); + if (rc) + return rc; + /* Retry if mt_free_pgs[] grew during the Put() */ + free_pgs = txn->mt_free_pgs; + } while (freecnt < free_pgs[0]); + mdb_midl_sort(free_pgs); + memcpy(data.mv_data, free_pgs, data.mv_size); +#if (MDB_DEBUG) > 1 + { + unsigned int i = free_pgs[0]; + DPRINTF(("IDL write txn %"Y"u root %"Y"u num %u", + txn->mt_txnid, txn->mt_dbs[FREE_DBI].md_root, i)); + for (; i; i--) + DPRINTF(("IDL %"Y"u", free_pgs[i])); + } +#endif + continue; + } + + mop = env->me_pghead; + mop_len = (mop ? mop[0] : 0) + txn->mt_loose_count; + + /* Reserve records for me_pghead[]. Split it if multi-page, + * to avoid searching freeDB for a page range. Use keys in + * range [1,me_pglast]: Smaller than txnid of oldest reader. + */ + if (total_room >= mop_len) { + if (total_room == mop_len || --more < 0) + break; + } else if (head_room >= maxfree_1pg && head_id > 1) { + /* Keep current record (overflow page), add a new one */ + head_id--; + head_room = 0; + } + /* (Re)write {key = head_id, IDL length = head_room} */ + total_room -= head_room; + head_room = mop_len - total_room; + if (head_room > maxfree_1pg && head_id > 1) { + /* Overflow multi-page for part of me_pghead */ + head_room /= head_id; /* amortize page sizes */ + head_room += maxfree_1pg - head_room % (maxfree_1pg + 1); + } else if (head_room < 0) { + /* Rare case, not bothering to delete this record */ + head_room = 0; + } + key.mv_size = sizeof(head_id); + key.mv_data = &head_id; + data.mv_size = (head_room + 1) * sizeof(pgno_t); + rc = mdb_cursor_put(&mc, &key, &data, MDB_RESERVE); + if (rc) + return rc; + /* IDL is initially empty, zero out at least the length */ + pgs = (pgno_t *)data.mv_data; + j = head_room > clean_limit ? head_room : 0; + do { + pgs[j] = 0; + } while (--j >= 0); + total_room += head_room; + } + + /* Return loose page numbers to me_pghead, though usually none are + * left at this point. The pages themselves remain in dirty_list. + */ + if (txn->mt_loose_pgs) { + MDB_page *mp = txn->mt_loose_pgs; + unsigned count = txn->mt_loose_count; + MDB_IDL loose; + /* Room for loose pages + temp IDL with same */ + if ((rc = mdb_midl_need(&env->me_pghead, 2*count+1)) != 0) + return rc; + mop = env->me_pghead; + loose = mop + MDB_IDL_ALLOCLEN(mop) - count; + for (count = 0; mp; mp = NEXT_LOOSE_PAGE(mp)) + loose[ ++count ] = mp->mp_pgno; + loose[0] = count; + mdb_midl_sort(loose); + mdb_midl_xmerge(mop, loose); + txn->mt_loose_pgs = NULL; + txn->mt_loose_count = 0; + mop_len = mop[0]; + } + + /* Fill in the reserved me_pghead records */ + rc = MDB_SUCCESS; + if (mop_len) { + MDB_val key, data; + + mop += mop_len; + rc = mdb_cursor_first(&mc, &key, &data); + for (; !rc; rc = mdb_cursor_next(&mc, &key, &data, MDB_NEXT)) { + txnid_t id = *(txnid_t *)key.mv_data; + ssize_t len = (ssize_t)(data.mv_size / sizeof(MDB_ID)) - 1; + MDB_ID save; + + mdb_tassert(txn, len >= 0 && id <= env->me_pglast); + key.mv_data = &id; + if (len > mop_len) { + len = mop_len; + data.mv_size = (len + 1) * sizeof(MDB_ID); + } + data.mv_data = mop -= len; + save = mop[0]; + mop[0] = len; + rc = mdb_cursor_put(&mc, &key, &data, MDB_CURRENT); + mop[0] = save; + if (rc || !(mop_len -= len)) + break; + } + } + return rc; +} + +/** Flush (some) dirty pages to the map, after clearing their dirty flag. + * @param[in] txn the transaction that's being committed + * @param[in] keep number of initial pages in dirty_list to keep dirty. + * @return 0 on success, non-zero on failure. + */ +static int +mdb_page_flush(MDB_txn *txn, int keep) +{ + MDB_env *env = txn->mt_env; + MDB_ID2L dl = txn->mt_u.dirty_list; + unsigned psize = env->me_psize, j; + int i, pagecount = dl[0].mid, rc; + size_t size = 0; + off64_t pos = 0; + pgno_t pgno = 0; + MDB_page *dp = NULL; +#ifdef _WIN32 + OVERLAPPED ov; +#else + struct iovec iov[MDB_COMMIT_PAGES]; + ssize_t wsize = 0, wres; + off64_t wpos = 0, next_pos = 1; /* impossible pos, so pos != next_pos */ + int n = 0; +#endif + + j = i = keep; + + if (env->me_flags & MDB_WRITEMAP) { + /* Clear dirty flags */ + while (++i <= pagecount) { + dp = dl[i].mptr; + /* Don't flush this page yet */ + if (dp->mp_flags & (P_LOOSE|P_KEEP)) { + dp->mp_flags &= ~P_KEEP; + dl[++j] = dl[i]; + continue; + } + dp->mp_flags &= ~P_DIRTY; + } + goto done; + } + + /* Write the pages */ + for (;;) { + if (++i <= pagecount) { + dp = dl[i].mptr; + /* Don't flush this page yet */ + if (dp->mp_flags & (P_LOOSE|P_KEEP)) { + dp->mp_flags &= ~P_KEEP; + dl[i].mid = 0; + continue; + } + pgno = dl[i].mid; + /* clear dirty flag */ + dp->mp_flags &= ~P_DIRTY; + pos = pgno * psize; + size = psize; + if (IS_OVERFLOW(dp)) size *= dp->mp_pages; + } +#ifdef _WIN32 + else break; + + /* Windows actually supports scatter/gather I/O, but only on + * unbuffered file handles. Since we're relying on the OS page + * cache for all our data, that's self-defeating. So we just + * write pages one at a time. We use the ov structure to set + * the write offset, to at least save the overhead of a Seek + * system call. + */ + DPRINTF(("committing page %"Z"u", pgno)); + memset(&ov, 0, sizeof(ov)); + ov.Offset = pos & 0xffffffff; + ov.OffsetHigh = pos >> 16 >> 16; + if (!WriteFile(env->me_fd, dp, size, NULL, &ov)) { + rc = ErrCode(); + DPRINTF(("WriteFile: %d", rc)); + return rc; + } +#else + /* Write up to MDB_COMMIT_PAGES dirty pages at a time. */ + if (pos!=next_pos || n==MDB_COMMIT_PAGES || wsize+size>MAX_WRITE) { + if (n) { +retry_write: + /* Write previous page(s) */ +#ifdef MDB_USE_PWRITEV + wres = pwritev(env->me_fd, iov, n, wpos); +#else + if (n == 1) { + wres = pwrite(env->me_fd, iov[0].iov_base, wsize, wpos); + } else { +retry_seek: + if (lseek(env->me_fd, wpos, SEEK_SET) == -1) { + rc = ErrCode(); + if (rc == EINTR) + goto retry_seek; + DPRINTF(("lseek: %s", strerror(rc))); + return rc; + } + wres = writev(env->me_fd, iov, n); + } +#endif + if (wres != wsize) { + if (wres < 0) { + rc = ErrCode(); + if (rc == EINTR) + goto retry_write; + DPRINTF(("Write error: %s", strerror(rc))); + } else { + rc = EIO; /* TODO: Use which error code? */ + DPUTS("short write, filesystem full?"); + } + return rc; + } + n = 0; + } + if (i > pagecount) + break; + wpos = pos; + wsize = 0; + } + DPRINTF(("committing page %"Y"u", pgno)); + next_pos = pos + size; + iov[n].iov_len = size; + iov[n].iov_base = (char *)dp; + wsize += size; + n++; +#endif /* _WIN32 */ + } +#ifdef MDB_VL32 + if (pgno > txn->mt_last_pgno) + txn->mt_last_pgno = pgno; +#endif + + /* MIPS has cache coherency issues, this is a no-op everywhere else + * Note: for any size >= on-chip cache size, entire on-chip cache is + * flushed. + */ + CACHEFLUSH(env->me_map, txn->mt_next_pgno * env->me_psize, DCACHE); + + for (i = keep; ++i <= pagecount; ) { + dp = dl[i].mptr; + /* This is a page we skipped above */ + if (!dl[i].mid) { + dl[++j] = dl[i]; + dl[j].mid = dp->mp_pgno; + continue; + } + mdb_dpage_free(env, dp); + } + +done: + i--; + txn->mt_dirty_room += i - j; + dl[0].mid = j; + return MDB_SUCCESS; +} + +static int ESECT mdb_env_share_locks(MDB_env *env, int *excl); + +int +mdb_txn_commit(MDB_txn *txn) +{ + int rc; + unsigned int i, end_mode; + MDB_env *env; + + if (txn == NULL) + return EINVAL; + + /* mdb_txn_end() mode for a commit which writes nothing */ + end_mode = MDB_END_EMPTY_COMMIT|MDB_END_UPDATE|MDB_END_SLOT|MDB_END_FREE; + + if (txn->mt_child) { + rc = mdb_txn_commit(txn->mt_child); + if (rc) + goto fail; + } + + env = txn->mt_env; + + if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)) { + goto done; + } + + if (txn->mt_flags & (MDB_TXN_FINISHED|MDB_TXN_ERROR)) { + DPUTS("txn has failed/finished, can't commit"); + if (txn->mt_parent) + txn->mt_parent->mt_flags |= MDB_TXN_ERROR; + rc = MDB_BAD_TXN; + goto fail; + } + + if (txn->mt_parent) { + MDB_txn *parent = txn->mt_parent; + MDB_page **lp; + MDB_ID2L dst, src; + MDB_IDL pspill; + unsigned x, y, len, ps_len; + + /* Append our free list to parent's */ + rc = mdb_midl_append_list(&parent->mt_free_pgs, txn->mt_free_pgs); + if (rc) + goto fail; + mdb_midl_free(txn->mt_free_pgs); + /* Failures after this must either undo the changes + * to the parent or set MDB_TXN_ERROR in the parent. + */ + + parent->mt_next_pgno = txn->mt_next_pgno; + parent->mt_flags = txn->mt_flags; + + /* Merge our cursors into parent's and close them */ + mdb_cursors_close(txn, 1); + + /* Update parent's DB table. */ + memcpy(parent->mt_dbs, txn->mt_dbs, txn->mt_numdbs * sizeof(MDB_db)); + parent->mt_numdbs = txn->mt_numdbs; + parent->mt_dbflags[FREE_DBI] = txn->mt_dbflags[FREE_DBI]; + parent->mt_dbflags[MAIN_DBI] = txn->mt_dbflags[MAIN_DBI]; + for (i=CORE_DBS; imt_numdbs; i++) { + /* preserve parent's DB_NEW status */ + x = parent->mt_dbflags[i] & DB_NEW; + parent->mt_dbflags[i] = txn->mt_dbflags[i] | x; + } + + dst = parent->mt_u.dirty_list; + src = txn->mt_u.dirty_list; + /* Remove anything in our dirty list from parent's spill list */ + if ((pspill = parent->mt_spill_pgs) && (ps_len = pspill[0])) { + x = y = ps_len; + pspill[0] = (pgno_t)-1; + /* Mark our dirty pages as deleted in parent spill list */ + for (i=0, len=src[0].mid; ++i <= len; ) { + MDB_ID pn = src[i].mid << 1; + while (pn > pspill[x]) + x--; + if (pn == pspill[x]) { + pspill[x] = 1; + y = --x; + } + } + /* Squash deleted pagenums if we deleted any */ + for (x=y; ++x <= ps_len; ) + if (!(pspill[x] & 1)) + pspill[++y] = pspill[x]; + pspill[0] = y; + } + + /* Remove anything in our spill list from parent's dirty list */ + if (txn->mt_spill_pgs && txn->mt_spill_pgs[0]) { + for (i=1; i<=txn->mt_spill_pgs[0]; i++) { + MDB_ID pn = txn->mt_spill_pgs[i]; + if (pn & 1) + continue; /* deleted spillpg */ + pn >>= 1; + y = mdb_mid2l_search(dst, pn); + if (y <= dst[0].mid && dst[y].mid == pn) { + free(dst[y].mptr); + while (y < dst[0].mid) { + dst[y] = dst[y+1]; + y++; + } + dst[0].mid--; + } + } + } + + /* Find len = length of merging our dirty list with parent's */ + x = dst[0].mid; + dst[0].mid = 0; /* simplify loops */ + if (parent->mt_parent) { + len = x + src[0].mid; + y = mdb_mid2l_search(src, dst[x].mid + 1) - 1; + for (i = x; y && i; y--) { + pgno_t yp = src[y].mid; + while (yp < dst[i].mid) + i--; + if (yp == dst[i].mid) { + i--; + len--; + } + } + } else { /* Simplify the above for single-ancestor case */ + len = MDB_IDL_UM_MAX - txn->mt_dirty_room; + } + /* Merge our dirty list with parent's */ + y = src[0].mid; + for (i = len; y; dst[i--] = src[y--]) { + pgno_t yp = src[y].mid; + while (yp < dst[x].mid) + dst[i--] = dst[x--]; + if (yp == dst[x].mid) + free(dst[x--].mptr); + } + mdb_tassert(txn, i == x); + dst[0].mid = len; + free(txn->mt_u.dirty_list); + parent->mt_dirty_room = txn->mt_dirty_room; + if (txn->mt_spill_pgs) { + if (parent->mt_spill_pgs) { + /* TODO: Prevent failure here, so parent does not fail */ + rc = mdb_midl_append_list(&parent->mt_spill_pgs, txn->mt_spill_pgs); + if (rc) + parent->mt_flags |= MDB_TXN_ERROR; + mdb_midl_free(txn->mt_spill_pgs); + mdb_midl_sort(parent->mt_spill_pgs); + } else { + parent->mt_spill_pgs = txn->mt_spill_pgs; + } + } + + /* Append our loose page list to parent's */ + for (lp = &parent->mt_loose_pgs; *lp; lp = &NEXT_LOOSE_PAGE(*lp)) + ; + *lp = txn->mt_loose_pgs; + parent->mt_loose_count += txn->mt_loose_count; + + parent->mt_child = NULL; + mdb_midl_free(((MDB_ntxn *)txn)->mnt_pgstate.mf_pghead); + free(txn); + return rc; + } + + if (txn != env->me_txn) { + DPUTS("attempt to commit unknown transaction"); + rc = EINVAL; + goto fail; + } + + mdb_cursors_close(txn, 0); + + if (!txn->mt_u.dirty_list[0].mid && + !(txn->mt_flags & (MDB_TXN_DIRTY|MDB_TXN_SPILLS))) + goto done; + + DPRINTF(("committing txn %"Y"u %p on mdbenv %p, root page %"Y"u", + txn->mt_txnid, (void*)txn, (void*)env, txn->mt_dbs[MAIN_DBI].md_root)); + + /* Update DB root pointers */ + if (txn->mt_numdbs > CORE_DBS) { + MDB_cursor mc; + MDB_dbi i; + MDB_val data; + data.mv_size = sizeof(MDB_db); + + mdb_cursor_init(&mc, txn, MAIN_DBI, NULL); + for (i = CORE_DBS; i < txn->mt_numdbs; i++) { + if (txn->mt_dbflags[i] & DB_DIRTY) { + if (TXN_DBI_CHANGED(txn, i)) { + rc = MDB_BAD_DBI; + goto fail; + } + data.mv_data = &txn->mt_dbs[i]; + rc = mdb_cursor_put(&mc, &txn->mt_dbxs[i].md_name, &data, + F_SUBDATA); + if (rc) + goto fail; + } + } + } + + rc = mdb_freelist_save(txn); + if (rc) + goto fail; + + mdb_midl_free(env->me_pghead); + env->me_pghead = NULL; + mdb_midl_shrink(&txn->mt_free_pgs); + +#if (MDB_DEBUG) > 2 + mdb_audit(txn); +#endif + + if ((rc = mdb_page_flush(txn, 0))) + goto fail; + if (!F_ISSET(txn->mt_flags, MDB_TXN_NOSYNC) && + (rc = mdb_env_sync0(env, 0, txn->mt_next_pgno))) + goto fail; + if ((rc = mdb_env_write_meta(txn))) + goto fail; + end_mode = MDB_END_COMMITTED|MDB_END_UPDATE; + if (env->me_flags & MDB_PREVSNAPSHOT) { + if (!(env->me_flags & MDB_NOLOCK)) { + int excl; + rc = mdb_env_share_locks(env, &excl); + if (rc) + goto fail; + } + env->me_flags ^= MDB_PREVSNAPSHOT; + } + +done: + mdb_txn_end(txn, end_mode); + return MDB_SUCCESS; + +fail: + mdb_txn_abort(txn); + return rc; +} + +/** Read the environment parameters of a DB environment before + * mapping it into memory. + * @param[in] env the environment handle + * @param[in] prev whether to read the backup meta page + * @param[out] meta address of where to store the meta information + * @return 0 on success, non-zero on failure. + */ +static int ESECT +mdb_env_read_header(MDB_env *env, int prev, MDB_meta *meta) +{ + MDB_metabuf pbuf; + MDB_page *p; + MDB_meta *m; + int i, rc, off; + enum { Size = sizeof(pbuf) }; + + /* We don't know the page size yet, so use a minimum value. + * Read both meta pages so we can use the latest one. + */ + + for (i=off=0; imm_psize) { +#ifdef _WIN32 + DWORD len; + OVERLAPPED ov; + memset(&ov, 0, sizeof(ov)); + ov.Offset = off; + rc = ReadFile(env->me_fd, &pbuf, Size, &len, &ov) ? (int)len : -1; + if (rc == -1 && ErrCode() == ERROR_HANDLE_EOF) + rc = 0; +#else + rc = pread(env->me_fd, &pbuf, Size, off); +#endif + if (rc != Size) { + if (rc == 0 && off == 0) + return ENOENT; + rc = rc < 0 ? (int) ErrCode() : MDB_INVALID; + DPRINTF(("read: %s", mdb_strerror(rc))); + return rc; + } + + p = (MDB_page *)&pbuf; + + if (!F_ISSET(p->mp_flags, P_META)) { + DPRINTF(("page %"Y"u not a meta page", p->mp_pgno)); + return MDB_INVALID; + } + + m = METADATA(p); + if (m->mm_magic != MDB_MAGIC) { + DPUTS("meta has invalid magic"); + return MDB_INVALID; + } + + if (m->mm_version != MDB_DATA_VERSION) { + DPRINTF(("database is version %u, expected version %u", + m->mm_version, MDB_DATA_VERSION)); + return MDB_VERSION_MISMATCH; + } + + if (off == 0 || (prev ? m->mm_txnid < meta->mm_txnid : m->mm_txnid > meta->mm_txnid)) + *meta = *m; + } + return 0; +} + +/** Fill in most of the zeroed #MDB_meta for an empty database environment */ +static void ESECT +mdb_env_init_meta0(MDB_env *env, MDB_meta *meta) +{ + meta->mm_magic = MDB_MAGIC; + meta->mm_version = MDB_DATA_VERSION; + meta->mm_mapsize = env->me_mapsize; + meta->mm_psize = env->me_psize; + meta->mm_last_pg = NUM_METAS-1; + meta->mm_flags = env->me_flags & 0xffff; + meta->mm_flags |= MDB_INTEGERKEY; /* this is mm_dbs[FREE_DBI].md_flags */ + meta->mm_dbs[FREE_DBI].md_root = P_INVALID; + meta->mm_dbs[MAIN_DBI].md_root = P_INVALID; +} + +/** Write the environment parameters of a freshly created DB environment. + * @param[in] env the environment handle + * @param[in] meta the #MDB_meta to write + * @return 0 on success, non-zero on failure. + */ +static int ESECT +mdb_env_init_meta(MDB_env *env, MDB_meta *meta) +{ + MDB_page *p, *q; + int rc; + unsigned int psize; +#ifdef _WIN32 + DWORD len; + OVERLAPPED ov; + memset(&ov, 0, sizeof(ov)); +#define DO_PWRITE(rc, fd, ptr, size, len, pos) do { \ + ov.Offset = pos; \ + rc = WriteFile(fd, ptr, size, &len, &ov); } while(0) +#else + int len; +#define DO_PWRITE(rc, fd, ptr, size, len, pos) do { \ + len = pwrite(fd, ptr, size, pos); \ + if (len == -1 && ErrCode() == EINTR) continue; \ + rc = (len >= 0); break; } while(1) +#endif + + DPUTS("writing new meta page"); + + psize = env->me_psize; + + p = calloc(NUM_METAS, psize); + if (!p) + return ENOMEM; + p->mp_pgno = 0; + p->mp_flags = P_META; + *(MDB_meta *)METADATA(p) = *meta; + + q = (MDB_page *)((char *)p + psize); + q->mp_pgno = 1; + q->mp_flags = P_META; + *(MDB_meta *)METADATA(q) = *meta; + + DO_PWRITE(rc, env->me_fd, p, psize * NUM_METAS, len, 0); + if (!rc) + rc = ErrCode(); + else if ((unsigned) len == psize * NUM_METAS) + rc = MDB_SUCCESS; + else + rc = ENOSPC; + free(p); + return rc; +} + +/** Update the environment info to commit a transaction. + * @param[in] txn the transaction that's being committed + * @return 0 on success, non-zero on failure. + */ +static int +mdb_env_write_meta(MDB_txn *txn) +{ + MDB_env *env; + MDB_meta meta, metab, *mp; + unsigned flags; + mdb_size_t mapsize; + off64_t off; + int rc, len, toggle; + char *ptr; + HANDLE mfd; +#ifdef _WIN32 + OVERLAPPED ov; +#else + int r2; +#endif + + toggle = txn->mt_txnid & 1; + DPRINTF(("writing meta page %d for root page %"Y"u", + toggle, txn->mt_dbs[MAIN_DBI].md_root)); + + env = txn->mt_env; + flags = txn->mt_flags | env->me_flags; + mp = env->me_metas[toggle]; + mapsize = env->me_metas[toggle ^ 1]->mm_mapsize; + /* Persist any increases of mapsize config */ + if (mapsize < env->me_mapsize) + mapsize = env->me_mapsize; + + if (flags & MDB_WRITEMAP) { + mp->mm_mapsize = mapsize; + mp->mm_dbs[FREE_DBI] = txn->mt_dbs[FREE_DBI]; + mp->mm_dbs[MAIN_DBI] = txn->mt_dbs[MAIN_DBI]; + mp->mm_last_pg = txn->mt_next_pgno - 1; +#if (__GNUC__ * 100 + __GNUC_MINOR__ >= 404) && /* TODO: portability */ \ + !(defined(__i386__) || defined(__x86_64__)) + /* LY: issue a memory barrier, if not x86. ITS#7969 */ + __sync_synchronize(); +#endif + mp->mm_txnid = txn->mt_txnid; + if (!(flags & (MDB_NOMETASYNC|MDB_NOSYNC))) { + unsigned meta_size = env->me_psize; + rc = (env->me_flags & MDB_MAPASYNC) ? MS_ASYNC : MS_SYNC; + ptr = (char *)mp - PAGEHDRSZ; +#ifndef _WIN32 /* POSIX msync() requires ptr = start of OS page */ + r2 = (ptr - env->me_map) & (env->me_os_psize - 1); + ptr -= r2; + meta_size += r2; +#endif + if (MDB_MSYNC(ptr, meta_size, rc)) { + rc = ErrCode(); + goto fail; + } + } + goto done; + } + metab.mm_txnid = mp->mm_txnid; + metab.mm_last_pg = mp->mm_last_pg; + + meta.mm_mapsize = mapsize; + meta.mm_dbs[FREE_DBI] = txn->mt_dbs[FREE_DBI]; + meta.mm_dbs[MAIN_DBI] = txn->mt_dbs[MAIN_DBI]; + meta.mm_last_pg = txn->mt_next_pgno - 1; + meta.mm_txnid = txn->mt_txnid; + + off = offsetof(MDB_meta, mm_mapsize); + ptr = (char *)&meta + off; + len = sizeof(MDB_meta) - off; + off += (char *)mp - env->me_map; + + /* Write to the SYNC fd */ + mfd = (flags & (MDB_NOSYNC|MDB_NOMETASYNC)) ? env->me_fd : env->me_mfd; +#ifdef _WIN32 + { + memset(&ov, 0, sizeof(ov)); + ov.Offset = off; + if (!WriteFile(mfd, ptr, len, (DWORD *)&rc, &ov)) + rc = -1; + } +#else +retry_write: + rc = pwrite(mfd, ptr, len, off); +#endif + if (rc != len) { + rc = rc < 0 ? ErrCode() : EIO; +#ifndef _WIN32 + if (rc == EINTR) + goto retry_write; +#endif + DPUTS("write failed, disk error?"); + /* On a failure, the pagecache still contains the new data. + * Write some old data back, to prevent it from being used. + * Use the non-SYNC fd; we know it will fail anyway. + */ + meta.mm_last_pg = metab.mm_last_pg; + meta.mm_txnid = metab.mm_txnid; +#ifdef _WIN32 + memset(&ov, 0, sizeof(ov)); + ov.Offset = off; + WriteFile(env->me_fd, ptr, len, NULL, &ov); +#else + r2 = pwrite(env->me_fd, ptr, len, off); + (void)r2; /* Silence warnings. We don't care about pwrite's return value */ +#endif +fail: + env->me_flags |= MDB_FATAL_ERROR; + return rc; + } + /* MIPS has cache coherency issues, this is a no-op everywhere else */ + CACHEFLUSH(env->me_map + off, len, DCACHE); +done: + /* Memory ordering issues are irrelevant; since the entire writer + * is wrapped by wmutex, all of these changes will become visible + * after the wmutex is unlocked. Since the DB is multi-version, + * readers will get consistent data regardless of how fresh or + * how stale their view of these values is. + */ + if (env->me_txns) + env->me_txns->mti_txnid = txn->mt_txnid; + + return MDB_SUCCESS; +} + +/** Check both meta pages to see which one is newer. + * @param[in] env the environment handle + * @return newest #MDB_meta. + */ +static MDB_meta * +mdb_env_pick_meta(const MDB_env *env) +{ + MDB_meta *const *metas = env->me_metas; + return metas[ (metas[0]->mm_txnid < metas[1]->mm_txnid) ^ + ((env->me_flags & MDB_PREVSNAPSHOT) != 0) ]; +} + +int ESECT +mdb_env_create(MDB_env **env) +{ + MDB_env *e; + + e = calloc(1, sizeof(MDB_env)); + if (!e) + return ENOMEM; + + e->me_maxreaders = DEFAULT_READERS; + e->me_maxdbs = e->me_numdbs = CORE_DBS; + e->me_fd = INVALID_HANDLE_VALUE; + e->me_lfd = INVALID_HANDLE_VALUE; + e->me_mfd = INVALID_HANDLE_VALUE; +#ifdef MDB_USE_POSIX_SEM + e->me_rmutex = SEM_FAILED; + e->me_wmutex = SEM_FAILED; +#elif defined MDB_USE_SYSV_SEM + e->me_rmutex->semid = -1; + e->me_wmutex->semid = -1; +#endif + e->me_pid = getpid(); + GET_PAGESIZE(e->me_os_psize); + VGMEMP_CREATE(e,0,0); + *env = e; + return MDB_SUCCESS; +} + +#ifdef _WIN32 +/** @brief Map a result from an NTAPI call to WIN32. */ +static DWORD +mdb_nt2win32(NTSTATUS st) +{ + OVERLAPPED o = {0}; + DWORD br; + o.Internal = st; + GetOverlappedResult(NULL, &o, &br, FALSE); + return GetLastError(); +} +#endif + +static int ESECT +mdb_env_map(MDB_env *env, void *addr) +{ + MDB_page *p; + unsigned int flags = env->me_flags; +#ifdef _WIN32 + int rc; + int access = SECTION_MAP_READ; + HANDLE mh; + void *map; + SIZE_T msize; + ULONG pageprot = PAGE_READONLY, secprot, alloctype; + + if (flags & MDB_WRITEMAP) { + access |= SECTION_MAP_WRITE; + pageprot = PAGE_READWRITE; + } + if (flags & MDB_RDONLY) { + secprot = PAGE_READONLY; + msize = 0; + alloctype = 0; + } else { + secprot = PAGE_READWRITE; + msize = env->me_mapsize; + alloctype = MEM_RESERVE; + } + + rc = NtCreateSection(&mh, access, NULL, NULL, secprot, SEC_RESERVE, env->me_fd); + if (rc) + return mdb_nt2win32(rc); + map = addr; +#ifdef MDB_VL32 + msize = NUM_METAS * env->me_psize; +#endif + rc = NtMapViewOfSection(mh, GetCurrentProcess(), &map, 0, 0, NULL, &msize, ViewUnmap, alloctype, pageprot); +#ifdef MDB_VL32 + env->me_fmh = mh; +#else + NtClose(mh); +#endif + if (rc) + return mdb_nt2win32(rc); + env->me_map = map; +#else +#ifdef MDB_VL32 + (void) flags; + env->me_map = mmap(addr, NUM_METAS * env->me_psize, PROT_READ, MAP_SHARED, + env->me_fd, 0); + if (env->me_map == MAP_FAILED) { + env->me_map = NULL; + return ErrCode(); + } +#else + int prot = PROT_READ; + if (flags & MDB_WRITEMAP) { + prot |= PROT_WRITE; + if (ftruncate(env->me_fd, env->me_mapsize) < 0) + return ErrCode(); + } + env->me_map = mmap(addr, env->me_mapsize, prot, MAP_SHARED, + env->me_fd, 0); + if (env->me_map == MAP_FAILED) { + env->me_map = NULL; + return ErrCode(); + } + + if (flags & MDB_NORDAHEAD) { + /* Turn off readahead. It's harmful when the DB is larger than RAM. */ +#ifdef MADV_RANDOM + madvise(env->me_map, env->me_mapsize, MADV_RANDOM); +#else +#ifdef POSIX_MADV_RANDOM + posix_madvise(env->me_map, env->me_mapsize, POSIX_MADV_RANDOM); +#endif /* POSIX_MADV_RANDOM */ +#endif /* MADV_RANDOM */ + } +#endif /* _WIN32 */ + + /* Can happen because the address argument to mmap() is just a + * hint. mmap() can pick another, e.g. if the range is in use. + * The MAP_FIXED flag would prevent that, but then mmap could + * instead unmap existing pages to make room for the new map. + */ + if (addr && env->me_map != addr) + return EBUSY; /* TODO: Make a new MDB_* error code? */ +#endif + + p = (MDB_page *)env->me_map; + env->me_metas[0] = METADATA(p); + env->me_metas[1] = (MDB_meta *)((char *)env->me_metas[0] + env->me_psize); + + return MDB_SUCCESS; +} + +int ESECT +mdb_env_set_mapsize(MDB_env *env, mdb_size_t size) +{ + /* If env is already open, caller is responsible for making + * sure there are no active txns. + */ + if (env->me_map) { + MDB_meta *meta; +#ifndef MDB_VL32 + void *old; + int rc; +#endif + if (env->me_txn) + return EINVAL; + meta = mdb_env_pick_meta(env); + if (!size) + size = meta->mm_mapsize; + { + /* Silently round up to minimum if the size is too small */ + mdb_size_t minsize = (meta->mm_last_pg + 1) * env->me_psize; + if (size < minsize) + size = minsize; + } +#ifndef MDB_VL32 + /* For MDB_VL32 this bit is a noop since we dynamically remap + * chunks of the DB anyway. + */ + munmap(env->me_map, env->me_mapsize); + env->me_mapsize = size; + old = (env->me_flags & MDB_FIXEDMAP) ? env->me_map : NULL; + rc = mdb_env_map(env, old); + if (rc) + return rc; +#endif /* !MDB_VL32 */ + } + env->me_mapsize = size; + if (env->me_psize) + env->me_maxpg = env->me_mapsize / env->me_psize; + return MDB_SUCCESS; +} + +int ESECT +mdb_env_set_maxdbs(MDB_env *env, MDB_dbi dbs) +{ + if (env->me_map) + return EINVAL; + env->me_maxdbs = dbs + CORE_DBS; + return MDB_SUCCESS; +} + +int ESECT +mdb_env_set_maxreaders(MDB_env *env, unsigned int readers) +{ + if (env->me_map || readers < 1) + return EINVAL; + env->me_maxreaders = readers; + return MDB_SUCCESS; +} + +int ESECT +mdb_env_get_maxreaders(MDB_env *env, unsigned int *readers) +{ + if (!env || !readers) + return EINVAL; + *readers = env->me_maxreaders; + return MDB_SUCCESS; +} + +static int ESECT +mdb_fsize(HANDLE fd, mdb_size_t *size) +{ +#ifdef _WIN32 + LARGE_INTEGER fsize; + + if (!GetFileSizeEx(fd, &fsize)) + return ErrCode(); + + *size = fsize.QuadPart; +#else + struct stat st; + + if (fstat(fd, &st)) + return ErrCode(); + + *size = st.st_size; +#endif + return MDB_SUCCESS; +} + +#ifdef BROKEN_FDATASYNC +#include +#include +#endif + +/** Further setup required for opening an LMDB environment + */ +static int ESECT +mdb_env_open2(MDB_env *env, int prev) +{ + unsigned int flags = env->me_flags; + int i, newenv = 0, rc; + MDB_meta meta; + +#ifdef _WIN32 + /* See if we should use QueryLimited */ + rc = GetVersion(); + if ((rc & 0xff) > 5) + env->me_pidquery = MDB_PROCESS_QUERY_LIMITED_INFORMATION; + else + env->me_pidquery = PROCESS_QUERY_INFORMATION; +#endif /* _WIN32 */ + +#ifdef BROKEN_FDATASYNC + /* ext3/ext4 fdatasync is broken on some older Linux kernels. + * https://lkml.org/lkml/2012/9/3/83 + * Kernels after 3.6-rc6 are known good. + * https://lkml.org/lkml/2012/9/10/556 + * See if the DB is on ext3/ext4, then check for new enough kernel + * Kernels 2.6.32.60, 2.6.34.15, 3.2.30, and 3.5.4 are also known + * to be patched. + */ + { + struct statfs st; + fstatfs(env->me_fd, &st); + while (st.f_type == 0xEF53) { + struct utsname uts; + int i; + uname(&uts); + if (uts.release[0] < '3') { + if (!strncmp(uts.release, "2.6.32.", 7)) { + i = atoi(uts.release+7); + if (i >= 60) + break; /* 2.6.32.60 and newer is OK */ + } else if (!strncmp(uts.release, "2.6.34.", 7)) { + i = atoi(uts.release+7); + if (i >= 15) + break; /* 2.6.34.15 and newer is OK */ + } + } else if (uts.release[0] == '3') { + i = atoi(uts.release+2); + if (i > 5) + break; /* 3.6 and newer is OK */ + if (i == 5) { + i = atoi(uts.release+4); + if (i >= 4) + break; /* 3.5.4 and newer is OK */ + } else if (i == 2) { + i = atoi(uts.release+4); + if (i >= 30) + break; /* 3.2.30 and newer is OK */ + } + } else { /* 4.x and newer is OK */ + break; + } + env->me_flags |= MDB_FSYNCONLY; + break; + } + } +#endif + + if ((i = mdb_env_read_header(env, prev, &meta)) != 0) { + if (i != ENOENT) + return i; + DPUTS("new mdbenv"); + newenv = 1; + env->me_psize = env->me_os_psize; + if (env->me_psize > MAX_PAGESIZE) + env->me_psize = MAX_PAGESIZE; + memset(&meta, 0, sizeof(meta)); + mdb_env_init_meta0(env, &meta); + meta.mm_mapsize = DEFAULT_MAPSIZE; + } else { + env->me_psize = meta.mm_psize; + } + + /* Was a mapsize configured? */ + if (!env->me_mapsize) { + env->me_mapsize = meta.mm_mapsize; + } + { + /* Make sure mapsize >= committed data size. Even when using + * mm_mapsize, which could be broken in old files (ITS#7789). + */ + mdb_size_t minsize = (meta.mm_last_pg + 1) * meta.mm_psize; + if (env->me_mapsize < minsize) + env->me_mapsize = minsize; + } + meta.mm_mapsize = env->me_mapsize; + + if (newenv && !(flags & MDB_FIXEDMAP)) { + /* mdb_env_map() may grow the datafile. Write the metapages + * first, so the file will be valid if initialization fails. + * Except with FIXEDMAP, since we do not yet know mm_address. + * We could fill in mm_address later, but then a different + * program might end up doing that - one with a memory layout + * and map address which does not suit the main program. + */ + rc = mdb_env_init_meta(env, &meta); + if (rc) + return rc; + newenv = 0; + } +#ifdef _WIN32 + /* For FIXEDMAP, make sure the file is non-empty before we attempt to map it */ + if (newenv) { + char dummy = 0; + DWORD len; + rc = WriteFile(env->me_fd, &dummy, 1, &len, NULL); + if (!rc) { + rc = ErrCode(); + return rc; + } + } +#endif + + rc = mdb_env_map(env, (flags & MDB_FIXEDMAP) ? meta.mm_address : NULL); + if (rc) + return rc; + + if (newenv) { + if (flags & MDB_FIXEDMAP) + meta.mm_address = env->me_map; + i = mdb_env_init_meta(env, &meta); + if (i != MDB_SUCCESS) { + return i; + } + } + + env->me_maxfree_1pg = (env->me_psize - PAGEHDRSZ) / sizeof(pgno_t) - 1; + env->me_nodemax = (((env->me_psize - PAGEHDRSZ) / MDB_MINKEYS) & -2) + - sizeof(indx_t); +#if !(MDB_MAXKEYSIZE) + env->me_maxkey = env->me_nodemax - (NODESIZE + sizeof(MDB_db)); +#endif + env->me_maxpg = env->me_mapsize / env->me_psize; + + if (env->me_txns) + env->me_txns->mti_txnid = meta.mm_txnid; + +#if MDB_DEBUG + { + MDB_meta *meta = mdb_env_pick_meta(env); + MDB_db *db = &meta->mm_dbs[MAIN_DBI]; + + DPRINTF(("opened database version %u, pagesize %u", + meta->mm_version, env->me_psize)); + DPRINTF(("using meta page %d", (int) (meta->mm_txnid & 1))); + DPRINTF(("depth: %u", db->md_depth)); + DPRINTF(("entries: %"Y"u", db->md_entries)); + DPRINTF(("branch pages: %"Y"u", db->md_branch_pages)); + DPRINTF(("leaf pages: %"Y"u", db->md_leaf_pages)); + DPRINTF(("overflow pages: %"Y"u", db->md_overflow_pages)); + DPRINTF(("root: %"Y"u", db->md_root)); + } +#endif + + return MDB_SUCCESS; +} + + +/** Release a reader thread's slot in the reader lock table. + * This function is called automatically when a thread exits. + * @param[in] ptr This points to the slot in the reader lock table. + */ +static void +mdb_env_reader_dest(void *ptr) +{ + MDB_reader *reader = ptr; + + reader->mr_pid = 0; +} + +#ifdef _WIN32 +/** Junk for arranging thread-specific callbacks on Windows. This is + * necessarily platform and compiler-specific. Windows supports up + * to 1088 keys. Let's assume nobody opens more than 64 environments + * in a single process, for now. They can override this if needed. + */ +#ifndef MAX_TLS_KEYS +#define MAX_TLS_KEYS 64 +#endif +static pthread_key_t mdb_tls_keys[MAX_TLS_KEYS]; +static int mdb_tls_nkeys; + +static void NTAPI mdb_tls_callback(PVOID module, DWORD reason, PVOID ptr) +{ + int i; + switch(reason) { + case DLL_PROCESS_ATTACH: break; + case DLL_THREAD_ATTACH: break; + case DLL_THREAD_DETACH: + for (i=0; ime_lfd, 0, 0, 1, 0, &ov)) { + rc = ErrCode(); + } else { + UnlockFile(env->me_lfd, 0, 0, 1, 0); + *excl = 0; + } + } +#else + { + struct flock lock_info; + /* The shared lock replaces the existing lock */ + memset((void *)&lock_info, 0, sizeof(lock_info)); + lock_info.l_type = F_RDLCK; + lock_info.l_whence = SEEK_SET; + lock_info.l_start = 0; + lock_info.l_len = 1; + while ((rc = fcntl(env->me_lfd, F_SETLK, &lock_info)) && + (rc = ErrCode()) == EINTR) ; + *excl = rc ? -1 : 0; /* error may mean we lost the lock */ + } +#endif + + return rc; +} + +/** Try to get exclusive lock, otherwise shared. + * Maintain *excl = -1: no/unknown lock, 0: shared, 1: exclusive. + */ +static int ESECT +mdb_env_excl_lock(MDB_env *env, int *excl) +{ + int rc = 0; +#ifdef _WIN32 + if (LockFile(env->me_lfd, 0, 0, 1, 0)) { + *excl = 1; + } else { + OVERLAPPED ov; + memset(&ov, 0, sizeof(ov)); + if (LockFileEx(env->me_lfd, 0, 0, 1, 0, &ov)) { + *excl = 0; + } else { + rc = ErrCode(); + } + } +#else + struct flock lock_info; + memset((void *)&lock_info, 0, sizeof(lock_info)); + lock_info.l_type = F_WRLCK; + lock_info.l_whence = SEEK_SET; + lock_info.l_start = 0; + lock_info.l_len = 1; + while ((rc = fcntl(env->me_lfd, F_SETLK, &lock_info)) && + (rc = ErrCode()) == EINTR) ; + if (!rc) { + *excl = 1; + } else +# ifndef MDB_USE_POSIX_MUTEX + if (*excl < 0) /* always true when MDB_USE_POSIX_MUTEX */ +# endif + { + lock_info.l_type = F_RDLCK; + while ((rc = fcntl(env->me_lfd, F_SETLKW, &lock_info)) && + (rc = ErrCode()) == EINTR) ; + if (rc == 0) + *excl = 0; + } +#endif + return rc; +} + +#ifdef MDB_USE_HASH +/* + * hash_64 - 64 bit Fowler/Noll/Vo-0 FNV-1a hash code + * + * @(#) $Revision: 5.1 $ + * @(#) $Id: hash_64a.c,v 5.1 2009/06/30 09:01:38 chongo Exp $ + * @(#) $Source: /usr/local/src/cmd/fnv/RCS/hash_64a.c,v $ + * + * http://www.isthe.com/chongo/tech/comp/fnv/index.html + * + *** + * + * Please do not copyright this code. This code is in the public domain. + * + * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * By: + * chongo /\oo/\ + * http://www.isthe.com/chongo/ + * + * Share and Enjoy! :-) + */ + +typedef unsigned long long mdb_hash_t; +#define MDB_HASH_INIT ((mdb_hash_t)0xcbf29ce484222325ULL) + +/** perform a 64 bit Fowler/Noll/Vo FNV-1a hash on a buffer + * @param[in] val value to hash + * @param[in] hval initial value for hash + * @return 64 bit hash + * + * NOTE: To use the recommended 64 bit FNV-1a hash, use MDB_HASH_INIT as the + * hval arg on the first call. + */ +static mdb_hash_t +mdb_hash_val(MDB_val *val, mdb_hash_t hval) +{ + unsigned char *s = (unsigned char *)val->mv_data; /* unsigned string */ + unsigned char *end = s + val->mv_size; + /* + * FNV-1a hash each octet of the string + */ + while (s < end) { + /* xor the bottom with the current octet */ + hval ^= (mdb_hash_t)*s++; + + /* multiply by the 64 bit FNV magic prime mod 2^64 */ + hval += (hval << 1) + (hval << 4) + (hval << 5) + + (hval << 7) + (hval << 8) + (hval << 40); + } + /* return our new hash value */ + return hval; +} + +/** Hash the string and output the encoded hash. + * This uses modified RFC1924 Ascii85 encoding to accommodate systems with + * very short name limits. We don't care about the encoding being reversible, + * we just want to preserve as many bits of the input as possible in a + * small printable string. + * @param[in] str string to hash + * @param[out] encbuf an array of 11 chars to hold the hash + */ +static const char mdb_a85[]= "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~"; + +static void ESECT +mdb_pack85(unsigned long l, char *out) +{ + int i; + + for (i=0; i<5; i++) { + *out++ = mdb_a85[l % 85]; + l /= 85; + } +} + +static void ESECT +mdb_hash_enc(MDB_val *val, char *encbuf) +{ + mdb_hash_t h = mdb_hash_val(val, MDB_HASH_INIT); + + mdb_pack85(h, encbuf); + mdb_pack85(h>>32, encbuf+5); + encbuf[10] = '\0'; +} +#endif + +/** Open and/or initialize the lock region for the environment. + * @param[in] env The LMDB environment. + * @param[in] lpath The pathname of the file used for the lock region. + * @param[in] mode The Unix permissions for the file, if we create it. + * @param[in,out] excl In -1, out lock type: -1 none, 0 shared, 1 exclusive + * @return 0 on success, non-zero on failure. + */ +static int ESECT +mdb_env_setup_locks(MDB_env *env, char *lpath, int mode, int *excl) +{ +#ifdef _WIN32 +# define MDB_ERRCODE_ROFS ERROR_WRITE_PROTECT +#else +# define MDB_ERRCODE_ROFS EROFS +#ifdef O_CLOEXEC /* Linux: Open file and set FD_CLOEXEC atomically */ +# define MDB_CLOEXEC O_CLOEXEC +#else + int fdflags; +# define MDB_CLOEXEC 0 +#endif +#endif +#ifdef MDB_USE_SYSV_SEM + int semid; + union semun semu; +#endif + int rc; + off64_t size, rsize; + +#ifdef _WIN32 + wchar_t *wlpath; + rc = utf8_to_utf16(lpath, -1, &wlpath, NULL); + if (rc) + return rc; + env->me_lfd = CreateFileW(wlpath, GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); + free(wlpath); +#else + env->me_lfd = open(lpath, O_RDWR|O_CREAT|MDB_CLOEXEC, mode); +#endif + if (env->me_lfd == INVALID_HANDLE_VALUE) { + rc = ErrCode(); + if (rc == MDB_ERRCODE_ROFS && (env->me_flags & MDB_RDONLY)) { + return MDB_SUCCESS; + } + goto fail_errno; + } +#if ! ((MDB_CLOEXEC) || defined(_WIN32)) + /* Lose record locks when exec*() */ + if ((fdflags = fcntl(env->me_lfd, F_GETFD) | FD_CLOEXEC) >= 0) + fcntl(env->me_lfd, F_SETFD, fdflags); +#endif + + if (!(env->me_flags & MDB_NOTLS)) { + rc = pthread_key_create(&env->me_txkey, mdb_env_reader_dest); + if (rc) + goto fail; + env->me_flags |= MDB_ENV_TXKEY; +#ifdef _WIN32 + /* Windows TLS callbacks need help finding their TLS info. */ + if (mdb_tls_nkeys >= MAX_TLS_KEYS) { + rc = MDB_TLS_FULL; + goto fail; + } + mdb_tls_keys[mdb_tls_nkeys++] = env->me_txkey; +#endif + } + + /* Try to get exclusive lock. If we succeed, then + * nobody is using the lock region and we should initialize it. + */ + if ((rc = mdb_env_excl_lock(env, excl))) goto fail; + +#ifdef _WIN32 + size = GetFileSize(env->me_lfd, NULL); +#else + size = lseek(env->me_lfd, 0, SEEK_END); + if (size == -1) goto fail_errno; +#endif + rsize = (env->me_maxreaders-1) * sizeof(MDB_reader) + sizeof(MDB_txninfo); + if (size < rsize && *excl > 0) { +#ifdef _WIN32 + if (SetFilePointer(env->me_lfd, rsize, NULL, FILE_BEGIN) != (DWORD)rsize + || !SetEndOfFile(env->me_lfd)) + goto fail_errno; +#else + if (ftruncate(env->me_lfd, rsize) != 0) goto fail_errno; +#endif + } else { + rsize = size; + size = rsize - sizeof(MDB_txninfo); + env->me_maxreaders = size/sizeof(MDB_reader) + 1; + } + { +#ifdef _WIN32 + HANDLE mh; + mh = CreateFileMapping(env->me_lfd, NULL, PAGE_READWRITE, + 0, 0, NULL); + if (!mh) goto fail_errno; + env->me_txns = MapViewOfFileEx(mh, FILE_MAP_WRITE, 0, 0, rsize, NULL); + CloseHandle(mh); + if (!env->me_txns) goto fail_errno; +#else + void *m = mmap(NULL, rsize, PROT_READ|PROT_WRITE, MAP_SHARED, + env->me_lfd, 0); + if (m == MAP_FAILED) goto fail_errno; + env->me_txns = m; +#endif + } + if (*excl > 0) { +#ifdef _WIN32 + BY_HANDLE_FILE_INFORMATION stbuf; + struct { + DWORD volume; + DWORD nhigh; + DWORD nlow; + } idbuf; + MDB_val val; + char encbuf[11]; + + if (!mdb_sec_inited) { + InitializeSecurityDescriptor(&mdb_null_sd, + SECURITY_DESCRIPTOR_REVISION); + SetSecurityDescriptorDacl(&mdb_null_sd, TRUE, 0, FALSE); + mdb_all_sa.nLength = sizeof(SECURITY_ATTRIBUTES); + mdb_all_sa.bInheritHandle = FALSE; + mdb_all_sa.lpSecurityDescriptor = &mdb_null_sd; + mdb_sec_inited = 1; + } + if (!GetFileInformationByHandle(env->me_lfd, &stbuf)) goto fail_errno; + idbuf.volume = stbuf.dwVolumeSerialNumber; + idbuf.nhigh = stbuf.nFileIndexHigh; + idbuf.nlow = stbuf.nFileIndexLow; + val.mv_data = &idbuf; + val.mv_size = sizeof(idbuf); + mdb_hash_enc(&val, encbuf); + sprintf(env->me_txns->mti_rmname, "Global\\MDBr%s", encbuf); + sprintf(env->me_txns->mti_wmname, "Global\\MDBw%s", encbuf); + env->me_rmutex = CreateMutexA(&mdb_all_sa, FALSE, env->me_txns->mti_rmname); + if (!env->me_rmutex) goto fail_errno; + env->me_wmutex = CreateMutexA(&mdb_all_sa, FALSE, env->me_txns->mti_wmname); + if (!env->me_wmutex) goto fail_errno; +#elif defined(MDB_USE_POSIX_SEM) + struct stat stbuf; + struct { + dev_t dev; + ino_t ino; + } idbuf; + MDB_val val; + char encbuf[11]; + +#if defined(__NetBSD__) +#define MDB_SHORT_SEMNAMES 1 /* limited to 14 chars */ +#endif + if (fstat(env->me_lfd, &stbuf)) goto fail_errno; + idbuf.dev = stbuf.st_dev; + idbuf.ino = stbuf.st_ino; + val.mv_data = &idbuf; + val.mv_size = sizeof(idbuf); + mdb_hash_enc(&val, encbuf); +#ifdef MDB_SHORT_SEMNAMES + encbuf[9] = '\0'; /* drop name from 15 chars to 14 chars */ +#endif + sprintf(env->me_txns->mti_rmname, "/MDBr%s", encbuf); + sprintf(env->me_txns->mti_wmname, "/MDBw%s", encbuf); + /* Clean up after a previous run, if needed: Try to + * remove both semaphores before doing anything else. + */ + sem_unlink(env->me_txns->mti_rmname); + sem_unlink(env->me_txns->mti_wmname); + env->me_rmutex = sem_open(env->me_txns->mti_rmname, + O_CREAT|O_EXCL, mode, 1); + if (env->me_rmutex == SEM_FAILED) goto fail_errno; + env->me_wmutex = sem_open(env->me_txns->mti_wmname, + O_CREAT|O_EXCL, mode, 1); + if (env->me_wmutex == SEM_FAILED) goto fail_errno; +#elif defined(MDB_USE_SYSV_SEM) + unsigned short vals[2] = {1, 1}; + key_t key = ftok(lpath, 'M'); + if (key == -1) + goto fail_errno; + semid = semget(key, 2, (mode & 0777) | IPC_CREAT); + if (semid < 0) + goto fail_errno; + semu.array = vals; + if (semctl(semid, 0, SETALL, semu) < 0) + goto fail_errno; + env->me_txns->mti_semid = semid; +#else /* MDB_USE_POSIX_MUTEX: */ + pthread_mutexattr_t mattr; + + if ((rc = pthread_mutexattr_init(&mattr)) + || (rc = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED)) +#ifdef MDB_ROBUST_SUPPORTED + || (rc = pthread_mutexattr_setrobust(&mattr, PTHREAD_MUTEX_ROBUST)) +#endif + || (rc = pthread_mutex_init(env->me_txns->mti_rmutex, &mattr)) + || (rc = pthread_mutex_init(env->me_txns->mti_wmutex, &mattr))) + goto fail; + pthread_mutexattr_destroy(&mattr); +#endif /* _WIN32 || ... */ + + env->me_txns->mti_magic = MDB_MAGIC; + env->me_txns->mti_format = MDB_LOCK_FORMAT; + env->me_txns->mti_txnid = 0; + env->me_txns->mti_numreaders = 0; + + } else { +#ifdef MDB_USE_SYSV_SEM + struct semid_ds buf; +#endif + if (env->me_txns->mti_magic != MDB_MAGIC) { + DPUTS("lock region has invalid magic"); + rc = MDB_INVALID; + goto fail; + } + if (env->me_txns->mti_format != MDB_LOCK_FORMAT) { + DPRINTF(("lock region has format+version 0x%x, expected 0x%x", + env->me_txns->mti_format, MDB_LOCK_FORMAT)); + rc = MDB_VERSION_MISMATCH; + goto fail; + } + rc = ErrCode(); + if (rc && rc != EACCES && rc != EAGAIN) { + goto fail; + } +#ifdef _WIN32 + env->me_rmutex = OpenMutexA(SYNCHRONIZE, FALSE, env->me_txns->mti_rmname); + if (!env->me_rmutex) goto fail_errno; + env->me_wmutex = OpenMutexA(SYNCHRONIZE, FALSE, env->me_txns->mti_wmname); + if (!env->me_wmutex) goto fail_errno; +#elif defined(MDB_USE_POSIX_SEM) + env->me_rmutex = sem_open(env->me_txns->mti_rmname, 0); + if (env->me_rmutex == SEM_FAILED) goto fail_errno; + env->me_wmutex = sem_open(env->me_txns->mti_wmname, 0); + if (env->me_wmutex == SEM_FAILED) goto fail_errno; +#elif defined(MDB_USE_SYSV_SEM) + semid = env->me_txns->mti_semid; + semu.buf = &buf; + /* check for read access */ + if (semctl(semid, 0, IPC_STAT, semu) < 0) + goto fail_errno; + /* check for write access */ + if (semctl(semid, 0, IPC_SET, semu) < 0) + goto fail_errno; +#endif + } +#ifdef MDB_USE_SYSV_SEM + env->me_rmutex->semid = semid; + env->me_wmutex->semid = semid; + env->me_rmutex->semnum = 0; + env->me_wmutex->semnum = 1; + env->me_rmutex->locked = &env->me_txns->mti_rlocked; + env->me_wmutex->locked = &env->me_txns->mti_wlocked; +#endif +#ifdef MDB_VL32 +#ifdef _WIN32 + env->me_rpmutex = CreateMutex(NULL, FALSE, NULL); +#else + pthread_mutex_init(&env->me_rpmutex, NULL); +#endif +#endif + + return MDB_SUCCESS; + +fail_errno: + rc = ErrCode(); +fail: + return rc; +} + + /** The name of the lock file in the DB environment */ +#define LOCKNAME "/lock.mdb" + /** The name of the data file in the DB environment */ +#define DATANAME "/data.mdb" + /** The suffix of the lock file when no subdir is used */ +#define LOCKSUFF "-lock" + /** Only a subset of the @ref mdb_env flags can be changed + * at runtime. Changing other flags requires closing the + * environment and re-opening it with the new flags. + */ +#define CHANGEABLE (MDB_NOSYNC|MDB_NOMETASYNC|MDB_MAPASYNC|MDB_NOMEMINIT) +#define CHANGELESS (MDB_FIXEDMAP|MDB_NOSUBDIR|MDB_RDONLY| \ + MDB_WRITEMAP|MDB_NOTLS|MDB_NOLOCK|MDB_NORDAHEAD|MDB_PREVSNAPSHOT) + +#if VALID_FLAGS & PERSISTENT_FLAGS & (CHANGEABLE|CHANGELESS) +# error "Persistent DB flags & env flags overlap, but both go in mm_flags" +#endif + +int ESECT +mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode) +{ + int oflags, rc, len, excl = -1; + char *lpath, *dpath; +#ifdef _WIN32 + wchar_t *wpath; +#endif + + if (env->me_fd!=INVALID_HANDLE_VALUE || (flags & ~(CHANGEABLE|CHANGELESS))) + return EINVAL; + +#ifdef MDB_VL32 + if (flags & MDB_WRITEMAP) { + /* silently ignore WRITEMAP in 32 bit mode */ + flags ^= MDB_WRITEMAP; + } + if (flags & MDB_FIXEDMAP) { + /* cannot support FIXEDMAP */ + return EINVAL; + } +#endif + + len = strlen(path); + if (flags & MDB_NOSUBDIR) { + rc = len + sizeof(LOCKSUFF) + len + 1; + } else { + rc = len + sizeof(LOCKNAME) + len + sizeof(DATANAME); + } + lpath = malloc(rc); + if (!lpath) + return ENOMEM; + if (flags & MDB_NOSUBDIR) { + dpath = lpath + len + sizeof(LOCKSUFF); + sprintf(lpath, "%s" LOCKSUFF, path); + strcpy(dpath, path); + } else { + dpath = lpath + len + sizeof(LOCKNAME); + sprintf(lpath, "%s" LOCKNAME, path); + sprintf(dpath, "%s" DATANAME, path); + } + + rc = MDB_SUCCESS; + flags |= env->me_flags; + if (flags & MDB_RDONLY) { + /* silently ignore WRITEMAP when we're only getting read access */ + flags &= ~MDB_WRITEMAP; + } else { + if (!((env->me_free_pgs = mdb_midl_alloc(MDB_IDL_UM_MAX)) && + (env->me_dirty_list = calloc(MDB_IDL_UM_SIZE, sizeof(MDB_ID2))))) + rc = ENOMEM; + } +#ifdef MDB_VL32 + if (!rc) { + env->me_rpages = malloc(MDB_ERPAGE_SIZE * sizeof(MDB_ID3)); + if (!env->me_rpages) { + rc = ENOMEM; + goto leave; + } + env->me_rpages[0].mid = 0; + env->me_rpcheck = MDB_ERPAGE_SIZE/2; + } +#endif + env->me_flags = flags |= MDB_ENV_ACTIVE; + if (rc) + goto leave; + + env->me_path = strdup(path); + env->me_dbxs = calloc(env->me_maxdbs, sizeof(MDB_dbx)); + env->me_dbflags = calloc(env->me_maxdbs, sizeof(uint16_t)); + env->me_dbiseqs = calloc(env->me_maxdbs, sizeof(unsigned int)); + if (!(env->me_dbxs && env->me_path && env->me_dbflags && env->me_dbiseqs)) { + rc = ENOMEM; + goto leave; + } + env->me_dbxs[FREE_DBI].md_cmp = mdb_cmp_long; /* aligned MDB_INTEGERKEY */ + + /* For RDONLY, get lockfile after we know datafile exists */ + if (!(flags & (MDB_RDONLY|MDB_NOLOCK))) { + rc = mdb_env_setup_locks(env, lpath, mode, &excl); + if (rc) + goto leave; + } + +#ifdef _WIN32 + if (F_ISSET(flags, MDB_RDONLY)) { + oflags = GENERIC_READ; + len = OPEN_EXISTING; + } else { + oflags = GENERIC_READ|GENERIC_WRITE; + len = OPEN_ALWAYS; + } + mode = FILE_ATTRIBUTE_NORMAL; + rc = utf8_to_utf16(dpath, -1, &wpath, NULL); + if (rc) + goto leave; + env->me_fd = CreateFileW(wpath, oflags, FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL, len, mode, NULL); + free(wpath); +#else + if (F_ISSET(flags, MDB_RDONLY)) + oflags = O_RDONLY; + else + oflags = O_RDWR | O_CREAT; + + env->me_fd = open(dpath, oflags, mode); +#endif + if (env->me_fd == INVALID_HANDLE_VALUE) { + rc = ErrCode(); + goto leave; + } + + if ((flags & (MDB_RDONLY|MDB_NOLOCK)) == MDB_RDONLY) { + rc = mdb_env_setup_locks(env, lpath, mode, &excl); + if (rc) + goto leave; + if ((flags & MDB_PREVSNAPSHOT) && !excl) { + rc = EAGAIN; + goto leave; + } + } + + if ((rc = mdb_env_open2(env, flags & MDB_PREVSNAPSHOT)) == MDB_SUCCESS) { + if (flags & (MDB_RDONLY|MDB_WRITEMAP)) { + env->me_mfd = env->me_fd; + } else { + /* Synchronous fd for meta writes. Needed even with + * MDB_NOSYNC/MDB_NOMETASYNC, in case these get reset. + */ +#ifdef _WIN32 + len = OPEN_EXISTING; + rc = utf8_to_utf16(dpath, -1, &wpath, NULL); + if (rc) + goto leave; + env->me_mfd = CreateFileW(wpath, oflags, + FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, len, + mode | FILE_FLAG_WRITE_THROUGH, NULL); + free(wpath); +#else + oflags &= ~O_CREAT; + env->me_mfd = open(dpath, oflags | MDB_DSYNC, mode); +#endif + if (env->me_mfd == INVALID_HANDLE_VALUE) { + rc = ErrCode(); + goto leave; + } + } + DPRINTF(("opened dbenv %p", (void *) env)); + if (excl > 0 && !(flags & MDB_PREVSNAPSHOT)) { + rc = mdb_env_share_locks(env, &excl); + if (rc) + goto leave; + } + if (!(flags & MDB_RDONLY)) { + MDB_txn *txn; + int tsize = sizeof(MDB_txn), size = tsize + env->me_maxdbs * + (sizeof(MDB_db)+sizeof(MDB_cursor *)+sizeof(unsigned int)+1); + if ((env->me_pbuf = calloc(1, env->me_psize)) && + (txn = calloc(1, size))) + { + txn->mt_dbs = (MDB_db *)((char *)txn + tsize); + txn->mt_cursors = (MDB_cursor **)(txn->mt_dbs + env->me_maxdbs); + txn->mt_dbiseqs = (unsigned int *)(txn->mt_cursors + env->me_maxdbs); + txn->mt_dbflags = (unsigned char *)(txn->mt_dbiseqs + env->me_maxdbs); + txn->mt_env = env; +#ifdef MDB_VL32 + txn->mt_rpages = malloc(MDB_TRPAGE_SIZE * sizeof(MDB_ID3)); + if (!txn->mt_rpages) { + free(txn); + rc = ENOMEM; + goto leave; + } + txn->mt_rpages[0].mid = 0; + txn->mt_rpcheck = MDB_TRPAGE_SIZE/2; +#endif + txn->mt_dbxs = env->me_dbxs; + txn->mt_flags = MDB_TXN_FINISHED; + env->me_txn0 = txn; + } else { + rc = ENOMEM; + } + } + } + +leave: + if (rc) { + mdb_env_close0(env, excl); + } + free(lpath); + return rc; +} + +/** Destroy resources from mdb_env_open(), clear our readers & DBIs */ +static void ESECT +mdb_env_close0(MDB_env *env, int excl) +{ + int i; + + if (!(env->me_flags & MDB_ENV_ACTIVE)) + return; + + /* Doing this here since me_dbxs may not exist during mdb_env_close */ + if (env->me_dbxs) { + for (i = env->me_maxdbs; --i >= CORE_DBS; ) + free(env->me_dbxs[i].md_name.mv_data); + free(env->me_dbxs); + } + + free(env->me_pbuf); + free(env->me_dbiseqs); + free(env->me_dbflags); + free(env->me_path); + free(env->me_dirty_list); +#ifdef MDB_VL32 + if (env->me_txn0 && env->me_txn0->mt_rpages) + free(env->me_txn0->mt_rpages); + { unsigned int x; + for (x=1; x<=env->me_rpages[0].mid; x++) + munmap(env->me_rpages[x].mptr, env->me_rpages[x].mcnt * env->me_psize); + } + free(env->me_rpages); +#endif + free(env->me_txn0); + mdb_midl_free(env->me_free_pgs); + + if (env->me_flags & MDB_ENV_TXKEY) { + pthread_key_delete(env->me_txkey); +#ifdef _WIN32 + /* Delete our key from the global list */ + for (i=0; ime_txkey) { + mdb_tls_keys[i] = mdb_tls_keys[mdb_tls_nkeys-1]; + mdb_tls_nkeys--; + break; + } +#endif + } + + if (env->me_map) { +#ifdef MDB_VL32 + munmap(env->me_map, NUM_METAS*env->me_psize); +#else + munmap(env->me_map, env->me_mapsize); +#endif + } + if (env->me_mfd != env->me_fd && env->me_mfd != INVALID_HANDLE_VALUE) + (void) close(env->me_mfd); + if (env->me_fd != INVALID_HANDLE_VALUE) + (void) close(env->me_fd); + if (env->me_txns) { + MDB_PID_T pid = env->me_pid; + /* Clearing readers is done in this function because + * me_txkey with its destructor must be disabled first. + * + * We skip the the reader mutex, so we touch only + * data owned by this process (me_close_readers and + * our readers), and clear each reader atomically. + */ + for (i = env->me_close_readers; --i >= 0; ) + if (env->me_txns->mti_readers[i].mr_pid == pid) + env->me_txns->mti_readers[i].mr_pid = 0; +#ifdef _WIN32 + if (env->me_rmutex) { + CloseHandle(env->me_rmutex); + if (env->me_wmutex) CloseHandle(env->me_wmutex); + } + /* Windows automatically destroys the mutexes when + * the last handle closes. + */ +#elif defined(MDB_USE_POSIX_SEM) + if (env->me_rmutex != SEM_FAILED) { + sem_close(env->me_rmutex); + if (env->me_wmutex != SEM_FAILED) + sem_close(env->me_wmutex); + /* If we have the filelock: If we are the + * only remaining user, clean up semaphores. + */ + if (excl == 0) + mdb_env_excl_lock(env, &excl); + if (excl > 0) { + sem_unlink(env->me_txns->mti_rmname); + sem_unlink(env->me_txns->mti_wmname); + } + } +#elif defined(MDB_USE_SYSV_SEM) + if (env->me_rmutex->semid != -1) { + /* If we have the filelock: If we are the + * only remaining user, clean up semaphores. + */ + if (excl == 0) + mdb_env_excl_lock(env, &excl); + if (excl > 0) + semctl(env->me_rmutex->semid, 0, IPC_RMID); + } +#endif + munmap((void *)env->me_txns, (env->me_maxreaders-1)*sizeof(MDB_reader)+sizeof(MDB_txninfo)); + } + if (env->me_lfd != INVALID_HANDLE_VALUE) { +#ifdef _WIN32 + if (excl >= 0) { + /* Unlock the lockfile. Windows would have unlocked it + * after closing anyway, but not necessarily at once. + */ + UnlockFile(env->me_lfd, 0, 0, 1, 0); + } +#endif + (void) close(env->me_lfd); + } +#ifdef MDB_VL32 +#ifdef _WIN32 + if (env->me_fmh) CloseHandle(env->me_fmh); + if (env->me_rpmutex) CloseHandle(env->me_rpmutex); +#else + pthread_mutex_destroy(&env->me_rpmutex); +#endif +#endif + + env->me_flags &= ~(MDB_ENV_ACTIVE|MDB_ENV_TXKEY); +} + +void ESECT +mdb_env_close(MDB_env *env) +{ + MDB_page *dp; + + if (env == NULL) + return; + + VGMEMP_DESTROY(env); + while ((dp = env->me_dpages) != NULL) { + VGMEMP_DEFINED(&dp->mp_next, sizeof(dp->mp_next)); + env->me_dpages = dp->mp_next; + free(dp); + } + + mdb_env_close0(env, 0); + free(env); +} + +/** Compare two items pointing at aligned mdb_size_t's */ +static int +mdb_cmp_long(const MDB_val *a, const MDB_val *b) +{ + return (*(mdb_size_t *)a->mv_data < *(mdb_size_t *)b->mv_data) ? -1 : + *(mdb_size_t *)a->mv_data > *(mdb_size_t *)b->mv_data; +} + +/** Compare two items pointing at aligned unsigned int's. + * + * This is also set as #MDB_INTEGERDUP|#MDB_DUPFIXED's #MDB_dbx.%md_dcmp, + * but #mdb_cmp_clong() is called instead if the data type is mdb_size_t. + */ +static int +mdb_cmp_int(const MDB_val *a, const MDB_val *b) +{ + return (*(unsigned int *)a->mv_data < *(unsigned int *)b->mv_data) ? -1 : + *(unsigned int *)a->mv_data > *(unsigned int *)b->mv_data; +} + +/** Compare two items pointing at unsigned ints of unknown alignment. + * Nodes and keys are guaranteed to be 2-byte aligned. + */ +static int +mdb_cmp_cint(const MDB_val *a, const MDB_val *b) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + unsigned short *u, *c; + int x; + + u = (unsigned short *) ((char *) a->mv_data + a->mv_size); + c = (unsigned short *) ((char *) b->mv_data + a->mv_size); + do { + x = *--u - *--c; + } while(!x && u > (unsigned short *)a->mv_data); + return x; +#else + unsigned short *u, *c, *end; + int x; + + end = (unsigned short *) ((char *) a->mv_data + a->mv_size); + u = (unsigned short *)a->mv_data; + c = (unsigned short *)b->mv_data; + do { + x = *u++ - *c++; + } while(!x && u < end); + return x; +#endif +} + +/** Compare two items lexically */ +static int +mdb_cmp_memn(const MDB_val *a, const MDB_val *b) +{ + int diff; + ssize_t len_diff; + unsigned int len; + + len = a->mv_size; + len_diff = (ssize_t) a->mv_size - (ssize_t) b->mv_size; + if (len_diff > 0) { + len = b->mv_size; + len_diff = 1; + } + + diff = memcmp(a->mv_data, b->mv_data, len); + return diff ? diff : len_diff<0 ? -1 : len_diff; +} + +/** Compare two items in reverse byte order */ +static int +mdb_cmp_memnr(const MDB_val *a, const MDB_val *b) +{ + const unsigned char *p1, *p2, *p1_lim; + ssize_t len_diff; + int diff; + + p1_lim = (const unsigned char *)a->mv_data; + p1 = (const unsigned char *)a->mv_data + a->mv_size; + p2 = (const unsigned char *)b->mv_data + b->mv_size; + + len_diff = (ssize_t) a->mv_size - (ssize_t) b->mv_size; + if (len_diff > 0) { + p1_lim += len_diff; + len_diff = 1; + } + + while (p1 > p1_lim) { + diff = *--p1 - *--p2; + if (diff) + return diff; + } + return len_diff<0 ? -1 : len_diff; +} + +/** Search for key within a page, using binary search. + * Returns the smallest entry larger or equal to the key. + * If exactp is non-null, stores whether the found entry was an exact match + * in *exactp (1 or 0). + * Updates the cursor index with the index of the found entry. + * If no entry larger or equal to the key is found, returns NULL. + */ +static MDB_node * +mdb_node_search(MDB_cursor *mc, MDB_val *key, int *exactp) +{ + unsigned int i = 0, nkeys; + int low, high; + int rc = 0; + MDB_page *mp = mc->mc_pg[mc->mc_top]; + MDB_node *node = NULL; + MDB_val nodekey; + MDB_cmp_func *cmp; + DKBUF; + + nkeys = NUMKEYS(mp); + + DPRINTF(("searching %u keys in %s %spage %"Y"u", + nkeys, IS_LEAF(mp) ? "leaf" : "branch", IS_SUBP(mp) ? "sub-" : "", + mdb_dbg_pgno(mp))); + + low = IS_LEAF(mp) ? 0 : 1; + high = nkeys - 1; + cmp = mc->mc_dbx->md_cmp; + + /* Branch pages have no data, so if using integer keys, + * alignment is guaranteed. Use faster mdb_cmp_int. + */ + if (cmp == mdb_cmp_cint && IS_BRANCH(mp)) { + if (NODEPTR(mp, 1)->mn_ksize == sizeof(mdb_size_t)) + cmp = mdb_cmp_long; + else + cmp = mdb_cmp_int; + } + + if (IS_LEAF2(mp)) { + nodekey.mv_size = mc->mc_db->md_pad; + node = NODEPTR(mp, 0); /* fake */ + while (low <= high) { + i = (low + high) >> 1; + nodekey.mv_data = LEAF2KEY(mp, i, nodekey.mv_size); + rc = cmp(key, &nodekey); + DPRINTF(("found leaf index %u [%s], rc = %i", + i, DKEY(&nodekey), rc)); + if (rc == 0) + break; + if (rc > 0) + low = i + 1; + else + high = i - 1; + } + } else { + while (low <= high) { + i = (low + high) >> 1; + + node = NODEPTR(mp, i); + nodekey.mv_size = NODEKSZ(node); + nodekey.mv_data = NODEKEY(node); + + rc = cmp(key, &nodekey); +#if MDB_DEBUG + if (IS_LEAF(mp)) + DPRINTF(("found leaf index %u [%s], rc = %i", + i, DKEY(&nodekey), rc)); + else + DPRINTF(("found branch index %u [%s -> %"Y"u], rc = %i", + i, DKEY(&nodekey), NODEPGNO(node), rc)); +#endif + if (rc == 0) + break; + if (rc > 0) + low = i + 1; + else + high = i - 1; + } + } + + if (rc > 0) { /* Found entry is less than the key. */ + i++; /* Skip to get the smallest entry larger than key. */ + if (!IS_LEAF2(mp)) + node = NODEPTR(mp, i); + } + if (exactp) + *exactp = (rc == 0 && nkeys > 0); + /* store the key index */ + mc->mc_ki[mc->mc_top] = i; + if (i >= nkeys) + /* There is no entry larger or equal to the key. */ + return NULL; + + /* nodeptr is fake for LEAF2 */ + return node; +} + +#if 0 +static void +mdb_cursor_adjust(MDB_cursor *mc, func) +{ + MDB_cursor *m2; + + for (m2 = mc->mc_txn->mt_cursors[mc->mc_dbi]; m2; m2=m2->mc_next) { + if (m2->mc_pg[m2->mc_top] == mc->mc_pg[mc->mc_top]) { + func(mc, m2); + } + } +} +#endif + +/** Pop a page off the top of the cursor's stack. */ +static void +mdb_cursor_pop(MDB_cursor *mc) +{ + if (mc->mc_snum) { + DPRINTF(("popping page %"Y"u off db %d cursor %p", + mc->mc_pg[mc->mc_top]->mp_pgno, DDBI(mc), (void *) mc)); + + mc->mc_snum--; + if (mc->mc_snum) { + mc->mc_top--; + } else { + mc->mc_flags &= ~C_INITIALIZED; + } + } +} + +/** Push a page onto the top of the cursor's stack. */ +static int +mdb_cursor_push(MDB_cursor *mc, MDB_page *mp) +{ + DPRINTF(("pushing page %"Y"u on db %d cursor %p", mp->mp_pgno, + DDBI(mc), (void *) mc)); + + if (mc->mc_snum >= CURSOR_STACK) { + mc->mc_txn->mt_flags |= MDB_TXN_ERROR; + return MDB_CURSOR_FULL; + } + + mc->mc_top = mc->mc_snum++; + mc->mc_pg[mc->mc_top] = mp; + mc->mc_ki[mc->mc_top] = 0; + + return MDB_SUCCESS; +} + +#ifdef MDB_VL32 +/** Map a read-only page. + * There are two levels of tracking in use, a per-txn list and a per-env list. + * ref'ing and unref'ing the per-txn list is faster since it requires no + * locking. Pages are cached in the per-env list for global reuse, and a lock + * is required. Pages are not immediately unmapped when their refcnt goes to + * zero; they hang around in case they will be reused again soon. + * + * When the per-txn list gets full, all pages with refcnt=0 are purged from the + * list and their refcnts in the per-env list are decremented. + * + * When the per-env list gets full, all pages with refcnt=0 are purged from the + * list and their pages are unmapped. + * + * @note "full" means the list has reached its respective rpcheck threshold. + * This threshold slowly raises if no pages could be purged on a given check, + * and returns to its original value when enough pages were purged. + * + * If purging doesn't free any slots, filling the per-txn list will return + * MDB_TXN_FULL, and filling the per-env list returns MDB_MAP_FULL. + * + * Reference tracking in a txn is imperfect, pages can linger with non-zero + * refcnt even without active references. It was deemed to be too invasive + * to add unrefs in every required location. However, all pages are unref'd + * at the end of the transaction. This guarantees that no stale references + * linger in the per-env list. + * + * Usually we map chunks of 16 pages at a time, but if an overflow page begins + * at the tail of the chunk we extend the chunk to include the entire overflow + * page. Unfortunately, pages can be turned into overflow pages after their + * chunk was already mapped. In that case we must remap the chunk if the + * overflow page is referenced. If the chunk's refcnt is 0 we can just remap + * it, otherwise we temporarily map a new chunk just for the overflow page. + * + * @note this chunk handling means we cannot guarantee that a data item + * returned from the DB will stay alive for the duration of the transaction: + * We unref pages as soon as a cursor moves away from the page + * A subsequent op may cause a purge, which may unmap any unref'd chunks + * The caller must copy the data if it must be used later in the same txn. + * + * Also - our reference counting revolves around cursors, but overflow pages + * aren't pointed to by a cursor's page stack. We have to remember them + * explicitly, in the added mc_ovpg field. A single cursor can only hold a + * reference to one overflow page at a time. + * + * @param[in] txn the transaction for this access. + * @param[in] pgno the page number for the page to retrieve. + * @param[out] ret address of a pointer where the page's address will be stored. + * @return 0 on success, non-zero on failure. + */ +static int +mdb_rpage_get(MDB_txn *txn, pgno_t pg0, MDB_page **ret) +{ + MDB_env *env = txn->mt_env; + MDB_page *p; + MDB_ID3L tl = txn->mt_rpages; + MDB_ID3L el = env->me_rpages; + MDB_ID3 id3; + unsigned x, rem; + pgno_t pgno; + int rc, retries = 1; +#ifdef _WIN32 + LARGE_INTEGER off; + SIZE_T len; +#define SET_OFF(off,val) off.QuadPart = val +#define MAP(rc,env,addr,len,off) \ + addr = NULL; \ + rc = NtMapViewOfSection(env->me_fmh, GetCurrentProcess(), &addr, 0, \ + len, &off, &len, ViewUnmap, (env->me_flags & MDB_RDONLY) ? 0 : MEM_RESERVE, PAGE_READONLY); \ + if (rc) rc = mdb_nt2win32(rc) +#else + off64_t off; + size_t len; +#define SET_OFF(off,val) off = val +#define MAP(rc,env,addr,len,off) \ + addr = mmap(NULL, len, PROT_READ, MAP_SHARED, env->me_fd, off); \ + rc = (addr == MAP_FAILED) ? errno : 0 +#endif + + /* remember the offset of the actual page number, so we can + * return the correct pointer at the end. + */ + rem = pg0 & (MDB_RPAGE_CHUNK-1); + pgno = pg0 ^ rem; + + id3.mid = 0; + x = mdb_mid3l_search(tl, pgno); + if (x <= tl[0].mid && tl[x].mid == pgno) { + if (x != tl[0].mid && tl[x+1].mid == pg0) + x++; + /* check for overflow size */ + p = (MDB_page *)((char *)tl[x].mptr + rem * env->me_psize); + if (IS_OVERFLOW(p) && p->mp_pages + rem > tl[x].mcnt) { + id3.mcnt = p->mp_pages + rem; + len = id3.mcnt * env->me_psize; + SET_OFF(off, pgno * env->me_psize); + MAP(rc, env, id3.mptr, len, off); + if (rc) + return rc; + /* check for local-only page */ + if (rem) { + mdb_tassert(txn, tl[x].mid != pg0); + /* hope there's room to insert this locally. + * setting mid here tells later code to just insert + * this id3 instead of searching for a match. + */ + id3.mid = pg0; + goto notlocal; + } else { + /* ignore the mapping we got from env, use new one */ + tl[x].mptr = id3.mptr; + tl[x].mcnt = id3.mcnt; + /* if no active ref, see if we can replace in env */ + if (!tl[x].mref) { + unsigned i; + pthread_mutex_lock(&env->me_rpmutex); + i = mdb_mid3l_search(el, tl[x].mid); + if (el[i].mref == 1) { + /* just us, replace it */ + munmap(el[i].mptr, el[i].mcnt * env->me_psize); + el[i].mptr = tl[x].mptr; + el[i].mcnt = tl[x].mcnt; + } else { + /* there are others, remove ourself */ + el[i].mref--; + } + pthread_mutex_unlock(&env->me_rpmutex); + } + } + } + id3.mptr = tl[x].mptr; + id3.mcnt = tl[x].mcnt; + tl[x].mref++; + goto ok; + } + +notlocal: + if (tl[0].mid >= MDB_TRPAGE_MAX - txn->mt_rpcheck) { + unsigned i, y; + /* purge unref'd pages from our list and unref in env */ + pthread_mutex_lock(&env->me_rpmutex); +retry: + y = 0; + for (i=1; i<=tl[0].mid; i++) { + if (!tl[i].mref) { + if (!y) y = i; + /* tmp overflow pages don't go to env */ + if (tl[i].mid & (MDB_RPAGE_CHUNK-1)) { + munmap(tl[i].mptr, tl[i].mcnt * env->me_psize); + continue; + } + x = mdb_mid3l_search(el, tl[i].mid); + el[x].mref--; + } + } + pthread_mutex_unlock(&env->me_rpmutex); + if (!y) { + /* we didn't find any unref'd chunks. + * if we're out of room, fail. + */ + if (tl[0].mid >= MDB_TRPAGE_MAX) + return MDB_TXN_FULL; + /* otherwise, raise threshold for next time around + * and let this go. + */ + txn->mt_rpcheck /= 2; + } else { + /* we found some unused; consolidate the list */ + for (i=y+1; i<= tl[0].mid; i++) + if (tl[i].mref) + tl[y++] = tl[i]; + tl[0].mid = y-1; + /* decrease the check threshold toward its original value */ + if (!txn->mt_rpcheck) + txn->mt_rpcheck = 1; + while (txn->mt_rpcheck < tl[0].mid && txn->mt_rpcheck < MDB_TRPAGE_SIZE/2) + txn->mt_rpcheck *= 2; + } + } + if (tl[0].mid < MDB_TRPAGE_SIZE) { + id3.mref = 1; + if (id3.mid) + goto found; + /* don't map past last written page in read-only envs */ + if ((env->me_flags & MDB_RDONLY) && pgno + MDB_RPAGE_CHUNK-1 > txn->mt_last_pgno) + id3.mcnt = txn->mt_last_pgno + 1 - pgno; + else + id3.mcnt = MDB_RPAGE_CHUNK; + len = id3.mcnt * env->me_psize; + id3.mid = pgno; + + /* search for page in env */ + pthread_mutex_lock(&env->me_rpmutex); + x = mdb_mid3l_search(el, pgno); + if (x <= el[0].mid && el[x].mid == pgno) { + id3.mptr = el[x].mptr; + id3.mcnt = el[x].mcnt; + /* check for overflow size */ + p = (MDB_page *)((char *)id3.mptr + rem * env->me_psize); + if (IS_OVERFLOW(p) && p->mp_pages + rem > id3.mcnt) { + id3.mcnt = p->mp_pages + rem; + len = id3.mcnt * env->me_psize; + SET_OFF(off, pgno * env->me_psize); + MAP(rc, env, id3.mptr, len, off); + if (rc) + goto fail; + if (!el[x].mref) { + munmap(el[x].mptr, env->me_psize * el[x].mcnt); + el[x].mptr = id3.mptr; + el[x].mcnt = id3.mcnt; + } else { + id3.mid = pg0; + pthread_mutex_unlock(&env->me_rpmutex); + goto found; + } + } + el[x].mref++; + pthread_mutex_unlock(&env->me_rpmutex); + goto found; + } + if (el[0].mid >= MDB_ERPAGE_MAX - env->me_rpcheck) { + /* purge unref'd pages */ + unsigned i, y = 0; + for (i=1; i<=el[0].mid; i++) { + if (!el[i].mref) { + if (!y) y = i; + munmap(el[i].mptr, env->me_psize * el[i].mcnt); + } + } + if (!y) { + if (retries) { + /* see if we can unref some local pages */ + retries--; + id3.mid = 0; + goto retry; + } + if (el[0].mid >= MDB_ERPAGE_MAX) { + pthread_mutex_unlock(&env->me_rpmutex); + return MDB_MAP_FULL; + } + env->me_rpcheck /= 2; + } else { + for (i=y+1; i<= el[0].mid; i++) + if (el[i].mref) + el[y++] = el[i]; + el[0].mid = y-1; + if (!env->me_rpcheck) + env->me_rpcheck = 1; + while (env->me_rpcheck < el[0].mid && env->me_rpcheck < MDB_ERPAGE_SIZE/2) + env->me_rpcheck *= 2; + } + } + SET_OFF(off, pgno * env->me_psize); + MAP(rc, env, id3.mptr, len, off); + if (rc) { +fail: + pthread_mutex_unlock(&env->me_rpmutex); + return rc; + } + /* check for overflow size */ + p = (MDB_page *)((char *)id3.mptr + rem * env->me_psize); + if (IS_OVERFLOW(p) && p->mp_pages + rem > id3.mcnt) { + id3.mcnt = p->mp_pages + rem; + munmap(id3.mptr, len); + len = id3.mcnt * env->me_psize; + MAP(rc, env, id3.mptr, len, off); + if (rc) + goto fail; + } + mdb_mid3l_insert(el, &id3); + pthread_mutex_unlock(&env->me_rpmutex); +found: + mdb_mid3l_insert(tl, &id3); + } else { + return MDB_TXN_FULL; + } +ok: + p = (MDB_page *)((char *)id3.mptr + rem * env->me_psize); +#if MDB_DEBUG /* we don't need this check any more */ + if (IS_OVERFLOW(p)) { + mdb_tassert(txn, p->mp_pages + rem <= id3.mcnt); + } +#endif + *ret = p; + return MDB_SUCCESS; +} +#endif + +/** Find the address of the page corresponding to a given page number. + * @param[in] mc the cursor accessing the page. + * @param[in] pgno the page number for the page to retrieve. + * @param[out] ret address of a pointer where the page's address will be stored. + * @param[out] lvl dirty_list inheritance level of found page. 1=current txn, 0=mapped page. + * @return 0 on success, non-zero on failure. + */ +static int +mdb_page_get(MDB_cursor *mc, pgno_t pgno, MDB_page **ret, int *lvl) +{ + MDB_txn *txn = mc->mc_txn; +#ifndef MDB_VL32 + MDB_env *env = txn->mt_env; +#endif + MDB_page *p = NULL; + int level; + + if (! (mc->mc_flags & (C_ORIG_RDONLY|C_WRITEMAP))) { + MDB_txn *tx2 = txn; + level = 1; + do { + MDB_ID2L dl = tx2->mt_u.dirty_list; + unsigned x; + /* Spilled pages were dirtied in this txn and flushed + * because the dirty list got full. Bring this page + * back in from the map (but don't unspill it here, + * leave that unless page_touch happens again). + */ + if (tx2->mt_spill_pgs) { + MDB_ID pn = pgno << 1; + x = mdb_midl_search(tx2->mt_spill_pgs, pn); + if (x <= tx2->mt_spill_pgs[0] && tx2->mt_spill_pgs[x] == pn) { +#ifdef MDB_VL32 + int rc = mdb_rpage_get(txn, pgno, &p); + if (rc) + return rc; +#else + p = (MDB_page *)(env->me_map + env->me_psize * pgno); +#endif + goto done; + } + } + if (dl[0].mid) { + unsigned x = mdb_mid2l_search(dl, pgno); + if (x <= dl[0].mid && dl[x].mid == pgno) { + p = dl[x].mptr; + goto done; + } + } + level++; + } while ((tx2 = tx2->mt_parent) != NULL); + } + + if (pgno < txn->mt_next_pgno) { + level = 0; +#ifdef MDB_VL32 + { + int rc = mdb_rpage_get(txn, pgno, &p); + if (rc) + return rc; + } +#else + p = (MDB_page *)(env->me_map + env->me_psize * pgno); +#endif + } else { + DPRINTF(("page %"Y"u not found", pgno)); + txn->mt_flags |= MDB_TXN_ERROR; + return MDB_PAGE_NOTFOUND; + } + +done: + *ret = p; + if (lvl) + *lvl = level; + return MDB_SUCCESS; +} + +/** Finish #mdb_page_search() / #mdb_page_search_lowest(). + * The cursor is at the root page, set up the rest of it. + */ +static int +mdb_page_search_root(MDB_cursor *mc, MDB_val *key, int flags) +{ + MDB_page *mp = mc->mc_pg[mc->mc_top]; + int rc; + DKBUF; + + while (IS_BRANCH(mp)) { + MDB_node *node; + indx_t i; + + DPRINTF(("branch page %"Y"u has %u keys", mp->mp_pgno, NUMKEYS(mp))); + /* Don't assert on branch pages in the FreeDB. We can get here + * while in the process of rebalancing a FreeDB branch page; we must + * let that proceed. ITS#8336 + */ + mdb_cassert(mc, !mc->mc_dbi || NUMKEYS(mp) > 1); + DPRINTF(("found index 0 to page %"Y"u", NODEPGNO(NODEPTR(mp, 0)))); + + if (flags & (MDB_PS_FIRST|MDB_PS_LAST)) { + i = 0; + if (flags & MDB_PS_LAST) + i = NUMKEYS(mp) - 1; + } else { + int exact; + node = mdb_node_search(mc, key, &exact); + if (node == NULL) + i = NUMKEYS(mp) - 1; + else { + i = mc->mc_ki[mc->mc_top]; + if (!exact) { + mdb_cassert(mc, i > 0); + i--; + } + } + DPRINTF(("following index %u for key [%s]", i, DKEY(key))); + } + + mdb_cassert(mc, i < NUMKEYS(mp)); + node = NODEPTR(mp, i); + + if ((rc = mdb_page_get(mc, NODEPGNO(node), &mp, NULL)) != 0) + return rc; + + mc->mc_ki[mc->mc_top] = i; + if ((rc = mdb_cursor_push(mc, mp))) + return rc; + + if (flags & MDB_PS_MODIFY) { + if ((rc = mdb_page_touch(mc)) != 0) + return rc; + mp = mc->mc_pg[mc->mc_top]; + } + } + + if (!IS_LEAF(mp)) { + DPRINTF(("internal error, index points to a %02X page!?", + mp->mp_flags)); + mc->mc_txn->mt_flags |= MDB_TXN_ERROR; + return MDB_CORRUPTED; + } + + DPRINTF(("found leaf page %"Y"u for key [%s]", mp->mp_pgno, + key ? DKEY(key) : "null")); + mc->mc_flags |= C_INITIALIZED; + mc->mc_flags &= ~C_EOF; + + return MDB_SUCCESS; +} + +/** Search for the lowest key under the current branch page. + * This just bypasses a NUMKEYS check in the current page + * before calling mdb_page_search_root(), because the callers + * are all in situations where the current page is known to + * be underfilled. + */ +static int +mdb_page_search_lowest(MDB_cursor *mc) +{ + MDB_page *mp = mc->mc_pg[mc->mc_top]; + MDB_node *node = NODEPTR(mp, 0); + int rc; + + if ((rc = mdb_page_get(mc, NODEPGNO(node), &mp, NULL)) != 0) + return rc; + + mc->mc_ki[mc->mc_top] = 0; + if ((rc = mdb_cursor_push(mc, mp))) + return rc; + return mdb_page_search_root(mc, NULL, MDB_PS_FIRST); +} + +/** Search for the page a given key should be in. + * Push it and its parent pages on the cursor stack. + * @param[in,out] mc the cursor for this operation. + * @param[in] key the key to search for, or NULL for first/last page. + * @param[in] flags If MDB_PS_MODIFY is set, visited pages in the DB + * are touched (updated with new page numbers). + * If MDB_PS_FIRST or MDB_PS_LAST is set, find first or last leaf. + * This is used by #mdb_cursor_first() and #mdb_cursor_last(). + * If MDB_PS_ROOTONLY set, just fetch root node, no further lookups. + * @return 0 on success, non-zero on failure. + */ +static int +mdb_page_search(MDB_cursor *mc, MDB_val *key, int flags) +{ + int rc; + pgno_t root; + + /* Make sure the txn is still viable, then find the root from + * the txn's db table and set it as the root of the cursor's stack. + */ + if (mc->mc_txn->mt_flags & MDB_TXN_BLOCKED) { + DPUTS("transaction may not be used now"); + return MDB_BAD_TXN; + } else { + /* Make sure we're using an up-to-date root */ + if (*mc->mc_dbflag & DB_STALE) { + MDB_cursor mc2; + if (TXN_DBI_CHANGED(mc->mc_txn, mc->mc_dbi)) + return MDB_BAD_DBI; + mdb_cursor_init(&mc2, mc->mc_txn, MAIN_DBI, NULL); + rc = mdb_page_search(&mc2, &mc->mc_dbx->md_name, 0); + if (rc) + return rc; + { + MDB_val data; + int exact = 0; + uint16_t flags; + MDB_node *leaf = mdb_node_search(&mc2, + &mc->mc_dbx->md_name, &exact); + if (!exact) + return MDB_NOTFOUND; + if ((leaf->mn_flags & (F_DUPDATA|F_SUBDATA)) != F_SUBDATA) + return MDB_INCOMPATIBLE; /* not a named DB */ + rc = mdb_node_read(&mc2, leaf, &data); + if (rc) + return rc; + memcpy(&flags, ((char *) data.mv_data + offsetof(MDB_db, md_flags)), + sizeof(uint16_t)); + /* The txn may not know this DBI, or another process may + * have dropped and recreated the DB with other flags. + */ + if ((mc->mc_db->md_flags & PERSISTENT_FLAGS) != flags) + return MDB_INCOMPATIBLE; + memcpy(mc->mc_db, data.mv_data, sizeof(MDB_db)); + } + *mc->mc_dbflag &= ~DB_STALE; + } + root = mc->mc_db->md_root; + + if (root == P_INVALID) { /* Tree is empty. */ + DPUTS("tree is empty"); + return MDB_NOTFOUND; + } + } + + mdb_cassert(mc, root > 1); + if (!mc->mc_pg[0] || mc->mc_pg[0]->mp_pgno != root) { +#ifdef MDB_VL32 + if (mc->mc_pg[0]) + MDB_PAGE_UNREF(mc->mc_txn, mc->mc_pg[0]); +#endif + if ((rc = mdb_page_get(mc, root, &mc->mc_pg[0], NULL)) != 0) + return rc; + } + +#ifdef MDB_VL32 + { + int i; + for (i=1; imc_snum; i++) + MDB_PAGE_UNREF(mc->mc_txn, mc->mc_pg[i]); + } +#endif + mc->mc_snum = 1; + mc->mc_top = 0; + + DPRINTF(("db %d root page %"Y"u has flags 0x%X", + DDBI(mc), root, mc->mc_pg[0]->mp_flags)); + + if (flags & MDB_PS_MODIFY) { + if ((rc = mdb_page_touch(mc))) + return rc; + } + + if (flags & MDB_PS_ROOTONLY) + return MDB_SUCCESS; + + return mdb_page_search_root(mc, key, flags); +} + +static int +mdb_ovpage_free(MDB_cursor *mc, MDB_page *mp) +{ + MDB_txn *txn = mc->mc_txn; + pgno_t pg = mp->mp_pgno; + unsigned x = 0, ovpages = mp->mp_pages; + MDB_env *env = txn->mt_env; + MDB_IDL sl = txn->mt_spill_pgs; + MDB_ID pn = pg << 1; + int rc; + + DPRINTF(("free ov page %"Y"u (%d)", pg, ovpages)); + /* If the page is dirty or on the spill list we just acquired it, + * so we should give it back to our current free list, if any. + * Otherwise put it onto the list of pages we freed in this txn. + * + * Won't create me_pghead: me_pglast must be inited along with it. + * Unsupported in nested txns: They would need to hide the page + * range in ancestor txns' dirty and spilled lists. + */ + if (env->me_pghead && + !txn->mt_parent && + ((mp->mp_flags & P_DIRTY) || + (sl && (x = mdb_midl_search(sl, pn)) <= sl[0] && sl[x] == pn))) + { + unsigned i, j; + pgno_t *mop; + MDB_ID2 *dl, ix, iy; + rc = mdb_midl_need(&env->me_pghead, ovpages); + if (rc) + return rc; + if (!(mp->mp_flags & P_DIRTY)) { + /* This page is no longer spilled */ + if (x == sl[0]) + sl[0]--; + else + sl[x] |= 1; + goto release; + } + /* Remove from dirty list */ + dl = txn->mt_u.dirty_list; + x = dl[0].mid--; + for (ix = dl[x]; ix.mptr != mp; ix = iy) { + if (x > 1) { + x--; + iy = dl[x]; + dl[x] = ix; + } else { + mdb_cassert(mc, x > 1); + j = ++(dl[0].mid); + dl[j] = ix; /* Unsorted. OK when MDB_TXN_ERROR. */ + txn->mt_flags |= MDB_TXN_ERROR; + return MDB_CORRUPTED; + } + } + txn->mt_dirty_room++; + if (!(env->me_flags & MDB_WRITEMAP)) + mdb_dpage_free(env, mp); +release: + /* Insert in me_pghead */ + mop = env->me_pghead; + j = mop[0] + ovpages; + for (i = mop[0]; i && mop[i] < pg; i--) + mop[j--] = mop[i]; + while (j>i) + mop[j--] = pg++; + mop[0] += ovpages; + } else { + rc = mdb_midl_append_range(&txn->mt_free_pgs, pg, ovpages); + if (rc) + return rc; + } +#ifdef MDB_VL32 + if (mc->mc_ovpg == mp) + mc->mc_ovpg = NULL; +#endif + mc->mc_db->md_overflow_pages -= ovpages; + return 0; +} + +/** Return the data associated with a given node. + * @param[in] mc The cursor for this operation. + * @param[in] leaf The node being read. + * @param[out] data Updated to point to the node's data. + * @return 0 on success, non-zero on failure. + */ +static int +mdb_node_read(MDB_cursor *mc, MDB_node *leaf, MDB_val *data) +{ + MDB_page *omp; /* overflow page */ + pgno_t pgno; + int rc; + +#ifdef MDB_VL32 + if (mc->mc_ovpg) { + MDB_PAGE_UNREF(mc->mc_txn, mc->mc_ovpg); + mc->mc_ovpg = 0; + } +#endif + if (!F_ISSET(leaf->mn_flags, F_BIGDATA)) { + data->mv_size = NODEDSZ(leaf); + data->mv_data = NODEDATA(leaf); + return MDB_SUCCESS; + } + + /* Read overflow data. + */ + data->mv_size = NODEDSZ(leaf); + memcpy(&pgno, NODEDATA(leaf), sizeof(pgno)); + if ((rc = mdb_page_get(mc, pgno, &omp, NULL)) != 0) { + DPRINTF(("read overflow page %"Y"u failed", pgno)); + return rc; + } + data->mv_data = METADATA(omp); +#ifdef MDB_VL32 + mc->mc_ovpg = omp; +#endif + + return MDB_SUCCESS; +} + +int +mdb_get(MDB_txn *txn, MDB_dbi dbi, + MDB_val *key, MDB_val *data) +{ + MDB_cursor mc; + MDB_xcursor mx; + int exact = 0, rc; + DKBUF; + + DPRINTF(("===> get db %u key [%s]", dbi, DKEY(key))); + + if (!key || !data || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) + return EINVAL; + + if (txn->mt_flags & MDB_TXN_BLOCKED) + return MDB_BAD_TXN; + + mdb_cursor_init(&mc, txn, dbi, &mx); + rc = mdb_cursor_set(&mc, key, data, MDB_SET, &exact); +#ifdef MDB_VL32 + { + /* unref all the pages - caller must copy the data + * before doing anything else + */ + mdb_cursor_unref(&mc); + } +#endif + return rc; +} + +/** Find a sibling for a page. + * Replaces the page at the top of the cursor's stack with the + * specified sibling, if one exists. + * @param[in] mc The cursor for this operation. + * @param[in] move_right Non-zero if the right sibling is requested, + * otherwise the left sibling. + * @return 0 on success, non-zero on failure. + */ +static int +mdb_cursor_sibling(MDB_cursor *mc, int move_right) +{ + int rc; + MDB_node *indx; + MDB_page *mp; +#ifdef MDB_VL32 + MDB_page *op; +#endif + + if (mc->mc_snum < 2) { + return MDB_NOTFOUND; /* root has no siblings */ + } + +#ifdef MDB_VL32 + op = mc->mc_pg[mc->mc_top]; +#endif + mdb_cursor_pop(mc); + DPRINTF(("parent page is page %"Y"u, index %u", + mc->mc_pg[mc->mc_top]->mp_pgno, mc->mc_ki[mc->mc_top])); + + if (move_right ? (mc->mc_ki[mc->mc_top] + 1u >= NUMKEYS(mc->mc_pg[mc->mc_top])) + : (mc->mc_ki[mc->mc_top] == 0)) { + DPRINTF(("no more keys left, moving to %s sibling", + move_right ? "right" : "left")); + if ((rc = mdb_cursor_sibling(mc, move_right)) != MDB_SUCCESS) { + /* undo cursor_pop before returning */ + mc->mc_top++; + mc->mc_snum++; + return rc; + } + } else { + if (move_right) + mc->mc_ki[mc->mc_top]++; + else + mc->mc_ki[mc->mc_top]--; + DPRINTF(("just moving to %s index key %u", + move_right ? "right" : "left", mc->mc_ki[mc->mc_top])); + } + mdb_cassert(mc, IS_BRANCH(mc->mc_pg[mc->mc_top])); + + MDB_PAGE_UNREF(mc->mc_txn, op); + + indx = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]); + if ((rc = mdb_page_get(mc, NODEPGNO(indx), &mp, NULL)) != 0) { + /* mc will be inconsistent if caller does mc_snum++ as above */ + mc->mc_flags &= ~(C_INITIALIZED|C_EOF); + return rc; + } + + mdb_cursor_push(mc, mp); + if (!move_right) + mc->mc_ki[mc->mc_top] = NUMKEYS(mp)-1; + + return MDB_SUCCESS; +} + +/** Move the cursor to the next data item. */ +static int +mdb_cursor_next(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op) +{ + MDB_page *mp; + MDB_node *leaf; + int rc; + + if (mc->mc_flags & C_EOF) { + return MDB_NOTFOUND; + } + + mdb_cassert(mc, mc->mc_flags & C_INITIALIZED); + + mp = mc->mc_pg[mc->mc_top]; + + if (mc->mc_db->md_flags & MDB_DUPSORT) { + leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]); + if (F_ISSET(leaf->mn_flags, F_DUPDATA)) { + if (op == MDB_NEXT || op == MDB_NEXT_DUP) { + rc = mdb_cursor_next(&mc->mc_xcursor->mx_cursor, data, NULL, MDB_NEXT); + if (op != MDB_NEXT || rc != MDB_NOTFOUND) { + if (rc == MDB_SUCCESS) + MDB_GET_KEY(leaf, key); + return rc; + } + } +#ifdef MDB_VL32 + else { + if (mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) { + mdb_cursor_unref(&mc->mc_xcursor->mx_cursor); + } + } +#endif + } else { + mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF); + if (op == MDB_NEXT_DUP) + return MDB_NOTFOUND; + } + } + + DPRINTF(("cursor_next: top page is %"Y"u in cursor %p", + mdb_dbg_pgno(mp), (void *) mc)); + if (mc->mc_flags & C_DEL) { + mc->mc_flags ^= C_DEL; + goto skip; + } + + if (mc->mc_ki[mc->mc_top] + 1u >= NUMKEYS(mp)) { + DPUTS("=====> move to next sibling page"); + if ((rc = mdb_cursor_sibling(mc, 1)) != MDB_SUCCESS) { + mc->mc_flags |= C_EOF; + return rc; + } + mp = mc->mc_pg[mc->mc_top]; + DPRINTF(("next page is %"Y"u, key index %u", mp->mp_pgno, mc->mc_ki[mc->mc_top])); + } else + mc->mc_ki[mc->mc_top]++; + +skip: + DPRINTF(("==> cursor points to page %"Y"u with %u keys, key index %u", + mdb_dbg_pgno(mp), NUMKEYS(mp), mc->mc_ki[mc->mc_top])); + + if (IS_LEAF2(mp)) { + key->mv_size = mc->mc_db->md_pad; + key->mv_data = LEAF2KEY(mp, mc->mc_ki[mc->mc_top], key->mv_size); + return MDB_SUCCESS; + } + + mdb_cassert(mc, IS_LEAF(mp)); + leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]); + + if (F_ISSET(leaf->mn_flags, F_DUPDATA)) { + mdb_xcursor_init1(mc, leaf); + } + if (data) { + if ((rc = mdb_node_read(mc, leaf, data)) != MDB_SUCCESS) + return rc; + + if (F_ISSET(leaf->mn_flags, F_DUPDATA)) { + rc = mdb_cursor_first(&mc->mc_xcursor->mx_cursor, data, NULL); + if (rc != MDB_SUCCESS) + return rc; + } + } + + MDB_GET_KEY(leaf, key); + return MDB_SUCCESS; +} + +/** Move the cursor to the previous data item. */ +static int +mdb_cursor_prev(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op) +{ + MDB_page *mp; + MDB_node *leaf; + int rc; + + mdb_cassert(mc, mc->mc_flags & C_INITIALIZED); + + mp = mc->mc_pg[mc->mc_top]; + + if (mc->mc_db->md_flags & MDB_DUPSORT) { + leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]); + if (F_ISSET(leaf->mn_flags, F_DUPDATA)) { + if (op == MDB_PREV || op == MDB_PREV_DUP) { + rc = mdb_cursor_prev(&mc->mc_xcursor->mx_cursor, data, NULL, MDB_PREV); + if (op != MDB_PREV || rc != MDB_NOTFOUND) { + if (rc == MDB_SUCCESS) { + MDB_GET_KEY(leaf, key); + mc->mc_flags &= ~C_EOF; + } + return rc; + } + } +#ifdef MDB_VL32 + else { + if (mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) { + mdb_cursor_unref(&mc->mc_xcursor->mx_cursor); + } + } +#endif + } else { + mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF); + if (op == MDB_PREV_DUP) + return MDB_NOTFOUND; + } + } + + DPRINTF(("cursor_prev: top page is %"Y"u in cursor %p", + mdb_dbg_pgno(mp), (void *) mc)); + + mc->mc_flags &= ~(C_EOF|C_DEL); + + if (mc->mc_ki[mc->mc_top] == 0) { + DPUTS("=====> move to prev sibling page"); + if ((rc = mdb_cursor_sibling(mc, 0)) != MDB_SUCCESS) { + return rc; + } + mp = mc->mc_pg[mc->mc_top]; + mc->mc_ki[mc->mc_top] = NUMKEYS(mp) - 1; + DPRINTF(("prev page is %"Y"u, key index %u", mp->mp_pgno, mc->mc_ki[mc->mc_top])); + } else + mc->mc_ki[mc->mc_top]--; + + mc->mc_flags &= ~C_EOF; + + DPRINTF(("==> cursor points to page %"Y"u with %u keys, key index %u", + mdb_dbg_pgno(mp), NUMKEYS(mp), mc->mc_ki[mc->mc_top])); + + if (IS_LEAF2(mp)) { + key->mv_size = mc->mc_db->md_pad; + key->mv_data = LEAF2KEY(mp, mc->mc_ki[mc->mc_top], key->mv_size); + return MDB_SUCCESS; + } + + mdb_cassert(mc, IS_LEAF(mp)); + leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]); + + if (F_ISSET(leaf->mn_flags, F_DUPDATA)) { + mdb_xcursor_init1(mc, leaf); + } + if (data) { + if ((rc = mdb_node_read(mc, leaf, data)) != MDB_SUCCESS) + return rc; + + if (F_ISSET(leaf->mn_flags, F_DUPDATA)) { + rc = mdb_cursor_last(&mc->mc_xcursor->mx_cursor, data, NULL); + if (rc != MDB_SUCCESS) + return rc; + } + } + + MDB_GET_KEY(leaf, key); + return MDB_SUCCESS; +} + +/** Set the cursor on a specific data item. */ +static int +mdb_cursor_set(MDB_cursor *mc, MDB_val *key, MDB_val *data, + MDB_cursor_op op, int *exactp) +{ + int rc; + MDB_page *mp; + MDB_node *leaf = NULL; + DKBUF; + + if (key->mv_size == 0) + return MDB_BAD_VALSIZE; + + if (mc->mc_xcursor) { +#ifdef MDB_VL32 + if (mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) { + mdb_cursor_unref(&mc->mc_xcursor->mx_cursor); + } +#endif + mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF); + } + + /* See if we're already on the right page */ + if (mc->mc_flags & C_INITIALIZED) { + MDB_val nodekey; + + mp = mc->mc_pg[mc->mc_top]; + if (!NUMKEYS(mp)) { + mc->mc_ki[mc->mc_top] = 0; + return MDB_NOTFOUND; + } + if (mp->mp_flags & P_LEAF2) { + nodekey.mv_size = mc->mc_db->md_pad; + nodekey.mv_data = LEAF2KEY(mp, 0, nodekey.mv_size); + } else { + leaf = NODEPTR(mp, 0); + MDB_GET_KEY2(leaf, nodekey); + } + rc = mc->mc_dbx->md_cmp(key, &nodekey); + if (rc == 0) { + /* Probably happens rarely, but first node on the page + * was the one we wanted. + */ + mc->mc_ki[mc->mc_top] = 0; + if (exactp) + *exactp = 1; + goto set1; + } + if (rc > 0) { + unsigned int i; + unsigned int nkeys = NUMKEYS(mp); + if (nkeys > 1) { + if (mp->mp_flags & P_LEAF2) { + nodekey.mv_data = LEAF2KEY(mp, + nkeys-1, nodekey.mv_size); + } else { + leaf = NODEPTR(mp, nkeys-1); + MDB_GET_KEY2(leaf, nodekey); + } + rc = mc->mc_dbx->md_cmp(key, &nodekey); + if (rc == 0) { + /* last node was the one we wanted */ + mc->mc_ki[mc->mc_top] = nkeys-1; + if (exactp) + *exactp = 1; + goto set1; + } + if (rc < 0) { + if (mc->mc_ki[mc->mc_top] < NUMKEYS(mp)) { + /* This is definitely the right page, skip search_page */ + if (mp->mp_flags & P_LEAF2) { + nodekey.mv_data = LEAF2KEY(mp, + mc->mc_ki[mc->mc_top], nodekey.mv_size); + } else { + leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]); + MDB_GET_KEY2(leaf, nodekey); + } + rc = mc->mc_dbx->md_cmp(key, &nodekey); + if (rc == 0) { + /* current node was the one we wanted */ + if (exactp) + *exactp = 1; + goto set1; + } + } + rc = 0; + goto set2; + } + } + /* If any parents have right-sibs, search. + * Otherwise, there's nothing further. + */ + for (i=0; imc_top; i++) + if (mc->mc_ki[i] < + NUMKEYS(mc->mc_pg[i])-1) + break; + if (i == mc->mc_top) { + /* There are no other pages */ + mc->mc_ki[mc->mc_top] = nkeys; + return MDB_NOTFOUND; + } + } + if (!mc->mc_top) { + /* There are no other pages */ + mc->mc_ki[mc->mc_top] = 0; + if (op == MDB_SET_RANGE && !exactp) { + rc = 0; + goto set1; + } else + return MDB_NOTFOUND; + } + } else { + mc->mc_pg[0] = 0; + } + + rc = mdb_page_search(mc, key, 0); + if (rc != MDB_SUCCESS) + return rc; + + mp = mc->mc_pg[mc->mc_top]; + mdb_cassert(mc, IS_LEAF(mp)); + +set2: + leaf = mdb_node_search(mc, key, exactp); + if (exactp != NULL && !*exactp) { + /* MDB_SET specified and not an exact match. */ + return MDB_NOTFOUND; + } + + if (leaf == NULL) { + DPUTS("===> inexact leaf not found, goto sibling"); + if ((rc = mdb_cursor_sibling(mc, 1)) != MDB_SUCCESS) { + mc->mc_flags |= C_EOF; + return rc; /* no entries matched */ + } + mp = mc->mc_pg[mc->mc_top]; + mdb_cassert(mc, IS_LEAF(mp)); + leaf = NODEPTR(mp, 0); + } + +set1: + mc->mc_flags |= C_INITIALIZED; + mc->mc_flags &= ~C_EOF; + + if (IS_LEAF2(mp)) { + if (op == MDB_SET_RANGE || op == MDB_SET_KEY) { + key->mv_size = mc->mc_db->md_pad; + key->mv_data = LEAF2KEY(mp, mc->mc_ki[mc->mc_top], key->mv_size); + } + return MDB_SUCCESS; + } + + if (F_ISSET(leaf->mn_flags, F_DUPDATA)) { + mdb_xcursor_init1(mc, leaf); + } + if (data) { + if (F_ISSET(leaf->mn_flags, F_DUPDATA)) { + if (op == MDB_SET || op == MDB_SET_KEY || op == MDB_SET_RANGE) { + rc = mdb_cursor_first(&mc->mc_xcursor->mx_cursor, data, NULL); + } else { + int ex2, *ex2p; + if (op == MDB_GET_BOTH) { + ex2p = &ex2; + ex2 = 0; + } else { + ex2p = NULL; + } + rc = mdb_cursor_set(&mc->mc_xcursor->mx_cursor, data, NULL, MDB_SET_RANGE, ex2p); + if (rc != MDB_SUCCESS) + return rc; + } + } else if (op == MDB_GET_BOTH || op == MDB_GET_BOTH_RANGE) { + MDB_val olddata; + MDB_cmp_func *dcmp; + if ((rc = mdb_node_read(mc, leaf, &olddata)) != MDB_SUCCESS) + return rc; + dcmp = mc->mc_dbx->md_dcmp; +#if UINT_MAX < SIZE_MAX || defined(MDB_VL32) + if (dcmp == mdb_cmp_int && olddata.mv_size == sizeof(mdb_size_t)) + dcmp = mdb_cmp_clong; +#endif + rc = dcmp(data, &olddata); + if (rc) { + if (op == MDB_GET_BOTH || rc > 0) + return MDB_NOTFOUND; + rc = 0; + } + *data = olddata; + + } else { + if (mc->mc_xcursor) + mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF); + if ((rc = mdb_node_read(mc, leaf, data)) != MDB_SUCCESS) + return rc; + } + } + + /* The key already matches in all other cases */ + if (op == MDB_SET_RANGE || op == MDB_SET_KEY) + MDB_GET_KEY(leaf, key); + DPRINTF(("==> cursor placed on key [%s]", DKEY(key))); + + return rc; +} + +/** Move the cursor to the first item in the database. */ +static int +mdb_cursor_first(MDB_cursor *mc, MDB_val *key, MDB_val *data) +{ + int rc; + MDB_node *leaf; + + if (mc->mc_xcursor) { +#ifdef MDB_VL32 + if (mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) { + mdb_cursor_unref(&mc->mc_xcursor->mx_cursor); + } +#endif + mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF); + } + + if (!(mc->mc_flags & C_INITIALIZED) || mc->mc_top) { + rc = mdb_page_search(mc, NULL, MDB_PS_FIRST); + if (rc != MDB_SUCCESS) + return rc; + } + mdb_cassert(mc, IS_LEAF(mc->mc_pg[mc->mc_top])); + + leaf = NODEPTR(mc->mc_pg[mc->mc_top], 0); + mc->mc_flags |= C_INITIALIZED; + mc->mc_flags &= ~C_EOF; + + mc->mc_ki[mc->mc_top] = 0; + + if (IS_LEAF2(mc->mc_pg[mc->mc_top])) { + key->mv_size = mc->mc_db->md_pad; + key->mv_data = LEAF2KEY(mc->mc_pg[mc->mc_top], 0, key->mv_size); + return MDB_SUCCESS; + } + + if (data) { + if (F_ISSET(leaf->mn_flags, F_DUPDATA)) { + mdb_xcursor_init1(mc, leaf); + rc = mdb_cursor_first(&mc->mc_xcursor->mx_cursor, data, NULL); + if (rc) + return rc; + } else { + if ((rc = mdb_node_read(mc, leaf, data)) != MDB_SUCCESS) + return rc; + } + } + MDB_GET_KEY(leaf, key); + return MDB_SUCCESS; +} + +/** Move the cursor to the last item in the database. */ +static int +mdb_cursor_last(MDB_cursor *mc, MDB_val *key, MDB_val *data) +{ + int rc; + MDB_node *leaf; + + if (mc->mc_xcursor) { +#ifdef MDB_VL32 + if (mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) { + mdb_cursor_unref(&mc->mc_xcursor->mx_cursor); + } +#endif + mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF); + } + + if (!(mc->mc_flags & C_EOF)) { + + if (!(mc->mc_flags & C_INITIALIZED) || mc->mc_top) { + rc = mdb_page_search(mc, NULL, MDB_PS_LAST); + if (rc != MDB_SUCCESS) + return rc; + } + mdb_cassert(mc, IS_LEAF(mc->mc_pg[mc->mc_top])); + + } + mc->mc_ki[mc->mc_top] = NUMKEYS(mc->mc_pg[mc->mc_top]) - 1; + mc->mc_flags |= C_INITIALIZED|C_EOF; + leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]); + + if (IS_LEAF2(mc->mc_pg[mc->mc_top])) { + key->mv_size = mc->mc_db->md_pad; + key->mv_data = LEAF2KEY(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top], key->mv_size); + return MDB_SUCCESS; + } + + if (data) { + if (F_ISSET(leaf->mn_flags, F_DUPDATA)) { + mdb_xcursor_init1(mc, leaf); + rc = mdb_cursor_last(&mc->mc_xcursor->mx_cursor, data, NULL); + if (rc) + return rc; + } else { + if ((rc = mdb_node_read(mc, leaf, data)) != MDB_SUCCESS) + return rc; + } + } + + MDB_GET_KEY(leaf, key); + return MDB_SUCCESS; +} + +int +mdb_cursor_get(MDB_cursor *mc, MDB_val *key, MDB_val *data, + MDB_cursor_op op) +{ + int rc; + int exact = 0; + int (*mfunc)(MDB_cursor *mc, MDB_val *key, MDB_val *data); + + if (mc == NULL) + return EINVAL; + + if (mc->mc_txn->mt_flags & MDB_TXN_BLOCKED) + return MDB_BAD_TXN; + + switch (op) { + case MDB_GET_CURRENT: + if (!(mc->mc_flags & C_INITIALIZED)) { + rc = EINVAL; + } else { + MDB_page *mp = mc->mc_pg[mc->mc_top]; + int nkeys = NUMKEYS(mp); + if (!nkeys || mc->mc_ki[mc->mc_top] >= nkeys) { + mc->mc_ki[mc->mc_top] = nkeys; + rc = MDB_NOTFOUND; + break; + } + rc = MDB_SUCCESS; + if (IS_LEAF2(mp)) { + key->mv_size = mc->mc_db->md_pad; + key->mv_data = LEAF2KEY(mp, mc->mc_ki[mc->mc_top], key->mv_size); + } else { + MDB_node *leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]); + MDB_GET_KEY(leaf, key); + if (data) { + if (F_ISSET(leaf->mn_flags, F_DUPDATA)) { + rc = mdb_cursor_get(&mc->mc_xcursor->mx_cursor, data, NULL, MDB_GET_CURRENT); + } else { + rc = mdb_node_read(mc, leaf, data); + } + } + } + } + break; + case MDB_GET_BOTH: + case MDB_GET_BOTH_RANGE: + if (data == NULL) { + rc = EINVAL; + break; + } + if (mc->mc_xcursor == NULL) { + rc = MDB_INCOMPATIBLE; + break; + } + /* FALLTHRU */ + case MDB_SET: + case MDB_SET_KEY: + case MDB_SET_RANGE: + if (key == NULL) { + rc = EINVAL; + } else { + rc = mdb_cursor_set(mc, key, data, op, + op == MDB_SET_RANGE ? NULL : &exact); + } + break; + case MDB_GET_MULTIPLE: + if (data == NULL || !(mc->mc_flags & C_INITIALIZED)) { + rc = EINVAL; + break; + } + if (!(mc->mc_db->md_flags & MDB_DUPFIXED)) { + rc = MDB_INCOMPATIBLE; + break; + } + rc = MDB_SUCCESS; + if (!(mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) || + (mc->mc_xcursor->mx_cursor.mc_flags & C_EOF)) + break; + goto fetchm; + case MDB_NEXT_MULTIPLE: + if (data == NULL) { + rc = EINVAL; + break; + } + if (!(mc->mc_db->md_flags & MDB_DUPFIXED)) { + rc = MDB_INCOMPATIBLE; + break; + } + if (!(mc->mc_flags & C_INITIALIZED)) + rc = mdb_cursor_first(mc, key, data); + else + rc = mdb_cursor_next(mc, key, data, MDB_NEXT_DUP); + if (rc == MDB_SUCCESS) { + if (mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) { + MDB_cursor *mx; +fetchm: + mx = &mc->mc_xcursor->mx_cursor; + data->mv_size = NUMKEYS(mx->mc_pg[mx->mc_top]) * + mx->mc_db->md_pad; + data->mv_data = METADATA(mx->mc_pg[mx->mc_top]); + mx->mc_ki[mx->mc_top] = NUMKEYS(mx->mc_pg[mx->mc_top])-1; + } else { + rc = MDB_NOTFOUND; + } + } + break; + case MDB_PREV_MULTIPLE: + if (data == NULL) { + rc = EINVAL; + break; + } + if (!(mc->mc_db->md_flags & MDB_DUPFIXED)) { + rc = MDB_INCOMPATIBLE; + break; + } + if (!(mc->mc_flags & C_INITIALIZED)) + rc = mdb_cursor_last(mc, key, data); + else + rc = MDB_SUCCESS; + if (rc == MDB_SUCCESS) { + MDB_cursor *mx = &mc->mc_xcursor->mx_cursor; + if (mx->mc_flags & C_INITIALIZED) { + rc = mdb_cursor_sibling(mx, 0); + if (rc == MDB_SUCCESS) + goto fetchm; + } else { + rc = MDB_NOTFOUND; + } + } + break; + case MDB_NEXT: + case MDB_NEXT_DUP: + case MDB_NEXT_NODUP: + if (!(mc->mc_flags & C_INITIALIZED)) + rc = mdb_cursor_first(mc, key, data); + else + rc = mdb_cursor_next(mc, key, data, op); + break; + case MDB_PREV: + case MDB_PREV_DUP: + case MDB_PREV_NODUP: + if (!(mc->mc_flags & C_INITIALIZED)) { + rc = mdb_cursor_last(mc, key, data); + if (rc) + break; + mc->mc_flags |= C_INITIALIZED; + mc->mc_ki[mc->mc_top]++; + } + rc = mdb_cursor_prev(mc, key, data, op); + break; + case MDB_FIRST: + rc = mdb_cursor_first(mc, key, data); + break; + case MDB_FIRST_DUP: + mfunc = mdb_cursor_first; + mmove: + if (data == NULL || !(mc->mc_flags & C_INITIALIZED)) { + rc = EINVAL; + break; + } + if (mc->mc_xcursor == NULL) { + rc = MDB_INCOMPATIBLE; + break; + } + { + MDB_node *leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]); + if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) { + MDB_GET_KEY(leaf, key); + rc = mdb_node_read(mc, leaf, data); + break; + } + } + if (!(mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED)) { + rc = EINVAL; + break; + } + rc = mfunc(&mc->mc_xcursor->mx_cursor, data, NULL); + break; + case MDB_LAST: + rc = mdb_cursor_last(mc, key, data); + break; + case MDB_LAST_DUP: + mfunc = mdb_cursor_last; + goto mmove; + default: + DPRINTF(("unhandled/unimplemented cursor operation %u", op)); + rc = EINVAL; + break; + } + + if (mc->mc_flags & C_DEL) + mc->mc_flags ^= C_DEL; + + return rc; +} + +/** Touch all the pages in the cursor stack. Set mc_top. + * Makes sure all the pages are writable, before attempting a write operation. + * @param[in] mc The cursor to operate on. + */ +static int +mdb_cursor_touch(MDB_cursor *mc) +{ + int rc = MDB_SUCCESS; + + if (mc->mc_dbi >= CORE_DBS && !(*mc->mc_dbflag & DB_DIRTY)) { + MDB_cursor mc2; + MDB_xcursor mcx; + if (TXN_DBI_CHANGED(mc->mc_txn, mc->mc_dbi)) + return MDB_BAD_DBI; + mdb_cursor_init(&mc2, mc->mc_txn, MAIN_DBI, &mcx); + rc = mdb_page_search(&mc2, &mc->mc_dbx->md_name, MDB_PS_MODIFY); + if (rc) + return rc; + *mc->mc_dbflag |= DB_DIRTY; + } + mc->mc_top = 0; + if (mc->mc_snum) { + do { + rc = mdb_page_touch(mc); + } while (!rc && ++(mc->mc_top) < mc->mc_snum); + mc->mc_top = mc->mc_snum-1; + } + return rc; +} + +/** Do not spill pages to disk if txn is getting full, may fail instead */ +#define MDB_NOSPILL 0x8000 + +int +mdb_cursor_put(MDB_cursor *mc, MDB_val *key, MDB_val *data, + unsigned int flags) +{ + MDB_env *env; + MDB_node *leaf = NULL; + MDB_page *fp, *mp, *sub_root = NULL; + uint16_t fp_flags; + MDB_val xdata, *rdata, dkey, olddata; + MDB_db dummy; + int do_sub = 0, insert_key, insert_data; + unsigned int mcount = 0, dcount = 0, nospill; + size_t nsize; + int rc, rc2; + unsigned int nflags; + DKBUF; + + if (mc == NULL || key == NULL) + return EINVAL; + + env = mc->mc_txn->mt_env; + + /* Check this first so counter will always be zero on any + * early failures. + */ + if (flags & MDB_MULTIPLE) { + dcount = data[1].mv_size; + data[1].mv_size = 0; + if (!F_ISSET(mc->mc_db->md_flags, MDB_DUPFIXED)) + return MDB_INCOMPATIBLE; + } + + nospill = flags & MDB_NOSPILL; + flags &= ~MDB_NOSPILL; + + if (mc->mc_txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_BLOCKED)) + return (mc->mc_txn->mt_flags & MDB_TXN_RDONLY) ? EACCES : MDB_BAD_TXN; + + if (key->mv_size-1 >= ENV_MAXKEY(env)) + return MDB_BAD_VALSIZE; + +#if SIZE_MAX > MAXDATASIZE + if (data->mv_size > ((mc->mc_db->md_flags & MDB_DUPSORT) ? ENV_MAXKEY(env) : MAXDATASIZE)) + return MDB_BAD_VALSIZE; +#else + if ((mc->mc_db->md_flags & MDB_DUPSORT) && data->mv_size > ENV_MAXKEY(env)) + return MDB_BAD_VALSIZE; +#endif + + DPRINTF(("==> put db %d key [%s], size %"Z"u, data size %"Z"u", + DDBI(mc), DKEY(key), key ? key->mv_size : 0, data->mv_size)); + + dkey.mv_size = 0; + + if (flags == MDB_CURRENT) { + if (!(mc->mc_flags & C_INITIALIZED)) + return EINVAL; + rc = MDB_SUCCESS; + } else if (mc->mc_db->md_root == P_INVALID) { + /* new database, cursor has nothing to point to */ + mc->mc_snum = 0; + mc->mc_top = 0; + mc->mc_flags &= ~C_INITIALIZED; + rc = MDB_NO_ROOT; + } else { + int exact = 0; + MDB_val d2; + if (flags & MDB_APPEND) { + MDB_val k2; + rc = mdb_cursor_last(mc, &k2, &d2); + if (rc == 0) { + rc = mc->mc_dbx->md_cmp(key, &k2); + if (rc > 0) { + rc = MDB_NOTFOUND; + mc->mc_ki[mc->mc_top]++; + } else { + /* new key is <= last key */ + rc = MDB_KEYEXIST; + } + } + } else { + rc = mdb_cursor_set(mc, key, &d2, MDB_SET, &exact); + } + if ((flags & MDB_NOOVERWRITE) && rc == 0) { + DPRINTF(("duplicate key [%s]", DKEY(key))); + *data = d2; + return MDB_KEYEXIST; + } + if (rc && rc != MDB_NOTFOUND) + return rc; + } + + if (mc->mc_flags & C_DEL) + mc->mc_flags ^= C_DEL; + + /* Cursor is positioned, check for room in the dirty list */ + if (!nospill) { + if (flags & MDB_MULTIPLE) { + rdata = &xdata; + xdata.mv_size = data->mv_size * dcount; + } else { + rdata = data; + } + if ((rc2 = mdb_page_spill(mc, key, rdata))) + return rc2; + } + + if (rc == MDB_NO_ROOT) { + MDB_page *np; + /* new database, write a root leaf page */ + DPUTS("allocating new root leaf page"); + if ((rc2 = mdb_page_new(mc, P_LEAF, 1, &np))) { + return rc2; + } + mdb_cursor_push(mc, np); + mc->mc_db->md_root = np->mp_pgno; + mc->mc_db->md_depth++; + *mc->mc_dbflag |= DB_DIRTY; + if ((mc->mc_db->md_flags & (MDB_DUPSORT|MDB_DUPFIXED)) + == MDB_DUPFIXED) + np->mp_flags |= P_LEAF2; + mc->mc_flags |= C_INITIALIZED; + } else { + /* make sure all cursor pages are writable */ + rc2 = mdb_cursor_touch(mc); + if (rc2) + return rc2; + } + + insert_key = insert_data = rc; + if (insert_key) { + /* The key does not exist */ + DPRINTF(("inserting key at index %i", mc->mc_ki[mc->mc_top])); + if ((mc->mc_db->md_flags & MDB_DUPSORT) && + LEAFSIZE(key, data) > env->me_nodemax) + { + /* Too big for a node, insert in sub-DB. Set up an empty + * "old sub-page" for prep_subDB to expand to a full page. + */ + fp_flags = P_LEAF|P_DIRTY; + fp = env->me_pbuf; + fp->mp_pad = data->mv_size; /* used if MDB_DUPFIXED */ + fp->mp_lower = fp->mp_upper = (PAGEHDRSZ-PAGEBASE); + olddata.mv_size = PAGEHDRSZ; + goto prep_subDB; + } + } else { + /* there's only a key anyway, so this is a no-op */ + if (IS_LEAF2(mc->mc_pg[mc->mc_top])) { + char *ptr; + unsigned int ksize = mc->mc_db->md_pad; + if (key->mv_size != ksize) + return MDB_BAD_VALSIZE; + ptr = LEAF2KEY(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top], ksize); + memcpy(ptr, key->mv_data, ksize); +fix_parent: + /* if overwriting slot 0 of leaf, need to + * update branch key if there is a parent page + */ + if (mc->mc_top && !mc->mc_ki[mc->mc_top]) { + unsigned short dtop = 1; + mc->mc_top--; + /* slot 0 is always an empty key, find real slot */ + while (mc->mc_top && !mc->mc_ki[mc->mc_top]) { + mc->mc_top--; + dtop++; + } + if (mc->mc_ki[mc->mc_top]) + rc2 = mdb_update_key(mc, key); + else + rc2 = MDB_SUCCESS; + mc->mc_top += dtop; + if (rc2) + return rc2; + } + return MDB_SUCCESS; + } + +more: + leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]); + olddata.mv_size = NODEDSZ(leaf); + olddata.mv_data = NODEDATA(leaf); + + /* DB has dups? */ + if (F_ISSET(mc->mc_db->md_flags, MDB_DUPSORT)) { + /* Prepare (sub-)page/sub-DB to accept the new item, + * if needed. fp: old sub-page or a header faking + * it. mp: new (sub-)page. offset: growth in page + * size. xdata: node data with new page or DB. + */ + unsigned i, offset = 0; + mp = fp = xdata.mv_data = env->me_pbuf; + mp->mp_pgno = mc->mc_pg[mc->mc_top]->mp_pgno; + + /* Was a single item before, must convert now */ + if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) { + MDB_cmp_func *dcmp; + /* Just overwrite the current item */ + if (flags == MDB_CURRENT) + goto current; + dcmp = mc->mc_dbx->md_dcmp; +#if UINT_MAX < SIZE_MAX || defined(MDB_VL32) + if (dcmp == mdb_cmp_int && olddata.mv_size == sizeof(mdb_size_t)) + dcmp = mdb_cmp_clong; +#endif + /* does data match? */ + if (!dcmp(data, &olddata)) { + if (flags & (MDB_NODUPDATA|MDB_APPENDDUP)) + return MDB_KEYEXIST; + /* overwrite it */ + goto current; + } + + /* Back up original data item */ + dkey.mv_size = olddata.mv_size; + dkey.mv_data = memcpy(fp+1, olddata.mv_data, olddata.mv_size); + + /* Make sub-page header for the dup items, with dummy body */ + fp->mp_flags = P_LEAF|P_DIRTY|P_SUBP; + fp->mp_lower = (PAGEHDRSZ-PAGEBASE); + xdata.mv_size = PAGEHDRSZ + dkey.mv_size + data->mv_size; + if (mc->mc_db->md_flags & MDB_DUPFIXED) { + fp->mp_flags |= P_LEAF2; + fp->mp_pad = data->mv_size; + xdata.mv_size += 2 * data->mv_size; /* leave space for 2 more */ + } else { + xdata.mv_size += 2 * (sizeof(indx_t) + NODESIZE) + + (dkey.mv_size & 1) + (data->mv_size & 1); + } + fp->mp_upper = xdata.mv_size - PAGEBASE; + olddata.mv_size = xdata.mv_size; /* pretend olddata is fp */ + } else if (leaf->mn_flags & F_SUBDATA) { + /* Data is on sub-DB, just store it */ + flags |= F_DUPDATA|F_SUBDATA; + goto put_sub; + } else { + /* Data is on sub-page */ + fp = olddata.mv_data; + switch (flags) { + default: + if (!(mc->mc_db->md_flags & MDB_DUPFIXED)) { + offset = EVEN(NODESIZE + sizeof(indx_t) + + data->mv_size); + break; + } + offset = fp->mp_pad; + if (SIZELEFT(fp) < offset) { + offset *= 4; /* space for 4 more */ + break; + } + /* FALLTHRU: Big enough MDB_DUPFIXED sub-page */ + case MDB_CURRENT: + fp->mp_flags |= P_DIRTY; + COPY_PGNO(fp->mp_pgno, mp->mp_pgno); + mc->mc_xcursor->mx_cursor.mc_pg[0] = fp; + flags |= F_DUPDATA; + goto put_sub; + } + xdata.mv_size = olddata.mv_size + offset; + } + + fp_flags = fp->mp_flags; + if (NODESIZE + NODEKSZ(leaf) + xdata.mv_size > env->me_nodemax) { + /* Too big for a sub-page, convert to sub-DB */ + fp_flags &= ~P_SUBP; +prep_subDB: + if (mc->mc_db->md_flags & MDB_DUPFIXED) { + fp_flags |= P_LEAF2; + dummy.md_pad = fp->mp_pad; + dummy.md_flags = MDB_DUPFIXED; + if (mc->mc_db->md_flags & MDB_INTEGERDUP) + dummy.md_flags |= MDB_INTEGERKEY; + } else { + dummy.md_pad = 0; + dummy.md_flags = 0; + } + dummy.md_depth = 1; + dummy.md_branch_pages = 0; + dummy.md_leaf_pages = 1; + dummy.md_overflow_pages = 0; + dummy.md_entries = NUMKEYS(fp); + xdata.mv_size = sizeof(MDB_db); + xdata.mv_data = &dummy; + if ((rc = mdb_page_alloc(mc, 1, &mp))) + return rc; + offset = env->me_psize - olddata.mv_size; + flags |= F_DUPDATA|F_SUBDATA; + dummy.md_root = mp->mp_pgno; + sub_root = mp; + } + if (mp != fp) { + mp->mp_flags = fp_flags | P_DIRTY; + mp->mp_pad = fp->mp_pad; + mp->mp_lower = fp->mp_lower; + mp->mp_upper = fp->mp_upper + offset; + if (fp_flags & P_LEAF2) { + memcpy(METADATA(mp), METADATA(fp), NUMKEYS(fp) * fp->mp_pad); + } else { + memcpy((char *)mp + mp->mp_upper + PAGEBASE, (char *)fp + fp->mp_upper + PAGEBASE, + olddata.mv_size - fp->mp_upper - PAGEBASE); + for (i=0; imp_ptrs[i] = fp->mp_ptrs[i] + offset; + } + } + + rdata = &xdata; + flags |= F_DUPDATA; + do_sub = 1; + if (!insert_key) + mdb_node_del(mc, 0); + goto new_sub; + } +current: + /* LMDB passes F_SUBDATA in 'flags' to write a DB record */ + if ((leaf->mn_flags ^ flags) & F_SUBDATA) + return MDB_INCOMPATIBLE; + /* overflow page overwrites need special handling */ + if (F_ISSET(leaf->mn_flags, F_BIGDATA)) { + MDB_page *omp; + pgno_t pg; + int level, ovpages, dpages = OVPAGES(data->mv_size, env->me_psize); + + memcpy(&pg, olddata.mv_data, sizeof(pg)); + if ((rc2 = mdb_page_get(mc, pg, &omp, &level)) != 0) + return rc2; + ovpages = omp->mp_pages; + + /* Is the ov page large enough? */ + if (ovpages >= dpages) { + if (!(omp->mp_flags & P_DIRTY) && + (level || (env->me_flags & MDB_WRITEMAP))) + { + rc = mdb_page_unspill(mc->mc_txn, omp, &omp); + if (rc) + return rc; + level = 0; /* dirty in this txn or clean */ + } + /* Is it dirty? */ + if (omp->mp_flags & P_DIRTY) { + /* yes, overwrite it. Note in this case we don't + * bother to try shrinking the page if the new data + * is smaller than the overflow threshold. + */ + if (level > 1) { + /* It is writable only in a parent txn */ + size_t sz = (size_t) env->me_psize * ovpages, off; + MDB_page *np = mdb_page_malloc(mc->mc_txn, ovpages); + MDB_ID2 id2; + if (!np) + return ENOMEM; + id2.mid = pg; + id2.mptr = np; + /* Note - this page is already counted in parent's dirty_room */ + rc2 = mdb_mid2l_insert(mc->mc_txn->mt_u.dirty_list, &id2); + mdb_cassert(mc, rc2 == 0); + if (!(flags & MDB_RESERVE)) { + /* Copy end of page, adjusting alignment so + * compiler may copy words instead of bytes. + */ + off = (PAGEHDRSZ + data->mv_size) & -sizeof(size_t); + memcpy((size_t *)((char *)np + off), + (size_t *)((char *)omp + off), sz - off); + sz = PAGEHDRSZ; + } + memcpy(np, omp, sz); /* Copy beginning of page */ + omp = np; + } + SETDSZ(leaf, data->mv_size); + if (F_ISSET(flags, MDB_RESERVE)) + data->mv_data = METADATA(omp); + else + memcpy(METADATA(omp), data->mv_data, data->mv_size); + return MDB_SUCCESS; + } + } + if ((rc2 = mdb_ovpage_free(mc, omp)) != MDB_SUCCESS) + return rc2; + } else if (data->mv_size == olddata.mv_size) { + /* same size, just replace it. Note that we could + * also reuse this node if the new data is smaller, + * but instead we opt to shrink the node in that case. + */ + if (F_ISSET(flags, MDB_RESERVE)) + data->mv_data = olddata.mv_data; + else if (!(mc->mc_flags & C_SUB)) + memcpy(olddata.mv_data, data->mv_data, data->mv_size); + else { + memcpy(NODEKEY(leaf), key->mv_data, key->mv_size); + goto fix_parent; + } + return MDB_SUCCESS; + } + mdb_node_del(mc, 0); + } + + rdata = data; + +new_sub: + nflags = flags & NODE_ADD_FLAGS; + nsize = IS_LEAF2(mc->mc_pg[mc->mc_top]) ? key->mv_size : mdb_leaf_size(env, key, rdata); + if (SIZELEFT(mc->mc_pg[mc->mc_top]) < nsize) { + if (( flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA ) + nflags &= ~MDB_APPEND; /* sub-page may need room to grow */ + if (!insert_key) + nflags |= MDB_SPLIT_REPLACE; + rc = mdb_page_split(mc, key, rdata, P_INVALID, nflags); + } else { + /* There is room already in this leaf page. */ + rc = mdb_node_add(mc, mc->mc_ki[mc->mc_top], key, rdata, 0, nflags); + if (rc == 0) { + /* Adjust other cursors pointing to mp */ + MDB_cursor *m2, *m3; + MDB_dbi dbi = mc->mc_dbi; + unsigned i = mc->mc_top; + MDB_page *mp = mc->mc_pg[i]; + + for (m2 = mc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) { + if (mc->mc_flags & C_SUB) + m3 = &m2->mc_xcursor->mx_cursor; + else + m3 = m2; + if (m3 == mc || m3->mc_snum < mc->mc_snum || m3->mc_pg[i] != mp) continue; + if (m3->mc_ki[i] >= mc->mc_ki[i] && insert_key) { + m3->mc_ki[i]++; + } + if (m3->mc_xcursor && (m3->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED)) { + MDB_node *n2 = NODEPTR(mp, m3->mc_ki[i]); + if ((n2->mn_flags & (F_SUBDATA|F_DUPDATA)) == F_DUPDATA) + m3->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(n2); + } + } + } + } + + if (rc == MDB_SUCCESS) { + /* Now store the actual data in the child DB. Note that we're + * storing the user data in the keys field, so there are strict + * size limits on dupdata. The actual data fields of the child + * DB are all zero size. + */ + if (do_sub) { + int xflags, new_dupdata; + mdb_size_t ecount; +put_sub: + xdata.mv_size = 0; + xdata.mv_data = ""; + leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]); + if (flags & MDB_CURRENT) { + xflags = MDB_CURRENT|MDB_NOSPILL; + } else { + mdb_xcursor_init1(mc, leaf); + xflags = (flags & MDB_NODUPDATA) ? + MDB_NOOVERWRITE|MDB_NOSPILL : MDB_NOSPILL; + } + if (sub_root) + mc->mc_xcursor->mx_cursor.mc_pg[0] = sub_root; + new_dupdata = (int)dkey.mv_size; + /* converted, write the original data first */ + if (dkey.mv_size) { + rc = mdb_cursor_put(&mc->mc_xcursor->mx_cursor, &dkey, &xdata, xflags); + if (rc) + goto bad_sub; + /* we've done our job */ + dkey.mv_size = 0; + } + if (!(leaf->mn_flags & F_SUBDATA) || sub_root) { + /* Adjust other cursors pointing to mp */ + MDB_cursor *m2; + MDB_xcursor *mx = mc->mc_xcursor; + unsigned i = mc->mc_top; + MDB_page *mp = mc->mc_pg[i]; + int nkeys = NUMKEYS(mp); + + for (m2 = mc->mc_txn->mt_cursors[mc->mc_dbi]; m2; m2=m2->mc_next) { + if (m2 == mc || m2->mc_snum < mc->mc_snum) continue; + if (!(m2->mc_flags & C_INITIALIZED)) continue; + if (m2->mc_pg[i] == mp) { + if (m2->mc_ki[i] == mc->mc_ki[i]) { + mdb_xcursor_init2(m2, mx, new_dupdata); + } else if (!insert_key && m2->mc_ki[i] < nkeys) { + MDB_node *n2 = NODEPTR(mp, m2->mc_ki[i]); + if ((n2->mn_flags & (F_SUBDATA|F_DUPDATA)) == F_DUPDATA) + m2->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(n2); + } + } + } + } + ecount = mc->mc_xcursor->mx_db.md_entries; + if (flags & MDB_APPENDDUP) + xflags |= MDB_APPEND; + rc = mdb_cursor_put(&mc->mc_xcursor->mx_cursor, data, &xdata, xflags); + if (flags & F_SUBDATA) { + void *db = NODEDATA(leaf); + memcpy(db, &mc->mc_xcursor->mx_db, sizeof(MDB_db)); + } + insert_data = mc->mc_xcursor->mx_db.md_entries - ecount; + } + /* Increment count unless we just replaced an existing item. */ + if (insert_data) + mc->mc_db->md_entries++; + if (insert_key) { + /* Invalidate txn if we created an empty sub-DB */ + if (rc) + goto bad_sub; + /* If we succeeded and the key didn't exist before, + * make sure the cursor is marked valid. + */ + mc->mc_flags |= C_INITIALIZED; + } + if (flags & MDB_MULTIPLE) { + if (!rc) { + mcount++; + /* let caller know how many succeeded, if any */ + data[1].mv_size = mcount; + if (mcount < dcount) { + data[0].mv_data = (char *)data[0].mv_data + data[0].mv_size; + insert_key = insert_data = 0; + goto more; + } + } + } + return rc; +bad_sub: + if (rc == MDB_KEYEXIST) /* should not happen, we deleted that item */ + rc = MDB_CORRUPTED; + } + mc->mc_txn->mt_flags |= MDB_TXN_ERROR; + return rc; +} + +int +mdb_cursor_del(MDB_cursor *mc, unsigned int flags) +{ + MDB_node *leaf; + MDB_page *mp; + int rc; + + if (mc->mc_txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_BLOCKED)) + return (mc->mc_txn->mt_flags & MDB_TXN_RDONLY) ? EACCES : MDB_BAD_TXN; + + if (!(mc->mc_flags & C_INITIALIZED)) + return EINVAL; + + if (mc->mc_ki[mc->mc_top] >= NUMKEYS(mc->mc_pg[mc->mc_top])) + return MDB_NOTFOUND; + + if (!(flags & MDB_NOSPILL) && (rc = mdb_page_spill(mc, NULL, NULL))) + return rc; + + rc = mdb_cursor_touch(mc); + if (rc) + return rc; + + mp = mc->mc_pg[mc->mc_top]; + if (IS_LEAF2(mp)) + goto del_key; + leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]); + + if (F_ISSET(leaf->mn_flags, F_DUPDATA)) { + if (flags & MDB_NODUPDATA) { + /* mdb_cursor_del0() will subtract the final entry */ + mc->mc_db->md_entries -= mc->mc_xcursor->mx_db.md_entries - 1; + mc->mc_xcursor->mx_cursor.mc_flags &= ~C_INITIALIZED; + } else { + if (!F_ISSET(leaf->mn_flags, F_SUBDATA)) { + mc->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(leaf); + } + rc = mdb_cursor_del(&mc->mc_xcursor->mx_cursor, MDB_NOSPILL); + if (rc) + return rc; + /* If sub-DB still has entries, we're done */ + if (mc->mc_xcursor->mx_db.md_entries) { + if (leaf->mn_flags & F_SUBDATA) { + /* update subDB info */ + void *db = NODEDATA(leaf); + memcpy(db, &mc->mc_xcursor->mx_db, sizeof(MDB_db)); + } else { + MDB_cursor *m2; + /* shrink fake page */ + mdb_node_shrink(mp, mc->mc_ki[mc->mc_top]); + leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]); + mc->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(leaf); + /* fix other sub-DB cursors pointed at fake pages on this page */ + for (m2 = mc->mc_txn->mt_cursors[mc->mc_dbi]; m2; m2=m2->mc_next) { + if (m2 == mc || m2->mc_snum < mc->mc_snum) continue; + if (!(m2->mc_flags & C_INITIALIZED)) continue; + if (m2->mc_pg[mc->mc_top] == mp) { + if (m2->mc_ki[mc->mc_top] == mc->mc_ki[mc->mc_top]) { + m2->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(leaf); + } else { + MDB_node *n2 = NODEPTR(mp, m2->mc_ki[mc->mc_top]); + if (!(n2->mn_flags & F_SUBDATA)) + m2->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(n2); + } + } + } + } + mc->mc_db->md_entries--; + return rc; + } else { + mc->mc_xcursor->mx_cursor.mc_flags &= ~C_INITIALIZED; + } + /* otherwise fall thru and delete the sub-DB */ + } + + if (leaf->mn_flags & F_SUBDATA) { + /* add all the child DB's pages to the free list */ + rc = mdb_drop0(&mc->mc_xcursor->mx_cursor, 0); + if (rc) + goto fail; + } + } + /* LMDB passes F_SUBDATA in 'flags' to delete a DB record */ + else if ((leaf->mn_flags ^ flags) & F_SUBDATA) { + rc = MDB_INCOMPATIBLE; + goto fail; + } + + /* add overflow pages to free list */ + if (F_ISSET(leaf->mn_flags, F_BIGDATA)) { + MDB_page *omp; + pgno_t pg; + + memcpy(&pg, NODEDATA(leaf), sizeof(pg)); + if ((rc = mdb_page_get(mc, pg, &omp, NULL)) || + (rc = mdb_ovpage_free(mc, omp))) + goto fail; + } + +del_key: + return mdb_cursor_del0(mc); + +fail: + mc->mc_txn->mt_flags |= MDB_TXN_ERROR; + return rc; +} + +/** Allocate and initialize new pages for a database. + * @param[in] mc a cursor on the database being added to. + * @param[in] flags flags defining what type of page is being allocated. + * @param[in] num the number of pages to allocate. This is usually 1, + * unless allocating overflow pages for a large record. + * @param[out] mp Address of a page, or NULL on failure. + * @return 0 on success, non-zero on failure. + */ +static int +mdb_page_new(MDB_cursor *mc, uint32_t flags, int num, MDB_page **mp) +{ + MDB_page *np; + int rc; + + if ((rc = mdb_page_alloc(mc, num, &np))) + return rc; + DPRINTF(("allocated new mpage %"Y"u, page size %u", + np->mp_pgno, mc->mc_txn->mt_env->me_psize)); + np->mp_flags = flags | P_DIRTY; + np->mp_lower = (PAGEHDRSZ-PAGEBASE); + np->mp_upper = mc->mc_txn->mt_env->me_psize - PAGEBASE; + + if (IS_BRANCH(np)) + mc->mc_db->md_branch_pages++; + else if (IS_LEAF(np)) + mc->mc_db->md_leaf_pages++; + else if (IS_OVERFLOW(np)) { + mc->mc_db->md_overflow_pages += num; + np->mp_pages = num; + } + *mp = np; + + return 0; +} + +/** Calculate the size of a leaf node. + * The size depends on the environment's page size; if a data item + * is too large it will be put onto an overflow page and the node + * size will only include the key and not the data. Sizes are always + * rounded up to an even number of bytes, to guarantee 2-byte alignment + * of the #MDB_node headers. + * @param[in] env The environment handle. + * @param[in] key The key for the node. + * @param[in] data The data for the node. + * @return The number of bytes needed to store the node. + */ +static size_t +mdb_leaf_size(MDB_env *env, MDB_val *key, MDB_val *data) +{ + size_t sz; + + sz = LEAFSIZE(key, data); + if (sz > env->me_nodemax) { + /* put on overflow page */ + sz -= data->mv_size - sizeof(pgno_t); + } + + return EVEN(sz + sizeof(indx_t)); +} + +/** Calculate the size of a branch node. + * The size should depend on the environment's page size but since + * we currently don't support spilling large keys onto overflow + * pages, it's simply the size of the #MDB_node header plus the + * size of the key. Sizes are always rounded up to an even number + * of bytes, to guarantee 2-byte alignment of the #MDB_node headers. + * @param[in] env The environment handle. + * @param[in] key The key for the node. + * @return The number of bytes needed to store the node. + */ +static size_t +mdb_branch_size(MDB_env *env, MDB_val *key) +{ + size_t sz; + + sz = INDXSIZE(key); + if (sz > env->me_nodemax) { + /* put on overflow page */ + /* not implemented */ + /* sz -= key->size - sizeof(pgno_t); */ + } + + return sz + sizeof(indx_t); +} + +/** Add a node to the page pointed to by the cursor. + * @param[in] mc The cursor for this operation. + * @param[in] indx The index on the page where the new node should be added. + * @param[in] key The key for the new node. + * @param[in] data The data for the new node, if any. + * @param[in] pgno The page number, if adding a branch node. + * @param[in] flags Flags for the node. + * @return 0 on success, non-zero on failure. Possible errors are: + *
    + *
  • ENOMEM - failed to allocate overflow pages for the node. + *
  • MDB_PAGE_FULL - there is insufficient room in the page. This error + * should never happen since all callers already calculate the + * page's free space before calling this function. + *
+ */ +static int +mdb_node_add(MDB_cursor *mc, indx_t indx, + MDB_val *key, MDB_val *data, pgno_t pgno, unsigned int flags) +{ + unsigned int i; + size_t node_size = NODESIZE; + ssize_t room; + indx_t ofs; + MDB_node *node; + MDB_page *mp = mc->mc_pg[mc->mc_top]; + MDB_page *ofp = NULL; /* overflow page */ + void *ndata; + DKBUF; + + mdb_cassert(mc, mp->mp_upper >= mp->mp_lower); + + DPRINTF(("add to %s %spage %"Y"u index %i, data size %"Z"u key size %"Z"u [%s]", + IS_LEAF(mp) ? "leaf" : "branch", + IS_SUBP(mp) ? "sub-" : "", + mdb_dbg_pgno(mp), indx, data ? data->mv_size : 0, + key ? key->mv_size : 0, key ? DKEY(key) : "null")); + + if (IS_LEAF2(mp)) { + /* Move higher keys up one slot. */ + int ksize = mc->mc_db->md_pad, dif; + char *ptr = LEAF2KEY(mp, indx, ksize); + dif = NUMKEYS(mp) - indx; + if (dif > 0) + memmove(ptr+ksize, ptr, dif*ksize); + /* insert new key */ + memcpy(ptr, key->mv_data, ksize); + + /* Just using these for counting */ + mp->mp_lower += sizeof(indx_t); + mp->mp_upper -= ksize - sizeof(indx_t); + return MDB_SUCCESS; + } + + room = (ssize_t)SIZELEFT(mp) - (ssize_t)sizeof(indx_t); + if (key != NULL) + node_size += key->mv_size; + if (IS_LEAF(mp)) { + mdb_cassert(mc, key && data); + if (F_ISSET(flags, F_BIGDATA)) { + /* Data already on overflow page. */ + node_size += sizeof(pgno_t); + } else if (node_size + data->mv_size > mc->mc_txn->mt_env->me_nodemax) { + int ovpages = OVPAGES(data->mv_size, mc->mc_txn->mt_env->me_psize); + int rc; + /* Put data on overflow page. */ + DPRINTF(("data size is %"Z"u, node would be %"Z"u, put data on overflow page", + data->mv_size, node_size+data->mv_size)); + node_size = EVEN(node_size + sizeof(pgno_t)); + if ((ssize_t)node_size > room) + goto full; + if ((rc = mdb_page_new(mc, P_OVERFLOW, ovpages, &ofp))) + return rc; + DPRINTF(("allocated overflow page %"Y"u", ofp->mp_pgno)); + flags |= F_BIGDATA; + goto update; + } else { + node_size += data->mv_size; + } + } + node_size = EVEN(node_size); + if ((ssize_t)node_size > room) + goto full; + +update: + /* Move higher pointers up one slot. */ + for (i = NUMKEYS(mp); i > indx; i--) + mp->mp_ptrs[i] = mp->mp_ptrs[i - 1]; + + /* Adjust free space offsets. */ + ofs = mp->mp_upper - node_size; + mdb_cassert(mc, ofs >= mp->mp_lower + sizeof(indx_t)); + mp->mp_ptrs[indx] = ofs; + mp->mp_upper = ofs; + mp->mp_lower += sizeof(indx_t); + + /* Write the node data. */ + node = NODEPTR(mp, indx); + node->mn_ksize = (key == NULL) ? 0 : key->mv_size; + node->mn_flags = flags; + if (IS_LEAF(mp)) + SETDSZ(node,data->mv_size); + else + SETPGNO(node,pgno); + + if (key) + memcpy(NODEKEY(node), key->mv_data, key->mv_size); + + if (IS_LEAF(mp)) { + ndata = NODEDATA(node); + if (ofp == NULL) { + if (F_ISSET(flags, F_BIGDATA)) + memcpy(ndata, data->mv_data, sizeof(pgno_t)); + else if (F_ISSET(flags, MDB_RESERVE)) + data->mv_data = ndata; + else + memcpy(ndata, data->mv_data, data->mv_size); + } else { + memcpy(ndata, &ofp->mp_pgno, sizeof(pgno_t)); + ndata = METADATA(ofp); + if (F_ISSET(flags, MDB_RESERVE)) + data->mv_data = ndata; + else + memcpy(ndata, data->mv_data, data->mv_size); + } + } + + return MDB_SUCCESS; + +full: + DPRINTF(("not enough room in page %"Y"u, got %u ptrs", + mdb_dbg_pgno(mp), NUMKEYS(mp))); + DPRINTF(("upper-lower = %u - %u = %"Z"d", mp->mp_upper,mp->mp_lower,room)); + DPRINTF(("node size = %"Z"u", node_size)); + mc->mc_txn->mt_flags |= MDB_TXN_ERROR; + return MDB_PAGE_FULL; +} + +/** Delete the specified node from a page. + * @param[in] mc Cursor pointing to the node to delete. + * @param[in] ksize The size of a node. Only used if the page is + * part of a #MDB_DUPFIXED database. + */ +static void +mdb_node_del(MDB_cursor *mc, int ksize) +{ + MDB_page *mp = mc->mc_pg[mc->mc_top]; + indx_t indx = mc->mc_ki[mc->mc_top]; + unsigned int sz; + indx_t i, j, numkeys, ptr; + MDB_node *node; + char *base; + + DPRINTF(("delete node %u on %s page %"Y"u", indx, + IS_LEAF(mp) ? "leaf" : "branch", mdb_dbg_pgno(mp))); + numkeys = NUMKEYS(mp); + mdb_cassert(mc, indx < numkeys); + + if (IS_LEAF2(mp)) { + int x = numkeys - 1 - indx; + base = LEAF2KEY(mp, indx, ksize); + if (x) + memmove(base, base + ksize, x * ksize); + mp->mp_lower -= sizeof(indx_t); + mp->mp_upper += ksize - sizeof(indx_t); + return; + } + + node = NODEPTR(mp, indx); + sz = NODESIZE + node->mn_ksize; + if (IS_LEAF(mp)) { + if (F_ISSET(node->mn_flags, F_BIGDATA)) + sz += sizeof(pgno_t); + else + sz += NODEDSZ(node); + } + sz = EVEN(sz); + + ptr = mp->mp_ptrs[indx]; + for (i = j = 0; i < numkeys; i++) { + if (i != indx) { + mp->mp_ptrs[j] = mp->mp_ptrs[i]; + if (mp->mp_ptrs[i] < ptr) + mp->mp_ptrs[j] += sz; + j++; + } + } + + base = (char *)mp + mp->mp_upper + PAGEBASE; + memmove(base + sz, base, ptr - mp->mp_upper); + + mp->mp_lower -= sizeof(indx_t); + mp->mp_upper += sz; +} + +/** Compact the main page after deleting a node on a subpage. + * @param[in] mp The main page to operate on. + * @param[in] indx The index of the subpage on the main page. + */ +static void +mdb_node_shrink(MDB_page *mp, indx_t indx) +{ + MDB_node *node; + MDB_page *sp, *xp; + char *base; + indx_t delta, nsize, len, ptr; + int i; + + node = NODEPTR(mp, indx); + sp = (MDB_page *)NODEDATA(node); + delta = SIZELEFT(sp); + nsize = NODEDSZ(node) - delta; + + /* Prepare to shift upward, set len = length(subpage part to shift) */ + if (IS_LEAF2(sp)) { + len = nsize; + if (nsize & 1) + return; /* do not make the node uneven-sized */ + } else { + xp = (MDB_page *)((char *)sp + delta); /* destination subpage */ + for (i = NUMKEYS(sp); --i >= 0; ) + xp->mp_ptrs[i] = sp->mp_ptrs[i] - delta; + len = PAGEHDRSZ; + } + sp->mp_upper = sp->mp_lower; + COPY_PGNO(sp->mp_pgno, mp->mp_pgno); + SETDSZ(node, nsize); + + /* Shift upward */ + base = (char *)mp + mp->mp_upper + PAGEBASE; + memmove(base + delta, base, (char *)sp + len - base); + + ptr = mp->mp_ptrs[indx]; + for (i = NUMKEYS(mp); --i >= 0; ) { + if (mp->mp_ptrs[i] <= ptr) + mp->mp_ptrs[i] += delta; + } + mp->mp_upper += delta; +} + +/** Initial setup of a sorted-dups cursor. + * Sorted duplicates are implemented as a sub-database for the given key. + * The duplicate data items are actually keys of the sub-database. + * Operations on the duplicate data items are performed using a sub-cursor + * initialized when the sub-database is first accessed. This function does + * the preliminary setup of the sub-cursor, filling in the fields that + * depend only on the parent DB. + * @param[in] mc The main cursor whose sorted-dups cursor is to be initialized. + */ +static void +mdb_xcursor_init0(MDB_cursor *mc) +{ + MDB_xcursor *mx = mc->mc_xcursor; + + mx->mx_cursor.mc_xcursor = NULL; + mx->mx_cursor.mc_txn = mc->mc_txn; + mx->mx_cursor.mc_db = &mx->mx_db; + mx->mx_cursor.mc_dbx = &mx->mx_dbx; + mx->mx_cursor.mc_dbi = mc->mc_dbi; + mx->mx_cursor.mc_dbflag = &mx->mx_dbflag; + mx->mx_cursor.mc_snum = 0; + mx->mx_cursor.mc_top = 0; +#ifdef MDB_VL32 + mx->mx_cursor.mc_ovpg = 0; +#endif + mx->mx_cursor.mc_flags = C_SUB | (mc->mc_flags & (C_ORIG_RDONLY|C_WRITEMAP)); + mx->mx_dbx.md_name.mv_size = 0; + mx->mx_dbx.md_name.mv_data = NULL; + mx->mx_dbx.md_cmp = mc->mc_dbx->md_dcmp; + mx->mx_dbx.md_dcmp = NULL; + mx->mx_dbx.md_rel = mc->mc_dbx->md_rel; +} + +/** Final setup of a sorted-dups cursor. + * Sets up the fields that depend on the data from the main cursor. + * @param[in] mc The main cursor whose sorted-dups cursor is to be initialized. + * @param[in] node The data containing the #MDB_db record for the + * sorted-dup database. + */ +static void +mdb_xcursor_init1(MDB_cursor *mc, MDB_node *node) +{ + MDB_xcursor *mx = mc->mc_xcursor; + + mx->mx_cursor.mc_flags &= C_SUB|C_ORIG_RDONLY|C_WRITEMAP; + if (node->mn_flags & F_SUBDATA) { + memcpy(&mx->mx_db, NODEDATA(node), sizeof(MDB_db)); + mx->mx_cursor.mc_pg[0] = 0; + mx->mx_cursor.mc_snum = 0; + mx->mx_cursor.mc_top = 0; + } else { + MDB_page *fp = NODEDATA(node); + mx->mx_db.md_pad = 0; + mx->mx_db.md_flags = 0; + mx->mx_db.md_depth = 1; + mx->mx_db.md_branch_pages = 0; + mx->mx_db.md_leaf_pages = 1; + mx->mx_db.md_overflow_pages = 0; + mx->mx_db.md_entries = NUMKEYS(fp); + COPY_PGNO(mx->mx_db.md_root, fp->mp_pgno); + mx->mx_cursor.mc_snum = 1; + mx->mx_cursor.mc_top = 0; + mx->mx_cursor.mc_flags |= C_INITIALIZED; + mx->mx_cursor.mc_pg[0] = fp; + mx->mx_cursor.mc_ki[0] = 0; + if (mc->mc_db->md_flags & MDB_DUPFIXED) { + mx->mx_db.md_flags = MDB_DUPFIXED; + mx->mx_db.md_pad = fp->mp_pad; + if (mc->mc_db->md_flags & MDB_INTEGERDUP) + mx->mx_db.md_flags |= MDB_INTEGERKEY; + } + } + DPRINTF(("Sub-db -%u root page %"Y"u", mx->mx_cursor.mc_dbi, + mx->mx_db.md_root)); + mx->mx_dbflag = DB_VALID|DB_USRVALID|DB_DIRTY; /* DB_DIRTY guides mdb_cursor_touch */ +#if UINT_MAX < SIZE_MAX || defined(MDB_VL32) + if (mx->mx_dbx.md_cmp == mdb_cmp_int && mx->mx_db.md_pad == sizeof(mdb_size_t)) + mx->mx_dbx.md_cmp = mdb_cmp_clong; +#endif +} + + +/** Fixup a sorted-dups cursor due to underlying update. + * Sets up some fields that depend on the data from the main cursor. + * Almost the same as init1, but skips initialization steps if the + * xcursor had already been used. + * @param[in] mc The main cursor whose sorted-dups cursor is to be fixed up. + * @param[in] src_mx The xcursor of an up-to-date cursor. + * @param[in] new_dupdata True if converting from a non-#F_DUPDATA item. + */ +static void +mdb_xcursor_init2(MDB_cursor *mc, MDB_xcursor *src_mx, int new_dupdata) +{ + MDB_xcursor *mx = mc->mc_xcursor; + + if (new_dupdata) { + mx->mx_cursor.mc_snum = 1; + mx->mx_cursor.mc_top = 0; + mx->mx_cursor.mc_flags |= C_INITIALIZED; + mx->mx_cursor.mc_ki[0] = 0; + mx->mx_dbflag = DB_VALID|DB_USRVALID|DB_DIRTY; /* DB_DIRTY guides mdb_cursor_touch */ +#if UINT_MAX < SIZE_MAX + mx->mx_dbx.md_cmp = src_mx->mx_dbx.md_cmp; +#endif + } else if (!(mx->mx_cursor.mc_flags & C_INITIALIZED)) { + return; + } + mx->mx_db = src_mx->mx_db; + mx->mx_cursor.mc_pg[0] = src_mx->mx_cursor.mc_pg[0]; + DPRINTF(("Sub-db -%u root page %"Y"u", mx->mx_cursor.mc_dbi, + mx->mx_db.md_root)); +} + +/** Initialize a cursor for a given transaction and database. */ +static void +mdb_cursor_init(MDB_cursor *mc, MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx) +{ + mc->mc_next = NULL; + mc->mc_backup = NULL; + mc->mc_dbi = dbi; + mc->mc_txn = txn; + mc->mc_db = &txn->mt_dbs[dbi]; + mc->mc_dbx = &txn->mt_dbxs[dbi]; + mc->mc_dbflag = &txn->mt_dbflags[dbi]; + mc->mc_snum = 0; + mc->mc_top = 0; + mc->mc_pg[0] = 0; + mc->mc_ki[0] = 0; +#ifdef MDB_VL32 + mc->mc_ovpg = 0; +#endif + mc->mc_flags = txn->mt_flags & (C_ORIG_RDONLY|C_WRITEMAP); + if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) { + mdb_tassert(txn, mx != NULL); + mc->mc_xcursor = mx; + mdb_xcursor_init0(mc); + } else { + mc->mc_xcursor = NULL; + } + if (*mc->mc_dbflag & DB_STALE) { + mdb_page_search(mc, NULL, MDB_PS_ROOTONLY); + } +} + +int +mdb_cursor_open(MDB_txn *txn, MDB_dbi dbi, MDB_cursor **ret) +{ + MDB_cursor *mc; + size_t size = sizeof(MDB_cursor); + + if (!ret || !TXN_DBI_EXIST(txn, dbi, DB_VALID)) + return EINVAL; + + if (txn->mt_flags & MDB_TXN_BLOCKED) + return MDB_BAD_TXN; + + if (dbi == FREE_DBI && !F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)) + return EINVAL; + + if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) + size += sizeof(MDB_xcursor); + + if ((mc = malloc(size)) != NULL) { + mdb_cursor_init(mc, txn, dbi, (MDB_xcursor *)(mc + 1)); + if (txn->mt_cursors) { + mc->mc_next = txn->mt_cursors[dbi]; + txn->mt_cursors[dbi] = mc; + mc->mc_flags |= C_UNTRACK; + } + } else { + return ENOMEM; + } + + *ret = mc; + + return MDB_SUCCESS; +} + +int +mdb_cursor_renew(MDB_txn *txn, MDB_cursor *mc) +{ + if (!mc || !TXN_DBI_EXIST(txn, mc->mc_dbi, DB_VALID)) + return EINVAL; + + if ((mc->mc_flags & C_UNTRACK) || txn->mt_cursors) + return EINVAL; + + if (txn->mt_flags & MDB_TXN_BLOCKED) + return MDB_BAD_TXN; + + mdb_cursor_init(mc, txn, mc->mc_dbi, mc->mc_xcursor); + return MDB_SUCCESS; +} + +/* Return the count of duplicate data items for the current key */ +int +mdb_cursor_count(MDB_cursor *mc, mdb_size_t *countp) +{ + MDB_node *leaf; + + if (mc == NULL || countp == NULL) + return EINVAL; + + if (mc->mc_xcursor == NULL) + return MDB_INCOMPATIBLE; + + if (mc->mc_txn->mt_flags & MDB_TXN_BLOCKED) + return MDB_BAD_TXN; + + if (!(mc->mc_flags & C_INITIALIZED)) + return EINVAL; + + if (!mc->mc_snum || (mc->mc_flags & C_EOF)) + return MDB_NOTFOUND; + + leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]); + if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) { + *countp = 1; + } else { + if (!(mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED)) + return EINVAL; + + *countp = mc->mc_xcursor->mx_db.md_entries; + } + return MDB_SUCCESS; +} + +void +mdb_cursor_close(MDB_cursor *mc) +{ +#ifdef MDB_VL32 + if (mc) { + mdb_cursor_unref(mc); + } +#endif + if (mc && !mc->mc_backup) { + /* remove from txn, if tracked */ + if ((mc->mc_flags & C_UNTRACK) && mc->mc_txn->mt_cursors) { + MDB_cursor **prev = &mc->mc_txn->mt_cursors[mc->mc_dbi]; + while (*prev && *prev != mc) prev = &(*prev)->mc_next; + if (*prev == mc) + *prev = mc->mc_next; + } + free(mc); + } +} + +MDB_txn * +mdb_cursor_txn(MDB_cursor *mc) +{ + if (!mc) return NULL; + return mc->mc_txn; +} + +MDB_dbi +mdb_cursor_dbi(MDB_cursor *mc) +{ + return mc->mc_dbi; +} + +/** Replace the key for a branch node with a new key. + * @param[in] mc Cursor pointing to the node to operate on. + * @param[in] key The new key to use. + * @return 0 on success, non-zero on failure. + */ +static int +mdb_update_key(MDB_cursor *mc, MDB_val *key) +{ + MDB_page *mp; + MDB_node *node; + char *base; + size_t len; + int delta, ksize, oksize; + indx_t ptr, i, numkeys, indx; + DKBUF; + + indx = mc->mc_ki[mc->mc_top]; + mp = mc->mc_pg[mc->mc_top]; + node = NODEPTR(mp, indx); + ptr = mp->mp_ptrs[indx]; +#if MDB_DEBUG + { + MDB_val k2; + char kbuf2[DKBUF_MAXKEYSIZE*2+1]; + k2.mv_data = NODEKEY(node); + k2.mv_size = node->mn_ksize; + DPRINTF(("update key %u (ofs %u) [%s] to [%s] on page %"Y"u", + indx, ptr, + mdb_dkey(&k2, kbuf2), + DKEY(key), + mp->mp_pgno)); + } +#endif + + /* Sizes must be 2-byte aligned. */ + ksize = EVEN(key->mv_size); + oksize = EVEN(node->mn_ksize); + delta = ksize - oksize; + + /* Shift node contents if EVEN(key length) changed. */ + if (delta) { + if (delta > 0 && SIZELEFT(mp) < delta) { + pgno_t pgno; + /* not enough space left, do a delete and split */ + DPRINTF(("Not enough room, delta = %d, splitting...", delta)); + pgno = NODEPGNO(node); + mdb_node_del(mc, 0); + return mdb_page_split(mc, key, NULL, pgno, MDB_SPLIT_REPLACE); + } + + numkeys = NUMKEYS(mp); + for (i = 0; i < numkeys; i++) { + if (mp->mp_ptrs[i] <= ptr) + mp->mp_ptrs[i] -= delta; + } + + base = (char *)mp + mp->mp_upper + PAGEBASE; + len = ptr - mp->mp_upper + NODESIZE; + memmove(base - delta, base, len); + mp->mp_upper -= delta; + + node = NODEPTR(mp, indx); + } + + /* But even if no shift was needed, update ksize */ + if (node->mn_ksize != key->mv_size) + node->mn_ksize = key->mv_size; + + if (key->mv_size) + memcpy(NODEKEY(node), key->mv_data, key->mv_size); + + return MDB_SUCCESS; +} + +static void +mdb_cursor_copy(const MDB_cursor *csrc, MDB_cursor *cdst); + +/** Perform \b act while tracking temporary cursor \b mn */ +#define WITH_CURSOR_TRACKING(mn, act) do { \ + MDB_cursor dummy, *tracked, **tp = &(mn).mc_txn->mt_cursors[mn.mc_dbi]; \ + if ((mn).mc_flags & C_SUB) { \ + dummy.mc_flags = C_INITIALIZED; \ + dummy.mc_xcursor = (MDB_xcursor *)&(mn); \ + tracked = &dummy; \ + } else { \ + tracked = &(mn); \ + } \ + tracked->mc_next = *tp; \ + *tp = tracked; \ + { act; } \ + *tp = tracked->mc_next; \ +} while (0) + +/** Move a node from csrc to cdst. + */ +static int +mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst, int fromleft) +{ + MDB_node *srcnode; + MDB_val key, data; + pgno_t srcpg; + MDB_cursor mn; + int rc; + unsigned short flags; + + DKBUF; + + /* Mark src and dst as dirty. */ + if ((rc = mdb_page_touch(csrc)) || + (rc = mdb_page_touch(cdst))) + return rc; + + if (IS_LEAF2(csrc->mc_pg[csrc->mc_top])) { + key.mv_size = csrc->mc_db->md_pad; + key.mv_data = LEAF2KEY(csrc->mc_pg[csrc->mc_top], csrc->mc_ki[csrc->mc_top], key.mv_size); + data.mv_size = 0; + data.mv_data = NULL; + srcpg = 0; + flags = 0; + } else { + srcnode = NODEPTR(csrc->mc_pg[csrc->mc_top], csrc->mc_ki[csrc->mc_top]); + mdb_cassert(csrc, !((size_t)srcnode & 1)); + srcpg = NODEPGNO(srcnode); + flags = srcnode->mn_flags; + if (csrc->mc_ki[csrc->mc_top] == 0 && IS_BRANCH(csrc->mc_pg[csrc->mc_top])) { + unsigned int snum = csrc->mc_snum; + MDB_node *s2; + /* must find the lowest key below src */ + rc = mdb_page_search_lowest(csrc); + if (rc) + return rc; + if (IS_LEAF2(csrc->mc_pg[csrc->mc_top])) { + key.mv_size = csrc->mc_db->md_pad; + key.mv_data = LEAF2KEY(csrc->mc_pg[csrc->mc_top], 0, key.mv_size); + } else { + s2 = NODEPTR(csrc->mc_pg[csrc->mc_top], 0); + key.mv_size = NODEKSZ(s2); + key.mv_data = NODEKEY(s2); + } + csrc->mc_snum = snum--; + csrc->mc_top = snum; + } else { + key.mv_size = NODEKSZ(srcnode); + key.mv_data = NODEKEY(srcnode); + } + data.mv_size = NODEDSZ(srcnode); + data.mv_data = NODEDATA(srcnode); + } + mn.mc_xcursor = NULL; + if (IS_BRANCH(cdst->mc_pg[cdst->mc_top]) && cdst->mc_ki[cdst->mc_top] == 0) { + unsigned int snum = cdst->mc_snum; + MDB_node *s2; + MDB_val bkey; + /* must find the lowest key below dst */ + mdb_cursor_copy(cdst, &mn); + rc = mdb_page_search_lowest(&mn); + if (rc) + return rc; + if (IS_LEAF2(mn.mc_pg[mn.mc_top])) { + bkey.mv_size = mn.mc_db->md_pad; + bkey.mv_data = LEAF2KEY(mn.mc_pg[mn.mc_top], 0, bkey.mv_size); + } else { + s2 = NODEPTR(mn.mc_pg[mn.mc_top], 0); + bkey.mv_size = NODEKSZ(s2); + bkey.mv_data = NODEKEY(s2); + } + mn.mc_snum = snum--; + mn.mc_top = snum; + mn.mc_ki[snum] = 0; + rc = mdb_update_key(&mn, &bkey); + if (rc) + return rc; + } + + DPRINTF(("moving %s node %u [%s] on page %"Y"u to node %u on page %"Y"u", + IS_LEAF(csrc->mc_pg[csrc->mc_top]) ? "leaf" : "branch", + csrc->mc_ki[csrc->mc_top], + DKEY(&key), + csrc->mc_pg[csrc->mc_top]->mp_pgno, + cdst->mc_ki[cdst->mc_top], cdst->mc_pg[cdst->mc_top]->mp_pgno)); + + /* Add the node to the destination page. + */ + rc = mdb_node_add(cdst, cdst->mc_ki[cdst->mc_top], &key, &data, srcpg, flags); + if (rc != MDB_SUCCESS) + return rc; + + /* Delete the node from the source page. + */ + mdb_node_del(csrc, key.mv_size); + + { + /* Adjust other cursors pointing to mp */ + MDB_cursor *m2, *m3; + MDB_dbi dbi = csrc->mc_dbi; + MDB_page *mpd, *mps; + + mps = csrc->mc_pg[csrc->mc_top]; + /* If we're adding on the left, bump others up */ + if (fromleft) { + mpd = cdst->mc_pg[csrc->mc_top]; + for (m2 = csrc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) { + if (csrc->mc_flags & C_SUB) + m3 = &m2->mc_xcursor->mx_cursor; + else + m3 = m2; + if (!(m3->mc_flags & C_INITIALIZED) || m3->mc_top < csrc->mc_top) + continue; + if (m3 != cdst && + m3->mc_pg[csrc->mc_top] == mpd && + m3->mc_ki[csrc->mc_top] >= cdst->mc_ki[csrc->mc_top]) { + m3->mc_ki[csrc->mc_top]++; + } + if (m3 !=csrc && + m3->mc_pg[csrc->mc_top] == mps && + m3->mc_ki[csrc->mc_top] == csrc->mc_ki[csrc->mc_top]) { + m3->mc_pg[csrc->mc_top] = cdst->mc_pg[cdst->mc_top]; + m3->mc_ki[csrc->mc_top] = cdst->mc_ki[cdst->mc_top]; + m3->mc_ki[csrc->mc_top-1]++; + } + if (m3->mc_xcursor && (m3->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) && + IS_LEAF(mps)) { + MDB_node *node = NODEPTR(m3->mc_pg[csrc->mc_top], m3->mc_ki[csrc->mc_top]); + if ((node->mn_flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA) + m3->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(node); + } + } + } else + /* Adding on the right, bump others down */ + { + for (m2 = csrc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) { + if (csrc->mc_flags & C_SUB) + m3 = &m2->mc_xcursor->mx_cursor; + else + m3 = m2; + if (m3 == csrc) continue; + if (!(m3->mc_flags & C_INITIALIZED) || m3->mc_top < csrc->mc_top) + continue; + if (m3->mc_pg[csrc->mc_top] == mps) { + if (!m3->mc_ki[csrc->mc_top]) { + m3->mc_pg[csrc->mc_top] = cdst->mc_pg[cdst->mc_top]; + m3->mc_ki[csrc->mc_top] = cdst->mc_ki[cdst->mc_top]; + m3->mc_ki[csrc->mc_top-1]--; + } else { + m3->mc_ki[csrc->mc_top]--; + } + if (m3->mc_xcursor && (m3->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) && + IS_LEAF(mps)) { + MDB_node *node = NODEPTR(m3->mc_pg[csrc->mc_top], m3->mc_ki[csrc->mc_top]); + if ((node->mn_flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA) + m3->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(node); + } + } + } + } + } + + /* Update the parent separators. + */ + if (csrc->mc_ki[csrc->mc_top] == 0) { + if (csrc->mc_ki[csrc->mc_top-1] != 0) { + if (IS_LEAF2(csrc->mc_pg[csrc->mc_top])) { + key.mv_data = LEAF2KEY(csrc->mc_pg[csrc->mc_top], 0, key.mv_size); + } else { + srcnode = NODEPTR(csrc->mc_pg[csrc->mc_top], 0); + key.mv_size = NODEKSZ(srcnode); + key.mv_data = NODEKEY(srcnode); + } + DPRINTF(("update separator for source page %"Y"u to [%s]", + csrc->mc_pg[csrc->mc_top]->mp_pgno, DKEY(&key))); + mdb_cursor_copy(csrc, &mn); + mn.mc_snum--; + mn.mc_top--; + /* We want mdb_rebalance to find mn when doing fixups */ + WITH_CURSOR_TRACKING(mn, + rc = mdb_update_key(&mn, &key)); + if (rc) + return rc; + } + if (IS_BRANCH(csrc->mc_pg[csrc->mc_top])) { + MDB_val nullkey; + indx_t ix = csrc->mc_ki[csrc->mc_top]; + nullkey.mv_size = 0; + csrc->mc_ki[csrc->mc_top] = 0; + rc = mdb_update_key(csrc, &nullkey); + csrc->mc_ki[csrc->mc_top] = ix; + mdb_cassert(csrc, rc == MDB_SUCCESS); + } + } + + if (cdst->mc_ki[cdst->mc_top] == 0) { + if (cdst->mc_ki[cdst->mc_top-1] != 0) { + if (IS_LEAF2(csrc->mc_pg[csrc->mc_top])) { + key.mv_data = LEAF2KEY(cdst->mc_pg[cdst->mc_top], 0, key.mv_size); + } else { + srcnode = NODEPTR(cdst->mc_pg[cdst->mc_top], 0); + key.mv_size = NODEKSZ(srcnode); + key.mv_data = NODEKEY(srcnode); + } + DPRINTF(("update separator for destination page %"Y"u to [%s]", + cdst->mc_pg[cdst->mc_top]->mp_pgno, DKEY(&key))); + mdb_cursor_copy(cdst, &mn); + mn.mc_snum--; + mn.mc_top--; + /* We want mdb_rebalance to find mn when doing fixups */ + WITH_CURSOR_TRACKING(mn, + rc = mdb_update_key(&mn, &key)); + if (rc) + return rc; + } + if (IS_BRANCH(cdst->mc_pg[cdst->mc_top])) { + MDB_val nullkey; + indx_t ix = cdst->mc_ki[cdst->mc_top]; + nullkey.mv_size = 0; + cdst->mc_ki[cdst->mc_top] = 0; + rc = mdb_update_key(cdst, &nullkey); + cdst->mc_ki[cdst->mc_top] = ix; + mdb_cassert(cdst, rc == MDB_SUCCESS); + } + } + + return MDB_SUCCESS; +} + +/** Merge one page into another. + * The nodes from the page pointed to by \b csrc will + * be copied to the page pointed to by \b cdst and then + * the \b csrc page will be freed. + * @param[in] csrc Cursor pointing to the source page. + * @param[in] cdst Cursor pointing to the destination page. + * @return 0 on success, non-zero on failure. + */ +static int +mdb_page_merge(MDB_cursor *csrc, MDB_cursor *cdst) +{ + MDB_page *psrc, *pdst; + MDB_node *srcnode; + MDB_val key, data; + unsigned nkeys; + int rc; + indx_t i, j; + + psrc = csrc->mc_pg[csrc->mc_top]; + pdst = cdst->mc_pg[cdst->mc_top]; + + DPRINTF(("merging page %"Y"u into %"Y"u", psrc->mp_pgno, pdst->mp_pgno)); + + mdb_cassert(csrc, csrc->mc_snum > 1); /* can't merge root page */ + mdb_cassert(csrc, cdst->mc_snum > 1); + + /* Mark dst as dirty. */ + if ((rc = mdb_page_touch(cdst))) + return rc; + + /* get dst page again now that we've touched it. */ + pdst = cdst->mc_pg[cdst->mc_top]; + + /* Move all nodes from src to dst. + */ + j = nkeys = NUMKEYS(pdst); + if (IS_LEAF2(psrc)) { + key.mv_size = csrc->mc_db->md_pad; + key.mv_data = METADATA(psrc); + for (i = 0; i < NUMKEYS(psrc); i++, j++) { + rc = mdb_node_add(cdst, j, &key, NULL, 0, 0); + if (rc != MDB_SUCCESS) + return rc; + key.mv_data = (char *)key.mv_data + key.mv_size; + } + } else { + for (i = 0; i < NUMKEYS(psrc); i++, j++) { + srcnode = NODEPTR(psrc, i); + if (i == 0 && IS_BRANCH(psrc)) { + MDB_cursor mn; + MDB_node *s2; + mdb_cursor_copy(csrc, &mn); + mn.mc_xcursor = NULL; + /* must find the lowest key below src */ + rc = mdb_page_search_lowest(&mn); + if (rc) + return rc; + if (IS_LEAF2(mn.mc_pg[mn.mc_top])) { + key.mv_size = mn.mc_db->md_pad; + key.mv_data = LEAF2KEY(mn.mc_pg[mn.mc_top], 0, key.mv_size); + } else { + s2 = NODEPTR(mn.mc_pg[mn.mc_top], 0); + key.mv_size = NODEKSZ(s2); + key.mv_data = NODEKEY(s2); + } + } else { + key.mv_size = srcnode->mn_ksize; + key.mv_data = NODEKEY(srcnode); + } + + data.mv_size = NODEDSZ(srcnode); + data.mv_data = NODEDATA(srcnode); + rc = mdb_node_add(cdst, j, &key, &data, NODEPGNO(srcnode), srcnode->mn_flags); + if (rc != MDB_SUCCESS) + return rc; + } + } + + DPRINTF(("dst page %"Y"u now has %u keys (%.1f%% filled)", + pdst->mp_pgno, NUMKEYS(pdst), + (float)PAGEFILL(cdst->mc_txn->mt_env, pdst) / 10)); + + /* Unlink the src page from parent and add to free list. + */ + csrc->mc_top--; + mdb_node_del(csrc, 0); + if (csrc->mc_ki[csrc->mc_top] == 0) { + key.mv_size = 0; + rc = mdb_update_key(csrc, &key); + if (rc) { + csrc->mc_top++; + return rc; + } + } + csrc->mc_top++; + + psrc = csrc->mc_pg[csrc->mc_top]; + /* If not operating on FreeDB, allow this page to be reused + * in this txn. Otherwise just add to free list. + */ + rc = mdb_page_loose(csrc, psrc); + if (rc) + return rc; + if (IS_LEAF(psrc)) + csrc->mc_db->md_leaf_pages--; + else + csrc->mc_db->md_branch_pages--; + { + /* Adjust other cursors pointing to mp */ + MDB_cursor *m2, *m3; + MDB_dbi dbi = csrc->mc_dbi; + unsigned int top = csrc->mc_top; + + for (m2 = csrc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) { + if (csrc->mc_flags & C_SUB) + m3 = &m2->mc_xcursor->mx_cursor; + else + m3 = m2; + if (m3 == csrc) continue; + if (m3->mc_snum < csrc->mc_snum) continue; + if (m3->mc_pg[top] == psrc) { + m3->mc_pg[top] = pdst; + m3->mc_ki[top] += nkeys; + m3->mc_ki[top-1] = cdst->mc_ki[top-1]; + } else if (m3->mc_pg[top-1] == csrc->mc_pg[top-1] && + m3->mc_ki[top-1] > csrc->mc_ki[top-1]) { + m3->mc_ki[top-1]--; + } + if (m3->mc_xcursor && (m3->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) && + IS_LEAF(psrc)) { + MDB_node *node = NODEPTR(m3->mc_pg[top], m3->mc_ki[top]); + if ((node->mn_flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA) + m3->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(node); + } + } + } + { + unsigned int snum = cdst->mc_snum; + uint16_t depth = cdst->mc_db->md_depth; + mdb_cursor_pop(cdst); + rc = mdb_rebalance(cdst); + /* Did the tree height change? */ + if (depth != cdst->mc_db->md_depth) + snum += cdst->mc_db->md_depth - depth; + cdst->mc_snum = snum; + cdst->mc_top = snum-1; + } + return rc; +} + +/** Copy the contents of a cursor. + * @param[in] csrc The cursor to copy from. + * @param[out] cdst The cursor to copy to. + */ +static void +mdb_cursor_copy(const MDB_cursor *csrc, MDB_cursor *cdst) +{ + unsigned int i; + + cdst->mc_txn = csrc->mc_txn; + cdst->mc_dbi = csrc->mc_dbi; + cdst->mc_db = csrc->mc_db; + cdst->mc_dbx = csrc->mc_dbx; + cdst->mc_snum = csrc->mc_snum; + cdst->mc_top = csrc->mc_top; + cdst->mc_flags = csrc->mc_flags; +#ifdef MDB_VL32 + cdst->mc_ovpg = csrc->mc_ovpg; +#endif + + for (i=0; imc_snum; i++) { + cdst->mc_pg[i] = csrc->mc_pg[i]; + cdst->mc_ki[i] = csrc->mc_ki[i]; + } +} + +/** Rebalance the tree after a delete operation. + * @param[in] mc Cursor pointing to the page where rebalancing + * should begin. + * @return 0 on success, non-zero on failure. + */ +static int +mdb_rebalance(MDB_cursor *mc) +{ + MDB_node *node; + int rc, fromleft; + unsigned int ptop, minkeys, thresh; + MDB_cursor mn; + indx_t oldki; + + if (IS_BRANCH(mc->mc_pg[mc->mc_top])) { + minkeys = 2; + thresh = 1; + } else { + minkeys = 1; + thresh = FILL_THRESHOLD; + } + DPRINTF(("rebalancing %s page %"Y"u (has %u keys, %.1f%% full)", + IS_LEAF(mc->mc_pg[mc->mc_top]) ? "leaf" : "branch", + mdb_dbg_pgno(mc->mc_pg[mc->mc_top]), NUMKEYS(mc->mc_pg[mc->mc_top]), + (float)PAGEFILL(mc->mc_txn->mt_env, mc->mc_pg[mc->mc_top]) / 10)); + + if (PAGEFILL(mc->mc_txn->mt_env, mc->mc_pg[mc->mc_top]) >= thresh && + NUMKEYS(mc->mc_pg[mc->mc_top]) >= minkeys) { + DPRINTF(("no need to rebalance page %"Y"u, above fill threshold", + mdb_dbg_pgno(mc->mc_pg[mc->mc_top]))); + return MDB_SUCCESS; + } + + if (mc->mc_snum < 2) { + MDB_page *mp = mc->mc_pg[0]; + if (IS_SUBP(mp)) { + DPUTS("Can't rebalance a subpage, ignoring"); + return MDB_SUCCESS; + } + if (NUMKEYS(mp) == 0) { + DPUTS("tree is completely empty"); + mc->mc_db->md_root = P_INVALID; + mc->mc_db->md_depth = 0; + mc->mc_db->md_leaf_pages = 0; + rc = mdb_midl_append(&mc->mc_txn->mt_free_pgs, mp->mp_pgno); + if (rc) + return rc; + /* Adjust cursors pointing to mp */ + mc->mc_snum = 0; + mc->mc_top = 0; + mc->mc_flags &= ~C_INITIALIZED; + { + MDB_cursor *m2, *m3; + MDB_dbi dbi = mc->mc_dbi; + + for (m2 = mc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) { + if (mc->mc_flags & C_SUB) + m3 = &m2->mc_xcursor->mx_cursor; + else + m3 = m2; + if (!(m3->mc_flags & C_INITIALIZED) || (m3->mc_snum < mc->mc_snum)) + continue; + if (m3->mc_pg[0] == mp) { + m3->mc_snum = 0; + m3->mc_top = 0; + m3->mc_flags &= ~C_INITIALIZED; + } + } + } + } else if (IS_BRANCH(mp) && NUMKEYS(mp) == 1) { + int i; + DPUTS("collapsing root page!"); + rc = mdb_midl_append(&mc->mc_txn->mt_free_pgs, mp->mp_pgno); + if (rc) + return rc; + mc->mc_db->md_root = NODEPGNO(NODEPTR(mp, 0)); + rc = mdb_page_get(mc, mc->mc_db->md_root, &mc->mc_pg[0], NULL); + if (rc) + return rc; + mc->mc_db->md_depth--; + mc->mc_db->md_branch_pages--; + mc->mc_ki[0] = mc->mc_ki[1]; + for (i = 1; imc_db->md_depth; i++) { + mc->mc_pg[i] = mc->mc_pg[i+1]; + mc->mc_ki[i] = mc->mc_ki[i+1]; + } + { + /* Adjust other cursors pointing to mp */ + MDB_cursor *m2, *m3; + MDB_dbi dbi = mc->mc_dbi; + + for (m2 = mc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) { + if (mc->mc_flags & C_SUB) + m3 = &m2->mc_xcursor->mx_cursor; + else + m3 = m2; + if (m3 == mc) continue; + if (!(m3->mc_flags & C_INITIALIZED)) + continue; + if (m3->mc_pg[0] == mp) { + for (i=0; imc_db->md_depth; i++) { + m3->mc_pg[i] = m3->mc_pg[i+1]; + m3->mc_ki[i] = m3->mc_ki[i+1]; + } + m3->mc_snum--; + m3->mc_top--; + } + } + } + } else + DPUTS("root page doesn't need rebalancing"); + return MDB_SUCCESS; + } + + /* The parent (branch page) must have at least 2 pointers, + * otherwise the tree is invalid. + */ + ptop = mc->mc_top-1; + mdb_cassert(mc, NUMKEYS(mc->mc_pg[ptop]) > 1); + + /* Leaf page fill factor is below the threshold. + * Try to move keys from left or right neighbor, or + * merge with a neighbor page. + */ + + /* Find neighbors. + */ + mdb_cursor_copy(mc, &mn); + mn.mc_xcursor = NULL; + + oldki = mc->mc_ki[mc->mc_top]; + if (mc->mc_ki[ptop] == 0) { + /* We're the leftmost leaf in our parent. + */ + DPUTS("reading right neighbor"); + mn.mc_ki[ptop]++; + node = NODEPTR(mc->mc_pg[ptop], mn.mc_ki[ptop]); + rc = mdb_page_get(mc, NODEPGNO(node), &mn.mc_pg[mn.mc_top], NULL); + if (rc) + return rc; + mn.mc_ki[mn.mc_top] = 0; + mc->mc_ki[mc->mc_top] = NUMKEYS(mc->mc_pg[mc->mc_top]); + fromleft = 0; + } else { + /* There is at least one neighbor to the left. + */ + DPUTS("reading left neighbor"); + mn.mc_ki[ptop]--; + node = NODEPTR(mc->mc_pg[ptop], mn.mc_ki[ptop]); + rc = mdb_page_get(mc, NODEPGNO(node), &mn.mc_pg[mn.mc_top], NULL); + if (rc) + return rc; + mn.mc_ki[mn.mc_top] = NUMKEYS(mn.mc_pg[mn.mc_top]) - 1; + mc->mc_ki[mc->mc_top] = 0; + fromleft = 1; + } + + DPRINTF(("found neighbor page %"Y"u (%u keys, %.1f%% full)", + mn.mc_pg[mn.mc_top]->mp_pgno, NUMKEYS(mn.mc_pg[mn.mc_top]), + (float)PAGEFILL(mc->mc_txn->mt_env, mn.mc_pg[mn.mc_top]) / 10)); + + /* If the neighbor page is above threshold and has enough keys, + * move one key from it. Otherwise we should try to merge them. + * (A branch page must never have less than 2 keys.) + */ + if (PAGEFILL(mc->mc_txn->mt_env, mn.mc_pg[mn.mc_top]) >= thresh && NUMKEYS(mn.mc_pg[mn.mc_top]) > minkeys) { + rc = mdb_node_move(&mn, mc, fromleft); + if (fromleft) { + /* if we inserted on left, bump position up */ + oldki++; + } + } else { + if (!fromleft) { + rc = mdb_page_merge(&mn, mc); + } else { + oldki += NUMKEYS(mn.mc_pg[mn.mc_top]); + mn.mc_ki[mn.mc_top] += mc->mc_ki[mn.mc_top] + 1; + /* We want mdb_rebalance to find mn when doing fixups */ + WITH_CURSOR_TRACKING(mn, + rc = mdb_page_merge(mc, &mn)); + mdb_cursor_copy(&mn, mc); + } + mc->mc_flags &= ~C_EOF; + } + mc->mc_ki[mc->mc_top] = oldki; + return rc; +} + +/** Complete a delete operation started by #mdb_cursor_del(). */ +static int +mdb_cursor_del0(MDB_cursor *mc) +{ + int rc; + MDB_page *mp; + indx_t ki; + unsigned int nkeys; + MDB_cursor *m2, *m3; + MDB_dbi dbi = mc->mc_dbi; + + ki = mc->mc_ki[mc->mc_top]; + mp = mc->mc_pg[mc->mc_top]; + mdb_node_del(mc, mc->mc_db->md_pad); + mc->mc_db->md_entries--; + { + /* Adjust other cursors pointing to mp */ + for (m2 = mc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) { + m3 = (mc->mc_flags & C_SUB) ? &m2->mc_xcursor->mx_cursor : m2; + if (! (m2->mc_flags & m3->mc_flags & C_INITIALIZED)) + continue; + if (m3 == mc || m3->mc_snum < mc->mc_snum) + continue; + if (m3->mc_pg[mc->mc_top] == mp) { + if (m3->mc_ki[mc->mc_top] == ki) { + m3->mc_flags |= C_DEL; + if (mc->mc_db->md_flags & MDB_DUPSORT) + m3->mc_xcursor->mx_cursor.mc_flags &= ~C_INITIALIZED; + } else if (m3->mc_ki[mc->mc_top] > ki) { + m3->mc_ki[mc->mc_top]--; + } + if (m3->mc_xcursor && (m3->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED)) { + MDB_node *node = NODEPTR(m3->mc_pg[mc->mc_top], m3->mc_ki[mc->mc_top]); + if ((node->mn_flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA) + m3->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(node); + } + } + } + } + rc = mdb_rebalance(mc); + + if (rc == MDB_SUCCESS) { + /* DB is totally empty now, just bail out. + * Other cursors adjustments were already done + * by mdb_rebalance and aren't needed here. + */ + if (!mc->mc_snum) + return rc; + + mp = mc->mc_pg[mc->mc_top]; + nkeys = NUMKEYS(mp); + + /* Adjust other cursors pointing to mp */ + for (m2 = mc->mc_txn->mt_cursors[dbi]; !rc && m2; m2=m2->mc_next) { + m3 = (mc->mc_flags & C_SUB) ? &m2->mc_xcursor->mx_cursor : m2; + if (! (m2->mc_flags & m3->mc_flags & C_INITIALIZED)) + continue; + if (m3->mc_snum < mc->mc_snum) + continue; + if (m3->mc_pg[mc->mc_top] == mp) { + /* if m3 points past last node in page, find next sibling */ + if (m3->mc_ki[mc->mc_top] >= nkeys) { + rc = mdb_cursor_sibling(m3, 1); + if (rc == MDB_NOTFOUND) { + m3->mc_flags |= C_EOF; + rc = MDB_SUCCESS; + } + } + } + } + mc->mc_flags |= C_DEL; + } + + if (rc) + mc->mc_txn->mt_flags |= MDB_TXN_ERROR; + return rc; +} + +int +mdb_del(MDB_txn *txn, MDB_dbi dbi, + MDB_val *key, MDB_val *data) +{ + if (!key || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) + return EINVAL; + + if (txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_BLOCKED)) + return (txn->mt_flags & MDB_TXN_RDONLY) ? EACCES : MDB_BAD_TXN; + + if (!F_ISSET(txn->mt_dbs[dbi].md_flags, MDB_DUPSORT)) { + /* must ignore any data */ + data = NULL; + } + + return mdb_del0(txn, dbi, key, data, 0); +} + +static int +mdb_del0(MDB_txn *txn, MDB_dbi dbi, + MDB_val *key, MDB_val *data, unsigned flags) +{ + MDB_cursor mc; + MDB_xcursor mx; + MDB_cursor_op op; + MDB_val rdata, *xdata; + int rc, exact = 0; + DKBUF; + + DPRINTF(("====> delete db %u key [%s]", dbi, DKEY(key))); + + mdb_cursor_init(&mc, txn, dbi, &mx); + + if (data) { + op = MDB_GET_BOTH; + rdata = *data; + xdata = &rdata; + } else { + op = MDB_SET; + xdata = NULL; + flags |= MDB_NODUPDATA; + } + rc = mdb_cursor_set(&mc, key, xdata, op, &exact); + if (rc == 0) { + /* let mdb_page_split know about this cursor if needed: + * delete will trigger a rebalance; if it needs to move + * a node from one page to another, it will have to + * update the parent's separator key(s). If the new sepkey + * is larger than the current one, the parent page may + * run out of space, triggering a split. We need this + * cursor to be consistent until the end of the rebalance. + */ + mc.mc_flags |= C_UNTRACK; + mc.mc_next = txn->mt_cursors[dbi]; + txn->mt_cursors[dbi] = &mc; + rc = mdb_cursor_del(&mc, flags); + txn->mt_cursors[dbi] = mc.mc_next; + } + return rc; +} + +/** Split a page and insert a new node. + * @param[in,out] mc Cursor pointing to the page and desired insertion index. + * The cursor will be updated to point to the actual page and index where + * the node got inserted after the split. + * @param[in] newkey The key for the newly inserted node. + * @param[in] newdata The data for the newly inserted node. + * @param[in] newpgno The page number, if the new node is a branch node. + * @param[in] nflags The #NODE_ADD_FLAGS for the new node. + * @return 0 on success, non-zero on failure. + */ +static int +mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno, + unsigned int nflags) +{ + unsigned int flags; + int rc = MDB_SUCCESS, new_root = 0, did_split = 0; + indx_t newindx; + pgno_t pgno = 0; + int i, j, split_indx, nkeys, pmax; + MDB_env *env = mc->mc_txn->mt_env; + MDB_node *node; + MDB_val sepkey, rkey, xdata, *rdata = &xdata; + MDB_page *copy = NULL; + MDB_page *mp, *rp, *pp; + int ptop; + MDB_cursor mn; + DKBUF; + + mp = mc->mc_pg[mc->mc_top]; + newindx = mc->mc_ki[mc->mc_top]; + nkeys = NUMKEYS(mp); + + DPRINTF(("-----> splitting %s page %"Y"u and adding [%s] at index %i/%i", + IS_LEAF(mp) ? "leaf" : "branch", mp->mp_pgno, + DKEY(newkey), mc->mc_ki[mc->mc_top], nkeys)); + + /* Create a right sibling. */ + if ((rc = mdb_page_new(mc, mp->mp_flags, 1, &rp))) + return rc; + rp->mp_pad = mp->mp_pad; + DPRINTF(("new right sibling: page %"Y"u", rp->mp_pgno)); + + /* Usually when splitting the root page, the cursor + * height is 1. But when called from mdb_update_key, + * the cursor height may be greater because it walks + * up the stack while finding the branch slot to update. + */ + if (mc->mc_top < 1) { + if ((rc = mdb_page_new(mc, P_BRANCH, 1, &pp))) + goto done; + /* shift current top to make room for new parent */ + for (i=mc->mc_snum; i>0; i--) { + mc->mc_pg[i] = mc->mc_pg[i-1]; + mc->mc_ki[i] = mc->mc_ki[i-1]; + } + mc->mc_pg[0] = pp; + mc->mc_ki[0] = 0; + mc->mc_db->md_root = pp->mp_pgno; + DPRINTF(("root split! new root = %"Y"u", pp->mp_pgno)); + new_root = mc->mc_db->md_depth++; + + /* Add left (implicit) pointer. */ + if ((rc = mdb_node_add(mc, 0, NULL, NULL, mp->mp_pgno, 0)) != MDB_SUCCESS) { + /* undo the pre-push */ + mc->mc_pg[0] = mc->mc_pg[1]; + mc->mc_ki[0] = mc->mc_ki[1]; + mc->mc_db->md_root = mp->mp_pgno; + mc->mc_db->md_depth--; + goto done; + } + mc->mc_snum++; + mc->mc_top++; + ptop = 0; + } else { + ptop = mc->mc_top-1; + DPRINTF(("parent branch page is %"Y"u", mc->mc_pg[ptop]->mp_pgno)); + } + + mdb_cursor_copy(mc, &mn); + mn.mc_xcursor = NULL; + mn.mc_pg[mn.mc_top] = rp; + mn.mc_ki[ptop] = mc->mc_ki[ptop]+1; + + if (nflags & MDB_APPEND) { + mn.mc_ki[mn.mc_top] = 0; + sepkey = *newkey; + split_indx = newindx; + nkeys = 0; + } else { + + split_indx = (nkeys+1) / 2; + + if (IS_LEAF2(rp)) { + char *split, *ins; + int x; + unsigned int lsize, rsize, ksize; + /* Move half of the keys to the right sibling */ + x = mc->mc_ki[mc->mc_top] - split_indx; + ksize = mc->mc_db->md_pad; + split = LEAF2KEY(mp, split_indx, ksize); + rsize = (nkeys - split_indx) * ksize; + lsize = (nkeys - split_indx) * sizeof(indx_t); + mp->mp_lower -= lsize; + rp->mp_lower += lsize; + mp->mp_upper += rsize - lsize; + rp->mp_upper -= rsize - lsize; + sepkey.mv_size = ksize; + if (newindx == split_indx) { + sepkey.mv_data = newkey->mv_data; + } else { + sepkey.mv_data = split; + } + if (x<0) { + ins = LEAF2KEY(mp, mc->mc_ki[mc->mc_top], ksize); + memcpy(rp->mp_ptrs, split, rsize); + sepkey.mv_data = rp->mp_ptrs; + memmove(ins+ksize, ins, (split_indx - mc->mc_ki[mc->mc_top]) * ksize); + memcpy(ins, newkey->mv_data, ksize); + mp->mp_lower += sizeof(indx_t); + mp->mp_upper -= ksize - sizeof(indx_t); + } else { + if (x) + memcpy(rp->mp_ptrs, split, x * ksize); + ins = LEAF2KEY(rp, x, ksize); + memcpy(ins, newkey->mv_data, ksize); + memcpy(ins+ksize, split + x * ksize, rsize - x * ksize); + rp->mp_lower += sizeof(indx_t); + rp->mp_upper -= ksize - sizeof(indx_t); + mc->mc_ki[mc->mc_top] = x; + } + } else { + int psize, nsize, k; + /* Maximum free space in an empty page */ + pmax = env->me_psize - PAGEHDRSZ; + if (IS_LEAF(mp)) + nsize = mdb_leaf_size(env, newkey, newdata); + else + nsize = mdb_branch_size(env, newkey); + nsize = EVEN(nsize); + + /* grab a page to hold a temporary copy */ + copy = mdb_page_malloc(mc->mc_txn, 1); + if (copy == NULL) { + rc = ENOMEM; + goto done; + } + copy->mp_pgno = mp->mp_pgno; + copy->mp_flags = mp->mp_flags; + copy->mp_lower = (PAGEHDRSZ-PAGEBASE); + copy->mp_upper = env->me_psize - PAGEBASE; + + /* prepare to insert */ + for (i=0, j=0; imp_ptrs[j++] = 0; + } + copy->mp_ptrs[j++] = mp->mp_ptrs[i]; + } + + /* When items are relatively large the split point needs + * to be checked, because being off-by-one will make the + * difference between success or failure in mdb_node_add. + * + * It's also relevant if a page happens to be laid out + * such that one half of its nodes are all "small" and + * the other half of its nodes are "large." If the new + * item is also "large" and falls on the half with + * "large" nodes, it also may not fit. + * + * As a final tweak, if the new item goes on the last + * spot on the page (and thus, onto the new page), bias + * the split so the new page is emptier than the old page. + * This yields better packing during sequential inserts. + */ + if (nkeys < 20 || nsize > pmax/16 || newindx >= nkeys) { + /* Find split point */ + psize = 0; + if (newindx <= split_indx || newindx >= nkeys) { + i = 0; j = 1; + k = newindx >= nkeys ? nkeys : split_indx+1+IS_LEAF(mp); + } else { + i = nkeys; j = -1; + k = split_indx-1; + } + for (; i!=k; i+=j) { + if (i == newindx) { + psize += nsize; + node = NULL; + } else { + node = (MDB_node *)((char *)mp + copy->mp_ptrs[i] + PAGEBASE); + psize += NODESIZE + NODEKSZ(node) + sizeof(indx_t); + if (IS_LEAF(mp)) { + if (F_ISSET(node->mn_flags, F_BIGDATA)) + psize += sizeof(pgno_t); + else + psize += NODEDSZ(node); + } + psize = EVEN(psize); + } + if (psize > pmax || i == k-j) { + split_indx = i + (j<0); + break; + } + } + } + if (split_indx == newindx) { + sepkey.mv_size = newkey->mv_size; + sepkey.mv_data = newkey->mv_data; + } else { + node = (MDB_node *)((char *)mp + copy->mp_ptrs[split_indx] + PAGEBASE); + sepkey.mv_size = node->mn_ksize; + sepkey.mv_data = NODEKEY(node); + } + } + } + + DPRINTF(("separator is %d [%s]", split_indx, DKEY(&sepkey))); + + /* Copy separator key to the parent. + */ + if (SIZELEFT(mn.mc_pg[ptop]) < mdb_branch_size(env, &sepkey)) { + int snum = mc->mc_snum; + mn.mc_snum--; + mn.mc_top--; + did_split = 1; + /* We want other splits to find mn when doing fixups */ + WITH_CURSOR_TRACKING(mn, + rc = mdb_page_split(&mn, &sepkey, NULL, rp->mp_pgno, 0)); + if (rc) + goto done; + + /* root split? */ + if (mc->mc_snum > snum) { + ptop++; + } + /* Right page might now have changed parent. + * Check if left page also changed parent. + */ + if (mn.mc_pg[ptop] != mc->mc_pg[ptop] && + mc->mc_ki[ptop] >= NUMKEYS(mc->mc_pg[ptop])) { + for (i=0; imc_pg[i] = mn.mc_pg[i]; + mc->mc_ki[i] = mn.mc_ki[i]; + } + mc->mc_pg[ptop] = mn.mc_pg[ptop]; + if (mn.mc_ki[ptop]) { + mc->mc_ki[ptop] = mn.mc_ki[ptop] - 1; + } else { + /* find right page's left sibling */ + mc->mc_ki[ptop] = mn.mc_ki[ptop]; + mdb_cursor_sibling(mc, 0); + } + } + } else { + mn.mc_top--; + rc = mdb_node_add(&mn, mn.mc_ki[ptop], &sepkey, NULL, rp->mp_pgno, 0); + mn.mc_top++; + } + if (rc != MDB_SUCCESS) { + goto done; + } + if (nflags & MDB_APPEND) { + mc->mc_pg[mc->mc_top] = rp; + mc->mc_ki[mc->mc_top] = 0; + rc = mdb_node_add(mc, 0, newkey, newdata, newpgno, nflags); + if (rc) + goto done; + for (i=0; imc_top; i++) + mc->mc_ki[i] = mn.mc_ki[i]; + } else if (!IS_LEAF2(mp)) { + /* Move nodes */ + mc->mc_pg[mc->mc_top] = rp; + i = split_indx; + j = 0; + do { + if (i == newindx) { + rkey.mv_data = newkey->mv_data; + rkey.mv_size = newkey->mv_size; + if (IS_LEAF(mp)) { + rdata = newdata; + } else + pgno = newpgno; + flags = nflags; + /* Update index for the new key. */ + mc->mc_ki[mc->mc_top] = j; + } else { + node = (MDB_node *)((char *)mp + copy->mp_ptrs[i] + PAGEBASE); + rkey.mv_data = NODEKEY(node); + rkey.mv_size = node->mn_ksize; + if (IS_LEAF(mp)) { + xdata.mv_data = NODEDATA(node); + xdata.mv_size = NODEDSZ(node); + rdata = &xdata; + } else + pgno = NODEPGNO(node); + flags = node->mn_flags; + } + + if (!IS_LEAF(mp) && j == 0) { + /* First branch index doesn't need key data. */ + rkey.mv_size = 0; + } + + rc = mdb_node_add(mc, j, &rkey, rdata, pgno, flags); + if (rc) + goto done; + if (i == nkeys) { + i = 0; + j = 0; + mc->mc_pg[mc->mc_top] = copy; + } else { + i++; + j++; + } + } while (i != split_indx); + + nkeys = NUMKEYS(copy); + for (i=0; imp_ptrs[i] = copy->mp_ptrs[i]; + mp->mp_lower = copy->mp_lower; + mp->mp_upper = copy->mp_upper; + memcpy(NODEPTR(mp, nkeys-1), NODEPTR(copy, nkeys-1), + env->me_psize - copy->mp_upper - PAGEBASE); + + /* reset back to original page */ + if (newindx < split_indx) { + mc->mc_pg[mc->mc_top] = mp; + } else { + mc->mc_pg[mc->mc_top] = rp; + mc->mc_ki[ptop]++; + /* Make sure mc_ki is still valid. + */ + if (mn.mc_pg[ptop] != mc->mc_pg[ptop] && + mc->mc_ki[ptop] >= NUMKEYS(mc->mc_pg[ptop])) { + for (i=0; i<=ptop; i++) { + mc->mc_pg[i] = mn.mc_pg[i]; + mc->mc_ki[i] = mn.mc_ki[i]; + } + } + } + if (nflags & MDB_RESERVE) { + node = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]); + if (!(node->mn_flags & F_BIGDATA)) + newdata->mv_data = NODEDATA(node); + } + } else { + if (newindx >= split_indx) { + mc->mc_pg[mc->mc_top] = rp; + mc->mc_ki[ptop]++; + /* Make sure mc_ki is still valid. + */ + if (mn.mc_pg[ptop] != mc->mc_pg[ptop] && + mc->mc_ki[ptop] >= NUMKEYS(mc->mc_pg[ptop])) { + for (i=0; i<=ptop; i++) { + mc->mc_pg[i] = mn.mc_pg[i]; + mc->mc_ki[i] = mn.mc_ki[i]; + } + } + } + } + + { + /* Adjust other cursors pointing to mp */ + MDB_cursor *m2, *m3; + MDB_dbi dbi = mc->mc_dbi; + nkeys = NUMKEYS(mp); + + for (m2 = mc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) { + if (mc->mc_flags & C_SUB) + m3 = &m2->mc_xcursor->mx_cursor; + else + m3 = m2; + if (m3 == mc) + continue; + if (!(m2->mc_flags & m3->mc_flags & C_INITIALIZED)) + continue; + if (new_root) { + int k; + /* sub cursors may be on different DB */ + if (m3->mc_pg[0] != mp) + continue; + /* root split */ + for (k=new_root; k>=0; k--) { + m3->mc_ki[k+1] = m3->mc_ki[k]; + m3->mc_pg[k+1] = m3->mc_pg[k]; + } + if (m3->mc_ki[0] >= nkeys) { + m3->mc_ki[0] = 1; + } else { + m3->mc_ki[0] = 0; + } + m3->mc_pg[0] = mc->mc_pg[0]; + m3->mc_snum++; + m3->mc_top++; + } + if (m3->mc_top >= mc->mc_top && m3->mc_pg[mc->mc_top] == mp) { + if (m3->mc_ki[mc->mc_top] >= newindx && !(nflags & MDB_SPLIT_REPLACE)) + m3->mc_ki[mc->mc_top]++; + if (m3->mc_ki[mc->mc_top] >= nkeys) { + m3->mc_pg[mc->mc_top] = rp; + m3->mc_ki[mc->mc_top] -= nkeys; + for (i=0; imc_top; i++) { + m3->mc_ki[i] = mn.mc_ki[i]; + m3->mc_pg[i] = mn.mc_pg[i]; + } + } + } else if (!did_split && m3->mc_top >= ptop && m3->mc_pg[ptop] == mc->mc_pg[ptop] && + m3->mc_ki[ptop] >= mc->mc_ki[ptop]) { + m3->mc_ki[ptop]++; + } + if (m3->mc_xcursor && (m3->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) && + IS_LEAF(mp)) { + MDB_node *node = NODEPTR(m3->mc_pg[mc->mc_top], m3->mc_ki[mc->mc_top]); + if ((node->mn_flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA) + m3->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(node); + } + } + } + DPRINTF(("mp left: %d, rp left: %d", SIZELEFT(mp), SIZELEFT(rp))); + +done: + if (copy) /* tmp page */ + mdb_page_free(env, copy); + if (rc) + mc->mc_txn->mt_flags |= MDB_TXN_ERROR; + return rc; +} + +int +mdb_put(MDB_txn *txn, MDB_dbi dbi, + MDB_val *key, MDB_val *data, unsigned int flags) +{ + MDB_cursor mc; + MDB_xcursor mx; + int rc; + + if (!key || !data || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) + return EINVAL; + + if (flags & ~(MDB_NOOVERWRITE|MDB_NODUPDATA|MDB_RESERVE|MDB_APPEND|MDB_APPENDDUP)) + return EINVAL; + + if (txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_BLOCKED)) + return (txn->mt_flags & MDB_TXN_RDONLY) ? EACCES : MDB_BAD_TXN; + + mdb_cursor_init(&mc, txn, dbi, &mx); + mc.mc_next = txn->mt_cursors[dbi]; + txn->mt_cursors[dbi] = &mc; + rc = mdb_cursor_put(&mc, key, data, flags); + txn->mt_cursors[dbi] = mc.mc_next; + return rc; +} + +#ifndef MDB_WBUF +#define MDB_WBUF (1024*1024) +#endif + + /** State needed for a compacting copy. */ +typedef struct mdb_copy { + pthread_mutex_t mc_mutex; + pthread_cond_t mc_cond; + char *mc_wbuf[2]; + char *mc_over[2]; + MDB_env *mc_env; + MDB_txn *mc_txn; + int mc_wlen[2]; + int mc_olen[2]; + pgno_t mc_next_pgno; + HANDLE mc_fd; + int mc_status; + volatile int mc_new; + int mc_toggle; + +} mdb_copy; + + /** Dedicated writer thread for compacting copy. */ +static THREAD_RET ESECT CALL_CONV +mdb_env_copythr(void *arg) +{ + mdb_copy *my = arg; + char *ptr; + int toggle = 0, wsize, rc; +#ifdef _WIN32 + DWORD len; +#define DO_WRITE(rc, fd, ptr, w2, len) rc = WriteFile(fd, ptr, w2, &len, NULL) +#else + int len; +#define DO_WRITE(rc, fd, ptr, w2, len) len = write(fd, ptr, w2); rc = (len >= 0) +#endif + + pthread_mutex_lock(&my->mc_mutex); + my->mc_new = 0; + pthread_cond_signal(&my->mc_cond); + for(;;) { + while (!my->mc_new) + pthread_cond_wait(&my->mc_cond, &my->mc_mutex); + if (my->mc_new < 0) { + my->mc_new = 0; + break; + } + my->mc_new = 0; + wsize = my->mc_wlen[toggle]; + ptr = my->mc_wbuf[toggle]; +again: + while (wsize > 0) { + DO_WRITE(rc, my->mc_fd, ptr, wsize, len); + if (!rc) { + rc = ErrCode(); + break; + } else if (len > 0) { + rc = MDB_SUCCESS; + ptr += len; + wsize -= len; + continue; + } else { + rc = EIO; + break; + } + } + if (rc) { + my->mc_status = rc; + break; + } + /* If there's an overflow page tail, write it too */ + if (my->mc_olen[toggle]) { + wsize = my->mc_olen[toggle]; + ptr = my->mc_over[toggle]; + my->mc_olen[toggle] = 0; + goto again; + } + my->mc_wlen[toggle] = 0; + toggle ^= 1; + pthread_cond_signal(&my->mc_cond); + } + pthread_cond_signal(&my->mc_cond); + pthread_mutex_unlock(&my->mc_mutex); + return (THREAD_RET)0; +#undef DO_WRITE +} + + /** Tell the writer thread there's a buffer ready to write */ +static int ESECT +mdb_env_cthr_toggle(mdb_copy *my, int st) +{ + int toggle = my->mc_toggle ^ 1; + pthread_mutex_lock(&my->mc_mutex); + if (my->mc_status) { + pthread_mutex_unlock(&my->mc_mutex); + return my->mc_status; + } + while (my->mc_new == 1) + pthread_cond_wait(&my->mc_cond, &my->mc_mutex); + my->mc_new = st; + my->mc_toggle = toggle; + pthread_cond_signal(&my->mc_cond); + pthread_mutex_unlock(&my->mc_mutex); + return 0; +} + + /** Depth-first tree traversal for compacting copy. */ +static int ESECT +mdb_env_cwalk(mdb_copy *my, pgno_t *pg, int flags) +{ + MDB_cursor mc; + MDB_node *ni; + MDB_page *mo, *mp, *leaf; + char *buf, *ptr; + int rc, toggle; + unsigned int i; + + /* Empty DB, nothing to do */ + if (*pg == P_INVALID) + return MDB_SUCCESS; + + mc.mc_snum = 1; + mc.mc_top = 0; + mc.mc_txn = my->mc_txn; + + rc = mdb_page_get(&mc, *pg, &mc.mc_pg[0], NULL); + if (rc) + return rc; + rc = mdb_page_search_root(&mc, NULL, MDB_PS_FIRST); + if (rc) + return rc; + + /* Make cursor pages writable */ + buf = ptr = malloc(my->mc_env->me_psize * mc.mc_snum); + if (buf == NULL) + return ENOMEM; + + for (i=0; imc_env->me_psize); + mc.mc_pg[i] = (MDB_page *)ptr; + ptr += my->mc_env->me_psize; + } + + /* This is writable space for a leaf page. Usually not needed. */ + leaf = (MDB_page *)ptr; + + toggle = my->mc_toggle; + while (mc.mc_snum > 0) { + unsigned n; + mp = mc.mc_pg[mc.mc_top]; + n = NUMKEYS(mp); + + if (IS_LEAF(mp)) { + if (!IS_LEAF2(mp) && !(flags & F_DUPDATA)) { + for (i=0; imn_flags & F_BIGDATA) { + MDB_page *omp; + pgno_t pg; + + /* Need writable leaf */ + if (mp != leaf) { + mc.mc_pg[mc.mc_top] = leaf; + mdb_page_copy(leaf, mp, my->mc_env->me_psize); + mp = leaf; + ni = NODEPTR(mp, i); + } + + memcpy(&pg, NODEDATA(ni), sizeof(pg)); + rc = mdb_page_get(&mc, pg, &omp, NULL); + if (rc) + goto done; + if (my->mc_wlen[toggle] >= MDB_WBUF) { + rc = mdb_env_cthr_toggle(my, 1); + if (rc) + goto done; + toggle = my->mc_toggle; + } + mo = (MDB_page *)(my->mc_wbuf[toggle] + my->mc_wlen[toggle]); + memcpy(mo, omp, my->mc_env->me_psize); + mo->mp_pgno = my->mc_next_pgno; + my->mc_next_pgno += omp->mp_pages; + my->mc_wlen[toggle] += my->mc_env->me_psize; + if (omp->mp_pages > 1) { + my->mc_olen[toggle] = my->mc_env->me_psize * (omp->mp_pages - 1); + my->mc_over[toggle] = (char *)omp + my->mc_env->me_psize; + rc = mdb_env_cthr_toggle(my, 1); + if (rc) + goto done; + toggle = my->mc_toggle; + } + memcpy(NODEDATA(ni), &mo->mp_pgno, sizeof(pgno_t)); + } else if (ni->mn_flags & F_SUBDATA) { + MDB_db db; + + /* Need writable leaf */ + if (mp != leaf) { + mc.mc_pg[mc.mc_top] = leaf; + mdb_page_copy(leaf, mp, my->mc_env->me_psize); + mp = leaf; + ni = NODEPTR(mp, i); + } + + memcpy(&db, NODEDATA(ni), sizeof(db)); + my->mc_toggle = toggle; + rc = mdb_env_cwalk(my, &db.md_root, ni->mn_flags & F_DUPDATA); + if (rc) + goto done; + toggle = my->mc_toggle; + memcpy(NODEDATA(ni), &db, sizeof(db)); + } + } + } + } else { + mc.mc_ki[mc.mc_top]++; + if (mc.mc_ki[mc.mc_top] < n) { + pgno_t pg; +again: + ni = NODEPTR(mp, mc.mc_ki[mc.mc_top]); + pg = NODEPGNO(ni); + rc = mdb_page_get(&mc, pg, &mp, NULL); + if (rc) + goto done; + mc.mc_top++; + mc.mc_snum++; + mc.mc_ki[mc.mc_top] = 0; + if (IS_BRANCH(mp)) { + /* Whenever we advance to a sibling branch page, + * we must proceed all the way down to its first leaf. + */ + mdb_page_copy(mc.mc_pg[mc.mc_top], mp, my->mc_env->me_psize); + goto again; + } else + mc.mc_pg[mc.mc_top] = mp; + continue; + } + } + if (my->mc_wlen[toggle] >= MDB_WBUF) { + rc = mdb_env_cthr_toggle(my, 1); + if (rc) + goto done; + toggle = my->mc_toggle; + } + mo = (MDB_page *)(my->mc_wbuf[toggle] + my->mc_wlen[toggle]); + mdb_page_copy(mo, mp, my->mc_env->me_psize); + mo->mp_pgno = my->mc_next_pgno++; + my->mc_wlen[toggle] += my->mc_env->me_psize; + if (mc.mc_top) { + /* Update parent if there is one */ + ni = NODEPTR(mc.mc_pg[mc.mc_top-1], mc.mc_ki[mc.mc_top-1]); + SETPGNO(ni, mo->mp_pgno); + mdb_cursor_pop(&mc); + } else { + /* Otherwise we're done */ + *pg = mo->mp_pgno; + break; + } + } +done: + free(buf); + return rc; +} + + /** Copy environment with compaction. */ +static int ESECT +mdb_env_copyfd1(MDB_env *env, HANDLE fd) +{ + MDB_meta *mm; + MDB_page *mp; + mdb_copy my; + MDB_txn *txn = NULL; + pthread_t thr; + int rc; + +#ifdef _WIN32 + my.mc_mutex = CreateMutex(NULL, FALSE, NULL); + my.mc_cond = CreateEvent(NULL, FALSE, FALSE, NULL); + my.mc_wbuf[0] = _aligned_malloc(MDB_WBUF*2, env->me_os_psize); + if (my.mc_wbuf[0] == NULL) + return errno; +#else + pthread_mutex_init(&my.mc_mutex, NULL); + pthread_cond_init(&my.mc_cond, NULL); +#ifdef HAVE_MEMALIGN + my.mc_wbuf[0] = memalign(env->me_os_psize, MDB_WBUF*2); + if (my.mc_wbuf[0] == NULL) + return errno; +#else + rc = posix_memalign((void **)&my.mc_wbuf[0], env->me_os_psize, MDB_WBUF*2); + if (rc) + return rc; +#endif +#endif + memset(my.mc_wbuf[0], 0, MDB_WBUF*2); + my.mc_wbuf[1] = my.mc_wbuf[0] + MDB_WBUF; + my.mc_wlen[0] = 0; + my.mc_wlen[1] = 0; + my.mc_olen[0] = 0; + my.mc_olen[1] = 0; + my.mc_next_pgno = NUM_METAS; + my.mc_status = 0; + my.mc_new = 1; + my.mc_toggle = 0; + my.mc_env = env; + my.mc_fd = fd; + THREAD_CREATE(thr, mdb_env_copythr, &my); + + rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn); + if (rc) + return rc; + + mp = (MDB_page *)my.mc_wbuf[0]; + memset(mp, 0, NUM_METAS * env->me_psize); + mp->mp_pgno = 0; + mp->mp_flags = P_META; + mm = (MDB_meta *)METADATA(mp); + mdb_env_init_meta0(env, mm); + mm->mm_address = env->me_metas[0]->mm_address; + + mp = (MDB_page *)(my.mc_wbuf[0] + env->me_psize); + mp->mp_pgno = 1; + mp->mp_flags = P_META; + *(MDB_meta *)METADATA(mp) = *mm; + mm = (MDB_meta *)METADATA(mp); + + /* Count the number of free pages, subtract from lastpg to find + * number of active pages + */ + { + MDB_ID freecount = 0; + MDB_cursor mc; + MDB_val key, data; + mdb_cursor_init(&mc, txn, FREE_DBI, NULL); + while ((rc = mdb_cursor_get(&mc, &key, &data, MDB_NEXT)) == 0) + freecount += *(MDB_ID *)data.mv_data; + freecount += txn->mt_dbs[FREE_DBI].md_branch_pages + + txn->mt_dbs[FREE_DBI].md_leaf_pages + + txn->mt_dbs[FREE_DBI].md_overflow_pages; + + /* Set metapage 1 */ + mm->mm_last_pg = txn->mt_next_pgno - freecount - 1; + mm->mm_dbs[MAIN_DBI] = txn->mt_dbs[MAIN_DBI]; + if (mm->mm_last_pg > NUM_METAS-1) { + mm->mm_dbs[MAIN_DBI].md_root = mm->mm_last_pg; + mm->mm_txnid = 1; + } else { + mm->mm_dbs[MAIN_DBI].md_root = P_INVALID; + } + } + my.mc_wlen[0] = env->me_psize * NUM_METAS; + my.mc_txn = txn; + pthread_mutex_lock(&my.mc_mutex); + while(my.mc_new) + pthread_cond_wait(&my.mc_cond, &my.mc_mutex); + pthread_mutex_unlock(&my.mc_mutex); + rc = mdb_env_cwalk(&my, &txn->mt_dbs[MAIN_DBI].md_root, 0); + if (rc == MDB_SUCCESS && my.mc_wlen[my.mc_toggle]) + rc = mdb_env_cthr_toggle(&my, 1); + mdb_env_cthr_toggle(&my, -1); + pthread_mutex_lock(&my.mc_mutex); + while(my.mc_new) + pthread_cond_wait(&my.mc_cond, &my.mc_mutex); + pthread_mutex_unlock(&my.mc_mutex); + THREAD_FINISH(thr); + + mdb_txn_abort(txn); +#ifdef _WIN32 + CloseHandle(my.mc_cond); + CloseHandle(my.mc_mutex); + _aligned_free(my.mc_wbuf[0]); +#else + pthread_cond_destroy(&my.mc_cond); + pthread_mutex_destroy(&my.mc_mutex); + free(my.mc_wbuf[0]); +#endif + return rc; +} + + /** Copy environment as-is. */ +static int ESECT +mdb_env_copyfd0(MDB_env *env, HANDLE fd) +{ + MDB_txn *txn = NULL; + mdb_mutexref_t wmutex = NULL; + int rc; + mdb_size_t wsize, w3; + char *ptr; +#ifdef _WIN32 + DWORD len, w2; +#define DO_WRITE(rc, fd, ptr, w2, len) rc = WriteFile(fd, ptr, w2, &len, NULL) +#else + ssize_t len; + size_t w2; +#define DO_WRITE(rc, fd, ptr, w2, len) len = write(fd, ptr, w2); rc = (len >= 0) +#endif + + /* Do the lock/unlock of the reader mutex before starting the + * write txn. Otherwise other read txns could block writers. + */ + rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn); + if (rc) + return rc; + + if (env->me_txns) { + /* We must start the actual read txn after blocking writers */ + mdb_txn_end(txn, MDB_END_RESET_TMP); + + /* Temporarily block writers until we snapshot the meta pages */ + wmutex = env->me_wmutex; + if (LOCK_MUTEX(rc, env, wmutex)) + goto leave; + + rc = mdb_txn_renew0(txn); + if (rc) { + UNLOCK_MUTEX(wmutex); + goto leave; + } + } + + wsize = env->me_psize * NUM_METAS; + ptr = env->me_map; + w2 = wsize; + while (w2 > 0) { + DO_WRITE(rc, fd, ptr, w2, len); + if (!rc) { + rc = ErrCode(); + break; + } else if (len > 0) { + rc = MDB_SUCCESS; + ptr += len; + w2 -= len; + continue; + } else { + /* Non-blocking or async handles are not supported */ + rc = EIO; + break; + } + } + if (wmutex) + UNLOCK_MUTEX(wmutex); + + if (rc) + goto leave; + + w3 = txn->mt_next_pgno * env->me_psize; + { + mdb_size_t fsize = 0; + if ((rc = mdb_fsize(env->me_fd, &fsize))) + goto leave; + if (w3 > fsize) + w3 = fsize; + } + wsize = w3 - wsize; + while (wsize > 0) { + if (wsize > MAX_WRITE) + w2 = MAX_WRITE; + else + w2 = wsize; + DO_WRITE(rc, fd, ptr, w2, len); + if (!rc) { + rc = ErrCode(); + break; + } else if (len > 0) { + rc = MDB_SUCCESS; + ptr += len; + wsize -= len; + continue; + } else { + rc = EIO; + break; + } + } + +leave: + mdb_txn_abort(txn); + return rc; +} + +int ESECT +mdb_env_copyfd2(MDB_env *env, HANDLE fd, unsigned int flags) +{ + if (flags & MDB_CP_COMPACT) + return mdb_env_copyfd1(env, fd); + else + return mdb_env_copyfd0(env, fd); +} + +int ESECT +mdb_env_copyfd(MDB_env *env, HANDLE fd) +{ + return mdb_env_copyfd2(env, fd, 0); +} + +int ESECT +mdb_env_copy2(MDB_env *env, const char *path, unsigned int flags) +{ + int rc, len; + char *lpath; + HANDLE newfd = INVALID_HANDLE_VALUE; +#ifdef _WIN32 + wchar_t *wpath; +#endif + + if (env->me_flags & MDB_NOSUBDIR) { + lpath = (char *)path; + } else { + len = strlen(path); + len += sizeof(DATANAME); + lpath = malloc(len); + if (!lpath) + return ENOMEM; + sprintf(lpath, "%s" DATANAME, path); + } + + /* The destination path must exist, but the destination file must not. + * We don't want the OS to cache the writes, since the source data is + * already in the OS cache. + */ +#ifdef _WIN32 + rc = utf8_to_utf16(lpath, -1, &wpath, NULL); + if (rc) + goto leave; + newfd = CreateFileW(wpath, GENERIC_WRITE, 0, NULL, CREATE_NEW, + FILE_FLAG_NO_BUFFERING|FILE_FLAG_WRITE_THROUGH, NULL); + free(wpath); +#else + newfd = open(lpath, O_WRONLY|O_CREAT|O_EXCL, 0666); +#endif + if (newfd == INVALID_HANDLE_VALUE) { + rc = ErrCode(); + goto leave; + } + + if (env->me_psize >= env->me_os_psize) { +#ifdef O_DIRECT + /* Set O_DIRECT if the file system supports it */ + if ((rc = fcntl(newfd, F_GETFL)) != -1) + (void) fcntl(newfd, F_SETFL, rc | O_DIRECT); +#endif +#ifdef F_NOCACHE /* __APPLE__ */ + rc = fcntl(newfd, F_NOCACHE, 1); + if (rc) { + rc = ErrCode(); + goto leave; + } +#endif + } + + rc = mdb_env_copyfd2(env, newfd, flags); + +leave: + if (!(env->me_flags & MDB_NOSUBDIR)) + free(lpath); + if (newfd != INVALID_HANDLE_VALUE) + if (close(newfd) < 0 && rc == MDB_SUCCESS) + rc = ErrCode(); + + return rc; +} + +int ESECT +mdb_env_copy(MDB_env *env, const char *path) +{ + return mdb_env_copy2(env, path, 0); +} + +int ESECT +mdb_env_set_flags(MDB_env *env, unsigned int flag, int onoff) +{ + if (flag & ~CHANGEABLE) + return EINVAL; + if (onoff) + env->me_flags |= flag; + else + env->me_flags &= ~flag; + return MDB_SUCCESS; +} + +int ESECT +mdb_env_get_flags(MDB_env *env, unsigned int *arg) +{ + if (!env || !arg) + return EINVAL; + + *arg = env->me_flags & (CHANGEABLE|CHANGELESS); + return MDB_SUCCESS; +} + +int ESECT +mdb_env_set_userctx(MDB_env *env, void *ctx) +{ + if (!env) + return EINVAL; + env->me_userctx = ctx; + return MDB_SUCCESS; +} + +void * ESECT +mdb_env_get_userctx(MDB_env *env) +{ + return env ? env->me_userctx : NULL; +} + +int ESECT +mdb_env_set_assert(MDB_env *env, MDB_assert_func *func) +{ + if (!env) + return EINVAL; +#ifndef NDEBUG + env->me_assert_func = func; +#endif + return MDB_SUCCESS; +} + +int ESECT +mdb_env_get_path(MDB_env *env, const char **arg) +{ + if (!env || !arg) + return EINVAL; + + *arg = env->me_path; + return MDB_SUCCESS; +} + +int ESECT +mdb_env_get_fd(MDB_env *env, mdb_filehandle_t *arg) +{ + if (!env || !arg) + return EINVAL; + + *arg = env->me_fd; + return MDB_SUCCESS; +} + +/** Common code for #mdb_stat() and #mdb_env_stat(). + * @param[in] env the environment to operate in. + * @param[in] db the #MDB_db record containing the stats to return. + * @param[out] arg the address of an #MDB_stat structure to receive the stats. + * @return 0, this function always succeeds. + */ +static int ESECT +mdb_stat0(MDB_env *env, MDB_db *db, MDB_stat *arg) +{ + arg->ms_psize = env->me_psize; + arg->ms_depth = db->md_depth; + arg->ms_branch_pages = db->md_branch_pages; + arg->ms_leaf_pages = db->md_leaf_pages; + arg->ms_overflow_pages = db->md_overflow_pages; + arg->ms_entries = db->md_entries; + + return MDB_SUCCESS; +} + +int ESECT +mdb_env_stat(MDB_env *env, MDB_stat *arg) +{ + MDB_meta *meta; + + if (env == NULL || arg == NULL) + return EINVAL; + + meta = mdb_env_pick_meta(env); + + return mdb_stat0(env, &meta->mm_dbs[MAIN_DBI], arg); +} + +int ESECT +mdb_env_info(MDB_env *env, MDB_envinfo *arg) +{ + MDB_meta *meta; + + if (env == NULL || arg == NULL) + return EINVAL; + + meta = mdb_env_pick_meta(env); + arg->me_mapaddr = meta->mm_address; + arg->me_last_pgno = meta->mm_last_pg; + arg->me_last_txnid = meta->mm_txnid; + + arg->me_mapsize = env->me_mapsize; + arg->me_maxreaders = env->me_maxreaders; + arg->me_numreaders = env->me_txns ? env->me_txns->mti_numreaders : 0; + return MDB_SUCCESS; +} + +/** Set the default comparison functions for a database. + * Called immediately after a database is opened to set the defaults. + * The user can then override them with #mdb_set_compare() or + * #mdb_set_dupsort(). + * @param[in] txn A transaction handle returned by #mdb_txn_begin() + * @param[in] dbi A database handle returned by #mdb_dbi_open() + */ +static void +mdb_default_cmp(MDB_txn *txn, MDB_dbi dbi) +{ + uint16_t f = txn->mt_dbs[dbi].md_flags; + + txn->mt_dbxs[dbi].md_cmp = + (f & MDB_REVERSEKEY) ? mdb_cmp_memnr : + (f & MDB_INTEGERKEY) ? mdb_cmp_cint : mdb_cmp_memn; + + txn->mt_dbxs[dbi].md_dcmp = + !(f & MDB_DUPSORT) ? 0 : + ((f & MDB_INTEGERDUP) + ? ((f & MDB_DUPFIXED) ? mdb_cmp_int : mdb_cmp_cint) + : ((f & MDB_REVERSEDUP) ? mdb_cmp_memnr : mdb_cmp_memn)); +} + +int mdb_dbi_open(MDB_txn *txn, const char *name, unsigned int flags, MDB_dbi *dbi) +{ + MDB_val key, data; + MDB_dbi i; + MDB_cursor mc; + MDB_db dummy; + int rc, dbflag, exact; + unsigned int unused = 0, seq; + char *namedup; + size_t len; + + if (flags & ~VALID_FLAGS) + return EINVAL; + if (txn->mt_flags & MDB_TXN_BLOCKED) + return MDB_BAD_TXN; + + /* main DB? */ + if (!name) { + *dbi = MAIN_DBI; + if (flags & PERSISTENT_FLAGS) { + uint16_t f2 = flags & PERSISTENT_FLAGS; + /* make sure flag changes get committed */ + if ((txn->mt_dbs[MAIN_DBI].md_flags | f2) != txn->mt_dbs[MAIN_DBI].md_flags) { + txn->mt_dbs[MAIN_DBI].md_flags |= f2; + txn->mt_flags |= MDB_TXN_DIRTY; + } + } + mdb_default_cmp(txn, MAIN_DBI); + return MDB_SUCCESS; + } + + if (txn->mt_dbxs[MAIN_DBI].md_cmp == NULL) { + mdb_default_cmp(txn, MAIN_DBI); + } + + /* Is the DB already open? */ + len = strlen(name); + for (i=CORE_DBS; imt_numdbs; i++) { + if (!txn->mt_dbxs[i].md_name.mv_size) { + /* Remember this free slot */ + if (!unused) unused = i; + continue; + } + if (len == txn->mt_dbxs[i].md_name.mv_size && + !strncmp(name, txn->mt_dbxs[i].md_name.mv_data, len)) { + *dbi = i; + return MDB_SUCCESS; + } + } + + /* If no free slot and max hit, fail */ + if (!unused && txn->mt_numdbs >= txn->mt_env->me_maxdbs) + return MDB_DBS_FULL; + + /* Cannot mix named databases with some mainDB flags */ + if (txn->mt_dbs[MAIN_DBI].md_flags & (MDB_DUPSORT|MDB_INTEGERKEY)) + return (flags & MDB_CREATE) ? MDB_INCOMPATIBLE : MDB_NOTFOUND; + + /* Find the DB info */ + dbflag = DB_NEW|DB_VALID|DB_USRVALID; + exact = 0; + key.mv_size = len; + key.mv_data = (void *)name; + mdb_cursor_init(&mc, txn, MAIN_DBI, NULL); + rc = mdb_cursor_set(&mc, &key, &data, MDB_SET, &exact); + if (rc == MDB_SUCCESS) { + /* make sure this is actually a DB */ + MDB_node *node = NODEPTR(mc.mc_pg[mc.mc_top], mc.mc_ki[mc.mc_top]); + if ((node->mn_flags & (F_DUPDATA|F_SUBDATA)) != F_SUBDATA) + return MDB_INCOMPATIBLE; + } else if (! (rc == MDB_NOTFOUND && (flags & MDB_CREATE))) { + return rc; + } + + /* Done here so we cannot fail after creating a new DB */ + if ((namedup = strdup(name)) == NULL) + return ENOMEM; + + if (rc) { + /* MDB_NOTFOUND and MDB_CREATE: Create new DB */ + data.mv_size = sizeof(MDB_db); + data.mv_data = &dummy; + memset(&dummy, 0, sizeof(dummy)); + dummy.md_root = P_INVALID; + dummy.md_flags = flags & PERSISTENT_FLAGS; + rc = mdb_cursor_put(&mc, &key, &data, F_SUBDATA); + dbflag |= DB_DIRTY; + } + + if (rc) { + free(namedup); + } else { + /* Got info, register DBI in this txn */ + unsigned int slot = unused ? unused : txn->mt_numdbs; + txn->mt_dbxs[slot].md_name.mv_data = namedup; + txn->mt_dbxs[slot].md_name.mv_size = len; + txn->mt_dbxs[slot].md_rel = NULL; + txn->mt_dbflags[slot] = dbflag; + /* txn-> and env-> are the same in read txns, use + * tmp variable to avoid undefined assignment + */ + seq = ++txn->mt_env->me_dbiseqs[slot]; + txn->mt_dbiseqs[slot] = seq; + + memcpy(&txn->mt_dbs[slot], data.mv_data, sizeof(MDB_db)); + *dbi = slot; + mdb_default_cmp(txn, slot); + if (!unused) { + txn->mt_numdbs++; + } + } + + return rc; +} + +int ESECT +mdb_stat(MDB_txn *txn, MDB_dbi dbi, MDB_stat *arg) +{ + if (!arg || !TXN_DBI_EXIST(txn, dbi, DB_VALID)) + return EINVAL; + + if (txn->mt_flags & MDB_TXN_BLOCKED) + return MDB_BAD_TXN; + + if (txn->mt_dbflags[dbi] & DB_STALE) { + MDB_cursor mc; + MDB_xcursor mx; + /* Stale, must read the DB's root. cursor_init does it for us. */ + mdb_cursor_init(&mc, txn, dbi, &mx); + } + return mdb_stat0(txn->mt_env, &txn->mt_dbs[dbi], arg); +} + +void mdb_dbi_close(MDB_env *env, MDB_dbi dbi) +{ + char *ptr; + if (dbi < CORE_DBS || dbi >= env->me_maxdbs) + return; + ptr = env->me_dbxs[dbi].md_name.mv_data; + /* If there was no name, this was already closed */ + if (ptr) { + env->me_dbxs[dbi].md_name.mv_data = NULL; + env->me_dbxs[dbi].md_name.mv_size = 0; + env->me_dbflags[dbi] = 0; + env->me_dbiseqs[dbi]++; + free(ptr); + } +} + +int mdb_dbi_flags(MDB_txn *txn, MDB_dbi dbi, unsigned int *flags) +{ + /* We could return the flags for the FREE_DBI too but what's the point? */ + if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) + return EINVAL; + *flags = txn->mt_dbs[dbi].md_flags & PERSISTENT_FLAGS; + return MDB_SUCCESS; +} + +/** Add all the DB's pages to the free list. + * @param[in] mc Cursor on the DB to free. + * @param[in] subs non-Zero to check for sub-DBs in this DB. + * @return 0 on success, non-zero on failure. + */ +static int +mdb_drop0(MDB_cursor *mc, int subs) +{ + int rc; + + rc = mdb_page_search(mc, NULL, MDB_PS_FIRST); + if (rc == MDB_SUCCESS) { + MDB_txn *txn = mc->mc_txn; + MDB_node *ni; + MDB_cursor mx; + unsigned int i; + + /* DUPSORT sub-DBs have no ovpages/DBs. Omit scanning leaves. + * This also avoids any P_LEAF2 pages, which have no nodes. + * Also if the DB doesn't have sub-DBs and has no overflow + * pages, omit scanning leaves. + */ + if ((mc->mc_flags & C_SUB) || + (!subs && !mc->mc_db->md_overflow_pages)) + mdb_cursor_pop(mc); + + mdb_cursor_copy(mc, &mx); +#ifdef MDB_VL32 + /* bump refcount for mx's pages */ + for (i=0; imc_snum; i++) + mdb_page_get(&mx, mc->mc_pg[i]->mp_pgno, &mx.mc_pg[i], NULL); +#endif + while (mc->mc_snum > 0) { + MDB_page *mp = mc->mc_pg[mc->mc_top]; + unsigned n = NUMKEYS(mp); + if (IS_LEAF(mp)) { + for (i=0; imn_flags & F_BIGDATA) { + MDB_page *omp; + pgno_t pg; + memcpy(&pg, NODEDATA(ni), sizeof(pg)); + rc = mdb_page_get(mc, pg, &omp, NULL); + if (rc != 0) + goto done; + mdb_cassert(mc, IS_OVERFLOW(omp)); + rc = mdb_midl_append_range(&txn->mt_free_pgs, + pg, omp->mp_pages); + if (rc) + goto done; + mc->mc_db->md_overflow_pages -= omp->mp_pages; + if (!mc->mc_db->md_overflow_pages && !subs) + break; + } else if (subs && (ni->mn_flags & F_SUBDATA)) { + mdb_xcursor_init1(mc, ni); + rc = mdb_drop0(&mc->mc_xcursor->mx_cursor, 0); + if (rc) + goto done; + } + } + if (!subs && !mc->mc_db->md_overflow_pages) + goto pop; + } else { + if ((rc = mdb_midl_need(&txn->mt_free_pgs, n)) != 0) + goto done; + for (i=0; imt_free_pgs, pg); + } + } + if (!mc->mc_top) + break; + mc->mc_ki[mc->mc_top] = i; + rc = mdb_cursor_sibling(mc, 1); + if (rc) { + if (rc != MDB_NOTFOUND) + goto done; + /* no more siblings, go back to beginning + * of previous level. + */ +pop: + mdb_cursor_pop(mc); + mc->mc_ki[0] = 0; + for (i=1; imc_snum; i++) { + mc->mc_ki[i] = 0; + mc->mc_pg[i] = mx.mc_pg[i]; + } + } + } + /* free it */ + rc = mdb_midl_append(&txn->mt_free_pgs, mc->mc_db->md_root); +done: + if (rc) + txn->mt_flags |= MDB_TXN_ERROR; +#ifdef MDB_VL32 + /* drop refcount for mx's pages */ + mdb_cursor_unref(&mx); +#endif + } else if (rc == MDB_NOTFOUND) { + rc = MDB_SUCCESS; + } + mc->mc_flags &= ~C_INITIALIZED; + return rc; +} + +int mdb_drop(MDB_txn *txn, MDB_dbi dbi, int del) +{ + MDB_cursor *mc, *m2; + int rc; + + if ((unsigned)del > 1 || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) + return EINVAL; + + if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)) + return EACCES; + + if (TXN_DBI_CHANGED(txn, dbi)) + return MDB_BAD_DBI; + + rc = mdb_cursor_open(txn, dbi, &mc); + if (rc) + return rc; + + rc = mdb_drop0(mc, mc->mc_db->md_flags & MDB_DUPSORT); + /* Invalidate the dropped DB's cursors */ + for (m2 = txn->mt_cursors[dbi]; m2; m2 = m2->mc_next) + m2->mc_flags &= ~(C_INITIALIZED|C_EOF); + if (rc) + goto leave; + + /* Can't delete the main DB */ + if (del && dbi >= CORE_DBS) { + rc = mdb_del0(txn, MAIN_DBI, &mc->mc_dbx->md_name, NULL, F_SUBDATA); + if (!rc) { + txn->mt_dbflags[dbi] = DB_STALE; + mdb_dbi_close(txn->mt_env, dbi); + } else { + txn->mt_flags |= MDB_TXN_ERROR; + } + } else { + /* reset the DB record, mark it dirty */ + txn->mt_dbflags[dbi] |= DB_DIRTY; + txn->mt_dbs[dbi].md_depth = 0; + txn->mt_dbs[dbi].md_branch_pages = 0; + txn->mt_dbs[dbi].md_leaf_pages = 0; + txn->mt_dbs[dbi].md_overflow_pages = 0; + txn->mt_dbs[dbi].md_entries = 0; + txn->mt_dbs[dbi].md_root = P_INVALID; + + txn->mt_flags |= MDB_TXN_DIRTY; + } +leave: + mdb_cursor_close(mc); + return rc; +} + +int mdb_set_compare(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp) +{ + if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) + return EINVAL; + + txn->mt_dbxs[dbi].md_cmp = cmp; + return MDB_SUCCESS; +} + +int mdb_set_dupsort(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp) +{ + if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) + return EINVAL; + + txn->mt_dbxs[dbi].md_dcmp = cmp; + return MDB_SUCCESS; +} + +int mdb_set_relfunc(MDB_txn *txn, MDB_dbi dbi, MDB_rel_func *rel) +{ + if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) + return EINVAL; + + txn->mt_dbxs[dbi].md_rel = rel; + return MDB_SUCCESS; +} + +int mdb_set_relctx(MDB_txn *txn, MDB_dbi dbi, void *ctx) +{ + if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) + return EINVAL; + + txn->mt_dbxs[dbi].md_relctx = ctx; + return MDB_SUCCESS; +} + +int ESECT +mdb_env_get_maxkeysize(MDB_env *env) +{ + return ENV_MAXKEY(env); +} + +int ESECT +mdb_reader_list(MDB_env *env, MDB_msg_func *func, void *ctx) +{ + unsigned int i, rdrs; + MDB_reader *mr; + char buf[64]; + int rc = 0, first = 1; + + if (!env || !func) + return -1; + if (!env->me_txns) { + return func("(no reader locks)\n", ctx); + } + rdrs = env->me_txns->mti_numreaders; + mr = env->me_txns->mti_readers; + for (i=0; i> 1; + cursor = base + pivot + 1; + val = pid - ids[cursor]; + + if( val < 0 ) { + n = pivot; + + } else if ( val > 0 ) { + base = cursor; + n -= pivot + 1; + + } else { + /* found, so it's a duplicate */ + return -1; + } + } + + if( val > 0 ) { + ++cursor; + } + ids[0]++; + for (n = ids[0]; n > cursor; n--) + ids[n] = ids[n-1]; + ids[n] = pid; + return 0; +} + +int ESECT +mdb_reader_check(MDB_env *env, int *dead) +{ + if (!env) + return EINVAL; + if (dead) + *dead = 0; + return env->me_txns ? mdb_reader_check0(env, 0, dead) : MDB_SUCCESS; +} + +/** As #mdb_reader_check(). rlocked = . */ +static int ESECT +mdb_reader_check0(MDB_env *env, int rlocked, int *dead) +{ + mdb_mutexref_t rmutex = rlocked ? NULL : env->me_rmutex; + unsigned int i, j, rdrs; + MDB_reader *mr; + MDB_PID_T *pids, pid; + int rc = MDB_SUCCESS, count = 0; + + rdrs = env->me_txns->mti_numreaders; + pids = malloc((rdrs+1) * sizeof(MDB_PID_T)); + if (!pids) + return ENOMEM; + pids[0] = 0; + mr = env->me_txns->mti_readers; + for (i=0; ime_pid) { + if (mdb_pid_insert(pids, pid) == 0) { + if (!mdb_reader_pid(env, Pidcheck, pid)) { + /* Stale reader found */ + j = i; + if (rmutex) { + if ((rc = LOCK_MUTEX0(rmutex)) != 0) { + if ((rc = mdb_mutex_failed(env, rmutex, rc))) + break; + rdrs = 0; /* the above checked all readers */ + } else { + /* Recheck, a new process may have reused pid */ + if (mdb_reader_pid(env, Pidcheck, pid)) + j = rdrs; + } + } + for (; jme_rmutex); + if (!rlocked) { + /* Keep mti_txnid updated, otherwise next writer can + * overwrite data which latest meta page refers to. + */ + meta = mdb_env_pick_meta(env); + env->me_txns->mti_txnid = meta->mm_txnid; + /* env is hosed if the dead thread was ours */ + if (env->me_txn) { + env->me_flags |= MDB_FATAL_ERROR; + env->me_txn = NULL; + rc = MDB_PANIC; + } + } + DPRINTF(("%cmutex owner died, %s", (rlocked ? 'r' : 'w'), + (rc ? "this process' env is hosed" : "recovering"))); + rc2 = mdb_reader_check0(env, rlocked, NULL); + if (rc2 == 0) + rc2 = mdb_mutex_consistent(mutex); + if (rc || (rc = rc2)) { + DPRINTF(("LOCK_MUTEX recovery failed, %s", mdb_strerror(rc))); + UNLOCK_MUTEX(mutex); + } + } else { +#ifdef _WIN32 + rc = ErrCode(); +#endif + DPRINTF(("LOCK_MUTEX failed, %s", mdb_strerror(rc))); + } + + return rc; +} +#endif /* MDB_ROBUST_SUPPORTED */ +/** @} */ + +#if defined(_WIN32) +static int utf8_to_utf16(const char *src, int srcsize, wchar_t **dst, int *dstsize) +{ + int need; + wchar_t *result; + need = MultiByteToWideChar(CP_UTF8, 0, src, srcsize, NULL, 0); + if (need == 0xFFFD) + return EILSEQ; + if (need == 0) + return EINVAL; + result = malloc(sizeof(wchar_t) * need); + if (!result) + return ENOMEM; + MultiByteToWideChar(CP_UTF8, 0, src, srcsize, result, need); + if (dstsize) + *dstsize = need; + *dst = result; + return 0; +} +#endif /* defined(_WIN32) */ diff --git a/contrib/db/liblmdb/mdb_copy.1 b/contrib/db/liblmdb/mdb_copy.1 new file mode 100644 index 00000000..401e47ab --- /dev/null +++ b/contrib/db/liblmdb/mdb_copy.1 @@ -0,0 +1,60 @@ +.TH MDB_COPY 1 "2014/06/20" "LMDB 0.9.14" +.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved. +.\" Copying restrictions apply. See COPYRIGHT/LICENSE. +.SH NAME +mdb_copy \- LMDB environment copy tool +.SH SYNOPSIS +.B mdb_copy +[\c +.BR \-V ] +[\c +.BR \-c ] +[\c +.BR \-n ] +[\c +.BR \-v ] +.B srcpath +[\c +.BR dstpath ] +.SH DESCRIPTION +The +.B mdb_copy +utility copies an LMDB environment. The environment can +be copied regardless of whether it is currently in use. +No lockfile is created, since it gets recreated at need. + +If +.I dstpath +is specified it must be the path of an empty directory +for storing the backup. Otherwise, the backup will be +written to stdout. + +.SH OPTIONS +.TP +.BR \-V +Write the library version number to the standard output, and exit. +.TP +.BR \-c +Compact while copying. Only current data pages will be copied; freed +or unused pages will be omitted from the copy. This option will +slow down the backup process as it is more CPU-intensive. +.TP +.BR \-n +Open LDMB environment(s) which do not use subdirectories. +.TP +.BR \-v +Use the previous environment state instead of the latest state. +This may be useful if the latest state has been corrupted. + +.SH DIAGNOSTICS +Exit status is zero if no errors occur. +Errors result in a non-zero exit status and +a diagnostic message being written to standard error. +.SH CAVEATS +This utility can trigger significant file size growth if run +in parallel with write transactions, because pages which they +free during copying cannot be reused until the copy is done. +.SH "SEE ALSO" +.BR mdb_stat (1) +.SH AUTHOR +Howard Chu of Symas Corporation diff --git a/contrib/db/liblmdb/mdb_copy.c b/contrib/db/liblmdb/mdb_copy.c new file mode 100644 index 00000000..95a6e713 --- /dev/null +++ b/contrib/db/liblmdb/mdb_copy.c @@ -0,0 +1,84 @@ +/* mdb_copy.c - memory-mapped database backup tool */ +/* + * Copyright 2012-2015 Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +#ifdef _WIN32 +#include +#define MDB_STDOUT GetStdHandle(STD_OUTPUT_HANDLE) +#else +#define MDB_STDOUT 1 +#endif +#include +#include +#include +#include "lmdb.h" + +static void +sighandle(int sig) +{ +} + +int main(int argc,char * argv[]) +{ + int rc; + MDB_env *env; + const char *progname = argv[0], *act; + unsigned flags = MDB_RDONLY; + unsigned cpflags = 0; + + for (; argc > 1 && argv[1][0] == '-'; argc--, argv++) { + if (argv[1][1] == 'n' && argv[1][2] == '\0') + flags |= MDB_NOSUBDIR; + else if (argv[1][1] == 'v' && argv[1][2] == '\0') + flags |= MDB_PREVSNAPSHOT; + else if (argv[1][1] == 'c' && argv[1][2] == '\0') + cpflags |= MDB_CP_COMPACT; + else if (argv[1][1] == 'V' && argv[1][2] == '\0') { + printf("%s\n", MDB_VERSION_STRING); + exit(0); + } else + argc = 0; + } + + if (argc<2 || argc>3) { + fprintf(stderr, "usage: %s [-V] [-c] [-n] [-v] srcpath [dstpath]\n", progname); + exit(EXIT_FAILURE); + } + +#ifdef SIGPIPE + signal(SIGPIPE, sighandle); +#endif +#ifdef SIGHUP + signal(SIGHUP, sighandle); +#endif + signal(SIGINT, sighandle); + signal(SIGTERM, sighandle); + + act = "opening environment"; + rc = mdb_env_create(&env); + if (rc == MDB_SUCCESS) { + rc = mdb_env_open(env, argv[1], flags, 0600); + } + if (rc == MDB_SUCCESS) { + act = "copying"; + if (argc == 2) + rc = mdb_env_copyfd2(env, MDB_STDOUT, cpflags); + else + rc = mdb_env_copy2(env, argv[2], cpflags); + } + if (rc) + fprintf(stderr, "%s: %s failed, error %d (%s)\n", + progname, act, rc, mdb_strerror(rc)); + mdb_env_close(env); + + return rc ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/contrib/db/liblmdb/mdb_dump.1 b/contrib/db/liblmdb/mdb_dump.1 new file mode 100644 index 00000000..a25fb92e --- /dev/null +++ b/contrib/db/liblmdb/mdb_dump.1 @@ -0,0 +1,81 @@ +.TH MDB_DUMP 1 "2014/06/20" "LMDB 0.9.14" +.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved. +.\" Copying restrictions apply. See COPYRIGHT/LICENSE. +.SH NAME +mdb_dump \- LMDB environment export tool +.SH SYNOPSIS +.B mdb_dump +[\c +.BR \-V ] +[\c +.BI \-f \ file\fR] +[\c +.BR \-l ] +[\c +.BR \-n ] +[\c +.BR \-v ] +[\c +.BR \-p ] +[\c +.BR \-a \ | +.BI \-s \ subdb\fR] +.BR \ envpath +.SH DESCRIPTION +The +.B mdb_dump +utility reads a database and writes its contents to the +standard output using a portable flat-text format +understood by the +.BR mdb_load (1) +utility. +.SH OPTIONS +.TP +.BR \-V +Write the library version number to the standard output, and exit. +.TP +.BR \-f \ file +Write to the specified file instead of to the standard output. +.TP +.BR \-l +List the databases stored in the environment. Just the +names will be listed, no data will be output. +.TP +.BR \-n +Dump an LMDB database which does not use subdirectories. +.TP +.BR \-v +Use the previous environment state instead of the latest state. +This may be useful if the latest state has been corrupted. +.TP +.BR \-p +If characters in either the key or data items are printing characters (as +defined by isprint(3)), output them directly. This option permits users to +use standard text editors and tools to modify the contents of databases. + +Note: different systems may have different notions about what characters +are considered printing characters, and databases dumped in this manner may +be less portable to external systems. +.TP +.BR \-a +Dump all of the subdatabases in the environment. +.TP +.BR \-s \ subdb +Dump a specific subdatabase. If no database is specified, only the main database is dumped. +.SH DIAGNOSTICS +Exit status is zero if no errors occur. +Errors result in a non-zero exit status and +a diagnostic message being written to standard error. + +Dumping and reloading databases that use user-defined comparison functions +will result in new databases that use the default comparison functions. +\fBIn this case it is quite likely that the reloaded database will be +damaged beyond repair permitting neither record storage nor retrieval.\fP + +The only available workaround is to modify the source for the +.BR mdb_load (1) +utility to load the database using the correct comparison functions. +.SH "SEE ALSO" +.BR mdb_load (1) +.SH AUTHOR +Howard Chu of Symas Corporation diff --git a/contrib/db/liblmdb/mdb_dump.c b/contrib/db/liblmdb/mdb_dump.c new file mode 100644 index 00000000..7a42bc0b --- /dev/null +++ b/contrib/db/liblmdb/mdb_dump.c @@ -0,0 +1,330 @@ +/* mdb_dump.c - memory-mapped database dump tool */ +/* + * Copyright 2011-2015 Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +#include +#include +#include +#include +#include +#include +#include +#include "lmdb.h" + +#ifdef _WIN32 +#define Z "I" +#else +#define Z "z" +#endif +#ifdef MDB_VL32 +#ifdef _WIN32 +#define Y "I64" +#else +#define Y "ll" +#endif +#else +#define Y Z +#endif + +#define PRINT 1 +static int mode; + +typedef struct flagbit { + int bit; + char *name; +} flagbit; + +flagbit dbflags[] = { + { MDB_REVERSEKEY, "reversekey" }, + { MDB_DUPSORT, "dupsort" }, + { MDB_INTEGERKEY, "integerkey" }, + { MDB_DUPFIXED, "dupfixed" }, + { MDB_INTEGERDUP, "integerdup" }, + { MDB_REVERSEDUP, "reversedup" }, + { 0, NULL } +}; + +static volatile sig_atomic_t gotsig; + +static void dumpsig( int sig ) +{ + gotsig=1; +} + +static const char hexc[] = "0123456789abcdef"; + +static void hex(unsigned char c) +{ + putchar(hexc[c >> 4]); + putchar(hexc[c & 0xf]); +} + +static void text(MDB_val *v) +{ + unsigned char *c, *end; + + putchar(' '); + c = v->mv_data; + end = c + v->mv_size; + while (c < end) { + if (isprint(*c)) { + putchar(*c); + } else { + putchar('\\'); + hex(*c); + } + c++; + } + putchar('\n'); +} + +static void byte(MDB_val *v) +{ + unsigned char *c, *end; + + putchar(' '); + c = v->mv_data; + end = c + v->mv_size; + while (c < end) { + hex(*c++); + } + putchar('\n'); +} + +/* Dump in BDB-compatible format */ +static int dumpit(MDB_txn *txn, MDB_dbi dbi, char *name) +{ + MDB_cursor *mc; + MDB_stat ms; + MDB_val key, data; + MDB_envinfo info; + unsigned int flags; + int rc, i; + + rc = mdb_dbi_flags(txn, dbi, &flags); + if (rc) return rc; + + rc = mdb_stat(txn, dbi, &ms); + if (rc) return rc; + + rc = mdb_env_info(mdb_txn_env(txn), &info); + if (rc) return rc; + + printf("VERSION=3\n"); + printf("format=%s\n", mode & PRINT ? "print" : "bytevalue"); + if (name) + printf("database=%s\n", name); + printf("type=btree\n"); + printf("mapsize=%" Y "u\n", info.me_mapsize); + if (info.me_mapaddr) + printf("mapaddr=%p\n", info.me_mapaddr); + printf("maxreaders=%u\n", info.me_maxreaders); + + if (flags & MDB_DUPSORT) + printf("duplicates=1\n"); + + for (i=0; dbflags[i].bit; i++) + if (flags & dbflags[i].bit) + printf("%s=1\n", dbflags[i].name); + + printf("db_pagesize=%d\n", ms.ms_psize); + printf("HEADER=END\n"); + + rc = mdb_cursor_open(txn, dbi, &mc); + if (rc) return rc; + + while ((rc = mdb_cursor_get(mc, &key, &data, MDB_NEXT) == MDB_SUCCESS)) { + if (gotsig) { + rc = EINTR; + break; + } + if (mode & PRINT) { + text(&key); + text(&data); + } else { + byte(&key); + byte(&data); + } + } + printf("DATA=END\n"); + if (rc == MDB_NOTFOUND) + rc = MDB_SUCCESS; + + return rc; +} + +static void usage(char *prog) +{ + fprintf(stderr, "usage: %s [-V] [-f output] [-l] [-n] [-p] [-v] [-a|-s subdb] dbpath\n", prog); + exit(EXIT_FAILURE); +} + +int main(int argc, char *argv[]) +{ + int i, rc; + MDB_env *env; + MDB_txn *txn; + MDB_dbi dbi; + char *prog = argv[0]; + char *envname; + char *subname = NULL; + int alldbs = 0, envflags = 0, list = 0; + + if (argc < 2) { + usage(prog); + } + + /* -a: dump main DB and all subDBs + * -s: dump only the named subDB + * -n: use NOSUBDIR flag on env_open + * -p: use printable characters + * -f: write to file instead of stdout + * -v: use previous snapshot + * -V: print version and exit + * (default) dump only the main DB + */ + while ((i = getopt(argc, argv, "af:lnps:V")) != EOF) { + switch(i) { + case 'V': + printf("%s\n", MDB_VERSION_STRING); + exit(0); + break; + case 'l': + list = 1; + /*FALLTHROUGH*/; + case 'a': + if (subname) + usage(prog); + alldbs++; + break; + case 'f': + if (freopen(optarg, "w", stdout) == NULL) { + fprintf(stderr, "%s: %s: reopen: %s\n", + prog, optarg, strerror(errno)); + exit(EXIT_FAILURE); + } + break; + case 'n': + envflags |= MDB_NOSUBDIR; + break; + case 'v': + envflags |= MDB_PREVSNAPSHOT; + break; + case 'p': + mode |= PRINT; + break; + case 's': + if (alldbs) + usage(prog); + subname = optarg; + break; + default: + usage(prog); + } + } + + if (optind != argc - 1) + usage(prog); + +#ifdef SIGPIPE + signal(SIGPIPE, dumpsig); +#endif +#ifdef SIGHUP + signal(SIGHUP, dumpsig); +#endif + signal(SIGINT, dumpsig); + signal(SIGTERM, dumpsig); + + envname = argv[optind]; + rc = mdb_env_create(&env); + if (rc) { + fprintf(stderr, "mdb_env_create failed, error %d %s\n", rc, mdb_strerror(rc)); + return EXIT_FAILURE; + } + + if (alldbs || subname) { + mdb_env_set_maxdbs(env, 2); + } + + rc = mdb_env_open(env, envname, envflags | MDB_RDONLY, 0664); + if (rc) { + fprintf(stderr, "mdb_env_open failed, error %d %s\n", rc, mdb_strerror(rc)); + goto env_close; + } + + rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn); + if (rc) { + fprintf(stderr, "mdb_txn_begin failed, error %d %s\n", rc, mdb_strerror(rc)); + goto env_close; + } + + rc = mdb_open(txn, subname, 0, &dbi); + if (rc) { + fprintf(stderr, "mdb_open failed, error %d %s\n", rc, mdb_strerror(rc)); + goto txn_abort; + } + + if (alldbs) { + MDB_cursor *cursor; + MDB_val key; + int count = 0; + + rc = mdb_cursor_open(txn, dbi, &cursor); + if (rc) { + fprintf(stderr, "mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc)); + goto txn_abort; + } + while ((rc = mdb_cursor_get(cursor, &key, NULL, MDB_NEXT_NODUP)) == 0) { + char *str; + MDB_dbi db2; + if (memchr(key.mv_data, '\0', key.mv_size)) + continue; + count++; + str = malloc(key.mv_size+1); + memcpy(str, key.mv_data, key.mv_size); + str[key.mv_size] = '\0'; + rc = mdb_open(txn, str, 0, &db2); + if (rc == MDB_SUCCESS) { + if (list) { + printf("%s\n", str); + list++; + } else { + rc = dumpit(txn, db2, str); + if (rc) + break; + } + mdb_close(env, db2); + } + free(str); + if (rc) continue; + } + mdb_cursor_close(cursor); + if (!count) { + fprintf(stderr, "%s: %s does not contain multiple databases\n", prog, envname); + rc = MDB_NOTFOUND; + } else if (rc == MDB_NOTFOUND) { + rc = MDB_SUCCESS; + } + } else { + rc = dumpit(txn, dbi, subname); + } + if (rc && rc != MDB_NOTFOUND) + fprintf(stderr, "%s: %s: %s\n", prog, envname, mdb_strerror(rc)); + + mdb_close(env, dbi); +txn_abort: + mdb_txn_abort(txn); +env_close: + mdb_env_close(env); + + return rc ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/contrib/db/liblmdb/mdb_load.1 b/contrib/db/liblmdb/mdb_load.1 new file mode 100644 index 00000000..ede3702d --- /dev/null +++ b/contrib/db/liblmdb/mdb_load.1 @@ -0,0 +1,84 @@ +.TH MDB_LOAD 1 "2014/06/20" "LMDB 0.9.14" +.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved. +.\" Copying restrictions apply. See COPYRIGHT/LICENSE. +.SH NAME +mdb_load \- LMDB environment import tool +.SH SYNOPSIS +.B mdb_load +[\c +.BR \-V ] +[\c +.BI \-f \ file\fR] +[\c +.BR \-n ] +[\c +.BI \-s \ subdb\fR] +[\c +.BR \-N ] +[\c +.BR \-T ] +.BR \ envpath +.SH DESCRIPTION +The +.B mdb_load +utility reads from the standard input and loads it into the +LMDB environment +.BR envpath . + +The input to +.B mdb_load +must be in the output format specified by the +.BR mdb_dump (1) +utility or as specified by the +.B -T +option below. +.SH OPTIONS +.TP +.BR \-V +Write the library version number to the standard output, and exit. +.TP +.BR \-a +Append all records in the order they appear in the input. The input is assumed to already be +in correctly sorted order and no sorting or checking for redundant values will be performed. +This option must be used to reload data that was produced by running +.B mdb_dump +on a database that uses custom compare functions. +.TP +.BR \-f \ file +Read from the specified file instead of from the standard input. +.TP +.BR \-n +Load an LMDB database which does not use subdirectories. +.TP +.BR \-s \ subdb +Load a specific subdatabase. If no database is specified, data is loaded into the main database. +.TP +.BR \-N +Don't overwrite existing records when loading into an already existing database; just skip them. +.TP +.BR \-T +Load data from simple text files. The input must be paired lines of text, where the first +line of the pair is the key item, and the second line of the pair is its corresponding +data item. + +A simple escape mechanism, where newline and backslash (\\) characters are special, is +applied to the text input. Newline characters are interpreted as record separators. +Backslash characters in the text will be interpreted in one of two ways: If the backslash +character precedes another backslash character, the pair will be interpreted as a literal +backslash. If the backslash character precedes any other character, the two characters +following the backslash will be interpreted as a hexadecimal specification of a single +character; for example, \\0a is a newline character in the ASCII character set. + +For this reason, any backslash or newline characters that naturally occur in the text +input must be escaped to avoid misinterpretation by +.BR mdb_load . + +.SH DIAGNOSTICS +Exit status is zero if no errors occur. +Errors result in a non-zero exit status and +a diagnostic message being written to standard error. + +.SH "SEE ALSO" +.BR mdb_dump (1) +.SH AUTHOR +Howard Chu of Symas Corporation diff --git a/contrib/db/liblmdb/mdb_load.c b/contrib/db/liblmdb/mdb_load.c new file mode 100644 index 00000000..797c2f97 --- /dev/null +++ b/contrib/db/liblmdb/mdb_load.c @@ -0,0 +1,499 @@ +/* mdb_load.c - memory-mapped database load tool */ +/* + * Copyright 2011-2015 Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +#include +#include +#include +#include +#include +#include +#include "lmdb.h" + +#define PRINT 1 +#define NOHDR 2 +static int mode; + +static char *subname = NULL; + +static size_t lineno; +static int version; + +static int flags; + +static char *prog; + +static int Eof; + +static MDB_envinfo info; + +static MDB_val kbuf, dbuf; +static MDB_val k0buf; + +#ifdef _WIN32 +#define Z "I" +#else +#define Z "z" +#endif +#ifdef MDB_VL32 +#ifdef _WIN32 +#define Y "I64" +#else +#define Y "ll" +#endif +#else +#define Y Z +#endif + +#define STRLENOF(s) (sizeof(s)-1) + +typedef struct flagbit { + int bit; + char *name; + int len; +} flagbit; + +#define S(s) s, STRLENOF(s) + +flagbit dbflags[] = { + { MDB_REVERSEKEY, S("reversekey") }, + { MDB_DUPSORT, S("dupsort") }, + { MDB_INTEGERKEY, S("integerkey") }, + { MDB_DUPFIXED, S("dupfixed") }, + { MDB_INTEGERDUP, S("integerdup") }, + { MDB_REVERSEDUP, S("reversedup") }, + { 0, NULL, 0 } +}; + +static void readhdr(void) +{ + char *ptr; + + while (fgets(dbuf.mv_data, dbuf.mv_size, stdin) != NULL) { + lineno++; + if (!strncmp(dbuf.mv_data, "VERSION=", STRLENOF("VERSION="))) { + version=atoi((char *)dbuf.mv_data+STRLENOF("VERSION=")); + if (version > 3) { + fprintf(stderr, "%s: line %" Z "d: unsupported VERSION %d\n", + prog, lineno, version); + exit(EXIT_FAILURE); + } + } else if (!strncmp(dbuf.mv_data, "HEADER=END", STRLENOF("HEADER=END"))) { + break; + } else if (!strncmp(dbuf.mv_data, "format=", STRLENOF("format="))) { + if (!strncmp((char *)dbuf.mv_data+STRLENOF("FORMAT="), "print", STRLENOF("print"))) + mode |= PRINT; + else if (strncmp((char *)dbuf.mv_data+STRLENOF("FORMAT="), "bytevalue", STRLENOF("bytevalue"))) { + fprintf(stderr, "%s: line %" Z "d: unsupported FORMAT %s\n", + prog, lineno, (char *)dbuf.mv_data+STRLENOF("FORMAT=")); + exit(EXIT_FAILURE); + } + } else if (!strncmp(dbuf.mv_data, "database=", STRLENOF("database="))) { + ptr = memchr(dbuf.mv_data, '\n', dbuf.mv_size); + if (ptr) *ptr = '\0'; + if (subname) free(subname); + subname = strdup((char *)dbuf.mv_data+STRLENOF("database=")); + } else if (!strncmp(dbuf.mv_data, "type=", STRLENOF("type="))) { + if (strncmp((char *)dbuf.mv_data+STRLENOF("type="), "btree", STRLENOF("btree"))) { + fprintf(stderr, "%s: line %" Z "d: unsupported type %s\n", + prog, lineno, (char *)dbuf.mv_data+STRLENOF("type=")); + exit(EXIT_FAILURE); + } + } else if (!strncmp(dbuf.mv_data, "mapaddr=", STRLENOF("mapaddr="))) { + int i; + ptr = memchr(dbuf.mv_data, '\n', dbuf.mv_size); + if (ptr) *ptr = '\0'; + i = sscanf((char *)dbuf.mv_data+STRLENOF("mapaddr="), "%p", &info.me_mapaddr); + if (i != 1) { + fprintf(stderr, "%s: line %" Z "d: invalid mapaddr %s\n", + prog, lineno, (char *)dbuf.mv_data+STRLENOF("mapaddr=")); + exit(EXIT_FAILURE); + } + } else if (!strncmp(dbuf.mv_data, "mapsize=", STRLENOF("mapsize="))) { + int i; + ptr = memchr(dbuf.mv_data, '\n', dbuf.mv_size); + if (ptr) *ptr = '\0'; + i = sscanf((char *)dbuf.mv_data+STRLENOF("mapsize="), "%" Y "u", &info.me_mapsize); + if (i != 1) { + fprintf(stderr, "%s: line %" Z "d: invalid mapsize %s\n", + prog, lineno, (char *)dbuf.mv_data+STRLENOF("mapsize=")); + exit(EXIT_FAILURE); + } + } else if (!strncmp(dbuf.mv_data, "maxreaders=", STRLENOF("maxreaders="))) { + int i; + ptr = memchr(dbuf.mv_data, '\n', dbuf.mv_size); + if (ptr) *ptr = '\0'; + i = sscanf((char *)dbuf.mv_data+STRLENOF("maxreaders="), "%u", &info.me_maxreaders); + if (i != 1) { + fprintf(stderr, "%s: line %" Z "d: invalid maxreaders %s\n", + prog, lineno, (char *)dbuf.mv_data+STRLENOF("maxreaders=")); + exit(EXIT_FAILURE); + } + } else { + int i; + for (i=0; dbflags[i].bit; i++) { + if (!strncmp(dbuf.mv_data, dbflags[i].name, dbflags[i].len) && + ((char *)dbuf.mv_data)[dbflags[i].len] == '=') { + flags |= dbflags[i].bit; + break; + } + } + if (!dbflags[i].bit) { + ptr = memchr(dbuf.mv_data, '=', dbuf.mv_size); + if (!ptr) { + fprintf(stderr, "%s: line %" Z "d: unexpected format\n", + prog, lineno); + exit(EXIT_FAILURE); + } else { + *ptr = '\0'; + fprintf(stderr, "%s: line %" Z "d: unrecognized keyword ignored: %s\n", + prog, lineno, (char *)dbuf.mv_data); + } + } + } + } +} + +static void badend(void) +{ + fprintf(stderr, "%s: line %" Z "d: unexpected end of input\n", + prog, lineno); +} + +static int unhex(unsigned char *c2) +{ + int x, c; + x = *c2++ & 0x4f; + if (x & 0x40) + x -= 55; + c = x << 4; + x = *c2 & 0x4f; + if (x & 0x40) + x -= 55; + c |= x; + return c; +} + +static int readline(MDB_val *out, MDB_val *buf) +{ + unsigned char *c1, *c2, *end; + size_t len, l2; + int c; + + if (!(mode & NOHDR)) { + c = fgetc(stdin); + if (c == EOF) { + Eof = 1; + return EOF; + } + if (c != ' ') { + lineno++; + if (fgets(buf->mv_data, buf->mv_size, stdin) == NULL) { +badend: + Eof = 1; + badend(); + return EOF; + } + if (c == 'D' && !strncmp(buf->mv_data, "ATA=END", STRLENOF("ATA=END"))) + return EOF; + goto badend; + } + } + if (fgets(buf->mv_data, buf->mv_size, stdin) == NULL) { + Eof = 1; + return EOF; + } + lineno++; + + c1 = buf->mv_data; + len = strlen((char *)c1); + l2 = len; + + /* Is buffer too short? */ + while (c1[len-1] != '\n') { + buf->mv_data = realloc(buf->mv_data, buf->mv_size*2); + if (!buf->mv_data) { + Eof = 1; + fprintf(stderr, "%s: line %" Z "d: out of memory, line too long\n", + prog, lineno); + return EOF; + } + c1 = buf->mv_data; + c1 += l2; + if (fgets((char *)c1, buf->mv_size+1, stdin) == NULL) { + Eof = 1; + badend(); + return EOF; + } + buf->mv_size *= 2; + len = strlen((char *)c1); + l2 += len; + } + c1 = c2 = buf->mv_data; + len = l2; + c1[--len] = '\0'; + end = c1 + len; + + if (mode & PRINT) { + while (c2 < end) { + if (*c2 == '\\') { + if (c2[1] == '\\') { + c1++; c2 += 2; + } else { + if (c2+3 > end || !isxdigit(c2[1]) || !isxdigit(c2[2])) { + Eof = 1; + badend(); + return EOF; + } + *c1++ = unhex(++c2); + c2 += 2; + } + } else { + c1++; c2++; + } + } + } else { + /* odd length not allowed */ + if (len & 1) { + Eof = 1; + badend(); + return EOF; + } + while (c2 < end) { + if (!isxdigit(*c2) || !isxdigit(c2[1])) { + Eof = 1; + badend(); + return EOF; + } + *c1++ = unhex(c2); + c2 += 2; + } + } + c2 = out->mv_data = buf->mv_data; + out->mv_size = c1 - c2; + + return 0; +} + +static void usage(void) +{ + fprintf(stderr, "usage: %s [-V] [-a] [-f input] [-n] [-s name] [-N] [-T] dbpath\n", prog); + exit(EXIT_FAILURE); +} + +static int greater(const MDB_val *a, const MDB_val *b) +{ + return 1; +} + +int main(int argc, char *argv[]) +{ + int i, rc; + MDB_env *env; + MDB_txn *txn; + MDB_cursor *mc; + MDB_dbi dbi; + char *envname; + int envflags = 0, putflags = 0; + int dohdr = 0, append = 0; + MDB_val prevk; + + prog = argv[0]; + + if (argc < 2) { + usage(); + } + + /* -a: append records in input order + * -f: load file instead of stdin + * -n: use NOSUBDIR flag on env_open + * -s: load into named subDB + * -N: use NOOVERWRITE on puts + * -T: read plaintext + * -V: print version and exit + */ + while ((i = getopt(argc, argv, "af:ns:NTV")) != EOF) { + switch(i) { + case 'V': + printf("%s\n", MDB_VERSION_STRING); + exit(0); + break; + case 'a': + append = 1; + break; + case 'f': + if (freopen(optarg, "r", stdin) == NULL) { + fprintf(stderr, "%s: %s: reopen: %s\n", + prog, optarg, strerror(errno)); + exit(EXIT_FAILURE); + } + break; + case 'n': + envflags |= MDB_NOSUBDIR; + break; + case 's': + subname = strdup(optarg); + break; + case 'N': + putflags = MDB_NOOVERWRITE|MDB_NODUPDATA; + break; + case 'T': + mode |= NOHDR | PRINT; + break; + default: + usage(); + } + } + + if (optind != argc - 1) + usage(); + + dbuf.mv_size = 4096; + dbuf.mv_data = malloc(dbuf.mv_size); + + if (!(mode & NOHDR)) + readhdr(); + + envname = argv[optind]; + rc = mdb_env_create(&env); + if (rc) { + fprintf(stderr, "mdb_env_create failed, error %d %s\n", rc, mdb_strerror(rc)); + return EXIT_FAILURE; + } + + mdb_env_set_maxdbs(env, 2); + + if (info.me_maxreaders) + mdb_env_set_maxreaders(env, info.me_maxreaders); + + if (info.me_mapsize) + mdb_env_set_mapsize(env, info.me_mapsize); + + if (info.me_mapaddr) + envflags |= MDB_FIXEDMAP; + + rc = mdb_env_open(env, envname, envflags, 0664); + if (rc) { + fprintf(stderr, "mdb_env_open failed, error %d %s\n", rc, mdb_strerror(rc)); + goto env_close; + } + + kbuf.mv_size = mdb_env_get_maxkeysize(env) * 2 + 2; + kbuf.mv_data = malloc(kbuf.mv_size * 2); + k0buf.mv_size = kbuf.mv_size; + k0buf.mv_data = (char *)kbuf.mv_data + kbuf.mv_size; + prevk.mv_size = 0; + prevk.mv_data = k0buf.mv_data; + + while(!Eof) { + MDB_val key, data; + int batch = 0; + flags = 0; + int appflag; + + if (!dohdr) { + dohdr = 1; + } else if (!(mode & NOHDR)) + readhdr(); + + rc = mdb_txn_begin(env, NULL, 0, &txn); + if (rc) { + fprintf(stderr, "mdb_txn_begin failed, error %d %s\n", rc, mdb_strerror(rc)); + goto env_close; + } + + rc = mdb_open(txn, subname, flags|MDB_CREATE, &dbi); + if (rc) { + fprintf(stderr, "mdb_open failed, error %d %s\n", rc, mdb_strerror(rc)); + goto txn_abort; + } + if (append) { + mdb_set_compare(txn, dbi, greater); + if (flags & MDB_DUPSORT) + mdb_set_dupsort(txn, dbi, greater); + } + + rc = mdb_cursor_open(txn, dbi, &mc); + if (rc) { + fprintf(stderr, "mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc)); + goto txn_abort; + } + + while(1) { + rc = readline(&key, &kbuf); + if (rc) /* rc == EOF */ + break; + + rc = readline(&data, &dbuf); + if (rc) { + fprintf(stderr, "%s: line %" Z "d: failed to read key value\n", prog, lineno); + goto txn_abort; + } + + if (append) { + appflag = MDB_APPEND; + if (flags & MDB_DUPSORT) { + if (prevk.mv_size == key.mv_size && !memcmp(prevk.mv_data, key.mv_data, key.mv_size)) + appflag = MDB_APPENDDUP; + else { + memcpy(prevk.mv_data, key.mv_data, key.mv_size); + prevk.mv_size = key.mv_size; + } + } + } else { + appflag = 0; + } + rc = mdb_cursor_put(mc, &key, &data, putflags|appflag); + if (rc == MDB_KEYEXIST && putflags) + continue; + if (rc) { + fprintf(stderr, "mdb_cursor_put failed, error %d %s\n", rc, mdb_strerror(rc)); + goto txn_abort; + } + batch++; + if (batch == 100) { + rc = mdb_txn_commit(txn); + if (rc) { + fprintf(stderr, "%s: line %" Z "d: txn_commit: %s\n", + prog, lineno, mdb_strerror(rc)); + goto env_close; + } + rc = mdb_txn_begin(env, NULL, 0, &txn); + if (rc) { + fprintf(stderr, "mdb_txn_begin failed, error %d %s\n", rc, mdb_strerror(rc)); + goto env_close; + } + rc = mdb_cursor_open(txn, dbi, &mc); + if (rc) { + fprintf(stderr, "mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc)); + goto txn_abort; + } + batch = 0; + } + } + rc = mdb_txn_commit(txn); + txn = NULL; + if (rc) { + fprintf(stderr, "%s: line %" Z "d: txn_commit: %s\n", + prog, lineno, mdb_strerror(rc)); + goto env_close; + } + mdb_dbi_close(env, dbi); + } + +txn_abort: + mdb_txn_abort(txn); +env_close: + mdb_env_close(env); + + return rc ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/contrib/db/liblmdb/mdb_stat.1 b/contrib/db/liblmdb/mdb_stat.1 new file mode 100644 index 00000000..bf49bd3b --- /dev/null +++ b/contrib/db/liblmdb/mdb_stat.1 @@ -0,0 +1,70 @@ +.TH MDB_STAT 1 "2014/06/20" "LMDB 0.9.14" +.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved. +.\" Copying restrictions apply. See COPYRIGHT/LICENSE. +.SH NAME +mdb_stat \- LMDB environment status tool +.SH SYNOPSIS +.B mdb_stat +[\c +.BR \-V ] +[\c +.BR \-e ] +[\c +.BR \-f [ f [ f ]]] +[\c +.BR \-n ] +[\c +.BR \-v ] +[\c +.BR \-r [ r ]] +[\c +.BR \-a \ | +.BI \-s \ subdb\fR] +.BR \ envpath +.SH DESCRIPTION +The +.B mdb_stat +utility displays the status of an LMDB environment. +.SH OPTIONS +.TP +.BR \-V +Write the library version number to the standard output, and exit. +.TP +.BR \-e +Display information about the database environment. +.TP +.BR \-f +Display information about the environment freelist. +If \fB\-ff\fP is given, summarize each freelist entry. +If \fB\-fff\fP is given, display the full list of page IDs in the freelist. +.TP +.BR \-n +Display the status of an LMDB database which does not use subdirectories. +.TP +.BR \-v +Use the previous environment state instead of the latest state. +This may be useful if the latest state has been corrupted. +.TP +.BR \-r +Display information about the environment reader table. +Shows the process ID, thread ID, and transaction ID for each active +reader slot. The process ID and transaction ID are in decimal, the +thread ID is in hexadecimal. The transaction ID is displayed as "-" +if the reader does not currently have a read transaction open. +If \fB\-rr\fP is given, check for stale entries in the reader +table and clear them. The reader table will be printed again +after the check is performed. +.TP +.BR \-a +Display the status of all of the subdatabases in the environment. +.TP +.BR \-s \ subdb +Display the status of a specific subdatabase. +.SH DIAGNOSTICS +Exit status is zero if no errors occur. +Errors result in a non-zero exit status and +a diagnostic message being written to standard error. +.SH "SEE ALSO" +.BR mdb_copy (1) +.SH AUTHOR +Howard Chu of Symas Corporation diff --git a/contrib/db/liblmdb/mdb_stat.c b/contrib/db/liblmdb/mdb_stat.c new file mode 100644 index 00000000..30ec81fe --- /dev/null +++ b/contrib/db/liblmdb/mdb_stat.c @@ -0,0 +1,276 @@ +/* mdb_stat.c - memory-mapped database status tool */ +/* + * Copyright 2011-2015 Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +#include +#include +#include +#include +#include "lmdb.h" + +#ifdef _WIN32 +#define Z "I" +#else +#define Z "z" +#endif +#ifdef MDB_VL32 +#ifdef _WIN32 +#define Y "I64" +#else +#define Y "ll" +#endif +#else +#define Y Z +#endif + +static void prstat(MDB_stat *ms) +{ +#if 0 + printf(" Page size: %u\n", ms->ms_psize); +#endif + printf(" Tree depth: %u\n", ms->ms_depth); + printf(" Branch pages: %"Y"u\n", ms->ms_branch_pages); + printf(" Leaf pages: %"Y"u\n", ms->ms_leaf_pages); + printf(" Overflow pages: %"Y"u\n", ms->ms_overflow_pages); + printf(" Entries: %"Y"u\n", ms->ms_entries); +} + +static void usage(char *prog) +{ + fprintf(stderr, "usage: %s [-V] [-n] [-e] [-r[r]] [-f[f[f]]] [-v] [-a|-s subdb] dbpath\n", prog); + exit(EXIT_FAILURE); +} + +int main(int argc, char *argv[]) +{ + int i, rc; + MDB_env *env; + MDB_txn *txn; + MDB_dbi dbi; + MDB_stat mst; + MDB_envinfo mei; + char *prog = argv[0]; + char *envname; + char *subname = NULL; + int alldbs = 0, envinfo = 0, envflags = 0, freinfo = 0, rdrinfo = 0; + + if (argc < 2) { + usage(prog); + } + + /* -a: print stat of main DB and all subDBs + * -s: print stat of only the named subDB + * -e: print env info + * -f: print freelist info + * -r: print reader info + * -n: use NOSUBDIR flag on env_open + * -v: use previous snapshot + * -V: print version and exit + * (default) print stat of only the main DB + */ + while ((i = getopt(argc, argv, "Vaefnrs:")) != EOF) { + switch(i) { + case 'V': + printf("%s\n", MDB_VERSION_STRING); + exit(0); + break; + case 'a': + if (subname) + usage(prog); + alldbs++; + break; + case 'e': + envinfo++; + break; + case 'f': + freinfo++; + break; + case 'n': + envflags |= MDB_NOSUBDIR; + break; + case 'v': + envflags |= MDB_PREVSNAPSHOT; + break; + case 'r': + rdrinfo++; + break; + case 's': + if (alldbs) + usage(prog); + subname = optarg; + break; + default: + usage(prog); + } + } + + if (optind != argc - 1) + usage(prog); + + envname = argv[optind]; + rc = mdb_env_create(&env); + if (rc) { + fprintf(stderr, "mdb_env_create failed, error %d %s\n", rc, mdb_strerror(rc)); + return EXIT_FAILURE; + } + + if (alldbs || subname) { + mdb_env_set_maxdbs(env, 4); + } + + rc = mdb_env_open(env, envname, envflags | MDB_RDONLY, 0664); + if (rc) { + fprintf(stderr, "mdb_env_open failed, error %d %s\n", rc, mdb_strerror(rc)); + goto env_close; + } + + if (envinfo) { + (void)mdb_env_stat(env, &mst); + (void)mdb_env_info(env, &mei); + printf("Environment Info\n"); + printf(" Map address: %p\n", mei.me_mapaddr); + printf(" Map size: %"Y"u\n", mei.me_mapsize); + printf(" Page size: %u\n", mst.ms_psize); + printf(" Max pages: %"Y"u\n", mei.me_mapsize / mst.ms_psize); + printf(" Number of pages used: %"Y"u\n", mei.me_last_pgno+1); + printf(" Last transaction ID: %"Y"u\n", mei.me_last_txnid); + printf(" Max readers: %u\n", mei.me_maxreaders); + printf(" Number of readers used: %u\n", mei.me_numreaders); + } + + if (rdrinfo) { + printf("Reader Table Status\n"); + rc = mdb_reader_list(env, (MDB_msg_func *)fputs, stdout); + if (rdrinfo > 1) { + int dead; + mdb_reader_check(env, &dead); + printf(" %d stale readers cleared.\n", dead); + rc = mdb_reader_list(env, (MDB_msg_func *)fputs, stdout); + } + if (!(subname || alldbs || freinfo)) + goto env_close; + } + + rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn); + if (rc) { + fprintf(stderr, "mdb_txn_begin failed, error %d %s\n", rc, mdb_strerror(rc)); + goto env_close; + } + + if (freinfo) { + MDB_cursor *cursor; + MDB_val key, data; + size_t pages = 0, *iptr; + + printf("Freelist Status\n"); + dbi = 0; + rc = mdb_cursor_open(txn, dbi, &cursor); + if (rc) { + fprintf(stderr, "mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc)); + goto txn_abort; + } + rc = mdb_stat(txn, dbi, &mst); + if (rc) { + fprintf(stderr, "mdb_stat failed, error %d %s\n", rc, mdb_strerror(rc)); + goto txn_abort; + } + prstat(&mst); + while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { + iptr = data.mv_data; + pages += *iptr; + if (freinfo > 1) { + char *bad = ""; + size_t pg, prev; + ssize_t i, j, span = 0; + j = *iptr++; + for (i = j, prev = 1; --i >= 0; ) { + pg = iptr[i]; + if (pg <= prev) + bad = " [bad sequence]"; + prev = pg; + pg += span; + for (; i >= span && iptr[i-span] == pg; span++, pg++) ; + } + printf(" Transaction %"Z"u, %"Z"d pages, maxspan %"Z"d%s\n", + *(size_t *)key.mv_data, j, span, bad); + if (freinfo > 2) { + for (--j; j >= 0; ) { + pg = iptr[j]; + for (span=1; --j >= 0 && iptr[j] == pg+span; span++) ; + printf(span>1 ? " %9"Z"u[%"Z"d]\n" : " %9"Z"u\n", + pg, span); + } + } + } + } + mdb_cursor_close(cursor); + printf(" Free pages: %"Z"u\n", pages); + } + + rc = mdb_open(txn, subname, 0, &dbi); + if (rc) { + fprintf(stderr, "mdb_open failed, error %d %s\n", rc, mdb_strerror(rc)); + goto txn_abort; + } + + rc = mdb_stat(txn, dbi, &mst); + if (rc) { + fprintf(stderr, "mdb_stat failed, error %d %s\n", rc, mdb_strerror(rc)); + goto txn_abort; + } + printf("Status of %s\n", subname ? subname : "Main DB"); + prstat(&mst); + + if (alldbs) { + MDB_cursor *cursor; + MDB_val key; + + rc = mdb_cursor_open(txn, dbi, &cursor); + if (rc) { + fprintf(stderr, "mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc)); + goto txn_abort; + } + while ((rc = mdb_cursor_get(cursor, &key, NULL, MDB_NEXT_NODUP)) == 0) { + char *str; + MDB_dbi db2; + if (memchr(key.mv_data, '\0', key.mv_size)) + continue; + str = malloc(key.mv_size+1); + memcpy(str, key.mv_data, key.mv_size); + str[key.mv_size] = '\0'; + rc = mdb_open(txn, str, 0, &db2); + if (rc == MDB_SUCCESS) + printf("Status of %s\n", str); + free(str); + if (rc) continue; + rc = mdb_stat(txn, db2, &mst); + if (rc) { + fprintf(stderr, "mdb_stat failed, error %d %s\n", rc, mdb_strerror(rc)); + goto txn_abort; + } + prstat(&mst); + mdb_close(env, db2); + } + mdb_cursor_close(cursor); + } + + if (rc == MDB_NOTFOUND) + rc = MDB_SUCCESS; + + mdb_close(env, dbi); +txn_abort: + mdb_txn_abort(txn); +env_close: + mdb_env_close(env); + + return rc ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/contrib/db/liblmdb/midl.c b/contrib/db/liblmdb/midl.c new file mode 100644 index 00000000..152a1ec0 --- /dev/null +++ b/contrib/db/liblmdb/midl.c @@ -0,0 +1,420 @@ +/** @file midl.c + * @brief ldap bdb back-end ID List functions */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 2000-2015 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ + +#include +#include +#include +#include +#include +#include "midl.h" + +/** @defgroup internal LMDB Internals + * @{ + */ +/** @defgroup idls ID List Management + * @{ + */ +#define CMP(x,y) ( (x) < (y) ? -1 : (x) > (y) ) + +unsigned mdb_midl_search( MDB_IDL ids, MDB_ID id ) +{ + /* + * binary search of id in ids + * if found, returns position of id + * if not found, returns first position greater than id + */ + unsigned base = 0; + unsigned cursor = 1; + int val = 0; + unsigned n = ids[0]; + + while( 0 < n ) { + unsigned pivot = n >> 1; + cursor = base + pivot + 1; + val = CMP( ids[cursor], id ); + + if( val < 0 ) { + n = pivot; + + } else if ( val > 0 ) { + base = cursor; + n -= pivot + 1; + + } else { + return cursor; + } + } + + if( val > 0 ) { + ++cursor; + } + return cursor; +} + +#if 0 /* superseded by append/sort */ +int mdb_midl_insert( MDB_IDL ids, MDB_ID id ) +{ + unsigned x, i; + + x = mdb_midl_search( ids, id ); + assert( x > 0 ); + + if( x < 1 ) { + /* internal error */ + return -2; + } + + if ( x <= ids[0] && ids[x] == id ) { + /* duplicate */ + assert(0); + return -1; + } + + if ( ++ids[0] >= MDB_IDL_DB_MAX ) { + /* no room */ + --ids[0]; + return -2; + + } else { + /* insert id */ + for (i=ids[0]; i>x; i--) + ids[i] = ids[i-1]; + ids[x] = id; + } + + return 0; +} +#endif + +MDB_IDL mdb_midl_alloc(int num) +{ + MDB_IDL ids = malloc((num+2) * sizeof(MDB_ID)); + if (ids) { + *ids++ = num; + *ids = 0; + } + return ids; +} + +void mdb_midl_free(MDB_IDL ids) +{ + if (ids) + free(ids-1); +} + +void mdb_midl_shrink( MDB_IDL *idp ) +{ + MDB_IDL ids = *idp; + if (*(--ids) > MDB_IDL_UM_MAX && + (ids = realloc(ids, (MDB_IDL_UM_MAX+2) * sizeof(MDB_ID)))) + { + *ids++ = MDB_IDL_UM_MAX; + *idp = ids; + } +} + +static int mdb_midl_grow( MDB_IDL *idp, int num ) +{ + MDB_IDL idn = *idp-1; + /* grow it */ + idn = realloc(idn, (*idn + num + 2) * sizeof(MDB_ID)); + if (!idn) + return ENOMEM; + *idn++ += num; + *idp = idn; + return 0; +} + +int mdb_midl_need( MDB_IDL *idp, unsigned num ) +{ + MDB_IDL ids = *idp; + num += ids[0]; + if (num > ids[-1]) { + num = (num + num/4 + (256 + 2)) & -256; + if (!(ids = realloc(ids-1, num * sizeof(MDB_ID)))) + return ENOMEM; + *ids++ = num - 2; + *idp = ids; + } + return 0; +} + +int mdb_midl_append( MDB_IDL *idp, MDB_ID id ) +{ + MDB_IDL ids = *idp; + /* Too big? */ + if (ids[0] >= ids[-1]) { + if (mdb_midl_grow(idp, MDB_IDL_UM_MAX)) + return ENOMEM; + ids = *idp; + } + ids[0]++; + ids[ids[0]] = id; + return 0; +} + +int mdb_midl_append_list( MDB_IDL *idp, MDB_IDL app ) +{ + MDB_IDL ids = *idp; + /* Too big? */ + if (ids[0] + app[0] >= ids[-1]) { + if (mdb_midl_grow(idp, app[0])) + return ENOMEM; + ids = *idp; + } + memcpy(&ids[ids[0]+1], &app[1], app[0] * sizeof(MDB_ID)); + ids[0] += app[0]; + return 0; +} + +int mdb_midl_append_range( MDB_IDL *idp, MDB_ID id, unsigned n ) +{ + MDB_ID *ids = *idp, len = ids[0]; + /* Too big? */ + if (len + n > ids[-1]) { + if (mdb_midl_grow(idp, n | MDB_IDL_UM_MAX)) + return ENOMEM; + ids = *idp; + } + ids[0] = len + n; + ids += len; + while (n) + ids[n--] = id++; + return 0; +} + +void mdb_midl_xmerge( MDB_IDL idl, MDB_IDL merge ) +{ + MDB_ID old_id, merge_id, i = merge[0], j = idl[0], k = i+j, total = k; + idl[0] = (MDB_ID)-1; /* delimiter for idl scan below */ + old_id = idl[j]; + while (i) { + merge_id = merge[i--]; + for (; old_id < merge_id; old_id = idl[--j]) + idl[k--] = old_id; + idl[k--] = merge_id; + } + idl[0] = total; +} + +/* Quicksort + Insertion sort for small arrays */ + +#define SMALL 8 +#define MIDL_SWAP(a,b) { itmp=(a); (a)=(b); (b)=itmp; } + +void +mdb_midl_sort( MDB_IDL ids ) +{ + /* Max possible depth of int-indexed tree * 2 items/level */ + int istack[sizeof(int)*CHAR_BIT * 2]; + int i,j,k,l,ir,jstack; + MDB_ID a, itmp; + + ir = (int)ids[0]; + l = 1; + jstack = 0; + for(;;) { + if (ir - l < SMALL) { /* Insertion sort */ + for (j=l+1;j<=ir;j++) { + a = ids[j]; + for (i=j-1;i>=1;i--) { + if (ids[i] >= a) break; + ids[i+1] = ids[i]; + } + ids[i+1] = a; + } + if (jstack == 0) break; + ir = istack[jstack--]; + l = istack[jstack--]; + } else { + k = (l + ir) >> 1; /* Choose median of left, center, right */ + MIDL_SWAP(ids[k], ids[l+1]); + if (ids[l] < ids[ir]) { + MIDL_SWAP(ids[l], ids[ir]); + } + if (ids[l+1] < ids[ir]) { + MIDL_SWAP(ids[l+1], ids[ir]); + } + if (ids[l] < ids[l+1]) { + MIDL_SWAP(ids[l], ids[l+1]); + } + i = l+1; + j = ir; + a = ids[l+1]; + for(;;) { + do i++; while(ids[i] > a); + do j--; while(ids[j] < a); + if (j < i) break; + MIDL_SWAP(ids[i],ids[j]); + } + ids[l+1] = ids[j]; + ids[j] = a; + jstack += 2; + if (ir-i+1 >= j-l) { + istack[jstack] = ir; + istack[jstack-1] = i; + ir = j-1; + } else { + istack[jstack] = j-1; + istack[jstack-1] = l; + l = i; + } + } + } +} + +unsigned mdb_mid2l_search( MDB_ID2L ids, MDB_ID id ) +{ + /* + * binary search of id in ids + * if found, returns position of id + * if not found, returns first position greater than id + */ + unsigned base = 0; + unsigned cursor = 1; + int val = 0; + unsigned n = (unsigned)ids[0].mid; + + while( 0 < n ) { + unsigned pivot = n >> 1; + cursor = base + pivot + 1; + val = CMP( id, ids[cursor].mid ); + + if( val < 0 ) { + n = pivot; + + } else if ( val > 0 ) { + base = cursor; + n -= pivot + 1; + + } else { + return cursor; + } + } + + if( val > 0 ) { + ++cursor; + } + return cursor; +} + +int mdb_mid2l_insert( MDB_ID2L ids, MDB_ID2 *id ) +{ + unsigned x, i; + + x = mdb_mid2l_search( ids, id->mid ); + + if( x < 1 ) { + /* internal error */ + return -2; + } + + if ( x <= ids[0].mid && ids[x].mid == id->mid ) { + /* duplicate */ + return -1; + } + + if ( ids[0].mid >= MDB_IDL_UM_MAX ) { + /* too big */ + return -2; + + } else { + /* insert id */ + ids[0].mid++; + for (i=(unsigned)ids[0].mid; i>x; i--) + ids[i] = ids[i-1]; + ids[x] = *id; + } + + return 0; +} + +int mdb_mid2l_append( MDB_ID2L ids, MDB_ID2 *id ) +{ + /* Too big? */ + if (ids[0].mid >= MDB_IDL_UM_MAX) { + return -2; + } + ids[0].mid++; + ids[ids[0].mid] = *id; + return 0; +} + +#ifdef MDB_VL32 +unsigned mdb_mid3l_search( MDB_ID3L ids, MDB_ID id ) +{ + /* + * binary search of id in ids + * if found, returns position of id + * if not found, returns first position greater than id + */ + unsigned base = 0; + unsigned cursor = 1; + int val = 0; + unsigned n = (unsigned)ids[0].mid; + + while( 0 < n ) { + unsigned pivot = n >> 1; + cursor = base + pivot + 1; + val = CMP( id, ids[cursor].mid ); + + if( val < 0 ) { + n = pivot; + + } else if ( val > 0 ) { + base = cursor; + n -= pivot + 1; + + } else { + return cursor; + } + } + + if( val > 0 ) { + ++cursor; + } + return cursor; +} + +int mdb_mid3l_insert( MDB_ID3L ids, MDB_ID3 *id ) +{ + unsigned x, i; + + x = mdb_mid3l_search( ids, id->mid ); + + if( x < 1 ) { + /* internal error */ + return -2; + } + + if ( x <= ids[0].mid && ids[x].mid == id->mid ) { + /* duplicate */ + return -1; + } + + /* insert id */ + ids[0].mid++; + for (i=(unsigned)ids[0].mid; i>x; i--) + ids[i] = ids[i-1]; + ids[x] = *id; + + return 0; +} +#endif /* MDB_VL32 */ + +/** @} */ +/** @} */ diff --git a/contrib/db/liblmdb/midl.h b/contrib/db/liblmdb/midl.h new file mode 100644 index 00000000..1555ecb1 --- /dev/null +++ b/contrib/db/liblmdb/midl.h @@ -0,0 +1,204 @@ +/** @file midl.h + * @brief LMDB ID List header file. + * + * This file was originally part of back-bdb but has been + * modified for use in libmdb. Most of the macros defined + * in this file are unused, just left over from the original. + * + * This file is only used internally in libmdb and its definitions + * are not exposed publicly. + */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 2000-2015 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ + +#ifndef _MDB_MIDL_H_ +#define _MDB_MIDL_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup internal LMDB Internals + * @{ + */ + +/** @defgroup idls ID List Management + * @{ + */ + /** A generic unsigned ID number. These were entryIDs in back-bdb. + * Preferably it should have the same size as a pointer. + */ +#ifdef MDB_VL32 +typedef uint64_t MDB_ID; +#else +typedef size_t MDB_ID; +#endif + + /** An IDL is an ID List, a sorted array of IDs. The first + * element of the array is a counter for how many actual + * IDs are in the list. In the original back-bdb code, IDLs are + * sorted in ascending order. For libmdb IDLs are sorted in + * descending order. + */ +typedef MDB_ID *MDB_IDL; + +/* IDL sizes - likely should be even bigger + * limiting factors: sizeof(ID), thread stack size + */ +#define MDB_IDL_LOGN 16 /* DB_SIZE is 2^16, UM_SIZE is 2^17 */ +#define MDB_IDL_DB_SIZE (1<. + */ +#include +#include +#include +#include "lmdb.h" + +#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr) +#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0)) +#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \ + "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort())) + +int main(int argc,char * argv[]) +{ + int i = 0, j = 0, rc; + MDB_env *env; + MDB_dbi dbi; + MDB_val key, data; + MDB_txn *txn; + MDB_stat mst; + MDB_cursor *cursor, *cur2; + MDB_cursor_op op; + int count; + int *values; + char sval[32] = ""; + + srand(time(NULL)); + + count = (rand()%384) + 64; + values = (int *)malloc(count*sizeof(int)); + + for(i = 0;i in each iteration, since MDB_NOOVERWRITE may modify it */ + data.mv_size = sizeof(sval); + data.mv_data = sval; + if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE))) { + j++; + data.mv_size = sizeof(sval); + data.mv_data = sval; + } + } + if (j) printf("%d duplicates skipped\n", j); + E(mdb_txn_commit(txn)); + E(mdb_env_stat(env, &mst)); + + E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); + E(mdb_cursor_open(txn, dbi, &cursor)); + while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { + printf("key: %p %.*s, data: %p %.*s\n", + key.mv_data, (int) key.mv_size, (char *) key.mv_data, + data.mv_data, (int) data.mv_size, (char *) data.mv_data); + } + CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); + mdb_cursor_close(cursor); + mdb_txn_abort(txn); + + j=0; + key.mv_data = sval; + for (i= count - 1; i > -1; i-= (rand()%5)) { + j++; + txn=NULL; + E(mdb_txn_begin(env, NULL, 0, &txn)); + sprintf(sval, "%03x ", values[i]); + if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, NULL))) { + j--; + mdb_txn_abort(txn); + } else { + E(mdb_txn_commit(txn)); + } + } + free(values); + printf("Deleted %d values\n", j); + + E(mdb_env_stat(env, &mst)); + E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); + E(mdb_cursor_open(txn, dbi, &cursor)); + printf("Cursor next\n"); + while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { + printf("key: %.*s, data: %.*s\n", + (int) key.mv_size, (char *) key.mv_data, + (int) data.mv_size, (char *) data.mv_data); + } + CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); + printf("Cursor last\n"); + E(mdb_cursor_get(cursor, &key, &data, MDB_LAST)); + printf("key: %.*s, data: %.*s\n", + (int) key.mv_size, (char *) key.mv_data, + (int) data.mv_size, (char *) data.mv_data); + printf("Cursor prev\n"); + while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) { + printf("key: %.*s, data: %.*s\n", + (int) key.mv_size, (char *) key.mv_data, + (int) data.mv_size, (char *) data.mv_data); + } + CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); + printf("Cursor last/prev\n"); + E(mdb_cursor_get(cursor, &key, &data, MDB_LAST)); + printf("key: %.*s, data: %.*s\n", + (int) key.mv_size, (char *) key.mv_data, + (int) data.mv_size, (char *) data.mv_data); + E(mdb_cursor_get(cursor, &key, &data, MDB_PREV)); + printf("key: %.*s, data: %.*s\n", + (int) key.mv_size, (char *) key.mv_data, + (int) data.mv_size, (char *) data.mv_data); + + mdb_cursor_close(cursor); + mdb_txn_abort(txn); + + printf("Deleting with cursor\n"); + E(mdb_txn_begin(env, NULL, 0, &txn)); + E(mdb_cursor_open(txn, dbi, &cur2)); + for (i=0; i<50; i++) { + if (RES(MDB_NOTFOUND, mdb_cursor_get(cur2, &key, &data, MDB_NEXT))) + break; + printf("key: %p %.*s, data: %p %.*s\n", + key.mv_data, (int) key.mv_size, (char *) key.mv_data, + data.mv_data, (int) data.mv_size, (char *) data.mv_data); + E(mdb_del(txn, dbi, &key, NULL)); + } + + printf("Restarting cursor in txn\n"); + for (op=MDB_FIRST, i=0; i<=32; op=MDB_NEXT, i++) { + if (RES(MDB_NOTFOUND, mdb_cursor_get(cur2, &key, &data, op))) + break; + printf("key: %p %.*s, data: %p %.*s\n", + key.mv_data, (int) key.mv_size, (char *) key.mv_data, + data.mv_data, (int) data.mv_size, (char *) data.mv_data); + } + mdb_cursor_close(cur2); + E(mdb_txn_commit(txn)); + + printf("Restarting cursor outside txn\n"); + E(mdb_txn_begin(env, NULL, 0, &txn)); + E(mdb_cursor_open(txn, dbi, &cursor)); + for (op=MDB_FIRST, i=0; i<=32; op=MDB_NEXT, i++) { + if (RES(MDB_NOTFOUND, mdb_cursor_get(cursor, &key, &data, op))) + break; + printf("key: %p %.*s, data: %p %.*s\n", + key.mv_data, (int) key.mv_size, (char *) key.mv_data, + data.mv_data, (int) data.mv_size, (char *) data.mv_data); + } + mdb_cursor_close(cursor); + mdb_txn_abort(txn); + + mdb_dbi_close(env, dbi); + mdb_env_close(env); + + return 0; +} diff --git a/contrib/db/liblmdb/mtest2.c b/contrib/db/liblmdb/mtest2.c new file mode 100644 index 00000000..eacbe59d --- /dev/null +++ b/contrib/db/liblmdb/mtest2.c @@ -0,0 +1,124 @@ +/* mtest2.c - memory-mapped database tester/toy */ +/* + * Copyright 2011-2015 Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ + +/* Just like mtest.c, but using a subDB instead of the main DB */ + +#include +#include +#include +#include "lmdb.h" + +#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr) +#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0)) +#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \ + "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort())) + +int main(int argc,char * argv[]) +{ + int i = 0, j = 0, rc; + MDB_env *env; + MDB_dbi dbi; + MDB_val key, data; + MDB_txn *txn; + MDB_stat mst; + MDB_cursor *cursor; + int count; + int *values; + char sval[32] = ""; + + srand(time(NULL)); + + count = (rand()%384) + 64; + values = (int *)malloc(count*sizeof(int)); + + for(i = 0;i -1; i-= (rand()%5)) { + j++; + txn=NULL; + E(mdb_txn_begin(env, NULL, 0, &txn)); + sprintf(sval, "%03x ", values[i]); + if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, NULL))) { + j--; + mdb_txn_abort(txn); + } else { + E(mdb_txn_commit(txn)); + } + } + free(values); + printf("Deleted %d values\n", j); + + E(mdb_env_stat(env, &mst)); + E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); + E(mdb_cursor_open(txn, dbi, &cursor)); + printf("Cursor next\n"); + while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { + printf("key: %.*s, data: %.*s\n", + (int) key.mv_size, (char *) key.mv_data, + (int) data.mv_size, (char *) data.mv_data); + } + CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); + printf("Cursor prev\n"); + while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) { + printf("key: %.*s, data: %.*s\n", + (int) key.mv_size, (char *) key.mv_data, + (int) data.mv_size, (char *) data.mv_data); + } + CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); + mdb_cursor_close(cursor); + mdb_txn_abort(txn); + + mdb_dbi_close(env, dbi); + mdb_env_close(env); + return 0; +} diff --git a/contrib/db/liblmdb/mtest3.c b/contrib/db/liblmdb/mtest3.c new file mode 100644 index 00000000..9db79e62 --- /dev/null +++ b/contrib/db/liblmdb/mtest3.c @@ -0,0 +1,133 @@ +/* mtest3.c - memory-mapped database tester/toy */ +/* + * Copyright 2011-2015 Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ + +/* Tests for sorted duplicate DBs */ +#include +#include +#include +#include +#include "lmdb.h" + +#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr) +#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0)) +#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \ + "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort())) + +int main(int argc,char * argv[]) +{ + int i = 0, j = 0, rc; + MDB_env *env; + MDB_dbi dbi; + MDB_val key, data; + MDB_txn *txn; + MDB_stat mst; + MDB_cursor *cursor; + int count; + int *values; + char sval[32]; + char kval[sizeof(int)]; + + srand(time(NULL)); + + memset(sval, 0, sizeof(sval)); + + count = (rand()%384) + 64; + values = (int *)malloc(count*sizeof(int)); + + for(i = 0;i -1; i-= (rand()%5)) { + j++; + txn=NULL; + E(mdb_txn_begin(env, NULL, 0, &txn)); + sprintf(kval, "%03x", values[i & ~0x0f]); + sprintf(sval, "%03x %d foo bar", values[i], values[i]); + key.mv_size = sizeof(int); + key.mv_data = kval; + data.mv_size = sizeof(sval); + data.mv_data = sval; + if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, &data))) { + j--; + mdb_txn_abort(txn); + } else { + E(mdb_txn_commit(txn)); + } + } + free(values); + printf("Deleted %d values\n", j); + + E(mdb_env_stat(env, &mst)); + E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); + E(mdb_cursor_open(txn, dbi, &cursor)); + printf("Cursor next\n"); + while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { + printf("key: %.*s, data: %.*s\n", + (int) key.mv_size, (char *) key.mv_data, + (int) data.mv_size, (char *) data.mv_data); + } + CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); + printf("Cursor prev\n"); + while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) { + printf("key: %.*s, data: %.*s\n", + (int) key.mv_size, (char *) key.mv_data, + (int) data.mv_size, (char *) data.mv_data); + } + CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); + mdb_cursor_close(cursor); + mdb_txn_abort(txn); + + mdb_dbi_close(env, dbi); + mdb_env_close(env); + return 0; +} diff --git a/contrib/db/liblmdb/mtest4.c b/contrib/db/liblmdb/mtest4.c new file mode 100644 index 00000000..6df890e2 --- /dev/null +++ b/contrib/db/liblmdb/mtest4.c @@ -0,0 +1,168 @@ +/* mtest4.c - memory-mapped database tester/toy */ +/* + * Copyright 2011-2015 Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ + +/* Tests for sorted duplicate DBs with fixed-size keys */ +#include +#include +#include +#include +#include "lmdb.h" + +#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr) +#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0)) +#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \ + "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort())) + +int main(int argc,char * argv[]) +{ + int i = 0, j = 0, rc; + MDB_env *env; + MDB_dbi dbi; + MDB_val key, data; + MDB_txn *txn; + MDB_stat mst; + MDB_cursor *cursor; + int count; + int *values; + char sval[8]; + char kval[sizeof(int)]; + + memset(sval, 0, sizeof(sval)); + + count = 510; + values = (int *)malloc(count*sizeof(int)); + + for(i = 0;i -1; i-= (rand()%3)) { + j++; + txn=NULL; + E(mdb_txn_begin(env, NULL, 0, &txn)); + sprintf(sval, "%07x", values[i]); + key.mv_size = sizeof(int); + key.mv_data = kval; + data.mv_size = sizeof(sval); + data.mv_data = sval; + if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, &data))) { + j--; + mdb_txn_abort(txn); + } else { + E(mdb_txn_commit(txn)); + } + } + free(values); + printf("Deleted %d values\n", j); + + E(mdb_env_stat(env, &mst)); + E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); + E(mdb_cursor_open(txn, dbi, &cursor)); + printf("Cursor next\n"); + while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { + printf("key: %.*s, data: %.*s\n", + (int) key.mv_size, (char *) key.mv_data, + (int) data.mv_size, (char *) data.mv_data); + } + CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); + printf("Cursor prev\n"); + while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) { + printf("key: %.*s, data: %.*s\n", + (int) key.mv_size, (char *) key.mv_data, + (int) data.mv_size, (char *) data.mv_data); + } + CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); + mdb_cursor_close(cursor); + mdb_txn_abort(txn); + + mdb_dbi_close(env, dbi); + mdb_env_close(env); + return 0; +} diff --git a/contrib/db/liblmdb/mtest5.c b/contrib/db/liblmdb/mtest5.c new file mode 100644 index 00000000..14e3c0da --- /dev/null +++ b/contrib/db/liblmdb/mtest5.c @@ -0,0 +1,135 @@ +/* mtest5.c - memory-mapped database tester/toy */ +/* + * Copyright 2011-2015 Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ + +/* Tests for sorted duplicate DBs using cursor_put */ +#include +#include +#include +#include +#include "lmdb.h" + +#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr) +#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0)) +#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \ + "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort())) + +int main(int argc,char * argv[]) +{ + int i = 0, j = 0, rc; + MDB_env *env; + MDB_dbi dbi; + MDB_val key, data; + MDB_txn *txn; + MDB_stat mst; + MDB_cursor *cursor; + int count; + int *values; + char sval[32]; + char kval[sizeof(int)]; + + srand(time(NULL)); + + memset(sval, 0, sizeof(sval)); + + count = (rand()%384) + 64; + values = (int *)malloc(count*sizeof(int)); + + for(i = 0;i -1; i-= (rand()%5)) { + j++; + txn=NULL; + E(mdb_txn_begin(env, NULL, 0, &txn)); + sprintf(kval, "%03x", values[i & ~0x0f]); + sprintf(sval, "%03x %d foo bar", values[i], values[i]); + key.mv_size = sizeof(int); + key.mv_data = kval; + data.mv_size = sizeof(sval); + data.mv_data = sval; + if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, &data))) { + j--; + mdb_txn_abort(txn); + } else { + E(mdb_txn_commit(txn)); + } + } + free(values); + printf("Deleted %d values\n", j); + + E(mdb_env_stat(env, &mst)); + E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); + E(mdb_cursor_open(txn, dbi, &cursor)); + printf("Cursor next\n"); + while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { + printf("key: %.*s, data: %.*s\n", + (int) key.mv_size, (char *) key.mv_data, + (int) data.mv_size, (char *) data.mv_data); + } + CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); + printf("Cursor prev\n"); + while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) { + printf("key: %.*s, data: %.*s\n", + (int) key.mv_size, (char *) key.mv_data, + (int) data.mv_size, (char *) data.mv_data); + } + CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); + mdb_cursor_close(cursor); + mdb_txn_abort(txn); + + mdb_dbi_close(env, dbi); + mdb_env_close(env); + return 0; +} diff --git a/contrib/db/liblmdb/mtest6.c b/contrib/db/liblmdb/mtest6.c new file mode 100644 index 00000000..ae3c7f26 --- /dev/null +++ b/contrib/db/liblmdb/mtest6.c @@ -0,0 +1,141 @@ +/* mtest6.c - memory-mapped database tester/toy */ +/* + * Copyright 2011-2015 Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ + +/* Tests for DB splits and merges */ +#include +#include +#include +#include +#include "lmdb.h" + +#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr) +#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0)) +#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \ + "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort())) + +char dkbuf[1024]; + +int main(int argc,char * argv[]) +{ + int i = 0, j = 0, rc; + MDB_env *env; + MDB_dbi dbi; + MDB_val key, data, sdata; + MDB_txn *txn; + MDB_stat mst; + MDB_cursor *cursor; + int count; + int *values; + long kval; + char *sval; + + srand(time(NULL)); + + E(mdb_env_create(&env)); + E(mdb_env_set_mapsize(env, 10485760)); + E(mdb_env_set_maxdbs(env, 4)); + E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664)); + + E(mdb_txn_begin(env, NULL, 0, &txn)); + E(mdb_dbi_open(txn, "id6", MDB_CREATE|MDB_INTEGERKEY, &dbi)); + E(mdb_cursor_open(txn, dbi, &cursor)); + E(mdb_stat(txn, dbi, &mst)); + + sval = calloc(1, mst.ms_psize / 4); + key.mv_size = sizeof(long); + key.mv_data = &kval; + sdata.mv_size = mst.ms_psize / 4 - 30; + sdata.mv_data = sval; + + printf("Adding 12 values, should yield 3 splits\n"); + for (i=0;i<12;i++) { + kval = i*5; + sprintf(sval, "%08x", kval); + data = sdata; + (void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE)); + } + printf("Adding 12 more values, should yield 3 splits\n"); + for (i=0;i<12;i++) { + kval = i*5+4; + sprintf(sval, "%08x", kval); + data = sdata; + (void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE)); + } + printf("Adding 12 more values, should yield 3 splits\n"); + for (i=0;i<12;i++) { + kval = i*5+1; + sprintf(sval, "%08x", kval); + data = sdata; + (void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE)); + } + E(mdb_cursor_get(cursor, &key, &data, MDB_FIRST)); + + do { + printf("key: %p %s, data: %p %.*s\n", + key.mv_data, mdb_dkey(&key, dkbuf), + data.mv_data, (int) data.mv_size, (char *) data.mv_data); + } while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0); + CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); + mdb_cursor_close(cursor); + mdb_txn_commit(txn); + +#if 0 + j=0; + + for (i= count - 1; i > -1; i-= (rand()%5)) { + j++; + txn=NULL; + E(mdb_txn_begin(env, NULL, 0, &txn)); + sprintf(kval, "%03x", values[i & ~0x0f]); + sprintf(sval, "%03x %d foo bar", values[i], values[i]); + key.mv_size = sizeof(int); + key.mv_data = kval; + data.mv_size = sizeof(sval); + data.mv_data = sval; + if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, &data))) { + j--; + mdb_txn_abort(txn); + } else { + E(mdb_txn_commit(txn)); + } + } + free(values); + printf("Deleted %d values\n", j); + + E(mdb_env_stat(env, &mst)); + E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); + E(mdb_cursor_open(txn, dbi, &cursor)); + printf("Cursor next\n"); + while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { + printf("key: %.*s, data: %.*s\n", + (int) key.mv_size, (char *) key.mv_data, + (int) data.mv_size, (char *) data.mv_data); + } + CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); + printf("Cursor prev\n"); + while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) { + printf("key: %.*s, data: %.*s\n", + (int) key.mv_size, (char *) key.mv_data, + (int) data.mv_size, (char *) data.mv_data); + } + CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); + mdb_cursor_close(cursor); + mdb_txn_abort(txn); + + mdb_dbi_close(env, dbi); +#endif + mdb_env_close(env); + + return 0; +} diff --git a/contrib/db/liblmdb/sample-bdb.txt b/contrib/db/liblmdb/sample-bdb.txt new file mode 100644 index 00000000..563807a2 --- /dev/null +++ b/contrib/db/liblmdb/sample-bdb.txt @@ -0,0 +1,73 @@ +/* sample-bdb.txt - BerkeleyDB toy/sample + * + * Do a line-by-line comparison of this and sample-mdb.txt + */ +/* + * Copyright 2012-2015 Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +#include +#include +#include + +int main(int argc,char * argv[]) +{ + int rc; + DB_ENV *env; + DB *dbi; + DBT key, data; + DB_TXN *txn; + DBC *cursor; + char sval[32], kval[32]; + + /* Note: Most error checking omitted for simplicity */ + +#define FLAGS (DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_TXN|DB_INIT_MPOOL|DB_CREATE|DB_THREAD) + rc = db_env_create(&env, 0); + rc = env->open(env, "./testdb", FLAGS, 0664); + rc = db_create(&dbi, env, 0); + rc = env->txn_begin(env, NULL, &txn, 0); + rc = dbi->open(dbi, txn, "test.bdb", NULL, DB_BTREE, DB_CREATE, 0664); + + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + key.size = sizeof(int); + key.data = sval; + data.size = sizeof(sval); + data.data = sval; + + sprintf(sval, "%03x %d foo bar", 32, 3141592); + rc = dbi->put(dbi, txn, &key, &data, 0); + rc = txn->commit(txn, 0); + if (rc) { + fprintf(stderr, "txn->commit: (%d) %s\n", rc, db_strerror(rc)); + goto leave; + } + rc = env->txn_begin(env, NULL, &txn, 0); + rc = dbi->cursor(dbi, txn, &cursor, 0); + key.flags = DB_DBT_USERMEM; + key.data = kval; + key.ulen = sizeof(kval); + data.flags = DB_DBT_USERMEM; + data.data = sval; + data.ulen = sizeof(sval); + while ((rc = cursor->c_get(cursor, &key, &data, DB_NEXT)) == 0) { + printf("key: %p %.*s, data: %p %.*s\n", + key.data, (int) key.size, (char *) key.data, + data.data, (int) data.size, (char *) data.data); + } + rc = cursor->c_close(cursor); + rc = txn->abort(txn); +leave: + rc = dbi->close(dbi, 0); + rc = env->close(env, 0); + return rc; +} diff --git a/contrib/db/liblmdb/sample-mdb.txt b/contrib/db/liblmdb/sample-mdb.txt new file mode 100644 index 00000000..10a25687 --- /dev/null +++ b/contrib/db/liblmdb/sample-mdb.txt @@ -0,0 +1,62 @@ +/* sample-mdb.txt - MDB toy/sample + * + * Do a line-by-line comparison of this and sample-bdb.txt + */ +/* + * Copyright 2012-2015 Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +#include +#include "lmdb.h" + +int main(int argc,char * argv[]) +{ + int rc; + MDB_env *env; + MDB_dbi dbi; + MDB_val key, data; + MDB_txn *txn; + MDB_cursor *cursor; + char sval[32]; + + /* Note: Most error checking omitted for simplicity */ + + rc = mdb_env_create(&env); + rc = mdb_env_open(env, "./testdb", 0, 0664); + rc = mdb_txn_begin(env, NULL, 0, &txn); + rc = mdb_dbi_open(txn, NULL, 0, &dbi); + + key.mv_size = sizeof(int); + key.mv_data = sval; + data.mv_size = sizeof(sval); + data.mv_data = sval; + + sprintf(sval, "%03x %d foo bar", 32, 3141592); + rc = mdb_put(txn, dbi, &key, &data, 0); + rc = mdb_txn_commit(txn); + if (rc) { + fprintf(stderr, "mdb_txn_commit: (%d) %s\n", rc, mdb_strerror(rc)); + goto leave; + } + rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn); + rc = mdb_cursor_open(txn, dbi, &cursor); + while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { + printf("key: %p %.*s, data: %p %.*s\n", + key.mv_data, (int) key.mv_size, (char *) key.mv_data, + data.mv_data, (int) data.mv_size, (char *) data.mv_data); + } + mdb_cursor_close(cursor); + mdb_txn_abort(txn); +leave: + mdb_dbi_close(env, dbi); + mdb_env_close(env); + return 0; +} diff --git a/contrib/db/liblmdb/tooltag b/contrib/db/liblmdb/tooltag new file mode 100644 index 00000000..229bf16b --- /dev/null +++ b/contrib/db/liblmdb/tooltag @@ -0,0 +1,22 @@ + + + mdb_copy_1 + mdb_copy - environment copy tool + mdb_copy.1 + + + mdb_dump_1 + mdb_dump - environment export tool + mdb_dump.1 + + + mdb_load_1 + mdb_load - environment import tool + mdb_load.1 + + + mdb_stat_1 + mdb_stat - environment status tool + mdb_stat.1 + + diff --git a/contrib/eos_portable_archive/change_log.txt b/contrib/eos_portable_archive/change_log.txt new file mode 100644 index 00000000..e5918d9c --- /dev/null +++ b/contrib/eos_portable_archive/change_log.txt @@ -0,0 +1,36 @@ +IMPORTANT: + +This is the last release from me as EOS employee. I plan to contribute all of this +work to the official boost libraries distribution and will continue to support users. +Francois Mauger joined me recently and already added a valuable tutorial for you! + +Changelog: + +26.06.2012 5.0 Ported to boost versions up to 1.49. + Added support for wstring, added tutorial by Francois Mauger. + +01.04.2011 4.2 Ported to boost versions up to 1.46.1. + Allow serialization of inf and nan values. + +17.12.2009 4.1 Ported to boost versions up to 1.41. + + 4.0 Changes in inheritance make arrays work. + +13.02.2009 3.1 Shared pointer serialization capabilities added + Ported to recent boost versions (up to 1.38) + +25.09.2008 3.0 Refactored, fixed and ported to recent boost versions + Archives are now named eos::portable_[io]archive + +17.09.2008 2.1 Improved floating point handling and error detection. + Extracted the exception class into an extra file. + +28.04.2008 2.0 Major Bugfix resolving negative number collision! + +28.11.2007 1.1 Small Bugfix in portable_binary_archive_exception class: + throwing specifiers did not match base class declaration + +12.11.2007 1.0 Initial Release to boost-users! + +Christian Pfligersdorffer +christian.pfligersdorffer@gmx.at \ No newline at end of file diff --git a/contrib/eos_portable_archive/eos/polymorphic_portable_archive.hpp b/contrib/eos_portable_archive/eos/polymorphic_portable_archive.hpp new file mode 100644 index 00000000..b2342c28 --- /dev/null +++ b/contrib/eos_portable_archive/eos/polymorphic_portable_archive.hpp @@ -0,0 +1,35 @@ +/*****************************************************************************/ +/** + * \file polymorphic_portable_archive.hpp + * \brief Needed for unit tests on portable archives. + * \author christian.pfligersdorffer@gmx.at + * + * Header for testing portable archives with all of the serialization tests. + * Before use copy all hpp files from this directory to your boost folder + * boost_.../libs/serialization/test and run from there a visual studio + * prompt with b2 oder bjam -sBOOST_ARCHIVE_LIST=portable_archive.hpp + * + * \note Since portable archives version 5.0 we depend on program_options! + * Edit libs/serialization/test/Jamfile.v2 and change the requirements to + * : requirements /boost/filesystem /boost/program_options + */ +/****************************************************************************/ + +#pragma warning( disable:4217 4127 4310 4244 4800 4267 ) + +// text_archive test header +// include output archive header +#include "portable_oarchive.hpp" +// set name of test output archive +typedef eos::polymorphic_portable_oarchive test_oarchive; +// set name of test output stream +typedef std::ofstream test_ostream; + +// repeat the above for input archive +#include "portable_iarchive.hpp" +typedef eos::polymorphic_portable_iarchive test_iarchive; +typedef std::ifstream test_istream; + +// define open mode for streams +// binary archives should use std::ios_base::binary +#define TEST_STREAM_FLAGS std::ios_base::binary diff --git a/contrib/eos_portable_archive/eos/portable_archive.hpp b/contrib/eos_portable_archive/eos/portable_archive.hpp new file mode 100644 index 00000000..f7f93315 --- /dev/null +++ b/contrib/eos_portable_archive/eos/portable_archive.hpp @@ -0,0 +1,36 @@ +/*****************************************************************************/ +/** + * \file portable_archive.hpp + * \brief Needed for unit tests on portable archives. + * \author christian.pfligersdorffer@gmx.at + * + * Header for testing portable archives with all of the serialization tests. + * Before use copy all hpp files from this directory to your boost folder + * boost_.../libs/serialization/test and run from there a visual studio + * prompt with b2 oder bjam -sBOOST_ARCHIVE_LIST=portable_archive.hpp + * + * \note Since portable archives version 5.0 we depend on program_options! + * Edit libs/serialization/test/Jamfile.v2 and change the requirements to + * : requirements /boost/filesystem /boost/program_options + */ +/****************************************************************************/ +#if defined(_MSC_VER) +#pragma warning( disable:4217 4127 4310 4244 4800 4267 ) +#endif + +// text_archive test header +// include output archive header +#include "portable_oarchive.hpp" +// set name of test output archive +typedef eos::portable_oarchive test_oarchive; +// set name of test output stream +typedef std::ofstream test_ostream; + +// repeat the above for input archive +#include "portable_iarchive.hpp" +typedef eos::portable_iarchive test_iarchive; +typedef std::ifstream test_istream; + +// define open mode for streams +// binary archives should use std::ios_base::binary +#define TEST_STREAM_FLAGS std::ios_base::binary diff --git a/contrib/eos_portable_archive/eos/portable_archive_exception.hpp b/contrib/eos_portable_archive/eos/portable_archive_exception.hpp new file mode 100644 index 00000000..fad9ed5f --- /dev/null +++ b/contrib/eos_portable_archive/eos/portable_archive_exception.hpp @@ -0,0 +1,94 @@ +/*****************************************************************************/ +/** + * \file portable_archive_exception.hpp + * \brief Provides error handling and constants. + * \author christian.pfligersdorffer@gmx.at + * + * Portable archive exceptions derive from the boost archive exceptions + * and add failure causes specific to the portable binary usecase. + * + * Additionally this header serves as common include for important + * constants or typedefs. + */ +/****************************************************************************/ + +#pragma once + +#include +#include +#include + +namespace eos { + + // this value is written to the top of the stream + const signed char magic_byte = 'e' | 'o' | 's'; + + // flag for fp serialization + const unsigned no_infnan = 64; + + // integral type for the archive version + #if BOOST_VERSION < 104400 + typedef boost::archive::version_type archive_version_type; + #else + typedef boost::archive::library_version_type archive_version_type; + #endif + + // version of the linked boost archive library + const archive_version_type archive_version( + 11 +// #if BOOST_VERSION < 103700 +// boost::archive::ARCHIVE_VERSION() +// #else +// boost::archive::BOOST_ARCHIVE_VERSION() +// #endif + ); + + /** + * \brief Exception being thrown when serialization cannot proceed. + * + * There are several situations in which the portable archives may fail and + * hence throw an exception: + * -# deserialization of an integer value that exceeds the range of the type + * -# (de)serialization of inf/nan through an archive with no_infnan flag set + * -# deserialization of a denormalized value without the floating point type + * supporting denormalized numbers + * + * Note that this exception will also be thrown if you mixed up your stream + * position and accidentially interpret some value for size data (in this case + * the reported size will be totally amiss most of the time). + */ + class portable_archive_exception : public boost::archive::archive_exception + { + std::string msg; + + public: + //! type size is not large enough for deserialized number + portable_archive_exception(signed char invalid_size) + : boost::archive::archive_exception(other_exception) + , msg("requested integer size exceeds type size: ") + { + msg += boost::lexical_cast(invalid_size); + } + + //! negative number in unsigned type + portable_archive_exception() + : boost::archive::archive_exception(other_exception) + , msg("cannot read a negative number into an unsigned type") + { + } + + //! serialization of inf, nan and denormals + template + portable_archive_exception(const T& abnormal) + : boost::archive::archive_exception(other_exception) + , msg("serialization of illegal floating point value: ") + { + msg += boost::lexical_cast(abnormal); + } + + //! override the base class function with our message + const char* what() const throw() { return msg.c_str(); } + ~portable_archive_exception() throw() {} + }; + +} // namespace eos diff --git a/contrib/eos_portable_archive/eos/portable_iarchive.hpp b/contrib/eos_portable_archive/eos/portable_iarchive.hpp new file mode 100644 index 00000000..54540989 --- /dev/null +++ b/contrib/eos_portable_archive/eos/portable_iarchive.hpp @@ -0,0 +1,488 @@ +/*****************************************************************************/ +/** + * \file portable_iarchive.hpp + * \brief Provides an archive to read from portable binary files. + * \author christian.pfligersdorffer@gmx.at + * \version 5.0 + * + * This pair of archives brings the advantages of binary streams to the cross + * platform boost::serialization user. While being almost as fast as the native + * binary archive it allows its files to be exchanged between cpu architectures + * using different byte order (endianness). Speaking of speed: in serializing + * numbers the (portable) binary approach is approximately ten times faster than + * the ascii implementation (that is inherently portable)! + * + * Based on the portable archive example by Robert Ramey this implementation + * uses Beman Dawes endian library and fp_utilities from Johan Rade, both being + * in boost since 1.36. Prior to that you need to add them both (header only) + * to your boost directory before you're able to use the archives provided. + * Our archives have been tested successfully for boost versions 1.33 to 1.49! + * + * \note Correct behaviour has so far been confirmed using PowerPC-32, x86-32 + * and x86-64 platforms featuring different byte order. So there is a good + * chance it will instantly work for your specific setup. If you encounter + * problems or have suggestions please contact the author. + * + * \note Version 5.0 is now compatible with boost up to version 1.49 and enables + * serialization of std::wstring by converting it to/from utf8 (thanks to + * Arash Abghari for this suggestion). With that all unit tests from the + * serialization library pass again with the notable exception of user + * defined primitive types. Those are not supported and as a result any + * user defined type to be used with the portable archives are required + * to be at least object_serializable. + * + * \note Version 4.2 maintains compatibility with the latest boost 1.45 and adds + * serialization of special floating point values inf and NaN as proposed + * by Francois Mauger. + * + * \note Version 4.1 makes the archives work together with boost 1.40 and 1.41. + * Thanks to Francois Mauger for his suggestions. + * + * \note Version 4 removes one level of the inheritance hierarchy and directly + * builds upon binary primitive and basic binary archive, thereby fixing + * the last open issue regarding array serialization. Thanks to Robert + * Ramey for the hint. + * + * \note A few fixes introduced in version 3.1 let the archives pass all of the + * serialization tests. Thanks to Sergey Morozov for running the tests. + * Wouter Bijlsma pointed out where to find the fp_utilities and endian + * libraries headers inside the boost distribution. I would never have + * found them so thank him it works out of the box since boost 1.36. + * + * \note With Version 3.0 the archives have been made portable across different + * boost versions. For that purpose a header is added to the data that + * supplies the underlying serialization library version. Backwards + * compatibility is maintained by assuming library version boost 1.33 if + * the iarchive is created using the no_header flag. Whether a header is + * present or not can be guessed by peeking into the stream: the header's + * first byte is the magic number 127 coinciding with 'e'|'o'|'s' :-) + * + * \note Version 2.1 removes several compiler warnings and enhances floating + * point diagnostics to inform the user if some preconditions are violated + * on his platform. We do not strive for the universally portable solution + * in binary floating point serialization as desired by some boost users. + * Instead we support only the most widely used IEEE 754 format and try to + * detect when requirements are not met and hence our approach must fail. + * Contributions we made by Johan Rade and kos Mary. + * + * \note Version 2.0 fixes a serious bug that effectively transformed most + * of negative integral values into positive values! For example the two + * numbers -12 and 234 were stored in the same 8-bit pattern and later + * always restored to 234. This was fixed in this version in a way that + * does not change the interpretation of existing archives that did work + * because there were no negative numbers. The other way round archives + * created by version 2.0 and containing negative numbers will raise an + * integer type size exception when reading it with version 1.0. Thanks + * to Markus Frohnmaier for testing the archives and finding the bug. + * + * \copyright The boost software license applies. + */ +/*****************************************************************************/ + +#pragma once + +#include + +// basic headers +#include +#include +#include +#include + +#if BOOST_VERSION >= 105600 +#include +#elif BOOST_VERSION >= 103500 +#include +#endif + +// funny polymorphics +#if BOOST_VERSION < 103500 +#include +#define POLYMORPHIC(T) boost::archive::detail::polymorphic_iarchive_impl + +#elif BOOST_VERSION < 103600 +#include +#define POLYMORPHIC(T) boost::archive::detail::polymorphic_iarchive_dispatch + +#else +#include +#define POLYMORPHIC(T) boost::archive::detail::polymorphic_iarchive_route +#endif + +// endian and fpclassify +#if BOOST_VERSION < 103600 +#include +#include +#elif BOOST_VERSION < 104800 +#include +#include +#else +#include +#include +#endif + +// namespace alias +#if BOOST_VERSION < 103800 +namespace fp = boost::math; +#else +namespace fp = boost::spirit::math; +#endif + +// namespace alias endian +#if BOOST_VERSION < 104800 +namespace endian = boost::detail; +#else +namespace endian = boost::spirit::detail; +#endif + +#ifndef BOOST_NO_STD_WSTRING +// used for wstring to utf8 conversion +#include +#include +#endif + +// generic type traits for numeric types +#include +#include +#include +#include + +#include "portable_archive_exception.hpp" + +// hint from Johan Rade: on VMS there is still support for +// the VAX floating point format and this macro detects it +#if defined(__vms) && defined(__DECCXX) && !__IEEE_FLOAT +#error "VAX floating point format is not supported!" +#endif + +namespace eos { + + // forward declaration + class portable_iarchive; + + typedef boost::archive::basic_binary_iprimitive< + portable_iarchive + #if BOOST_VERSION < 103400 + , std::istream + #else + , std::istream::char_type + , std::istream::traits_type + #endif + > portable_iprimitive; + + /** + * \brief Portable binary input archive using little endian format. + * + * This archive addresses integer size, endianness and floating point types so + * that data can be transferred across different systems. There may still be + * constraints as to what systems are compatible and the user will have to take + * care that e.g. a very large int being saved on a 64 bit machine will result + * in a portable_archive_exception if loaded into an int on a 32 bit system. + * A possible workaround to this would be to use fixed types like + * boost::uint64_t in your serialization structures. + * + * \note The class is based on the portable binary example by Robert Ramey and + * uses Beman Dawes endian library plus fp_utilities by Johan Rade. + */ + class portable_iarchive : public portable_iprimitive + + // the example derives from common_oarchive but that lacks the + // load_override functions so we chose to stay one level higher + , public boost::archive::basic_binary_iarchive + + #if BOOST_VERSION >= 105600 + // mix-in helper class for serializing shared_ptr does not exist anymore + #elif BOOST_VERSION >= 103500 + // mix-in helper class for serializing shared_ptr + , public boost::archive::detail::shared_ptr_helper + #endif + { + // only needed for Robert's hack in basic_binary_iarchive::init + friend class boost::archive::basic_binary_iarchive; + + // workaround for gcc: use a dummy struct + // as additional argument type for overloading + template struct dummy { dummy(int) {}}; + + // loads directly from stream + inline signed char load_signed_char() + { + signed char c; + portable_iprimitive::load(c); + return c; + } + + // archive initialization + void init(unsigned flags) + { + using namespace boost::archive; + archive_version_type input_library_version(3); + + // it is vital to have version information! + // if we don't have any we assume boost 1.33 + if (flags & no_header) + set_library_version(input_library_version); + + // extract and check the magic eos byte + else if (load_signed_char() != magic_byte) + throw archive_exception(archive_exception::invalid_signature); + + else + { + // extract version information + operator>>(input_library_version); + + // throw if file version is newer than we are + if (input_library_version > archive_version) + throw archive_exception(archive_exception::unsupported_version); + + // else set the library version accordingly + else set_library_version(input_library_version); + } + } + + public: + /** + * \brief Constructor on a stream using ios::binary mode! + * + * We cannot call basic_binary_iprimitive::init which tries to detect + * if the binary archive stems from a different platform by examining + * type sizes. + * + * We could have called basic_binary_iarchive::init which would create + * the boost::serialization standard archive header containing also the + * library version. Due to efficiency we stick with our own. + */ + portable_iarchive(std::istream& is, unsigned flags = 0) + #if BOOST_VERSION < 103400 + : portable_iprimitive(is, flags & boost::archive::no_codecvt) + #else + : portable_iprimitive(*is.rdbuf(), flags & boost::archive::no_codecvt) + #endif + , boost::archive::basic_binary_iarchive(flags) + { + init(flags); + } + + #if BOOST_VERSION >= 103400 + portable_iarchive(std::streambuf& sb, unsigned flags = 0) + : portable_iprimitive(sb, flags & boost::archive::no_codecvt) + , boost::archive::basic_binary_iarchive(flags) + { + init(flags); + } + #endif + + //! Load narrow strings. + void load(std::string& s) + { + portable_iprimitive::load(s); + } + + #ifndef BOOST_NO_STD_WSTRING + /** + * \brief Load wide strings. + * + * This is rather tricky to get right for true portability as there + * are so many different character encodings around. However, wide + * strings that are encoded in one of the Unicode schemes only need + * to be _transcoded_ which is a lot easier actually. + * + * We generate the output string to be encoded in the system's native + * format, ie. UTF-16 on Windows and UTF-32 on Linux machines. Don't + * know about Mac here so I can't really say about that. + */ + void load(std::wstring& s) + { + std::string utf8; + load(utf8); + s = boost::from_utf8(utf8); + } + #endif + + /** + * \brief Loading bool type. + * + * Byte pattern is same as with integer types, so this function + * is somewhat redundant but treating bool as integer generates + * a lot of compiler warnings. + * + * \note If you cannot compile your application and it says something + * about load(bool) cannot convert your type A& into bool& then you + * should check your BOOST_CLASS_IMPLEMENTATION setting for A, as + * portable_archive is not able to handle custom primitive types in + * a general manner. + */ + void load(bool& b) + { + switch (signed char c = load_signed_char()) + { + case 0: b = false; break; + case 1: b = load_signed_char(); break; + default: throw portable_archive_exception(c); + } + } + + /** + * \brief Load integer types. + * + * First we load the size information ie. the number of bytes that + * hold the actual data. Then we retrieve the data and transform it + * to the original value by using load_little_endian. + */ + template + typename boost::enable_if >::type + load(T & t, dummy<2> = 0) + { + // get the number of bytes in the stream + if (signed char size = load_signed_char()) + { + // check for negative value in unsigned type + if (size < 0 && boost::is_unsigned::value) + throw portable_archive_exception(); + + // check that our type T is large enough + else if ((unsigned) abs(size) > sizeof(T)) + throw portable_archive_exception(size); + + // reconstruct the value + T temp = size < 0 ? -1 : 0; + load_binary(&temp, abs(size)); + + // load the value from little endian - is is then converted + // to the target type T and fits it because size <= sizeof(T) + t = endian::load_little_endian(&temp); + } + + else t = 0; // zero optimization + } + + /** + * \brief Load floating point types. + * + * We simply rely on fp_traits to set the bit pattern from the (unsigned) + * integral type that was stored in the stream. Francois Mauger provided + * standardized behaviour for special values like inf and NaN, that need to + * be serialized in his application. + * + * \note by Johan Rade (author of the floating point utilities library): + * Be warned that the math::detail::fp_traits::type::get_bits() function + * is *not* guaranteed to give you all bits of the floating point number. It + * will give you all bits if and only if there is an integer type that has + * the same size as the floating point you are copying from. It will not + * give you all bits for double if there is no uint64_t. It will not give + * you all bits for long double if sizeof(long double) > 8 or there is no + * uint64_t. + * + * The member fp_traits::type::coverage will tell you whether all bits + * are copied. This is a typedef for either math::detail::all_bits or + * math::detail::not_all_bits. + * + * If the function does not copy all bits, then it will copy the most + * significant bits. So if you serialize and deserialize the way you + * describe, and fp_traits::type::coverage is math::detail::not_all_bits, + * then your floating point numbers will be truncated. This will introduce + * small rounding off errors. + */ + template + typename boost::enable_if >::type + load(T & t, dummy<3> = 0) + { + typedef typename fp::detail::fp_traits::type traits; + + // if you end here there are three possibilities: + // 1. you're serializing a long double which is not portable + // 2. you're serializing a double but have no 64 bit integer + // 3. your machine is using an unknown floating point format + // after reading the note above you still might decide to + // deactivate this static assert and try if it works out. + typename traits::bits bits; + BOOST_STATIC_ASSERT(sizeof(bits) == sizeof(T)); + BOOST_STATIC_ASSERT(std::numeric_limits::is_iec559); + + load(bits); + traits::set_bits(t, bits); + + // if the no_infnan flag is set we must throw here + if (get_flags() & no_infnan && !fp::isfinite(t)) + throw portable_archive_exception(t); + + // if you end here your floating point type does not support + // denormalized numbers. this might be the case even though + // your type conforms to IEC 559 (and thus to IEEE 754) + if (std::numeric_limits::has_denorm == std::denorm_absent + && fp::fpclassify(t) == (int) FP_SUBNORMAL) // GCC4 + throw portable_archive_exception(t); + } + + // in boost 1.44 version_type was splitted into library_version_type and + // item_version_type, plus a whole bunch of additional strong typedefs. + template + typename boost::disable_if >::type + load(T& t, dummy<4> = 0) + { + // we provide a generic load routine for all types that feature + // conversion operators into an unsigned integer value like those + // created through BOOST_STRONG_TYPEDEF(X, some unsigned int) like + // library_version_type, collection_size_type, item_version_type, + // class_id_type, object_id_type, version_type and tracking_type + load((typename boost::uint_t::least&)(t)); + } + }; + + // polymorphic portable binary iarchive typedef + typedef POLYMORPHIC(portable_iarchive) polymorphic_portable_iarchive; + #undef POLYMORPHIC + +} // namespace eos + +// this is required by export which registers all of your +// classes with all the inbuilt archives plus our archive. +#if BOOST_VERSION < 103500 +#define BOOST_ARCHIVE_CUSTOM_IARCHIVE_TYPES eos::portable_iarchive +#else +BOOST_SERIALIZATION_REGISTER_ARCHIVE(eos::portable_iarchive) +BOOST_SERIALIZATION_REGISTER_ARCHIVE(eos::polymorphic_portable_iarchive) +#endif + +// if you include this header multiple times and your compiler is picky +// about multiple template instantiations (eg. gcc is) then you need to +// define NO_EXPLICIT_TEMPLATE_INSTANTIATION before every include but one +// or you move the instantiation section into an implementation file +#ifndef NO_EXPLICIT_TEMPLATE_INSTANTIATION + +#include +#include + +#if BOOST_VERSION < 104000 +#include +#elif !defined BOOST_ARCHIVE_SERIALIZER_INCLUDED +#include +#define BOOST_ARCHIVE_SERIALIZER_INCLUDED +#endif + +namespace boost { namespace archive { + + // explicitly instantiate for this type of binary stream + template class basic_binary_iarchive; + + template class basic_binary_iprimitive< + eos::portable_iarchive + #if BOOST_VERSION < 103400 + , std::istream + #else + , std::istream::char_type + , std::istream::traits_type + #endif + >; + +#if BOOST_VERSION < 104000 + template class detail::archive_pointer_iserializer; +#else + template class detail::archive_serializer_map; + //template class detail::archive_serializer_map; +#endif + +} } // namespace boost::archive + +#endif diff --git a/contrib/eos_portable_archive/eos/portable_oarchive.hpp b/contrib/eos_portable_archive/eos/portable_oarchive.hpp new file mode 100644 index 00000000..67f3a695 --- /dev/null +++ b/contrib/eos_portable_archive/eos/portable_oarchive.hpp @@ -0,0 +1,474 @@ +/*****************************************************************************/ +/** + * \file portable_oarchive.hpp + * \brief Provides an archive to create portable binary files. + * \author christian.pfligersdorffer@gmx.at + * \version 5.0 + * + * This pair of archives brings the advantages of binary streams to the cross + * platform boost::serialization user. While being almost as fast as the native + * binary archive it allows its files to be exchanged between cpu architectures + * using different byte order (endianness). Speaking of speed: in serializing + * numbers the (portable) binary approach is approximately ten times faster than + * the ascii implementation (that is inherently portable)! + * + * Based on the portable archive example by Robert Ramey this implementation + * uses Beman Dawes endian library and fp_utilities from Johan Rade, both being + * in boost since 1.36. Prior to that you need to add them both (header only) + * to your boost directory before you're able to use the archives provided. + * Our archives have been tested successfully for boost versions 1.33 to 1.49! + * + * \note Correct behaviour has so far been confirmed using PowerPC-32, x86-32 + * and x86-64 platforms featuring different byte order. So there is a good + * chance it will instantly work for your specific setup. If you encounter + * problems or have suggestions please contact the author. + * + * \note Version 5.0 is now compatible with boost up to version 1.49 and enables + * serialization of std::wstring by converting it to/from utf8 (thanks to + * Arash Abghari for this suggestion). With that all unit tests from the + * serialization library pass again with the notable exception of user + * defined primitive types. Those are not supported and as a result any + * user defined type to be used with the portable archives are required + * to be at least object_serializable. + * + * \note Oliver Putz pointed out that -0.0 was not serialized correctly, so + * version 4.3 provides a fix for that. Thanks Ollie! + * + * \note Version 4.2 maintains compatibility with the latest boost 1.45 and adds + * serialization of special floating point values inf and NaN as proposed + * by Francois Mauger. + * + * \note Version 4.1 makes the archives work together with boost 1.40 and 1.41. + * Thanks to Francois Mauger for his suggestions. + * + * \note Version 4 removes one level of the inheritance hierarchy and directly + * builds upon binary primitive and basic binary archive, thereby fixing + * the last open issue regarding array serialization. Thanks to Robert + * Ramey for the hint. + * + * \note A few fixes introduced in version 3.1 let the archives pass all of the + * serialization tests. Thanks to Sergey Morozov for running the tests. + * Wouter Bijlsma pointed out where to find the fp_utilities and endian + * libraries headers inside the boost distribution. I would never have + * found them so thank him it works out of the box since boost 1.36. + * + * \note With Version 3.0 the archives have been made portable across different + * boost versions. For that purpose a header is added to the data that + * supplies the underlying serialization library version. Backwards + * compatibility is maintained by assuming library version boost 1.33 if + * the iarchive is created using the no_header flag. Whether a header is + * present or not can be guessed by peeking into the stream: the header's + * first byte is the magic number 127 coinciding with 'e'|'o'|'s' :-) + * + * \note Version 2.1 removes several compiler warnings and enhances floating + * point diagnostics to inform the user if some preconditions are violated + * on his platform. We do not strive for the universally portable solution + * in binary floating point serialization as desired by some boost users. + * Instead we support only the most widely used IEEE 754 format and try to + * detect when requirements are not met and hence our approach must fail. + * Contributions we made by Johan Rade and kos Mary. + * + * \note Version 2.0 fixes a serious bug that effectively transformed most + * of negative integral values into positive values! For example the two + * numbers -12 and 234 were stored in the same 8-bit pattern and later + * always restored to 234. This was fixed in this version in a way that + * does not change the interpretation of existing archives that did work + * because there were no negative numbers. The other way round archives + * created by version 2.0 and containing negative numbers will raise an + * integer type size exception when reading it with version 1.0. Thanks + * to Markus Frohnmaier for testing the archives and finding the bug. + * + * \copyright The boost software license applies. + */ +/*****************************************************************************/ + +#pragma once + +#include + +// basic headers +#include +#include +#include +#include +#if BOOST_VERSION >= 105600 +#include +#elif BOOST_VERSION >= 103500 +#include +#endif + +#if BOOST_VERSION >= 104500 +#include +#include +#endif + +// funny polymorphics +#if BOOST_VERSION < 103500 +#include +#define POLYMORPHIC(T) boost::archive::detail::polymorphic_oarchive_impl + +#elif BOOST_VERSION < 103600 +#include +#define POLYMORPHIC(T) boost::archive::detail::polymorphic_oarchive_dispatch + +#else +#include +#define POLYMORPHIC(T) boost::archive::detail::polymorphic_oarchive_route +#endif + +// endian and fpclassify +#if BOOST_VERSION < 103600 +#include +#include +#elif BOOST_VERSION < 104800 +#include +#include +#else +#include +#include +#endif + +// namespace alias fp_classify +#if BOOST_VERSION < 103800 +namespace fp = boost::math; +#else +namespace fp = boost::spirit::math; +#endif + +// namespace alias endian +#if BOOST_VERSION < 104800 +namespace endian = boost::detail; +#else +namespace endian = boost::spirit::detail; +#endif + +#ifndef BOOST_NO_STD_WSTRING +// used for wstring to utf8 conversion +#include +#include +#endif + +// generic type traits for numeric types +#include +#include +#include +#include + +#include "portable_archive_exception.hpp" + +// hint from Johan Rade: on VMS there is still support for +// the VAX floating point format and this macro detects it +#if defined(__vms) && defined(__DECCXX) && !__IEEE_FLOAT +#error "VAX floating point format is not supported!" +#endif + +namespace eos { + + // forward declaration + class portable_oarchive; + + typedef boost::archive::basic_binary_oprimitive< + portable_oarchive + #if BOOST_VERSION < 103400 + , std::ostream + #else + , std::ostream::char_type + , std::ostream::traits_type + #endif + > portable_oprimitive; + + /** + * \brief Portable binary output archive using little endian format. + * + * This archive addresses integer size, endianness and floating point types so + * that data can be transferred across different systems. The archive consists + * primarily of three different save implementations for integral types, + * floating point types and string types. Those functions are templates and use + * enable_if to be correctly selected for overloading. + * + * \note The class is based on the portable binary example by Robert Ramey and + * uses Beman Dawes endian library plus fp_utilities by Johan Rade. + */ + class portable_oarchive : public portable_oprimitive + + // the example derives from common_oarchive but that lacks the + // save_override functions so we chose to stay one level higher + , public boost::archive::basic_binary_oarchive + + #if BOOST_VERSION >= 105600 + // mix-in helper class for serializing shared_ptr does not exist anymore + #elif BOOST_VERSION >= 103500 + // mix-in helper class for serializing shared_ptr + , public boost::archive::detail::shared_ptr_helper + #endif + { + // workaround for gcc: use a dummy struct + // as additional argument type for overloading + template struct dummy { dummy(int) {}}; + + // stores a signed char directly to stream + inline void save_signed_char(const signed char& c) + { + portable_oprimitive::save(c); + } + + // archive initialization + void init(unsigned flags) + { + // it is vital to have version information if the archive is + // to be parsed with a newer version of boost::serialization + // therefor we create a header, no header means boost 1.33 + if (flags & boost::archive::no_header) + BOOST_ASSERT(archive_version == 3); + else + { + // write our minimalistic header (magic byte plus version) + // the boost archives write a string instead - by calling + // boost::archive::basic_binary_oarchive::init() + save_signed_char(magic_byte); + + // write current version +// save(archive_version); + operator<<(archive_version); + } + } + + public: + /** + * \brief Constructor on a stream using ios::binary mode! + * + * We cannot call basic_binary_oprimitive::init which stores type + * sizes to the archive in order to detect transfers to non-compatible + * platforms. + * + * We could have called basic_binary_oarchive::init which would create + * the boost::serialization standard archive header containing also the + * library version. Due to efficiency we stick with our own. + */ + portable_oarchive(std::ostream& os, unsigned flags = 0) + #if BOOST_VERSION < 103400 + : portable_oprimitive(os, flags & boost::archive::no_codecvt) + #else + : portable_oprimitive(*os.rdbuf(), flags & boost::archive::no_codecvt) + #endif + , boost::archive::basic_binary_oarchive(flags) + { + init(flags); + } + + #if BOOST_VERSION >= 103400 + portable_oarchive(std::streambuf& sb, unsigned flags = 0) + : portable_oprimitive(sb, flags & boost::archive::no_codecvt) + , boost::archive::basic_binary_oarchive(flags) + { + init(flags); + } + #endif + + //! Save narrow strings. + void save(const std::string& s) + { + portable_oprimitive::save(s); + } + + #ifndef BOOST_NO_STD_WSTRING + /** + * \brief Save wide strings. + * + * This is rather tricky to get right for true portability as there + * are so many different character encodings around. However, wide + * strings that are encoded in one of the Unicode schemes only need + * to be _transcoded_ which is a lot easier actually. + * + * We expect the input string to be encoded in the system's native + * format, ie. UTF-16 on Windows and UTF-32 on Linux machines. Don't + * know about Mac here so I can't really say about that. + */ + void save(const std::wstring& s) + { + save(boost::to_utf8(s)); + } + #endif + + /** + * \brief Saving bool type. + * + * Saving bool directly, not by const reference + * because of tracking_type's operator (bool). + * + * \note If you cannot compile your application and it says something + * about save(bool) cannot convert your type const A& into bool then + * you should check your BOOST_CLASS_IMPLEMENTATION setting for A, as + * portable_archive is not able to handle custom primitive types in + * a general manner. + */ + void save(const bool& b) + { + save_signed_char(b); + if (b) save_signed_char('T'); + } + + /** + * \brief Save integer types. + * + * First we save the size information ie. the number of bytes that hold the + * actual data. We subsequently transform the data using store_little_endian + * and store non-zero bytes to the stream. + */ + template + typename boost::enable_if >::type + save(const T & t, dummy<2> = 0) + { + if (T temp = t) + { + // examine the number of bytes + // needed to represent the number + signed char size = 0; + do { temp >>= CHAR_BIT; ++size; } + while (temp != 0 && temp != (T) -1); + + // encode the sign bit into the size + save_signed_char(t > 0 ? size : -size); + BOOST_ASSERT(t > 0 || boost::is_signed::value); + + // we choose to use little endian because this way we just + // save the first size bytes to the stream and skip the rest + endian::store_little_endian(&temp, t); + save_binary(&temp, size); + } + // zero optimization + else save_signed_char(0); + } + + /** + * \brief Save floating point types. + * + * We simply rely on fp_traits to extract the bit pattern into an (unsigned) + * integral type and store that into the stream. Francois Mauger provided + * standardized behaviour for special values like inf and NaN, that need to + * be serialized in his application. + * + * \note by Johan Rade (author of the floating point utilities library): + * Be warned that the math::detail::fp_traits::type::get_bits() function + * is *not* guaranteed to give you all bits of the floating point number. It + * will give you all bits if and only if there is an integer type that has + * the same size as the floating point you are copying from. It will not + * give you all bits for double if there is no uint64_t. It will not give + * you all bits for long double if sizeof(long double) > 8 or there is no + * uint64_t. + * + * The member fp_traits::type::coverage will tell you whether all bits + * are copied. This is a typedef for either math::detail::all_bits or + * math::detail::not_all_bits. + * + * If the function does not copy all bits, then it will copy the most + * significant bits. So if you serialize and deserialize the way you + * describe, and fp_traits::type::coverage is math::detail::not_all_bits, + * then your floating point numbers will be truncated. This will introduce + * small rounding off errors. + */ + template + typename boost::enable_if >::type + save(const T & t, dummy<3> = 0) + { + typedef typename fp::detail::fp_traits::type traits; + + // if the no_infnan flag is set we must throw here + if (get_flags() & no_infnan && !fp::isfinite(t)) + throw portable_archive_exception(t); + + // if you end here there are three possibilities: + // 1. you're serializing a long double which is not portable + // 2. you're serializing a double but have no 64 bit integer + // 3. your machine is using an unknown floating point format + // after reading the note above you still might decide to + // deactivate this static assert and try if it works out. + typename traits::bits bits; + BOOST_STATIC_ASSERT(sizeof(bits) == sizeof(T)); + BOOST_STATIC_ASSERT(std::numeric_limits::is_iec559); + + // examine value closely + switch (fp::fpclassify(t)) + { + //case FP_ZERO: bits = 0; break; + case FP_NAN: bits = traits::exponent | traits::mantissa; break; + case FP_INFINITE: bits = traits::exponent | (t<0) * traits::sign; break; + case FP_SUBNORMAL: assert(std::numeric_limits::has_denorm); // pass + case FP_ZERO: // note that floats can be 0.0 + case FP_NORMAL: traits::get_bits(t, bits); break; + default: throw portable_archive_exception(t); + } + + save(bits); + } + + // in boost 1.44 version_type was splitted into library_version_type and + // item_version_type, plus a whole bunch of additional strong typedefs. + template + typename boost::disable_if >::type + save(const T& t, dummy<4> = 0) + { + // we provide a generic save routine for all types that feature + // conversion operators into an unsigned integer value like those + // created through BOOST_STRONG_TYPEDEF(X, some unsigned int) like + // library_version_type, collection_size_type, item_version_type, + // class_id_type, object_id_type, version_type and tracking_type + save((typename boost::uint_t::least)(t)); + } + }; + + // polymorphic portable binary oarchive typedef + typedef POLYMORPHIC(portable_oarchive) polymorphic_portable_oarchive; + #undef POLYMORPHIC + +} // namespace eos + +// required by export +#if BOOST_VERSION < 103500 +#define BOOST_ARCHIVE_CUSTOM_OARCHIVE_TYPES eos::portable_oarchive +#else +BOOST_SERIALIZATION_REGISTER_ARCHIVE(eos::portable_oarchive) +BOOST_SERIALIZATION_REGISTER_ARCHIVE(eos::polymorphic_portable_oarchive) +#endif + +// if you include this header multiple times and your compiler is picky +// about multiple template instantiations (eg. gcc is) then you need to +// define NO_EXPLICIT_TEMPLATE_INSTANTIATION before every include but one +// or you move the instantiation section into an implementation file +#ifndef NO_EXPLICIT_TEMPLATE_INSTANTIATION + +#include +#include + +#if BOOST_VERSION < 104000 +#include +#elif !defined BOOST_ARCHIVE_SERIALIZER_INCLUDED +#include +#define BOOST_ARCHIVE_SERIALIZER_INCLUDED +#endif + +namespace boost { namespace archive { + + // explicitly instantiate for this type of binary stream + template class basic_binary_oarchive; + + template class basic_binary_oprimitive< + eos::portable_oarchive + #if BOOST_VERSION < 103400 + , std::ostream + #else + , std::ostream::char_type + , std::ostream::traits_type + #endif + >; + +#if BOOST_VERSION < 104000 + template class detail::archive_pointer_oserializer; +#else + template class detail::archive_serializer_map; + //template class detail::archive_serializer_map; +#endif + +} } // namespace boost::archive + +#endif diff --git a/contrib/eos_portable_archive/release_notes.txt b/contrib/eos_portable_archive/release_notes.txt new file mode 100644 index 00000000..42e1fbdf --- /dev/null +++ b/contrib/eos_portable_archive/release_notes.txt @@ -0,0 +1,36 @@ +IMPORTANT: + +This is the last release from me as EOS employee. I plan to contribute all of this +work to the official boost libraries distribution and will continue to support users. +Francois Mauger joined me recently and already added a valuable tutorial for you! + + +Dear user, + +I am proud to announce the very first release of our portable_binary_[io]archive +which we use here at EOS to move data between different platforms. It really is +a conglomerate of pieces that already were there - as is most often the case in +OO world - we simply put them together in a way that seemed to make sense. I know +a lot of people were interested in portable binary archives, so here you are - +give it a try and let me know what you think about it! + +We rely heavily on boost::serialization and really appreciate the amount of time +and knowledge that went into it. By publishing this small missing piece we hope +to contribute our mite to this great library. + +The work extends the portable binary example which was done by Robert Ramey and +uses Beman Dawes' endian library plus the fp_utilities by Johan Rade. You will +need to get those two libraries in order to use our classes - look for them at +the boost vault (http://www.boost-consulting.com/vault/) in categories 'integer' +and 'math - numerics'. Finally you will find the portable binary archive in +category 'serialization' as well. + +Regards, +Christian Pfligersdorffer + +Munich, End of 2007 + +-- +christian.pfligersdorffer@eos.info +christian.pfligersdorffer@gmx.at +http://www.eos.info \ No newline at end of file diff --git a/contrib/eos_portable_archive/tutorial/code/tutorial_pba_0.cpp b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_0.cpp new file mode 100644 index 00000000..aaec78c7 --- /dev/null +++ b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_0.cpp @@ -0,0 +1,56 @@ +/** tutorial_pba_0.cpp + * + * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer + * + * Use, modification and distribution is subject to the Boost Software + * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ + +/** + * The intent of this program is to serve as a tutorial for + * users of the portable binary archive in the framework of + * the Boost/Serialization library. + * + * This quick start example shows how to store some variables + * of basic types (bool, integer, floating point numbers, STL string) + * using the portable binary archive format associated to a + * standard output file stream. + * + */ + +#include +#include + +#include +#include + +int main (void) +{ + // The name for the example data file : + std::string filename = "pba_0.data"; + + // Some variables of various primitive types : + bool b = true; + char c = 'B'; + uint32_t answer = 42; + float computing_time = 7.5e6; + double e = 2.71828182845905; + std::string slogan = "DON'T PANIC"; + + // Open an output file stream in binary mode : + std::ofstream fout (filename.c_str (), std::ios_base::binary); + + { + // Create an output portable binary archive attached to the output file : + boost::archive::portable_binary_oarchive opba (fout); + + // Store (serializing) variables : + opba & b & c & answer & computing_time & e & slogan; + } + + return 0; +} + +// end of tutorial_pba_0.cpp diff --git a/contrib/eos_portable_archive/tutorial/code/tutorial_pba_1.cpp b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_1.cpp new file mode 100644 index 00000000..1b5fb8fc --- /dev/null +++ b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_1.cpp @@ -0,0 +1,68 @@ +/** tutorial_pba_1.cpp + * + * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer + * + * Use, modification and distribution is subject to the Boost Software + * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ + +/** + * The intent of this program is to serve as a tutorial for + * users of the portable binary archive in the framework of + * the Boost/Serialization package. + * + * This quick start example shows how to load some variables + * of basic types (bool, integer, floating point numbers, STL string) + * using the portable binary archive format associated to a + * standard input file stream. + * + */ + +#include +#include +#include + +#include +#include + +int main (void) +{ + using namespace std; + + // The name for the example data file : + string filename = "pba_0.data"; + + // Some variables of various types : + bool b; + char c; + uint32_t answer; + float computing_time; + double e; + string slogan; + + // Open an input file stream in binary mode : + ifstream fin (filename.c_str (), ios_base::binary); + + { + // Create an input portable binary archive attached to the input file : + boost::archive::portable_binary_iarchive ipba (fin); + + // Loading (de-serializing) variables using the same + // order than for serialization (see tutorial_pba_0.cpp) : + ipba & b & c & answer & computing_time & e & slogan; + } + + cout.precision (15); + cout << "Variable 'b' is : " << b << " " << "(bool)" << endl; + cout << "Variable 'c' is : '" << c << "' " << " " << "(char)" << endl; + cout << "Variable 'answer' is : " << answer << " " << "(unsigned 32-bit integer)" << endl; + cout << "Variable 'computing_time' is : " << computing_time << " " << "(single precision 32-bit float)" << endl; + cout << "Variable 'e' is : " << e << " " << "(double precision 64-bit float)" << endl; + cout << "Variable 'slogan' is : \"" << slogan << "\" " << "(std::string)" << endl; + + return 0; +} + +// end of tutorial_pba_1.cpp diff --git a/contrib/eos_portable_archive/tutorial/code/tutorial_pba_10.cpp b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_10.cpp new file mode 100644 index 00000000..a2d44391 --- /dev/null +++ b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_10.cpp @@ -0,0 +1,162 @@ +/** tutorial_pba_10.cpp + * + * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer + * + * Use, modification and distribution is subject to the Boost Software + * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ + +/** + * The intent of this program is to serve as a tutorial for + * users of the portable binary archive in the framework of + * the Boost/Serialization library. + * + * This example shows how use PBAs combined with on-the-fly + * compressed I/O streams. + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +class data_type +{ +private: + friend class boost::serialization::access; + template + void serialize (Archive & ar, const unsigned int version); +public: + void print (ostream & out, const string & title) const; +public: + vector values; + data_type (); +}; + +data_type::data_type () : values () +{ + return; +} + +void data_type::print (ostream & out, const string & title) const +{ + out << endl; + out << title << " :" << endl; + for (int i = 0; i < this->values.size (); ++i) + { + out.precision (16); + out.width (18); + out << this->values [i] << ' ' ; + if ((i%4) == 3) clog << endl; + } + out << endl; + return; +} + +template +void data_type::serialize (Archive & ar, const unsigned int version) +{ + ar & values; + return; +} + +void do_gzipped_out (void) +{ + // The name for the output data file : + string filename = "pba_10.data.gz"; + + // A data structure to be stored : + data_type my_data; + + // Fill the vector with arbitrary (possibly non-finite) values : + size_t dim = 1000; + my_data.values.reserve (dim); + for (int i = 0; i < dim; ++i) + { + double val = (i + 1) * (1.0 + 3 * numeric_limits::epsilon ()); + if (i == 4) val = numeric_limits::quiet_NaN (); + if (i == 23) val = numeric_limits::infinity (); + if (i == 73) val = -numeric_limits::infinity (); + if (i == 90) val = 0.0; + my_data.values.push_back (val); + } + + // Print: + my_data.print (clog, "Stored data"); + + // Create an output filtering stream : + boost::iostreams::filtering_ostream zout; + zout.push (boost::iostreams::gzip_compressor ()); + + // Open an output file stream in binary mode : + ofstream fout (filename.c_str (), ios_base::binary); + zout.push (fout); + + // Save to PBA : + { + // Create an output portable binary archive attached to the output file : + boost::archive::portable_binary_oarchive opba (zout); + + // Store (serializing) the data : + opba & my_data; + } + + // Clean termination of the streams : + zout.flush (); + zout.reset (); + + return; +} + +void do_gzipped_in (void) +{ + // The name for the input data file : + string filename = "pba_10.data.gz"; + + // A data structure to be loaded : + data_type my_data; + + // Create an input filtering stream : + boost::iostreams::filtering_istream zin; + zin.push (boost::iostreams::gzip_decompressor ()); + + // Open an input file stream in binary mode : + ifstream fin (filename.c_str (), ios_base::binary); + zin.push (fin); + + // Load from PBA : + { + // Create an input portable binary archive attached to the input file : + boost::archive::portable_binary_iarchive ipba (zin); + + // Load (deserializing) the data : + ipba & my_data; + } + + // Print: + my_data.print (clog, "Loaded data"); + + return; +} + +int main (void) +{ + do_gzipped_out (); + do_gzipped_in (); + return 0; +} + +// end of tutorial_pba_10.cpp diff --git a/contrib/eos_portable_archive/tutorial/code/tutorial_pba_10b.cpp b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_10b.cpp new file mode 100644 index 00000000..f1695f4d --- /dev/null +++ b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_10b.cpp @@ -0,0 +1,198 @@ +/** tutorial_pba_10b.cpp + * + * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer + * + * Use, modification and distribution is subject to the Boost Software + * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ + +/** + * The intent of this program is to serve as a tutorial for + * users of the portable binary archive in the framework of + * the Boost/Serialization library. + * + * This example shows how use PBAs combined with on-the-fly + * compressed I/O streams. + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +class data_type +{ +private: + friend class boost::serialization::access; + template + void serialize (Archive & ar, const unsigned int version); +public: + void print (ostream & out, const string & title) const; +public: + vector values; + data_type (); +}; + +//BOOST_CLASS_VERSION(data_type, 7) + +data_type::data_type () : values () +{ + return; +} + +void data_type::print (ostream & out, const string & title) const +{ + out << endl; + out << title << " :" << endl; + for (int i = 0; i < this->values.size (); ++i) + { + out.precision (16); + out.width (18); + out << this->values [i] << ' ' ; + if ((i%4) == 3) clog << endl; + } + out << endl; + return; +} + +template +void data_type::serialize (Archive & ar, const unsigned int version) +{ + ar & BOOST_SERIALIZATION_NVP (values); + return; +} + +class data_type2 +{ +private: + friend class boost::serialization::access; + template + void serialize (Archive & ar, const unsigned int version); +public: + double value; + data_type2 (); +}; + +BOOST_CLASS_VERSION(data_type2, 99) + +data_type2::data_type2 () : value (666.666) +{ + return; +} + +template +void data_type2::serialize (Archive & ar, const unsigned int version) +{ + ar & BOOST_SERIALIZATION_NVP (value); + return; +} + +class data_type3 +{ +private: + friend class boost::serialization::access; + template + void serialize (Archive & ar, const unsigned int version); +public: + vector values; + data_type3 (); +}; + +BOOST_CLASS_VERSION(data_type3, 33) + +data_type3::data_type3 () +{ + { + data_type2 d; + d.value = 6.66; + values.push_back (d); + } + { + data_type2 d; + d.value = 66.66; + values.push_back (d); + } + { + data_type2 d; + d.value = 666.66; + values.push_back (d); + } + return; +} + +template +void data_type3::serialize (Archive & ar, const unsigned int version) +{ + ar & BOOST_SERIALIZATION_NVP (values); + return; +} + +/********************/ + +void do_xml_out (void) +{ + // The name for the output data file : + string filename = "pba_10.xml"; + + // A data structure to be stored : + data_type my_data; + + // Fill the vector with arbitrary (possibly non-finite) values : + size_t dim = 6; + my_data.values.reserve (dim); + for (int i = 0; i < dim; ++i) + { + double val = (i + 1) * (1.0 + 3 * numeric_limits::epsilon ()); + if (i == 4) val = numeric_limits::quiet_NaN (); + if (i == 7) val = numeric_limits::infinity (); + if (i == 9) val = -numeric_limits::infinity (); + if (i == 13) val = 0.0; + my_data.values.push_back (val); + } + + // Print: + my_data.print (clog, "Stored data"); + + data_type2 my_data2; + data_type3 my_data3; + + // Open an output file stream in binary mode : + ofstream fout (filename.c_str ()); + + // Save to PBA : + { + // Create an output XML archive attached to the output file : + boost::archive::xml_oarchive oxa (fout); + + // Store (serializing) the data : + oxa & BOOST_SERIALIZATION_NVP(my_data); + oxa & BOOST_SERIALIZATION_NVP(my_data2); + oxa & BOOST_SERIALIZATION_NVP(my_data3); + } + + return; +} + +int main (void) +{ + do_xml_out (); + return 0; +} + +// end of tutorial_pba_10b.cpp diff --git a/contrib/eos_portable_archive/tutorial/code/tutorial_pba_11.cpp b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_11.cpp new file mode 100644 index 00000000..3e606480 --- /dev/null +++ b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_11.cpp @@ -0,0 +1,187 @@ +/** tutorial_pba_11.cpp + * + * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer + * + * Use, modification and distribution is subject to the Boost Software + * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ + +/** + * The intent of this program is to serve as a tutorial for + * users of the portable binary archive in the framework of + * the Boost/Serialization library. + * + * This example program compares the times needed to serialize + * and deserialize some large amount of data using PBA and + * text archives. + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +class data_type +{ +private: + friend class boost::serialization::access; + template + void serialize (Archive & ar, const unsigned int version); +public: + void print (ostream & out, const string & title) const; +public: + vector values; + data_type (); +}; + +data_type::data_type () : values () +{ + return; +} + +void data_type::print (ostream & out, const string & title) const +{ + out << endl; + out << title << " :" << endl; + bool skip = false; + for (int i = 0; i < this->values.size (); ++i) + { + if ((i >= 12) && (i < (int) this->values.size () - 8)) + { + if (! skip) out << " ..." << endl; + skip = true; + continue; + } + out.precision (16); + out.width (18); + out << this->values [i] << ' ' ; + if ((i%4) == 3) clog << endl; + } + out << endl; + return; +} + +template +void data_type::serialize (Archive & ar, const unsigned int version) +{ + ar & values; + return; +} + +double do_pba_out (const data_type & a_data) +{ + string filename = "pba_11.data"; + ofstream fout (filename.c_str (), ios_base::binary); + boost::timer io_timer; + { + boost::archive::portable_binary_oarchive opba (fout); + opba & a_data; + } + return io_timer.elapsed (); +} + +double do_pba_in (data_type & a_data) +{ + string filename = "pba_11.data"; + ifstream fin (filename.c_str (), ios_base::binary); + boost::timer io_timer; + { + boost::archive::portable_binary_iarchive ipba (fin); + ipba & a_data; + } + return io_timer.elapsed (); +} + +double do_text_out (const data_type & a_data) +{ + string filename = "pba_11.txt"; + ofstream fout (filename.c_str ()); + boost::timer io_timer; + { + boost::archive::text_oarchive ota (fout); + ota & a_data; + } + return io_timer.elapsed (); +} + +double do_text_in (data_type & a_data) +{ + string filename = "pba_11.txt"; + ifstream fin (filename.c_str ()); + boost::timer io_timer; + { + boost::archive::text_iarchive ita (fin); + ita & a_data; + } + return io_timer.elapsed (); +} + +int main (void) +{ + double elapsed_time_pba_out; + double elapsed_time_text_out; + double elapsed_time_pba_in; + double elapsed_time_text_in; + data_type my_data; // A data structure to be stored then loaded. + + { + // Fill the vector with random values : + size_t dim = 10000000; + my_data.values.reserve (dim); + boost::random::mt19937 rng; + boost::random::uniform_real_distribution<> flat (0.0, 100.0); + for (int i = 0; i < dim; ++i) + { + double val = flat (rng); + my_data.values.push_back (val); + } + my_data.print (clog, "Stored data in PBA and text archive"); + } + + { + // Store in PBA : + elapsed_time_pba_out = do_pba_out (my_data); + } + + { + // Store in text archive : + elapsed_time_text_out = do_text_out (my_data); + } + + { + my_data.values.clear (); + // Load from PBA : + elapsed_time_pba_in = do_pba_in (my_data); + my_data.print (clog, "Loaded data from PBA"); + } + + { + my_data.values.clear (); + // Load from text archive : + elapsed_time_text_in = do_text_in (my_data); + my_data.print (clog, "Loaded data from text archive"); + } + + clog << "PBA store I/O elapsed time : " << elapsed_time_pba_out << " (second)" << endl; + clog << "Text store I/O elapsed time : " << elapsed_time_text_out << " (second)" << endl; + clog << "PBA load I/O elapsed time : " << elapsed_time_pba_in << " (second)" << endl; + clog << "Text load I/O elapsed time : " << elapsed_time_text_in << " (second)" << endl; + + return 0; +} + +// end of tutorial_pba_11.cpp diff --git a/contrib/eos_portable_archive/tutorial/code/tutorial_pba_2.cpp b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_2.cpp new file mode 100644 index 00000000..7f6c875b --- /dev/null +++ b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_2.cpp @@ -0,0 +1,105 @@ +/** tutorial_pba_2.cpp + * + * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer + * + * Use, modification and distribution is subject to the Boost Software + * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ + +/** + * The intent of this program is to serve as a tutorial for + * users of the portable binary archive in the framework of + * the Boost/Serialization library. + * + * This sample program shows how to use a portable binary archive + * to store/load floating point numbers including non-finite and + * special (denormalized) values. + * + */ + +#include +#include +#include + +#include +#include + +int main (void) +{ + using namespace std; + + // The name for the example data file : + string filename = "pba_2.data"; + + { + // A normal single precision floating point number : + float pi = 3.14159265; + + // Single precision zeroed floating point number : + float zero = 0.0; + + // A denormalized single precision floating point number : + float tiny = 1.e-40; + + // A single precision floating point number with `+Infinity' value : + float plus_infinity = numeric_limits::infinity (); + + // A single precision floating point number with `-Infinity' value : + float minus_infinity = -numeric_limits::infinity (); + + // A single precision `Not-a-Number' (NaN): + float nan = numeric_limits::quiet_NaN (); + + // Open an output file stream in binary mode : + ofstream fout (filename.c_str (), ios_base::binary); + + { + // Create an output portable binary archive attached to the output file : + boost::archive::portable_binary_oarchive opba (fout); + + // Store (serialize) variables : + opba & pi & zero & tiny & plus_infinity & minus_infinity & nan; + } + } + + { + // Single precision floating point numbers to be loaded : + float x[6]; + + // Open an input file stream in binary mode : + ifstream fin (filename.c_str (), ios_base::binary); + + { + // Create an input portable binary archive attached to the input file : + boost::archive::portable_binary_iarchive ipba (fin); + + // Load (de-serialize) variables using the same + // order than for serialization : + for (int i = 0; i < 6; ++i) + { + ipba & x[i]; + } + } + + // Print : + for (int i = 0; i < 6; ++i) + { + cout.precision (8); + cout << "Loaded x[" << i << "] = " << x[i]; + switch (fp::fpclassify(x[i])) + { + case FP_NAN: cout << " (NaN)"; break; + case FP_INFINITE: cout << " (infinite)"; break; + case FP_SUBNORMAL: cout << " (denormalized)"; break; + case FP_NORMAL: cout << " (normalized)"; break; + } + cout << endl; + } + } + + return 0; +} + +// end of tutorial_pba_2.cpp diff --git a/contrib/eos_portable_archive/tutorial/code/tutorial_pba_3.cpp b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_3.cpp new file mode 100644 index 00000000..42df3bf9 --- /dev/null +++ b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_3.cpp @@ -0,0 +1,70 @@ +/** tutorial_pba_3.cpp + * + * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer + * + * Use, modification and distribution is subject to the Boost Software + * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ + +/** + * The intent of this program is to serve as a tutorial for + * users of the portable binary archive in the framework of + * the Boost/Serialization library. + * + * This sample program shows how to use a portable binary archive + * and prevent the serialization of non-finite floating numbers. + * + */ + +#include +#include +#include + +#include + +int main (void) +{ + using namespace std; + + // The name for the example data file : + string filename = "pba_3.data"; + + try + { + // An array of single precision floating numbers: + float x[5]; + x[0] = 3.14159; // Pi + x[1] = 6.022e22; // Avogadro constant + x[2] = 1.6e-19; // Electron charge magnitude + x[3] = 1.e-40; // A tiny (denormalized) value + x[4] = numeric_limits::infinity (); // This will fail while serializing... + + // Open an output file stream in binary mode : + ofstream fout (filename.c_str (), ios_base::binary); + + { + // Create an output portable binary archive attached to the output file, + // using the special 'boost::archive::no_infnan' flag : + boost::archive::portable_binary_oarchive opba (fout, boost::archive::no_infnan); + + // Store (serialize) variables : + for (int i = 0; i < 5; ++i) + { + clog << "Serializing value : " << x[i] << " ... "; + opba & x[i]; + clog << "Ok !" << endl; + } + } + } + catch (exception & x) + { + cerr << "ERROR: " << x.what () << endl; + return 1; + } + + return 0; +} + +// end of tutorial_pba_3.cpp diff --git a/contrib/eos_portable_archive/tutorial/code/tutorial_pba_4.cpp b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_4.cpp new file mode 100644 index 00000000..61d05f6f --- /dev/null +++ b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_4.cpp @@ -0,0 +1,105 @@ +/** tutorial_pba_4.cpp + * + * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer + * + * Use, modification and distribution is subject to the Boost Software + * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ + +/** + * The intent of this program is to serve as a tutorial for + * users of the portable binary archive in the framework of + * the Boost/Serialization library. + * + * This sample program shows how to use a portable binary archive + * to store/load integer numbers of various sizes using the Boost + * portable integer typedefs. + * + */ + +#include +#include + +#include +#include +#include + +int main (void) +{ + using namespace std; + + // The name for the example data file : + string filename = "pba_4.data"; + + { + // Some integer numbers : + bool t = true; + char c = 'c'; + unsigned char u = 'u'; + int8_t b = -3; // char + uint8_t B = +6; // unsigned char + int16_t s = -16; + uint16_t S = +32; + int32_t l = -128; + uint32_t L = +127; + int64_t ll = -1024; + uint64_t LL = +2048; + + // Open an output file stream in binary mode : + ofstream fout (filename.c_str (), ios_base::binary); + + { + // Create an output portable binary archive attached to the output file : + boost::archive::portable_binary_oarchive opba (fout); + + // Store (serialize) variables : + opba & t & c & u & b & B & s & S & l & L & ll & LL; + } + } + + { + // Single precision floating numbers to be loaded : + // Some integer numbers : + bool t; + char c; + unsigned char u; + int8_t b; + uint8_t B; + int16_t s; + uint16_t S; + int32_t l; + uint32_t L; + int64_t ll; + uint64_t LL; + + // Open an input file stream in binary mode : + ifstream fin (filename.c_str (), ios_base::binary); + + { + // Create an input portable binary archive attached to the input file : + boost::archive::portable_binary_iarchive ipba (fin); + + // Load (de-serialize) variables using the same + // order than for serialization : + ipba & t & c & u & b & B & s & S & l & L & ll & LL; + } + + clog << "t = " << t << " (bool)" << endl; + clog << "c = '" << c << "' (char)" << endl; + clog << "u = '" << u << "' (unsigned char)" << endl; + clog << "b = " << (int) b << " (int8_t)" << endl; + clog << "B = " << (int) B << " (uint8_t)" << endl; + clog << "s = " << s << " (int16_t)" << endl; + clog << "S = " << S << " (uint16_t)" << endl; + clog << "l = " << l << " (int32_t)" << endl; + clog << "L = " << L << " (uint32_t)" << endl; + clog << "ll = " << ll << " (int64_t)" << endl; + clog << "LL = " << LL << " (uint64_t)" << endl; + } + + return 0; +} + +// end of tutorial_pba_4.cpp diff --git a/contrib/eos_portable_archive/tutorial/code/tutorial_pba_5.cpp b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_5.cpp new file mode 100644 index 00000000..18f61392 --- /dev/null +++ b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_5.cpp @@ -0,0 +1,111 @@ +/** tutorial_pba_5.cpp + * + * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer + * + * Use, modification and distribution is subject to the Boost Software + * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ + +/** + * The intent of this program is to serve as a tutorial for + * users of the portable binary archive in the framework of + * the Boost/Serialization library. + * + * This sample program shows how to use a portable binary archive + * to store/load data in a memory buffer. + * + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include + +int main (void) +{ + using namespace std; + + // The memory buffer is implemented using a STL vector : + typedef std::vector buffer_type; + buffer_type buffer; + + { + // Some data to be stored : + bool t = true; + char c = 'c'; + int16_t s = +16; + int32_t l = -128; + int64_t ll = +10000000000; + float pi = 3.14159; + double nan = numeric_limits::quiet_NaN (); + string hello = "World !"; + + buffer.reserve (1024); // pre-allocate some memory + + // The output stream interface to the buffer : + boost::iostreams::stream > output_stream (buffer); + + { + // Create an output portable binary archive attached to the output file : + boost::archive::portable_binary_oarchive opba (output_stream); + + // Store (serialize) variables : + opba & t & c & s & l & ll & pi & nan & hello; + } + + } + + clog << "Buffer content is " << buffer.size () << " bytes : " << endl << " "; + for (int i = 0; i < buffer.size (); ++i) + { + clog << (int) ((unsigned char) buffer[i]) << ' '; + if ((i + 1) % 20 == 0) clog << endl << " "; + } + clog << endl; + + { + // Some data to be loaded : + bool t; + char c; + int16_t s; + int32_t l; + int64_t ll; + float pi; + double nan; + string hello; + + // The input stream interface to the buffer : + boost::iostreams::stream input_stream (&buffer[0], + buffer.size ()); + + { + // Create an input portable binary archive attached to the input file : + boost::archive::portable_binary_iarchive ipba (input_stream); + + // Load (de-serialize) variables : + ipba & t & c & s & l & ll & pi & nan & hello; + } + + clog << "Loaded values from the buffer are: " << endl; + clog << " t = " << t << " (bool)" << endl; + clog << " c = '" << c << "' (char)" << endl; + clog << " s = " << s << " (int16_t)" << endl; + clog << " l = " << l << " (int32_t)" << endl; + clog << " ll = " << ll << " (int64_t)" << endl; + clog << " pi = " << pi << " (float)" << endl; + clog << " nan = " << nan << " (double)" << endl; + clog << " hello = \"" << hello << "\" (std::string)" << endl; + } + + return 0; +} + +// end of tutorial_pba_5.cpp diff --git a/contrib/eos_portable_archive/tutorial/code/tutorial_pba_6.cpp b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_6.cpp new file mode 100644 index 00000000..f32659a4 --- /dev/null +++ b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_6.cpp @@ -0,0 +1,112 @@ +/** tutorial_pba_6.cpp + * + * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer + * + * Use, modification and distribution is subject to the Boost Software + * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ + +/** + * The intent of this program is to serve as a tutorial for + * users of the portable binary archive in the framework of + * the Boost/Serialization library. + * + * This sample program shows how to use a portable binary archive + * associated to a memory buffer to copy a non-copyable object. + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +using namespace std; + +/* A foo noncopyable class */ +struct foo : boost::noncopyable +{ + uint32_t status; + double value; + double special; + + string to_string () const + { + ostringstream sout; + sout << "foo={status=" << status << "; value=" << value << "; special=" << special<< "}"; + return sout.str(); + } + + template + void serialize (Archive & ar, const unsigned int version) + { + ar & status; + ar & value; + ar & special; + return; + } + +}; + +// A templatized copy function for Boost/Serialization equipped classes. +// Here we use PBAs associated to a memory buffer : +template +void copy (const Serializable & source, Serializable & target) +{ + namespace io = boost::iostreams; + namespace ba = boost::archive; + if (&source == &target) return; // self-copy guard + typedef std::vector buffer_type; + buffer_type buffer; + buffer.reserve (1024); + { + io::stream > output_stream (buffer); + ba::portable_binary_oarchive opba (output_stream); + opba & source; + } + { + io::stream input_stream (&buffer[0], buffer.size ()); + ba::portable_binary_iarchive ipba (input_stream); + ipba & target; + } + return; +} + +int main (void) +{ + // Some instance of the 'foo' class : + foo dummy; + dummy.status = 1; + dummy.value = 3.14159; + dummy.special = numeric_limits::quiet_NaN (); + clog << "dummy is : " << dummy.to_string () << endl; + + // Another instance of the 'foo' class : + foo clone; + + /* The following instruction is forbidden because foo + inherits 'boost::noncopyable' : + + clone = dummy; // this ends in a compilation error. + + */ + + // Anyway, we can use this workaround : + copy (dummy, clone); + clog << "clone is : " << clone.to_string () << endl; + + return 0; +} + +// end of tutorial_pba_6.cpp diff --git a/contrib/eos_portable_archive/tutorial/code/tutorial_pba_7.cpp b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_7.cpp new file mode 100644 index 00000000..30722b18 --- /dev/null +++ b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_7.cpp @@ -0,0 +1,54 @@ +/** tutorial_pba_7.cpp + * + * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer + * + * Use, modification and distribution is subject to the Boost Software + * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ + +/** + * The intent of this program is to serve as a tutorial for + * users of the portable binary archive in the framework of + * the Boost/Serialization library. + * + * This example shows how the default behaviour of standard + * I/O streams does not support the read/write operations of + * non-finite floating point values in a portable way. + * + */ + +#include +#include +#include +#include + +using namespace std; + +int main (void) +{ + { + float x = numeric_limits::infinity (); + double y = numeric_limits::quiet_NaN (); + cout.precision (8); + cout << "x = " << x << endl; + cout.precision (16); + cout << "y = " << y << endl; + } + + { + string input ("inf nan"); + istringstream iss (input); + float x; + double y; + iss >> x >> y; + if (! iss) + { + cerr << "Cannot read 'x' or 'y' : non finite values are not supported !" << endl; + } + } + return 0; +} + +// end of tutorial_pba_7.cpp diff --git a/contrib/eos_portable_archive/tutorial/code/tutorial_pba_8.cpp b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_8.cpp new file mode 100644 index 00000000..a41e46fb --- /dev/null +++ b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_8.cpp @@ -0,0 +1,118 @@ +/** tutorial_pba_8.cpp + * + * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer + * + * Use, modification and distribution is subject to the Boost Software + * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ + +/** + * The intent of this program is to serve as a tutorial for + * users of the portable binary archive in the framework of + * the Boost/Serialization library. + * + * This example shows how to store some variables + * of basic types (bool, integer, floating point numbers, STL string) + * using the text or XML archive format associated to a + * standard output file stream supporting portable non-finite + * floating point values. + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace std; + +void do_text_out (void) +{ + // The name for the example data text file : + string filename = "pba_8.txt"; + + // Some variables of various primitive types : + bool b = true; + char c = 'B'; + uint32_t answer = 42; + float value = numeric_limits::infinity (); + double precision = numeric_limits::quiet_NaN (); + string question = "What makes you think she's a witch?"; + + // Open an output file stream : + ofstream fout (filename.c_str ()); + + // Prepare the output file stream for inf/NaN support : + locale default_locale (locale::classic (), + new boost::archive::codecvt_null); + locale infnan_locale (default_locale, + new boost::math::nonfinite_num_put); + fout.imbue (infnan_locale); + + { + // Create an output text archive attached to the output file : + boost::archive::text_oarchive ota (fout, boost::archive::no_codecvt); + + // Store (serializing) variables : + ota & b & c & answer & value & precision & question; + } + + return; +} + +void do_xml_out (void) +{ + // The name for the example data XML file : + string filename = "pba_8.xml"; + + // Some variables of various primitive types : + bool b = true; + char c = 'B'; + uint32_t answer = 42; + float value = numeric_limits::infinity (); + double precision = numeric_limits::quiet_NaN (); + string question = "What makes you think she's a witch?"; + + // Open an output file stream : + ofstream fout (filename.c_str ()); + + // Prepare the output file stream for inf/NaN support : + locale default_locale (locale::classic (), + new boost::archive::codecvt_null); + locale infnan_locale (default_locale, + new boost::math::nonfinite_num_put); + fout.imbue (infnan_locale); + + { + // Create an output text archive attached to the output file : + boost::archive::xml_oarchive oxa (fout, boost::archive::no_codecvt); + + // Store (serializing) variables : + oxa & BOOST_SERIALIZATION_NVP(b) + & BOOST_SERIALIZATION_NVP(c) + & BOOST_SERIALIZATION_NVP(answer) + & BOOST_SERIALIZATION_NVP(value) + & BOOST_SERIALIZATION_NVP(precision) + & BOOST_SERIALIZATION_NVP(question); + } + + return; +} + +int main (void) +{ + do_text_out (); + do_xml_out (); + return 0; +} + +// end of tutorial_pba_8.cpp diff --git a/contrib/eos_portable_archive/tutorial/code/tutorial_pba_9.cpp b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_9.cpp new file mode 100644 index 00000000..ff564be1 --- /dev/null +++ b/contrib/eos_portable_archive/tutorial/code/tutorial_pba_9.cpp @@ -0,0 +1,134 @@ +/** tutorial_pba_9.cpp + * + * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer + * + * Use, modification and distribution is subject to the Boost Software + * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ + +/** + * The intent of this program is to serve as a tutorial for + * users of the portable binary archive in the framework of + * the Boost/Serialization library. + * + * This example shows how to load some variables of basic + * types (bool, char, integer, floating point numbers, STL string) + * using the text or XML archive format associated to a + * standard file input stream supporting portable non-finite + * floating point values. + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +void do_text_in (void) +{ + // The name for the example data text file : + string filename = "pba_8.txt"; + // Some variables of various primitive types : + bool b; + char c; + uint32_t answer; + float value; + double precision; + string question; + + // Open an input file stream : + ifstream fin (filename.c_str ()); + + // Prepare the input file stream for inf/NaN support : + locale default_locale (locale::classic (), + new boost::archive::codecvt_null); + locale infnan_locale (default_locale, + new boost::math::nonfinite_num_get); + fin.imbue (infnan_locale); + + { + // Create an input text archive attached to the input file : + boost::archive::text_iarchive ita (fin, boost::archive::no_codecvt); + + // Store (serializing) variables : + ita & b & c & answer & value & precision & question; + } + + clog << "Loaded values from text archive are: " << endl; + clog << " b = " << b << endl; + clog << " c = '" << c << "'" << endl; + clog << " answer = " << answer << endl; + clog << " value = " << value << endl; + clog << " precision = " << precision << endl; + clog << " question = \"" << question << "\"" << endl; + + return; +} + +void do_xml_in (void) +{ + // The name for the example data text file : + string filename = "pba_8.xml"; + + // Some variables of various primitive types : + bool b; + char c; + uint32_t answer; + float value; + double precision; + string question; + + // Open an input file stream : + ifstream fin (filename.c_str ()); + + // Prepare the input file stream for inf/NaN support : + locale default_locale (locale::classic (), + new boost::archive::codecvt_null); + locale infnan_locale (default_locale, + new boost::math::nonfinite_num_get); + fin.imbue (infnan_locale); + + { + // Create an output text archive attached to the output file : + boost::archive::xml_iarchive ixa (fin, boost::archive::no_codecvt); + + // Store (serializing) variables : + ixa & BOOST_SERIALIZATION_NVP(b) + & BOOST_SERIALIZATION_NVP(c) + & BOOST_SERIALIZATION_NVP(answer) + & BOOST_SERIALIZATION_NVP(value) + & BOOST_SERIALIZATION_NVP(precision) + & BOOST_SERIALIZATION_NVP(question); + } + + clog << "Loaded values from XML archive are: " << endl; + clog << " b = " << b << endl; + clog << " c = '" << c << "'" << endl; + clog << " answer = " << answer << endl; + clog << " value = " << value << endl; + clog << " precision = " << precision << endl; + clog << " question = \"" << question << "\"" << endl; + + return; +} + +int main (void) +{ + do_text_in (); + do_xml_in (); + return 0; +} + +// end of tutorial_pba_9.cpp diff --git a/contrib/eos_portable_archive/tutorial/images/boost.png b/contrib/eos_portable_archive/tutorial/images/boost.png new file mode 100644 index 00000000..b4d51fcd Binary files /dev/null and b/contrib/eos_portable_archive/tutorial/images/boost.png differ diff --git a/contrib/eos_portable_archive/tutorial/images/c++-source-code.png b/contrib/eos_portable_archive/tutorial/images/c++-source-code.png new file mode 100644 index 00000000..8328062f Binary files /dev/null and b/contrib/eos_portable_archive/tutorial/images/c++-source-code.png differ diff --git a/contrib/eos_portable_archive/tutorial/scripts/jquery-1.4.min.js b/contrib/eos_portable_archive/tutorial/scripts/jquery-1.4.min.js new file mode 100644 index 00000000..5c70e4c5 --- /dev/null +++ b/contrib/eos_portable_archive/tutorial/scripts/jquery-1.4.min.js @@ -0,0 +1,151 @@ +/*! + * jQuery JavaScript Library v1.4 + * http://jquery.com/ + * + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://docs.jquery.com/License + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2010, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Wed Jan 13 15:23:05 2010 -0500 + */ +(function(A,w){function oa(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(oa,1);return}c.ready()}}function La(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function $(a,b,d,f,e,i){var j=a.length;if(typeof b==="object"){for(var o in b)$(a,o,b[o],f,e,d);return a}if(d!==w){f=!i&&f&&c.isFunction(d);for(o=0;o-1){i=j.data;i.beforeFilter&&i.beforeFilter[a.type]&&!i.beforeFilter[a.type](a)||f.push(j.selector)}else delete t[p]}i=c(a.target).closest(f,a.currentTarget); +n=0;for(l=i.length;n)[^>]*$|^#([\w-]+)$/,Pa=/^.[^:#\[\.,]*$/,Qa=/\S/, +Ra=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Sa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],M,ca=Object.prototype.toString,da=Object.prototype.hasOwnProperty,ea=Array.prototype.push,R=Array.prototype.slice,V=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(typeof a==="string")if((d=Oa.exec(a))&&(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Sa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])]; +c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=ua([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return U.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a)}else return!b||b.jquery?(b||U).find(a):c(b).find(a);else if(c.isFunction(a))return U.ready(a);if(a.selector!==w){this.selector=a.selector; +this.context=a.context}return c.isArray(a)?this.setArray(a):c.makeArray(a,this)},selector:"",jquery:"1.4",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){a=c(a||null);a.prevObject=this;a.context=this.context;if(b==="find")a.selector=this.selector+(this.selector?" ":"")+d;else if(b)a.selector=this.selector+"."+b+"("+d+")";return a},setArray:function(a){this.length= +0;ea.apply(this,a);return this},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject|| +c(null)},push:ea,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,i,j,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
a";var e=d.getElementsByTagName("*"),i=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!i)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length, +htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(i.getAttribute("style")),hrefNormalized:i.getAttribute("href")==="/a",opacity:/^0.55$/.test(i.style.opacity),cssFloat:!!i.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(j){}a.insertBefore(b, +a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function o(){c.support.noCloneEvent=false;d.detachEvent("onclick",o)});d.cloneNode(true).fireEvent("onclick")}c(function(){var o=s.createElement("div");o.style.width=o.style.paddingLeft="1px";s.body.appendChild(o);c.boxModel=c.support.boxModel=o.offsetWidth===2;s.body.removeChild(o).style.display="none"});a=function(o){var p=s.createElement("div");o="on"+o;var n=o in +p;if(!n){p.setAttribute(o,"return;");n=typeof p[o]==="function"}return n};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=i=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var H="jQuery"+K(),Ta=0,ya={},Ua={};c.extend({cache:{},expando:H,noData:{embed:true,object:true,applet:true},data:function(a, +b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?ya:a;var f=a[H],e=c.cache;if(!b&&!f)return null;f||(f=++Ta);if(typeof b==="object"){a[H]=f;e=e[f]=c.extend(true,{},b)}else e=e[f]?e[f]:typeof d==="undefined"?Ua:(e[f]={});if(d!==w){a[H]=f;e[b]=d}return typeof b==="string"?e[b]:e}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?ya:a;var d=a[H],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{try{delete a[H]}catch(i){a.removeAttribute&& +a.removeAttribute(H)}delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,a,b)})},removeData:function(a){return this.each(function(){c.removeData(this, +a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this, +a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var za=/[\n\t]/g,fa=/\s+/,Va=/\r/g,Wa=/href|src|style/,Xa=/(button|input)/i,Ya=/(button|input|object|select|textarea)/i,Za=/^(a|area)$/i,Aa=/radio|checkbox/;c.fn.extend({attr:function(a, +b){return $(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(p){var n=c(this);n.addClass(a.call(this,p,n.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(fa),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var i=b?d:0;for(d=b?d+1:e.length;i=0;else if(c.nodeName(this,"select")){var z=c.makeArray(t);c("option",this).each(function(){this.selected=c.inArray(c(this).val(),z)>=0});if(!z.length)this.selectedIndex= +-1}else this.value=t}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var i=Wa.test(b);if(b in a&&f&&!i){if(e){if(b==="type"&&Xa.test(a.nodeName)&&a.parentNode)throw"type property can't be changed";a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue; +if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:Ya.test(a.nodeName)||Za.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&i?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var $a=function(a){return a.replace(/[^\w\s\.\|`]/g,function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType=== +3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;if(!d.guid)d.guid=c.guid++;if(f!==w){d=c.proxy(d);d.data=f}var e=c.data(a,"events")||c.data(a,"events",{}),i=c.data(a,"handle"),j;if(!i){j=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(j.elem,arguments):w};i=c.data(a,"handle",j)}if(i){i.elem=a;b=b.split(/\s+/);for(var o,p=0;o=b[p++];){var n=o.split(".");o=n.shift();d.type=n.slice(0).sort().join(".");var t=e[o],z=this.special[o]||{};if(!t){t=e[o]={}; +if(!z.setup||z.setup.call(a,f,n,d)===false)if(a.addEventListener)a.addEventListener(o,i,false);else a.attachEvent&&a.attachEvent("on"+o,i)}if(z.add)if((n=z.add.call(a,d,f,n,t))&&c.isFunction(n)){n.guid=n.guid||d.guid;d=n}t[d.guid]=d;this.global[o]=true}a=null}}},global:{},remove:function(a,b,d){if(!(a.nodeType===3||a.nodeType===8)){var f=c.data(a,"events"),e,i,j;if(f){if(b===w||typeof b==="string"&&b.charAt(0)===".")for(i in f)this.remove(a,i+(b||""));else{if(b.type){d=b.handler;b=b.type}b=b.split(/\s+/); +for(var o=0;i=b[o++];){var p=i.split(".");i=p.shift();var n=!p.length,t=c.map(p.slice(0).sort(),$a);t=new RegExp("(^|\\.)"+t.join("\\.(?:.*\\.)?")+"(\\.|$)");var z=this.special[i]||{};if(f[i]){if(d){j=f[i][d.guid];delete f[i][d.guid]}else for(var B in f[i])if(n||t.test(f[i][B].type))delete f[i][B];z.remove&&z.remove.call(a,p,j);for(e in f[i])break;if(!e){if(!z.teardown||z.teardown.call(a,p)===false)if(a.removeEventListener)a.removeEventListener(i,c.data(a,"handle"),false);else a.detachEvent&&a.detachEvent("on"+ +i,c.data(a,"handle"));e=null;delete f[i]}}}}for(e in f)break;if(!e){if(B=c.data(a,"handle"))B.elem=null;c.removeData(a,"events");c.removeData(a,"handle")}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[H]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();this.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType=== +8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;var i=c.data(d,"handle");i&&i.apply(d,b);var j,o;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()])){j=d[e];o=d["on"+e]}}catch(p){}i=c.nodeName(d,"a")&&e==="click";if(!f&&j&&!a.isDefaultPrevented()&&!i){this.triggered=true;try{d[e]()}catch(n){}}else if(o&&d["on"+e].apply(d,b)===false)a.result=false;this.triggered=false;if(!a.isPropagationStopped())(d=d.parentNode||d.ownerDocument)&&c.event.trigger(a,b,d,true)}, +handle:function(a){var b,d;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;d=a.type.split(".");a.type=d.shift();b=!d.length&&!a.exclusive;var f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)");d=(c.data(this,"events")||{})[a.type];for(var e in d){var i=d[e];if(b||f.test(i.type)){a.handler=i;a.data=i.data;i=i.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}return a.result}, +props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(a){if(a[H])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement|| +s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&& +a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a,b){c.extend(a,b||{});a.guid+=b.selector+b.live;c.event.add(this,b.live,qa,b)},remove:function(a){if(a.length){var b=0,d=new RegExp("(^|\\.)"+a[0]+"(\\.|$)");c.each(c.data(this,"events").live||{},function(){d.test(this.type)&&b++});b<1&&c.event.remove(this,a[0],qa)}},special:{}},beforeunload:{setup:function(a, +b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=a;this.type=a.type}else this.type=a;this.timeStamp=K();this[H]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=ba;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped= +ba;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=ba;this.stopPropagation()},isDefaultPrevented:aa,isPropagationStopped:aa,isImmediatePropagationStopped:aa};var Ba=function(a){for(var b=a.relatedTarget;b&&b!==this;)try{b=b.parentNode}catch(d){break}if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}},Ca=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover", +mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ca:Ba,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ca:Ba)}}});if(!c.support.submitBubbles)c.event.special.submit={setup:function(a,b,d){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit."+d.guid,function(f){var e=f.target,i=e.type;if((i==="submit"||i==="image")&&c(e).closest("form").length)return pa("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit."+ +d.guid,function(f){var e=f.target,i=e.type;if((i==="text"||i==="password")&&c(e).closest("form").length&&f.keyCode===13)return pa("submit",this,arguments)})}else return false},remove:function(a,b){c.event.remove(this,"click.specialSubmit"+(b?"."+b.guid:""));c.event.remove(this,"keypress.specialSubmit"+(b?"."+b.guid:""))}};if(!c.support.changeBubbles){var ga=/textarea|input|select/i;function Da(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex> +-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d}function ha(a,b){var d=a.target,f,e;if(!(!ga.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Da(d);if(e!==f){if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",e);if(d.type!=="select"&&(f!=null||e)){a.type="change";return c.event.trigger(a,b,this)}}}}c.event.special.change={filters:{focusout:ha,click:function(a){var b=a.target,d=b.type;if(d=== +"radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return ha.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return ha.call(this,a)},beforeactivate:function(a){a=a.target;a.nodeName.toLowerCase()==="input"&&a.type==="radio"&&c.data(a,"_change_data",Da(a))}},setup:function(a,b,d){for(var f in W)c.event.add(this,f+".specialChange."+d.guid,W[f]);return ga.test(this.nodeName)}, +remove:function(a,b){for(var d in W)c.event.remove(this,d+".specialChange"+(b?"."+b.guid:""),W[d]);return ga.test(this.nodeName)}};var W=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d, +f,e){if(typeof d==="object"){for(var i in d)this[b](i,f,d[i],e);return this}if(c.isFunction(f)){thisObject=e;e=f;f=w}var j=b==="one"?c.proxy(e,function(o){c(this).unbind(o,j);return e.apply(this,arguments)}):e;return d==="unload"&&b!=="one"?this.one(d,f,e,thisObject):this.each(function(){c.event.add(this,d,j,f)})}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&!a.preventDefault){for(var d in a)this.unbind(d,a[d]);return this}return this.each(function(){c.event.remove(this,a,b)})},trigger:function(a, +b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},toggle:function(a){for(var b=arguments,d=1;d0){y=u;break}}u=u[g]}m[r]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, +e=0,i=Object.prototype.toString,j=false,o=true;[0,0].sort(function(){o=false;return 0});var p=function(g,h,k,m){k=k||[];var r=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return k;for(var q=[],v,u,y,S,I=true,N=x(h),J=g;(f.exec(""),v=f.exec(J))!==null;){J=v[3];q.push(v[1]);if(v[2]){S=v[3];break}}if(q.length>1&&t.exec(g))if(q.length===2&&n.relative[q[0]])u=ia(q[0]+q[1],h);else for(u=n.relative[q[0]]?[h]:p(q.shift(),h);q.length;){g=q.shift();if(n.relative[g])g+=q.shift(); +u=ia(g,u)}else{if(!m&&q.length>1&&h.nodeType===9&&!N&&n.match.ID.test(q[0])&&!n.match.ID.test(q[q.length-1])){v=p.find(q.shift(),h,N);h=v.expr?p.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:q.pop(),set:B(m)}:p.find(q.pop(),q.length===1&&(q[0]==="~"||q[0]==="+")&&h.parentNode?h.parentNode:h,N);u=v.expr?p.filter(v.expr,v.set):v.set;if(q.length>0)y=B(u);else I=false;for(;q.length;){var E=q.pop();v=E;if(n.relative[E])v=q.pop();else E="";if(v==null)v=h;n.relative[E](y,v,N)}}else y=[]}y||(y=u);if(!y)throw"Syntax error, unrecognized expression: "+ +(E||g);if(i.call(y)==="[object Array]")if(I)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&F(h,y[g])))k.push(u[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&k.push(u[g]);else k.push.apply(k,y);else B(y,k);if(S){p(S,r,k,m);p.uniqueSort(k)}return k};p.uniqueSort=function(g){if(D){j=o;g.sort(D);if(j)for(var h=1;h":function(g,h){var k=typeof h==="string";if(k&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,r=g.length;m=0))k||m.push(v);else if(k)h[q]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, +CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,k,m,r,q){h=g[1].replace(/\\/g,"");if(!q&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,k,m,r){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=p(g[3],null,null,h);else{g=p.filter(g[3],h,k,true^r);k||m.push.apply(m, +g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,k){return!!p(k[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, +text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, +setFilters:{first:function(g,h){return h===0},last:function(g,h,k,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,k){return hk[3]-0},nth:function(g,h,k){return k[3]-0===h},eq:function(g,h,k){return k[3]-0===h}},filter:{PSEUDO:function(g,h,k,m){var r=h[1],q=n.filters[r];if(q)return q(g,k,h,m);else if(r==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(r==="not"){h= +h[3];k=0;for(m=h.length;k=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var k=h[1];g=n.attrHandle[k]?n.attrHandle[k](g):g[k]!=null?g[k]:g.getAttribute(k);k=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== +"="?k===h:m==="*="?k.indexOf(h)>=0:m==="~="?(" "+k+" ").indexOf(h)>=0:!h?k&&g!==false:m==="!="?k!==h:m==="^="?k.indexOf(h)===0:m==="$="?k.substr(k.length-h.length)===h:m==="|="?k===h||k.substr(0,h.length+1)===h+"-":false},POS:function(g,h,k,m){var r=n.setFilters[h[2]];if(r)return r(g,k,h,m)}}},t=n.match.POS;for(var z in n.match){n.match[z]=new RegExp(n.match[z].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[z]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[z].source.replace(/\\(\d+)/g,function(g, +h){return"\\"+(h-0+1)}))}var B=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){B=function(g,h){h=h||[];if(i.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var k=0,m=g.length;k";var k=s.documentElement;k.insertBefore(g,k.firstChild);if(s.getElementById(h)){n.find.ID=function(m,r,q){if(typeof r.getElementById!=="undefined"&&!q)return(r=r.getElementById(m[1]))?r.id===m[1]||typeof r.getAttributeNode!=="undefined"&& +r.getAttributeNode("id").nodeValue===m[1]?[r]:w:[]};n.filter.ID=function(m,r){var q=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&q&&q.nodeValue===r}}k.removeChild(g);k=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,k){k=k.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;k[m];m++)k[m].nodeType===1&&h.push(k[m]);k=h}return k};g.innerHTML=""; +if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=p,h=s.createElement("div");h.innerHTML="

";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){p=function(m,r,q,v){r=r||s;if(!v&&r.nodeType===9&&!x(r))try{return B(r.querySelectorAll(m),q)}catch(u){}return g(m,r,q,v)};for(var k in g)p[k]=g[k];h=null}}(); +(function(){var g=s.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,k,m){if(typeof k.getElementsByClassName!=="undefined"&&!m)return k.getElementsByClassName(h[1])};g=null}}})();var F=s.compareDocumentPosition?function(g,h){return g.compareDocumentPosition(h)&16}:function(g, +h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ia=function(g,h){var k=[],m="",r;for(h=h.nodeType?[h]:h;r=n.match.PSEUDO.exec(g);){m+=r[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;r=0;for(var q=h.length;r=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var i=d;i0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,i= +{},j;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:j,elem:f});delete i[j]}}f=f.parentNode}}return d}var p=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,t){for(;t&&t.ownerDocument&&t!==b;){if(p?p.index(t)>-1:c(t).is(a))return t;t=t.parentNode}return null})},index:function(a){if(!a||typeof a=== +"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(sa(a[0])||sa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", +d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? +a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);ab.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||cb.test(f))&&bb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||!c(a).is(d));){a.nodeType=== +1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ga=/ jQuery\d+="(?:\d+|null)"/g,Y=/^\s+/,db=/(<([\w:]+)[^>]*?)\/>/g,eb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,Ha=/<([\w:]+)/,fb=/"},G={option:[1,""], +legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};G.optgroup=G.option;G.tbody=G.tfoot=G.colgroup=G.caption=G.thead;G.th=G.td;if(!c.support.htmlSerialize)G._default=[1,"div
","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=c(this); +return d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.getText(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, +wrapInner:function(a){return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&& +this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this.nextSibling)});else if(arguments.length){var a=this.pushStack(this, +"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ga,"").replace(Y,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ta(this,b);ta(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType=== +1?this[0].innerHTML.replace(Ga,""):null;else if(typeof a==="string"&&!/ + + + + + + + + + + + + + + +
+

+ Boost

+
+

Boost/Serialization ‐ Portable Binary Archives (PBA)

+

Tutorial

+

NOTE: Naming differs from the source code! This tutorial reflects our hope to get + the eos portable archives an official part of the boost serialization library. + Work is in progress :-) +

+
+ + +
+
+
Quick start
+ +
+ +
Format +
+ +
Examples
+ +
+
+ +

+

+
+ +

Quick start

+ +Are you impatient to enjoy the Boost Portable Binary Archives (PBA) ? +If so, this section is for you. + +

How to store some simple data in a portable binary output archive

+ +

+The tutorial_pba_0.cpp sample +program uses a boost::archive::portable_binary_oarchive object +attached to a standard output file stream to store a couple of +variables of primitive types (bool, +char, integer +numbers, floating numbers) and even a std::string. +

+ +
+ The tutorial_pba_0.cpp source code DownloadShow/hide +
+/** tutorial_pba_0.cpp
+ *
+ * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
+ *
+ * Use, modification and distribution is subject to the Boost Software
+ * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+ * http://www.boost.org/LICENSE_1_0.txt)
+ *
+ */
+
+/**
+ * The intent of this program is to serve as a tutorial for
+ * users of the portable binary archive in the framework of 
+ * the Boost/Serialization library. 
+ *
+ * This quick start example shows how to store some variables
+ * of basic types (bool, integer, floating point numbers, STL string) 
+ * using the portable binary archive format associated to a 
+ * standard output file stream.
+ *
+ */
+
+#include <string>
+#include <fstream>
+
+#include <boost/cstdint.hpp>
+#include <boost/archive/portable_binary_oarchive.hpp>
+
+int main (void)
+{
+  // The name for the example data file :  
+  std::string filename = "pba_0.data"; 
+
+  // Some variables of various primitive types :
+  bool        b              = true;
+  char        c              = 'B';
+  uint32_t    answer         = 42;
+  float       computing_time = 7.5e6;
+  double      e              = 2.71828182845905;
+  std::string slogan         = "DON'T PANIC";
+  
+  // Open an output file stream in binary mode :
+  std::ofstream fout (filename.c_str (), std::ios_base::binary);
+  
+  {
+    // Create an output portable binary archive attached to the output file :
+    boost::archive::portable_binary_oarchive opba (fout);
+    
+    // Store (serializing) variables :
+    opba & b & c & answer & computing_time & e & slogan;
+  }
+
+  return 0;   
+}
+
+// end of tutorial_pba_0.cpp
+
+
+

+ + +

+The compiled executable creates the pba_0.data file which +contains the following bytes: +

127   1   9   1  84   1  66   1  42   4 192 225 228  74   8 116
+ 87  20 139  10 191   5  64   1  11  68  79  78  39  84  32  80
+ 65  78  73  67
+
+This format is explained in details below. + + +

Note: +

    +
  • the output of the byte content in the pba_0.data file +can be obtained invoking some command like +  od -t u1 pba_0.data  +on a GNU/Linux system.
    +
  • one should notice that this program makes use of +the typedef-ed integer types from +the boost/cstdint.hpp header (uint32_t...). It is a +strong recommendation to ensure cross-environment portability while +(de)serializing integer numbers (see also +the Examples section). +
+

+ + + +
+To top +
+
+ + +

How to load some simple data from a portable binary input archive

+ +

+The tutorial_pba_1.cpp sample program uses +a boost::archive::portable_binary_iarchive object +attached to a standard input file stream in order to load the +data previously stored by +the tutorial_pba_0.cpp program in +the pba_0.data file. +

+ + +
+ The tutorial_pba_1.cpp source code DownloadShow/hide +
+/** tutorial_pba_1.cpp
+ *
+ * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
+ *
+ * Use, modification and distribution is subject to the Boost Software
+ * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+ * http://www.boost.org/LICENSE_1_0.txt)
+ *
+ */
+
+/**
+ * The intent of this program is to serve as a tutorial for
+ * users of the portable binary archive in the framework of 
+ * the Boost/Serialization package. 
+ *
+ * This quick start example shows how to load some variables
+ * of basic types (bool, integer, floating point numbers, STL string) 
+ * using the portable binary archive format associated to a 
+ * standard input file stream. 
+ *
+ */
+
+#include <iostream>
+#include <string>
+#include <fstream>
+
+#include <boost/cstdint.hpp>
+#include <boost/archive/portable_binary_iarchive.hpp>
+
+int main (void)
+{
+  using namespace std;
+
+  // The name for the example data file :  
+  string filename = "pba_0.data"; 
+
+  // Some variables of various types :
+  bool     b;
+  char     c;
+  uint32_t answer;
+  float    computing_time;
+  double   e;
+  string   slogan;
+   
+  // Open an input file stream in binary mode :
+  ifstream fin (filename.c_str (), ios_base::binary);
+  
+  {
+    // Create an input portable binary archive attached to the input file :
+    boost::archive::portable_binary_iarchive ipba (fin);
+    
+    // Loading (de-serializing) variables using the same 
+    // order than for serialization (see tutorial_pba_0.cpp) :
+    ipba & b & c & answer & computing_time & e & slogan;
+  }
+
+  cout.precision (15);
+  cout << "Variable 'b' is              : " << b << " " << "(bool)" << endl;
+  cout << "Variable 'c' is              : '" << c << "' " << " " << "(char)" << endl;
+  cout << "Variable 'answer' is         : " << answer  << " " << "(unsigned 32-bit integer)" << endl;
+  cout << "Variable 'computing_time' is : " << computing_time  << " " << "(single precision 32-bit float)" << endl;
+  cout << "Variable 'e' is              : " << e  << " " << "(double precision 64-bit float)" << endl;
+  cout << "Variable 'slogan' is         : \"" << slogan  << "\" " << "(std::string)" << endl;
+
+  return 0;   
+}
+
+// end of tutorial_pba_1.cpp
+
+
+

+ + +

+The executable reads the pba_0.data file and deserializes its +contents in the same order it has been stored. It then prints the +restored values of the variables: +

Variable 'b' is              : 1 (bool)
+Variable 'c' is              : 'B'  (char)
+Variable 'answer' is         : 42 (unsigned 32-bit integer)
+Variable 'computing_time' is : 7500000 (single precision 32-bit float)
+Variable 'e' is              : 2.71828182845905 (double precision 64-bit float)
+Variable 'slogan' is         : "DON'T PANIC" (std::string)
+
+

+ + + +
+To top +
+
+ + + +
+

Format

+ +

+This section aims to give some details about the binary format of +portable binary archives (PBA). We will analyse the byte contents of +the sample binary archive pba_0.data file +created by the tutorial_pba_0.cpp +program (see the previous section). +

+ +

+Like any other archive format within Boost/Serialization, a PBA starts +with a header (this is the default behaviour but it is possible to +deactivate the use of this header using a special flag at +construction, see this example). This +header is made of two informations : +

    +
  • + a magic byte with the conventionnal decimal value : +
    127
    +
  • + the Boost library version number which is encoded as an integer + number. +

    The PBA encoding of integer numbers uses the following + scheme: + <size> <content>, + where first the size stores the minimal + number of non zero bytes needed to store the binary + representation of the integer value; then the bytes corresponding to the content are stored + starting from the less significant ones (see + also this example). For the library + version number we have here: +

    1 9
    + where 1 is the number of byte needed to store the + value 9 which comes with the Serialization library for + Boost version 1.47.0. Here, the 9 value being less than 256, + one unique byte is enough to store this number. +
+

+

+ +

+Now we are done with the header, let's have a look on the serialized data ! +

+ +
    +
  • +The first variable is of boolean type with value true. Here +the PBA conventionnaly encodes the true value with the +character 'T' which is stored using the corresponding ASCII +integer value (84). As 84 is less +than 256, this uses only 1 byte: +
    1  84
    +

    + +
  • The next variable uses 1 byte to store a 8-bit +character (char) taking value 'B'. Again the PBA +scheme encodes it using its ASCII integer value +(66). This gives: +
    1  66
    +

    + +
  • Then we have an unsigned 32-bit integer with +value 42 (a fondamental constant from +the H2G2). As the natural binary 32-bit encoding of this value +(<256) only needs +1 non-zero byte, the PBA stores : +
    1  42
    +This scheme results in saving 2 bytes compared to the size of the transient value. +

    + +
  • The next variable is a single precision number with +value 7.5×106. Following the IEEE 754 standard one thus uses +32 bits to encode the sign bit, +the 8-bit exponent and +the 23-bit significant (mantissa). +As 7.5×106 can be rewritten +in +1.78813934×222, we have the +following bits contents:
    +
    +010010101111001001110000111000000

    +where the phantom bit (not stored) is conventionaly set +at 1 and the exponent is stored after +being shifted conventionaly by 27-1=127, thus +(10010101)2=(149)10 +(subscripts indicate the number base) and 149-127=22.
    + +
    +Packing these bits using 4 +bytes, we get:

    + + + + + + + + + + + + + +
    01001010111001001110000111000000
    74228225192
    +
    + +Thus the PBA streams the following 5 bytes (first the size then the content +from the least significant byte to the most significant byte), giving : +
    4 192 225 228 74
    + +
  • The next floating number 2.71828182845905 = ++1.35914091422952×2(1024-1023), +is stored using the double precision IEEE 754 64-bit pattern (using the conventionnal exponent shift 210-1=1023): +

    + + + + + + + + + + + + + + + + + + + + + +
    0100000000000101110111110000101010001011000101000101011101110100
    645191101392087116
    +
    + +Thus the PBA uses the following 9 bytes, the first one for the size (8) and the other ones +for the content (starting with the LSB): +
    8 116 87 20 139 10 191 5 64
    + +
  • Finally the string "DON'T PANIC" is stored: +
      +
    • + first is given the number of characters using the PBA + integer encoding scheme; here + 1 byte is enough to store the + value 11:
      +
      1  11
      +
    • then the array of 11 characters is given using the + corresponding ASCII codes: +

      + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      DON'T PANIC
      6879783984328065787367
      +
      +
      68  79  78  39  84  32  80 65  78  73  67 
      +
    + +
+ +

+ +

+Now the contents of the pba_0.data file can be fully +understood : +

127   1   9   1  84   1  66   1  42   4 192 225 228  74   8 116
+ 87  20 139  10 191   5  64   1  11  68  79  78  39  84  32  80
+ 65  78  73  67
+
+ +More details about the format (non finite floating point values, +negative integer numbers) will be given in +the sample codes below. +

+ + + +
+To top +
+
+ + + +
+

Examples

+ + + +

Handling special floating point values

+ +

+The PBA has been designed in the aims to handle single and double +precision floating point numbers, including non-finite and special values: +

    +
  • ±infinity +
  • NaN (not a number) +
  • denormalized numbers (i.e. floating point numbers with non-guaranteed roundoff precision) +
+

+ +

+The tutorial_pba_2.cpp sample program +illustrates the use of such special cases while serializing single precision +floating point numbers: +

+ +
+ The tutorial_pba_2.cpp source code DownloadShow/hide +
+/** tutorial_pba_2.cpp
+ *
+ * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
+ *
+ * Use, modification and distribution is subject to the Boost Software
+ * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+ * http://www.boost.org/LICENSE_1_0.txt)
+ *
+ */
+
+/**
+ * The intent of this program is to serve as a tutorial for
+ * users of the portable binary archive in the framework of 
+ * the Boost/Serialization library. 
+ *
+ * This sample program shows how to use a portable binary archive 
+ * to store/load floating point numbers including non-finite and 
+ * special (denormalized) values.
+ *
+ */
+
+#include <string>
+#include <fstream>
+#include <limits>
+
+#include <boost/archive/portable_binary_oarchive.hpp>
+#include <boost/archive/portable_binary_iarchive.hpp>
+
+int main (void)
+{
+  using namespace std;
+
+  // The name for the example data file :  
+  string filename = "pba_2.data"; 
+
+  {
+    // A normal single precision floating point number :
+    float pi = 3.14159265; 
+
+    // Single precision zeroed floating point number :
+    float zero = 0.0;
+
+    // A denormalized single precision floating point number :
+    float tiny = 1.e-40;
+    
+    // A single precision floating point number with `+Infinity' value :
+    float plus_infinity = numeric_limits<float>::infinity ();
+    
+    // A single precision floating point number with `-Infinity' value :
+    float minus_infinity = -numeric_limits<float>::infinity ();
+    
+    // A single precision `Not-a-Number' (NaN):
+    float nan = numeric_limits<float>::quiet_NaN ();
+    
+    // Open an output file stream in binary mode :
+    ofstream fout (filename.c_str (), ios_base::binary);
+    
+    {
+      // Create an output portable binary archive attached to the output file :
+      boost::archive::portable_binary_oarchive opba (fout);
+      
+      // Store (serialize) variables :
+      opba & pi & zero & tiny & plus_infinity & minus_infinity & nan;
+    }
+  }
+
+  { 
+    // Single precision floating point numbers to be loaded :
+    float x[6];
+
+    // Open an input file stream in binary mode :
+    ifstream fin (filename.c_str (), ios_base::binary);
+  
+    {
+      // Create an input portable binary archive attached to the input file :
+      boost::archive::portable_binary_iarchive ipba (fin);
+      
+      // Load (de-serialize) variables using the same 
+      // order than for serialization :
+      for (int i = 0; i < 6; ++i)
+	{
+	  ipba & x[i];
+	}
+    }
+
+    // Print :
+    for (int i = 0; i < 6; ++i)
+      {
+	cout.precision (8);
+	cout << "Loaded x[" << i << "] = " << x[i];
+	switch (fp::fpclassify(x[i]))
+	  {
+	  case FP_NAN: cout << " (NaN)"; break;
+	  case FP_INFINITE: cout << " (infinite)"; break;
+	  case FP_SUBNORMAL: cout << " (denormalized)"; break;
+	  case FP_NORMAL:  cout << " (normalized)"; break;
+	  }
+	cout << endl;
+      }
+  }
+
+  return 0;   
+}
+
+// end of tutorial_pba_2.cpp
+
+
+

+ + +

+The pba_2.data output data file thus contains the following bytes: +

127   1   9   4 219  15  73  64   0   3 194  22   1   4   0   0
+128 127   4   0   0 128 255   4 255 255 255 127
+
+where: +
    + +
  • 127 1 9 is the standard archive header + +
  • 5 bytes are used to encode the value of π : one byte for the size=4 and 4 bytes for the content + (reversed order): +

    + + + + + + + + + + + + + +
    647315219
    01000000010010010000111111011011
    +
    + and π = +1.5707963×2(128-127) = 3.14159265. + +
  • the value zero is stored using only + one 0 byte (this is called zero optimization and this save bytes for storage). + +
  • a denormalized value then comes with only 3 bytes (note that the MSB byte is zero so it is omitted) +

    + + + + + + + + + + + + + +
    122194
    00000000000000010001011011000010
    +
    + Here the value + is +0.017014027×2(0-127) + = 0.9999946×10-40 which, as expected for + denormalized numbers, misses the requested + value 10-40 by the relative error of + magnitude 5.4×10-6, which is larger than the machine + roundoff precision (~10-7 for the single precision scheme). + +
  • the +∞ value is stored using one byte for the size + plus 4 content bytes, fulfilling the IEEE 754 standard, + i.e. maximal exponent and zero mantissa : +

    + + + + + + + + + + + + + +
    12712800
    01111111100000000000000000000000
    +
    + +
  • the -∞ value is stored using the same scheme as above, but the sign bit : +

    + + + + + + + + + + + + + +
    25512800
    11111111100000000000000000000000
    +
    + +
  • the final NaN value is stored also using one size byte plus 4 content bytes with maximal exponent and non-zero mantissa : +

    + + + + + + + + + + + + + +
    127255255255
    01111111111111111111111111111111
    +
    + See this link for an explanation of the IEEE 754 standard. + +
+

+ + + +
+To top +
+
+ + + +

Forbidding the serialization of non finite float values

+ +

+One can ask a PBA to reject non-finite values. This is done by +passing the boost::archive::no_infnan flag to the constructor +of the output archive. Note that in this case, denormalized values are +still accepted, but infinite and NaNs aren't. +

+ +

+The tutorial_pba_3.cpp sample +program that illustrates this special case: +

+ +
+ The tutorial_pba_3.cpp source code DownloadShow/hide +
+/** tutorial_pba_3.cpp
+ *
+ * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
+ *
+ * Use, modification and distribution is subject to the Boost Software
+ * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+ * http://www.boost.org/LICENSE_1_0.txt)
+ *
+ */
+
+/**
+ * The intent of this program is to serve as a tutorial for
+ * users of the portable binary archive in the framework of 
+ * the Boost/Serialization library. 
+ *
+ * This sample program shows how to use a portable binary archive 
+ * and prevent the serialization of non-finite floating numbers.
+ *
+ */
+
+#include <string>
+#include <fstream>
+#include <limits>
+
+#include <boost/archive/portable_binary_oarchive.hpp>
+
+int main (void)
+{
+  using namespace std;
+
+  // The name for the example data file :  
+  string filename = "pba_3.data"; 
+
+  try 
+    {
+      // An array of single precision floating numbers:
+      float x[5]; 
+      x[0] = 3.14159;  // Pi
+      x[1] = 6.022e22; // Avogadro constant
+      x[2] = 1.6e-19;  // Electron charge magnitude
+      x[3] = 1.e-40;   // A tiny (denormalized) value
+      x[4] = numeric_limits<float>::infinity (); // This will fail while serializing...
+
+      // Open an output file stream in binary mode :
+      ofstream fout (filename.c_str (), ios_base::binary);
+    
+      {
+	// Create an output portable binary archive attached to the output file,
+	// using the special 'boost::archive::no_infnan' flag :
+	boost::archive::portable_binary_oarchive opba (fout, boost::archive::no_infnan);
+	
+	// Store (serialize) variables :
+	for (int i = 0; i < 5; ++i)
+	  {
+	    clog << "Serializing value : " << x[i] << " ... ";
+	    opba & x[i];
+	    clog << "Ok !" << endl;
+	  }
+      }
+    }
+  catch (exception & x)
+    {
+      cerr << "ERROR: " << x.what () << endl;
+      return 1;
+    }
+
+  return 0;   
+}
+
+// end of tutorial_pba_3.cpp
+
+
+

+ + +

+We can check that the PBA now throws an exception as soon as it +encounters a non finite floating point value during the serialization +process: +

+Serializing value : 3.14159 ... Ok !
+Serializing value : 6.022e+22 ... Ok !
+Serializing value : 1.6e-19 ... Ok !
+Serializing value : 9.99995e-41 ... Ok !
+Serializing value : inf ... ERROR: serialization of illegal floating point value: inf
+
+
+

+ + + +
+To top +
+
+ + + +

Serializing integer numbers

+ +

+The PBA obviously handles integer numbers. Unfortunately, C/C++ does +not garantee the portable size of its primitive integer types (short, +int, long... and their unsigned versions). It depends on the +architecture (32-bit/64-bit) and the compiler. +

+

The Boost library +addresses this issue through a collection of typedefs for +integer types of common sizes. This technique is supposed to allow +the manipulation of integer variables in a portable way, typically with +text or XML archives. So, we are generally + encouraged to use the boost/cstdint.hpp header file and +the typedefs defined therein. +

+

Due to its encoding scheme +of integer numbers, the PBA does not strictly need such technique to ensure +a correct behaviour while (de)serializing integer numbers. +This is because the little endian encoding approach allows to only store the non-zero bytes. +It is thus possible to serialize a value using one integer type (short int) and then +deserialize it using another integer type (long long). +

+

+However, for a strict and safe portable behaviour +of PBA, we recommend that, in most cases, the user should systematically use such typedefs for all +serializable integer values. This applies particularly for member attributes +in structs and classes and should allows the transparent switching +to another kind of archive (text, XML) thanks to the serialize template method. +

+ +

+The tutorial_pba_4.cpp sample +program illustrates the serialization/deserialization of 8-bit, +16-bit, 32-bit and 64-bit integer numbers: +

+ +
+ The tutorial_pba_4.cpp source code DownloadShow/hide +
+/** tutorial_pba_4.cpp
+ *
+ * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
+ *
+ * Use, modification and distribution is subject to the Boost Software
+ * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+ * http://www.boost.org/LICENSE_1_0.txt)
+ *
+ */
+
+/**
+ * The intent of this program is to serve as a tutorial for
+ * users of the portable binary archive in the framework of 
+ * the Boost/Serialization library. 
+ *
+ * This sample program shows how to use a portable binary archive 
+ * to store/load integer numbers of various sizes using the Boost 
+ * portable integer typedefs.
+ *
+ */
+
+#include <string>
+#include <fstream>
+
+#include <boost/cstdint.hpp>
+#include <boost/archive/portable_binary_oarchive.hpp>
+#include <boost/archive/portable_binary_iarchive.hpp>
+
+int main (void)
+{
+  using namespace std;
+
+  // The name for the example data file :  
+  string filename = "pba_4.data"; 
+
+  {
+    // Some integer numbers :
+    bool t = true;
+    char c = 'c';
+    unsigned char u = 'u';
+    int8_t   b = -3; // char
+    uint8_t  B = +6; // unsigned char 
+    int16_t  s = -16;
+    uint16_t S = +32;
+    int32_t  l = -128;
+    uint32_t L = +127;
+    int64_t  ll = -1024;
+    uint64_t LL = +2048;
+
+    // Open an output file stream in binary mode :
+    ofstream fout (filename.c_str (), ios_base::binary);
+    
+    {
+      // Create an output portable binary archive attached to the output file :
+      boost::archive::portable_binary_oarchive opba (fout);
+      
+      // Store (serialize) variables :
+      opba & t & c & u & b & B & s & S & l & L & ll & LL;
+    }
+  }
+
+  { 
+    // Single precision floating numbers to be loaded :
+    // Some integer numbers :
+    bool t;
+    char c;
+    unsigned char u;
+    int8_t   b;
+    uint8_t  B;
+    int16_t  s;
+    uint16_t S;
+    int32_t  l;
+    uint32_t L;
+    int64_t  ll;
+    uint64_t LL;
+
+    // Open an input file stream in binary mode :
+    ifstream fin (filename.c_str (), ios_base::binary);
+  
+    {
+      // Create an input portable binary archive attached to the input file :
+      boost::archive::portable_binary_iarchive ipba (fin);
+      
+      // Load (de-serialize) variables using the same 
+      // order than for serialization :
+      ipba & t & c & u & b & B & s & S & l & L & ll & LL;
+    }
+
+    clog << "t  = " << t << " (bool)" << endl;
+    clog << "c  = '" << c << "' (char)" << endl;
+    clog << "u  = '" << u << "' (unsigned char)" << endl;
+    clog << "b  = " << (int) b << " (int8_t)" << endl;
+    clog << "B  = " << (int) B << " (uint8_t)" << endl;
+    clog << "s  = " << s << " (int16_t)" << endl;
+    clog << "S  = " << S << " (uint16_t)" << endl;
+    clog << "l  = " << l << " (int32_t)" << endl;
+    clog << "L  = " << L << " (uint32_t)" << endl;
+    clog << "ll = " << ll << " (int64_t)" << endl;
+    clog << "LL = " << LL << " (uint64_t)" << endl;
+  }
+
+  return 0;   
+}
+
+// end of tutorial_pba_4.cpp
+
+
+

+ + +

+The resulting PBA file is: +

127   1   9   1  84   1  99   1 117 255 253   1   6 255 240   1
+ 32 255 128   1 127 254   0 252   2   0   8
+
+ +where: +
    + +
  • 127 1 9 is the archive header. + +
  • 1 84 indicates 1 byte to +store the true boolean value (ASCII code +is 84). + +
  • 1 99 indicates 1 byte to +store the ASCII code of character 'c' (99). + +
  • 1 117 indicates 1 byte to +store the ASCII code of character 'u' +(117). + +
  • 255 253 corresponds to the special case for a +negative integer: + 255 is the binary coding for value -1 +which means that the integer is negative and needs 1 byte to be +stored, 253, i.e. the 8-bit encoding of the signed +decimal value -3. + +
  • 1 6 indicates 1 byte to store +value 6. + +
  • 255 240 corresponds again to a negative +integer: + 255 is the byte coding for value -1 +(negative integer encoded using 1 single byte) +and 240 is the 8-bit encoding of decimal +value -16. + +
  • the same scheme is used for all remaining values in the archive : + the verification is let as an exercise. + +
+ +

+ +

Note that this coding scheme optimizes the number of streamed +bytes. Particularly, it discards the leading zero-ed bytes +(MSB) of the binary encoding of any integer value in order to save +storage. Also we recall that the exact 0 value (zero +or false for a boolean data) is always encoded using a +unique 0 byte (zero optimization). Note this approach is also +used for floating point numbers. +

+ + + +
+To top +
+
+ + + +

Using PBA serialization with a memory buffer

+ +

+In some case, we don't want to serialize some data in a file +(std::ofstream), but we simply plan to stream it in a memory buffer. +

+ +

+The tutorial_pba_5.cpp sample +program makes use of a memory buffer implemented with a STL vector of +characters. The PBA is associated to this buffer thanks to a special +streaming interface mechanism provided by the Boost/Iostreams +library. With such technique one can stream serializable data in +some memory buffer in place of a file : +

+ +
+ The tutorial_pba_5.cpp source code DownloadShow/hide +
+/** tutorial_pba_5.cpp
+ *
+ * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
+ *
+ * Use, modification and distribution is subject to the Boost Software
+ * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+ * http://www.boost.org/LICENSE_1_0.txt)
+ *
+ */
+
+/**
+ * The intent of this program is to serve as a tutorial for
+ * users of the portable binary archive in the framework of 
+ * the Boost/Serialization library. 
+ *
+ * This sample program shows how to use a portable binary archive 
+ * to store/load data in a memory buffer.
+ *
+ */
+
+#include <string>
+#include <vector>
+
+#include <boost/iostreams/stream.hpp>
+#include <boost/iostreams/device/back_inserter.hpp>
+#include <boost/iostreams/device/array.hpp>
+
+#include <boost/cstdint.hpp>
+#include <boost/archive/portable_binary_oarchive.hpp>
+#include <boost/archive/portable_binary_iarchive.hpp>
+
+int main (void)
+{
+  using namespace std;
+
+  // The memory buffer is implemented using a STL vector :
+  typedef std::vector<char> buffer_type;
+  buffer_type buffer; 
+
+  {
+    // Some data to be stored :
+    bool    t = true;
+    char    c = 'c';
+    int16_t s = +16;
+    int32_t l = -128;
+    int64_t ll = +10000000000;
+    float   pi = 3.14159;
+    double  nan = numeric_limits<double>::quiet_NaN ();
+    string  hello = "World !";
+
+    buffer.reserve (1024); // pre-allocate some memory
+
+    // The output stream interface to the buffer :
+    boost::iostreams::stream<boost::iostreams::back_insert_device<buffer_type> > output_stream (buffer);
+
+    {    
+      // Create an output portable binary archive attached to the output file :
+      boost::archive::portable_binary_oarchive opba (output_stream);
+      
+      // Store (serialize) variables :
+      opba & t & c & s & l & ll & pi & nan & hello;
+    }
+
+  }
+
+  clog << "Buffer content is " << buffer.size () << " bytes : " << endl << "  ";
+  for (int i = 0; i < buffer.size (); ++i)
+    {
+      clog << (int) ((unsigned char) buffer[i]) << ' '; 
+      if ((i + 1) % 20 == 0) clog << endl << "  ";
+    }
+  clog << endl;
+
+  { 
+    // Some data to be loaded :
+    bool    t;
+    char    c;
+    int16_t s;
+    int32_t l;
+    int64_t ll;
+    float   pi;
+    double  nan;
+    string  hello;
+
+    // The input stream interface to the buffer :
+    boost::iostreams::stream<boost::iostreams::array_source> input_stream (&buffer[0], 
+									   buffer.size ());
+
+    {
+      // Create an input portable binary archive attached to the input file :
+      boost::archive::portable_binary_iarchive ipba (input_stream);
+      
+      // Load (de-serialize) variables :
+      ipba & t & c & s & l & ll & pi & nan & hello;
+    }
+
+    clog << "Loaded values from the buffer are: " << endl;
+    clog << "  t  = " << t << " (bool)" << endl;
+    clog << "  c  = '" << c << "' (char)" << endl;
+    clog << "  s  = " << s << " (int16_t)" << endl;
+    clog << "  l  = " << l << " (int32_t)" << endl;
+    clog << "  ll = " << ll << " (int64_t)" << endl;
+    clog << "  pi = " << pi << " (float)" << endl;
+    clog << "  nan = " << nan << " (double)" << endl;
+    clog << "  hello = \"" << hello << "\" (std::string)" << endl;
+  }
+
+  return 0;   
+}
+
+// end of tutorial_pba_5.cpp
+
+
+

+ + +

+After the storing of data in the archive, the content of the buffer of +characters is printed: +

+Buffer content is 40 bytes : 
+  127 1 9 1 84 1 99 1 16 255 128 5 0 228 11 84 2 4 208 15 
+  73 64 8 255 255 255 255 255 255 255 127 1 7 87 111 114 108 100 32 33 
+  
+Loaded values from the buffer are: 
+  t  = 1 (bool)
+  c  = 'c' (char)
+  s  = 16 (int16_t)
+  l  = -128 (int32_t)
+  ll = 10000000000 (int64_t)
+  pi = 3.14159 (float)
+  nan = nan (double)
+  hello = "World !" (std::string)
+
+
+Again the PBA encoding scheme can be easily interpreted. This is let +as an exercise. +

+ +

Extra:

+

+You may have a look on the tutorial_pba_6.cpp program that shows a possible — and +provocative — combined usage of the Boost/Serialization concepts, the +Boost/Iostreams facilities and the PBA; it enables the copy of an object +of a non-copyable class. +

+ +
+ The tutorial_pba_6.cpp source code DownloadShow/hide +
+/** tutorial_pba_6.cpp
+ *
+ * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
+ *
+ * Use, modification and distribution is subject to the Boost Software
+ * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+ * http://www.boost.org/LICENSE_1_0.txt)
+ *
+ */
+
+/**
+ * The intent of this program is to serve as a tutorial for
+ * users of the portable binary archive in the framework of
+ * the Boost/Serialization library.
+ *
+ * This sample program shows how to use a portable binary archive
+ * associated to a memory buffer to copy a non-copyable object.
+ *
+ */
+
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <vector>
+
+#include <boost/utility.hpp>
+#include <boost/iostreams/stream.hpp>
+#include <boost/iostreams/device/back_inserter.hpp>
+#include <boost/iostreams/device/array.hpp>
+
+#include <boost/cstdint.hpp>
+#include <boost/archive/portable_binary_oarchive.hpp>
+#include <boost/archive/portable_binary_iarchive.hpp>
+
+using namespace std;
+
+/* A foo noncopyable class */
+struct foo : boost::noncopyable
+{
+  uint32_t status;
+  double   value;
+  double   special;
+
+  string to_string () const
+  {
+    ostringstream sout;
+    sout << "foo={status=" << status << "; value=" << value  << "; special=" << special<< "}";
+    return sout.str();
+  }
+
+  template<class Archive>
+  void serialize (Archive & ar, const unsigned int version)
+  {
+    ar & status;
+    ar & value;
+    ar & special;
+    return;
+  }
+
+};
+
+// A templatized copy function for Boost/Serialization equipped classes.
+// Here we use PBAs associated to a memory buffer :
+template <class Serializable>
+void copy (const Serializable & source, Serializable & target)
+{
+  namespace io = boost::iostreams;
+  namespace ba = boost::archive;
+  if (&source == &target) return; // self-copy guard
+  typedef std::vector<char> buffer_type;
+  buffer_type buffer;
+  buffer.reserve (1024);
+  {
+    io::stream<io::back_insert_device<buffer_type> > output_stream (buffer);
+    ba::portable_binary_oarchive opba (output_stream);
+    opba & source;
+  }
+  {
+    io::stream<io::array_source> input_stream (&buffer[0], buffer.size ());
+    ba::portable_binary_iarchive ipba (input_stream);
+    ipba & target;
+  }
+  return;
+}
+
+int main (void)
+{
+  // Some instance of the 'foo' class :
+  foo dummy;
+  dummy.status = 1;
+  dummy.value = 3.14159;
+  dummy.special = numeric_limits<double>::quiet_NaN ();
+  clog << "dummy is : " << dummy.to_string () << endl;
+
+  // Another instance of the 'foo' class :
+  foo clone;
+
+  /* The following instruction is forbidden because foo 
+     inherits 'boost::noncopyable' :
+   
+   clone = dummy; // this ends in a compilation error.
+   
+   */
+
+  // Anyway, we can use this workaround :
+  copy (dummy, clone);
+  clog << "clone is : " << clone.to_string () << endl;
+
+  return 0;
+}
+
+// end of tutorial_pba_6.cpp
+
+
+

+ + +

Remark : if a class has been made non-copyable at design, +it is likely for a good reason; so it is not recommended to workaround +this trait using such a trick, unless you know what you are doing +and all the consequences ! +

+ + + +
+To top +
+
+ + + +

An alternative to PBA using text or XML archives made portable

+ +

+In some circonstances, it may be useful to use the Boost text +and XML archives in somewhat portable way. For example, we may +want to benefit of the XML archive's human-friendly format for +debugging purpose before to switch to the PBA for production runs. +However, the text and XML archives provided by the Boost +serialization library are not strictly portable, particularly because +they does not support the serialization of non-finite floating point +numbers. This is because the serialization of floating point numbers +depends on some formatting features of standard I/O streams. See the +tutorial_pba_7.cpp sample program below : +

+ +
+ The tutorial_pba_7.cpp source code DownloadShow/hide +
+/** tutorial_pba_7.cpp
+ *
+ * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
+ *
+ * Use, modification and distribution is subject to the Boost Software
+ * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+ * http://www.boost.org/LICENSE_1_0.txt)
+ *
+ */
+
+/**
+ * The intent of this program is to serve as a tutorial for
+ * users of the portable binary archive in the framework of 
+ * the Boost/Serialization library. 
+ *
+ * This example shows how the default behaviour of standard 
+ * I/O streams does not support the read/write operations of 
+ * non-finite floating point values in a portable way.
+ *
+ */
+
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <limits>
+
+using namespace std;
+
+int main (void)
+{
+  {
+    float x = numeric_limits<float>::infinity ();
+    double y = numeric_limits<double>::quiet_NaN ();
+    cout.precision (8);
+    cout << "x = " << x << endl;
+    cout.precision (16);
+    cout << "y = " << y << endl;
+  }
+
+  {
+    string input ("inf nan");
+    istringstream iss (input);
+    float x; 
+    double y;
+    iss >> x >> y;
+    if (! iss)
+      {
+	cerr << "Cannot read 'x' or 'y' : non finite values are not supported !" << endl;
+      }
+  }
+  return 0;
+}
+
+// end of tutorial_pba_7.cpp
+
+
+

+ + +

+Depending on the system, one can get some various representation +respectively for the infinity and NaN values : +

    +
  • typically on Windows : +
    +1.#INF
    +
    +and +
    +-1.#IND
    +
    +
  • and on Linux : +
    +inf
    +
    +and +
    +nan
    +
    + +
+Usually one can print such non finite values in an output stream +(using such a non portable representation), but parsing it from an +input stream fails ! +

+ +

+Hopefully this issue can be solved by configuring the I/O streams with +some special locale features provided by Boost +(see this +link). +

+ +

+The tutorial_pba_8.cpp program +shows how this can be achieved through the use of special resources +from the boost/archive/codecvt_null.hpp and +boost/math/special_functions/nonfinite_num_facets.hpp headers : +

+ +
+ The tutorial_pba_8.cpp source code DownloadShow/hide +
+/** tutorial_pba_8.cpp
+ *
+ * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
+ *
+ * Use, modification and distribution is subject to the Boost Software
+ * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+ * http://www.boost.org/LICENSE_1_0.txt)
+ *
+ */
+
+/**
+ * The intent of this program is to serve as a tutorial for
+ * users of the portable binary archive in the framework of 
+ * the Boost/Serialization library. 
+ *
+ * This example shows how to store some variables
+ * of basic types (bool, integer, floating point numbers, STL string) 
+ * using the text or XML archive format associated to a 
+ * standard output file stream supporting portable non-finite
+ * floating point values.
+ *
+ */
+
+#include <string>
+#include <fstream>
+#include <limits>
+#include <locale>
+
+#include <boost/cstdint.hpp>
+#include <boost/archive/xml_oarchive.hpp>
+#include <boost/archive/text_oarchive.hpp>
+#include <boost/serialization/nvp.hpp>
+#include <boost/archive/codecvt_null.hpp>
+#include <boost/math/special_functions/nonfinite_num_facets.hpp>
+
+using namespace std;
+
+void do_text_out (void)
+{
+  // The name for the example data text file :  
+  string filename = "pba_8.txt"; 
+
+  // Some variables of various primitive types :
+  bool        b         = true;
+  char        c         = 'B';
+  uint32_t    answer    = 42;
+  float       value     = numeric_limits<float>::infinity ();
+  double      precision = numeric_limits<double>::quiet_NaN ();
+  string      question  = "What makes you think she's a witch?";
+  
+  // Open an output file stream :
+  ofstream fout (filename.c_str ());
+
+  // Prepare the output file stream for inf/NaN support :
+  locale default_locale (locale::classic (),
+			 new boost::archive::codecvt_null<char>);
+  locale infnan_locale (default_locale,
+			new boost::math::nonfinite_num_put<char>);
+  fout.imbue (infnan_locale);
+  
+  {
+    // Create an output text archive attached to the output file :
+    boost::archive::text_oarchive ota (fout, boost::archive::no_codecvt);
+    
+    // Store (serializing) variables :
+    ota & b & c & answer & value & precision & question;
+  }
+
+  return;   
+}
+
+void do_xml_out (void)
+{
+  // The name for the example data XML file :  
+  string filename = "pba_8.xml"; 
+
+  // Some variables of various primitive types :
+  bool        b         = true;
+  char        c         = 'B';
+  uint32_t    answer    = 42;
+  float       value     = numeric_limits<float>::infinity ();
+  double      precision = numeric_limits<double>::quiet_NaN ();
+  string      question  = "What makes you think she's a witch?";
+  
+  // Open an output file stream :
+  ofstream fout (filename.c_str ());
+
+  // Prepare the output file stream for inf/NaN support :
+  locale default_locale (locale::classic (),
+			 new boost::archive::codecvt_null<char>);
+  locale infnan_locale (default_locale,
+			new boost::math::nonfinite_num_put<char>);
+  fout.imbue (infnan_locale);
+   
+  {
+    // Create an output text archive attached to the output file :
+    boost::archive::xml_oarchive oxa (fout, boost::archive::no_codecvt);
+    
+    // Store (serializing) variables :
+    oxa & BOOST_SERIALIZATION_NVP(b)
+      & BOOST_SERIALIZATION_NVP(c)
+      & BOOST_SERIALIZATION_NVP(answer)
+      & BOOST_SERIALIZATION_NVP(value)
+      & BOOST_SERIALIZATION_NVP(precision) 
+      & BOOST_SERIALIZATION_NVP(question);
+  }
+
+  return;   
+}
+
+int main (void)
+{
+  do_text_out ();
+  do_xml_out ();
+  return 0;
+}
+
+// end of tutorial_pba_8.cpp
+
+
+

+ + +

+The program creates two output files : +

    +
  • pba_8.txt stores a text archive with + non finite floating point values : +
    +22 serialization::archive 9 1 66 42 inf nan 35 What makes you think she's a witch?
    +
    +
    +
  • pba_8.xml which stored the equivalent content + using the XML archive format : + +
    +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
    +<!DOCTYPE boost_serialization>
    +<boost_serialization signature="serialization::archive" version="9">
    +<b>1</b>
    +<c>66</c>
    +<answer>42</answer>
    +<value>inf</value>
    +<precision>nan</precision>
    +<question>What makes you think she&apos;s a witch?</question>
    +</boost_serialization>
    +
    +
    + + +
+

+ +

+The tutorial_pba_9.cpp program +deserializes the data from the text and XML archive files (respectively +pba_8.txt and pba_8.xml) and prints the restored variables : +

+Loaded values from text archive are: 
+  b         = 1
+  c         = 'B'
+  answer    = 42
+  value     = inf
+  precision = nan
+  question  = "What makes you think she's a witch?"
+Loaded values from XML archive are: 
+  b         = 1
+  c         = 'B'
+  answer    = 42
+  value     = inf
+  precision = nan
+  question  = "What makes you think she's a witch?"
+
+
+

+ +

+

+ The tutorial_pba_9.cpp source code DownloadShow/hide +
+/** tutorial_pba_9.cpp
+ *
+ * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
+ *
+ * Use, modification and distribution is subject to the Boost Software
+ * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+ * http://www.boost.org/LICENSE_1_0.txt)
+ *
+ */
+
+/**
+ * The intent of this program is to serve as a tutorial for
+ * users of the portable binary archive in the framework of 
+ * the Boost/Serialization library. 
+ *
+ * This example shows how to load some variables of basic 
+ * types (bool, char, integer, floating point numbers, STL string) 
+ * using the text or XML archive format associated to a 
+ * standard file input stream supporting portable non-finite
+ * floating point values.
+ *
+ */
+
+#include <string>
+#include <fstream>
+#include <limits>
+#include <locale>
+
+#include <boost/cstdint.hpp>
+#include <boost/archive/xml_iarchive.hpp>
+#include <boost/archive/text_iarchive.hpp>
+#include <boost/serialization/nvp.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/archive/codecvt_null.hpp>
+#include <boost/math/special_functions/nonfinite_num_facets.hpp>
+
+using namespace std;
+
+void do_text_in (void)
+{
+  // The name for the example data text file :  
+  string filename = "pba_8.txt"; 
+  // Some variables of various primitive types :
+  bool        b;
+  char        c;
+  uint32_t    answer;
+  float       value;
+  double      precision;
+  string      question;
+  
+  // Open an input file stream :
+  ifstream fin (filename.c_str ());
+
+  // Prepare the input file stream for inf/NaN support :
+  locale default_locale (locale::classic (),
+			 new boost::archive::codecvt_null<char>);
+  locale infnan_locale (default_locale,
+			new boost::math::nonfinite_num_get<char>);
+  fin.imbue (infnan_locale);
+ 
+  {
+    // Create an input text archive attached to the input file :
+    boost::archive::text_iarchive ita (fin, boost::archive::no_codecvt);
+    
+    // Store (serializing) variables :
+    ita & b & c & answer & value & precision & question;
+  }
+
+  clog << "Loaded values from text archive are: " << endl;
+  clog << "  b         = " << b << endl;
+  clog << "  c         = '" << c << "'" <<  endl;
+  clog << "  answer    = " << answer << endl;
+  clog << "  value     = " << value << endl;
+  clog << "  precision = " << precision << endl;
+  clog << "  question  = \"" << question << "\"" << endl;
+
+  return;   
+}
+
+void do_xml_in (void)
+{
+  // The name for the example data text file :  
+  string filename = "pba_8.xml"; 
+
+  // Some variables of various primitive types :
+  bool        b;
+  char        c;
+  uint32_t    answer;
+  float       value;
+  double      precision;
+  string      question;
+  
+  // Open an input file stream :
+  ifstream fin (filename.c_str ());
+
+  // Prepare the input file stream for inf/NaN support :
+  locale default_locale (locale::classic (),
+			 new boost::archive::codecvt_null<char>);
+  locale infnan_locale (default_locale,
+			new boost::math::nonfinite_num_get<char>);
+  fin.imbue (infnan_locale);
+
+  {
+    // Create an output text archive attached to the output file :
+    boost::archive::xml_iarchive ixa (fin, boost::archive::no_codecvt);
+    
+    // Store (serializing) variables :
+    ixa & BOOST_SERIALIZATION_NVP(b)
+      & BOOST_SERIALIZATION_NVP(c)
+      & BOOST_SERIALIZATION_NVP(answer)
+      & BOOST_SERIALIZATION_NVP(value)
+      & BOOST_SERIALIZATION_NVP(precision) 
+      & BOOST_SERIALIZATION_NVP(question);
+  }
+
+  clog << "Loaded values from XML archive are: " << endl;
+  clog << "  b         = " << b << endl;
+  clog << "  c         = '" << c << "'" <<  endl;
+  clog << "  answer    = " << answer << endl;
+  clog << "  value     = " << value << endl;
+  clog << "  precision = " << precision << endl;
+  clog << "  question  = \"" << question << "\"" << endl;
+
+  return;   
+}
+
+int main (void)
+{
+  do_text_in ();
+  do_xml_in ();
+  return 0;
+}
+
+// end of tutorial_pba_9.cpp
+
+
+

+ +

+ + + +
+To top +
+
+ + + +

Using PBA serialization associated with on-the-fly (de)compressed file streams

+ +

+The tutorial_pba_10.cpp program +illustrates how to serialize, then deserialize, a class from a PBA associated +to a GZIP compressed file stream, thanks to a technique +provided by the Boost/Iostreams library. The class contains a large +STL vector of double precision floating point numbers with arbitrary values: +

+ +
+ The tutorial_pba_10.cpp source code DownloadShow/hide +
+/** tutorial_pba_10.cpp
+ *
+ * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
+ *
+ * Use, modification and distribution is subject to the Boost Software
+ * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+ * http://www.boost.org/LICENSE_1_0.txt)
+ *
+ */
+
+/**
+ * The intent of this program is to serve as a tutorial for
+ * users of the portable binary archive in the framework of 
+ * the Boost/Serialization library. 
+ *
+ * This example shows how use PBAs combined with on-the-fly 
+ * compressed I/O streams.
+ *
+ */
+
+#include <string>
+#include <fstream>
+#include <limits>
+#include <vector>
+
+#include <boost/cstdint.hpp>
+#include <boost/archive/portable_binary_oarchive.hpp>
+#include <boost/archive/portable_binary_iarchive.hpp>
+#include <boost/iostreams/filtering_stream.hpp>
+#include <boost/iostreams/filter/gzip.hpp>
+#include <boost/serialization/access.hpp>
+#include <boost/serialization/vector.hpp>
+
+using namespace std;
+
+class data_type
+{
+private:
+  friend class boost::serialization::access;
+  template<class Archive>
+  void serialize (Archive & ar, const unsigned int version);
+public:
+  void print (ostream & out, const string & title) const;
+public:
+  vector<double> values;
+  data_type ();
+};
+
+data_type::data_type () : values ()
+{
+  return;
+}
+
+void data_type::print (ostream & out, const string & title) const
+{
+  out << endl;
+  out << title << " :" << endl;
+  for (int i = 0; i < this->values.size (); ++i)
+    {
+      out.precision (16);
+      out.width (18);
+      out << this->values [i] << ' ' ;
+      if ((i%4) == 3) clog << endl;
+    }
+  out << endl;
+  return;
+}
+  
+template<class Archive>
+void data_type::serialize (Archive & ar, const unsigned int version)
+{
+  ar & values;
+  return;
+}
+
+void do_gzipped_out (void)
+{
+  // The name for the output data file :  
+  string filename = "pba_10.data.gz"; 
+
+  // A data structure to be stored :
+  data_type my_data;
+
+  // Fill the vector with arbitrary (possibly non-finite) values :
+  size_t dim = 1000;
+  my_data.values.reserve (dim);
+  for (int i = 0; i < dim; ++i)
+    {      
+      double val = (i + 1) * (1.0 + 3 * numeric_limits<double>::epsilon ());
+      if (i == 4) val = numeric_limits<double>::quiet_NaN ();
+      if (i == 23) val = numeric_limits<double>::infinity ();
+      if (i == 73) val = -numeric_limits<double>::infinity ();
+      if (i == 90) val = 0.0;
+      my_data.values.push_back (val);
+    }
+
+  // Print:
+  my_data.print (clog, "Stored data");
+
+  // Create an output filtering stream :
+  boost::iostreams::filtering_ostream zout;
+  zout.push (boost::iostreams::gzip_compressor ());
+  
+  // Open an output file stream in binary mode :
+  ofstream fout (filename.c_str (), ios_base::binary);
+  zout.push (fout);
+
+  // Save to PBA :
+  {
+    // Create an output portable binary archive attached to the output file :
+    boost::archive::portable_binary_oarchive opba (zout);
+    
+    // Store (serializing) the data :
+    opba & my_data;
+  }
+
+  // Clean termination of the streams :
+  zout.flush ();
+  zout.reset ();
+
+  return;   
+}
+
+void do_gzipped_in (void)
+{
+  // The name for the input data file :  
+  string filename = "pba_10.data.gz"; 
+
+  // A data structure to be loaded :
+  data_type my_data;
+
+  // Create an input filtering stream :
+  boost::iostreams::filtering_istream zin;
+  zin.push (boost::iostreams::gzip_decompressor ());
+  
+  // Open an input file stream in binary mode :
+  ifstream fin (filename.c_str (), ios_base::binary);
+  zin.push (fin);
+
+  // Load from PBA :
+  {
+    // Create an input portable binary archive attached to the input file :
+    boost::archive::portable_binary_iarchive ipba (zin);
+    
+    // Load (deserializing) the data :
+    ipba & my_data;
+  }
+
+  // Print:
+  my_data.print (clog, "Loaded data");
+
+  return;   
+}
+
+int main (void)
+{
+  do_gzipped_out (); 
+  do_gzipped_in ();
+  return 0;
+}
+
+// end of tutorial_pba_10.cpp
+
+
+

+ + +

The resulting compressed pba_10.data.gz file contains 1,574 bytes. +This has to be compared with the size of the plain (uncompressed) +binary archive which equals 9,001 bytes: + +

127   1   9   0   0   2 232   3   0   8   3   0   0   0   0   0
+240  63   8   3   0   0   0   0   0   0  64   8   4   0   0   0
+  0   0   8  64   8   3   0   0   0   0   0  16  64   8 255 255
+255 255 255 255 255 127   8   4   0   0   0   0   0  24  64   8
+...
+
+ +which can be interpreted as : +
    +
  • 3 bytes for the usual archive header : 127 1 +9, +
  • 2 zero-optimized bytes to store the class ID + and the class version :0 0, +
  • 3 bytes to store the size of the vector (1000) using the PBA +representation of integers (2 232 3), +
  • 1 zero-optimized byte to store the class version of the +objects stored in the STL vector (here +the primitive double type) : 0, +
  • 999 non-zero double precision floating point values (including non-finite values) each using 9 bytes (1 byte for +the size and 8 bytes for the content) : 8 ? ? ? ? ? +? ? ?, +
  • 1 zero floating point value that uses only one zero-optimized byte : 0. +
+Thus one here achieves a very interesting compression level. +

+

+It is also possible to use BZIP2 in a similar fashion +(using ressources from the boost/iostreams/filter/bzip2.hpp header +in place of boost/iostreams/filter/gzip.hpp). +

+ + + +
+To top +
+
+ + +

A simple PBA versus text archive benchmark test

+ +

+The tutorial_pba_11.cpp program +runs a benchmark test in the aim to compare the relative fastness of PBA and text archives +both for read and write operations. It stores then loads a vector of many (107) +random double values and prints the associated (de)serialization time for both kinds of archives: +

+ +
+ The tutorial_pba_11.cpp source code DownloadShow/hide +
+/** tutorial_pba_11.cpp
+ *
+ * (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
+ *
+ * Use, modification and distribution is subject to the Boost Software
+ * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+ * http://www.boost.org/LICENSE_1_0.txt)
+ *
+ */
+
+/**
+ * The intent of this program is to serve as a tutorial for
+ * users of the portable binary archive in the framework of 
+ * the Boost/Serialization library. 
+ *
+ * This example program compares the times needed to serialize
+ * and deserialize some large amount of data using PBA and 
+ * text archives.
+ *
+ */
+
+#include <string>
+#include <fstream>
+#include <vector>
+
+#include <boost/archive/portable_binary_oarchive.hpp>
+#include <boost/archive/portable_binary_iarchive.hpp>
+#include <boost/archive/text_oarchive.hpp>
+#include <boost/archive/text_iarchive.hpp>
+#include <boost/serialization/access.hpp>
+#include <boost/serialization/vector.hpp>
+#include <boost/random/mersenne_twister.hpp>
+#include <boost/random/uniform_real_distribution.hpp>
+#include <boost/timer.hpp>
+
+using namespace std;
+
+class data_type
+{
+private:
+  friend class boost::serialization::access;
+  template<class Archive>
+  void serialize (Archive & ar, const unsigned int version);
+public:
+  void print (ostream & out, const string & title) const;
+public:
+  vector<double> values;
+  data_type ();
+};
+
+data_type::data_type () : values ()
+{
+  return;
+}
+
+void data_type::print (ostream & out, const string & title) const
+{
+  out << endl;
+  out << title << " :" << endl;
+  bool skip = false;
+  for (int i = 0; i < this->values.size (); ++i)
+    {
+      if ((i >= 12) && (i < (int) this->values.size () - 8)) 
+	{
+	  if (! skip) out << " ..." << endl;
+	  skip = true;
+	  continue;
+	}
+      out.precision (16);
+      out.width (18);
+      out << this->values [i] << ' ' ;
+      if ((i%4) == 3) clog << endl;
+    }
+  out << endl;
+  return;
+}
+  
+template<class Archive>
+void data_type::serialize (Archive & ar, const unsigned int version)
+{
+  ar & values;
+  return;
+}
+
+double do_pba_out (const data_type & a_data)
+{
+  string filename = "pba_11.data"; 
+  ofstream fout (filename.c_str (), ios_base::binary);
+  boost::timer io_timer;    
+  {
+    boost::archive::portable_binary_oarchive opba (fout);
+    opba & a_data;
+  }
+  return io_timer.elapsed ();
+}
+
+double do_pba_in (data_type & a_data)
+{
+  string filename = "pba_11.data"; 
+  ifstream fin (filename.c_str (), ios_base::binary);
+  boost::timer io_timer;    
+  {
+    boost::archive::portable_binary_iarchive ipba (fin);
+    ipba & a_data;
+  }
+  return io_timer.elapsed ();
+}
+
+double do_text_out (const data_type & a_data)
+{
+  string filename = "pba_11.txt"; 
+  ofstream fout (filename.c_str ());
+  boost::timer io_timer;    
+  {
+    boost::archive::text_oarchive ota (fout);
+    ota & a_data;
+  }
+  return io_timer.elapsed ();
+}
+
+double do_text_in (data_type & a_data)
+{
+  string filename = "pba_11.txt"; 
+  ifstream fin (filename.c_str ());
+  boost::timer io_timer;    
+  {
+    boost::archive::text_iarchive ita (fin);
+    ita & a_data;
+  }
+  return io_timer.elapsed ();
+}
+
+int main (void)
+{
+  double elapsed_time_pba_out; 
+  double elapsed_time_text_out; 
+  double elapsed_time_pba_in; 
+  double elapsed_time_text_in; 
+  data_type my_data; // A data structure to be stored then loaded.
+
+  {
+    // Fill the vector with random values :
+    size_t dim = 10000000;
+    my_data.values.reserve (dim);
+    boost::random::mt19937 rng;
+    boost::random::uniform_real_distribution<> flat (0.0, 100.0);
+    for (int i = 0; i < dim; ++i)
+      {      
+	double val = flat (rng);
+	my_data.values.push_back (val);
+      }
+    my_data.print (clog, "Stored data in PBA and text archive");
+  }
+
+  {
+    // Store in PBA :
+    elapsed_time_pba_out = do_pba_out (my_data);
+  }
+
+  {
+    // Store in text archive :
+    elapsed_time_text_out = do_text_out (my_data);
+  }     
+
+  {
+    my_data.values.clear ();
+    // Load from PBA :
+    elapsed_time_pba_in = do_pba_in (my_data);
+    my_data.print (clog, "Loaded data from PBA");
+  }
+
+  {
+    my_data.values.clear ();
+    // Load from text archive :
+    elapsed_time_text_in = do_text_in (my_data);
+    my_data.print (clog, "Loaded data from text archive");
+  }
+  
+  clog << "PBA  store I/O elapsed time : " << elapsed_time_pba_out  << " (second)" << endl;
+  clog << "Text store I/O elapsed time : " << elapsed_time_text_out << " (second)" << endl;  
+  clog << "PBA  load  I/O elapsed time : " << elapsed_time_pba_in   << " (second)" << endl;
+  clog << "Text load  I/O elapsed time : " << elapsed_time_text_in  << " (second)" << endl;
+
+  return 0;
+}
+
+// end of tutorial_pba_11.cpp
+
+
+

+ + +

On a 1.60 GHz processor running gcc 4.5.2 on Linux 2.6.38, the result is the following: +

PBA  store I/O elapsed time : 1.86 (second)
+Text store I/O elapsed time : 22.66 (second)
+PBA  load  I/O elapsed time : 1.53 (second)
+Text load  I/O elapsed time : 19.71 (second)
+
+It this simple case, the use of portable binary archives is faster by at least a factor 10 +compared to the traditional Boost text archives. This is a +significant saving in time. These performances are highly desirable in the typical framework +of scientific/computing activities where large amounts of data are accessed through files. +The PBA concept is thus a valuable candidate for such applications. +

+ +

+One can also consider the sizes of the resulting archive files: +

    +
  • pba_11.data (PBA) : 90,000,010 bytes +
  • pba_11.txt (text archive) : 189,000,040 bytes +
+The PBA allows to save a typical factor 2 in storage space compared to text archive. +This is another strong argument for using PBA. +

+ + + +
+To top +
+
+ + + +
+

Revised 2011-11-07 +

© Copyright François Mauger, +Christian Pfligersdorffer 2011.
+Distributed under the Boost Software License, Version 1.0.
+(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +
+

+ + + + + diff --git a/contrib/epee/LICENSE.txt b/contrib/epee/LICENSE.txt new file mode 100644 index 00000000..4a6b529e --- /dev/null +++ b/contrib/epee/LICENSE.txt @@ -0,0 +1,25 @@ +Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * 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. + * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 Andrey N. Sabelnikov 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. \ No newline at end of file diff --git a/contrib/epee/README.md b/contrib/epee/README.md new file mode 100644 index 00000000..a69884f5 --- /dev/null +++ b/contrib/epee/README.md @@ -0,0 +1 @@ +epee - is a small library of helpers, wrappers, tools and and so on, used to make my life easier. \ No newline at end of file diff --git a/contrib/epee/demo/.gitignore b/contrib/epee/demo/.gitignore new file mode 100644 index 00000000..d9b4f015 --- /dev/null +++ b/contrib/epee/demo/.gitignore @@ -0,0 +1 @@ +/build/* diff --git a/contrib/epee/demo/CMakeLists.txt b/contrib/epee/demo/CMakeLists.txt new file mode 100644 index 00000000..b4ac2cc8 --- /dev/null +++ b/contrib/epee/demo/CMakeLists.txt @@ -0,0 +1,49 @@ +cmake_minimum_required(VERSION 2.8) +set(Boost_USE_MULTITHREADED ON) +#set(Boost_DEBUG 1) +find_package(Boost COMPONENTS system filesystem thread date_time chrono regex ) + +include_directories( ${Boost_INCLUDE_DIRS} ) + + +IF (MSVC) + add_definitions( "/W3 /D_CRT_SECURE_NO_WARNINGS /wd4996 /wd4345 /nologo /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /bigobj" ) +ELSE() + # set stuff for other systems + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wno-reorder -D_GNU_SOURCE") +ENDIF() + + +include_directories(.) +include_directories(../include) +include_directories(iface) + + +# Add folders to filters +file(GLOB_RECURSE LEVIN_GENERAL_SECTION RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/demo_levin_server/*.h + ${CMAKE_CURRENT_SOURCE_DIR}/demo_levin_server/*.inl + ${CMAKE_CURRENT_SOURCE_DIR}/demo_levin_server/*.cpp) + +file(GLOB_RECURSE HTTP_GENERAL_SECTION RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/demo_http_server/*.h + ${CMAKE_CURRENT_SOURCE_DIR}/demo_http_server/*.inl + ${CMAKE_CURRENT_SOURCE_DIR}/demo_http_server/*.cpp) + + + +source_group(general FILES ${LEVIN_GENERAL_SECTION} FILES ${HTTP_GENERAL_SECTION}) +#source_group(general FILES ${HTTP_GENERAL_SECTION}) + +add_executable(demo_http_server ${HTTP_GENERAL_SECTION} ) +add_executable(demo_levin_server ${LEVIN_GENERAL_SECTION} ) + +target_link_libraries( demo_http_server ${Boost_LIBRARIES} ) +target_link_libraries( demo_levin_server ${Boost_LIBRARIES} ) + +IF (NOT WIN32) + target_link_libraries (demo_http_server rt) + target_link_libraries (demo_levin_server rt) +ENDIF() + + diff --git a/contrib/epee/demo/README.txt b/contrib/epee/demo/README.txt new file mode 100644 index 00000000..e69de29b diff --git a/contrib/epee/demo/demo_http_server/demo_http_server.cpp b/contrib/epee/demo/demo_http_server/demo_http_server.cpp new file mode 100644 index 00000000..85547e4c --- /dev/null +++ b/contrib/epee/demo/demo_http_server/demo_http_server.cpp @@ -0,0 +1,217 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + +#include "stdafx.h" +#include "console_handler.h" +#include "demo_http_server.h" +#include "net/http_client.h" +#include "storages/http_abstract_invoke.h" + + +template +bool communicate(const std::string url, t_request& req, t_response& rsp, const std::string& ip, const std::string& port, bool use_json, bool use_jrpc = false) +{ + epee::net_utils::http::http_simple_client http_client; + bool r = http_client.connect(ip, port, 1000); + CHECK_AND_ASSERT_MES(r, false, "failed to connect"); + if(use_json) + { + if(use_jrpc) + { + epee::json_rpc::request req_t = AUTO_VAL_INIT(req_t); + req_t.jsonrpc = "2.0"; + req_t.id = epee::serialization::storage_entry(10); + req_t.method = "command_example_1"; + req_t.params = req; + epee::json_rpc::response resp_t = AUTO_VAL_INIT(resp_t); + if(!epee::net_utils::invoke_http_json_remote_command2("/request_json_rpc", req_t, resp_t, http_client)) + { + return false; + } + rsp = resp_t.result; + return true; + }else + return epee::net_utils::invoke_http_json_remote_command2(url, req, rsp, http_client); + } + else + return epee::net_utils::invoke_http_bin_remote_command2(url, req, rsp, http_client); +} + + +int main(int argc, char* argv[]) +{ + TRY_ENTRY(); + string_tools::set_module_name_and_folder(argv[0]); + + //set up logging options + log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2); + log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL); + log_space::log_singletone::add_logger(LOGGER_FILE, + log_space::log_singletone::get_default_log_file().c_str(), + log_space::log_singletone::get_default_log_folder().c_str()); + + + + LOG_PRINT("Demo server starting ...", LOG_LEVEL_0); + + + demo::demo_http_server srv; + + start_default_console(&srv, "#"); + + std::string bind_param = "0.0.0.0"; + std::string port = "83"; + + if(!srv.init(port, bind_param)) + { + LOG_ERROR("Failed to initialize srv!"); + return 1; + } + + //log loop + srv.run(); + size_t count = 0; + while (!srv.is_stop()) + { + + demo::COMMAND_EXAMPLE_1::request req; + req.sub = demo::get_test_data(); + demo::COMMAND_EXAMPLE_1::response rsp; + bool r = false; + if(count%2) + {//invoke json + r = communicate("/request_api_json_1", req, rsp, "127.0.0.1", port, true, true); + }else{ + r = communicate("/request_api_bin_1", req, rsp, "127.0.0.1", port, false); + } + CHECK_AND_ASSERT_MES(r, false, "failed to invoke http request"); + CHECK_AND_ASSERT_MES(rsp.m_success, false, "wrong response"); + CHECK_AND_ASSERT_MES(rsp.subs.size()==1, false, "wrong response"); + CHECK_AND_ASSERT_MES(rsp.subs.front() == demo::get_test_data(), false, "wrong response"); + //misc_utils::sleep_no_w(1000); + ++count; + } + bool r = srv.wait_stop(); + CHECK_AND_ASSERT_MES(r, 1, "failed to wait server stop"); + srv.deinit(); + + LOG_PRINT("Demo server stoped.", LOG_LEVEL_0); + return 1; + + CATCH_ENTRY_L0("main", 1); +} + +/************************************************************************/ +/* */ +/************************************************************************/ +namespace demo +{ + bool demo_http_server::init(const std::string& bind_port, const std::string& bind_ip) + { + + + //set self as callback handler + m_net_server.get_config_object().m_phandler = this; + + //here set folder for hosting reqests + m_net_server.get_config_object().m_folder = ""; + + LOG_PRINT_L0("Binding on " << bind_ip << ":" << bind_port); + return m_net_server.init_server(bind_port, bind_ip); + } + + bool demo_http_server::run() + { + m_stop = false; + //here you can set worker threads count + int thrds_count = 4; + + //go to loop + LOG_PRINT("Run net_service loop( " << thrds_count << " threads)...", LOG_LEVEL_0); + if(!m_net_server.run_server(thrds_count, false)) + { + LOG_ERROR("Failed to run net tcp server!"); + } + + return true; + } + + bool demo_http_server::deinit() + { + return m_net_server.deinit_server(); + } + + bool demo_http_server::send_stop_signal() + { + m_stop = true; + m_net_server.send_stop_signal(); + return true; + } + + bool demo_http_server::on_requestr_uri_1(const net_utils::http::http_request_info& query_info, + net_utils::http::http_response_info& response, + const net_utils::connection_context_base& m_conn_context) + { + return true; + } + + + bool demo_http_server::on_requestr_uri_2(const net_utils::http::http_request_info& query_info, + net_utils::http::http_response_info& response, + const net_utils::connection_context_base& m_conn_context) + { + return true; + } + + + bool demo_http_server::on_hosting_request( const net_utils::http::http_request_info& query_info, + net_utils::http::http_response_info& response, + const net_utils::connection_context_base& m_conn_context) + { + //read file from filesystem here + return true; + } + + bool demo_http_server::on_request_api_1(const COMMAND_EXAMPLE_1::request& req, COMMAND_EXAMPLE_1::response& res, connection_context& ctxt) + { + CHECK_AND_ASSERT_MES(req.sub == demo::get_test_data(), false, "wrong request"); + res.m_success = true; + res.subs.push_back(req.sub); + return true; + } + + bool demo_http_server::on_request_api_1_with_error(const COMMAND_EXAMPLE_1::request& req, COMMAND_EXAMPLE_1::response& res, epee::json_rpc::error& error_resp, connection_context& ctxt) + { + error_resp.code = 232432; + error_resp.message = "bla bla bla"; + return false; + } + + bool demo_http_server::on_request_api_2(const COMMAND_EXAMPLE_2::request& req, COMMAND_EXAMPLE_2::response& res, connection_context& ctxt) + { + return true; + } +} diff --git a/contrib/epee/demo/demo_http_server/demo_http_server.h b/contrib/epee/demo/demo_http_server/demo_http_server.h new file mode 100644 index 00000000..088ead54 --- /dev/null +++ b/contrib/epee/demo/demo_http_server/demo_http_server.h @@ -0,0 +1,103 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#pragma once +#include +#include + +#include "net/http_server_cp2.h" +#include "transport_defs.h" +#include "net/http_server_handlers_map2.h" + +using namespace epee; + +namespace demo +{ + + class demo_http_server: public net_utils::http::i_http_server_handler + { + public: + typedef epee::net_utils::connection_context_base connection_context; + + demo_http_server():m_stop(false){} + bool run(); + bool init(const std::string& bind_port = "11112", const std::string& bind_ip = "0.0.0.0"); + bool deinit(); + bool send_stop_signal(); + bool is_stop(){return m_stop;} + bool wait_stop(){return m_net_server.timed_wait_server_stop(100000);} + private: + + + CHAIN_HTTP_TO_MAP2(connection_context); //forward http requests to uri map + + BEGIN_URI_MAP2() + MAP_URI2("/requestr_uri_1", on_requestr_uri_1) + MAP_URI2("/requestr_uri_2", on_requestr_uri_1) + //MAP_URI_AUTO_XML2("/request_api_xml_1", on_request_api_1, COMMAND_EXAMPLE_1) + //MAP_URI_AUTO_XML2("/request_api_xml_2", on_request_api_2, COMMAND_EXAMPLE_2) + MAP_URI_AUTO_JON2("/request_api_json_1", on_request_api_1, COMMAND_EXAMPLE_1) + MAP_URI_AUTO_JON2("/request_api_json_2", on_request_api_2, COMMAND_EXAMPLE_2) + MAP_URI_AUTO_BIN2("/request_api_bin_1", on_request_api_1, COMMAND_EXAMPLE_1) + MAP_URI_AUTO_BIN2("/request_api_bin_2", on_request_api_2, COMMAND_EXAMPLE_2) + BEGIN_JSON_RPC_MAP("/request_json_rpc") + MAP_JON_RPC("command_example_1", on_request_api_1, COMMAND_EXAMPLE_1) + MAP_JON_RPC("command_example_2", on_request_api_2, COMMAND_EXAMPLE_2) + MAP_JON_RPC_WE("command_example_1_we", on_request_api_1_with_error, COMMAND_EXAMPLE_1) + END_JSON_RPC_MAP() + CHAIN_URI_MAP2(on_hosting_request) + END_URI_MAP2() + + + + bool on_requestr_uri_1(const net_utils::http::http_request_info& query_info, + net_utils::http::http_response_info& response, + const net_utils::connection_context_base& m_conn_context); + + + bool on_requestr_uri_2(const net_utils::http::http_request_info& query_info, + net_utils::http::http_response_info& response, + const net_utils::connection_context_base& m_conn_context); + + + + + bool on_hosting_request( const net_utils::http::http_request_info& query_info, + net_utils::http::http_response_info& response, + const net_utils::connection_context_base& m_conn_context); + + bool on_request_api_1(const COMMAND_EXAMPLE_1::request& req, COMMAND_EXAMPLE_1::response& res, connection_context& ctxt); + bool on_request_api_2(const COMMAND_EXAMPLE_2::request& req, COMMAND_EXAMPLE_2::response& res, connection_context& ctxt); + + bool on_request_api_1_with_error(const COMMAND_EXAMPLE_1::request& req, COMMAND_EXAMPLE_1::response& res, epee::json_rpc::error& error_resp, connection_context& ctxt); + + net_utils::boosted_http_server_custum_handling m_net_server; + std::atomic m_stop; + }; +} + diff --git a/contrib/epee/demo/demo_http_server/stdafx.cpp b/contrib/epee/demo/demo_http_server/stdafx.cpp new file mode 100644 index 00000000..ecec2465 --- /dev/null +++ b/contrib/epee/demo/demo_http_server/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// demo_http_server.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/contrib/epee/demo/demo_http_server/stdafx.h b/contrib/epee/demo/demo_http_server/stdafx.h new file mode 100644 index 00000000..e2888320 --- /dev/null +++ b/contrib/epee/demo/demo_http_server/stdafx.h @@ -0,0 +1,40 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + +#pragma once + +#include "targetver.h" + + +#include + + +#define BOOST_FILESYSTEM_VERSION 3 +#define ENABLE_RELEASE_LOGGING +#include "misc_log_ex.h" + + diff --git a/contrib/epee/demo/demo_http_server/targetver.h b/contrib/epee/demo/demo_http_server/targetver.h new file mode 100644 index 00000000..6fe8eb79 --- /dev/null +++ b/contrib/epee/demo/demo_http_server/targetver.h @@ -0,0 +1,13 @@ +#pragma once + +// The following macros define the minimum required platform. The minimum required platform +// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run +// your application. The macros work by enabling all features available on platform versions up to and +// including the version specified. + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. +#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. +#endif + diff --git a/contrib/epee/demo/demo_levin_server/demo_levin_server.cpp b/contrib/epee/demo/demo_levin_server/demo_levin_server.cpp new file mode 100644 index 00000000..a99a1f56 --- /dev/null +++ b/contrib/epee/demo/demo_levin_server/demo_levin_server.cpp @@ -0,0 +1,200 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#include "stdafx.h" +#include "demo_levin_server.h" +#include "console_handler.h" + + +template +bool communicate(net_utils::boosted_levin_async_server& transport, int id, t_request& req, const std::string& ip, const std::string& port, bool use_async) +{ + if(use_async) + { + //IMPORTANT: do not pass local parameters from stack by reference! connect_async returns immediately, and callback will call in any thread later + transport.connect_async(ip, port, 10000, [&transport, id, req, ip, port](net_utils::connection_context_base& ctx, const boost::system::error_code& ec_) + { + if(!!ec_) + { + LOG_ERROR("Failed to connect to " << ip << ":" << port); + }else + {//connected ok! + + epee::net_utils::async_invoke_remote_command2(ctx.m_connection_id, id, req, transport.get_config_object(), [&transport, ip, port](int res_code, demo::COMMAND_EXAMPLE_1::response& rsp, net_utils::connection_context_base& ctx) + { + if(res_code < 0) + { + LOG_ERROR("Failed to invoke to " << ip << ":" << port); + }else + {//invoked ok + CHECK_AND_ASSERT_MES(rsp.m_success, false, "wrong response"); + CHECK_AND_ASSERT_MES(rsp.subs.size()==1, false, "wrong response"); + CHECK_AND_ASSERT_MES(rsp.subs.front() == demo::get_test_data(), false, "wrong response"); + LOG_PRINT_GREEN("Client COMMAND_EXAMPLE_1 async invoked ok", LOG_LEVEL_0); + } + transport.get_config_object().close(ctx.m_connection_id); + return true; + }); + LOG_PRINT_GREEN("Client COMMAND_EXAMPLE_1 async invoke requested", LOG_LEVEL_0); + } + }); + }else + { + net_utils::connection_context_base ctx = AUTO_VAL_INIT(ctx); + bool r = transport.connect(ip, port, 10000, ctx); + CHECK_AND_ASSERT_MES(r, false, "failed to connect to " << ip << ":" << port); + demo::COMMAND_EXAMPLE_1::response rsp = AUTO_VAL_INIT(rsp); + LOG_PRINT_GREEN("Client COMMAND_EXAMPLE_1 sync invoke requested", LOG_LEVEL_0); + r = epee::net_utils::invoke_remote_command2(ctx.m_connection_id, id, req, rsp, transport.get_config_object()); + CHECK_AND_ASSERT_MES(r, false, "failed to invoke levin request"); + CHECK_AND_ASSERT_MES(rsp.m_success, false, "wrong response"); + CHECK_AND_ASSERT_MES(rsp.subs.size()==1, false, "wrong response"); + CHECK_AND_ASSERT_MES(rsp.subs.front() == demo::get_test_data(), false, "wrong response"); + transport.get_config_object().close(ctx.m_connection_id); + LOG_PRINT_GREEN("Client COMMAND_EXAMPLE_1 sync invoked ok", LOG_LEVEL_0); + } + return true; +} + + +int main(int argc, char* argv[]) +{ + TRY_ENTRY(); + string_tools::set_module_name_and_folder(argv[0]); + + //set up logging options + log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2); + log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL); + log_space::log_singletone::add_logger(LOGGER_FILE, + log_space::log_singletone::get_default_log_file().c_str(), + log_space::log_singletone::get_default_log_folder().c_str()); + + + + LOG_PRINT("Demo server starting ...", LOG_LEVEL_0); + + + demo::demo_levin_server srv; + + start_default_console(&srv, "#"); + + std::string bind_param = "0.0.0.0"; + std::string port = "12345"; + + if(!srv.init(port, bind_param)) + { + LOG_ERROR("Failed to initialize srv!"); + return 1; + } + + srv.run(); + + size_t c = 1; + while (!srv.is_stop()) + { + + demo::COMMAND_EXAMPLE_1::request req; + req.sub = demo::get_test_data(); + bool r = communicate(srv.get_server(), demo::COMMAND_EXAMPLE_1::ID, req, "127.0.0.1", port, (c%2 == 0)); + misc_utils::sleep_no_w(1000); + ++c; + } + bool r = srv.wait_stop(); + CHECK_AND_ASSERT_MES(r, 1, "failed to wait server stop"); + + + srv.deinit(); + + LOG_PRINT("Demo server stoped.", LOG_LEVEL_0); + return 1; + + CATCH_ENTRY_L0("main", 1); +} + +/************************************************************************/ +/* */ +/************************************************************************/ +namespace demo +{ + bool demo_levin_server::init(const std::string& bind_port, const std::string& bind_ip) + { + m_net_server.get_config_object().m_pcommands_handler = this; + LOG_PRINT_L0("Binding on " << bind_ip << ":" << bind_port); + return m_net_server.init_server(bind_port, bind_ip); + } + + bool demo_levin_server::run() + { + m_stop = false; + //here you can set worker threads count + int thrds_count = 4; + m_net_server.get_config_object().m_invoke_timeout = 10000; + m_net_server.get_config_object().m_pcommands_handler = this; + + //go to loop + LOG_PRINT("Run net_service loop( " << thrds_count << " threads)...", LOG_LEVEL_0); + if(!m_net_server.run_server(thrds_count, false)) + { + LOG_ERROR("Failed to run net tcp server!"); + } + + LOG_PRINT("net_service loop stopped.", LOG_LEVEL_0); + return true; + } + + bool demo_levin_server::deinit() + { + return m_net_server.deinit_server(); + } + + bool demo_levin_server::send_stop_signal() + { + m_net_server.send_stop_signal(); + return true; + } + int demo_levin_server::handle_command_1(int command, COMMAND_EXAMPLE_1::request& arg, COMMAND_EXAMPLE_1::response& rsp, const net_utils::connection_context_base& context) + { + CHECK_AND_ASSERT_MES(arg.sub == demo::get_test_data(), false, "wrong request"); + rsp.m_success = true; + rsp.subs.push_back(arg.sub); + LOG_PRINT_GREEN("Server COMMAND_EXAMPLE_1 ok", LOG_LEVEL_0); + return 1; + } + int demo_levin_server::handle_command_2(int command, COMMAND_EXAMPLE_2::request& arg, COMMAND_EXAMPLE_2::response& rsp, const net_utils::connection_context_base& context) + { + return 1; + } + int demo_levin_server::handle_notify_1(int command, COMMAND_EXAMPLE_1::request& arg, const net_utils::connection_context_base& context) + { + return 1; + } + int demo_levin_server::handle_notify_2(int command, COMMAND_EXAMPLE_2::request& arg, const net_utils::connection_context_base& context) + { + return 1; + } +} diff --git a/contrib/epee/demo/demo_levin_server/demo_levin_server.h b/contrib/epee/demo/demo_levin_server/demo_levin_server.h new file mode 100644 index 00000000..5a6f68f2 --- /dev/null +++ b/contrib/epee/demo/demo_levin_server/demo_levin_server.h @@ -0,0 +1,76 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#pragma once +#include +#include + +#include "net/levin_server_cp2.h" +#include "transport_defs.h" +#include "storages/levin_abstract_invoke2.h" + +using namespace epee; + +namespace demo +{ + + class demo_levin_server: public levin::levin_commands_handler<> + { + public: + bool run(); + bool init(const std::string& bind_port = "11112", const std::string& bind_ip = "0.0.0.0"); + bool deinit(); + bool send_stop_signal(); + bool is_stop(){return m_stop;} + bool wait_stop(){return m_net_server.timed_wait_server_stop(100000);} + net_utils::boosted_levin_async_server& get_server(){return m_net_server;} + private: + + + CHAIN_LEVIN_INVOKE_MAP(); //move levin_commands_handler interface invoke(...) callbacks into invoke map + CHAIN_LEVIN_NOTIFY_STUB(); //move levin_commands_handler interface notify(...) callbacks into nothing + + BEGIN_INVOKE_MAP2(demo_levin_server) + HANDLE_INVOKE_T2(COMMAND_EXAMPLE_1, &demo_levin_server::handle_command_1) + HANDLE_INVOKE_T2(COMMAND_EXAMPLE_2, &demo_levin_server::handle_command_2) + HANDLE_NOTIFY_T2(COMMAND_EXAMPLE_1, &demo_levin_server::handle_notify_1) + HANDLE_NOTIFY_T2(COMMAND_EXAMPLE_2, &demo_levin_server::handle_notify_2) + END_INVOKE_MAP2() + + //----------------- commands handlers ---------------------------------------------- + int handle_command_1(int command, COMMAND_EXAMPLE_1::request& arg, COMMAND_EXAMPLE_1::response& rsp, const net_utils::connection_context_base& context); + int handle_command_2(int command, COMMAND_EXAMPLE_2::request& arg, COMMAND_EXAMPLE_2::response& rsp, const net_utils::connection_context_base& context); + int handle_notify_1(int command, COMMAND_EXAMPLE_1::request& arg, const net_utils::connection_context_base& context); + int handle_notify_2(int command, COMMAND_EXAMPLE_2::request& arg, const net_utils::connection_context_base& context); + //---------------------------------------------------------------------------------- + net_utils::boosted_levin_async_server m_net_server; + std::atomic m_stop; + + }; +} + diff --git a/contrib/epee/demo/demo_levin_server/stdafx.cpp b/contrib/epee/demo/demo_levin_server/stdafx.cpp new file mode 100644 index 00000000..d6ea1c6f --- /dev/null +++ b/contrib/epee/demo/demo_levin_server/stdafx.cpp @@ -0,0 +1,30 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#include "stdafx.h" + diff --git a/contrib/epee/demo/demo_levin_server/stdafx.h b/contrib/epee/demo/demo_levin_server/stdafx.h new file mode 100644 index 00000000..e2888320 --- /dev/null +++ b/contrib/epee/demo/demo_levin_server/stdafx.h @@ -0,0 +1,40 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + +#pragma once + +#include "targetver.h" + + +#include + + +#define BOOST_FILESYSTEM_VERSION 3 +#define ENABLE_RELEASE_LOGGING +#include "misc_log_ex.h" + + diff --git a/contrib/epee/demo/demo_levin_server/targetver.h b/contrib/epee/demo/demo_levin_server/targetver.h new file mode 100644 index 00000000..6fe8eb79 --- /dev/null +++ b/contrib/epee/demo/demo_levin_server/targetver.h @@ -0,0 +1,13 @@ +#pragma once + +// The following macros define the minimum required platform. The minimum required platform +// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run +// your application. The macros work by enabling all features available on platform versions up to and +// including the version specified. + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. +#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. +#endif + diff --git a/contrib/epee/demo/generate_gcc.sh b/contrib/epee/demo/generate_gcc.sh new file mode 100644 index 00000000..fcd0a8a7 --- /dev/null +++ b/contrib/epee/demo/generate_gcc.sh @@ -0,0 +1,4 @@ +mkdir build +cd build +cmake .. +#cmake -DBOOST_ROOT=/usr/local/proj/boost_1_49_0 -DBOOST_LIBRARYDIR=/usr/local/proj/boost_1_49_0/stage/lib .. diff --git a/contrib/epee/demo/generate_vc_proj.bat b/contrib/epee/demo/generate_vc_proj.bat new file mode 100644 index 00000000..11140598 --- /dev/null +++ b/contrib/epee/demo/generate_vc_proj.bat @@ -0,0 +1,7 @@ +mkdir build + +cd build + +cmake "-DBoost_USE_STATIC_LIBS=TRUE" -G "Visual Studio 11 Win64" .. +cd .. +pause \ No newline at end of file diff --git a/contrib/epee/demo/iface/transport_defs.h b/contrib/epee/demo/iface/transport_defs.h new file mode 100644 index 00000000..8463eb90 --- /dev/null +++ b/contrib/epee/demo/iface/transport_defs.h @@ -0,0 +1,221 @@ +#pragma once + +#include "serialization/keyvalue_serialization.h" +#include "storages/portable_storage_base.h" + +namespace demo +{ + + struct some_test_subdata + { + std::string m_str; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(m_str) + END_KV_SERIALIZE_MAP() + }; + + struct some_test_data + { + std::string m_str; + uint64_t m_uint64; + uint32_t m_uint32; + uint16_t m_uint16; + uint8_t m_uint8; + int64_t m_int64; + int32_t m_int32; + int16_t m_int16; + int8_t m_int8; + double m_double; + bool m_bool; + std::list m_list_of_str; + std::list m_list_of_uint64_t; + std::list m_list_of_uint32_t; + std::list m_list_of_uint16_t; + std::list m_list_of_uint8_t; + std::list m_list_of_int64_t; + std::list m_list_of_int32_t; + std::list m_list_of_int16_t; + std::list m_list_of_int8_t; + std::list m_list_of_double; + std::list m_list_of_bool; + some_test_subdata m_subobj; + std::list m_list_of_self; + epee::serialization::storage_entry m_storage_entry_int; + epee::serialization::storage_entry m_storage_entry_string; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(m_str) + KV_SERIALIZE(m_uint64) + KV_SERIALIZE(m_uint32) + KV_SERIALIZE(m_uint16) + KV_SERIALIZE(m_uint8) + KV_SERIALIZE(m_int64) + KV_SERIALIZE(m_int32) + KV_SERIALIZE(m_int16) + KV_SERIALIZE(m_int8) + KV_SERIALIZE(m_double) + KV_SERIALIZE(m_bool) + KV_SERIALIZE(m_subobj) + KV_SERIALIZE(m_list_of_str) + KV_SERIALIZE(m_list_of_uint64_t) + KV_SERIALIZE(m_list_of_uint32_t) + KV_SERIALIZE(m_list_of_uint16_t) + KV_SERIALIZE(m_list_of_uint8_t) + KV_SERIALIZE(m_list_of_int64_t) + KV_SERIALIZE(m_list_of_int32_t) + KV_SERIALIZE(m_list_of_int16_t) + KV_SERIALIZE(m_list_of_int8_t) + KV_SERIALIZE(m_list_of_double) + KV_SERIALIZE(m_list_of_bool) + KV_SERIALIZE(m_list_of_self) + KV_SERIALIZE(m_storage_entry_int) + KV_SERIALIZE(m_storage_entry_string) + END_KV_SERIALIZE_MAP() + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + struct COMMAND_EXAMPLE_1 + { + const static int ID = 1000; + + struct request + { + std::string example_string_data; + some_test_data sub; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(example_string_data) + KV_SERIALIZE(sub) + END_KV_SERIALIZE_MAP() + }; + + + struct response + { + bool m_success; + std::list subs; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(m_success) + KV_SERIALIZE(subs) + END_KV_SERIALIZE_MAP() + }; + }; + + + + struct COMMAND_EXAMPLE_2 + { + const static int ID = 1001; + + struct request + { + std::string example_string_data2; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(example_string_data2) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + bool m_success; + + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(m_success) + END_KV_SERIALIZE_MAP() + }; + }; + + + //------------------------------------------------------------------------------------- + //------------------------------------------------------------------------------------- + //in debug purpose + bool operator != (const some_test_subdata& a, const some_test_subdata& b) + { + return b.m_str != a.m_str; + } + + bool operator == (const some_test_data& a, const some_test_data& b) + { + if( b.m_str != a.m_str + || b.m_uint64 != a.m_uint64 + || b.m_uint32 != a.m_uint32 + || b.m_uint16 != a.m_uint16 + || b.m_uint8 != a.m_uint8 + || b.m_int64 != a.m_int64 + || b.m_int32 != a.m_int32 + || b.m_int16 != a.m_int16 + || b.m_int8 != a.m_int8 + || b.m_double != a.m_double + || b.m_bool != a.m_bool + || b.m_list_of_str != a.m_list_of_str + || b.m_list_of_uint64_t != a.m_list_of_uint64_t + || b.m_list_of_uint32_t != a.m_list_of_uint32_t + || b.m_list_of_uint16_t != a.m_list_of_uint16_t + || b.m_list_of_uint8_t != a.m_list_of_uint8_t + || b.m_list_of_int64_t != a.m_list_of_int64_t + || b.m_list_of_int32_t != a.m_list_of_int32_t + || b.m_list_of_int16_t != a.m_list_of_int16_t + || b.m_list_of_int8_t != a.m_list_of_int8_t + || b.m_list_of_double != a.m_list_of_double + || b.m_list_of_bool != a.m_list_of_bool + || b.m_subobj != a.m_subobj + || b.m_list_of_self != a.m_list_of_self + || b.m_storage_entry_int.which() != a.m_storage_entry_int.which() + || b.m_storage_entry_string.which() != a.m_storage_entry_string.which() + ) + return false; + return true; + } + + inline some_test_data get_test_data() + { + some_test_data s; + s.m_str = "zuzuzuzuzuz"; + s.m_uint64 = 111111111111111; + s.m_uint32 = 2222222; + s.m_uint16 = 2222; + s.m_uint8 = 22; + s.m_int64 = -111111111111111; + s.m_int32 = -2222222; + s.m_int16 = -2222; + s.m_int8 = -24; + s.m_double = 0.11111; + s.m_bool = true; + s.m_list_of_str.push_back("1112121"); + s.m_list_of_uint64_t.push_back(1111111111); + s.m_list_of_uint64_t.push_back(2222222222); + s.m_list_of_uint32_t.push_back(1111111); + s.m_list_of_uint32_t.push_back(2222222); + s.m_list_of_uint16_t.push_back(1111); + s.m_list_of_uint16_t.push_back(2222); + s.m_list_of_uint8_t.push_back(11); + s.m_list_of_uint8_t.push_back(22); + + + s.m_list_of_int64_t.push_back(-1111111111); + s.m_list_of_int64_t.push_back(-222222222); + s.m_list_of_int32_t.push_back(-1111111); + s.m_list_of_int32_t.push_back(-2222222); + s.m_list_of_int16_t.push_back(-1111); + s.m_list_of_int16_t.push_back(-2222); + s.m_list_of_int8_t.push_back(-11); + s.m_list_of_int8_t.push_back(-22); + + s.m_list_of_double.push_back(0.11111); + s.m_list_of_double.push_back(0.22222); + s.m_list_of_bool.push_back(true); + s.m_list_of_bool.push_back(false); + + s.m_subobj.m_str = "subszzzzzzzz"; + s.m_list_of_self.push_back(s); + s.m_storage_entry_int = epee::serialization::storage_entry(uint64_t(22222));; + s.m_storage_entry_string = epee::serialization::storage_entry(std::string("sdsvsdvs")); + return s; + } +} \ No newline at end of file diff --git a/contrib/epee/include/auto_val_init.h b/contrib/epee/include/auto_val_init.h new file mode 100644 index 00000000..d35f9a04 --- /dev/null +++ b/contrib/epee/include/auto_val_init.h @@ -0,0 +1,34 @@ +// Copyright (c) 2006-2017, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + +#pragma once +#include + + + +#define AUTO_VAL_INIT(v) boost::value_initialized() +#define AUTO_VAL_INIT_T(t) boost::value_initialized() diff --git a/contrib/epee/include/cache_helper.h b/contrib/epee/include/cache_helper.h new file mode 100644 index 00000000..0da21621 --- /dev/null +++ b/contrib/epee/include/cache_helper.h @@ -0,0 +1,260 @@ +// Copyright (c) 2006-2016, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + +#pragma once +#include +#include +#include +#include +#include "boost/optional.hpp" +#include "syncobj.h" +#include "include_base_utils.h" + +namespace epee +{ + namespace misc_utils + { + /************************************************************************/ + /* */ + /************************************************************************/ + template + struct container_selector; + + template + struct container_selector + { + typedef std::map container; + }; + + template + struct container_selector + { + typedef std::unordered_map container; + }; + + + + template + class cache_base + { + uint64_t mac_allowed_elements; + std::list most_recet_acessed; + typename container_selector::iterator> >::container data; + protected: + critical_section m_lock; + public: + + cache_base() : mac_allowed_elements(max_elements) + {} + + size_t size() + { + + return data.size(); + } + + void set_max_elements(uint64_t e) + { + mac_allowed_elements = e; + } + + bool get(const t_key& k, t_value& v) + { + CRITICAL_REGION_LOCAL(m_lock); + auto it = data.find(k); + if (it == data.end()) + return false; + + most_recet_acessed.splice(most_recet_acessed.begin(), most_recet_acessed, it->second.second); + v = it->second.first; + return true; + } + + bool set(const t_key& k, const t_value& v) + { + CRITICAL_REGION_LOCAL(m_lock); + most_recet_acessed.push_front(k); + data[k] = std::pair::iterator>(v, most_recet_acessed.begin()); + + trim(); + return true; + } + + void clear() + { + CRITICAL_REGION_LOCAL(m_lock); + data.clear(); + most_recet_acessed.clear(); + } + + bool erase(const t_key& k) + { + CRITICAL_REGION_LOCAL(m_lock); + auto data_it = data.find(k); + if (data_it == data.end()) + return false; + + most_recet_acessed.erase(data_it->second.second); + data.erase(data_it); + return true; + } + protected: + void trim() + { + CRITICAL_REGION_LOCAL(m_lock); + while (most_recet_acessed.size() > mac_allowed_elements) + { + auto data_it = data.find(most_recet_acessed.back()); + if (data_it != data.end()) + data.erase(data_it); + most_recet_acessed.erase(--most_recet_acessed.end()); + } + } + }; + + class isolation_lock + { + private: + critical_section m_my_lock; + critical_section& m_lock; + boost::optional m_current_writer_thread; + public: + isolation_lock() :m_lock(m_my_lock) + {} + + isolation_lock(critical_section& lock) :m_lock(lock) + {} + + template + res_type isolated_access(callback_t cb) const + { + CRITICAL_REGION_LOCAL(m_lock); + if (m_current_writer_thread.is_initialized()) + { + //has writer + if (std::this_thread::get_id() != m_current_writer_thread.get()) + { + // cache isolated (not allowed) + return cb(false); + } + } + //cache shared(allowed) + return cb(true); + } + + + template + res_type isolated_write_access(callback_t cb) const + { + return isolated_access([&](bool is_allowed_cache) + { + if (!is_allowed_cache) + { + ASSERT_MES_AND_THROW("internal error: writer not allowed while it's not in writer transaction"); + } + return cb(); + }); + } + + void set_isolation_mode() + { + CRITICAL_REGION_LOCAL(m_lock); + CHECK_AND_ASSERT_THROW_MES(!m_current_writer_thread.is_initialized(), "Isolation mode already enabled for cache"); + m_current_writer_thread = std::this_thread::get_id(); + } + + void reset_isolation_mode() + { + CRITICAL_REGION_LOCAL(m_lock); + CHECK_AND_ASSERT_THROW_MES(m_current_writer_thread.is_initialized(), "Isolation mode already disable for cache"); + m_current_writer_thread = boost::optional(); + } + }; + + + template + class cache_with_write_isolation : public cache_base + { + typedef cache_base base_class; + isolation_lock& m_isolation; + public: + cache_with_write_isolation(isolation_lock& isolation) : m_isolation(isolation) + {} + + bool get(const t_key& k, t_value& v) + { + return m_isolation.isolated_access([&](bool allowed_cache) + { + if (allowed_cache) + return base_class::get(k, v); + else + return false; + }); + } + + bool set(const t_key& k, const t_value& v) + { + return m_isolation.isolated_access([&] (bool cache_allowed) + { + if (cache_allowed) + return base_class::set(k, v); + return true; + }); + } + + void clear() + { + m_isolation.isolated_access([&](bool cache_allowed) + { + if (cache_allowed) + base_class::clear(); + return true; + }); + + } + + bool erase(const t_key& k) + { + return m_isolation.isolated_write_access([&](){return base_class::erase(k); }); + } + }; + + template + class cache_dummy : public cache_base + { + typedef cache_base base_class; + isolation_lock& m_isolation; + public: + cache_dummy(isolation_lock& isolation) : m_isolation(isolation){} + bool get(const t_key& k, t_value& v){return false;} + bool set(const t_key& k, const t_value& v){return true;} + void clear(){} + bool erase(const t_key& k){return true;} + }; + + } + +} diff --git a/contrib/epee/include/console_handler.h b/contrib/epee/include/console_handler.h new file mode 100644 index 00000000..ef131696 --- /dev/null +++ b/contrib/epee/include/console_handler.h @@ -0,0 +1,528 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + +#pragma once + +#include +#include +#include +#include +#include + +namespace epee +{ + class async_stdin_reader + { + public: + async_stdin_reader() + : m_run(true) + , m_has_read_request(false) + , m_read_status(state_init) + { + m_reader_thread = std::thread(std::bind(&async_stdin_reader::reader_thread_func, this)); + } + + ~async_stdin_reader() + { + stop(); + } + + // Not thread safe. Only one thread can call this method at once. + bool get_line(std::string& line) + { + if (!start_read()) + return false; + + std::unique_lock lock(m_response_mutex); + while (state_init == m_read_status) + { + m_response_cv.wait(lock); + } + + bool res = false; + if (state_success == m_read_status) + { + line = m_line; + res = true; + } + + m_read_status = state_init; + + return res; + } + + void stop() + { + if (m_run) + { + m_run.store(false, std::memory_order_relaxed); + +#if defined(WIN32) + ::CloseHandle(::GetStdHandle(STD_INPUT_HANDLE)); +#endif + + m_request_cv.notify_one(); + m_reader_thread.join(); + } + } + + private: + bool start_read() + { + std::unique_lock lock(m_request_mutex); + if (!m_run.load(std::memory_order_relaxed) || m_has_read_request) + return false; + + m_has_read_request = true; + m_request_cv.notify_one(); + return true; + } + + bool wait_read() + { + std::unique_lock lock(m_request_mutex); + while (m_run.load(std::memory_order_relaxed) && !m_has_read_request) + { + m_request_cv.wait(lock); + } + + if (m_has_read_request) + { + m_has_read_request = false; + return true; + } + + return false; + } + + bool wait_stdin_data() + { +#if !defined(WIN32) + int stdin_fileno = ::fileno(stdin); + + while (m_run.load(std::memory_order_relaxed)) + { + fd_set read_set; + FD_ZERO(&read_set); + FD_SET(stdin_fileno, &read_set); + + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 100 * 1000; + + int retval = ::select(stdin_fileno + 1, &read_set, NULL, NULL, &tv); + if (retval < 0) + return false; + else if (0 < retval) + return true; + } +#endif + + return true; + } + + void reader_thread_func() + { + while (true) + { + if (!wait_read()) + break; + + std::string line; + bool read_ok = true; + if (wait_stdin_data()) + { + if (m_run.load(std::memory_order_relaxed)) + { + std::getline(std::cin, line); + read_ok = !std::cin.eof() && !std::cin.fail(); + } + } + else + { + read_ok = false; + } + + { + std::unique_lock lock(m_response_mutex); + if (m_run.load(std::memory_order_relaxed)) + { + m_line = std::move(line); + m_read_status = read_ok ? state_success : state_error; + } + else + { + m_read_status = state_cancelled; + } + m_response_cv.notify_one(); + } + } + } + + enum t_state + { + state_init, + state_success, + state_error, + state_cancelled + }; + + private: + std::thread m_reader_thread; + std::atomic m_run; + + std::string m_line; + bool m_has_read_request; + t_state m_read_status; + + std::mutex m_request_mutex; + std::mutex m_response_mutex; + std::condition_variable m_request_cv; + std::condition_variable m_response_cv; + }; + + + template + bool empty_commands_handler(t_server* psrv, const std::string& command) + { + return true; + } + + + class async_console_handler + { + public: + async_console_handler() + { + } + + template + bool run(t_server* psrv, chain_handler ch_handler, const std::string& prompt = "#", const std::string& usage = "") + { + return run(prompt, usage, [&](const std::string& cmd) { return ch_handler(psrv, cmd); }, [&] { psrv->send_stop_signal(); }); + } + + template + bool run(chain_handler ch_handler, const std::string& prompt = "#", const std::string& usage = "") + { + return run(prompt, usage, [&](const std::string& cmd) { return ch_handler(cmd); }, [] { }); + } + + void stop() + { + m_stdin_reader.stop(); + } + + private: + template + bool run(const std::string& prompt, const std::string& usage, const t_cmd_handler& cmd_handler, const t_exit_handler& exit_handler) + { + TRY_ENTRY(); + bool continue_handle = true; + while(continue_handle) + { + if (!prompt.empty()) + { + epee::log_space::set_console_color(epee::log_space::console_color_yellow, true); + std::cout << prompt; + if (' ' != prompt.back()) + std::cout << ' '; + epee::log_space::reset_console_color(); + std::cout.flush(); + } + + std::string command; + if(!m_stdin_reader.get_line(command)) + { + LOG_PRINT("Failed to read line. Stopping...", LOG_LEVEL_0); + continue_handle = false; + break; + } + string_tools::trim(command); + + LOG_PRINT_L2("Read command: " << command); + if(0 == command.compare("exit") || 0 == command.compare("q")) + { + cmd_handler(command); + continue_handle = false; + }else if (!command.compare(0, 7, "set_log")) + { + //parse set_log command + static const std::string command_wrong_syntax = "set_log: wrong syntax, usage: set_log log_level_number | log_channel_name_1,log_channel_name_2,... 0|1"; + std::string args = epee::string_tools::trim(command.substr(7)); + if (args.empty()) + { + std::set& enabled_channels = epee::log_space::log_singletone::get_enabled_channels(); + std::cout << "current log level: " << log_space::get_set_log_detalisation_level() << ", enabled channels: "; + for(auto& channel : enabled_channels) + std::cout << channel << " "; + std::cout << std::endl; + continue; + } + + size_t args_space_pos = args.find(' '); + if (args_space_pos != std::string::npos) + { + // channel enabling / disabling + std::string channel_str = args.substr(0, args_space_pos); + std::string value_str = args.substr(args_space_pos + 1); + if (channel_str.empty() || value_str.empty()) + { + std::cout << command_wrong_syntax << std::endl; + continue; + } + + bool multi_channels = channel_str.find_first_of(",;:") != std::string::npos; + + if (value_str == "1" || value_str == "e" || value_str == "y") + if (multi_channels) + epee::log_space::log_singletone::enable_channels(channel_str); + else + epee::log_space::log_singletone::enable_channel(channel_str); + else + if (multi_channels) + epee::log_space::log_singletone::disable_channels(channel_str); + else + epee::log_space::log_singletone::disable_channel(channel_str); + } + else + { + // log level set + uint16_t n = 0; + if(!string_tools::get_xtype_from_string(n, args)) + { + std::cout << command_wrong_syntax << std::endl; + continue; + } + uint16_t previous_log_level = log_space::get_set_log_detalisation_level(); + log_space::get_set_log_detalisation_level(true, n); + if (n < LOG_LEVEL_2) + std::cout << "log level: " << previous_log_level << " -> " << n << std::endl; + LOG_PRINT_L2("log level: " << previous_log_level << " -> " << n); + } + + if (args.empty()) + { + std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl; + continue; + } + }else if (command.empty()) + { + continue; + } + else if(cmd_handler(command)) + { + continue; + } else + { + std::cout << "unknown command: " << command << std::endl; + std::cout << usage; + } + } + exit_handler(); + return true; + CATCH_ENTRY_L0("console_handler", false); + } + + private: + async_stdin_reader m_stdin_reader; + }; + + + template + bool start_default_console(t_server* ptsrv, t_handler handlr, const std::string& prompt, const std::string& usage = "") + { + std::shared_ptr console_handler = std::make_shared(); + boost::thread([=](){console_handler->run(ptsrv, handlr, prompt, usage);}).detach(); + return true; + } + + template + bool start_default_console(t_server* ptsrv, const std::string& prompt, const std::string& usage = "") + { + return start_default_console(ptsrv, empty_commands_handler, prompt, usage); + } + + template + bool no_srv_param_adapter(t_server* ptsrv, const std::string& cmd, t_handler handlr) + { + return handlr(cmd); + } + + template + bool run_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, const std::string& prompt, const std::string& usage = "") + { + async_console_handler console_handler; + return console_handler.run(ptsrv, boost::bind(no_srv_param_adapter, _1, _2, handlr), prompt, usage); + } + + template + bool start_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, const std::string& prompt, const std::string& usage = "") + { + boost::thread( boost::bind(run_default_console_handler_no_srv_param, ptsrv, handlr, prompt, usage) ); + return true; + } + + /*template + bool f(int i, a l) + { + return true; + }*/ + /* + template + bool default_console_handler2(chain_handler ch_handler, const std::string usage) + */ + + + /*template + bool start_default_console2(t_handler handlr, const std::string& usage = "") + { + //std::string usage_local = usage; + boost::thread( boost::bind(default_console_handler2, handlr, usage) ); + //boost::function p__ = boost::bind(f, 1, handlr); + //boost::function p__ = boost::bind(default_console_handler2, handlr, usage); + //boost::thread tr(p__); + return true; + }*/ + + /************************************************************************/ + /* */ + /************************************************************************/ + class console_handlers_binder + { + typedef boost::function &)> console_command_handler; + typedef std::map > command_handlers_map; + std::unique_ptr m_console_thread; + command_handlers_map m_command_handlers; + async_console_handler m_console_handler; + public: + std::string get_usage() + { + std::stringstream ss; + ss << "Commands: " << ENDL; + size_t max_command_len = 0; + for(auto& x:m_command_handlers) + if(x.first.size() > max_command_len) + max_command_len = x.first.size(); + + for(auto& x:m_command_handlers) + { + ss.width(max_command_len + 3); + ss << " " << std::left << x.first << " " << x.second.second << ENDL; + } + return ss.str(); + } + void set_handler(const std::string& cmd, const console_command_handler& hndlr, const std::string& usage = "") + { + command_handlers_map::mapped_type & vt = m_command_handlers[cmd]; + vt.first = hndlr; + vt.second = usage; + } + bool process_command_vec(const std::vector& cmd) + { + if(!cmd.size()) + return false; + auto it = m_command_handlers.find(cmd.front()); + if(it == m_command_handlers.end()) + return false; + std::vector cmd_local(cmd.begin()+1, cmd.end()); + return it->second.first(cmd_local); + } + + bool process_command_str(const std::string& cmd) + { + std::vector cmd_v; + boost::split(cmd_v,cmd,boost::is_any_of(" "), boost::token_compress_on); + return process_command_vec(cmd_v); + } + + /*template + bool start_handling(t_srv& srv, const std::string& usage_string = "") + { + start_default_console_handler_no_srv_param(&srv, boost::bind(&console_handlers_binder::process_command_str, this, _1)); + return true; + }*/ + + bool start_handling(const std::string& prompt, const std::string& usage_string = "") + { + m_console_thread.reset(new boost::thread(boost::bind(&console_handlers_binder::run_handling, this, prompt, usage_string))); + m_console_thread->detach(); + return true; + } + + void stop_handling() + { + m_console_handler.stop(); + } + + bool run_handling(const std::string& prompt, const std::string& usage_string) + { + return m_console_handler.run(boost::bind(&console_handlers_binder::process_command_str, this, _1), prompt, usage_string); + } + + bool help(const std::vector& /*args*/) + { + std::cout << get_usage() << ENDL; + return true; + } + /*template + bool run_handling(t_srv& srv, const std::string& usage_string) + { + return run_default_console_handler_no_srv_param(&srv, boost::bind(&console_handlers_binder::process_command_str, this, _1), usage_string); + }*/ + }; + + /* work around because of broken boost bind */ + template + class srv_console_handlers_binder: public console_handlers_binder + { + bool process_command_str(t_server* /*psrv*/, const std::string& cmd) + { + return console_handlers_binder::process_command_str(cmd); + } + public: + bool start_handling(t_server* psrv, const std::string& prompt, const std::string& usage_string = "") + { + boost::thread(boost::bind(&srv_console_handlers_binder::run_handling, this, psrv, prompt, usage_string)).detach(); + return true; + } + + bool run_handling(t_server* psrv, const std::string& prompt, const std::string& usage_string) + { + return m_console_handler.run(psrv, boost::bind(&srv_console_handlers_binder::process_command_str, this, _1, _2), prompt, usage_string); + } + + void stop_handling() + { + m_console_handler.stop(); + } + + //-------------------------------------------------------------------------------- + + private: + async_console_handler m_console_handler; + }; +} diff --git a/contrib/epee/include/copyable_atomic.h b/contrib/epee/include/copyable_atomic.h new file mode 100644 index 00000000..6b5691ab --- /dev/null +++ b/contrib/epee/include/copyable_atomic.h @@ -0,0 +1,54 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + +#pragma once + +#include + +namespace epee +{ + class copyable_atomic: public std::atomic + { + public: + copyable_atomic() + {}; + copyable_atomic(const copyable_atomic& a):std::atomic(a.load()) + {} + copyable_atomic& operator= (const copyable_atomic& a) + { + store(a.load()); + return *this; + } + uint32_t operator++() + { + return std::atomic::operator++(); + } + uint32_t operator++(int fake) + { + return std::atomic::operator++(fake); + } + }; +} \ No newline at end of file diff --git a/contrib/epee/include/file_io_utils.h b/contrib/epee/include/file_io_utils.h new file mode 100644 index 00000000..cb4e0a21 --- /dev/null +++ b/contrib/epee/include/file_io_utils.h @@ -0,0 +1,570 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + +#ifndef _FILE_IO_UTILS_H_ +#define _FILE_IO_UTILS_H_ + + +//#include +//#include + +#include +#include +#include + +#ifndef MAKE64 + #define MAKE64(low,high) ((__int64)(((DWORD)(low)) | ((__int64)((DWORD)(high))) << 32)) +#endif + +#ifdef WINDOWS_PLATFORM +#include +#include +#include +#include +#endif + +#ifndef WIN32 +#include +#endif + +#include "include_base_utils.h" + +namespace epee +{ +namespace file_io_utils +{ +#ifdef WINDOWS_PLATFORM + + inline + std::string get_temp_file_name_a() + { + std::string str_result; + char sz_temp[MAX_PATH*2] = {0}; + if(!::GetTempPathA( sizeof( sz_temp ), sz_temp )) + return str_result; + + char sz_temp_file[MAX_PATH*2] = {0}; + if(!::GetTempFileNameA( sz_temp, "mail", 0, sz_temp_file)) + return str_result; + sz_temp_file[sizeof(sz_temp_file)-1] = 0; //be happy! + str_result = sz_temp_file; + return str_result; + } + + +#ifdef BOOST_LEXICAL_CAST_INCLUDED + inline + bool get_not_used_filename(const std::string& folder, OUT std::string& result_name) + { + DWORD folder_attr = ::GetFileAttributesA(folder.c_str()); + if(folder_attr == INVALID_FILE_ATTRIBUTES) + return false; + if(!(folder_attr&FILE_ATTRIBUTE_DIRECTORY)) + return false; + + + std::string base_name = folder + "\\tmp"; + std::string tmp_name; + bool name_found = false; + int current_index = 0; + tmp_name = base_name + boost::lexical_cast(current_index) + ".tmp"; + while(!name_found) + { + if(INVALID_FILE_ATTRIBUTES == ::GetFileAttributesA(tmp_name.c_str())) + name_found = true; + else + { + current_index++; + tmp_name = base_name + boost::lexical_cast(current_index) + ".tmp"; + } + } + result_name = tmp_name; + return true; + } +#endif + + inline + std::string get_temp_folder_a() + { + std::string str_result; + char sz_temp[MAX_PATH*2] = {0}; + if(!::GetTempPathA( sizeof( sz_temp ), sz_temp )) + return str_result; + sz_temp[(sizeof(sz_temp)/sizeof(sz_temp[0])) -1] = 0; + str_result = sz_temp; + return str_result; + } + + std::string convert_from_device_path_to_standart(const std::string& path) + { + + + STRSAFE_LPSTR pszFilename = (STRSAFE_LPSTR)path.c_str(); + + // Translate path with device name to drive letters. + char szTemp[4000] = {0}; + + if (::GetLogicalDriveStringsA(sizeof(szTemp)-1, szTemp)) + { + char szName[MAX_PATH]; + char szDrive[3] = " :"; + BOOL bFound = FALSE; + char* p = szTemp; + + do + { + // Copy the drive letter to the template string + *szDrive = *p; + + // Look up each device name + if (::QueryDosDeviceA(szDrive, szName, sizeof(szName))) + { + UINT uNameLen = strlen(szName); + + if (uNameLen < MAX_PATH) + { + bFound = _mbsnbicmp((const unsigned char*)pszFilename, (const unsigned char*)szName, + uNameLen) == 0; + + if (bFound) + { + // Reconstruct pszFilename using szTempFile + // Replace device path with DOS path + char szTempFile[MAX_PATH] = {0}; + StringCchPrintfA(szTempFile, + MAX_PATH, + "%s%s", + szDrive, + pszFilename+uNameLen); + return szTempFile; + //::StringCchCopyNA(pszFilename, MAX_PATH+1, szTempFile, strlen(szTempFile)); + } + } + } + + // Go to the next NULL character. + while (*p++); + } while (!bFound && *p); // end of string + } + + return ""; + } + + inline + std::string get_process_path_by_pid(DWORD pid) + { + std::string res; + + HANDLE hprocess = 0; + if( hprocess = ::OpenProcess( PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, FALSE, pid) ) + { + char buff[MAX_PATH]= {0}; + if(!::GetModuleFileNameExA( hprocess, 0, buff, MAX_PATH - 1 )) + res = "Unknown_b"; + else + { + buff[MAX_PATH - 1]=0; //be happy! + res = buff; + std::string::size_type a = res.rfind( '\\' ); + if ( a != std::string::npos ) + res.erase( 0, a+1); + + } + ::CloseHandle( hprocess ); + }else + res = "Unknown_a"; + + return res; + } + + + + + + inline + std::wstring get_temp_file_name_w() + { + std::wstring str_result; + wchar_t sz_temp[MAX_PATH*2] = {0}; + if(!::GetTempPathW( sizeof(sz_temp)/sizeof(sz_temp[0]), sz_temp )) + return str_result; + + wchar_t sz_temp_file[MAX_PATH+1] = {0}; + if(!::GetTempFileNameW( sz_temp, L"mail", 0, sz_temp_file)) + return str_result; + + sz_temp_file[(sizeof(sz_temp_file)/sizeof(sz_temp_file[0]))-1] = 0; //be happy! + str_result = sz_temp_file; + return str_result; + } +#endif + + template + bool is_file_exist(const t_string& path) + { + boost::filesystem::path p(path); + return boost::filesystem::exists(p); + } + + /* + inline + bool save_string_to_handle(HANDLE hfile, const std::string& str) + { + + + + if( INVALID_HANDLE_VALUE != hfile ) + { + DWORD dw; + if( !::WriteFile( hfile, str.data(), (DWORD) str.size(), &dw, NULL) ) + { + int err_code = GetLastError(); + //LOG_PRINT("Failed to write to file handle: " << hfile<< " Last error code:" << err_code << " : " << log_space::get_win32_err_descr(err_code), LOG_LEVEL_2); + return false; + } + ::CloseHandle(hfile); + return true; + }else + { + //LOG_WIN32_ERROR(::GetLastError()); + return false; + } + + return false; + }*/ + + + template + bool save_string_to_file_throw(const t_string& path_to_file, const std::string& str) + { + //std::ofstream fstream; + boost::filesystem::ofstream fstream; + fstream.exceptions(std::ifstream::failbit | std::ifstream::badbit); + fstream.open(path_to_file, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc); + fstream << str; + fstream.close(); + return true; + } + + template + bool save_string_to_file(const t_string& path_to_file, const std::string& str) + { + + try + { + return save_string_to_file_throw(path_to_file, str); + } + catch (const std::exception& /*ex*/) + { + return false; + } + + catch(...) + { + return false; + } + } + + /* + inline + bool load_form_handle(HANDLE hfile, std::string& str) + { + if( INVALID_HANDLE_VALUE != hfile ) + { + bool res = true; + DWORD dw = 0; + DWORD fsize = ::GetFileSize(hfile, &dw); + if(fsize > 300000000) + { + ::CloseHandle(hfile); + return false; + } + if(fsize) + { + str.resize(fsize); + if(!::ReadFile( hfile, (LPVOID)str.data(), (DWORD)str.size(), &dw, NULL)) + res = false; + } + ::CloseHandle(hfile); + return res; + } + return false; + } + */ + inline + bool get_file_time(const std::string& path_to_file, OUT time_t& ft) + { + boost::system::error_code ec; + ft = boost::filesystem::last_write_time(boost::filesystem::path(path_to_file), ec); + if(!ec) + return true; + else + return false; + } + + inline + bool set_file_time(const std::string& path_to_file, const time_t& ft) + { + boost::system::error_code ec; + boost::filesystem::last_write_time(boost::filesystem::path(path_to_file), ft, ec); + if(!ec) + return true; + else + return false; + } + + + inline + bool load_file_to_string(const std::string& path_to_file, std::string& target_str) + { + try + { + std::ifstream fstream; + //fstream.exceptions(std::ifstream::failbit | std::ifstream::badbit); + fstream.open(path_to_file, std::ios_base::binary | std::ios_base::in | std::ios::ate); + if (!fstream.good()) + return false; + std::ifstream::pos_type file_size = fstream.tellg(); + + if(file_size > 1000000000) + return false;//don't go crazy + size_t file_size_t = static_cast(file_size); + + target_str.resize(file_size_t); + + fstream.seekg (0, std::ios::beg); + fstream.read((char*)target_str.data(), target_str.size()); + if (!fstream.good()) + return false; + + fstream.close(); + return true; + } + + catch(...) + { + return false; + } + } + +#ifdef WIN32 + typedef HANDLE native_filesystem_handle; +#else + typedef int native_filesystem_handle; +#endif + + inline bool open_and_lock_file(const std::string file_path, native_filesystem_handle& h_file) + { +#ifdef WIN32 + h_file = ::CreateFileA(file_path.c_str(), // name of the write + GENERIC_WRITE, // open for writing + 0, // do not share + NULL, // default security + OPEN_ALWAYS, // create new file only + FILE_ATTRIBUTE_NORMAL, // normal file + NULL); // no attr. template + if (h_file == INVALID_HANDLE_VALUE) + return false; + else + return true; +#else + h_file = open(file_path.c_str(), O_RDWR | O_CREAT, 0666); // open or create lockfile + if (h_file < 0) + return false; + //check open success... + int rc = flock(h_file, LOCK_EX | LOCK_NB); // grab exclusive lock, fail if can't obtain. + if (rc < 0) + { + return false; + } + return true; +#endif + } + + inline bool unlock_and_close_file(native_filesystem_handle& h_file) + { +#ifdef WIN32 + ::CloseHandle(h_file); // no attr. template +#else + flock(h_file, LOCK_UN); // grab exclusive lock, fail if can't obtain. + close(h_file); +#endif + return true; + } + + + inline + bool load_last_n_from_file_to_string(const std::string& path_to_file, uint64_t size_to_load, std::string& target_str) + { + try + { + std::ifstream fstream; + //fstream.exceptions(std::ifstream::failbit | std::ifstream::badbit); + fstream.open(path_to_file, std::ios_base::binary | std::ios_base::in | std::ios::ate); + if (!fstream.good()) + return false; + std::ifstream::pos_type file_size = fstream.tellg(); + + uint64_t size_to_load_to_buff = file_size; + if (static_cast(file_size) > size_to_load) + { + fstream.seekg(size_to_load_to_buff - size_to_load, std::ios::beg); + size_to_load_to_buff = size_to_load; + }else + { + fstream.seekg(0, std::ios::beg); + } + + size_t size_to_load_to_buff_t = static_cast(size_to_load_to_buff); + + target_str.resize(size_to_load_to_buff_t); + + + fstream.read((char*)target_str.data(), target_str.size()); + if (!fstream.good()) + return false; + + fstream.close(); + return true; + } + + catch (...) + { + return false; + } + } + + inline + bool copy_file(const std::string& source, const std::string& destination) + { + boost::system::error_code ec; + boost::filesystem::copy_file(source, destination, ec); + if (ec) + return false; + else + return true; + } + inline + bool append_string_to_file(const std::string& path_to_file, const std::string& str) + { + try + { + std::ofstream fstream; + fstream.exceptions(std::ifstream::failbit | std::ifstream::badbit); + fstream.open(path_to_file.c_str(), std::ios_base::binary | std::ios_base::out | std::ios_base::app); + fstream << str; + fstream.close(); + return true; + } + + catch(...) + { + return false; + } + } + + /* + bool remove_dir_and_subirs(const char* path_to_dir); + + inline + bool clean_dir(const char* path_to_dir) + { + if(!path_to_dir) + return false; + + std::string folder = path_to_dir; + WIN32_FIND_DATAA find_data = {0}; + HANDLE hfind = ::FindFirstFileA((folder + "\\*.*").c_str(), &find_data); + if(INVALID_HANDLE_VALUE == hfind) + return false; + do{ + if(!strcmp("..", find_data.cFileName) || (!strcmp(".", find_data.cFileName))) + continue; + + if(find_data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) + { + if(!remove_dir_and_subirs((folder + "\\" + find_data.cFileName).c_str())) + return false; + }else + { + if(!::DeleteFileA((folder + "\\" + find_data.cFileName).c_str())) + return false; + } + + + }while(::FindNextFileA(hfind, &find_data)); + ::FindClose(hfind); + + return true; + } + */ +#ifdef WINDOWS_PLATFORM + inline bool get_folder_content(const std::string& path, std::list& OUT target_list) + { + WIN32_FIND_DATAA find_data = {0}; + HANDLE hfind = ::FindFirstFileA((path + "\\*.*").c_str(), &find_data); + if(INVALID_HANDLE_VALUE == hfind) + return false; + do{ + if(!strcmp("..", find_data.cFileName) || (!strcmp(".", find_data.cFileName))) + continue; + + target_list.push_back(find_data); + + }while(::FindNextFileA(hfind, &find_data)); + ::FindClose(hfind); + + return true; + } +#endif + inline bool get_folder_content(const std::string& path, std::list& OUT target_list, bool only_files = false) + { + try + { + + boost::filesystem::directory_iterator end_itr; // default construction yields past-the-end + for ( boost::filesystem::directory_iterator itr( path ); itr != end_itr; ++itr ) + { + if ( only_files && boost::filesystem::is_directory(itr->status()) ) + { + continue; + } + target_list.push_back(itr->path().filename().string()); + } + + } + + catch(...) + { + return false; + } + return true; + } +} +} + +#endif //_FILE_IO_UTILS_H_ diff --git a/contrib/epee/include/global_stream_operators.h b/contrib/epee/include/global_stream_operators.h new file mode 100644 index 00000000..6fbdbc2e --- /dev/null +++ b/contrib/epee/include/global_stream_operators.h @@ -0,0 +1,35 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + +#pragma once + +std::stringstream& operator<<(std::stringstream& out, const std::wstring& ws) +{ + std::string as = string_encoding::convert_to_ansii(ws); + out << as; + return out; +} diff --git a/contrib/epee/include/gzip_encoding.h b/contrib/epee/include/gzip_encoding.h new file mode 100644 index 00000000..2be51e77 --- /dev/null +++ b/contrib/epee/include/gzip_encoding.h @@ -0,0 +1,227 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + + +#ifndef _GZIP_ENCODING_H_ +#define _GZIP_ENCODING_H_ +#include "net/http_client_base.h" +#include "zlib/zlib.h" +//#include "http.h" + + +namespace epee +{ +namespace net_utils +{ + + + + class content_encoding_gzip: public i_sub_handler + { + public: + /*! \brief + * Function content_encoding_gzip : Constructor + * + */ + inline + content_encoding_gzip(i_target_handler* powner_filter, bool is_deflate_mode = false):m_powner_filter(powner_filter), + m_is_stream_ended(false), + m_is_deflate_mode(is_deflate_mode), + m_is_first_update_in(true) + { + memset(&m_zstream_in, 0, sizeof(m_zstream_in)); + memset(&m_zstream_out, 0, sizeof(m_zstream_out)); + int ret = 0; + if(is_deflate_mode) + { + ret = inflateInit(&m_zstream_in); + ret = deflateInit(&m_zstream_out, Z_DEFAULT_COMPRESSION); + }else + { + ret = inflateInit2(&m_zstream_in, 0x1F); + ret = deflateInit2(&m_zstream_out, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 0x1F, 8, Z_DEFAULT_STRATEGY); + } + } + /*! \brief + * Function content_encoding_gzip : Destructor + * + */ + inline + ~content_encoding_gzip() + { + inflateEnd(& m_zstream_in ); + deflateEnd(& m_zstream_out ); + } + /*! \brief + * Function update_in : Entry point for income data + * + */ + inline + virtual bool update_in( std::string& piece_of_transfer) + { + + bool is_first_time_here = m_is_first_update_in; + m_is_first_update_in = false; + + if(m_pre_decode.size()) + m_pre_decode += piece_of_transfer; + else + m_pre_decode.swap(piece_of_transfer); + piece_of_transfer.clear(); + + std::string decode_summary_buff; + + size_t ungzip_size = m_pre_decode.size() * 0x30; + std::string current_decode_buff(ungzip_size, 'X'); + + //Here the cycle is introduced where we unpack the buffer, the cycle is required + //because of the case where if after unpacking the data will exceed the awaited size, we will not halt with error + bool continue_unpacking = true; + bool first_step = true; + while(m_pre_decode.size() && continue_unpacking) + { + + //fill buffers + m_zstream_in.next_in = (Bytef*)m_pre_decode.data(); + m_zstream_in.avail_in = (uInt)m_pre_decode.size(); + m_zstream_in.next_out = (Bytef*)current_decode_buff.data(); + m_zstream_in.avail_out = (uInt)ungzip_size; + + int flag = Z_SYNC_FLUSH; + int ret = inflate(&m_zstream_in, flag); + CHECK_AND_ASSERT_MES(ret>=0 || m_zstream_in.avail_out ||m_is_deflate_mode, false, "content_encoding_gzip::update_in() Failed to inflate. err = " << ret); + + if(Z_STREAM_END == ret) + m_is_stream_ended = true; + else if(Z_DATA_ERROR == ret && is_first_time_here && m_is_deflate_mode&& first_step) + { + // some servers (notably Apache with mod_deflate) don't generate zlib headers + // insert a dummy header and try again + static char dummy_head[2] = + { + 0x8 + 0x7 * 0x10, + (((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF, + }; + inflateReset(&m_zstream_in); + m_zstream_in.next_in = (Bytef*) dummy_head; + m_zstream_in.avail_in = sizeof(dummy_head); + + ret = inflate(&m_zstream_in, Z_NO_FLUSH); + if (ret != Z_OK) + { + LOCAL_ASSERT(0); + m_pre_decode.swap(piece_of_transfer); + return false; + } + m_zstream_in.next_in = (Bytef*)m_pre_decode.data(); + m_zstream_in.avail_in = (uInt)m_pre_decode.size(); + + ret = inflate(&m_zstream_in, Z_NO_FLUSH); + if (ret != Z_OK) + { + LOCAL_ASSERT(0); + m_pre_decode.swap(piece_of_transfer); + return false; + } + } + + + //leave only unpacked part in the output buffer to start with it the next time + m_pre_decode.erase(0, m_pre_decode.size()-m_zstream_in.avail_in); + //if decoder gave nothing to return, then everything is ahead, now simply break + if(ungzip_size == m_zstream_in.avail_out) + break; + + //decode_buff currently stores data parts that were unpacked, fix this size + current_decode_buff.resize(ungzip_size - m_zstream_in.avail_out); + if(decode_summary_buff.size()) + decode_summary_buff += current_decode_buff; + else + current_decode_buff.swap(decode_summary_buff); + + current_decode_buff.resize(ungzip_size); + first_step = false; + } + + //Process these data if required + bool res = true; + + res = m_powner_filter->handle_target_data(decode_summary_buff); + + return true; + + } + /*! \brief + * Function stop : Entry point for stop signal and flushing cached data buffer. + * + */ + inline + virtual void stop(std::string& OUT collect_remains) + { + } + protected: + private: + /*! \brief + * Pointer to parent HTTP-parser + */ + i_target_handler* m_powner_filter; + /*! \brief + * ZLIB object for income stream + */ + z_stream m_zstream_in; + /*! \brief + * ZLIB object for outcome stream + */ + z_stream m_zstream_out; + /*! \brief + * Data that could not be unpacked immediately, left to wait for the next packet of data + */ + std::string m_pre_decode; + /*! \brief + * The data are accumulated for a package in the buffer to send the web client + */ + std::string m_pre_encode; + /*! \brief + * Signals that stream looks like ended + */ + bool m_is_stream_ended; + /*! \brief + * If this flag is set, income data is in HTTP-deflate mode + */ + bool m_is_deflate_mode; + /*! \brief + * Marks that it is a first data packet + */ + bool m_is_first_update_in; + }; +} +} + + + +#endif //_GZIP_ENCODING_H_ diff --git a/contrib/epee/include/hmac-md5.h b/contrib/epee/include/hmac-md5.h new file mode 100644 index 00000000..2a4e0d40 --- /dev/null +++ b/contrib/epee/include/hmac-md5.h @@ -0,0 +1,93 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project 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 AUTHORS AND CONTRIBUTORS ``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 AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* hmac-md5.h -- HMAC_MD5 functions + */ + +/* + * $Id: hmac-md5.h,v 1.1.1.1 2005/03/18 20:17:28 zautrix Exp $ + */ + +#ifndef HMAC_MD5_H +#define HMAC_MD5_H 1 + +namespace md5 +{ + + + +#define HMAC_MD5_SIZE 16 + + /* intermediate MD5 context */ + typedef struct HMAC_MD5_CTX_s { + MD5_CTX ictx, octx; + } HMAC_MD5_CTX; + + /* intermediate HMAC state + * values stored in network byte order (Big Endian) + */ + typedef struct HMAC_MD5_STATE_s { + UINT4 istate[4]; + UINT4 ostate[4]; + } HMAC_MD5_STATE; + + /* One step hmac computation + * + * digest may be same as text or key + */ + void hmac_md5(const unsigned char *text, int text_len, + const unsigned char *key, int key_len, + unsigned char digest[HMAC_MD5_SIZE]); + + /* create context from key + */ + void hmac_md5_init(HMAC_MD5_CTX *hmac, + const unsigned char *key, int key_len); + + /* precalculate intermediate state from key + */ + void hmac_md5_precalc(HMAC_MD5_STATE *hmac, + const unsigned char *key, int key_len); + + /* initialize context from intermediate state + */ + void hmac_md5_import(HMAC_MD5_CTX *hmac, HMAC_MD5_STATE *state); + +#define hmac_md5_update(hmac, text, text_len) MD5Update(&(hmac)->ictx, (text), (text_len)) + + /* finish hmac from intermediate result. Intermediate result is zeroed. + */ + void hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE], + HMAC_MD5_CTX *hmac); + +} + +#endif /* HMAC_MD5_H */ diff --git a/contrib/epee/include/include_base_utils.h b/contrib/epee/include/include_base_utils.h new file mode 100644 index 00000000..8412a008 --- /dev/null +++ b/contrib/epee/include/include_base_utils.h @@ -0,0 +1,34 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + +#pragma once + +#define BOOST_FILESYSTEM_VERSION 3 +#define ENABLE_RELEASE_LOGGING + +#include "misc_log_ex.h" + + diff --git a/contrib/epee/include/math_helper.h b/contrib/epee/include/math_helper.h new file mode 100644 index 00000000..3646d050 --- /dev/null +++ b/contrib/epee/include/math_helper.h @@ -0,0 +1,271 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + + +#pragma once + + +#include +#include +#include +#include +#include + +#include "misc_os_dependent.h" + +namespace epee +{ +namespace math_helper +{ + + template + class average + { + public: + + average() + { + m_base = default_base; + } + + bool set_base() + { + CRITICAL_REGION_LOCAL(m_lock); + + m_base = default_base; + if(m_list.size() > m_base) + m_list.resize(m_base); + + return true; + } + + typedef val value_type; + + void push(const value_type& vl) + { + CRITICAL_REGION_LOCAL(m_lock); + +//#ifndef DEBUG_STUB + m_list.push_back(vl); + if(m_list.size() > m_base ) + m_list.pop_front(); +//#endif + } + + double update(const value_type& vl) + { + CRITICAL_REGION_LOCAL(m_lock); +//#ifndef DEBUG_STUB + push(vl); +//#endif + + return get_avg(); + } + + double get_avg() const + { + CRITICAL_REGION_LOCAL( static_cast(m_lock)); + + value_type vl = std::accumulate(m_list.begin(), m_list.end(), value_type(0)); + if(m_list.size()) + return (double)(vl/m_list.size()); + + return (double)vl; + } + + value_type get_last_val() + { + CRITICAL_REGION_LOCAL(m_lock); + if(m_list.size()) + return m_list.back(); + + return 0; + } + + private: + unsigned int m_base; + std::list m_list; + mutable critical_section m_lock; + }; + + +#ifdef WINDOWS_PLATFORM + + /************************************************************************/ + /* */ + /************************************************************************/ + class timing_guard_base + { + public: + virtual ~timing_guard_base(){}; + }; + + template + class timing_guard: public timing_guard_base + { + public: + timing_guard(T& avrg):m_avrg(avrg) + { + m_start_ticks = ::GetTickCount(); + } + + ~timing_guard() + { + m_avrg.push(::GetTickCount()-m_start_ticks); + } + + private: + T& m_avrg; + DWORD m_start_ticks; + }; + + template + timing_guard_base* create_timing_guard(t_timing& timing){return new timing_guard(timing);} + +#define BEGIN_TIMING_ZONE(timing_var) { boost::shared_ptr local_timing_guard_ptr(math_helper::create_timing_guard(timing_var)); +#define END_TIMING_ZONE() } +#endif + +//#ifdef WINDOWS_PLATFORM_EX + template + class speed + { + public: + + speed() + { + m_time_window = default_time_window; + m_last_speed_value = 0; + } + bool chick() + { +#ifndef DEBUG_STUB + uint64_t ticks = misc_utils::get_tick_count(); + CRITICAL_REGION_BEGIN(m_lock); + m_chicks.push_back(ticks); + CRITICAL_REGION_END(); + //flush(ticks); +#endif + return true; + } + + bool chick(size_t count) + { + for(size_t s = 0; s != count; s++) + chick(); + + return true; + } + + + size_t get_speed() + { + flush(misc_utils::get_tick_count()); + return m_last_speed_value = m_chicks.size(); + } + private: + + bool flush(uint64_t ticks) + { + CRITICAL_REGION_BEGIN(m_lock); + std::list::iterator it = m_chicks.begin(); + while(it != m_chicks.end()) + { + if(*it + m_time_window < ticks) + m_chicks.erase(it++); + else + break; + } + CRITICAL_REGION_END(); + return true; + } + + std::list m_chicks; + uint64_t m_time_window; + size_t m_last_speed_value; + critical_section m_lock; + }; +//#endif + + template + void randomize_list(tlist& t_list) + { + for(typename tlist::iterator it = t_list.begin();it!=t_list.end();it++) + { + size_t offset = rand()%t_list.size(); + typename tlist::iterator it_2 = t_list.begin(); + for(size_t local_offset = 0;local_offset!=offset;local_offset++) + it_2++; + if(it_2 == it) + continue; + std::swap(*it_2, *it); + } + + } +PUSH_WARNINGS +DISABLE_GCC_WARNING(strict-aliasing) + inline + uint64_t generated_random_uint64() + { + boost::uuids::uuid id___ = boost::uuids::random_generator()(); + return *reinterpret_cast(&id___.data[0]); //(*reinterpret_cast(&id___.data[0]) ^ *reinterpret_cast(&id___.data[8])); + } +POP_WARNINGS + template + class once_a_time_seconds + { + public: + once_a_time_seconds():m_interval(default_interval) + { + m_last_worked_time = 0; + if(!start_immediate) + time(&m_last_worked_time); + } + + template + bool do_call(functor_t functr) + { + time_t current_time = 0; + time(¤t_time); + + if(current_time - m_last_worked_time > m_interval) + { + bool res = functr(); + time(&m_last_worked_time); + return res; + } + return true; + } + + private: + time_t m_last_worked_time; + time_t m_interval; + }; + +} +} \ No newline at end of file diff --git a/contrib/epee/include/md5_l.h b/contrib/epee/include/md5_l.h new file mode 100644 index 00000000..fe4c67db --- /dev/null +++ b/contrib/epee/include/md5_l.h @@ -0,0 +1,97 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project 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 AUTHORS AND CONTRIBUTORS ``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 AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id: md5.h,v 1.1.1.1 2005/03/18 20:17:27 zautrix Exp $ + */ + +/* MD5.H - header file for MD5C.C + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. +These notices must be retained in any copies of any part of this +documentation and/or software. + */ +#ifndef MD5_H +#define MD5_H + + +#include "md5global.h" + +namespace md5 +{ + /* MD5 context. */ + typedef struct { + UINT4 state[4]; /* state (ABCD) */ + UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ + } MD5_CTX; + + static void MD5Init(MD5_CTX * context); + static void MD5Update( MD5_CTX *context, const unsigned char *input, unsigned int inputLen ); + static void MD5Final ( unsigned char digest[16], MD5_CTX *context ); + static void hmac_md5(const unsigned char* text, int text_len, const unsigned char* key, int key_len, unsigned char *digest); + + + inline bool md5( unsigned char *input, int ilen, unsigned char output[16] ) + { + MD5_CTX ctx; + + MD5Init( &ctx ); + MD5Update( &ctx, input, ilen ); + MD5Final( output, &ctx); + + memset( &ctx, 0, sizeof( MD5_CTX) ); + return true; + } + + +} + +#include "md5_l.inl" + +#endif diff --git a/contrib/epee/include/md5_l.inl b/contrib/epee/include/md5_l.inl new file mode 100644 index 00000000..c3da1a3b --- /dev/null +++ b/contrib/epee/include/md5_l.inl @@ -0,0 +1,563 @@ +/* +* libEtPan! -- a mail stuff library +* +* Copyright (C) 2001, 2005 - DINH Viet Hoa +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* 3. Neither the name of the libEtPan! project 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 AUTHORS AND CONTRIBUTORS ``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 AUTHORS OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +* SUCH DAMAGE. +*/ + +/* +* $Id: md5.c,v 1.1.1.1 2005/03/18 20:17:27 zautrix Exp $ +*/ + +/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm +*/ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. +*/ + +/* do i need all of this just for htonl()? damn. */ +//#include +//#include +//#include +//#include + + + +#include "md5global.h" +#include "md5_l.h" +#include "hmac-md5.h" + +namespace md5 +{ + /* Constants for MD5Transform routine. + */ + +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + + /* + static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64])); + static void Encode PROTO_LIST + ((unsigned char *, UINT4 *, unsigned int)); + static void Decode PROTO_LIST + ((UINT4 *, unsigned char *, unsigned int)); + static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int)); + static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int)); + */ + + static void MD5_memcpy (POINTER output, POINTER input, unsigned int len) + { + unsigned int i; + + for (i = 0; i < len; i++) + output[i] = input[i]; + } + + /* Note: Replace "for loop" with standard memset if possible. + */ + + static void MD5_memset (POINTER output, int value, unsigned int len) + { + unsigned int i; + + for (i = 0; i < len; i++) + ((char *)output)[i] = (char)value; + } + + static void MD5Transform (UINT4 state[4], unsigned char block[64]); + + static unsigned char* PADDING() + { + static unsigned char local_PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + return local_PADDING; + + } + + + + /* F, G, H and I are basic MD5 functions. + + */ +#ifdef I + /* This might be defined via NANA */ +#undef I +#endif + +#define MD5_M_F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define MD5_M_G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define MD5_M_H(x, y, z) ((x) ^ (y) ^ (z)) +#define MD5_M_I(x, y, z) ((y) ^ ((x) | (~z))) + + /* ROTATE_LEFT rotates x left n bits. + + */ + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + + /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. + Rotation is separate from addition to prevent recomputation. + */ + +#define FF(a, b, c, d, x, s, ac) { (a) += MD5_M_F ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); } +#define GG(a, b, c, d, x, s, ac) { (a) += MD5_M_G ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); } +#define HH(a, b, c, d, x, s, ac) { (a) += MD5_M_H ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); } +#define II(a, b, c, d, x, s, ac) { (a) += MD5_M_I ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); } + + /* MD5 initialization. Begins an MD5 operation, writing a new context. + */ + + static void MD5Init(MD5_CTX * context) + { + context->count[0] = context->count[1] = 0; + + /* Load magic initialization constants. + + */ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; + } + + /* MD5 block update operation. Continues an MD5 message-digest + operation, processing another message block, and updating the context. + */ + + static void MD5Update( MD5_CTX *context, const unsigned char *input, unsigned int inputLen ) + { + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += ((UINT4)inputLen << 3)) + < ((UINT4)inputLen << 3)) + context->count[1]++; + context->count[1] += ((UINT4)inputLen >> 29); + + partLen = 64 - index; + + /* Transform as many times as possible. + + */ + if (inputLen >= partLen) + { + MD5_memcpy( (POINTER)&context->buffer[index], (POINTER)input, partLen ); + MD5Transform( context->state, context->buffer ); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform (context->state, (unsigned char*)&input[i]); + + index = 0; + } + else + i = 0; + + /* Buffer remaining input */ + MD5_memcpy( (POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i ); + + } + + /* Encodes input (UINT4) into output (unsigned char). Assumes len is + a multiple of 4. + + */ + + static void Encode (unsigned char *output, UINT4 *input, unsigned int len) + { + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } + } + + /* Decodes input (unsigned char) into output (UINT4). Assumes len is + a multiple of 4. + + */ + + static void Decode (UINT4 *output, unsigned char *input, unsigned int len) + { + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16) + | (((UINT4)input[j+3]) << 24); + } + + /* MD5 finalization. Ends an MD5 message-digest operation, writing the + the message digest and zeroizing the context. + + */ + + static void MD5Final ( unsigned char digest[16], MD5_CTX *context ) + { + unsigned char bits[8]; + unsigned int index, padLen; + + /* Save number of bits */ + Encode (bits, context->count, 8); + + /* Pad out to 56 mod 64. + + */ + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update (context, PADDING(), padLen); + + /* Append length (before padding) */ + MD5Update (context, bits, 8); + + /* Store state in digest */ + Encode (digest, context->state, 16); + + /* Zeroize sensitive information. + + */ + MD5_memset ((POINTER)context, 0, sizeof (*context)); + } + + /* MD5 basic transformation. Transforms state based on block. + + */ + + static void MD5Transform (UINT4 state[4], unsigned char block[64]) + { + UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. + */ + MD5_memset ((POINTER)x, 0, sizeof (x)); + } + + /* Note: Replace "for loop" with standard memcpy if possible. + + */ + inline + void hmac_md5_init(HMAC_MD5_CTX *hmac, + const unsigned char *key, + int key_len) + { + unsigned char k_ipad[65]; /* inner padding - + * key XORd with ipad + */ + unsigned char k_opad[65]; /* outer padding - + * key XORd with opad + */ + unsigned char tk[16]; + int i; + /* if key is longer than 64 bytes reset it to key=MD5(key) */ + if (key_len > 64) { + + MD5_CTX tctx; + + MD5Init(&tctx); + MD5Update(&tctx, key, key_len); + MD5Final(tk, &tctx); + + key = tk; + key_len = 16; + } + + /* + * the HMAC_MD5 transform looks like: + * + * MD5(K XOR opad, MD5(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected + */ + + /* start out by storing key in pads */ + MD5_memset(k_ipad, '\0', sizeof k_ipad); + MD5_memset(k_opad, '\0', sizeof k_opad); + MD5_memcpy( k_ipad, (POINTER)key, key_len); + MD5_memcpy( k_opad, (POINTER)key, key_len); + + /* XOR key with ipad and opad values */ + for (i=0; i<64; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + MD5Init(&hmac->ictx); /* init inner context */ + MD5Update(&hmac->ictx, k_ipad, 64); /* apply inner pad */ + + MD5Init(&hmac->octx); /* init outer context */ + MD5Update(&hmac->octx, k_opad, 64); /* apply outer pad */ + + /* scrub the pads and key context (if used) */ + MD5_memset( (POINTER)&k_ipad, 0, sizeof(k_ipad)); + MD5_memset( (POINTER)&k_opad, 0, sizeof(k_opad)); + MD5_memset( (POINTER)&tk, 0, sizeof(tk)); + + /* and we're done. */ + } + + /* The precalc and import routines here rely on the fact that we pad + * the key out to 64 bytes and use that to initialize the md5 + * contexts, and that updating an md5 context with 64 bytes of data + * leaves nothing left over; all of the interesting state is contained + * in the state field, and none of it is left over in the count and + * buffer fields. So all we have to do is save the state field; we + * can zero the others when we reload it. Which is why the decision + * was made to pad the key out to 64 bytes in the first place. */ + inline + void hmac_md5_precalc(HMAC_MD5_STATE *state, + const unsigned char *key, + int key_len) + { + HMAC_MD5_CTX hmac; + unsigned lupe; + + hmac_md5_init(&hmac, key, key_len); + for (lupe = 0; lupe < 4; lupe++) { + state->istate[lupe] = htonl(hmac.ictx.state[lupe]); + state->ostate[lupe] = htonl(hmac.octx.state[lupe]); + } + MD5_memset( (POINTER)&hmac, 0, sizeof(hmac)); + } + + + inline + void hmac_md5_import(HMAC_MD5_CTX *hmac, + HMAC_MD5_STATE *state) + { + unsigned lupe; + MD5_memset( (POINTER)hmac, 0, sizeof(HMAC_MD5_CTX)); + for (lupe = 0; lupe < 4; lupe++) { + hmac->ictx.state[lupe] = ntohl(state->istate[lupe]); + hmac->octx.state[lupe] = ntohl(state->ostate[lupe]); + } + /* Init the counts to account for our having applied + * 64 bytes of key; this works out to 0x200 (64 << 3; see + * MD5Update above...) */ + hmac->ictx.count[0] = hmac->octx.count[0] = 0x200; + } + + inline + void hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE], + HMAC_MD5_CTX *hmac) + { + MD5Final(digest, &hmac->ictx); /* Finalize inner md5 */ + MD5Update(&hmac->octx, digest, 16); /* Update outer ctx */ + MD5Final(digest, &hmac->octx); /* Finalize outer md5 */ + } + + + void hmac_md5(const unsigned char* text, int text_len, const unsigned char* key, int key_len, unsigned char *digest) + { + MD5_CTX context; + + unsigned char k_ipad[65]; /* inner padding - + * key XORd with ipad + */ + unsigned char k_opad[65]; /* outer padding - + * key XORd with opad + */ + unsigned char tk[16]; + int i; + /* if key is longer than 64 bytes reset it to key=MD5(key) */ + if (key_len > 64) { + + MD5_CTX tctx; + + MD5Init(&tctx); + MD5Update(&tctx, key, key_len); + MD5Final(tk, &tctx); + + key = tk; + key_len = 16; + } + + /* + * the HMAC_MD5 transform looks like: + * + * MD5(K XOR opad, MD5(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected + */ + + /* start out by storing key in pads */ + MD5_memset(k_ipad, '\0', sizeof k_ipad); + MD5_memset(k_opad, '\0', sizeof k_opad); + MD5_memcpy( k_ipad, (POINTER)key, key_len); + MD5_memcpy( k_opad, (POINTER)key, key_len); + + /* XOR key with ipad and opad values */ + for (i=0; i<64; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + /* + * perform inner MD5 + */ + + MD5Init(&context); /* init context for 1st + * pass */ + MD5Update(&context, k_ipad, 64); /* start with inner pad */ + MD5Update(&context, text, text_len); /* then text of datagram */ + MD5Final(digest, &context); /* finish up 1st pass */ + + /* + * perform outer MD5 + */ + MD5Init(&context); /* init context for 2nd + * pass */ + MD5Update(&context, k_opad, 64); /* start with outer pad */ + MD5Update(&context, digest, 16); /* then results of 1st + * hash */ + MD5Final(digest, &context); /* finish up 2nd pass */ + + } +} \ No newline at end of file diff --git a/contrib/epee/include/md5global.h b/contrib/epee/include/md5global.h new file mode 100644 index 00000000..afc22901 --- /dev/null +++ b/contrib/epee/include/md5global.h @@ -0,0 +1,77 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project 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 AUTHORS AND CONTRIBUTORS ``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 AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id: md5global.h,v 1.1.1.1 2005/03/18 20:17:28 zautrix Exp $ + */ + +/* GLOBAL.H - RSAREF types and constants + */ + +#ifndef MD5GLOBAL_H +#define MD5GLOBAL_H + +namespace md5 +{ + + + /* PROTOTYPES should be set to one if and only if the compiler supports + function argument prototyping. + The following makes PROTOTYPES default to 0 if it has not already + been defined with C compiler flags. + */ +#ifndef PROTOTYPES +#define PROTOTYPES 0 +#endif + + /* POINTER defines a generic pointer type */ + typedef unsigned char *POINTER; + + /* UINT2 defines a two byte word */ + typedef unsigned short int UINT2; + + /* UINT4 defines a four byte word */ + //typedef unsigned long int UINT4; + typedef unsigned int UINT4; + + /* PROTO_LIST is defined depending on how PROTOTYPES is defined above. + If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it + returns an empty list. + */ +#if PROTOTYPES +#define PROTO_LIST(list) list +#else +#define PROTO_LIST(list) () +#endif + +} + +#endif diff --git a/contrib/epee/include/misc_language.h b/contrib/epee/include/misc_language.h new file mode 100644 index 00000000..b70052c7 --- /dev/null +++ b/contrib/epee/include/misc_language.h @@ -0,0 +1,432 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#pragma once +#include +#include +#include +#include +#include "include_base_utils.h" +#include "auto_val_init.h" + + +#define MARK_AS_POD_C11(type) \ +namespace std \ +{ \ + template<> \ +struct is_pod< type > \ + { \ + static const bool value = true; \ + }; \ +} + + +namespace epee +{ +#define STD_TRY_BEGIN() try { + +#define STD_TRY_CATCH(where_, ret_val) \ + } \ + catch (const std::exception &e) \ + { \ + LOG_ERROR("EXCEPTION: " << where_ << ", mes: "<< e.what()); \ + return ret_val; \ + } \ + catch (...) \ + { \ + LOG_ERROR("EXCEPTION: " << where_ ); \ + return ret_val; \ + } + + + /* helper class, to make able get namespace via decltype()::*/ + template + class namespace_accessor: public base_class{}; + + +#define STRINGIFY_EXPAND(s) STRINGIFY(s) +#define STRINGIFY(s) #s + + + +namespace misc_utils +{ + template + t_type get_max_t_val(t_type t) + { + return (std::numeric_limits::max)(); + } + + // TEMPLATE STRUCT less + template + struct less_as_pod + : public std::binary_function<_Ty, _Ty, bool> + { // functor for operator< + bool operator()(const _Ty& _Left, const _Ty& _Right) const + { // apply operator< to operands + return memcmp(&_Left, &_Right, sizeof(_Left)) < 0; + } + }; + + template + bool is_less_as_pod(const _Ty& _Left, const _Ty& _Right) + { // apply operator< to operands + return memcmp(&_Left, &_Right, sizeof(_Left)) < 0; + } + + + inline + bool sleep_no_w(long ms ) + { + boost::this_thread::sleep( + boost::get_system_time() + + boost::posix_time::milliseconds( std::max(ms,0) ) ); + + return true; + } + /************************************************************************/ + /* */ + /************************************************************************/ + template + class median_helper + { + typedef std::multiset ordered_items_container; + typedef std::pair queued_item_type; + typedef std::list queued_items_container; + typedef std::list > recent_items_container; + ordered_items_container ordered_items; + queued_items_container queued_items; + recent_items_container recent_items; // this needed to have chance to roll back at least for some depth, so we keep elements removed from median window for a while + bool had_been_in_recent_items; + mutable critical_section m_lock; + + typename ordered_items_container::iterator m_current_median_it; + uint64_t current_index; + + virtual void handle_purge_back_item() {} + virtual void handle_add_front_item(const key& k, const associated_data& ad) {} + virtual void handle_remove_front_item(const key& k) {} + void push_item_as_recent(const key& k, const associated_data& ad) + { + CRITICAL_REGION_LOCAL(m_lock); + auto it = ordered_items.insert(k); + queued_items.push_front(queued_item_type(it, ad)); + } + public: + median_helper() :had_been_in_recent_items(false) + { + m_current_median_it = ordered_items.end(); + current_index = 0; + } + void clear() + { + CRITICAL_REGION_LOCAL(m_lock); + ordered_items.clear(); + queued_items.clear(); + recent_items.clear(); + had_been_in_recent_items = false; + m_current_median_it = ordered_items.end(); + current_index = 0; + } + + void push_item(const key& k, const associated_data& ad) + { + CRITICAL_REGION_LOCAL(m_lock); + auto it = ordered_items.insert(k); + queued_items.push_back(queued_item_type(it, ad)); + handle_add_front_item(k, ad); + } + + void pop_item() + { + CRITICAL_REGION_LOCAL(m_lock); + if (!queued_items.empty()) + { + auto it = queued_items.back().first; + handle_remove_front_item(*it); + ordered_items.erase(it); + queued_items.pop_back(); + } + } + + /* + cb(key, associated_data) - enumerating while result is false + when returned true - clean items behind and move it to recent_items + + cb_final_remove(key, associated_data) - for every element in recent_items if returned false - element removed forever + */ + template + bool scan_items(cb_t cb, cb_t2 cb_final_remove) + { + CRITICAL_REGION_LOCAL(m_lock); + //process median window items + for (auto it = queued_items.begin(); it != queued_items.end(); it++) + { + if (cb(*it->first, it->second)) + { + //stop element, remove all items before this + for (auto clean_it = queued_items.begin(); clean_it != it; clean_it++) + { + //std::pair p(*it->first, it->second); + recent_items.push_back(std::make_pair(*clean_it->first, clean_it->second)); + had_been_in_recent_items = true; + ordered_items.erase(clean_it->first); + } + queued_items.erase(queued_items.begin(), it); + break; + } + } + //process recent items front part (put back to median window set if needed) + for (auto it = recent_items.rbegin(); it != recent_items.rend();) + { + if (!cb(it->first, it->second)) + break;//element should stay in recent + + //element should be back to median window + this->push_item_as_recent(it->first, it->second); + it = typename recent_items_container::reverse_iterator(recent_items.erase((++it).base())); // remove *it and advance 'it' by 1 + } + + + //process recent items back part (remove outdated elements) + while (recent_items.size() && !cb_final_remove(recent_items.begin()->first, recent_items.begin()->second)) + { + recent_items.erase(recent_items.begin()); + handle_purge_back_item(); + } + + //detect if recent_items exhausted + if (!recent_items.size() && had_been_in_recent_items) + { + LOG_PRINT_RED_L0("[MEDIAN_HELPER]: recent_items exhausted, need to rebuild median from scratch"); + return false; + } + return true; + } + + uint64_t get_median() const + { + CRITICAL_REGION_LOCAL(m_lock); + if (!ordered_items.size()) + return 0; + + size_t n = ordered_items.size() / 2; + //std::sort(v.begin(), v.end()); + + auto n_it = std::next(ordered_items.begin(), n); + + //nth_element(v.begin(), v.begin()+n-1, v.end()); + if (ordered_items.size() % 2) + {//1, 3, 5... + return *n_it; + } + else + {//2, 4, 6... + auto n_it_sub = n_it; + --n_it_sub; + return (*n_it_sub + *n_it) / 2; + } + } + + template + friend std::ostream & operator<< (std::ostream &out, median_helper const &mh); + }; // class median_helper + + template + std::ostream & operator<< (std::ostream &s, median_helper const &mh) + { + s << "median_helper<" << typeid(key_t).name() << ", " << typeid(associated_data_t).name() << "> instance 0x" << &mh << ENDL + << " ordered_items: " << mh.ordered_items.size() << ENDL + << " queued_items: " << mh.queued_items.size() << ENDL + << " recent_items: " << mh.recent_items.size() << ENDL + << " had_been_in_recent_items: " << mh.had_been_in_recent_items << ENDL; + return s; + } + + /************************************************************************/ + /* */ + /************************************************************************/ + template + type_vec_type median(std::vector &v) + { + //CRITICAL_REGION_LOCAL(m_lock); + if(v.empty()) + return boost::value_initialized(); + if(v.size() == 1) + return v[0]; + + size_t n = (v.size()) / 2; + std::sort(v.begin(), v.end()); + //nth_element(v.begin(), v.begin()+n-1, v.end()); + if(v.size()%2) + {//1, 3, 5... + return v[n]; + }else + {//2, 4, 6... + return (v[n-1] + v[n])/2; + } + + } + + /************************************************************************/ + /* */ + /************************************************************************/ + + struct call_befor_die_base + { + virtual ~call_befor_die_base(){} + }; + + typedef boost::shared_ptr auto_scope_leave_caller; + + + template + struct call_befor_die: public call_befor_die_base + { + t_scope_leave_handler m_func; + call_befor_die(t_scope_leave_handler f):m_func(f) + {} + ~call_befor_die() + { + m_func(); + } + }; + + template + auto_scope_leave_caller create_scope_leave_handler(t_scope_leave_handler f) + { + auto_scope_leave_caller slc(new call_befor_die(f)); + return slc; + } + + +#define ON_EXIT misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler + + + template< typename t_contaner, typename t_redicate> + void erase_if( t_contaner& items, const t_redicate& predicate ) + { + for(auto it = items.begin(); it != items.end(); ) + { + if( predicate(*it) ) + it = items.erase(it); + else + ++it; + } + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + struct call_basic + { + virtual void do_call(){}; + }; + + + template + struct call_specific: public call_basic + { + call_specific(t_callback cb):m_cb(cb) + {} + virtual void do_call() + { + m_cb(); + } + private: + t_callback m_cb; + }; + + template + auto build_abstract_callback(t_callback cb) -> std::shared_ptr + { + return std::shared_ptr(new call_specific(cb)); + } + + + + template + bool static_initializer(callback_type cb) + { + return cb(); + }; + + + template + typename t_container_type::mapped_type& get_or_insert_value_initialized(t_container_type& container, const typename t_container_type::key_type& key) + { + auto it = container.find(key); + if (it != container.end()) + { + return it->second; + } + + auto res = container.insert(typename t_container_type::value_type(key, AUTO_VAL_INIT(typename t_container_type::mapped_type()))); + return res.first->second; + } +} +} + +template +std::ostream& print_container_content(std::ostream& out, const T& v); + +template +std::ostream& operator<< (std::ostream& out, const std::vector& v) +{ + return print_container_content(out, v); +} +template +std::ostream& operator<< (std::ostream& out, const std::list& v) +{ + return print_container_content(out, v); +} + +template +std::ostream& print_container_content(std::ostream& out, const T& v) +{ + + out << "["; + if (!v.size()) + { + out << "]"; + return out; + } + + typename T::const_iterator last_it = --v.end(); + + for (typename T::const_iterator it = v.begin(); it != v.end(); it++) + { + out << *it; + if (it != last_it) + out << ", "; + } + out << "]"; + return out; +} + + diff --git a/contrib/epee/include/misc_log_ex.h b/contrib/epee/include/misc_log_ex.h new file mode 100644 index 00000000..c74378fc --- /dev/null +++ b/contrib/epee/include/misc_log_ex.h @@ -0,0 +1,1702 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + +#ifndef _MISC_LOG_EX_H_ +#define _MISC_LOG_EX_H_ + +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef Q_MOC_RUN +#include +#include +#include +#include +#endif +#if defined(WIN32) +#include +#else +#include +#endif +#include "os_defenitions.h" +#include "warnings.h" +PUSH_WARNINGS +DISABLE_VS_WARNINGS(4100) + + +#include "static_initializer.h" +#include "string_tools.h" +#include "time_helper.h" +#include "misc_os_dependent.h" + +#include "syncobj.h" +#include "sync_locked_object.h" + + +#define LOG_LEVEL_SILENT -1 +#define LOG_LEVEL_0 0 +#define LOG_LEVEL_1 1 +#define LOG_LEVEL_2 2 +#define LOG_LEVEL_3 3 +#define LOG_LEVEL_4 4 +#define LOG_LEVEL_MIN LOG_LEVEL_SILENT +#define LOG_LEVEL_MAX LOG_LEVEL_4 + + +#define LOGGER_NULL 0 +#define LOGGER_FILE 1 +#define LOGGER_DEBUGGER 2 +#define LOGGER_CONSOLE 3 +#define LOGGER_DUMP 4 + +#define LOG_JOURNAL_MAX_ELEMENTS 100 + +#ifdef _DEBUG + #define _ASSERTE__(expr) if(!expr) {__debugbreak();} +#else + #define _ASSERTE__(expr) +#endif + + +#ifndef LOCAL_ASSERT + #include + #if (defined _MSC_VER) + #define LOCAL_ASSERT(expr) {if(epee::debug::get_set_enable_assert()){_ASSERTE__(expr);}} + #define FORCE_ASSERT(expr) { _ASSERTE(expr); } + #else + #define LOCAL_ASSERT(expr) + #define FORCE_ASSERT(expr) + #endif +#endif + + +#define COMBINE1(X,Y) X##Y // helper macro +#define COMBINE(X,Y) COMBINE1(X,Y) +#define _STR(X) #X +#define STR(X) _STR(X) + +#if defined(_MSC_VER) +#define LOCAL_FUNCTION_DEF__ __FUNCTION__ +#define UNUSED_ATTRIBUTE +#else +#define LOCAL_FUNCTION_DEF__ __PRETTY_FUNCTION__ +#define UNUSED_ATTRIBUTE __attribute__((unused)) +#endif + +#define LOCATION_SS "[" << LOCAL_FUNCTION_DEF__ << ("] @ " __FILE__ ":" STR(__LINE__)) + + +namespace epee +{ +namespace debug +{ + inline bool get_set_enable_assert(bool set = false, bool v = false) + { + static bool e = true; + if(set) + e = v; + return e; + } +} +namespace log_space +{ + class logger; + class log_message; + class log_singletone; + + /************************************************************************/ + /* */ + /************************************************************************/ + enum console_colors + { + console_color_default, + console_color_white, + console_color_red, + console_color_green, + console_color_blue, + console_color_cyan, + console_color_magenta, + console_color_yellow + }; + + + struct ibase_log_stream + { + ibase_log_stream(){} + virtual ~ibase_log_stream(){} + virtual bool out_buffer( const char* buffer, int buffer_len , int log_level, int color, const char* plog_name = NULL)=0; + virtual int get_type(){return 0;} + + virtual bool set_max_logfile_size(uint64_t max_size){return true;}; + virtual bool set_log_rotate_cmd(const std::string& cmd){return true;}; + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + /*struct ibase_log_value + { + public: + virtual void debug_out( std::stringstream* p_stream)const = 0; + };*/ + + /************************************************************************/ + /* */ + /************************************************************************/ + /*class log_message: public std::stringstream + { + public: + log_message(const log_message& lm): std::stringstream(), std::stringstream::basic_ios() + {} + log_message(){} + + template + log_message& operator<< (T t) + { + std::stringstream* pstrstr = this; + (*pstrstr) << t; + + return *this; + } + }; + inline + log_space::log_message& operator<<(log_space::log_message& sstream, const ibase_log_value& log_val) + { + log_val.debug_out(&sstream); + return sstream; + } + */ + /************************************************************************/ + /* */ + /************************************************************************/ +#define CONSOLE_DEFAULT_STREAM std::cout + + + struct delete_ptr + { + template + void operator() (P p) + { + delete p.first; + } + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + //------------------------------------------------------------------------ +#define max_dbg_str_len 80 +#ifdef _MSC_VER + class debug_output_stream: public ibase_log_stream + { + virtual bool out_buffer( const char* buffer, int buffer_len , int log_level, int color, const char* plog_name = NULL) + { + for ( int i = 0; i < buffer_len; i = i + max_dbg_str_len ) + { + std::string s( buffer + i, buffer_len- i < max_dbg_str_len ? + buffer_len - i : max_dbg_str_len ); + + ::OutputDebugStringA( s.c_str() ); + } + return true; + } + + }; +#endif + + inline bool is_stdout_a_tty() + { + static std::atomic initialized(false); + static std::atomic is_a_tty(false); + + if (!initialized.load(std::memory_order_acquire)) + { +#if defined(WIN32) + is_a_tty.store(0 != _isatty(_fileno(stdout)), std::memory_order_relaxed); +#else + is_a_tty.store(0 != isatty(fileno(stdout)), std::memory_order_relaxed); +#endif + initialized.store(true, std::memory_order_release); + } + + return is_a_tty.load(std::memory_order_relaxed); + } + + inline void set_console_color(int color, bool bright) + { + if (!is_stdout_a_tty()) + return; + + switch(color) + { + case console_color_default: + { +#ifdef WIN32 + HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE| (bright ? FOREGROUND_INTENSITY:0)); +#else + if(bright) + CONSOLE_DEFAULT_STREAM << "\033[1;37m"; + else + CONSOLE_DEFAULT_STREAM << "\033[0m"; +#endif + } + break; + case console_color_white: + { +#ifdef WIN32 + HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | (bright ? FOREGROUND_INTENSITY:0)); +#else + if(bright) + CONSOLE_DEFAULT_STREAM << "\033[1;37m"; + else + CONSOLE_DEFAULT_STREAM << "\033[0;37m"; +#endif + } + break; + case console_color_red: + { +#ifdef WIN32 + HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | (bright ? FOREGROUND_INTENSITY:0)); +#else + if(bright) + CONSOLE_DEFAULT_STREAM << "\033[1;31m"; + else + CONSOLE_DEFAULT_STREAM << "\033[0;31m"; +#endif + } + break; + case console_color_green: + { +#ifdef WIN32 + HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleTextAttribute(h_stdout, FOREGROUND_GREEN | (bright ? FOREGROUND_INTENSITY:0)); +#else + if(bright) + CONSOLE_DEFAULT_STREAM << "\033[1;32m"; + else + CONSOLE_DEFAULT_STREAM << "\033[0;32m"; +#endif + } + break; + + case console_color_blue: + { +#ifdef WIN32 + HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleTextAttribute(h_stdout, FOREGROUND_BLUE | FOREGROUND_INTENSITY);//(bright ? FOREGROUND_INTENSITY:0)); +#else + if(bright) + CONSOLE_DEFAULT_STREAM << "\033[1;34m"; + else + CONSOLE_DEFAULT_STREAM << "\033[0;34m"; +#endif + } + break; + + case console_color_cyan: + { +#ifdef WIN32 + HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleTextAttribute(h_stdout, FOREGROUND_GREEN | FOREGROUND_BLUE | (bright ? FOREGROUND_INTENSITY:0)); +#else + if(bright) + CONSOLE_DEFAULT_STREAM << "\033[1;36m"; + else + CONSOLE_DEFAULT_STREAM << "\033[0;36m"; +#endif + } + break; + + case console_color_magenta: + { +#ifdef WIN32 + HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleTextAttribute(h_stdout, FOREGROUND_BLUE | FOREGROUND_RED | (bright ? FOREGROUND_INTENSITY:0)); +#else + if(bright) + CONSOLE_DEFAULT_STREAM << "\033[1;35m"; + else + CONSOLE_DEFAULT_STREAM << "\033[0;35m"; +#endif + } + break; + + case console_color_yellow: + { +#ifdef WIN32 + HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_GREEN | (bright ? FOREGROUND_INTENSITY:0)); +#else + if(bright) + CONSOLE_DEFAULT_STREAM << "\033[1;33m"; + else + CONSOLE_DEFAULT_STREAM << "\033[0;33m"; +#endif + } + break; + + } + } + + inline void reset_console_color() { + if (!is_stdout_a_tty()) + return; + +#ifdef WIN32 + HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); +#else + CONSOLE_DEFAULT_STREAM << "\033[0m"; + CONSOLE_DEFAULT_STREAM.flush(); +#endif + } + + class console_output_stream: public ibase_log_stream + { +#ifdef _MSC_VER + bool m_have_to_kill_console; +#endif + + public: + console_output_stream() + { +#ifdef _MSC_VER + + if(!::GetStdHandle(STD_OUTPUT_HANDLE)) + m_have_to_kill_console = true; + else + m_have_to_kill_console = false; + + ::AllocConsole(); + freopen("CONOUT$", "w", stdout); + std::cout.clear(); +#endif + } + + ~console_output_stream() + { +#ifdef _MSC_VER + if(m_have_to_kill_console) + ::FreeConsole(); +#endif + } + int get_type(){return LOGGER_CONSOLE;} + + + + virtual bool out_buffer( const char* buffer, int buffer_len , int log_level, int color, const char* plog_name = NULL) + { + if(plog_name) + return true; //skip alternative logs from console + + set_console_color(color, log_level < 1); + +#ifdef _MSC_VER + const char* ptarget_buf = NULL; + char* pallocated_buf = NULL; + + // + int i = 0; + for(; i < buffer_len; i++) + if(buffer[i] == '\a') break; + if(i == buffer_len) + ptarget_buf = buffer; + else + { + pallocated_buf = new char[buffer_len]; + ptarget_buf = pallocated_buf; + for(i = 0; i < buffer_len; i++) + { + if(buffer[i] == '\a') + pallocated_buf[i] = '^'; + else + pallocated_buf[i] = buffer[i]; + } + } + + //uint32_t b = 0; + //::WriteConsoleA(::GetStdHandle(STD_OUTPUT_HANDLE), ptarget_buf, buffer_len, (DWORD*)&b, 0); + CONSOLE_DEFAULT_STREAM << ptarget_buf; + if(pallocated_buf) delete [] pallocated_buf; +#else + std::string buf(buffer, buffer_len); + for(size_t i = 0; i!= buf.size(); i++) + { + if(buf[i] == 7 || buf[i] == -107) + buf[i] = '^'; + } + + CONSOLE_DEFAULT_STREAM << buf; +#endif + reset_console_color(); + return true; + } + + + }; + + inline bool rotate_log_file(const char* pfile_path) + { +#ifdef _MSC_VER + if(!pfile_path) + return false; + + std::string file_path = pfile_path; + std::string::size_type a = file_path .rfind('.'); + if ( a != std::string::npos ) + file_path .erase( a, file_path .size()); + + ::DeleteFileA( (file_path + ".0").c_str() ); + ::MoveFileA( (file_path + ".log").c_str(), (file_path + ".0").c_str() ); +#else + return false;//not implemented yet +#endif + return true; + } + + + + + //--------------------------------------------------------------------------// + class file_output_stream : public ibase_log_stream + { + public: + typedef std::map named_log_streams; + + file_output_stream( std::string default_log_file_name, std::string log_path ) + { + m_default_log_filename = default_log_file_name; + m_max_logfile_size = 0; + m_default_log_path = log_path; + m_pdefault_file_stream = add_new_stream_and_open(default_log_file_name.c_str()); + } + + ~file_output_stream() + { + for(named_log_streams::iterator it = m_log_file_names.begin(); it!=m_log_file_names.end(); it++) + { + if ( it->second->is_open() ) + { + it->second->flush(); + it->second->close(); + } + delete it->second; + } + } + private: + named_log_streams m_log_file_names; + std::string m_default_log_path; + std::ofstream* m_pdefault_file_stream; + std::string m_log_rotate_cmd; + std::string m_default_log_filename; + uint64_t m_max_logfile_size; + + + std::ofstream* add_new_stream_and_open(const char* pstream_name) + { + //log_space::rotate_log_file((m_default_log_path + "\\" + pstream_name).c_str()); + boost::system::error_code ec; + boost::filesystem::create_directories(m_default_log_path, ec); + std::ofstream* pstream = (m_log_file_names[pstream_name] = new std::ofstream); + std::string target_path = m_default_log_path + "/" + pstream_name; + pstream->open( target_path.c_str(), std::ios_base::out | std::ios::app /*ios_base::trunc */); + if(pstream->fail()) + return NULL; + return pstream; + } + + bool set_max_logfile_size(uint64_t max_size) + { + m_max_logfile_size = max_size; + return true; + } + + bool set_log_rotate_cmd(const std::string& cmd) + { + m_log_rotate_cmd = cmd; + return true; + } + + + + virtual bool out_buffer( const char* buffer, int buffer_len, int log_level, int color, const char* plog_name = NULL ) + { + std::ofstream* m_target_file_stream = m_pdefault_file_stream; + if(plog_name) + { //find named stream + named_log_streams::iterator it = m_log_file_names.find(plog_name); + if(it == m_log_file_names.end()) + m_target_file_stream = add_new_stream_and_open(plog_name); + else + m_target_file_stream = it->second; + } + if(!m_target_file_stream || !m_target_file_stream->is_open()) + return false;//TODO: add assert here + + m_target_file_stream->write(buffer, buffer_len ); + m_target_file_stream->flush(); + + if(m_max_logfile_size) + { + std::ofstream::pos_type pt = m_target_file_stream->tellp(); + uint64_t current_sz = pt; + if(current_sz > m_max_logfile_size) + { + CONSOLE_DEFAULT_STREAM << "current_sz= " << current_sz << " m_max_logfile_size= " << m_max_logfile_size << std::endl; + std::string log_file_name; + if(!plog_name) + log_file_name = m_default_log_filename; + else + log_file_name = plog_name; + + m_target_file_stream->close(); + std::string new_log_file_name = log_file_name; + + time_t tm = 0; + time(&tm); + + int err_count = 0; + boost::system::error_code ec; + do + { + new_log_file_name = string_tools::cut_off_extension(log_file_name); + if(err_count) + new_log_file_name += misc_utils::get_time_str_v2(tm) + "(" + boost::lexical_cast(err_count) + ")" + ".log"; + else + new_log_file_name += misc_utils::get_time_str_v2(tm) + ".log"; + + err_count++; + }while(boost::filesystem::exists(m_default_log_path + "/" + new_log_file_name, ec)); + + std::string new_log_file_path = m_default_log_path + "/" + new_log_file_name; + boost::filesystem::rename(m_default_log_path + "/" + log_file_name, new_log_file_path, ec); + if(ec) + { + CONSOLE_DEFAULT_STREAM << "Filed to rename, ec = " << ec.message() << std::endl; + } + + if(m_log_rotate_cmd.size()) + { + + std::string m_log_rotate_cmd_local_copy = m_log_rotate_cmd; + //boost::replace_all(m_log_rotate_cmd, "[*SOURCE*]", new_log_file_path); + boost::replace_all(m_log_rotate_cmd_local_copy, "[*TARGET*]", new_log_file_path); + + misc_utils::call_sys_cmd(m_log_rotate_cmd_local_copy); + } + + m_target_file_stream->open( (m_default_log_path + "/" + log_file_name).c_str(), std::ios_base::out | std::ios::app /*ios_base::trunc */); + if(m_target_file_stream->fail()) + return false; + } + } + + return true; + } + int get_type(){return LOGGER_FILE;} + }; + /************************************************************************/ + /* */ + /************************************************************************/ + class log_stream_splitter + { + public: + typedef std::list > streams_container; + + log_stream_splitter(){} + ~log_stream_splitter() + { + //free pointers + std::for_each(m_log_streams.begin(), m_log_streams.end(), delete_ptr()); + } + + bool set_max_logfile_size(uint64_t max_size) + { + for(streams_container::iterator it = m_log_streams.begin(); it!=m_log_streams.end();it++) + it->first->set_max_logfile_size(max_size); + return true; + } + + bool set_log_rotate_cmd(const std::string& cmd) + { + for(streams_container::iterator it = m_log_streams.begin(); it!=m_log_streams.end();it++) + it->first->set_log_rotate_cmd(cmd); + return true; + } + + bool do_log_message(const std::string& rlog_mes, int log_level, int color, const char* plog_name = NULL) + { + std::string str_mess = rlog_mes; + size_t str_len = str_mess.size(); + const char* pstr = str_mess.c_str(); + for(streams_container::iterator it = m_log_streams.begin(); it!=m_log_streams.end();it++) + if(it->second >= log_level) + it->first->out_buffer(pstr, (int)str_len, log_level, color, plog_name); + return true; + } + + std::string get_log_file_path() + { + return m_default_log_file_path; + } + + bool add_logger( int type, const char* pdefault_file_name, const char* pdefault_log_folder, int log_level_limit = LOG_LEVEL_4 ) + { + ibase_log_stream* ls = NULL; + + switch( type ) + { + case LOGGER_FILE: + m_default_log_file_path = std::string(pdefault_log_folder) + "/" + pdefault_file_name; + ls = new file_output_stream( pdefault_file_name, pdefault_log_folder ); + break; + + case LOGGER_DEBUGGER: +#ifdef _MSC_VER + ls = new debug_output_stream( ); +#else + return false;//not implemented yet +#endif + break; + case LOGGER_CONSOLE: + ls = new console_output_stream( ); + break; + } + + if ( ls ) { + m_log_streams.push_back(streams_container::value_type(ls, log_level_limit)); + return true; + } + return ls ? true:false; + } + bool add_logger( ibase_log_stream* pstream, int log_level_limit = LOG_LEVEL_4 ) + { + m_log_streams.push_back(streams_container::value_type(pstream, log_level_limit) ); + return true; + } + + bool remove_logger(int type) + { + streams_container::iterator it = m_log_streams.begin(); + for(;it!=m_log_streams.end(); it++) + { + if(it->first->get_type() == type) + { + delete it->first; + m_log_streams.erase(it); + return true; + } + } + return false; + + } + + protected: + private: + + streams_container m_log_streams; + std::string m_default_log_file_path; + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + inline int get_set_log_detalisation_level(bool is_need_set = false, int log_level_to_set = LOG_LEVEL_1); + inline int get_set_time_level(bool is_need_set = false, int time_log_level = LOG_LEVEL_0); + inline bool get_set_need_thread_id(bool is_need_set = false, bool is_need_val = false); + inline bool get_set_need_proc_name(bool is_need_set = false, bool is_need_val = false); + + typedef std::map channels_err_stat_container_type; + inline epee::locked_object_proxy get_channels_errors_stat_container() + { + static std::recursive_mutex cs; + static channels_err_stat_container_type errors_by_channel; + epee::locked_object_proxy res(errors_by_channel, cs); + return res; + } + + inline void increase_error_count(const char* channel) + { + auto ch_container = get_channels_errors_stat_container(); + std::string ch_name = channel ? channel : ""; + uint64_t& r = (*ch_container)[ch_name]; + r++; + } + + inline std::string get_daytime_string2() + { + boost::posix_time::ptime p = boost::posix_time::microsec_clock::local_time(); + return misc_utils::get_time_str_v3(p); + } + inline std::string get_day_time_string() + { + return get_daytime_string2(); + //time_t tm = 0; + //time(&tm); + //return misc_utils::get_time_str(tm); + } + + inline std::string get_time_string() + { + return get_daytime_string2(); + + } +#ifdef _MSC_VER + inline std::string get_time_string_adv(SYSTEMTIME* pst = NULL) + { + SYSTEMTIME st = {0}; + if(!pst) + { + pst = &st; + GetSystemTime(&st); + } + std::stringstream str_str; + str_str.fill('0'); + str_str << std::setw(2) << pst->wHour << "_" + << std::setw(2) << pst->wMinute << "_" + << std::setw(2) << pst->wSecond << "_" + << std::setw(3) << pst->wMilliseconds; + return str_str.str(); + } +#endif + + + + + + class logger + { + public: + friend class log_singletone; + + logger() + { + FAST_CRITICAL_REGION_BEGIN(m_critical_sec); + init(); + FAST_CRITICAL_REGION_END(); + } + ~logger() + { + } + + bool set_max_logfile_size(uint64_t max_size) + { + FAST_CRITICAL_REGION_BEGIN(m_critical_sec); + m_log_target.set_max_logfile_size(max_size); + FAST_CRITICAL_REGION_END(); + return true; + } + + bool set_log_rotate_cmd(const std::string& cmd) + { + FAST_CRITICAL_REGION_BEGIN(m_critical_sec); + m_log_target.set_log_rotate_cmd(cmd); + FAST_CRITICAL_REGION_END(); + return true; + } + + bool take_away_journal(std::list& journal) + { + FAST_CRITICAL_REGION_BEGIN(m_critical_sec); + m_journal.swap(journal); + FAST_CRITICAL_REGION_END(); + return true; + } + + bool get_journal_items(std::list& journal, size_t count) + { + FAST_CRITICAL_REGION_BEGIN(m_critical_sec); + size_t i = 0; + for (auto it = m_journal.rbegin(); it != m_journal.rend() && i!= count; it++, i++) + { + journal.push_front(*it); + } + FAST_CRITICAL_REGION_END(); + return true; + } + bool do_log_message(const std::string& rlog_mes, int log_level, int color, bool add_to_journal = false, const char* plog_name = NULL) + { + FAST_CRITICAL_REGION_BEGIN(m_critical_sec); + m_log_target.do_log_message(rlog_mes, log_level, color, plog_name); + if (add_to_journal) + { + m_journal.push_back(rlog_mes); + if (m_journal.size() > m_journal_max_elements) + m_journal.pop_front(); + } + + return true; + FAST_CRITICAL_REGION_END(); + } + + bool add_logger( int type, const char* pdefault_file_name, const char* pdefault_log_folder , int log_level_limit = LOG_LEVEL_4) + { + FAST_CRITICAL_REGION_BEGIN(m_critical_sec); + return m_log_target.add_logger( type, pdefault_file_name, pdefault_log_folder, log_level_limit); + FAST_CRITICAL_REGION_END(); + } + bool add_logger( ibase_log_stream* pstream, int log_level_limit = LOG_LEVEL_4) + { + FAST_CRITICAL_REGION_BEGIN(m_critical_sec); + return m_log_target.add_logger(pstream, log_level_limit); + FAST_CRITICAL_REGION_END(); + } + + bool remove_logger(int type) + { + FAST_CRITICAL_REGION_BEGIN(m_critical_sec); + return m_log_target.remove_logger(type); + FAST_CRITICAL_REGION_END(); + } + + + bool set_thread_prefix(const std::string& prefix) + { + FAST_CRITICAL_REGION_BEGIN(m_critical_sec); + m_thr_prefix_strings[misc_utils::get_thread_string_id()] = prefix; + FAST_CRITICAL_REGION_END(); + return true; + } + + std::string get_thread_prefix() + { + FAST_CRITICAL_REGION_LOCAL(m_critical_sec); + return m_thr_prefix_strings[misc_utils::get_thread_string_id()]; + + } + + std::string get_default_log_file() + { + return m_default_log_file; + } + + std::string get_default_log_folder() + { + return m_default_log_folder; + } + + void set_default_log_folder(const std::string& folder) + { + m_default_log_folder = folder; + } + + std::string get_actual_log_file_path() + { + return m_log_target.get_log_file_path(); + } + + protected: + private: + bool init() + { + // + m_journal_max_elements = LOG_JOURNAL_MAX_ELEMENTS; + m_process_name = string_tools::get_current_module_name(); + + init_log_path_by_default(); + + //this need ti initialize static critical section in get_channels_errors_stat_container() + get_channels_errors_stat_container(); + + //init default set of loggers + init_default_loggers(); + + std::stringstream ss; + ss << get_time_string() << " Init logging. Level=" << get_set_log_detalisation_level() + << "Default log path=" << m_default_log_folder << std::endl; + this->do_log_message(ss.str(), console_color_white, LOG_LEVEL_0); + return true; + } + bool init_default_loggers() + { + //TODO: + return true; + } + + bool init_log_path_by_default() + { + m_default_log_file = m_process_name; + std::string::size_type a = m_default_log_file.rfind('.'); + if (a != std::string::npos) + m_default_log_file.erase(a, m_default_log_file.size()); + + //load process name + m_default_log_folder = string_tools::get_current_module_folder(); + + m_default_log_file += ".log"; + + return true; + } + + log_stream_splitter m_log_target; + + std::string m_default_log_folder; + std::string m_default_log_file; + std::string m_process_name; + std::map m_thr_prefix_strings; + std::list m_journal; + size_t m_journal_max_elements; + critical_section m_critical_sec; + }; + /************************************************************************/ + /* */ + /************************************************************************/ + class log_singletone + { + public: + friend class initializer; + friend class logger; + static int get_log_detalisation_level() + { + get_or_create_instance();//to initialize logger, if it not initialized + return get_set_log_detalisation_level(); + } + + //get_enabled_channels not thread-safe, at the moment leave it like this because it's configured in main, before other threads started + static std::set& get_enabled_channels() + { + static std::set genabled_channels; + return genabled_channels; + } + + static bool channel_enabled(const std::string& ch_name) + { + std::set& genabled_channels = get_enabled_channels(); + return genabled_channels.find(ch_name) != genabled_channels.end(); + } + + static void enable_channels(const std::string& channels_set) + { + std::set& genabled_channels = get_enabled_channels(); + std::list list_of_channels; + boost::split(list_of_channels, channels_set, boost::is_any_of(",;: "), boost::token_compress_on); + std::cout << "log channels: "; + for (const auto& ch : list_of_channels) + { + genabled_channels.insert(ch); + std::cout << ch << " "; + } + std::cout << " enabled" << std::endl; + } + + static void enable_channel(const std::string& ch_name) + { + std::set& genabled_channels = get_enabled_channels(); + //lazy synchronization: just replace with modified copy of whole set + std::set enabled_channels_local = genabled_channels; + enabled_channels_local.insert(ch_name); + genabled_channels.swap(enabled_channels_local); + std::cout << "log channel '" << ch_name << "' enabled" << std::endl; + } + + static void disable_channels(const std::string& channels_set) + { + std::set& genabled_channels = get_enabled_channels(); + std::list list_of_channels; + boost::split(list_of_channels, channels_set, boost::is_any_of(",;: "), boost::token_compress_on); + std::cout << "log channels: "; + for (const auto& ch : list_of_channels) + { + genabled_channels.erase(ch); + std::cout << ch << " "; + } + std::cout << " disabled" << std::endl; + } + + static void disable_channel(const std::string& ch_name) + { + std::set& genabled_channels = get_enabled_channels(); + //lazy synchronization: just replace with modified copy of whole set + std::set enabled_channels_local = genabled_channels; + auto it = enabled_channels_local.find(ch_name); + if (it != enabled_channels_local.end()) + enabled_channels_local.erase(it); + genabled_channels.swap(enabled_channels_local); + std::cout << "log channel '" << ch_name << "' disabled" << std::endl; + } + + static bool channel_enabled(const char* pch_name) + { + //null channel, enabled by default + if (!pch_name) + return true; + return channel_enabled(std::string(pch_name)); + } + + + static bool is_filter_error(int error_code) + { + return false; + } + + + static bool do_log_message(const std::string& rlog_mes, int log_level, int color, bool keep_in_journal, const char* plog_name = NULL) + { + logger* plogger = get_or_create_instance(); + bool res = false; + if(plogger) + res = plogger->do_log_message(rlog_mes, log_level, color, keep_in_journal, plog_name); + else + { //globally uninitialized, create new logger for each call of do_log_message() and then delete it + plogger = new logger(); + //TODO: some extra initialization + res = plogger->do_log_message(rlog_mes, log_level, color, keep_in_journal, plog_name); + delete plogger; + plogger = NULL; + } + return res; + } + + static bool take_away_journal(std::list& journal) + { + logger* plogger = get_or_create_instance(); + bool res = false; + if(plogger) + res = plogger->take_away_journal(journal); + + return res; + } + + static bool get_journal_items(std::list& journal, size_t count) + { + logger* plogger = get_or_create_instance(); + bool res = false; + if (plogger) + res = plogger->get_journal_items(journal, count); + + return res; + } + + static bool set_max_logfile_size(uint64_t file_size) + { + logger* plogger = get_or_create_instance(); + if(!plogger) return false; + return plogger->set_max_logfile_size(file_size); + } + + + static bool set_log_rotate_cmd(const std::string& cmd) + { + logger* plogger = get_or_create_instance(); + if(!plogger) return false; + return plogger->set_log_rotate_cmd(cmd); + } + + + static bool add_logger( int type, const char* pdefault_file_name, const char* pdefault_log_folder, int log_level_limit = LOG_LEVEL_4) + { + logger* plogger = get_or_create_instance(); + if(!plogger) return false; + return plogger->add_logger(type, pdefault_file_name, pdefault_log_folder, log_level_limit); + } + + static std::string get_default_log_file() + { + logger* plogger = get_or_create_instance(); + if(plogger) + return plogger->get_default_log_file(); + + return ""; + } + + static std::string get_actual_log_file_path() + { + logger* plogger = get_or_create_instance(); + if (plogger) + return plogger->get_actual_log_file_path(); + return ""; + } + + static std::string get_default_log_folder() + { + logger* plogger = get_or_create_instance(); + if(plogger) + return plogger->get_default_log_folder(); + + return ""; + } + + static void set_default_log_folder(const std::string& folder) + { + logger* plogger = get_or_create_instance(); + if (plogger) + plogger->set_default_log_folder(folder); + + } + + + static bool add_logger( ibase_log_stream* pstream, int log_level_limit = LOG_LEVEL_4 ) + { + logger* plogger = get_or_create_instance(); + if(!plogger) return false; + return plogger->add_logger(pstream, log_level_limit); + } + + + static bool remove_logger( int type ) + { + logger* plogger = get_or_create_instance(); + if(!plogger) return false; + return plogger->remove_logger(type); + } +PUSH_WARNINGS +DISABLE_GCC_WARNING(maybe-uninitialized) + static int get_set_log_detalisation_level(bool is_need_set = false, int log_level_to_set = LOG_LEVEL_1) + { + + static int log_detalisation_level = LOG_LEVEL_1; + if (is_need_set) + { + log_detalisation_level = log_level_to_set; + } + return log_detalisation_level; + } +POP_WARNINGS + static int get_set_time_level(bool is_need_set = false, int time_log_level = LOG_LEVEL_0) + { + static int val_time_log_level = LOG_LEVEL_0; + if(is_need_set) + val_time_log_level = time_log_level; + + return val_time_log_level; + } + + static int get_set_process_level(bool is_need_set = false, int process_log_level = LOG_LEVEL_0) + { + static int val_process_log_level = LOG_LEVEL_0; + if(is_need_set) + val_process_log_level = process_log_level; + + return val_process_log_level; + } + + /*static int get_set_tid_level(bool is_need_set = false, int tid_log_level = LOG_LEVEL_0) + { + static int val_tid_log_level = LOG_LEVEL_0; + if(is_need_set) + val_tid_log_level = tid_log_level; + + return val_tid_log_level; + }*/ + + static bool get_set_need_thread_id(bool is_need_set = false, bool is_need_val = false) + { + static bool is_need = false; + if(is_need_set) + is_need = is_need_val; + + return is_need; + } + + static bool get_set_need_proc_name(bool is_need_set = false, bool is_need_val = false) + { + static bool is_need = true; + if(is_need_set) + is_need = is_need_val; + + return is_need; + } + + + + +#ifdef _MSC_VER + + + static void SetThreadName( DWORD dwThreadID, const char* threadName) + { +#define MS_VC_EXCEPTION 0x406D1388 + +#pragma pack(push,8) + typedef struct tagTHREADNAME_INFO + { + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to name (in user addr space). + DWORD dwThreadID; // Thread ID (-1=caller thread). + DWORD dwFlags; // Reserved for future use, must be zero. + } THREADNAME_INFO; +#pragma pack(pop) + + + + Sleep(10); + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = (char*)threadName; + info.dwThreadID = dwThreadID; + info.dwFlags = 0; + + __try + { + RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info ); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + } + } +#endif + + static bool set_thread_log_prefix(const std::string& prefix) + { +#ifdef _MSC_VER + SetThreadName(-1, prefix.c_str()); +#endif + + logger* plogger = get_or_create_instance(); + if(!plogger) return false; + return plogger->set_thread_prefix(prefix); + } + + static std::string get_thread_log_prefix() + { + logger* plogger = get_or_create_instance(); + if (!plogger) return ""; + return plogger->get_thread_prefix(); + } + + + + static std::string get_prefix_entry() + { + std::stringstream str_prefix; + //write time entry + if ( get_set_time_level() <= get_set_log_detalisation_level() ) + str_prefix << get_day_time_string() << " "; + + //write process info + logger* plogger = get_or_create_instance(); + //bool res = false; + if(!plogger) + { //globally uninitialized, create new logger for each call of get_prefix_entry() and then delete it + plogger = new logger(); + } + + //if ( get_set_need_proc_name() && get_set_process_level() <= get_set_log_detalisation_level() ) + // str_prefix << "[" << plogger->m_process_name << " (id=" << GetCurrentProcessId() << ")] "; +//#ifdef _MSC_VER_EX + if ( get_set_need_thread_id() /*&& get_set_tid_level() <= get_set_log_detalisation_level()*/ ) + str_prefix << "[tid:" << misc_utils::get_thread_string_id() << "] "; +//#endif + + if(plogger->m_thr_prefix_strings.size()) + { + FAST_CRITICAL_REGION_LOCAL(plogger->m_critical_sec); + std::string thr_str = misc_utils::get_thread_string_id(); + std::map::iterator it = plogger->m_thr_prefix_strings.find(thr_str); + if(it!=plogger->m_thr_prefix_strings.end()) + { + str_prefix << it->second; + } + } + + + if(get_set_is_uninitialized()) + delete plogger; + + return str_prefix.str(); + } + + private: + log_singletone(){}//restric to create an instance + //static initializer m_log_initializer;//must be in one .cpp file (for example main.cpp) via DEFINE_LOGGING macro + + static bool init() + { + return true;/*do nothing here*/ + } + static bool un_init() + { + //delete object + logger* plogger = get_set_instance_internal(); + if(plogger) delete plogger; + //set uninitialized + get_set_is_uninitialized(true, true); + get_set_instance_internal(true, NULL); + return true; + } + + static logger* get_or_create_instance() + { + logger* plogger = get_set_instance_internal(); + if(!plogger) + if(!get_set_is_uninitialized()) + get_set_instance_internal(true, plogger = new logger); + + return plogger; + } + + static logger* get_set_instance_internal(bool is_need_set = false, logger* pnew_logger_val = NULL) + { + static logger* val_plogger = NULL; + + if(is_need_set) + val_plogger = pnew_logger_val; + + return val_plogger; + } + + static bool get_set_is_uninitialized(bool is_need_set = false, bool is_uninitialized = false) + { + static bool val_is_uninitialized = false; + + if(is_need_set) + val_is_uninitialized = is_uninitialized; + + return val_is_uninitialized; + } + //static int get_set_error_filter(bool is_need_set = false) + }; + + const static initializer log_initializer; + /************************************************************************/ + /* */ +// /************************************************************************/ +// class log_array_value +// { +// int num; +// log_message& m_ref_log_mes; +// +// public: +// +// log_array_value( log_message& log_mes ) : num(0), m_ref_log_mes(log_mes) {} +// +// void operator ( )( ibase_log_value *val ) { +// m_ref_log_mes << "\n[" << num++ << "] "/* << val*/; } +// +// +// template +// void operator ()(T &value ) +// { +// m_ref_log_mes << "\n[" << num++ << "] " << value; +// } +// }; + + class log_frame + { + std::string m_name; + int m_level; + const char* m_plog_name; + public: + + log_frame(const std::string& name, int dlevel = LOG_LEVEL_2 , const char* plog_name = NULL) + { +#ifdef _MSC_VER + int lasterr=::GetLastError(); +#endif + m_plog_name = plog_name; + if ( dlevel <= log_singletone::get_log_detalisation_level() ) + { + m_name = name; + std::stringstream ss; + ss << log_space::log_singletone::get_prefix_entry() << "-->>" << m_name << std::endl; + log_singletone::do_log_message(ss.str(), dlevel, console_color_default, false, m_plog_name); + } + m_level = dlevel; +#ifdef _MSC_VER + ::SetLastError(lasterr); +#endif + } + ~log_frame() + { +#ifdef _MSC_VER + int lasterr=::GetLastError(); +#endif + + if (m_level <= log_singletone::get_log_detalisation_level() ) + { + std::stringstream ss; + ss << log_space::log_singletone::get_prefix_entry() << "<<--" << m_name << std::endl; + log_singletone::do_log_message(ss.str(), m_level, console_color_default, false,m_plog_name); + } +#ifdef _MSC_VER + ::SetLastError(lasterr); +#endif + } + }; + + inline int get_set_time_level(bool is_need_set, int time_log_level) + { + return log_singletone::get_set_time_level(is_need_set, time_log_level); + } + inline int get_set_log_detalisation_level(bool is_need_set, int log_level_to_set) + { + return log_singletone::get_set_log_detalisation_level(is_need_set, log_level_to_set); + } + inline std::string get_prefix_entry() + { + return log_singletone::get_prefix_entry(); + } + inline bool get_set_need_thread_id(bool is_need_set, bool is_need_val) + { + return log_singletone::get_set_need_thread_id(is_need_set, is_need_val); + } + inline bool get_set_need_proc_name(bool is_need_set, bool is_need_val ) + { + return log_singletone::get_set_need_proc_name(is_need_set, is_need_val); + } + + inline std::string get_win32_err_descr(int err_no) + { +#ifdef _MSC_VER + LPVOID lpMsgBuf; + + FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + err_no, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (char*) &lpMsgBuf, + 0, NULL ); + + std::string fix_sys_message = "(null)"; + if(lpMsgBuf) fix_sys_message = (char*)lpMsgBuf; + std::string::size_type a; + if ( (a = fix_sys_message.rfind( '\n' )) != std::string::npos ) + fix_sys_message.erase(a); + if ( (a = fix_sys_message.rfind( '\r' )) != std::string::npos ) + fix_sys_message.erase(a); + + LocalFree(lpMsgBuf); + return fix_sys_message; +#else + return "Not implemented yet"; +#endif + } + + inline bool getwin32_err_text(std::stringstream& ref_message, int error_no) + { + ref_message << "win32 error:" << get_win32_err_descr(error_no); + return true; + } +} + +#if !defined(DISABLE_RELEASE_LOGGING) + #define ENABLE_LOGGING_INTERNAL +#endif + + + +#define LOG_DEFAULT_CHANNEL NULL +#define ENABLE_CHANNEL_BY_DEFAULT(ch_name) \ + static bool COMBINE(init_channel, __LINE__) UNUSED_ATTRIBUTE = epee::misc_utils::static_initializer([](){ \ + epee::log_space::log_singletone::enable_channel(ch_name); return true; \ +}); + + + + + +#if defined(ENABLE_LOGGING_INTERNAL) + +#define LOG_PRINT_CHANNEL_NO_PREFIX2(log_channel, log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ + {std::stringstream ss________; ss________ << x << std::endl; epee::log_space::log_singletone::do_log_message(ss________.str() , y, epee::log_space::console_color_default, false, log_name);}} + +#define LOG_PRINT_CHANNEL_NO_PREFIX_NO_POSTFIX2(log_channel, log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ + {std::stringstream ss________; ss________ << x; epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, false, log_name);}} + +#define LOG_PRINT_CHANNEL_NO_POSTFIX2(log_channel, log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ + {std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x; epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, false, log_name);}} + +#define LOG_PRINT_CHANNEL2(log_channel, log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ + {std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x << std::endl;epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, false, log_name);}} + +#define LOG_PRINT_CHANNEL_COLOR2(log_channel, log_name, x, y, color) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ + {std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x << std::endl;epee::log_space::log_singletone::do_log_message(ss________.str(), y, color, false, log_name);}} + +#define LOG_PRINT_CHANNEL_2_JORNAL(log_channel, log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ + {std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x << std::endl;epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, true, log_name);}} + + + +#define LOG_ERROR2(log_name, x) { \ + std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << "[ERROR] Location: " << std::endl << LOCATION_SS << epee::misc_utils::print_trace() << " Message:" << std::endl << x << std::endl; epee::log_space::log_singletone::do_log_message(ss________.str(), LOG_LEVEL_0, epee::log_space::console_color_red, true, log_name); LOCAL_ASSERT(0); epee::log_space::increase_error_count(LOG_DEFAULT_CHANNEL); } + +#define LOG_FRAME2(log_name, x, y) epee::log_space::log_frame frame(x, y, log_name) + +#else // #if defined(ENABLE_LOGGING_INTERNAL) + + +#define LOG_PRINT_NO_PREFIX2(log_name, x, y) + +#define LOG_PRINT_NO_PREFIX_NO_POSTFIX2(log_name, x, y) + +#define LOG_PRINT_NO_POSTFIX2(log_name, x, y) + +#define LOG_PRINT_COLOR2(log_name, x, y, color) + +#define LOG_PRINT2_JORNAL(log_name, x, y) + +#define LOG_PRINT2(log_name, x, y) + +#define LOG_ERROR2(log_name, x) + + +#define LOG_FRAME2(log_name, x, y) + + +#endif // #if defined(ENABLE_LOGGING_INTERNAL) + +#define LOG_PRINT_NO_PREFIX2(log_name, x, y) LOG_PRINT_CHANNEL_NO_PREFIX2(LOG_DEFAULT_CHANNEL, log_name, x, y) +#define LOG_PRINT_NO_PREFIX_NO_POSTFIX2(log_name, x, y) LOG_PRINT_CHANNEL_NO_PREFIX_NO_POSTFIX2(LOG_DEFAULT_CHANNEL, log_name, x, y) +#define LOG_PRINT_NO_POSTFIX2(log_name, x, y) LOG_PRINT_CHANNEL_NO_POSTFIX2(LOG_DEFAULT_CHANNEL, log_name, x, y) +#define LOG_PRINT2(log_name, x, y) LOG_PRINT_CHANNEL2(LOG_DEFAULT_CHANNEL, log_name, x, y) +#define LOG_PRINT_COLOR2(log_name, x, y, color) LOG_PRINT_CHANNEL_COLOR2(LOG_DEFAULT_CHANNEL, log_name, x, y, color) +#define LOG_PRINT2_JORNAL(log_name, x, y) LOG_PRINT_CHANNEL_2_JORNAL(LOG_DEFAULT_CHANNEL, log_name, x, y) + + + +#ifndef LOG_DEFAULT_TARGET + #define LOG_DEFAULT_TARGET NULL +#endif + + + + +#define LOG_PRINT_NO_POSTFIX(mess, level) LOG_PRINT_NO_POSTFIX2(LOG_DEFAULT_TARGET, mess, level) +#define LOG_PRINT_NO_PREFIX(mess, level) LOG_PRINT_NO_PREFIX2(LOG_DEFAULT_TARGET, mess, level) +#define LOG_PRINT_NO_PREFIX_NO_POSTFIX(mess, level) LOG_PRINT_NO_PREFIX_NO_POSTFIX2(LOG_DEFAULT_TARGET, mess, level) +#define LOG_PRINT(mess, level) LOG_PRINT2(LOG_DEFAULT_TARGET, mess, level) + +#define LOG_PRINT_COLOR(mess, level, color) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, color) +#define LOG_PRINT_RED(mess, level) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, epee::log_space::console_color_red) +#define LOG_PRINT_GREEN(mess, level) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, epee::log_space::console_color_green) +#define LOG_PRINT_BLUE(mess, level) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, epee::log_space::console_color_blue) +#define LOG_PRINT_YELLOW(mess, level) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, epee::log_space::console_color_yellow) +#define LOG_PRINT_CYAN(mess, level) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, epee::log_space::console_color_cyan) +#define LOG_PRINT_MAGENTA(mess, level) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, epee::log_space::console_color_magenta) + +#define LOG_PRINT_RED_L0(mess) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, LOG_LEVEL_0, epee::log_space::console_color_red) + +#define LOG_PRINT_L0(mess) LOG_PRINT(mess, LOG_LEVEL_0) +#define LOG_PRINT_L1(mess) LOG_PRINT(mess, LOG_LEVEL_1) +#define LOG_PRINT_L2(mess) LOG_PRINT(mess, LOG_LEVEL_2) +#define LOG_PRINT_L3(mess) LOG_PRINT(mess, LOG_LEVEL_3) +#define LOG_PRINT_L4(mess) LOG_PRINT(mess, LOG_LEVEL_4) +#define LOG_PRINT_J(mess, level) LOG_PRINT2_JORNAL(LOG_DEFAULT_TARGET, mess, level) + +#define LOG_ERROR(mess) LOG_ERROR2(LOG_DEFAULT_TARGET, mess) +#define LOG_FRAME(mess, level) LOG_FRAME2(LOG_DEFAULT_TARGET, mess, level) +#define LOG_VALUE(mess, level) LOG_VALUE2(LOG_DEFAULT_TARGET, mess, level) +#define LOG_ARRAY(mess, level) LOG_ARRAY2(LOG_DEFAULT_TARGET, mess, level) +//#define LOGWIN_PLATFORM_ERROR(err_no) LOGWINDWOS_PLATFORM_ERROR2(LOG_DEFAULT_TARGET, err_no) +#define LOG_SOCKET_ERROR(err_no) LOG_SOCKET_ERROR2(LOG_DEFAULT_TARGET, err_no) +//#define LOGWIN_PLATFORM_ERROR_UNCRITICAL(mess) LOGWINDWOS_PLATFORM_ERROR_UNCRITICAL2(LOG_DEFAULT_TARGET, mess) + +#define ENDL std::endl + +#define TRY_ENTRY() try { +#define CATCH_ENTRY_CUSTOM(location, custom_code, return_val) } \ + catch(const std::exception& ex) \ +{ \ + (void)(ex); \ + LOG_ERROR("Exception at [" << location << "], what=" << ex.what()); \ + custom_code; \ + return return_val; \ +} \ + catch(...) \ +{ \ + LOG_ERROR("Exception at [" << location << "], generic exception \"...\""); \ + custom_code; \ + return return_val; \ +} +#define CATCH_ENTRY(location, return_val) CATCH_ENTRY_CUSTOM(location, (void)0, return_val) + +#define CATCH_ENTRY2(return_val) CATCH_ENTRY_CUSTOM(LOCATION_SS, (void)0, return_val) + +#define CATCH_ENTRY_L0(location, return_val) CATCH_ENTRY(location, return_val) +#define CATCH_ENTRY_L1(location, return_val) CATCH_ENTRY(location, return_val) +#define CATCH_ENTRY_L2(location, return_val) CATCH_ENTRY(location, return_val) +#define CATCH_ENTRY_L3(location, return_val) CATCH_ENTRY(location, return_val) +#define CATCH_ENTRY_L4(location, return_val) CATCH_ENTRY(location, return_val) + + +#define ASSERT_MES_AND_THROW(message) {LOG_ERROR(message); std::stringstream ss; ss << message; throw std::runtime_error(ss.str());} + +#define CHECK_AND_ASSERT_THROW_MES(expr, message) {if(!(expr)) ASSERT_MES_AND_THROW(message << ENDL << "thrown from " << LOCATION_SS);} +#define CHECK_AND_ASSERT_THROW(expr, exception_exp) {if(!(expr)) {LOG_ERROR("EXCEPTION is thrown from " << LOCATION_SS); throw exception_exp; };} + + +#ifndef CHECK_AND_ASSERT +#define CHECK_AND_ASSERT(expr, fail_ret_val) do{if(!(expr)){LOCAL_ASSERT(expr); return fail_ret_val;};}while(0) +#endif + +#define NOTHING + +#ifndef CHECK_AND_ASSERT_MES +#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message) do{if(!(expr)) {LOG_ERROR(message); return fail_ret_val;};}while(0) +#endif + +#ifndef CHECK_AND_FORCE_ASSERT_MES +#define CHECK_AND_FORCE_ASSERT_MES(expr, fail_ret_val, message) do{if(!(expr)) {LOG_ERROR(message); FORCE_ASSERT(expr); return fail_ret_val;};}while(0) +#endif + + +#ifndef CHECK_AND_ASSERT_MES_CUSTOM +#define CHECK_AND_ASSERT_MES_CUSTOM(expr, fail_ret_val, custom_code, message) do{if(!(expr)) {LOG_ERROR(message); custom_code; return fail_ret_val;};}while(0) +#endif + +/*#ifndef CHECK_AND_ASSERT_MES_AND_THROW +#define CHECK_AND_ASSERT_MES_AND_THROW(expr, message) do{if(!(expr)) {LOG_ERROR(message); throw std::runtime_error(message);};}while(0) +#endif +*/ + +#ifndef CHECK_AND_NO_ASSERT_MES +#define CHECK_AND_NO_ASSERT_MES(expr, fail_ret_val, message) do{if(!(expr)) {LOG_PRINT_MAGENTA(message, LOG_LEVEL_0); /*LOCAL_ASSERT(expr);*/ return fail_ret_val;};}while(0) +#endif + +#ifndef CHECK_AND_NO_ASSERT_MES_LEVEL +#define CHECK_AND_NO_ASSERT_MES_LEVEL(expr, fail_ret_val, message, log_level) do{if(!(expr)) {LOG_PRINT(message, log_level); return fail_ret_val;};}while(0) +#endif + +#ifndef CHECK_AND_ASSERT_MES_NO_RET +#define CHECK_AND_ASSERT_MES_NO_RET(expr, message) do{if(!(expr)) {LOG_ERROR(message);};}while(0) +#endif + + +#ifndef CHECK_AND_ASSERT_MES2 +#define CHECK_AND_ASSERT_MES2(expr, message) do{if(!(expr)) {LOG_ERROR(message); };}while(0) +#endif + + +} + +POP_WARNINGS + +#endif //_MISC_LOG_EX_H_ diff --git a/contrib/epee/include/misc_os_dependent.h b/contrib/epee/include/misc_os_dependent.h new file mode 100644 index 00000000..4fe89b9f --- /dev/null +++ b/contrib/epee/include/misc_os_dependent.h @@ -0,0 +1,137 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// +#ifdef WIN32 + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + + //#ifdef _WIN32_WINNT + // #undef _WIN32_WINNT + // #define _WIN32_WINNT 0x0600 + //#endif + + +#include +#endif + +#ifdef __MACH__ +#include +#include +#endif + +#pragma once +namespace epee +{ +namespace misc_utils +{ + + inline uint64_t get_tick_count() + { +#if defined(_MSC_VER) + typedef ULONGLONG(*GetTickCount64Ptr)(); + static GetTickCount64Ptr get_tick_count64 = (GetTickCount64Ptr)(GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetTickCount64")); + if (get_tick_count64) + return (*get_tick_count64)(); + return GetTickCount(); +#elif defined(__MACH__) + clock_serv_t cclock; + mach_timespec_t mts; + + host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self(), cclock); + + return (mts.tv_sec * 1000) + (mts.tv_nsec/1000000); +#else + struct timespec ts; + if(clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { + return 0; + } + return (ts.tv_sec * 1000) + (ts.tv_nsec/1000000); +#endif + } + + + inline int call_sys_cmd(const std::string& cmd) + { + std::cout << "# " << cmd << std::endl; + + FILE * fp ; + //char tstCommand[] ="ls *"; + char path[1000] = {0}; +#if !defined(__GNUC__) + fp = _popen(cmd.c_str(), "r"); +#else + fp = popen(cmd.c_str(), "r"); +#endif + while ( fgets( path, 1000, fp ) != NULL ) + std::cout << path; + +#if !defined(__GNUC__) + _pclose(fp); +#else + pclose(fp); +#endif + return 0; + + } + + + inline std::string get_thread_string_id() + { +#if defined(_MSC_VER) + return boost::lexical_cast(GetCurrentThreadId()); +#elif defined(__GNUC__) + return boost::lexical_cast(pthread_self()); +#endif + } + +#if defined(__GNUC__) +#include +#endif + inline std::string print_trace() + { + std::stringstream ss; +#if defined(__GNUC__) + ss << std::endl << "STACK" << std::endl; + const size_t max_depth = 100; + size_t stack_depth; + void *stack_addrs[max_depth]; + char **stack_strings; + + stack_depth = backtrace(stack_addrs, max_depth); + stack_strings = backtrace_symbols(stack_addrs, stack_depth); + + + for (size_t i = 1; i < stack_depth; i++) { + ss << stack_strings[i] << std::endl; + } + free(stack_strings); // malloc()ed by backtrace_symbols +#endif + return ss.str(); + } +} +} diff --git a/contrib/epee/include/net/abstract_tcp_server2.h b/contrib/epee/include/net/abstract_tcp_server2.h new file mode 100644 index 00000000..4c274c0e --- /dev/null +++ b/contrib/epee/include/net/abstract_tcp_server2.h @@ -0,0 +1,293 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#ifndef _ABSTRACT_TCP_SERVER2_H_ +#define _ABSTRACT_TCP_SERVER2_H_ + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "net_utils_base.h" +#include "syncobj.h" + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL "net_server" + +#define ABSTRACT_SERVER_SEND_QUE_MAX_COUNT 1000 + +namespace epee +{ +namespace net_utils +{ + + struct i_connection_filter + { + virtual bool is_remote_ip_allowed(uint32_t adress)=0; + protected: + virtual ~i_connection_filter(){} + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + /// Represents a single connection from a client. + template + class connection + : public boost::enable_shared_from_this >, + private boost::noncopyable, + public i_service_endpoint + { + public: + typedef typename t_protocol_handler::connection_context t_connection_context; + /// Construct a connection with the given io_service. + explicit connection(boost::asio::io_service& io_service, + typename t_protocol_handler::config_type& config, volatile uint32_t& sock_count, i_connection_filter * &pfilter); + + virtual ~connection(); + /// Get the socket associated with the connection. + boost::asio::ip::tcp::socket& socket(); + + /// Start the first asynchronous operation for the connection. + bool start(bool is_income, bool is_multithreaded); + + void get_context(t_connection_context& context_){context_ = context;} + + void call_back_starter(); + bool is_shutdown(){return m_was_shutdown;} + bool cancel(); + private: + //----------------- i_service_endpoint --------------------- + virtual bool do_send(const void* ptr, size_t cb); + virtual bool close(); + virtual bool call_run_once_service_io(); + virtual bool request_callback(); + virtual boost::asio::io_service& get_io_service(); + virtual bool add_ref(); + virtual bool release(); + //------------------------------------------------------ + boost::shared_ptr > safe_shared_from_this(); + bool shutdown(); + /// Handle completion of a read operation. + void handle_read(const boost::system::error_code& e, + std::size_t bytes_transferred); + + /// Handle completion of a write operation. + void handle_write(const boost::system::error_code& e, size_t cb); + + /// Strand to ensure the connection's handlers are not called concurrently. + boost::asio::io_service::strand strand_; + + /// Socket for the connection. + boost::asio::ip::tcp::socket socket_; + + /// Buffer for incoming data. + boost::array buffer_; + + t_connection_context context; + volatile uint32_t m_want_close_connection; + std::atomic m_was_shutdown; + critical_section m_send_que_lock; + std::list m_send_que; + volatile uint32_t& m_ref_sockets_count; + i_connection_filter* &m_pfilter; + volatile bool m_is_multithreaded; + + //this should be the last one, because it could be wait on destructor, while other activities possible on other threads + t_protocol_handler m_protocol_handler; + //typename t_protocol_handler::config_type m_dummy_config; + std::list > > m_self_refs; // add_ref/release support + critical_section m_self_refs_lock; + }; + + + /************************************************************************/ + /* */ + /************************************************************************/ + template + class boosted_tcp_server + : private boost::noncopyable + { + public: + typedef boost::shared_ptr > connection_ptr; + typedef typename t_protocol_handler::connection_context t_connection_context; + /// Construct the server to listen on the specified TCP address and port, and + /// serve up files from the given directory. + boosted_tcp_server(); + explicit boosted_tcp_server(boost::asio::io_service& external_io_service); + ~boosted_tcp_server(); + + bool init_server(uint32_t port, const std::string address = "0.0.0.0"); + bool init_server(const std::string port, const std::string& address = "0.0.0.0"); + + /// Run the server's io_service loop. + bool run_server(size_t threads_count, bool wait = true); + + /// wait for service workers stop + bool timed_wait_server_stop(uint64_t wait_mseconds); + + /// Stop the server. + void send_stop_signal(); + + bool is_stop_signal_sent(); + + void set_threads_prefix(const std::string& prefix_name); + + bool deinit_server(){return true;} + + size_t get_threads_count(){return m_threads_count;} + + void set_connection_filter(i_connection_filter* pfilter); + + bool connect(const std::string& adr, const std::string& port, uint32_t conn_timeot, t_connection_context& cn, const std::string& bind_ip = "0.0.0.0"); + template + bool connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeot, t_callback cb, const std::string& bind_ip = "0.0.0.0"); + + typename t_protocol_handler::config_type& get_config_object(){return m_config;} + + int get_binded_port(){return m_port;} + + boost::asio::io_service& get_io_service(){return io_service_;} + + struct idle_callback_conext_base + { + virtual ~idle_callback_conext_base(){} + + virtual bool call_handler(){return true;} + + idle_callback_conext_base(boost::asio::io_service& io_serice): + m_timer(io_serice) + {} + boost::asio::deadline_timer m_timer; + uint64_t m_period; + }; + + template + struct idle_callback_conext: public idle_callback_conext_base + { + idle_callback_conext(boost::asio::io_service& io_serice, t_handler& h, uint64_t period): + idle_callback_conext_base(io_serice), + m_handler(h) + {this->m_period = period;} + + t_handler m_handler; + virtual bool call_handler() + { + return m_handler(); + } + }; + + template + bool add_idle_handler(t_handler t_callback, uint64_t timeout_ms) + { + boost::shared_ptr ptr(new idle_callback_conext(io_service_, t_callback, timeout_ms)); + //needed call handler here ?... + ptr->m_timer.expires_from_now(boost::posix_time::milliseconds(ptr->m_period)); + ptr->m_timer.async_wait(boost::bind(&boosted_tcp_server::global_timer_handler, this, ptr)); + return true; + } + + bool global_timer_handler(/*const boost::system::error_code& err, */boost::shared_ptr ptr) + { + //if handler return false - he don't want to be called anymore + try{ + if (!ptr->call_handler()) + return true; + } + catch (...) + { + return true; + } + + + ptr->m_timer.expires_from_now(boost::posix_time::milliseconds(ptr->m_period)); + ptr->m_timer.async_wait(boost::bind(&boosted_tcp_server::global_timer_handler, this, ptr)); + return true; + } + + template + bool async_call(t_handler t_callback) + { + io_service_.post(t_callback); + return true; + } + + protected: + typename t_protocol_handler::config_type m_config; + + private: + /// Run the server's io_service loop. + bool worker_thread(); + /// Handle completion of an asynchronous accept operation. + void handle_accept(const boost::system::error_code& e); + + bool is_thread_worker(); + + /// The io_service used to perform asynchronous operations. + std::unique_ptr m_io_service_local_instance; + boost::asio::io_service& io_service_; + + /// Acceptor used to listen for incoming connections. + boost::asio::ip::tcp::acceptor acceptor_; + + /// The next connection to be accepted. + connection_ptr new_connection_; + //std::mutex connections_mutex; + //std::deque connections_; + std::atomic m_stop_signal_sent; + uint32_t m_port; + volatile uint32_t m_sockets_count; + std::string m_address; + std::string m_thread_name_prefix; + size_t m_threads_count; + i_connection_filter* m_pfilter; + std::vector > m_threads; + boost::thread::id m_main_thread_id; + critical_section m_threads_lock; + volatile uint32_t m_thread_index; + }; +} +} + +#include "abstract_tcp_server2.inl" + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL NULL + +#endif \ No newline at end of file diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl new file mode 100644 index 00000000..15ce8441 --- /dev/null +++ b/contrib/epee/include/net/abstract_tcp_server2.inl @@ -0,0 +1,843 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#include "net_utils_base.h" +#include +#include +#include +#include +#include +#include +#include +#include "misc_language.h" +#include "warnings.h" + +PUSH_WARNINGS +namespace epee +{ +namespace net_utils +{ + /************************************************************************/ + /* */ + /************************************************************************/ +DISABLE_VS_WARNINGS(4355) + + template + connection::connection(boost::asio::io_service& io_service, + typename t_protocol_handler::config_type& config, volatile uint32_t& sock_count, i_connection_filter* &pfilter) + : strand_(io_service), + socket_(io_service), + m_protocol_handler(this, config, context), + m_want_close_connection(0), + m_was_shutdown(0), + m_ref_sockets_count(sock_count), + m_pfilter(pfilter) + { + boost::interprocess::ipcdetail::atomic_inc32(&m_ref_sockets_count); + } +DISABLE_VS_WARNINGS(4355) + //--------------------------------------------------------------------------------- + template + connection::~connection() + { + if(!m_was_shutdown) + { + LOG_PRINT_L3("[sock " << socket_.native_handle() << "] Socket destroyed without shutdown."); + shutdown(); + } + + LOG_PRINT_L3("[sock " << socket_.native_handle() << "] Socket destroyed"); + boost::interprocess::ipcdetail::atomic_dec32(&m_ref_sockets_count); + VALIDATE_MUTEX_IS_FREE(m_send_que_lock); + VALIDATE_MUTEX_IS_FREE(m_self_refs_lock); + } + //--------------------------------------------------------------------------------- + template + boost::asio::ip::tcp::socket& connection::socket() + { + return socket_; + } + //--------------------------------------------------------------------------------- + template + boost::shared_ptr > connection::safe_shared_from_this() + { + try + { + return connection::shared_from_this(); + } + catch (const boost::bad_weak_ptr&) + { + // It happens when the connection is being deleted + return boost::shared_ptr >(); + } + } + //--------------------------------------------------------------------------------- + template + bool connection::start(bool is_income, bool is_multithreaded) + { + TRY_ENTRY(); + + // Use safe_shared_from_this, because of this is public method and it can be called on the object being deleted + auto self = safe_shared_from_this(); + if(!self) + { + LOG_PRINT_RED("Failed to start conntection, failed to call safe_shared_from_this", LOG_LEVEL_2); + return false; + } + + m_is_multithreaded = is_multithreaded; + + boost::system::error_code ec; + auto remote_ep = socket_.remote_endpoint(ec); + CHECK_AND_NO_ASSERT_MES(!m_was_shutdown, false, "was shutdown on start connection"); + + CHECK_AND_NO_ASSERT_MES_LEVEL(!ec, false, "Failed to get remote endpoint(" << (is_income?"INT":"OUT") << "): " << ec.message() << ':' << ec.value(), LOG_LEVEL_2); + + auto local_ep = socket_.local_endpoint(ec); + CHECK_AND_NO_ASSERT_MES(!ec, false, "Failed to get local endpoint: " << ec.message() << ':' << ec.value()); + + context = boost::value_initialized(); + long ip_ = boost::asio::detail::socket_ops::host_to_network_long(remote_ep.address().to_v4().to_ulong()); + + context.set_details(boost::uuids::random_generator()(), ip_, remote_ep.port(), is_income); + context.m_last_send = context.m_last_recv = time(NULL); + + LOG_PRINT_L3("[sock " << socket_.native_handle() << "] new connection, remote end_point: " << print_connection_context_short(context) << + " local end_point: " << local_ep.address().to_string() << ':' << local_ep.port() << + ", total sockets objects " << m_ref_sockets_count); + + if(is_income && m_pfilter && !m_pfilter->is_remote_ip_allowed(context.m_remote_ip)) + { + LOG_PRINT_L0("[sock " << socket_.native_handle() << "] ip denied " << string_tools::get_ip_string_from_int32(context.m_remote_ip) << ", shutdowning connection"); + close(); + return false; + } + + m_protocol_handler.after_init_connection(); + + socket_.async_read_some(boost::asio::buffer(buffer_), + strand_.wrap( + boost::bind(&connection::handle_read, self, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred))); + + + return true; + + CATCH_ENTRY_L0("connection::start()", false); + } + //--------------------------------------------------------------------------------- + template + bool connection::request_callback() + { + TRY_ENTRY(); + LOG_PRINT_L2("[" << print_connection_context_short(context) << "] request_callback"); + // Use safe_shared_from_this, because of this is public method and it can be called on the object being deleted + auto self = safe_shared_from_this(); + if(!self) + return false; + + strand_.post(boost::bind(&connection::call_back_starter, self)); + CATCH_ENTRY_L0("connection::request_callback()", false); + return true; + } + //--------------------------------------------------------------------------------- + template + boost::asio::io_service& connection::get_io_service() + { + return socket_.get_io_service(); + } + //--------------------------------------------------------------------------------- + template + bool connection::add_ref() + { + TRY_ENTRY(); + LOG_PRINT_L4("[sock " << socket_.native_handle() << "] add_ref"); + CRITICAL_REGION_LOCAL(m_self_refs_lock); + + // Use safe_shared_from_this, because of this is public method and it can be called on the object being deleted + auto self = safe_shared_from_this(); + if(!self) + return false; + if(m_was_shutdown) + return false; + m_self_refs.push_back(self); + return true; + CATCH_ENTRY_L0("connection::add_ref()", false); + } + //--------------------------------------------------------------------------------- + template + bool connection::release() + { + TRY_ENTRY(); + boost::shared_ptr > back_connection_copy; + LOG_PRINT_L4("[sock " << socket_.native_handle() << "] release"); + CRITICAL_REGION_BEGIN(m_self_refs_lock); + CHECK_AND_ASSERT_MES(m_self_refs.size(), false, "[sock " << socket_.native_handle() << "] m_self_refs empty at connection::release() call"); + //erasing from container without additional copy can cause start deleting object, including m_self_refs + back_connection_copy = m_self_refs.back(); + m_self_refs.pop_back(); + CRITICAL_REGION_END(); + return true; + CATCH_ENTRY_L0("connection::release()", false); + } + //--------------------------------------------------------------------------------- + template + void connection::call_back_starter() + { + TRY_ENTRY(); + LOG_PRINT_L2("[" << print_connection_context_short(context) << "] fired_callback"); + m_protocol_handler.handle_qued_callback(); + CATCH_ENTRY_L0("connection::call_back_starter()", void()); + } + //--------------------------------------------------------------------------------- + template + void connection::handle_read(const boost::system::error_code& e, + std::size_t bytes_transferred) + { + TRY_ENTRY(); + LOG_PRINT_L4("[sock " << socket_.native_handle() << "] Assync read calledback."); + + if (!e) + { + LOG_PRINT("[sock " << socket_.native_handle() << "] RECV " << bytes_transferred, LOG_LEVEL_4); + context.m_last_recv = time(NULL); + context.m_recv_cnt += bytes_transferred; + bool recv_res = m_protocol_handler.handle_recv(buffer_.data(), bytes_transferred); + if(!recv_res) + { + LOG_PRINT("[sock " << socket_.native_handle() << "] protocol_want_close", LOG_LEVEL_4); + + //some error in protocol, protocol handler ask to close connection + boost::interprocess::ipcdetail::atomic_write32(&m_want_close_connection, 1); + bool do_shutdown = false; + CRITICAL_REGION_BEGIN(m_send_que_lock); + if(!m_send_que.size()) + do_shutdown = true; + CRITICAL_REGION_END(); + if(do_shutdown) + shutdown(); + }else + { + socket_.async_read_some(boost::asio::buffer(buffer_), + strand_.wrap( + boost::bind(&connection::handle_read, connection::shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred))); + LOG_PRINT_L4("[sock " << socket_.native_handle() << "]Assync read requested."); + } + }else + { + LOG_PRINT_L3("[sock " << socket_.native_handle() << "] Some not success at read: " << e.message() << ':' << e.value()); + if(e.value() != 2) + { + LOG_PRINT_L3("[sock " << socket_.native_handle() << "] Some problems at read: " << e.message() << ':' << e.value()); + shutdown(); + } + } + // If an error occurs then no new asynchronous operations are started. This + // means that all shared_ptr references to the connection object will + // disappear and the object will be destroyed automatically after this + // handler returns. The connection class's destructor closes the socket. + CATCH_ENTRY_L0("connection::handle_read", void()); + } + //--------------------------------------------------------------------------------- + template + bool connection::call_run_once_service_io() + { + TRY_ENTRY(); + if(!m_is_multithreaded) + { + //single thread model, we can wait in blocked call + size_t cnt = socket_.get_io_service().run_one(); + if(!cnt)//service is going to quit + return false; + }else + { + //multi thread model, we can't(!) wait in blocked call + //so we make non blocking call and releasing CPU by calling sleep(0); + //if no handlers were called + //TODO: Maybe we need to have have critical section + event + callback to upper protocol to + //ask it inside(!) critical region if we still able to go in event wait... + size_t cnt = socket_.get_io_service().poll_one(); + if(!cnt) + misc_utils::sleep_no_w(0); + } + + return true; + CATCH_ENTRY_L0("connection::call_run_once_service_io", false); + } + //--------------------------------------------------------------------------------- + template + bool connection::do_send(const void* ptr, size_t cb) + { + TRY_ENTRY(); + // Use safe_shared_from_this, because of this is public method and it can be called on the object being deleted + auto self = safe_shared_from_this(); + if(!self) + return false; + if(m_was_shutdown) + return false; + + LOG_PRINT("[sock " << socket_.native_handle() << "] SEND " << cb, LOG_LEVEL_4); + context.m_last_send = time(NULL); + context.m_send_cnt += cb; + //some data should be wrote to stream + //request complete + + CRITICAL_REGION_LOCAL_VAR(m_send_que_lock, send_guard); + if(m_send_que.size() > ABSTRACT_SERVER_SEND_QUE_MAX_COUNT) + { + send_guard.unlock();//manual unlock + LOG_ERROR("send to [" << print_connection_context_short(context) << ", (" << (void*)this << ")] que size is more than ABSTRACT_SERVER_SEND_QUE_MAX_COUNT(" << ABSTRACT_SERVER_SEND_QUE_MAX_COUNT << "), shutting down connection"); + close(); + return false; + } + + m_send_que.resize(m_send_que.size()+1); + m_send_que.back().assign((const char*)ptr, cb); + + if(m_send_que.size() > 1) + { + //active operation should be in progress, nothing to do, just wait last operation callback + }else + { + //no active operation + if(m_send_que.size()!=1) + { + LOG_ERROR("Looks like no active operations, but send que size != 1!!"); + return false; + } + + boost::asio::async_write(socket_, boost::asio::buffer(m_send_que.front().data(), m_send_que.front().size()), + //strand_.wrap( + boost::bind(&connection::handle_write, self, _1, _2) + //) + ); + + LOG_PRINT_L4("[sock " << socket_.native_handle() << "] Assync send requested " << m_send_que.front().size()); + } + + return true; + + CATCH_ENTRY_L0("connection::do_send", false); + } + //--------------------------------------------------------------------------------- + template + bool connection::shutdown() + { + // Initiate graceful connection closure. + boost::system::error_code ignored_ec; + socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); + m_was_shutdown = true; + m_protocol_handler.release_protocol(); + return true; + } + //--------------------------------------------------------------------------------- + template + bool connection::close() + { + TRY_ENTRY(); + LOG_PRINT_L4("[sock " << socket_.native_handle() << "] Que Shutdown called."); + size_t send_que_size = 0; + CRITICAL_REGION_BEGIN(m_send_que_lock); + send_que_size = m_send_que.size(); + CRITICAL_REGION_END(); + boost::interprocess::ipcdetail::atomic_write32(&m_want_close_connection, 1); + if(!send_que_size) + { + shutdown(); + } + + return true; + CATCH_ENTRY_L0("connection::close", false); + } + //--------------------------------------------------------------------------------- + template + bool connection::cancel() + { + return close(); + } + //--------------------------------------------------------------------------------- + template + void connection::handle_write(const boost::system::error_code& e, size_t cb) + { + TRY_ENTRY(); + LOG_PRINT_L4("[sock " << socket_.native_handle() << "] Assync send calledback " << cb); + + if (e) + { + LOG_PRINT_L0("[sock " << socket_.native_handle() << "] Some problems at write: " << e.message() << ':' << e.value()); + shutdown(); + return; + } + + bool do_shutdown = false; + CRITICAL_REGION_BEGIN(m_send_que_lock); + if(m_send_que.empty()) + { + LOG_ERROR("[sock " << socket_.native_handle() << "] m_send_que.size() == 0 at handle_write!"); + return; + } + + m_send_que.pop_front(); + if(m_send_que.empty()) + { + if(boost::interprocess::ipcdetail::atomic_read32(&m_want_close_connection)) + { + do_shutdown = true; + } + }else + { + //have more data to send + boost::asio::async_write(socket_, boost::asio::buffer(m_send_que.front().data(), m_send_que.front().size()), + //strand_.wrap( + boost::bind(&connection::handle_write, connection::shared_from_this(), _1, _2)); + //); + } + CRITICAL_REGION_END(); + + if(do_shutdown) + { + shutdown(); + } + CATCH_ENTRY_L0("connection::handle_write", void()); + } + /************************************************************************/ + /* */ + /************************************************************************/ + template + boosted_tcp_server::boosted_tcp_server(): + m_io_service_local_instance(new boost::asio::io_service()), + io_service_(*m_io_service_local_instance.get()), + acceptor_(io_service_), + new_connection_(new connection(io_service_, m_config, m_sockets_count, m_pfilter)), + m_stop_signal_sent(false), m_port(0), m_sockets_count(0), m_threads_count(0), m_pfilter(NULL), m_thread_index(0) + { + m_thread_name_prefix = "NET"; + } + + template + boosted_tcp_server::boosted_tcp_server(boost::asio::io_service& extarnal_io_service): + io_service_(extarnal_io_service), + acceptor_(io_service_), + new_connection_(new connection(io_service_, m_config, m_sockets_count, m_pfilter)), + m_stop_signal_sent(false), m_port(0), m_sockets_count(0), m_threads_count(0), m_pfilter(NULL), m_thread_index(0) + { + m_thread_name_prefix = "NET"; + } + //--------------------------------------------------------------------------------- + template + boosted_tcp_server::~boosted_tcp_server() + { + this->send_stop_signal(); + timed_wait_server_stop(10000); + } + //--------------------------------------------------------------------------------- + template + bool boosted_tcp_server::init_server(uint32_t port, const std::string address) + { + TRY_ENTRY(); + m_stop_signal_sent = false; + m_port = port; + m_address = address; + // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR). + boost::asio::ip::tcp::resolver resolver(io_service_); + boost::asio::ip::tcp::resolver::query query(address, boost::lexical_cast(port)); + boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query); + acceptor_.open(endpoint.protocol()); + acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + acceptor_.bind(endpoint); + acceptor_.listen(); + boost::asio::ip::tcp::endpoint binded_endpoint = acceptor_.local_endpoint(); + m_port = binded_endpoint.port(); + acceptor_.async_accept(new_connection_->socket(), + boost::bind(&boosted_tcp_server::handle_accept, this, + boost::asio::placeholders::error)); + + return true; + CATCH_ENTRY_L0("boosted_tcp_server::init_server", false); + } + //----------------------------------------------------------------------------- +PUSH_WARNINGS +DISABLE_GCC_WARNING(maybe-uninitialized) + template + bool boosted_tcp_server::init_server(const std::string port, const std::string& address) + { + uint32_t p = 0; + + if (port.size() && !string_tools::get_xtype_from_string(p, port)) { + LOG_ERROR("Failed to convert port no = " << port); + return false; + } + return this->init_server(p, address); + } +POP_WARNINGS + //--------------------------------------------------------------------------------- + template + bool boosted_tcp_server::worker_thread() + { + TRY_ENTRY(); + uint32_t local_thr_index = boost::interprocess::ipcdetail::atomic_inc32(&m_thread_index); + std::string thread_name = std::string("[") + m_thread_name_prefix; + thread_name += boost::to_string(local_thr_index) + "]"; + log_space::log_singletone::set_thread_log_prefix(thread_name); + while(!m_stop_signal_sent) + { + try + { + io_service_.run(); + } + catch(const std::exception& ex) + { + LOG_ERROR("Exception at server worker thread, what=" << ex.what()); + } + catch(...) + { + LOG_ERROR("Exception at server worker thread, unknown execption"); + } + } + LOG_PRINT_L4("Worker thread finished"); + return true; + CATCH_ENTRY_L0("boosted_tcp_server::worker_thread", false); + } + //--------------------------------------------------------------------------------- + template + void boosted_tcp_server::set_threads_prefix(const std::string& prefix_name) + { + m_thread_name_prefix = prefix_name; + } + //--------------------------------------------------------------------------------- + template + void boosted_tcp_server::set_connection_filter(i_connection_filter* pfilter) + { + m_pfilter = pfilter; + } + //--------------------------------------------------------------------------------- + template + bool boosted_tcp_server::run_server(size_t threads_count, bool wait) + { + TRY_ENTRY(); + m_threads_count = threads_count; + m_main_thread_id = boost::this_thread::get_id(); + log_space::log_singletone::set_thread_log_prefix("[SRV_MAIN]"); + while(!m_stop_signal_sent) + { + + // Create a pool of threads to run all of the io_services. + CRITICAL_REGION_BEGIN(m_threads_lock); + for (std::size_t i = 0; i < threads_count; ++i) + { + boost::shared_ptr thread(new boost::thread( + boost::bind(&boosted_tcp_server::worker_thread, this))); + m_threads.push_back(thread); + } + CRITICAL_REGION_END(); + // Wait for all threads in the pool to exit. + if(wait) + { + for (std::size_t i = 0; i < m_threads.size(); ++i) + m_threads[i]->join(); + m_threads.clear(); + + }else + { + return true; + } + + if(wait && !m_stop_signal_sent) + { + //some problems with the listening socket ?.. + LOG_PRINT_L0("Net service stopped without stop request, restarting..."); + if(!this->init_server(m_port, m_address)) + { + LOG_PRINT_L0("Reiniting service failed, exit."); + return false; + }else + { + LOG_PRINT_L0("Reiniting OK."); + } + } + } + return true; + CATCH_ENTRY_L0("boosted_tcp_server::run_server", false); + } + //--------------------------------------------------------------------------------- + template + bool boosted_tcp_server::is_thread_worker() + { + TRY_ENTRY(); + CRITICAL_REGION_LOCAL(m_threads_lock); + BOOST_FOREACH(boost::shared_ptr& thp, m_threads) + { + if(thp->get_id() == boost::this_thread::get_id()) + return true; + } + if(m_threads_count == 1 && boost::this_thread::get_id() == m_main_thread_id) + return true; + return false; + CATCH_ENTRY_L0("boosted_tcp_server::is_thread_worker", false); + } + //--------------------------------------------------------------------------------- + template + bool boosted_tcp_server::timed_wait_server_stop(uint64_t wait_mseconds) + { + TRY_ENTRY(); + boost::chrono::milliseconds ms(wait_mseconds); + for (std::size_t i = 0; i < m_threads.size(); ++i) + { + if(m_threads[i]->joinable() && !m_threads[i]->try_join_for(ms)) + { + LOG_PRINT_L0("Interrupting thread " << m_threads[i]->native_handle()); + m_threads[i]->interrupt(); + } + } + return true; + CATCH_ENTRY_L0("boosted_tcp_server::timed_wait_server_stop", false); + } + //--------------------------------------------------------------------------------- + template + void boosted_tcp_server::send_stop_signal() + { + m_stop_signal_sent = true; + TRY_ENTRY(); + m_config.on_send_stop_signal(); + + io_service_.stop(); + CATCH_ENTRY_L0("boosted_tcp_server::send_stop_signal()", void()); + } + //--------------------------------------------------------------------------------- + template + bool boosted_tcp_server::is_stop_signal_sent() + { + return m_stop_signal_sent; + } + //--------------------------------------------------------------------------------- + template + void boosted_tcp_server::handle_accept(const boost::system::error_code& e) + { + TRY_ENTRY(); + if (!e) + { + connection_ptr conn(std::move(new_connection_)); + + new_connection_.reset(new connection(io_service_, m_config, m_sockets_count, m_pfilter)); + acceptor_.async_accept(new_connection_->socket(), + boost::bind(&boosted_tcp_server::handle_accept, this, + boost::asio::placeholders::error)); + + conn->start(true, 1 < m_threads_count); + }else + { + LOG_ERROR("Some problems at accept: " << e.message() << ", connections_count = " << m_sockets_count); + } + CATCH_ENTRY_L0("boosted_tcp_server::handle_accept", void()); + } + //--------------------------------------------------------------------------------- + template + bool boosted_tcp_server::connect(const std::string& adr, const std::string& port, uint32_t conn_timeout, t_connection_context& conn_context, const std::string& bind_ip) + { + TRY_ENTRY(); + + connection_ptr new_connection_l(new connection(io_service_, m_config, m_sockets_count, m_pfilter) ); + boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket(); + + ////////////////////////////////////////////////////////////////////////// + boost::asio::ip::tcp::resolver resolver(io_service_); + boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), adr, port); + boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query); + boost::asio::ip::tcp::resolver::iterator end; + if(iterator == end) + { + LOG_ERROR("Failed to resolve " << adr); + return false; + } + ////////////////////////////////////////////////////////////////////////// + + + //boost::asio::ip::tcp::endpoint remote_endpoint(boost::asio::ip::address::from_string(addr.c_str()), port); + boost::asio::ip::tcp::endpoint remote_endpoint(*iterator); + + sock_.open(remote_endpoint.protocol()); + if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" ) + { + boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(adr.c_str()), 0); + sock_.bind(local_endpoint); + } + + /* + NOTICE: be careful to make sync connection from event handler: in case if all threads suddenly do sync connect, there will be no thread to dispatch events from io service. + */ + + boost::system::error_code ec = boost::asio::error::would_block; + + //have another free thread(s), work in wait mode, without event handling + struct local_async_context + { + boost::system::error_code ec; + boost::mutex connect_mut; + boost::condition_variable cond; + }; + + boost::shared_ptr local_shared_context(new local_async_context()); + local_shared_context->ec = boost::asio::error::would_block; + boost::unique_lock lock(local_shared_context->connect_mut); + auto connect_callback = [](boost::system::error_code ec_, boost::shared_ptr shared_context) + { + CRITICAL_SECTION_LOCK(shared_context->connect_mut); + shared_context->ec = ec_; + CRITICAL_SECTION_UNLOCK(shared_context->connect_mut); + shared_context->cond.notify_one(); + }; + + sock_.async_connect(remote_endpoint, boost::bind(connect_callback, _1, local_shared_context)); + while(local_shared_context->ec == boost::asio::error::would_block) + { + bool r = false; + try{ + r = local_shared_context->cond.timed_wait(lock, boost::get_system_time() + boost::posix_time::milliseconds(conn_timeout)); + } + catch (...) + { + //timeout + sock_.close(); + LOG_PRINT_L3("timed_wait throwed, " << adr << ":" << port << ", because of timeout (" << conn_timeout << ")"); + return false; + } + if(local_shared_context->ec == boost::asio::error::would_block && !r) + { + //timeout + sock_.close(); + LOG_PRINT_L3("Failed to connect to " << adr << ":" << port << ", because of timeout (" << conn_timeout << ")"); + return false; + } + } + ec = local_shared_context->ec; + + if (ec || !sock_.is_open()) + { + LOG_PRINT("Some problems at connect, message: " << ec.message(), LOG_LEVEL_3); + return false; + } + + LOG_PRINT_L3("Connected success to " << adr << ':' << port); + + bool r = new_connection_l->start(false, 1 < m_threads_count); + if (r) + { + new_connection_l->get_context(conn_context); + //new_connection_l.reset(new connection(io_service_, m_config, m_sockets_count, m_pfilter)); + } + + return r; + + CATCH_ENTRY_L0("boosted_tcp_server::connect", false); + } + //--------------------------------------------------------------------------------- + template template + bool boosted_tcp_server::connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeout, t_callback cb, const std::string& bind_ip) + { + TRY_ENTRY(); + connection_ptr new_connection_l(new connection(io_service_, m_config, m_sockets_count, m_pfilter) ); + boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket(); + + ////////////////////////////////////////////////////////////////////////// + boost::asio::ip::tcp::resolver resolver(io_service_); + boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), adr, port); + boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query); + boost::asio::ip::tcp::resolver::iterator end; + if(iterator == end) + { + LOG_ERROR("Failed to resolve " << adr); + return false; + } + ////////////////////////////////////////////////////////////////////////// + boost::asio::ip::tcp::endpoint remote_endpoint(*iterator); + + sock_.open(remote_endpoint.protocol()); + if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" ) + { + boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(adr.c_str()), 0); + sock_.bind(local_endpoint); + } + + boost::shared_ptr sh_deadline(new boost::asio::deadline_timer(io_service_)); + //start deadline + sh_deadline->expires_from_now(boost::posix_time::milliseconds(conn_timeout)); + sh_deadline->async_wait([=](const boost::system::error_code& error) + { + if(error != boost::asio::error::operation_aborted) + { + LOG_PRINT_L3("Failed to connect to " << adr << ':' << port << ", because of timeout (" << conn_timeout << ")"); + new_connection_l->socket().close(); + } + }); + //start async connect + sock_.async_connect(remote_endpoint, [=](const boost::system::error_code& ec_) + { + t_connection_context conn_context = AUTO_VAL_INIT(conn_context); + boost::system::error_code ignored_ec; + boost::asio::ip::tcp::socket::endpoint_type lep = new_connection_l->socket().local_endpoint(ignored_ec); + if(!ec_) + {//success + if(!sh_deadline->cancel()) + { + cb(conn_context, boost::asio::error::operation_aborted);//this mean that deadline timer already queued callback with cancel operation, rare situation + }else if(new_connection_l->is_shutdown()) + { + //if deadline timer started and finished callback right after async_connect callback is started and before deadline timer sh_deadline->cancel() is called + cb(conn_context, boost::asio::error::operation_aborted); + } + else + { + LOG_PRINT_L3("[sock " << new_connection_l->socket().native_handle() << "] Connected success to " << adr << ':' << port << + " from " << lep.address().to_string() << ':' << lep.port()); + bool r = new_connection_l->start(false, 1 < m_threads_count); + if (r) + { + new_connection_l->get_context(conn_context); + cb(conn_context, ec_); + } + else + { + cb(conn_context, boost::asio::error::fault); + } + } + }else + { + LOG_PRINT_L3("[sock " << new_connection_l->socket().native_handle() << "] Failed to connect to " << adr << ':' << port << + " from " << lep.address().to_string() << ':' << lep.port() << ": " << ec_.message() << ':' << ec_.value()); + cb(conn_context, ec_); + } + }); + return true; + CATCH_ENTRY_L0("boosted_tcp_server::connect_async", false); + } +} +} +POP_WARNINGS diff --git a/contrib/epee/include/net/http_base.h b/contrib/epee/include/net/http_base.h new file mode 100644 index 00000000..49b0839b --- /dev/null +++ b/contrib/epee/include/net/http_base.h @@ -0,0 +1,184 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#pragma once +#include +#include + +#include "string_tools.h" +namespace epee +{ +namespace net_utils +{ + namespace http + { + + enum http_method{ + http_method_get, + http_method_post, + http_method_put, + http_method_head, + http_method_etc, + http_method_unknown + }; + + enum http_content_type + { + http_content_type_text_html, + http_content_type_image_gif, + http_content_type_other, + http_content_type_not_set + }; + + typedef std::list > fields_list; + + inline + std::string get_value_from_fields_list(const std::string& param_name, const net_utils::http::fields_list& fields) + { + fields_list::const_iterator it = fields.begin(); + for(; it != fields.end(); it++) + if(!string_tools::compare_no_case(param_name, it->first)) + break; + + if(it==fields.end()) + return std::string(); + + return it->second; + } + + + inline + std::string get_value_from_uri_line(const std::string& param_name, const std::string& uri) + { + std::string buff = "([\\?|&])"; + buff += param_name + "=([^&]*)"; + boost::regex match_param(buff.c_str(), boost::regex::icase | boost::regex::normal); + boost::smatch result; + if(boost::regex_search(uri, result, match_param, boost::match_default) && result[0].matched) + { + return result[2]; + } + return std::string(); + } + + + + struct http_header_info + { + std::string m_connection; //"Connection:" + std::string m_referer; //"Referer:" + std::string m_content_length; //"Content-Length:" + std::string m_content_type; //"Content-Type:" + std::string m_transfer_encoding;//"Transfer-Encoding:" + std::string m_content_encoding; //"Content-Encoding:" + std::string m_host; //"Host:" + std::string m_cookie; //"Cookie:" + fields_list m_etc_fields; + + void clear() + { + m_connection.clear(); + m_referer.clear(); + m_content_length.clear(); + m_content_type.clear(); + m_transfer_encoding.clear(); + m_content_encoding.clear(); + m_host.clear(); + m_cookie.clear(); + m_etc_fields.clear(); + } + }; + + struct uri_content + { + std::string m_path; + std::string m_query; + std::string m_fragment; + std::list > m_query_params; + }; + + struct url_content + { + std::string schema; + std::string host; + std::string uri; + uint64_t port; + uri_content m_uri_content; + }; + + + struct http_request_info + { + http_request_info():m_http_method(http_method_unknown), + m_http_ver_hi(0), + m_http_ver_lo(0), + m_have_to_block(false) + {} + + http_method m_http_method; + std::string m_URI; + std::string m_http_method_str; + std::string m_full_request_str; + std::string m_replace_html; + std::string m_request_head; + int m_http_ver_hi; + int m_http_ver_lo; + bool m_have_to_block; + http_header_info m_header_info; + uri_content m_uri_content; + size_t m_full_request_buf_size; + std::string m_body; + + void clear() + { + this->~http_request_info(); + new(this) http_request_info(); + } + }; + + + struct http_response_info + { + int m_response_code; + std::string m_response_comment; + fields_list m_additional_fields; + std::string m_body; + std::string m_mime_tipe; + http_header_info m_header_info; + int m_http_ver_hi;// OUT paramter only + int m_http_ver_lo;// OUT paramter only + + void clear() + { + this->~http_response_info(); + new(this) http_response_info(); + } + }; + } +} +} \ No newline at end of file diff --git a/contrib/epee/include/net/http_client.h b/contrib/epee/include/net/http_client.h new file mode 100644 index 00000000..7de1f153 --- /dev/null +++ b/contrib/epee/include/net/http_client.h @@ -0,0 +1,882 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#pragma once +#include +#include +#include +//#include +#include +#include +#include + +#include "net_helper.h" +#include "http_client_base.h" + +#ifdef HTTP_ENABLE_GZIP +#include "gzip_encoding.h" +#endif + +#include "string_tools.h" +#include "reg_exp_definer.h" +#include "http_base.h" +#include "to_nonconst_iterator.h" +#include "net_parse_helpers.h" + +//#include "shlwapi.h" + +//#pragma comment(lib, "shlwapi.lib") + +extern epee::critical_section gregexp_lock; + + +namespace epee +{ +namespace net_utils +{ + +using namespace std; + + /*struct url + { + public: + void parse(const std::string& url_s) + { + const string prot_end("://"); + string::const_iterator prot_i = search(url_s.begin(), url_s.end(), + prot_end.begin(), prot_end.end()); + protocol_.reserve(distance(url_s.begin(), prot_i)); + transform(url_s.begin(), prot_i, + back_inserter(protocol_), + ptr_fun(tolower)); // protocol is icase + if( prot_i == url_s.end() ) + return; + advance(prot_i, prot_end.length()); + string::const_iterator path_i = find(prot_i, url_s.end(), '/'); + host_.reserve(distance(prot_i, path_i)); + transform(prot_i, path_i, + back_inserter(host_), + ptr_fun(tolower)); // host is icase + string::const_iterator query_i = find(path_i, url_s.end(), '?'); + path_.assign(path_i, query_i); + if( query_i != url_s.end() ) + ++query_i; + query_.assign(query_i, url_s.end()); + } + + std::string protocol_; + std::string host_; + std::string path_; + std::string query_; + };*/ + + + + + //--------------------------------------------------------------------------- + static inline const char* get_hex_vals() + { + static char hexVals[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + return hexVals; + } + + static inline const char* get_unsave_chars() + { + //static char unsave_chars[] = "\"<>%\\^[]`+$,@:;/!#?=&"; + static char unsave_chars[] = "\"<>%\\^[]`+$,@:;!#&"; + return unsave_chars; + } + + static inline bool is_unsafe(unsigned char compare_char) + { + if(compare_char <= 32 || compare_char >= 123) + return true; + + const char* punsave = get_unsave_chars(); + + for(int ichar_pos = 0; 0!=punsave[ichar_pos] ;ichar_pos++) + if(compare_char == punsave[ichar_pos]) + return true; + + return false; + } + + static inline + std::string dec_to_hex(char num, int radix) + { + int temp=0; + std::string csTmp; + int num_char; + + num_char = (int) num; + if (num_char < 0) + num_char = 256 + num_char; + + while (num_char >= radix) + { + temp = num_char % radix; + num_char = (int)floor((float)num_char / (float)radix); + csTmp = get_hex_vals()[temp]; + } + + csTmp += get_hex_vals()[num_char]; + + if(csTmp.size() < 2) + { + csTmp += '0'; + } + + std::reverse(csTmp.begin(), csTmp.end()); + //_mbsrev((unsigned char*)csTmp.data()); + + return csTmp; + } + + static inline std::string convert(char val) + { + std::string csRet; + csRet += "%"; + csRet += dec_to_hex(val, 16); + return csRet; + } + static inline std::string conver_to_url_format(const std::string& uri) + { + + std::string result; + + for(size_t i = 0; i!= uri.size(); i++) + { + if(is_unsafe(uri[i])) + result += convert(uri[i]); + else + result += uri[i]; + + } + + return result; + } + + static inline std::string convert_to_url_format_force_all(const std::string& uri) + { + + std::string result; + + for(size_t i = 0; i!= uri.size(); i++) + { + result += convert(uri[i]); + } + + return result; + } + + + + + + namespace http + { + + class http_simple_client: public i_target_handler + { + public: + + + private: + enum reciev_machine_state + { + reciev_machine_state_header, + reciev_machine_state_body_content_len, + reciev_machine_state_body_connection_close, + reciev_machine_state_body_chunked, + reciev_machine_state_done, + reciev_machine_state_error + }; + + + + enum chunked_state{ + http_chunked_state_chunk_head, + http_chunked_state_chunk_body, + http_chunked_state_done, + http_chunked_state_undefined + }; + + + blocked_mode_client m_net_client; + std::string m_host_buff; + std::string m_port; + unsigned int m_timeout; + std::string m_header_cache; + http_response_info m_response_info; + size_t m_len_in_summary; + size_t m_len_in_remain; + //std::string* m_ptarget_buffer; + boost::shared_ptr m_pcontent_encoding_handler; + reciev_machine_state m_state; + chunked_state m_chunked_state; + std::string m_chunked_cache; + critical_section m_lock; + + public: + void set_host_name(const std::string& name) + { + CRITICAL_REGION_LOCAL(m_lock); + m_host_buff = name; + } + + boost::asio::ip::tcp::socket& get_socket() + { + return m_net_client.get_socket(); + } + + + bool connect(const std::string& host, int port, unsigned int timeout) + { + return connect(host, std::to_string(port), timeout); + } + bool connect(const std::string& host, const std::string& port, unsigned int timeout) + { + CRITICAL_REGION_LOCAL(m_lock); + m_host_buff = host; + m_port = port; + m_timeout = timeout; + + return m_net_client.connect(host, port, timeout, timeout); + } + //--------------------------------------------------------------------------- + bool disconnect() + { + CRITICAL_REGION_LOCAL(m_lock); + return m_net_client.disconnect(); + } + //--------------------------------------------------------------------------- + bool is_connected() + { + CRITICAL_REGION_LOCAL(m_lock); + return m_net_client.is_connected(); + } + //--------------------------------------------------------------------------- + virtual bool handle_target_data(std::string& piece_of_transfer) + { + CRITICAL_REGION_LOCAL(m_lock); + m_response_info.m_body += piece_of_transfer; + piece_of_transfer.clear(); + return true; + } + //--------------------------------------------------------------------------- + inline + bool invoke_get(const std::string& uri, const std::string& body = std::string(), const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) + { + CRITICAL_REGION_LOCAL(m_lock); + return invoke(uri, "GET", body, ppresponse_info, additional_params); + } + + //--------------------------------------------------------------------------- + inline bool invoke(const std::string& uri, const std::string& method, const std::string& body, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) + { + CRITICAL_REGION_LOCAL(m_lock); + if(!is_connected()) + { + LOG_PRINT("Reconnecting...", LOG_LEVEL_3); + if(!connect(m_host_buff, m_port, m_timeout)) + { + LOG_PRINT("Failed to connect to " << m_host_buff << ":" << m_port, LOG_LEVEL_3); + return false; + } + } + m_response_info.clear(); + std::string req_buff = method + " "; + req_buff += uri + " HTTP/1.1\r\n" + + "Host: "+ m_host_buff +"\r\n" + "Content-Length: " + boost::lexical_cast(body.size()) + "\r\n"; + + + //handle "additional_params" + for(fields_list::const_iterator it = additional_params.begin(); it!=additional_params.end(); it++) + req_buff += it->first + ": " + it->second + "\r\n"; + req_buff += "\r\n"; + //-- + + bool res = m_net_client.send(req_buff); + CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND"); + if(body.size()) + res = m_net_client.send(body); + CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND"); + + if(ppresponse_info) + *ppresponse_info = &m_response_info; + + m_state = reciev_machine_state_header; + return handle_reciev(); + } + //--------------------------------------------------------------------------- + inline bool invoke_post(const std::string& uri, const std::string& body, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) + { + CRITICAL_REGION_LOCAL(m_lock); + return invoke(uri, "POST", body, ppresponse_info, additional_params); + } + private: + //--------------------------------------------------------------------------- + inline bool handle_reciev() + { + CRITICAL_REGION_LOCAL(m_lock); + bool keep_handling = true; + bool need_more_data = true; + std::string recv_buffer; + while(keep_handling) + { + if(need_more_data) + { + if(!m_net_client.recv(recv_buffer)) + { + LOG_PRINT("Unexpected reciec fail", LOG_LEVEL_3); + m_state = reciev_machine_state_error; + } + if(!recv_buffer.size()) + { + //connection is going to be closed + if(reciev_machine_state_body_connection_close != m_state) + { + m_state = reciev_machine_state_error; + } + } + need_more_data = false; + } + switch(m_state) + { + case reciev_machine_state_header: + keep_handling = handle_header(recv_buffer, need_more_data); + break; + case reciev_machine_state_body_content_len: + keep_handling = handle_body_content_len(recv_buffer, need_more_data); + break; + case reciev_machine_state_body_connection_close: + keep_handling = handle_body_connection_close(recv_buffer, need_more_data); + break; + case reciev_machine_state_body_chunked: + keep_handling = handle_body_body_chunked(recv_buffer, need_more_data); + break; + case reciev_machine_state_done: + keep_handling = false; + break; + case reciev_machine_state_error: + keep_handling = false; + break; + } + + } + m_header_cache.clear(); + if(m_state != reciev_machine_state_error) + { + if(m_response_info.m_header_info.m_connection.size() && !string_tools::compare_no_case("close", m_response_info.m_header_info.m_connection)) + disconnect(); + + return true; + } + else + { + LOG_PRINT_L3("Returning false because of wrong state machine. state: " << m_state); + return false; + } + } + //--------------------------------------------------------------------------- + inline + bool handle_header(std::string& recv_buff, bool& need_more_data) + { + + CRITICAL_REGION_LOCAL(m_lock); + if(!recv_buff.size()) + { + LOG_ERROR("Connection closed at handle_header"); + m_state = reciev_machine_state_error; + return false; + } + + m_header_cache += recv_buff; + recv_buff.clear(); + std::string::size_type pos = m_header_cache.find("\r\n\r\n"); + if(pos != std::string::npos) + { + recv_buff.assign(m_header_cache.begin()+pos+4, m_header_cache.end()); + m_header_cache.erase(m_header_cache.begin()+pos+4, m_header_cache.end()); + + analize_cached_header_and_invoke_state(); + m_header_cache.clear(); + if(!recv_buff.size() && (m_state != reciev_machine_state_error && m_state != reciev_machine_state_done)) + need_more_data = true; + + return true; + }else + need_more_data = true; + return true; + } + //--------------------------------------------------------------------------- + inline + bool handle_body_content_len(std::string& recv_buff, bool& need_more_data) + { + CRITICAL_REGION_LOCAL(m_lock); + if(!recv_buff.size()) + { + LOG_PRINT("Warning: Content-Len mode, but connection unexpectedly closed", LOG_LEVEL_3); + m_state = reciev_machine_state_done; + return true; + } + CHECK_AND_ASSERT_MES(m_len_in_remain >= recv_buff.size(), false, "m_len_in_remain >= recv_buff.size()"); + m_len_in_remain -= recv_buff.size(); + m_pcontent_encoding_handler->update_in(recv_buff); + + if(m_len_in_remain == 0) + m_state = reciev_machine_state_done; + else + need_more_data = true; + + return true; + } + //--------------------------------------------------------------------------- + inline + bool handle_body_connection_close(std::string& recv_buff, bool& need_more_data) + { + CRITICAL_REGION_LOCAL(m_lock); + if(!recv_buff.size()) + { + m_state = reciev_machine_state_done; + return true; + } + need_more_data = true; + m_pcontent_encoding_handler->update_in(recv_buff); + + + return true; + } + //--------------------------------------------------------------------------- + inline bool is_hex_symbol(char ch) + { + + if( (ch >= '0' && ch <='9')||(ch >= 'A' && ch <='F')||(ch >= 'a' && ch <='f')) + return true; + else + return false; + } + //--------------------------------------------------------------------------- + inline + bool get_len_from_chunk_head(const std::string &chunk_head, size_t& result_size) + { + std::stringstream str_stream; + str_stream << std::hex; + if(!(str_stream << chunk_head && str_stream >> result_size)) + return false; + + return true; + } + //--------------------------------------------------------------------------- + inline + bool get_chunk_head(std::string& buff, size_t& chunk_size, bool& is_matched) + { + is_matched = false; + size_t offset = 0; + for(std::string::iterator it = buff.begin(); it!= buff.end(); it++, offset++) + { + if(!is_hex_symbol(*it)) + { + if(*it == '\r' || *it == ' ' ) + { + offset--; + continue; + } + else if(*it == '\n') + { + std::string chunk_head = buff.substr(0, offset); + if(!get_len_from_chunk_head(chunk_head, chunk_size)) + return false; + + if(0 == chunk_size) + { + //Here is a small confusion + //In breif - if the chunk is the last one we need to get terminating sequence + //along with the cipher, generally in the "ddd\r\n\r\n" form + + for(it++;it != buff.end(); it++) + { + if('\r' == *it) + continue; + else if('\n' == *it) + break; + else + { + LOG_ERROR("http_stream_filter: Wrong last chunk terminator"); + return false; + } + } + + if(it == buff.end()) + return true; + } + + buff.erase(buff.begin(), ++it); + + is_matched = true; + return true; + } + else + return false; + } + } + + return true; + } + //--------------------------------------------------------------------------- + inline + bool handle_body_body_chunked(std::string& recv_buff, bool& need_more_data) + { + CRITICAL_REGION_LOCAL(m_lock); + if(!recv_buff.size()) + { + LOG_PRINT("Warning: CHUNKED mode, but connection unexpectedly closed", LOG_LEVEL_3); + m_state = reciev_machine_state_done; + return true; + } + m_chunked_cache += recv_buff; + recv_buff.clear(); + bool is_matched = false; + + while(true) + { + if(!m_chunked_cache.size()) + { + need_more_data = true; + break; + } + + switch(m_chunked_state) + { + case http_chunked_state_chunk_head: + if(m_chunked_cache[0] == '\n' || m_chunked_cache[0] == '\r') + { + //optimize a bit + if(m_chunked_cache[0] == '\r' && m_chunked_cache.size()>1 && m_chunked_cache[1] == '\n') + m_chunked_cache.erase(0, 2); + else + m_chunked_cache.erase(0, 1); + break; + } + if(!get_chunk_head(m_chunked_cache, m_len_in_remain, is_matched)) + { + LOG_ERROR("http_stream_filter::handle_chunked(*) Failed to get length from chunked head:" << m_chunked_cache); + m_state = reciev_machine_state_error; + return false; + } + + if(!is_matched) + { + need_more_data = true; + return true; + }else + { + m_chunked_state = http_chunked_state_chunk_body; + if(m_len_in_remain == 0) + {//last chunk, let stop the stream and fix the chunk queue. + m_state = reciev_machine_state_done; + return true; + } + m_chunked_state = http_chunked_state_chunk_body; + break; + } + break; + case http_chunked_state_chunk_body: + { + std::string chunk_body; + if(m_len_in_remain >= m_chunked_cache.size()) + { + m_len_in_remain -= m_chunked_cache.size(); + chunk_body.swap(m_chunked_cache); + }else + { + chunk_body.assign(m_chunked_cache, 0, m_len_in_remain); + m_chunked_cache.erase(0, m_len_in_remain); + m_len_in_remain = 0; + } + + m_pcontent_encoding_handler->update_in(chunk_body); + + if(!m_len_in_remain) + m_chunked_state = http_chunked_state_chunk_head; + } + break; + case http_chunked_state_done: + m_state = reciev_machine_state_done; + return true; + case http_chunked_state_undefined: + default: + LOG_ERROR("http_stream_filter::handle_chunked(): Wrong state" << m_chunked_state); + return false; + } + } + + return true; + } + //--------------------------------------------------------------------------- + inline + bool parse_header(http_header_info& body_info, const std::string& m_cache_to_process) + { + LOG_FRAME("http_stream_filter::parse_cached_header(*)", LOG_LEVEL_4); + + STATIC_REGEXP_EXPR_1(rexp_mach_field, + "\n?((Connection)|(Referer)|(Content-Length)|(Content-Type)|(Transfer-Encoding)|(Content-Encoding)|(Host)|(Cookie)" + // 12 3 4 5 6 7 8 9 + "|([\\w-]+?)) ?: ?((.*?)(\r?\n))[^\t ]", + //10 1112 13 + boost::regex::icase | boost::regex::normal); + + boost::smatch result; + std::string::const_iterator it_current_bound = m_cache_to_process.begin(); + std::string::const_iterator it_end_bound = m_cache_to_process.end(); + + + + //lookup all fields and fill well-known fields + while( boost::regex_search( it_current_bound, it_end_bound, result, rexp_mach_field, boost::match_default) && result[0].matched) + { + const size_t field_val = 12; + //const size_t field_etc_name = 10; + + int i = 2; //start position = 2 + if(result[i++].matched)//"Connection" + body_info.m_connection = result[field_val]; + else if(result[i++].matched)//"Referrer" + body_info.m_referer = result[field_val]; + else if(result[i++].matched)//"Content-Length" + body_info.m_content_length = result[field_val]; + else if(result[i++].matched)//"Content-Type" + body_info.m_content_type = result[field_val]; + else if(result[i++].matched)//"Transfer-Encoding" + body_info.m_transfer_encoding = result[field_val]; + else if(result[i++].matched)//"Content-Encoding" + body_info.m_content_encoding = result[field_val]; + else if(result[i++].matched)//"Host" + { body_info.m_host = result[field_val]; + string_tools::trim(body_info.m_host); + } + else if(result[i++].matched)//"Cookie" + body_info.m_cookie = result[field_val]; + else if(result[i++].matched)//e.t.c (HAVE TO BE MATCHED!) + {;} + else + {CHECK_AND_ASSERT_MES(false, false, "http_stream_filter::parse_cached_header() not matched last entry in:"<(result[1]); + m_response_info.m_http_ver_lo = boost::lexical_cast(result[2]); + m_response_info.m_response_code = boost::lexical_cast(result[3]); + + m_header_cache.erase(to_nonsonst_iterator(m_header_cache, result[0].first), to_nonsonst_iterator(m_header_cache, result[0].second)); + return true; + }else + { + LOG_ERROR("http_stream_filter::handle_invoke_reply_line(): Failed to match first response line:" << m_header_cache); + return false; + } + + } + inline + bool set_reply_content_encoder() + { + STATIC_REGEXP_EXPR_1(rexp_match_gzip, "^.*?((gzip)|(deflate))", boost::regex::icase | boost::regex::normal); + boost::smatch result; // 12 3 + if(boost::regex_search( m_response_info.m_header_info.m_content_encoding, result, rexp_match_gzip, boost::match_default) && result[0].matched) + { +#ifdef HTTP_ENABLE_GZIP + m_pcontent_encoding_handler.reset(new content_encoding_gzip(this, result[3].matched)); +#else + m_pcontent_encoding_handler.reset(new do_nothing_sub_handler(this)); + LOG_ERROR("GZIP encoding not supported in this build, please add zlib to your project and define HTTP_ENABLE_GZIP"); + return false; +#endif + } + else + { + m_pcontent_encoding_handler.reset(new do_nothing_sub_handler(this)); + } + + return true; + } + inline + bool analize_cached_header_and_invoke_state() + { + m_response_info.clear(); + analize_first_response_line(); + std::string fake_str; //gcc error workaround + + bool res = parse_header(m_response_info.m_header_info, m_header_cache); + CHECK_AND_ASSERT_MES(res, false, "http_stream_filter::analize_cached_reply_header_and_invoke_state(): failed to anilize reply header: " << m_header_cache); + + set_reply_content_encoder(); + + m_len_in_summary = 0; + bool content_len_valid = false; + if(m_response_info.m_header_info.m_content_length.size()) + content_len_valid = string_tools::get_xtype_from_string(m_len_in_summary, m_response_info.m_header_info.m_content_length); + + + + if(!m_len_in_summary && ((m_response_info.m_response_code>=100&&m_response_info.m_response_code<200) + || 204 == m_response_info.m_response_code + || 304 == m_response_info.m_response_code) ) + {//There will be no response body, server will display the local page with error + m_state = reciev_machine_state_done; + return true; + }else if(m_response_info.m_header_info.m_transfer_encoding.size()) + { + string_tools::trim(m_response_info.m_header_info.m_transfer_encoding); + if(string_tools::compare_no_case(m_response_info.m_header_info.m_transfer_encoding, "chunked")) + { + LOG_ERROR("Wrong Transfer-Encoding:" << m_response_info.m_header_info.m_transfer_encoding); + m_state = reciev_machine_state_error; + return false; + } + m_state = reciev_machine_state_body_chunked; + m_chunked_state = http_chunked_state_chunk_head; + return true; + } + else if(!m_response_info.m_header_info.m_content_length.empty()) + { + //In the response header the length was specified + if(!content_len_valid) + { + LOG_ERROR("http_stream_filter::analize_cached_reply_header_and_invoke_state(): Failed to get_len_from_content_lenght();, m_query_info.m_content_length="<(u_c.port), timeout); + CHECK_AND_ASSERT_MES(res, false, "failed to connect " << u_c.host << ":" << u_c.port); + } + + return tr.invoke(u_c.uri, method, body, ppresponse_info, additional_params); + } + + } +} +} diff --git a/contrib/epee/include/net/http_client_abstract_invoke.h b/contrib/epee/include/net/http_client_abstract_invoke.h new file mode 100644 index 00000000..425a355e --- /dev/null +++ b/contrib/epee/include/net/http_client_abstract_invoke.h @@ -0,0 +1,98 @@ + +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + +#pragma once +#include "storages/serializeble_struct_helper.h" + +namespace epee +{ + namespace net_utils + { + namespace http + { + template + bool invoke_http_json_remote_command(const std::string& url, TArg& out_struct, TResult& result_struct, TTransport& transport, unsigned int timeout = 5000, const std::string& method = "GET") + { + std::string req_param; + StorageNamed::InMemStorageSpace::json::store_t_to_json(out_struct, req_param); + + const http_response_info* pri = NULL; + if(!invoke_request(url, transport, timeout, &pri, method, req_param)) + { + LOG_PRINT_L1("Failed to invoke http request to " << url); + return false; + } + + if(!pri->m_response_code) + { + LOG_PRINT_L1("Failed to invoke http request to " << url << ", internal error (null response ptr)"); + return false; + } + + if(pri->m_response_code != 200) + { + LOG_PRINT_L1("Failed to invoke http request to " << url << ", wrong response code: " << pri->m_response_code); + return false; + } + + return StorageNamed::InMemStorageSpace::json::load_t_from_json(result_struct, pri->m_body); + } + + + + template + bool invoke_http_bin_remote_command(const std::string& url, TArg& out_struct, TResult& result_struct, TTransport& transport, unsigned int timeout = 5000, const std::string& method = "GET") + { + std::string req_param; + epee::StorageNamed::save_struct_as_storage_to_buff(out_struct, req_param); + + const http_response_info* pri = NULL; + if(!invoke_request(url, transport, timeout, &pri, method, req_param)) + { + LOG_PRINT_L1("Failed to invoke http request to " << url); + return false; + } + + if(!pri->m_response_code) + { + LOG_PRINT_L1("Failed to invoke http request to " << url << ", internal error (null response ptr)"); + return false; + } + + if(pri->m_response_code != 200) + { + LOG_PRINT_L1("Failed to invoke http request to " << url << ", wrong response code: " << pri->m_response_code); + return false; + } + + return epee::StorageNamed::load_struct_from_storage_buff(result_struct, pri->m_body); + } + + + } + } +} diff --git a/contrib/epee/include/net/http_client_base.h b/contrib/epee/include/net/http_client_base.h new file mode 100644 index 00000000..571e27f7 --- /dev/null +++ b/contrib/epee/include/net/http_client_base.h @@ -0,0 +1,73 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + +#pragma once + +namespace epee +{ + namespace net_utils + { + struct i_sub_handler + { + virtual ~i_sub_handler(){} + + virtual bool update_in( std::string& piece_of_transfer)=0; + virtual void stop(std::string& OUT collect_remains)=0; + virtual bool update_and_stop(std::string& OUT collect_remains, bool& is_changed) + { + is_changed = true; + bool res = this->update_in(collect_remains); + if(res) + this->stop(collect_remains); + return res; + } + }; + + + struct i_target_handler + { + virtual ~i_target_handler(){} + virtual bool handle_target_data( std::string& piece_of_transfer)=0; + }; + + + class do_nothing_sub_handler: public i_sub_handler + { + public: + do_nothing_sub_handler(i_target_handler* powner_filter):m_powner_filter(powner_filter) + {} + virtual bool update_in( std::string& piece_of_transfer) + { + return m_powner_filter->handle_target_data(piece_of_transfer); + } + virtual void stop(std::string& OUT collect_remains) + { + + } + i_target_handler* m_powner_filter; + }; + } +} \ No newline at end of file diff --git a/contrib/epee/include/net/http_client_via_api_helper.h b/contrib/epee/include/net/http_client_via_api_helper.h new file mode 100644 index 00000000..45a70993 --- /dev/null +++ b/contrib/epee/include/net/http_client_via_api_helper.h @@ -0,0 +1,177 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + + +#pragma once +#include +#include +#pragma comment(lib, "Wininet.lib") + +namespace epee +{ +namespace net_utils +{ + inline + bool http_ssl_invoke(const std::string& url, const std::string usr, const std::string psw, std::string& http_response_body, bool use_post = false) + { + bool final_res = false; + + ATL::CUrl url_obj; + BOOL crack_rss = url_obj.CrackUrl(string_encoding::convert_to_t >(url).c_str()); + + HINTERNET hinet = ::InternetOpenA(SHARED_JOBSCOMMON_HTTP_AGENT, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); + if(!hinet) + { + int err = ::GetLastError(); + LOG_PRINT("Failed to call InternetOpenA, \nError: " << err << " " << log_space::get_win32_err_descr(err), LOG_LEVEL_0); + return false; + } + + DWORD dwFlags = 0; + DWORD dwBuffLen = sizeof(dwFlags); + + if(usr.size()) + { + dwFlags |= INTERNET_FLAG_IGNORE_CERT_CN_INVALID|INTERNET_FLAG_IGNORE_CERT_DATE_INVALID| + INTERNET_FLAG_PRAGMA_NOCACHE | SECURITY_FLAG_IGNORE_UNKNOWN_CA|INTERNET_FLAG_SECURE; + }else + { + dwFlags |= INTERNET_FLAG_PRAGMA_NOCACHE; + } + + + int port = url_obj.GetPortNumber(); + BOOL res = FALSE; + + HINTERNET hsession = ::InternetConnectA(hinet, string_encoding::convert_to_ansii(url_obj.GetHostName()).c_str(), port/*INTERNET_DEFAULT_HTTPS_PORT*/, usr.c_str(), psw.c_str(), INTERNET_SERVICE_HTTP, dwFlags, NULL); + if(hsession) + { + const std::string uri = string_encoding::convert_to_ansii(url_obj.GetUrlPath()) + string_encoding::convert_to_ansii(url_obj.GetExtraInfo()); + + HINTERNET hrequest = ::HttpOpenRequestA(hsession, use_post?"POST":NULL, uri.c_str(), NULL, NULL,NULL, dwFlags, NULL); + if(hrequest) + { + while(true) + { + res = ::HttpSendRequestA(hrequest, NULL, 0, NULL, 0); + if(!res) + { + //ERROR_INTERNET_INVALID_CA 45 + //ERROR_INTERNET_INVALID_URL (INTERNET_ERROR_BASE + 5) + int err = ::GetLastError(); + LOG_PRINT("Failed to call HttpSendRequestA, \nError: " << log_space::get_win32_err_descr(err), LOG_LEVEL_0); + break; + } + + DWORD code = 0; + DWORD buf_len = sizeof(code); + DWORD index = 0; + res = ::HttpQueryInfo(hrequest, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, &code, &buf_len, &index); + if(!res) + { + //ERROR_INTERNET_INVALID_CA 45 + //ERROR_INTERNET_INVALID_URL (INTERNET_ERROR_BASE + 5) + int err = ::GetLastError(); + LOG_PRINT("Failed to call HttpQueryInfo, \nError: " << log_space::get_win32_err_descr(err), LOG_LEVEL_0); + break; + } + if(code < 200 || code > 299) + { + LOG_PRINT("Wrong server response, HttpQueryInfo returned statuse code" << code , LOG_LEVEL_0); + break; + } + + + char buff[100000] = {0}; + DWORD readed = 0; + while(true) + { + res = ::InternetReadFile(hrequest, buff, sizeof(buff), &readed); + if(!res) + { + int err = ::GetLastError(); + LOG_PRINT("Failed to call InternetReadFile, \nError: " << log_space::get_win32_err_descr(err), LOG_LEVEL_0); + break; + } + if(readed) + { + http_response_body.append(buff, readed); + } + else + break; + } + + if(!res) + break; + + + //we success + final_res = true; + + res = ::InternetCloseHandle(hrequest); + if(!res) + { + int err = ::GetLastError(); + LOG_PRINT("Failed to call InternetCloseHandle, \nError: " << log_space::get_win32_err_descr(err), LOG_LEVEL_0); + } + + break; + } + } + else + { + //ERROR_INTERNET_INVALID_CA + int err = ::GetLastError(); + LOG_PRINT("Failed to call InternetOpenUrlA, \nError: " << log_space::get_win32_err_descr(err), LOG_LEVEL_0); + return false; + } + + res = ::InternetCloseHandle(hsession); + if(!res) + { + int err = ::GetLastError(); + LOG_PRINT("Failed to call InternetCloseHandle, \nError: " << log_space::get_win32_err_descr(err), LOG_LEVEL_0); + } + }else + { + int err = ::GetLastError(); + LOG_PRINT("Failed to call InternetConnectA(" << string_encoding::convert_to_ansii(url_obj.GetHostName()) << ", port " << port << " \nError: " << log_space::get_win32_err_descr(err), LOG_LEVEL_0); + } + + + + res = ::InternetCloseHandle(hinet); + if(!res) + { + int err = ::GetLastError(); + LOG_PRINT("Failed to call InternetCloseHandle, \nError: " << log_space::get_win32_err_descr(err), LOG_LEVEL_0); + } + return final_res; + } +} +} \ No newline at end of file diff --git a/contrib/epee/include/net/http_protocol_handler.h b/contrib/epee/include/net/http_protocol_handler.h new file mode 100644 index 00000000..569b6128 --- /dev/null +++ b/contrib/epee/include/net/http_protocol_handler.h @@ -0,0 +1,213 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + + +#ifndef _HTTP_SERVER_H_ +#define _HTTP_SERVER_H_ + +#include +#include "net_utils_base.h" +#include "to_nonconst_iterator.h" +#include "http_base.h" + +namespace epee +{ +namespace net_utils +{ + namespace http + { + + + /************************************************************************/ + /* */ + /************************************************************************/ + struct http_server_config + { + void on_send_stop_signal(){} + std::string m_folder; + critical_section m_lock; + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + template + class simple_http_connection_handler + { + public: + typedef t_connection_context connection_context;//t_connection_context net_utils::connection_context_base connection_context; + typedef http_server_config config_type; + + simple_http_connection_handler(i_service_endpoint* psnd_hndlr, config_type& config); + virtual ~simple_http_connection_handler(){} + + bool release_protocol() + { + return true; + } + + virtual bool thread_init() + { + return true; + } + + virtual bool thread_deinit() + { + return true; + } + bool after_init_connection() + { + return true; + } + virtual bool handle_recv(const void* ptr, size_t cb); + virtual bool handle_request(const http::http_request_info& query_info, http_response_info& response); + + + //temporary here + //bool parse_uri(const std::string uri, uri_content& content); + + private: + enum machine_state{ + http_state_retriving_comand_line, + http_state_retriving_header, + http_state_retriving_body, + http_state_connection_close, + http_state_error + }; + + enum body_transfer_type{ + http_body_transfer_chunked, + http_body_transfer_measure,//mean "Content-Length" valid + http_body_transfer_chunked_instead_measure, + http_body_transfer_connection_close, + http_body_transfer_multipart, + http_body_transfer_undefined + }; + + bool handle_buff_in(std::string& buf); + + bool analize_cached_request_header_and_invoke_state(size_t pos); + + bool handle_invoke_query_line(); + bool parse_cached_header(http_header_info& body_info, const std::string& m_cache_to_process, size_t pos); + std::string::size_type match_end_of_header(const std::string& buf); + bool get_len_from_content_lenght(const std::string& str, size_t& len); + bool handle_retriving_query_body(); + bool handle_query_measure(); + bool set_ready_state(); + bool slash_to_back_slash(std::string& str); + std::string get_file_mime_tipe(const std::string& path); + std::string get_response_header(const http_response_info& response); + + //major function + inline bool handle_request_and_send_response(const http::http_request_info& query_info); + + + std::string get_not_found_response_body(const std::string& URI); + + std::string m_root_path; + std::string m_cache; + machine_state m_state; + body_transfer_type m_body_transfer_type; + bool m_is_stop_handling; + http::http_request_info m_query_info; + size_t m_len_summary, m_len_remain; + config_type& m_config; + bool m_want_close; + protected: + i_service_endpoint* m_psnd_hndlr; + }; + + template + struct i_http_server_handler + { + virtual ~i_http_server_handler(){} + virtual bool handle_http_request(const http_request_info& query_info, http_response_info& response, t_connection_context& m_conn_context)=0; + virtual bool init_server_thread(){return true;} + virtual bool deinit_server_thread(){return true;} + }; + + template + struct custum_handler_config: public http_server_config + { + i_http_server_handler* m_phandler; + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + + template + class http_custom_handler: public simple_http_connection_handler + { + public: + typedef custum_handler_config config_type; + + http_custom_handler(i_service_endpoint* psnd_hndlr, config_type& config, t_connection_context& conn_context):simple_http_connection_handler(psnd_hndlr, config), + m_config(config), + m_conn_context(conn_context) + {} + inline bool handle_request(const http_request_info& query_info, http_response_info& response) + { + CHECK_AND_ASSERT_MES(m_config.m_phandler, false, "m_config.m_phandler is NULL!!!!"); + //fill with default values + response.m_mime_tipe = "text/plain"; + response.m_response_code = 200; + response.m_response_comment = "OK"; + response.m_body.clear(); + return m_config.m_phandler->handle_http_request(query_info, response, m_conn_context); + } + + virtual bool thread_init() + { + return m_config.m_phandler->init_server_thread();; + } + + virtual bool thread_deinit() + { + return m_config.m_phandler->deinit_server_thread(); + } + void handle_qued_callback() + {} + bool after_init_connection() + { + return true; + } + + private: + //simple_http_connection_handler::config_type m_stub_config; + config_type& m_config; + t_connection_context& m_conn_context; + }; + } +} +} + +#include "http_protocol_handler.inl" + +#endif //_HTTP_SERVER_H_ diff --git a/contrib/epee/include/net/http_protocol_handler.inl b/contrib/epee/include/net/http_protocol_handler.inl new file mode 100644 index 00000000..d981cdc8 --- /dev/null +++ b/contrib/epee/include/net/http_protocol_handler.inl @@ -0,0 +1,685 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + +#include +#include +#include "http_protocol_handler.h" +#include "reg_exp_definer.h" +#include "string_tools.h" +#include "file_io_utils.h" +#include "net_parse_helpers.h" + +#define HTTP_MAX_URI_LEN 9000 +#define HTTP_MAX_HEADER_LEN 100000 + +PUSH_WARNINGS +DISABLE_GCC_WARNING(maybe-uninitialized) + + +namespace epee +{ +namespace net_utils +{ + namespace http + { + + struct multipart_entry + { + std::list > m_etc_header_fields; + std::string m_content_disposition; + std::string m_content_type; + std::string m_body; + }; + + inline + bool match_boundary(const std::string& content_type, std::string& boundary) + { + STATIC_REGEXP_EXPR_1(rexp_match_boundary, "boundary=(.*?)(($)|([;\\s,]))", boost::regex::icase | boost::regex::normal); + // 1 + boost::smatch result; + if(boost::regex_search(content_type, result, rexp_match_boundary, boost::match_default) && result[0].matched) + { + boundary = result[1]; + return true; + } + + return false; + } + + inline + bool parse_header(std::string::const_iterator it_begin, std::string::const_iterator it_end, multipart_entry& entry) + { + STATIC_REGEXP_EXPR_1(rexp_mach_field, + "\n?((Content-Disposition)|(Content-Type)" + // 12 3 + "|([\\w-]+?)) ?: ?((.*?)(\r?\n))[^\t ]", + //4 56 7 + boost::regex::icase | boost::regex::normal); + + boost::smatch result; + std::string::const_iterator it_current_bound = it_begin; + std::string::const_iterator it_end_bound = it_end; + + //lookup all fields and fill well-known fields + while( boost::regex_search( it_current_bound, it_end_bound, result, rexp_mach_field, boost::match_default) && result[0].matched) + { + const size_t field_val = 6; + const size_t field_etc_name = 4; + + int i = 2; //start position = 2 + if(result[i++].matched)//"Content-Disposition" + entry.m_content_disposition = result[field_val]; + else if(result[i++].matched)//"Content-Type" + entry.m_content_type = result[field_val]; + else if(result[i++].matched)//e.t.c (HAVE TO BE MATCHED!) + entry.m_etc_header_fields.push_back(std::pair(result[field_etc_name], result[field_val])); + else + { + LOG_ERROR("simple_http_connection_handler::parse_header() not matched last entry in:"<& out_values) + { + //bool res = file_io_utils::load_file_to_string("C:\\public\\multupart_data", body); + + std::string boundary; + if(!match_boundary(content_type, boundary)) + { + LOG_PRINT("Failed to match boundary in content type: " << content_type, LOG_LEVEL_0); + return false; + } + + boundary+="\r\n"; + bool is_stop = false; + bool first_step = true; + + std::string::const_iterator it_begin = body.begin(); + std::string::const_iterator it_end; + while(!is_stop) + { + std::string::size_type pos = body.find(boundary, std::distance(body.begin(), it_begin)); + + if(std::string::npos == pos) + { + is_stop = true; + boundary.erase(boundary.size()-2, 2); + boundary+= "--"; + pos = body.find(boundary, std::distance(body.begin(), it_begin)); + if(std::string::npos == pos) + { + LOG_PRINT("Error: Filed to match closing multipart tag", LOG_LEVEL_0); + it_end = body.end(); + }else + { + it_end = body.begin() + pos; + } + }else + it_end = body.begin() + pos; + + + if(first_step && !is_stop) + { + first_step = false; + it_begin = it_end + boundary.size(); + std::string temp = "\r\n--"; + boundary = temp + boundary; + continue; + } + + out_values.push_back(multipart_entry()); + if(!handle_part_of_multipart(it_begin, it_end, out_values.back())) + { + LOG_PRINT("Failed to handle_part_of_multipart", LOG_LEVEL_0); + return false; + } + + it_begin = it_end + boundary.size(); + } + + return true; + } + + + + + //-------------------------------------------------------------------------------------------- + template + simple_http_connection_handler::simple_http_connection_handler(i_service_endpoint* psnd_hndlr, config_type& config): + m_state(http_state_retriving_comand_line), + m_body_transfer_type(http_body_transfer_undefined), + m_is_stop_handling(false), + m_len_summary(0), + m_len_remain(0), + m_config(config), + m_want_close(false), + m_psnd_hndlr(psnd_hndlr) + { + + } + //-------------------------------------------------------------------------------------------- + template + bool simple_http_connection_handler::set_ready_state() + { + m_is_stop_handling = false; + m_state = http_state_retriving_comand_line; + m_body_transfer_type = http_body_transfer_undefined; + m_query_info.clear(); + m_len_summary = 0; + return true; + } + //-------------------------------------------------------------------------------------------- + template + bool simple_http_connection_handler::handle_recv(const void* ptr, size_t cb) + { + std::string buf((const char*)ptr, cb); + //LOG_PRINT_L0("HTTP_RECV: " << ptr << "\r\n" << buf); + //file_io_utils::save_string_to_file(string_tools::get_current_module_folder() + "/" + boost::lexical_cast(ptr), std::string((const char*)ptr, cb)); + + bool res = handle_buff_in(buf); + if(m_want_close/*m_state == http_state_connection_close || m_state == http_state_error*/) + return false; + return res; + } + //-------------------------------------------------------------------------------------------- + template + bool simple_http_connection_handler::handle_buff_in(std::string& buf) + { + + if(m_cache.size()) + m_cache += buf; + else + m_cache.swap(buf); + + m_is_stop_handling = false; + while(!m_is_stop_handling) + { + switch(m_state) + { + case http_state_retriving_comand_line: + //The HTTP protocol does not place any a priori limit on the length of a URI. (c)RFC2616 + //but we forebly restirct it len to HTTP_MAX_URI_LEN to make it more safely + if(!m_cache.size()) + break; + + //check_and_handle_fake_response(); + if((m_cache[0] == '\r' || m_cache[0] == '\n')) + { + //some times it could be that before query line cold be few line breaks + //so we have to be calm without panic with assers + m_cache.erase(0, 1); + break; + } + + if(std::string::npos != m_cache.find('\n', 0)) + handle_invoke_query_line(); + else + { + m_is_stop_handling = true; + if(m_cache.size() > HTTP_MAX_URI_LEN) + { + LOG_ERROR("simple_http_connection_handler::handle_buff_out: Too long URI line"); + m_state = http_state_error; + return false; + } + } + break; + case http_state_retriving_header: + { + std::string::size_type pos = match_end_of_header(m_cache); + if(std::string::npos == pos) + { + m_is_stop_handling = true; + if(m_cache.size() > HTTP_MAX_HEADER_LEN) + { + LOG_ERROR("simple_http_connection_handler::handle_buff_in: Too long header area"); + m_state = http_state_error; + return false; + } + break; + } + analize_cached_request_header_and_invoke_state(pos); + break; + } + case http_state_retriving_body: + return handle_retriving_query_body(); + case http_state_connection_close: + return false; + default: + LOG_ERROR("simple_http_connection_handler::handle_char_out: Wrong state: " << m_state); + return false; + case http_state_error: + LOG_ERROR("simple_http_connection_handler::handle_char_out: Error state!!!"); + return false; + } + + if(!m_cache.size()) + m_is_stop_handling = true; + } + + return true; + } + //-------------------------------------------------------------------------------------------- + inline bool analize_http_method(const boost::smatch& result, http::http_method& method, int& http_ver_major, int& http_ver_minor) + { + CHECK_AND_ASSERT_MES(result[0].matched, false, "simple_http_connection_handler::analize_http_method() assert failed..."); + http_ver_major = boost::lexical_cast(result[11]); + http_ver_minor = boost::lexical_cast(result[12]); + if(result[4].matched) + method = http::http_method_get; + else if(result[5].matched) + method = http::http_method_head; + else if(result[6].matched) + method = http::http_method_post; + else if(result[7].matched) + method = http::http_method_put; + else + method = http::http_method_etc; + + return true; + } + + //-------------------------------------------------------------------------------------------- + template + bool simple_http_connection_handler::handle_invoke_query_line() + { + LOG_FRAME("simple_http_connection_handler::handle_recognize_protocol_out(*)", LOG_LEVEL_3); + + STATIC_REGEXP_EXPR_1(rexp_match_command_line, "^(((OPTIONS)|(GET)|(HEAD)|(POST)|(PUT)|(DELETE)|(TRACE)) (\\S+) HTTP/(\\d+).(\\d+))\r?\n", boost::regex::icase | boost::regex::normal); + // 123 4 5 6 7 8 9 10 11 12 + //size_t match_len = 0; + boost::smatch result; + if(boost::regex_search(m_cache, result, rexp_match_command_line, boost::match_default) && result[0].matched) + { + analize_http_method(result, m_query_info.m_http_method, m_query_info.m_http_ver_hi, m_query_info.m_http_ver_hi); + m_query_info.m_URI = result[10]; + parse_uri(m_query_info.m_URI, m_query_info.m_uri_content); + m_query_info.m_http_method_str = result[2]; + m_query_info.m_full_request_str = result[0]; + + m_cache.erase(m_cache.begin(), to_nonsonst_iterator(m_cache, result[0].second)); + + m_state = http_state_retriving_header; + + return true; + }else + { + m_state = http_state_error; + LOG_ERROR("simple_http_connection_handler::handle_invoke_query_line(): Failed to match first line: " << m_cache); + return false; + } + + return false; + } + //-------------------------------------------------------------------------------------------- + template + std::string::size_type simple_http_connection_handler::match_end_of_header(const std::string& buf) + { + + //Here we returning head size, including terminating sequence (\r\n\r\n or \n\n) + std::string::size_type res = buf.find("\r\n\r\n"); + if(std::string::npos != res) + return res+4; + res = buf.find("\n\n"); + if(std::string::npos != res) + return res+2; + return res; + } + //-------------------------------------------------------------------------------------------- + template + bool simple_http_connection_handler::analize_cached_request_header_and_invoke_state(size_t pos) + { + //LOG_PRINT_L4("HTTP HEAD:\r\n" << m_cache.substr(0, pos)); + + LOG_FRAME("simple_http_connection_handler::analize_cached_request_header_and_invoke_state(*)", LOG_LEVEL_3); + + m_query_info.m_full_request_buf_size = pos; + m_query_info.m_request_head.assign(m_cache.begin(), m_cache.begin()+pos); + + if(!parse_cached_header(m_query_info.m_header_info, m_cache, pos)) + { + LOG_ERROR("simple_http_connection_handler::analize_cached_request_header_and_invoke_state(): failed to anilize request header: " << m_cache); + m_state = http_state_error; + } + + m_cache.erase(0, pos); + + std::string req_command_str = m_query_info.m_full_request_str; + //if we have POST or PUT command, it is very possible tha we will get body + //but now, we suppose than we have body only in case of we have "ContentLength" + if(m_query_info.m_header_info.m_content_length.size()) + { + m_state = http_state_retriving_body; + m_body_transfer_type = http_body_transfer_measure; + if(!get_len_from_content_lenght(m_query_info.m_header_info.m_content_length, m_len_summary)) + { + LOG_ERROR("simple_http_connection_handler::analize_cached_request_header_and_invoke_state(): Failed to get_len_from_content_lenght();, m_query_info.m_content_length="< + bool simple_http_connection_handler::handle_retriving_query_body() + { + switch(m_body_transfer_type) + { + case http_body_transfer_measure: + return handle_query_measure(); + case http_body_transfer_chunked: + case http_body_transfer_connection_close: + case http_body_transfer_multipart: + case http_body_transfer_undefined: + default: + LOG_ERROR("simple_http_connection_handler::handle_retriving_query_body(): Unexpected m_body_query_type state:" << m_body_transfer_type); + m_state = http_state_error; + return false; + } + + return true; + } + //----------------------------------------------------------------------------------- + template + bool simple_http_connection_handler::handle_query_measure() + { + + if(m_len_remain >= m_cache.size()) + { + m_len_remain -= m_cache.size(); + m_query_info.m_body += m_cache; + m_cache.clear(); + }else + { + m_query_info.m_body.append(m_cache.begin(), m_cache.begin() + m_len_remain); + m_cache.erase(0, m_len_remain); + m_len_remain = 0; + } + + if(!m_len_remain) + { + if(handle_request_and_send_response(m_query_info)) + set_ready_state(); + else + m_state = http_state_error; + } + return true; + } + //-------------------------------------------------------------------------------------------- + template + bool simple_http_connection_handler::parse_cached_header(http_header_info& body_info, const std::string& m_cache_to_process, size_t pos) + { + LOG_FRAME("http_stream_filter::parse_cached_header(*)", LOG_LEVEL_3); + + STATIC_REGEXP_EXPR_1(rexp_mach_field, + "\n?((Connection)|(Referer)|(Content-Length)|(Content-Type)|(Transfer-Encoding)|(Content-Encoding)|(Host)|(Cookie)" + // 12 3 4 5 6 7 8 9 + "|([\\w-]+?)) ?: ?((.*?)(\r?\n))[^\t ]", + //10 1112 13 + boost::regex::icase | boost::regex::normal); + + boost::smatch result; + std::string::const_iterator it_current_bound = m_cache_to_process.begin(); + std::string::const_iterator it_end_bound = m_cache_to_process.begin()+pos; + + body_info.clear(); + + //lookup all fields and fill well-known fields + while( boost::regex_search( it_current_bound, it_end_bound, result, rexp_mach_field, boost::match_default) && result[0].matched) + { + const size_t field_val = 12; + const size_t field_etc_name = 10; + + int i = 2; //start position = 2 + if(result[i++].matched)//"Connection" + body_info.m_connection = result[field_val]; + else if(result[i++].matched)//"Referer" + body_info.m_referer = result[field_val]; + else if(result[i++].matched)//"Content-Length" + body_info.m_content_length = result[field_val]; + else if(result[i++].matched)//"Content-Type" + body_info.m_content_type = result[field_val]; + else if(result[i++].matched)//"Transfer-Encoding" + body_info.m_transfer_encoding = result[field_val]; + else if(result[i++].matched)//"Content-Encoding" + body_info.m_content_encoding = result[field_val]; + else if(result[i++].matched)//"Host" + body_info.m_host = result[field_val]; + else if(result[i++].matched)//"Cookie" + body_info.m_cookie = result[field_val]; + else if(result[i++].matched)//e.t.c (HAVE TO BE MATCHED!) + body_info.m_etc_fields.push_back(std::pair(result[field_etc_name], result[field_val])); + else + { + LOG_ERROR("simple_http_connection_handler::parse_cached_header() not matched last entry in:"< + bool simple_http_connection_handler::get_len_from_content_lenght(const std::string& str, size_t& OUT len) + { + STATIC_REGEXP_EXPR_1(rexp_mach_field, "\\d+", boost::regex::normal); + std::string res; + boost::smatch result; + if(!(boost::regex_search( str, result, rexp_mach_field, boost::match_default) && result[0].matched)) + return false; + + len = boost::lexical_cast(result[0]); + return true; + } + //----------------------------------------------------------------------------------- + template + bool simple_http_connection_handler::handle_request_and_send_response(const http::http_request_info& query_info) + { + http_response_info response; + bool res = handle_request(query_info, response); + //CHECK_AND_ASSERT_MES(res, res, "handle_request(query_info, response) returned false" ); + + std::string response_data = get_response_header(response); + + //LOG_PRINT_L0("HTTP_SEND: << \r\n" << response_data + response.m_body); + LOG_PRINT_L3("HTTP_RESPONSE_HEAD: << \r\n" << response_data); + + m_psnd_hndlr->do_send((void*)response_data.data(), response_data.size()); + if(response.m_body.size()) + m_psnd_hndlr->do_send((void*)response.m_body.data(), response.m_body.size()); + return res; + } + //----------------------------------------------------------------------------------- + template + bool simple_http_connection_handler::handle_request(const http::http_request_info& query_info, http_response_info& response) + { + + std::string uri_to_path = query_info.m_uri_content.m_path; + if("/" == uri_to_path) + uri_to_path = "/index.html"; + + //slash_to_back_slash(uri_to_path); + CRITICAL_SECTION_LOCK(m_config.m_lock); + std::string destination_file_path = m_config.m_folder + uri_to_path; + CRITICAL_SECTION_UNLOCK(m_config.m_lock); + if(!file_io_utils::load_file_to_string(destination_file_path.c_str(), response.m_body)) + { + LOG_PRINT("URI \""<< query_info.m_full_request_str.substr(0, query_info.m_full_request_str.size()-2) << "\" [" << destination_file_path << "] Not Found (404 )" , LOG_LEVEL_1); + response.m_body = get_not_found_response_body(query_info.m_URI); + response.m_response_code = 404; + response.m_response_comment = "Not found"; + response.m_mime_tipe = "text/html"; + return true; + } + + LOG_PRINT(" -->> " << query_info.m_full_request_str << "\r\n<<--OK" , LOG_LEVEL_3); + response.m_response_code = 200; + response.m_response_comment = "OK"; + response.m_mime_tipe = get_file_mime_tipe(uri_to_path); + + + return true; + } + //----------------------------------------------------------------------------------- + template + std::string simple_http_connection_handler::get_response_header(const http_response_info& response) + { + std::string buf = "HTTP/1.1 "; + buf += boost::lexical_cast(response.m_response_code) + " " + response.m_response_comment + "\r\n" + + "Server: Epee-based\r\n" + "Content-Length: "; + buf += boost::lexical_cast(response.m_body.size()) + "\r\n"; + buf += "Content-Type: "; + buf += response.m_mime_tipe + "\r\n"; + + buf += "Last-Modified: "; + time_t tm; + time(&tm); + buf += misc_utils::get_internet_time_str(tm) + "\r\n"; + buf += "Accept-Ranges: bytes\r\n"; + //Wed, 01 Dec 2010 03:27:41 GMT" + + string_tools::trim(m_query_info.m_header_info.m_connection); + if(m_query_info.m_header_info.m_connection.size()) + { + if(!string_tools::compare_no_case("close", m_query_info.m_header_info.m_connection)) + { + //closing connection after sending + buf += "Connection: close\r\n"; + m_state = http_state_connection_close; + m_want_close = true; + } + } + //add additional fields, if it is + for(fields_list::const_iterator it = response.m_additional_fields.begin(); it!=response.m_additional_fields.end(); it++) + buf += it->first + ":" + it->second + "\r\n"; + + buf+="\r\n"; + + return buf; + } + //----------------------------------------------------------------------------------- + template + std::string simple_http_connection_handler::get_file_mime_tipe(const std::string& path) + { + std::string result; + std::string ext = string_tools::get_extension(path); + if(!string_tools::compare_no_case(ext, "gif")) + result = "image/gif"; + else if(!string_tools::compare_no_case(ext, "jpg")) + result = "image/jpeg"; + else if(!string_tools::compare_no_case(ext, "html")) + result = "text/html"; + else if(!string_tools::compare_no_case(ext, "htm")) + result = "text/html"; + else if(!string_tools::compare_no_case(ext, "js")) + result = "application/x-javascript"; + else if(!string_tools::compare_no_case(ext, "css")) + result = "text/css"; + else if(!string_tools::compare_no_case(ext, "xml")) + result = "application/xml"; + else if(!string_tools::compare_no_case(ext, "svg")) + result = "image/svg+xml"; + + + return result; + } + //----------------------------------------------------------------------------------- + template + std::string simple_http_connection_handler::get_not_found_response_body(const std::string& URI) + { + std::string body = + "\r\n" + "\r\n" + "404 Not Found\r\n" + "\r\n" + "

Not Found

\r\n" + "

The requested URL \r\n"; + body += URI; + body += "was not found on this server.

\r\n" + "\r\n"; + + return body; + } + //-------------------------------------------------------------------------------------------- + template + bool simple_http_connection_handler::slash_to_back_slash(std::string& str) + { + for(std::string::iterator it = str.begin(); it!=str.end(); it++) + if('/' == *it) + *it = '\\'; + return true; + } + } +} +} + +POP_WARNINGS +//-------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/contrib/epee/include/net/http_server_cp.h b/contrib/epee/include/net/http_server_cp.h new file mode 100644 index 00000000..bbb167f9 --- /dev/null +++ b/contrib/epee/include/net/http_server_cp.h @@ -0,0 +1,48 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + + +#ifndef _HTTP_SERVER_CP_H_ +#define _HTTP_SERVER_CP_H_ + +#include "abstract_tcp_server_cp.h" +#include "http_server.h" +namespace epee +{ +namespace net_utils +{ + typedef cp_server_impl cp_http_server_file_system; + typedef cp_server_impl cp_http_server_custum_handling; +} +} + + + +#endif + + diff --git a/contrib/epee/include/net/http_server_cp2.h b/contrib/epee/include/net/http_server_cp2.h new file mode 100644 index 00000000..1a503a4d --- /dev/null +++ b/contrib/epee/include/net/http_server_cp2.h @@ -0,0 +1,47 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + + +#ifndef _HTTP_SERVER_CP2_H_ +#define _HTTP_SERVER_CP2_H_ + +#include "abstract_tcp_server2.h" +#include "http_protocol_handler.h" +namespace epee +{ +namespace net_utils +{ + typedef boosted_tcp_server > boosted_http_server_file_system; + typedef boosted_tcp_server > boosted_http_server_custum_handling; +} +} + + +#endif + + diff --git a/contrib/epee/include/net/http_server_handlers_map2.h b/contrib/epee/include/net/http_server_handlers_map2.h new file mode 100644 index 00000000..0d439cab --- /dev/null +++ b/contrib/epee/include/net/http_server_handlers_map2.h @@ -0,0 +1,348 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + +#pragma once +#include "serialization/keyvalue_serialization.h" +#include "storages/portable_storage_template_helper.h" +#include "http_base.h" + +template +bool auto_doc_t(const std::string& prefix_name, std::string& generate_reference) +{ + if (!generate_reference.size()) return true; + request_t req = AUTO_VAL_INIT(req); + response_t res = AUTO_VAL_INIT(res); + std::stringstream ss; + ss << prefix_name << ENDL + << "REQUEST: " << ENDL << epee::serialization::store_t_to_json(req) << ENDL << "--------------------------------" << ENDL + << "RESPONSE: " << ENDL << epee::serialization::store_t_to_json(res) << ENDL << "################################" << ENDL; + generate_reference += ss.str(); + return true; +} + + +template +bool auto_doc(const std::string& prefix_name, std::string& generate_reference) +{ + return auto_doc_t(prefix_name, generate_reference); +} + + +#define CHAIN_HTTP_TO_MAP2(context_type) bool handle_http_request(const epee::net_utils::http::http_request_info& query_info, \ + epee::net_utils::http::http_response_info& response, \ + context_type& m_conn_context) \ +{\ + response.m_response_code = 200; \ + response.m_response_comment = "Ok"; \ + std::string reference_stub; \ + bool call_found = false; \ + if(!handle_http_request_map(query_info, response, m_conn_context, call_found, reference_stub) && response.m_response_code == 200) \ + { response.m_response_code = 500; response.m_response_comment = "Internal Server Error"; return true; } \ + if (!call_found) \ + { response.m_response_code = 404; response.m_response_comment = "Not Found"; return true; } \ + return true; \ +} + +#define BEGIN_URI_MAP2() template bool handle_http_request_map(const epee::net_utils::http::http_request_info& query_info, \ + epee::net_utils::http::http_response_info& response_info, \ + t_context& m_conn_context, bool& call_found, std::string& generate_reference) { \ + call_found = false; \ + if(false) return true; //just a stub to have "else if" + +#define MAP_URI2(pattern, callback) else if(std::string::npos != query_info.m_URI.find(pattern)) return callback(query_info, response_info, m_conn_context); + +#define MAP_URI_AUTO_XML2(s_pattern, callback_f, command_type) //TODO: don't think i ever again will use xml - ambiguous and "overtagged" format + +#define MAP_URI_AUTO_JON2(s_pattern, callback_f, command_type) \ + else if(auto_doc(s_pattern "[JSON]", generate_reference) && query_info.m_URI == s_pattern) \ + { \ + call_found = true; \ + uint64_t ticks = misc_utils::get_tick_count(); \ + boost::value_initialized req; \ + bool res = epee::serialization::load_t_from_json(static_cast(req), query_info.m_body); \ + CHECK_AND_ASSERT_MES(res, false, "Failed to parse json: \r\n" << query_info.m_body); \ + uint64_t ticks1 = epee::misc_utils::get_tick_count(); \ + boost::value_initialized resp;\ + res = callback_f(static_cast(req), static_cast(resp), m_conn_context); \ + CHECK_AND_ASSERT_MES(res, false, "Failed to call " << #callback_f << "() while handling " << s_pattern); \ + uint64_t ticks2 = epee::misc_utils::get_tick_count(); \ + epee::serialization::store_t_to_json(static_cast(resp), response_info.m_body); \ + uint64_t ticks3 = epee::misc_utils::get_tick_count(); \ + response_info.m_mime_tipe = "application/json"; \ + response_info.m_header_info.m_content_type = " application/json"; \ + LOG_PRINT("[HTTP/JSON][" << epee::string_tools::get_ip_string_from_int32(m_conn_context.m_remote_ip ) << "][" << query_info.m_URI << "] processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); \ + } + +#define MAP_URI_AUTO_BIN2(s_pattern, callback_f, command_type) \ + else if(auto_doc(s_pattern "[BIN]", generate_reference) && query_info.m_URI == s_pattern) \ + { \ + call_found = true; \ + uint64_t ticks = misc_utils::get_tick_count(); \ + boost::value_initialized req; \ + bool res = epee::serialization::load_t_from_binary(static_cast(req), query_info.m_body); \ + CHECK_AND_ASSERT_MES(res, false, "Failed to parse bin body data, body size=" << query_info.m_body.size()); \ + uint64_t ticks1 = misc_utils::get_tick_count(); \ + boost::value_initialized resp;\ + res = callback_f(static_cast(req), static_cast(resp), m_conn_context); \ + CHECK_AND_ASSERT_MES(res, false, "Failed to call " << #callback_f << "() while handling " << s_pattern); \ + uint64_t ticks2 = misc_utils::get_tick_count(); \ + epee::serialization::store_t_to_binary(static_cast(resp), response_info.m_body); \ + uint64_t ticks3 = epee::misc_utils::get_tick_count(); \ + response_info.m_mime_tipe = " application/octet-stream"; \ + response_info.m_header_info.m_content_type = " application/octet-stream"; \ + LOG_PRINT( "[HTTP/BIN][" << epee::string_tools::get_ip_string_from_int32(m_conn_context.m_remote_ip ) << "][" << query_info.m_URI << "] processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); \ + } + +#define CHAIN_URI_MAP2(callback) else {callback(query_info, response_info, m_conn_context);call_found = true;} + +#define END_URI_MAP2() return true;} + + + + +namespace epee +{ + namespace json_rpc + { + template + struct request + { + std::string jsonrpc; + std::string method; + epee::serialization::storage_entry id; + t_param params; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(jsonrpc) + KV_SERIALIZE(id) + KV_SERIALIZE(method) + KV_SERIALIZE(params) + END_KV_SERIALIZE_MAP() + }; + + struct error + { + int64_t code; + std::string message; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(code) + KV_SERIALIZE(message) + END_KV_SERIALIZE_MAP() + }; + + struct dummy_error + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct dummy_result + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + template + struct response + { + std::string jsonrpc; + t_param result; + epee::serialization::storage_entry id; + t_error error; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(jsonrpc) + KV_SERIALIZE(id) + KV_SERIALIZE(result) + KV_SERIALIZE(error) + END_KV_SERIALIZE_MAP() + }; + + template + struct response + { + std::string jsonrpc; + t_param result; + epee::serialization::storage_entry id; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(jsonrpc) + KV_SERIALIZE(id) + KV_SERIALIZE(result) + END_KV_SERIALIZE_MAP() + }; + + template + struct response + { + std::string jsonrpc; + t_error error; + epee::serialization::storage_entry id; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(jsonrpc) + KV_SERIALIZE(id) + KV_SERIALIZE(error) + END_KV_SERIALIZE_MAP() + }; + + typedef response error_response; + } +} + +template +struct json_command_type_t +{ + typedef typename epee::json_rpc::request request; + typedef typename epee::json_rpc::request response; +}; + +#define JSON_RPC_REFERENCE_MARKER "JSON_RPC" + + + +#define BEGIN_JSON_RPC_MAP(uri) else if(query_info.m_URI == JSON_RPC_REFERENCE_MARKER || query_info.m_URI == uri) \ + { \ + if(query_info.m_URI == JSON_RPC_REFERENCE_MARKER) {generate_reference = "JSON RPC URL: " uri "\n";} \ + LOG_PRINT_L4("[JSON_REQUEST_BODY]: " << ENDL << query_info.m_body); \ + uint64_t ticks = epee::misc_utils::get_tick_count(); \ + epee::serialization::portable_storage ps; \ + if(!ps.load_from_json(query_info.m_body)) \ + { \ + boost::value_initialized rsp; \ + static_cast(rsp).error.code = -32700; \ + static_cast(rsp).error.message = "Parse error"; \ + epee::serialization::store_t_to_json(static_cast(rsp), response_info.m_body); \ + return true; \ + } \ + epee::serialization::storage_entry id_; \ + id_ = epee::serialization::storage_entry(std::string()); \ + ps.get_value("id", id_, nullptr); \ + std::string callback_name; \ + if(!ps.get_value("method", callback_name, nullptr)) \ + { \ + epee::json_rpc::error_response rsp; \ + rsp.jsonrpc = "2.0"; \ + rsp.error.code = -32600; \ + rsp.error.message = "Invalid Request"; \ + epee::serialization::store_t_to_json(static_cast(rsp), response_info.m_body); \ + return true; \ + } \ + if(false) return true; //just a stub to have "else if" + + + + +#define PREPARE_OBJECTS_FROM_JSON(command_type) \ + call_found = true; \ + boost::value_initialized > req_; \ + epee::json_rpc::request& req = static_cast&>(req_);\ + if(!req.load(ps)) \ + { \ + epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \ + fail_resp.jsonrpc = "2.0"; \ + fail_resp.id = req.id; \ + fail_resp.error.code = -32602; \ + fail_resp.error.message = "Invalid params"; \ + epee::serialization::store_t_to_json(static_cast(fail_resp), response_info.m_body); \ + return true; \ + } \ + uint64_t ticks1 = epee::misc_utils::get_tick_count(); \ + boost::value_initialized > resp_; \ + epee::json_rpc::response& resp = static_cast &>(resp_); \ + resp.jsonrpc = "2.0"; \ + resp.id = req.id; + +#define FINALIZE_OBJECTS_TO_JSON(method_name) \ + uint64_t ticks2 = epee::misc_utils::get_tick_count(); \ + epee::serialization::store_t_to_json(resp, response_info.m_body); \ + uint64_t ticks3 = epee::misc_utils::get_tick_count(); \ + response_info.m_mime_tipe = "application/json"; \ + response_info.m_header_info.m_content_type = " application/json"; \ + LOG_PRINT( query_info.m_URI << "[" << method_name << "] processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); + +#define MAP_JON_RPC_WE(method_name, callback_f, command_type) \ + else if(auto_doc>("[" method_name "]", generate_reference) && callback_name == method_name) \ +{ \ + PREPARE_OBJECTS_FROM_JSON(command_type) \ + epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \ + fail_resp.jsonrpc = "2.0"; \ + fail_resp.id = req.id; \ + if(!callback_f(req.params, resp.result, fail_resp.error, m_conn_context)) \ + { \ + epee::serialization::store_t_to_json(static_cast(fail_resp), response_info.m_body); \ + return true; \ + } \ + FINALIZE_OBJECTS_TO_JSON(method_name) \ + return true;\ +} + +#define MAP_JON_RPC_WERI(method_name, callback_f, command_type) \ + else if(auto_doc>("[" method_name "]", generate_reference) && callback_name == method_name) \ +{ \ + PREPARE_OBJECTS_FROM_JSON(command_type) \ + epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \ + fail_resp.jsonrpc = "2.0"; \ + fail_resp.id = req.id; \ + if(!callback_f(req.params, resp.result, fail_resp.error, m_conn_context, response_info)) \ + { \ + epee::serialization::store_t_to_json(static_cast(fail_resp), response_info.m_body); \ + return true; \ + } \ + FINALIZE_OBJECTS_TO_JSON(method_name) \ + return true;\ +} + +#define MAP_JON_RPC(method_name, callback_f, command_type) \ + else if(auto_doc>(std::string("[") + method_name + "]", generate_reference) && callback_name == method_name) \ +{ \ + PREPARE_OBJECTS_FROM_JSON(command_type) \ + if(!callback_f(req.params, resp.result, m_conn_context)) \ + { \ + epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \ + fail_resp.jsonrpc = "2.0"; \ + fail_resp.id = req.id; \ + fail_resp.error.code = -32603; \ + fail_resp.error.message = "Internal error"; \ + epee::serialization::store_t_to_json(static_cast(fail_resp), response_info.m_body); \ + return true; \ + } \ + FINALIZE_OBJECTS_TO_JSON(method_name) \ + return true;\ +} + +#define MAP_JON_RPC_N(callback_f, command_type) MAP_JON_RPC(command_type::methodname(), callback_f, command_type) + +#define END_JSON_RPC_MAP() \ + epee::json_rpc::error_response rsp; \ + rsp.id = id_; \ + rsp.jsonrpc = "2.0"; \ + rsp.error.code = -32601; \ + rsp.error.message = "Method not found"; \ + epee::serialization::store_t_to_json(static_cast(rsp), response_info.m_body); \ + LOG_PRINT_L4("[JSON_RESPONSE_BODY]: " << ENDL << query_info.m_body); \ + return true; \ + } + + diff --git a/contrib/epee/include/net/http_server_impl_base.h b/contrib/epee/include/net/http_server_impl_base.h new file mode 100644 index 00000000..c02475c3 --- /dev/null +++ b/contrib/epee/include/net/http_server_impl_base.h @@ -0,0 +1,112 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + + +#pragma once + + +#include +#include + +#include "net/http_server_cp2.h" +#include "net/http_server_handlers_map2.h" + +namespace epee +{ + + template + class http_server_impl_base: public net_utils::http::i_http_server_handler + { + + public: + http_server_impl_base() + : m_net_server() + {} + + explicit http_server_impl_base(boost::asio::io_service& external_io_service) + : m_net_server(external_io_service) + {} + + bool init(const std::string& bind_port = "0", const std::string& bind_ip = "0.0.0.0") + { + + //set self as callback handler + m_net_server.get_config_object().m_phandler = static_cast(this); + + //here set folder for hosting reqests + m_net_server.get_config_object().m_folder = ""; + + LOG_PRINT_L0("Binding on " << bind_ip << ":" << bind_port); + bool res = m_net_server.init_server(bind_port, bind_ip); + if(!res) + { + LOG_ERROR("Failed to bind server"); + return false; + } + return true; + } + + bool run(size_t threads_count, bool wait = true) + { + //go to loop + LOG_PRINT("Run net_service loop( " << threads_count << " threads)...", LOG_LEVEL_0); + if(!m_net_server.run_server(threads_count, wait)) + { + LOG_ERROR("Failed to run net tcp server!"); + } + + if(wait) + LOG_PRINT("net_service loop stopped.", LOG_LEVEL_0); + return true; + } + + bool deinit() + { + return m_net_server.deinit_server(); + } + + bool timed_wait_server_stop(uint64_t ms) + { + return m_net_server.timed_wait_server_stop(ms); + } + + bool send_stop_signal() + { + m_net_server.send_stop_signal(); + return true; + } + + int get_binded_port() + { + return m_net_server.get_binded_port(); + } + + protected: + net_utils::boosted_tcp_server > m_net_server; + }; +} \ No newline at end of file diff --git a/contrib/epee/include/net/http_server_thread_per_connect.h b/contrib/epee/include/net/http_server_thread_per_connect.h new file mode 100644 index 00000000..bec43b72 --- /dev/null +++ b/contrib/epee/include/net/http_server_thread_per_connect.h @@ -0,0 +1,48 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#ifndef _HTTP_SERVER_CP_H_ +#define _HTTP_SERVER_CP_H_ + +#include "abstract_tcp_server.h" +#include "http_server.h" + +namespace epee +{ +namespace net_utils +{ + typedef abstract_tcp_server mt_http_server_file_system; + typedef abstract_tcp_server mt_http_server_custum_handling; + +} +} + + +#endif + + diff --git a/contrib/epee/include/net/levin_base.h b/contrib/epee/include/net/levin_base.h new file mode 100644 index 00000000..4f55b0df --- /dev/null +++ b/contrib/epee/include/net/levin_base.h @@ -0,0 +1,131 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#ifndef _LEVIN_BASE_H_ +#define _LEVIN_BASE_H_ + +#include "net_utils_base.h" + +#define LEVIN_SIGNATURE 0x0101010101012101LL //Bender's nightmare + +namespace epee +{ +namespace levin +{ +#pragma pack(push) +#pragma pack(1) + struct bucket_head + { + uint64_t m_signature; + uint64_t m_cb; + bool m_have_to_return_data; + uint32_t m_command; + int32_t m_return_code; + uint32_t m_reservedA; //probably some flags in future + uint32_t m_reservedB; //probably some check sum in future + }; +#pragma pack(pop) + + +#pragma pack(push) +#pragma pack(1) + struct bucket_head2 + { + uint64_t m_signature; + uint64_t m_cb; + bool m_have_to_return_data; + uint32_t m_command; + int32_t m_return_code; + uint32_t m_flags; + uint32_t m_protocol_version; + }; +#pragma pack(pop) + + +#define LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED 0 +#define LEVIN_DEFAULT_MAX_PACKET_SIZE 100000000 //100MB by default + +#define LEVIN_PACKET_REQUEST 0x00000001 +#define LEVIN_PACKET_RESPONSE 0x00000002 + + +#define LEVIN_PROTOCOL_VER_0 0 +#define LEVIN_PROTOCOL_VER_1 1 + + template + struct levin_commands_handler + { + virtual int invoke(int command, const std::string& in_buff, std::string& buff_out, t_connection_context& context)=0; + virtual int notify(int command, const std::string& in_buff, t_connection_context& context)=0; + virtual void callback(t_connection_context& context){}; + + virtual void on_connection_new(t_connection_context& context){}; + virtual void on_connection_close(t_connection_context& context){}; + + }; + +#define LEVIN_OK 0 +#define LEVIN_ERROR_CONNECTION -1 +#define LEVIN_ERROR_CONNECTION_NOT_FOUND -2 +#define LEVIN_ERROR_CONNECTION_DESTROYED -3 +#define LEVIN_ERROR_CONNECTION_TIMEDOUT -4 +#define LEVIN_ERROR_CONNECTION_NO_DUPLEX_PROTOCOL -5 +#define LEVIN_ERROR_CONNECTION_HANDLER_NOT_DEFINED -6 +#define LEVIN_ERROR_FORMAT -7 +#define LEVIN_ERROR_EXCEPTION -8 +#define LEVIN_ERROR_UNKNOWN_ERROR -9 +#define LEVIN_ERROR_INTERNAL -10 +#define LEVIN_ERROR_PROTOCOL_INCONSISTENT -11 +#define LEVIN_ERROR_NET_ERROR -12 +#define LEVIN_ERROR_SIGNATURE_MISMATCH -13 + +#define DESCRIBE_RET_CODE(code) case code: return #code; + inline + const char* get_err_descr(int err) + { + switch(err) + { + DESCRIBE_RET_CODE(LEVIN_OK); + DESCRIBE_RET_CODE(LEVIN_ERROR_CONNECTION); + DESCRIBE_RET_CODE(LEVIN_ERROR_CONNECTION_NOT_FOUND); + DESCRIBE_RET_CODE(LEVIN_ERROR_CONNECTION_DESTROYED); + DESCRIBE_RET_CODE(LEVIN_ERROR_CONNECTION_TIMEDOUT); + DESCRIBE_RET_CODE(LEVIN_ERROR_CONNECTION_NO_DUPLEX_PROTOCOL); + DESCRIBE_RET_CODE(LEVIN_ERROR_CONNECTION_HANDLER_NOT_DEFINED); + DESCRIBE_RET_CODE(LEVIN_ERROR_FORMAT); + default: + return "unknown code"; + } + } + + +} +} + + +#endif //_LEVIN_BASE_H_ diff --git a/contrib/epee/include/net/levin_client.h b/contrib/epee/include/net/levin_client.h new file mode 100644 index 00000000..335f6ba0 --- /dev/null +++ b/contrib/epee/include/net/levin_client.h @@ -0,0 +1,89 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + + + +#ifndef _LEVIN_CLIENT_H_ +#define _LEVIN_CLIENT_H_ + +#include "net_helper.h" +#include "levin_base.h" + + +#ifndef MAKE_IP +#define MAKE_IP( a1, a2, a3, a4 ) (a1|(a2<<8)|(a3<<16)|(a4<<24)) +#endif + +namespace epee +{ +namespace levin +{ + /************************************************************************/ + /* */ + /************************************************************************/ + class levin_client_impl + { + public: + levin_client_impl(); + virtual ~levin_client_impl(); + + bool connect(u_long ip, int port, unsigned int timeout, const std::string& bind_ip = "0.0.0.0"); + bool connect(const std::string& addr, int port, unsigned int timeout, const std::string& bind_ip = "0.0.0.0"); + bool is_connected(); + bool disconnect(); + + virtual int invoke(int command, const std::string& in_buff, std::string& buff_out); + virtual int notify(int command, const std::string& in_buff); + + protected: + net_utils::blocked_mode_client m_transport; + }; + + + /************************************************************************/ + /* */ + /************************************************************************/ + class levin_client_impl2: public levin_client_impl + { + public: + + int invoke(int command, const std::string& in_buff, std::string& buff_out); + int notify(int command, const std::string& in_buff); + }; + +} +namespace net_utils +{ + typedef levin::levin_client_impl levin_client; + typedef levin::levin_client_impl2 levin_client2; +} +} + +#include "levin_client.inl" + +#endif //_LEVIN_CLIENT_H_ diff --git a/contrib/epee/include/net/levin_client.inl b/contrib/epee/include/net/levin_client.inl new file mode 100644 index 00000000..6f7c473e --- /dev/null +++ b/contrib/epee/include/net/levin_client.inl @@ -0,0 +1,206 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +#include "string_tools.h" +namespace epee +{ +namespace levin +{ +inline +bool levin_client_impl::connect(u_long ip, int port, unsigned int timeout, const std::string& bind_ip) +{ + return m_transport.connect(string_tools::get_ip_string_from_int32(ip), port, timeout, timeout, bind_ip); +} +//------------------------------------------------------------------------------ +inline + bool levin_client_impl::connect(const std::string& addr, int port, unsigned int timeout, const std::string& bind_ip) +{ + return m_transport.connect(addr, port, timeout, timeout, bind_ip); +} +//------------------------------------------------------------------------------ +inline +bool levin_client_impl::is_connected() +{ + return m_transport.is_connected(); +} +//------------------------------------------------------------------------------ +inline +bool levin_client_impl::disconnect() +{ + return m_transport.disconnect(); +} +//------------------------------------------------------------------------------ +inline +levin_client_impl::levin_client_impl() +{ +} +//------------------------------------------------------------------------------ +inline +levin_client_impl::~levin_client_impl() +{ + disconnect(); +} +//------------------------------------------------------------------------------ +inline +int levin_client_impl::invoke(int command, const std::string& in_buff, std::string& buff_out) +{ + if(!is_connected()) + return -1; + + bucket_head head = {0}; + head.m_signature = LEVIN_SIGNATURE; + head.m_cb = in_buff.size(); + head.m_have_to_return_data = true; + head.m_command = command; + if(!m_transport.send(&head, sizeof(head))) + return -1; + + if(!m_transport.send(in_buff)) + return -1; + + std::string local_buff; + if(!m_transport.recv_n(local_buff, sizeof(bucket_head))) + return -1; + + head = *(bucket_head*)local_buff.data(); + + + if(head.m_signature!=LEVIN_SIGNATURE) + { + LOG_PRINT_L0("Signature missmatch in response"); + return -1; + } + + if(!m_transport.recv_n(buff_out, head.m_cb)) + return -1; + + return head.m_return_code; +} +//------------------------------------------------------------------------------ +inline +int levin_client_impl::notify(int command, const std::string& in_buff) +{ + if(!is_connected()) + return -1; + + bucket_head head = {0}; + head.m_signature = LEVIN_SIGNATURE; + head.m_cb = in_buff.size(); + head.m_have_to_return_data = false; + head.m_command = command; + + if(!m_transport.send((const char*)&head, sizeof(head))) + return -1; + + if(!m_transport.send(in_buff)) + return -1; + + return 1; +} + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +inline + int levin_client_impl2::invoke(int command, const std::string& in_buff, std::string& buff_out) +{ + if(!is_connected()) + return -1; + + bucket_head2 head = {0}; + head.m_signature = LEVIN_SIGNATURE; + head.m_cb = in_buff.size(); + head.m_have_to_return_data = true; + head.m_command = static_cast(command); + head.m_protocol_version = LEVIN_PROTOCOL_VER_1; + head.m_flags = LEVIN_PACKET_REQUEST; + if(!m_transport.send(&head, sizeof(head))) + return -1; + + if(!m_transport.send(in_buff)) + return -1; + + //Since other side of connection could be running by async server, + //we can receive some unexpected notify(forwarded broadcast notifications for example). + //let's ignore every notify in the channel until we get invoke response + std::string local_buff; + + while (true) + { + if (!m_transport.recv_n(local_buff, sizeof(bucket_head2))) + return LEVIN_ERROR_NET_ERROR; + + head = *(bucket_head2*)local_buff.data(); + if (head.m_signature != LEVIN_SIGNATURE) + { + LOG_PRINT_L0("Signature missmatch in response"); + return LEVIN_ERROR_SIGNATURE_MISMATCH; + } + if (!m_transport.recv_n(buff_out, head.m_cb)) + return LEVIN_ERROR_NET_ERROR; + + //now check if this is response to invoke (and extra validate if it's response to this(!) invoke) + if (head.m_flags&LEVIN_PACKET_RESPONSE) + { + //we got response, extra validate if its response to our request + CHECK_AND_ASSERT_MES(head.m_command == static_cast(command), LEVIN_ERROR_PROTOCOL_INCONSISTENT, "command id missmatch in response: " << head.m_command << ", expected: " << command); + return head.m_return_code; + } + } + //never comes here + return LEVIN_ERROR_INTERNAL; +} +//------------------------------------------------------------------------------ +inline + int levin_client_impl2::notify(int command, const std::string& in_buff) +{ + if(!is_connected()) + return -1; + + bucket_head2 head = {0}; + head.m_signature = LEVIN_SIGNATURE; + head.m_cb = in_buff.size(); + head.m_have_to_return_data = false; + head.m_command = command; + head.m_protocol_version = LEVIN_PROTOCOL_VER_1; + head.m_flags = LEVIN_PACKET_REQUEST; + + if(!m_transport.send((const char*)&head, sizeof(head))) + return -1; + + if(!m_transport.send(in_buff)) + return -1; + + return 1; +} + +} +} +//------------------------------------------------------------------------------ \ No newline at end of file diff --git a/contrib/epee/include/net/levin_client_async.h b/contrib/epee/include/net/levin_client_async.h new file mode 100644 index 00000000..9e76cd50 --- /dev/null +++ b/contrib/epee/include/net/levin_client_async.h @@ -0,0 +1,577 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + +#pragma once + +#include "" +#include "net_helper.h" +#include "levin_base.h" + + +namespace epee +{ +namespace levin +{ + + /************************************************************************ + * levin_client_async - probably it is not really fast implementation, + * each handler thread could make up to 30 ms latency. + * But, handling events in reader thread will cause dead locks in + * case of recursive call (call invoke() to the same connection + * on reader thread on remote invoke() handler) + ***********************************************************************/ + + + class levin_client_async + { + levin_commands_handler* m_pcommands_handler; + volatile uint32_t m_is_stop; + volatile uint32_t m_threads_count; + ::critical_section m_send_lock; + + std::string m_local_invoke_buff; + ::critical_section m_local_invoke_buff_lock; + volatile int m_invoke_res; + + volatile uint32_t m_invoke_data_ready; + volatile uint32_t m_invoke_is_active; + + boost::mutex m_invoke_event; + boost::condition_variable m_invoke_cond; + size_t m_timeout; + + ::critical_section m_recieved_packets_lock; + struct packet_entry + { + bucket_head m_hd; + std::string m_body; + uint32_t m_connection_index; + }; + std::list m_recieved_packets; + /* + m_current_connection_index needed when some connection was broken and reconnected - in this + case we could have some received packets in que, which shoud not be handled + */ + volatile uint32_t m_current_connection_index; + ::critical_section m_invoke_lock; + ::critical_section m_reciev_packet_lock; + ::critical_section m_connection_lock; + net_utils::blocked_mode_client m_transport; + public: + levin_client_async():m_pcommands_handler(NULL), m_is_stop(0), m_threads_count(0), m_invoke_data_ready(0), m_invoke_is_active(0) + {} + levin_client_async(const levin_client_async& /*v*/):m_pcommands_handler(NULL), m_is_stop(0), m_threads_count(0), m_invoke_data_ready(0), m_invoke_is_active(0) + {} + ~levin_client_async() + { + boost::interprocess::ipcdetail::atomic_write32(&m_is_stop, 1); + disconnect(); + + + while(boost::interprocess::ipcdetail::atomic_read32(&m_threads_count)) + ::Sleep(100); + } + + void set_handler(levin_commands_handler* phandler) + { + m_pcommands_handler = phandler; + } + + bool connect(uint32_t ip, uint32_t port, uint32_t timeout) + { + loop_call_guard(); + critical_region cr(m_connection_lock); + + m_timeout = timeout; + bool res = false; + CRITICAL_REGION_BEGIN(m_reciev_packet_lock); + CRITICAL_REGION_BEGIN(m_send_lock); + res = levin_client_impl::connect(ip, port, timeout); + boost::interprocess::ipcdetail::atomic_inc32(&m_current_connection_index); + CRITICAL_REGION_END(); + CRITICAL_REGION_END(); + if(res && !boost::interprocess::ipcdetail::atomic_read32(&m_threads_count) ) + { + //boost::interprocess::ipcdetail::atomic_write32(&m_is_stop, 0);//m_is_stop = false; + boost::thread( boost::bind(&levin_duplex_client::reciever_thread, this) ); + boost::thread( boost::bind(&levin_duplex_client::handler_thread, this) ); + boost::thread( boost::bind(&levin_duplex_client::handler_thread, this) ); + } + + return res; + } + bool is_connected() + { + loop_call_guard(); + critical_region cr(m_cs); + return levin_client_impl::is_connected(); + } + + inline + bool check_connection() + { + loop_call_guard(); + critical_region cr(m_cs); + + if(!is_connected()) + { + if( !reconnect() ) + { + LOG_ERROR("Reconnect Failed. Failed to invoke() becouse not connected!"); + return false; + } + } + return true; + } + + //------------------------------------------------------------------------------ + inline + bool recv_n(SOCKET s, char* pbuff, size_t cb) + { + while(cb) + { + int res = ::recv(m_socket, pbuff, (int)cb, 0); + + if(SOCKET_ERROR == res) + { + if(!m_connected) + return false; + + int err = ::WSAGetLastError(); + LOG_ERROR("Failed to recv(), err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\""); + disconnect(); + //reconnect(); + return false; + }else if(res == 0) + { + disconnect(); + //reconnect(); + return false; + } + LOG_PRINT_L4("[" << m_socket <<"] RECV " << res); + cb -= res; + pbuff += res; + } + + return true; + } + + //------------------------------------------------------------------------------ + inline + bool recv_n(SOCKET s, std::string& buff) + { + size_t cb_remain = buff.size(); + char* m_current_ptr = (char*)buff.data(); + return recv_n(s, m_current_ptr, cb_remain); + } + + bool disconnect() + { + //boost::interprocess::ipcdetail::atomic_write32(&m_is_stop, 1);//m_is_stop = true; + loop_call_guard(); + critical_region cr(m_cs); + levin_client_impl::disconnect(); + + CRITICAL_REGION_BEGIN(m_local_invoke_buff_lock); + m_local_invoke_buff.clear(); + m_invoke_res = LEVIN_ERROR_CONNECTION_DESTROYED; + CRITICAL_REGION_END(); + boost::interprocess::ipcdetail::atomic_write32(&m_invoke_data_ready, 1); //m_invoke_data_ready = true; + m_invoke_cond.notify_all(); + return true; + } + + void loop_call_guard() + { + + } + + void on_leave_invoke() + { + boost::interprocess::ipcdetail::atomic_write32(&m_invoke_is_active, 0); + } + + int invoke(const GUID& target, int command, const std::string& in_buff, std::string& buff_out) + { + + critical_region cr_invoke(m_invoke_lock); + + boost::interprocess::ipcdetail::atomic_write32(&m_invoke_is_active, 1); + boost::interprocess::ipcdetail::atomic_write32(&m_invoke_data_ready, 0); + misc_utils::destr_ptr hdlr = misc_utils::add_exit_scope_handler(boost::bind(&levin_duplex_client::on_leave_invoke, this)); + + loop_call_guard(); + + if(!check_connection()) + return LEVIN_ERROR_CONNECTION_DESTROYED; + + + bucket_head head = {0}; + head.m_signature = LEVIN_SIGNATURE; + head.m_cb = in_buff.size(); + head.m_have_to_return_data = true; + head.m_id = target; +#ifdef TRACE_LEVIN_PACKETS_BY_GUIDS + ::UuidCreate(&head.m_id); +#endif + head.m_command = command; + head.m_protocol_version = LEVIN_PROTOCOL_VER_1; + head.m_flags = LEVIN_PACKET_REQUEST; + LOG_PRINT("[" << m_socket <<"] Sending invoke data", LOG_LEVEL_4); + + CRITICAL_REGION_BEGIN(m_send_lock); + LOG_PRINT_L4("[" << m_socket <<"] SEND " << sizeof(head)); + int res = ::send(m_socket, (const char*)&head, sizeof(head), 0); + if(SOCKET_ERROR == res) + { + int err = ::WSAGetLastError(); + LOG_ERROR("Failed to send(), err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\""); + disconnect(); + return LEVIN_ERROR_CONNECTION_DESTROYED; + } + LOG_PRINT_L4("[" << m_socket <<"] SEND " << (int)in_buff.size()); + res = ::send(m_socket, in_buff.data(), (int)in_buff.size(), 0); + if(SOCKET_ERROR == res) + { + int err = ::WSAGetLastError(); + LOG_ERROR("Failed to send(), err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\""); + disconnect(); + return LEVIN_ERROR_CONNECTION_DESTROYED; + } + CRITICAL_REGION_END(); + LOG_PRINT_L4("LEVIN_PACKET_SENT. [len=" << head.m_cb << ", flags=" << head.m_flags << ", is_cmd=" << head.m_have_to_return_data <<", cmd_id = " << head.m_command << ", pr_v=" << head.m_protocol_version << ", uid=" << string_tools::get_str_from_guid_a(head.m_id) << "]"); + + //hard coded timeout in 10 minutes for maximum invoke period. if it happens, it could mean only some real troubles. + boost::system_time timeout = boost::get_system_time()+ boost::posix_time::milliseconds(100); + size_t timeout_count = 0; + boost::unique_lock lock(m_invoke_event); + + while(!boost::interprocess::ipcdetail::atomic_read32(&m_invoke_data_ready)) + { + if(!m_invoke_cond.timed_wait(lock, timeout)) + { + if(timeout_count < 10) + { + //workaround to avoid freezing at timed_wait called after notify_all. + timeout = boost::get_system_time()+ boost::posix_time::milliseconds(100); + ++timeout_count; + continue; + }else if(timeout_count == 10) + { + //workaround to avoid freezing at timed_wait called after notify_all. + timeout = boost::get_system_time()+ boost::posix_time::minutes(10); + ++timeout_count; + continue; + }else + { + LOG_PRINT("[" << m_socket <<"] Timeout on waiting invoke result. ", LOG_LEVEL_0); + //disconnect(); + return LEVIN_ERROR_CONNECTION_TIMEDOUT; + } + } + } + + + CRITICAL_REGION_BEGIN(m_local_invoke_buff_lock); + buff_out.swap(m_local_invoke_buff); + m_local_invoke_buff.clear(); + CRITICAL_REGION_END(); + return m_invoke_res; + } + + int notify(const GUID& target, int command, const std::string& in_buff) + { + if(!check_connection()) + return LEVIN_ERROR_CONNECTION_DESTROYED; + + bucket_head head = {0}; + head.m_signature = LEVIN_SIGNATURE; + head.m_cb = in_buff.size(); + head.m_have_to_return_data = false; + head.m_id = target; +#ifdef TRACE_LEVIN_PACKETS_BY_GUIDS + ::UuidCreate(&head.m_id); +#endif + head.m_command = command; + head.m_protocol_version = LEVIN_PROTOCOL_VER_1; + head.m_flags = LEVIN_PACKET_REQUEST; + CRITICAL_REGION_BEGIN(m_send_lock); + LOG_PRINT_L4("[" << m_socket <<"] SEND " << sizeof(head)); + int res = ::send(m_socket, (const char*)&head, sizeof(head), 0); + if(SOCKET_ERROR == res) + { + int err = ::WSAGetLastError(); + LOG_ERROR("Failed to send(), err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\""); + disconnect(); + return LEVIN_ERROR_CONNECTION_DESTROYED; + } + LOG_PRINT_L4("[" << m_socket <<"] SEND " << (int)in_buff.size()); + res = ::send(m_socket, in_buff.data(), (int)in_buff.size(), 0); + if(SOCKET_ERROR == res) + { + int err = ::WSAGetLastError(); + LOG_ERROR("Failed to send(), err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\""); + disconnect(); + return LEVIN_ERROR_CONNECTION_DESTROYED; + } + CRITICAL_REGION_END(); + LOG_PRINT_L4("LEVIN_PACKET_SENT. [len=" << head.m_cb << ", flags=" << head.m_flags << ", is_cmd=" << head.m_have_to_return_data <<", cmd_id = " << head.m_command << ", pr_v=" << head.m_protocol_version << ", uid=" << string_tools::get_str_from_guid_a(head.m_id) << "]"); + + return 1; + } + + + private: + bool have_some_data(SOCKET sock, int interval = 1) + { + fd_set fds; + FD_ZERO(&fds); + FD_SET(sock, &fds); + + fd_set fdse; + FD_ZERO(&fdse); + FD_SET(sock, &fdse); + + + timeval tv; + tv.tv_sec = interval; + tv.tv_usec = 0; + + int sel_res = select(0, &fds, 0, &fdse, &tv); + if(0 == sel_res) + return false; + else if(sel_res == SOCKET_ERROR) + { + if(m_is_stop) + return false; + int err_code = ::WSAGetLastError(); + LOG_ERROR("Filed to call select, err code = " << err_code); + disconnect(); + }else + { + if(fds.fd_array[0]) + {//some read operations was performed + return true; + }else if(fdse.fd_array[0]) + {//some error was at the socket + return true; + } + } + return false; + } + + + bool reciev_and_process_incoming_data() + { + bucket_head head = {0}; + uint32_t conn_index = 0; + bool is_request = false; + std::string local_buff; + CRITICAL_REGION_BEGIN(m_reciev_packet_lock);//to protect from socket reconnect between head and body + + if(!recv_n(m_socket, (char*)&head, sizeof(head))) + { + if(m_is_stop) + return false; + LOG_ERROR("Failed to recv_n"); + return false; + } + + conn_index = boost::interprocess::ipcdetail::atomic_read32(&m_current_connection_index); + + if(head.m_signature!=LEVIN_SIGNATURE) + { + LOG_ERROR("Signature missmatch in response"); + return false; + } + + is_request = (head.m_protocol_version == LEVIN_PROTOCOL_VER_1 && head.m_flags&LEVIN_PACKET_REQUEST); + + + local_buff.resize((size_t)head.m_cb); + if(!recv_n(m_socket, local_buff)) + { + if(m_is_stop) + return false; + LOG_ERROR("Filed to reciev"); + return false; + } + CRITICAL_REGION_END(); + + LOG_PRINT_L4("LEVIN_PACKET_RECIEVED. [len=" << head.m_cb << ", flags=" << head.m_flags << ", is_cmd=" << head.m_have_to_return_data <<", cmd_id = " << head.m_command << ", pr_v=" << head.m_protocol_version << ", uid=" << string_tools::get_str_from_guid_a(head.m_id) << "]"); + + if(is_request) + { + CRITICAL_REGION_BEGIN(m_recieved_packets_lock); + m_recieved_packets.resize(m_recieved_packets.size() + 1); + m_recieved_packets.back().m_hd = head; + m_recieved_packets.back().m_body.swap(local_buff); + m_recieved_packets.back().m_connection_index = conn_index; + CRITICAL_REGION_END(); + /* + + */ + }else + {//this is some response + + CRITICAL_REGION_BEGIN(m_local_invoke_buff_lock); + m_local_invoke_buff.swap(local_buff); + m_invoke_res = head.m_return_code; + CRITICAL_REGION_END(); + boost::interprocess::ipcdetail::atomic_write32(&m_invoke_data_ready, 1); //m_invoke_data_ready = true; + m_invoke_cond.notify_all(); + + } + return true; + } + + bool reciever_thread() + { + LOG_PRINT_L3("[" << m_socket <<"] Socket reciever thread started.[m_threads_count=" << m_threads_count << "]"); + log_space::log_singletone::set_thread_log_prefix("RECIEVER_WORKER"); + boost::interprocess::ipcdetail::atomic_inc32(&m_threads_count); + + while(!m_is_stop) + { + if(!m_connected) + { + Sleep(100); + continue; + } + + if(have_some_data(m_socket, 1)) + { + if(!reciev_and_process_incoming_data()) + { + if(m_is_stop) + { + break;//boost::interprocess::ipcdetail::atomic_dec32(&m_threads_count); + //return true; + } + LOG_ERROR("Failed to reciev_and_process_incoming_data. shutting down"); + //boost::interprocess::ipcdetail::atomic_dec32(&m_threads_count); + //disconnect_no_wait(); + //break; + } + } + } + + boost::interprocess::ipcdetail::atomic_dec32(&m_threads_count); + LOG_PRINT_L3("[" << m_socket <<"] Socket reciever thread stopped.[m_threads_count=" << m_threads_count << "]"); + return true; + } + + bool process_recieved_packet(bucket_head& head, const std::string& local_buff, uint32_t conn_index) + { + + net_utils::connection_context_base conn_context; + conn_context.m_remote_ip = m_ip; + conn_context.m_remote_port = m_port; + if(head.m_have_to_return_data) + { + std::string return_buff; + if(m_pcommands_handler) + head.m_return_code = m_pcommands_handler->invoke(head.m_id, head.m_command, local_buff, return_buff, conn_context); + else + head.m_return_code = LEVIN_ERROR_CONNECTION_HANDLER_NOT_DEFINED; + + + + head.m_cb = return_buff.size(); + head.m_have_to_return_data = false; + head.m_protocol_version = LEVIN_PROTOCOL_VER_1; + head.m_flags = LEVIN_PACKET_RESPONSE; + + std::string send_buff((const char*)&head, sizeof(head)); + send_buff += return_buff; + CRITICAL_REGION_BEGIN(m_send_lock); + if(conn_index != boost::interprocess::ipcdetail::atomic_read32(&m_current_connection_index)) + {//there was reconnect, send response back is not allowed + return true; + } + int res = ::send(m_socket, (const char*)send_buff.data(), send_buff.size(), 0); + if(res == SOCKET_ERROR) + { + int err_code = ::WSAGetLastError(); + LOG_ERROR("Failed to send, err = " << err_code); + return false; + } + CRITICAL_REGION_END(); + LOG_PRINT_L4("LEVIN_PACKET_SENT. [len=" << head.m_cb << ", flags=" << head.m_flags << ", is_cmd=" << head.m_have_to_return_data <<", cmd_id = " << head.m_command << ", pr_v=" << head.m_protocol_version << ", uid=" << string_tools::get_str_from_guid_a(head.m_id) << "]"); + + } + else + { + if(m_pcommands_handler) + m_pcommands_handler->notify(head.m_id, head.m_command, local_buff, conn_context); + } + + return true; + } + + bool handler_thread() + { + LOG_PRINT_L3("[" << m_socket <<"] Socket handler thread started.[m_threads_count=" << m_threads_count << "]"); + log_space::log_singletone::set_thread_log_prefix("HANDLER_WORKER"); + boost::interprocess::ipcdetail::atomic_inc32(&m_threads_count); + + while(!m_is_stop) + { + bool have_some_work = false; + std::string local_buff; + bucket_head bh = {0}; + uint32_t conn_index = 0; + + CRITICAL_REGION_BEGIN(m_recieved_packets_lock); + if(m_recieved_packets.size()) + { + bh = m_recieved_packets.begin()->m_hd; + conn_index = m_recieved_packets.begin()->m_connection_index; + local_buff.swap(m_recieved_packets.begin()->m_body); + have_some_work = true; + m_recieved_packets.pop_front(); + } + CRITICAL_REGION_END(); + + if(have_some_work) + { + process_recieved_packet(bh, local_buff, conn_index); + }else + { + //Idle when no work + Sleep(30); + } + } + + boost::interprocess::ipcdetail::atomic_dec32(&m_threads_count); + LOG_PRINT_L3("[" << m_socket <<"] Socket handler thread stopped.[m_threads_count=" << m_threads_count << "]"); + return true; + } + }; + +} +} \ No newline at end of file diff --git a/contrib/epee/include/net/levin_client_async.inl b/contrib/epee/include/net/levin_client_async.inl new file mode 100644 index 00000000..e69de29b diff --git a/contrib/epee/include/net/levin_helper.h b/contrib/epee/include/net/levin_helper.h new file mode 100644 index 00000000..a8406103 --- /dev/null +++ b/contrib/epee/include/net/levin_helper.h @@ -0,0 +1,137 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#pragma once + +#include "levin_base.h" +#include "serializeble_struct_helper.h" + +namespace epee +{ +namespace levin +{ + template + bool pack_struct_to_levin_message(const t_struct& t, std::string& buff, int command_id) + { + buff.resize(sizeof(levin::bucket_head)); + levin::bucket_head& head = *(levin::bucket_head*)(&buff[0]); + head.m_signature = LEVIN_SIGNATURE; + head.m_cb = 0; + head.m_have_to_return_data = true; + head.m_command = command_id; + head.m_return_code = 1; + head.m_reservedA = rand(); //probably some flags in future + head.m_reservedB = rand(); //probably some check summ in future + + std::string buff_strg; + if(!StorageNamed::save_struct_as_storage_to_buff_t(t, buff_strg)) + return false; + + head.m_cb = buff_strg.size(); + buff.append(buff_strg); + return true; + } + + + bool pack_data_to_levin_message(const std::string& data, std::string& buff, int command_id) + { + buff.resize(sizeof(levin::bucket_head)); + levin::bucket_head& head = *(levin::bucket_head*)(&buff[0]); + head.m_signature = LEVIN_SIGNATURE; + head.m_cb = 0; + head.m_have_to_return_data = true; + head.m_command = command_id; + head.m_return_code = 1; + head.m_reservedA = rand(); //probably some flags in future + head.m_reservedB = rand(); //probably some check summ in future + + head.m_cb = data.size(); + buff.append(data); + return true; + } + + bool load_levin_data_from_levin_message(std::string& levin_data, const std::string& buff, int& command) + { + if(buff.size() < sizeof(levin::bucket_head) ) + { + LOG_PRINT_L3("size of buff(" << buff.size() << ") is too small, at load_struct_from_levin_message"); + return false; + } + + levin::bucket_head& head = *(levin::bucket_head*)(&buff[0]); + if(head.m_signature != LEVIN_SIGNATURE) + { + LOG_PRINT_L3("Failed to read signature in levin message, at load_struct_from_levin_message"); + return false; + } + if(head.m_cb != buff.size()-sizeof(levin::bucket_head)) + { + LOG_PRINT_L3("sizes missmatch, at load_struct_from_levin_message"); + return false; + } + + //std::string buff_strg; + levin_data.assign(&buff[sizeof(levin::bucket_head)], buff.size()-sizeof(levin::bucket_head)); + command = head.m_command; + return true; + } + + template + bool load_struct_from_levin_message(t_struct& t, const std::string& buff, int& command) + { + if(buff.size() < sizeof(levin::bucket_head) ) + { + LOG_ERROR("size of buff(" << buff.size() << ") is too small, at load_struct_from_levin_message"); + return false; + } + + levin::bucket_head& head = *(levin::bucket_head*)(&buff[0]); + if(head.m_signature != LEVIN_SIGNATURE) + { + LOG_ERROR("Failed to read signature in levin message, at load_struct_from_levin_message"); + return false; + } + if(head.m_cb != buff.size()-sizeof(levin::bucket_head)) + { + LOG_ERROR("sizes missmatch, at load_struct_from_levin_message"); + return false; + } + + std::string buff_strg; + buff_strg.assign(&buff[sizeof(levin::bucket_head)], buff.size()-sizeof(levin::bucket_head)); + + if(!StorageNamed::load_struct_from_storage_buff_t(t, buff_strg)) + { + LOG_ERROR("Failed to read storage, at load_struct_from_levin_message"); + return false; + } + command = head.m_command; + return true; + } +} +} \ No newline at end of file diff --git a/contrib/epee/include/net/levin_protocol_handler.h b/contrib/epee/include/net/levin_protocol_handler.h new file mode 100644 index 00000000..e693d2f0 --- /dev/null +++ b/contrib/epee/include/net/levin_protocol_handler.h @@ -0,0 +1,176 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#ifndef _LEVIN_PROTOCOL_HANDLER_H_ +#define _LEVIN_PROTOCOL_HANDLER_H_ + +#include +#include "levin_base.h" + + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL "net_protocol" + +namespace epee +{ +namespace levin +{ + template + struct protocl_handler_config + { + levin_commands_handler* m_pcommands_handler; + }; + + template + class protocol_handler + { + public: + typedef t_connection_context connection_context; + typedef protocl_handler_config config_type; + + protocol_handler(net_utils::i_service_endpoint* psnd_hndlr, config_type& config, t_connection_context& conn_context); + virtual ~protocol_handler(){} + + virtual bool handle_recv(const void* ptr, size_t cb); + + bool after_init_connection(){return true;} + private: + enum connection_data_state + { + conn_state_reading_head, + conn_state_reading_body + }; + + + config_type& m_config; + t_connection_context& m_conn_context; + net_utils::i_service_endpoint* m_psnd_hndlr; + std::string m_cach_in_buffer; + connection_data_state m_state; + bucket_head m_current_head; + }; + + template + protocol_handler::protocol_handler(net_utils::i_service_endpoint* psnd_hndlr, config_type& config, t_connection_context& conn_context): + m_config(config), + m_conn_context(conn_context), + m_psnd_hndlr(psnd_hndlr), + m_state(conn_state_reading_head), + m_current_head(bucket_head()) + {} + + template + bool protocol_handler::handle_recv(const void* ptr, size_t cb) + { + if(!m_config.m_pcommands_handler) + { + LOG_ERROR("Command handler not set!"); + return false; + } + m_cach_in_buffer.append((const char*)ptr, cb); + + bool is_continue = true; + while(is_continue) + { + switch(m_state) + { + case conn_state_reading_head: + if(m_cach_in_buffer.size() < sizeof(bucket_head)) + { + if(m_cach_in_buffer.size() >= sizeof(uint64_t) && *((uint64_t*)m_cach_in_buffer.data()) != LEVIN_SIGNATURE) + { + LOG_ERROR("Signature missmatch on accepted connection"); + return false; + } + is_continue = false; + break; + } + { + bucket_head* phead = (bucket_head*)m_cach_in_buffer.data(); + if(LEVIN_SIGNATURE != phead->m_signature) + { + LOG_ERROR("Signature missmatch on accepted connection"); + return false; + } + m_current_head = *phead; + } + m_cach_in_buffer.erase(0, sizeof(bucket_head)); + m_state = conn_state_reading_body; + break; + case conn_state_reading_body: + if(m_cach_in_buffer.size() < m_current_head.m_cb) + { + is_continue = false; + break; + } + { + std::string buff_to_invoke; + if(m_cach_in_buffer.size() == m_current_head.m_cb) + buff_to_invoke.swap(m_cach_in_buffer); + else + { + buff_to_invoke.assign(m_cach_in_buffer, 0, (std::string::size_type)m_current_head.m_cb); + m_cach_in_buffer.erase(0, (std::string::size_type)m_current_head.m_cb); + } + + + if(m_current_head.m_have_to_return_data) + { + std::string return_buff; + m_current_head.m_return_code = m_config.m_pcommands_handler->invoke(m_current_head.m_command, buff_to_invoke, return_buff, m_conn_context); + m_current_head.m_cb = return_buff.size(); + m_current_head.m_have_to_return_data = false; + std::string send_buff((const char*)&m_current_head, sizeof(m_current_head)); + send_buff += return_buff; + + if(!m_psnd_hndlr->do_send(send_buff.data(), send_buff.size())) + return false; + + } + else + m_config.m_pcommands_handler->notify(m_current_head.m_command, buff_to_invoke, m_conn_context); + } + m_state = conn_state_reading_head; + break; + default: + LOG_ERROR("Undefined state in levin_server_impl::connection_handler, m_state=" << m_state); + return false; + } + } + + return true; + } +} +} + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL NULL + + +#endif //_LEVIN_PROTOCOL_HANDLER_H_ + diff --git a/contrib/epee/include/net/levin_protocol_handler_async.h b/contrib/epee/include/net/levin_protocol_handler_async.h new file mode 100644 index 00000000..105af24a --- /dev/null +++ b/contrib/epee/include/net/levin_protocol_handler_async.h @@ -0,0 +1,885 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + +#pragma once +#include +#include + +#include +#include +#include + +#include "levin_base.h" +#include "misc_language.h" +#include "profile_tools.h" + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL "levin_protocol" +ENABLE_CHANNEL_BY_DEFAULT("levin_protocol"); + +namespace epee +{ +namespace levin +{ + +/************************************************************************/ +/* */ +/************************************************************************/ +template +class async_protocol_handler; + +template +class async_protocol_handler_config +{ + typedef std::unordered_map* , boost::hash > connections_map; + critical_section m_connects_lock; + std::atomic m_is_in_sendstop_loop; + connections_map m_connects; + + void add_connection(async_protocol_handler* pc); + void del_connection(async_protocol_handler* pc); + + async_protocol_handler* find_connection(boost::uuids::uuid connection_id) const; + int find_and_lock_connection(boost::uuids::uuid connection_id, async_protocol_handler*& aph); + + friend class async_protocol_handler; + +public: + typedef t_connection_context connection_context; + levin_commands_handler* m_pcommands_handler; + uint64_t m_max_packet_size; + uint64_t m_invoke_timeout; + + void on_send_stop_signal(); + int invoke(int command, const std::string& in_buff, std::string& buff_out, boost::uuids::uuid connection_id); + template + int invoke_async(int command, const std::string& in_buff, boost::uuids::uuid connection_id, callback_t cb, size_t timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED); + + int notify(int command, const std::string& in_buff, boost::uuids::uuid connection_id); + bool close(boost::uuids::uuid connection_id); + bool update_connection_context(const t_connection_context& contxt); + bool request_callback(boost::uuids::uuid connection_id); + template + bool foreach_connection(callback_t cb); + size_t get_connections_count(); + + async_protocol_handler_config() :m_pcommands_handler(NULL), m_max_packet_size(LEVIN_DEFAULT_MAX_PACKET_SIZE), m_is_in_sendstop_loop(false) + {} + ~async_protocol_handler_config() + { + CRITICAL_REGION_LOCAL(m_connects_lock); + m_connects.clear(); + } + +}; + + +/************************************************************************/ +/* */ +/************************************************************************/ +template +class async_protocol_handler +{ +public: + typedef t_connection_context connection_context; + typedef async_protocol_handler_config config_type; + + enum stream_state + { + stream_state_head, + stream_state_body + }; + + std::atomic m_deletion_initiated; + std::atomic m_protocol_released; + volatile uint32_t m_invoke_buf_ready; + + volatile int m_invoke_result_code; + + critical_section m_local_inv_buff_lock; + std::string m_local_inv_buff; + + critical_section m_send_lock; + critical_section m_call_lock; + + volatile uint32_t m_wait_count; + volatile uint32_t m_close_called; + bucket_head2 m_current_head; + net_utils::i_service_endpoint* m_pservice_endpoint; + config_type& m_config; + t_connection_context& m_connection_context; + + std::string m_cache_in_buffer; + stream_state m_state; + + int32_t m_oponent_protocol_ver; + bool m_connection_initialized; + + struct invoke_response_handler_base + { + virtual bool handle(int res, const std::string& buff, connection_context& context)=0; + virtual bool is_timer_started() const=0; + virtual void cancel()=0; + virtual bool cancel_timer()=0; + }; + template + struct invoke_handler: invoke_response_handler_base + { + invoke_handler(const callback_t& cb, uint64_t timeout, async_protocol_handler& con, int command) + :m_cb(cb), m_con(con), m_timer(con.m_pservice_endpoint->get_io_service()), m_timer_started(false), + m_cancel_timer_called(false), m_timer_cancelled(false), m_command(command) + { + if(m_con.start_outer_call()) + { + m_timer.expires_from_now(boost::posix_time::milliseconds(timeout)); + m_timer.async_wait([&con, command, cb](const boost::system::error_code& ec) + { + if(ec == boost::asio::error::operation_aborted) + return; + LOG_PRINT_CC(con.get_context_ref(), "Timeout on invoke operation happened, command: " << command, LOG_LEVEL_2); + std::string fake; + cb(LEVIN_ERROR_CONNECTION_TIMEDOUT, fake, con.get_context_ref()); + con.close(); + con.finish_outer_call(); + }); + m_timer_started = true; + } + } + virtual ~invoke_handler() + {} + callback_t m_cb; + async_protocol_handler& m_con; + boost::asio::deadline_timer m_timer; + bool m_timer_started; + std::atomic m_cancel_timer_called; + bool m_timer_cancelled; + int m_command; + virtual bool handle(int res, const std::string& buff, typename async_protocol_handler::connection_context& context) + { + if(!cancel_timer()) + return false; + m_cb(res, buff, context); + m_con.finish_outer_call(); + return true; + } + virtual bool is_timer_started() const + { + return m_timer_started; + } + virtual void cancel() + { + if(cancel_timer()) + { + std::string fake; + m_cb(LEVIN_ERROR_CONNECTION_DESTROYED, fake, m_con.get_context_ref()); + m_con.finish_outer_call(); + } + } + virtual bool cancel_timer() + { + if(!m_cancel_timer_called) + { + m_cancel_timer_called = true; + boost::system::error_code ignored_ec; + m_timer_cancelled = 1 == m_timer.cancel(ignored_ec); + } + return m_timer_cancelled; + } + }; + critical_section m_invoke_response_handlers_lock; + std::list > m_invoke_response_handlers; + + template + bool add_invoke_response_handler(callback_t cb, uint64_t timeout, async_protocol_handler& con, int command) + { + CRITICAL_REGION_LOCAL(m_invoke_response_handlers_lock); + boost::shared_ptr handler(boost::make_shared>(cb, timeout, con, command)); + m_invoke_response_handlers.push_back(handler); + LOG_PRINT_L4("[LEVIN_PROTOCOL" << this << "] INVOKE_HANDLER_QUE: PUSH_BACK RESPONSE HANDLER"); + return handler->is_timer_started(); + } + template friend struct invoke_handler; +public: + async_protocol_handler(net_utils::i_service_endpoint* psnd_hndlr, + config_type& config, + t_connection_context& conn_context): + m_current_head(bucket_head2()), + m_pservice_endpoint(psnd_hndlr), + m_config(config), + m_connection_context(conn_context), + m_state(stream_state_head) + { + m_close_called = 0; + m_deletion_initiated = false; + m_protocol_released = false; + m_wait_count = 0; + m_oponent_protocol_ver = 0; + m_connection_initialized = false; + LOG_PRINT_CC(m_connection_context, "[LEVIN_PROTOCOL" << this << "] CONSTRUCTED", LOG_LEVEL_4); + } + + virtual ~async_protocol_handler() + { + m_deletion_initiated = true; + if(m_connection_initialized) + { + m_config.del_connection(this); + } + + for (size_t i = 0; i < 60 * 1000 / 100 && 0 != boost::interprocess::ipcdetail::atomic_read32(&m_wait_count); ++i) + { + misc_utils::sleep_no_w(100); + } + CHECK_AND_ASSERT_MES_NO_RET(0 == boost::interprocess::ipcdetail::atomic_read32(&m_wait_count), "Failed to wait for operation completion. m_wait_count = " << m_wait_count); + + LOG_PRINT_CC(m_connection_context, "[LEVIN_PROTOCOL" << this << "] DESTRUCTING", LOG_LEVEL_4); + + VALIDATE_MUTEX_IS_FREE(m_local_inv_buff_lock); + VALIDATE_MUTEX_IS_FREE(m_send_lock); + VALIDATE_MUTEX_IS_FREE(m_call_lock); + VALIDATE_MUTEX_IS_FREE(m_invoke_response_handlers_lock); + } + + bool start_outer_call() + { + LOG_PRINT_CC_L4(m_connection_context, "[LEVIN_PROTOCOL" << this << "] -->> start_outer_call"); + if(!m_pservice_endpoint->add_ref()) + { + LOG_PRINT_CC_RED(m_connection_context, "[LEVIN_PROTOCOL" << this << "] -->> start_outer_call failed", LOG_LEVEL_4); + return false; + } + boost::interprocess::ipcdetail::atomic_inc32(&m_wait_count); + return true; + } + bool finish_outer_call() + { + LOG_PRINT_CC_L4(m_connection_context, "[LEVIN_PROTOCOL" << this << "] <<-- finish_outer_call"); + boost::interprocess::ipcdetail::atomic_dec32(&m_wait_count); + m_pservice_endpoint->release(); + return true; + } + + bool release_protocol() + { + decltype(m_invoke_response_handlers) local_invoke_response_handlers; + CRITICAL_REGION_BEGIN(m_invoke_response_handlers_lock); + LOG_PRINT_L4("[LEVIN_PROTOCOL" << this << "] INVOKE_HANDLER_QUE: Invoke response_handlers(" << m_invoke_response_handlers.size() <<") swap, protocol released"); + local_invoke_response_handlers.swap(m_invoke_response_handlers); + m_protocol_released = true; + CRITICAL_REGION_END(); + + // Never call callback inside critical section, that can cause deadlock. Callback can be called when + // invoke_response_handler_base is cancelled + std::for_each(local_invoke_response_handlers.begin(), local_invoke_response_handlers.end(), [](const boost::shared_ptr& pinv_resp_hndlr) { + pinv_resp_hndlr->cancel(); + }); + LOG_PRINT_L4("[LEVIN_PROTOCOL" << this << "] Invoke response_handlers(" << local_invoke_response_handlers.size() << ") canceled"); + return true; + } + + bool close() + { + boost::interprocess::ipcdetail::atomic_inc32(&m_close_called); + + m_pservice_endpoint->close(); + return true; + } + + void update_connection_context(const connection_context& contxt) + { + m_connection_context = contxt; + } + + void request_callback() + { + misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler( + boost::bind(&async_protocol_handler::finish_outer_call, this)); + + m_pservice_endpoint->request_callback(); + } + + void handle_qued_callback() + { + m_config.m_pcommands_handler->callback(m_connection_context); + } + + virtual bool handle_recv(const void* ptr, size_t cb) + { + if(boost::interprocess::ipcdetail::atomic_read32(&m_close_called)) + return false; //closing connections + + //update threads name to see connection context where errors came from + std::string original_prefix = epee::log_space::log_singletone::get_thread_log_prefix(); + epee::log_space::log_singletone::set_thread_log_prefix(original_prefix + "[" + epee::net_utils::print_connection_context_short(m_connection_context) + "]"); + ON_EXIT([&](){epee::log_space::log_singletone::set_thread_log_prefix(original_prefix); }); + + //create_scope_leave_handler() + + if(!m_config.m_pcommands_handler) + { + LOG_ERROR_CC(m_connection_context, "[LEVIN_PROTOCOL" << this << "]Commands handler not set!"); + return false; + } + + if(m_cache_in_buffer.size() + cb > m_config.m_max_packet_size) + { + LOG_ERROR_CC(m_connection_context, "[LEVIN_PROTOCOL" << this << "]Maximum packet size exceed!, m_max_packet_size = " << m_config.m_max_packet_size + << ", packet received " << m_cache_in_buffer.size() + cb + << ", connection will be closed."); + return false; + } + + m_cache_in_buffer.append((const char*)ptr, cb); + + bool is_continue = true; + while(is_continue) + { + switch(m_state) + { + case stream_state_body: + if(m_cache_in_buffer.size() < m_current_head.m_cb) + { + is_continue = false; + break; + } + { + std::string buff_to_invoke; + if(m_cache_in_buffer.size() == m_current_head.m_cb) + buff_to_invoke.swap(m_cache_in_buffer); + else + { + buff_to_invoke.assign(m_cache_in_buffer, 0, (std::string::size_type)m_current_head.m_cb); + m_cache_in_buffer.erase(0, (std::string::size_type)m_current_head.m_cb); + } + + bool is_response = (m_oponent_protocol_ver == LEVIN_PROTOCOL_VER_1 && m_current_head.m_flags&LEVIN_PACKET_RESPONSE); + + + LOG_PRINT_CC_L4(m_connection_context, "[LEVIN_PROTOCOL" << this << "] RECIEVED PACKET [" << (is_response ? ("RESP"):(m_current_head.m_have_to_return_data? "-->INVOKE":"-->NOTIFY")) << "][len=" << m_current_head.m_cb + << ", flags" << m_current_head.m_flags + << ", r?=" << m_current_head.m_have_to_return_data + <<", cmd = " << m_current_head.m_command + << ", v=" << m_current_head.m_protocol_version); + + if(is_response) + {//response to some invoke + CRITICAL_REGION_LOCAL_VAR(m_invoke_response_handlers_lock, invoke_response_handlers_guard); + if(!m_invoke_response_handlers.empty()) + {//async call scenario + boost::shared_ptr response_handler = m_invoke_response_handlers.front(); + bool timer_cancelled = response_handler->cancel_timer(); + + if (timer_cancelled) + { + LOG_PRINT_L4("[LEVIN_PROTOCOL" << this << "] INVOKE_HANDLER_QUE: POP_FRONT"); + m_invoke_response_handlers.pop_front(); + } + invoke_response_handlers_guard.unlock();//manual unlock(this type of guard let manual unlock) + + if(timer_cancelled) + response_handler->handle(m_current_head.m_return_code, buff_to_invoke, m_connection_context); + } + else + { + invoke_response_handlers_guard.unlock();//manual unlock(this type of guard let manual unlock) + //use sync call scenario + if(!boost::interprocess::ipcdetail::atomic_read32(&m_wait_count) && !boost::interprocess::ipcdetail::atomic_read32(&m_close_called)) + { + if(!m_protocol_released) + { + LOG_ERROR_CC(m_connection_context, "[LEVIN_PROTOCOL" << this << "]no active invoke when response came, wtf?"); + } + return false; + }else + { + CRITICAL_REGION_BEGIN(m_local_inv_buff_lock); + buff_to_invoke.swap(m_local_inv_buff); + buff_to_invoke.clear(); + m_invoke_result_code = m_current_head.m_return_code; + CRITICAL_REGION_END(); + boost::interprocess::ipcdetail::atomic_write32(&m_invoke_buf_ready, 1); + } + } + }else + { + if(m_current_head.m_have_to_return_data) + { + std::string return_buff; + TIME_MEASURE_START_MS(invoke_handle_time); + m_current_head.m_return_code = m_config.m_pcommands_handler->invoke( + m_current_head.m_command, + buff_to_invoke, + return_buff, + m_connection_context); + TIME_MEASURE_FINISH_MS(invoke_handle_time); + LOG_PRINT_CC_L3(m_connection_context, "[LEVIN_PROTOCOL" << this << "] INVOKE HANDLER: " << invoke_handle_time << "ms, command: " << m_current_head.m_command); + if (invoke_handle_time > m_config.m_invoke_timeout / 2) + { + LOG_PRINT_CC_RED(m_connection_context, "[LEVIN_PROTOCOL" << this << "] LONG INVOKE HANDLER: " << invoke_handle_time << "ms, command: " << m_current_head.m_command, LOG_LEVEL_0); + } + + m_current_head.m_cb = return_buff.size(); + m_current_head.m_have_to_return_data = false; + m_current_head.m_protocol_version = LEVIN_PROTOCOL_VER_1; + m_current_head.m_flags = LEVIN_PACKET_RESPONSE; + std::string send_buff((const char*)&m_current_head, sizeof(m_current_head)); + send_buff += return_buff; + CRITICAL_REGION_BEGIN(m_send_lock); + if(!m_pservice_endpoint->do_send(send_buff.data(), send_buff.size())) + return false; + CRITICAL_REGION_END(); + LOG_PRINT_CC_L4(m_connection_context, "[LEVIN_PROTOCOL" << this << "] PACKET_SENT. [len=" << m_current_head.m_cb + << ", flags" << m_current_head.m_flags + << ", r?=" << m_current_head.m_have_to_return_data + <<", cmd = " << m_current_head.m_command + << ", ver=" << m_current_head.m_protocol_version); + } + else + { + + TIME_MEASURE_START_MS(notify_handle_time); + m_config.m_pcommands_handler->notify(m_current_head.m_command, buff_to_invoke, m_connection_context); + TIME_MEASURE_FINISH_MS(notify_handle_time); + LOG_PRINT_CC_L3(m_connection_context, "[LEVIN_PROTOCOL" << this << "] NOTIFY HANDLER: " << notify_handle_time << "ms, command: " << m_current_head.m_command); + if (notify_handle_time > m_config.m_invoke_timeout / 2) + { + LOG_PRINT_CC_RED(m_connection_context, "[LEVIN_PROTOCOL" << this << "] LONG NOTIFY HANDLER: " << notify_handle_time << "ms, command: " << m_current_head.m_command, LOG_LEVEL_0); + } + + } + + } + } + m_state = stream_state_head; + break; + case stream_state_head: + { + if(m_cache_in_buffer.size() < sizeof(bucket_head2)) + { + if(m_cache_in_buffer.size() >= sizeof(uint64_t) && *((uint64_t*)m_cache_in_buffer.data()) != LEVIN_SIGNATURE) + { + LOG_PRINT_CC_L0(m_connection_context, "[LEVIN_PROTOCOL" << this << "] Signature mismatch, connection will be closed"); + return false; + } + is_continue = false; + break; + } + + bucket_head2* phead = (bucket_head2*)m_cache_in_buffer.data(); + if(LEVIN_SIGNATURE != phead->m_signature) + { + LOG_PRINT_CC_L0(m_connection_context, "[LEVIN_PROTOCOL" << this << "] Signature mismatch, connection will be closed"); + return false; + } + m_current_head = *phead; + + m_cache_in_buffer.erase(0, sizeof(bucket_head2)); + m_state = stream_state_body; + LOG_PRINT_L4("[LEVIN_PROTOCOL" << this << "] RECEIVED_HEADER(command " << m_current_head.m_command << ")"); + m_oponent_protocol_ver = m_current_head.m_protocol_version; + if(m_current_head.m_cb > m_config.m_max_packet_size) + { + LOG_ERROR_CC(m_connection_context, "[LEVIN_PROTOCOL" << this << "]Maximum packet size exceed!, m_max_packet_size = " << m_config.m_max_packet_size + << ", packet header received " << m_current_head.m_cb + << ", connection will be closed."); + return false; + } + } + break; + default: + LOG_ERROR_CC(m_connection_context, "[LEVIN_PROTOCOL" << this << "]Undefined state in levin_server_impl::connection_handler, m_state=" << m_state); + return false; + } + } + + return true; + } + + bool after_init_connection() + { + if (!m_connection_initialized) + { + m_connection_initialized = true; + m_config.add_connection(this); + } + return true; + } + + template + bool async_invoke(int command, const std::string& in_buff, callback_t cb, size_t timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED) + { + misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler( + boost::bind(&async_protocol_handler::finish_outer_call, this)); + + if(timeout == LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED) + timeout = static_cast(m_config.m_invoke_timeout); + + int err_code = LEVIN_OK; + do + { + if(m_deletion_initiated) + { + err_code = LEVIN_ERROR_CONNECTION_DESTROYED; + break; + } + + CRITICAL_REGION_LOCAL(m_call_lock); + + if(m_deletion_initiated) + { + err_code = LEVIN_ERROR_CONNECTION_DESTROYED; + break; + } + + bucket_head2 head = {0}; + head.m_signature = LEVIN_SIGNATURE; + head.m_cb = in_buff.size(); + head.m_have_to_return_data = true; + + head.m_flags = LEVIN_PACKET_REQUEST; + head.m_command = command; + head.m_protocol_version = LEVIN_PROTOCOL_VER_1; + + boost::interprocess::ipcdetail::atomic_write32(&m_invoke_buf_ready, 0); + CRITICAL_REGION_BEGIN(m_send_lock); + CRITICAL_REGION_LOCAL1(m_invoke_response_handlers_lock); + if(!m_pservice_endpoint->do_send(&head, sizeof(head))) + { + LOG_PRINT_CC_RED(m_connection_context, "[LEVIN_PROTOCOL" << this << "]Failed to do_send", LOG_LEVEL_2); + err_code = LEVIN_ERROR_CONNECTION; + break; + } + LOG_PRINT_L4("[LEVIN_PROTOCOL" << this << "] SENT_HEADER(command " << command << ")"); + + + //add response handler before do_send of the last + //part of packet, in case if it somehow lead to situation when response + //comes before it return control and response could be handled + //by protocol state machine without proper invoke_response_handler + if (!add_invoke_response_handler(cb, timeout, *this, command)) + { + err_code = LEVIN_ERROR_CONNECTION_DESTROYED; + break; + } + LOG_PRINT_L4("[LEVIN_PROTOCOL" << this << "] ADD_INVOKE_HANDLER(command " << command << ")"); + + + if(!m_pservice_endpoint->do_send(in_buff.data(), (int)in_buff.size())) + { + LOG_PRINT_CC_RED(m_connection_context, "Failed to do_send", LOG_LEVEL_2); + err_code = LEVIN_ERROR_CONNECTION; + break; + } + LOG_PRINT_L4("[LEVIN_PROTOCOL" << this << "] SENT_BODY(command " << command << ")"); + + + CRITICAL_REGION_END(); + } while (false); + + if (LEVIN_OK != err_code) + { + std::string stub_buff; + // Never call callback inside critical section, that can cause deadlock + cb(err_code, stub_buff, m_connection_context); + return false; + } + + return true; + } + + int invoke(int command, const std::string& in_buff, std::string& buff_out) + { + misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler( + boost::bind(&async_protocol_handler::finish_outer_call, this)); + + if(m_deletion_initiated) + return LEVIN_ERROR_CONNECTION_DESTROYED; + + CRITICAL_REGION_LOCAL(m_call_lock); + + if(m_deletion_initiated) + return LEVIN_ERROR_CONNECTION_DESTROYED; + + bucket_head2 head = {0}; + head.m_signature = LEVIN_SIGNATURE; + head.m_cb = in_buff.size(); + head.m_have_to_return_data = true; + + head.m_flags = LEVIN_PACKET_REQUEST; + head.m_command = command; + head.m_protocol_version = LEVIN_PROTOCOL_VER_1; + + boost::interprocess::ipcdetail::atomic_write32(&m_invoke_buf_ready, 0); + CRITICAL_REGION_BEGIN(m_send_lock); + if(!m_pservice_endpoint->do_send(&head, sizeof(head))) + { + LOG_ERROR_CC(m_connection_context, "[LEVIN_PROTOCOL" << this << "]Failed to do_send"); + return LEVIN_ERROR_CONNECTION; + } + + if(!m_pservice_endpoint->do_send(in_buff.data(), (int)in_buff.size())) + { + LOG_ERROR_CC(m_connection_context, "[LEVIN_PROTOCOL" << this << "]Failed to do_send"); + return LEVIN_ERROR_CONNECTION; + } + CRITICAL_REGION_END(); + + LOG_PRINT_CC_L4(m_connection_context, "[LEVIN_PROTOCOL" << this << "] PACKET_SENT. [len=" << head.m_cb + << ", f=" << head.m_flags + << ", r?=" << head.m_have_to_return_data + << ", cmd = " << head.m_command + << ", ver=" << head.m_protocol_version); + + uint64_t ticks_start = misc_utils::get_tick_count(); + + while(!boost::interprocess::ipcdetail::atomic_read32(&m_invoke_buf_ready) && !m_deletion_initiated && !m_protocol_released) + { + if(misc_utils::get_tick_count() - ticks_start > m_config.m_invoke_timeout) + { + LOG_PRINT_CC_L2(m_connection_context, "[LEVIN_PROTOCOL" << this << "] invoke timeout (" << m_config.m_invoke_timeout << "), closing connection "); + close(); + return LEVIN_ERROR_CONNECTION_TIMEDOUT; + } + if(!m_pservice_endpoint->call_run_once_service_io()) + return LEVIN_ERROR_CONNECTION_DESTROYED; + } + + if(m_deletion_initiated || m_protocol_released) + return LEVIN_ERROR_CONNECTION_DESTROYED; + + CRITICAL_REGION_BEGIN(m_local_inv_buff_lock); + buff_out.swap(m_local_inv_buff); + m_local_inv_buff.clear(); + CRITICAL_REGION_END(); + + return m_invoke_result_code; + } + + int notify(int command, const std::string& in_buff) + { + misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler( + boost::bind(&async_protocol_handler::finish_outer_call, this)); + + if(m_deletion_initiated) + return LEVIN_ERROR_CONNECTION_DESTROYED; + + CRITICAL_REGION_LOCAL(m_call_lock); + + if(m_deletion_initiated) + return LEVIN_ERROR_CONNECTION_DESTROYED; + + bucket_head2 head = {0}; + head.m_signature = LEVIN_SIGNATURE; + head.m_have_to_return_data = false; + head.m_cb = in_buff.size(); + + head.m_command = command; + head.m_protocol_version = LEVIN_PROTOCOL_VER_1; + head.m_flags = LEVIN_PACKET_REQUEST; + CRITICAL_REGION_BEGIN(m_send_lock); + if(!m_pservice_endpoint->do_send(&head, sizeof(head))) + { + LOG_PRINT_CC_RED(m_connection_context, "[LEVIN_PROTOCOL" << this << "]Failed to do_send()", LOG_LEVEL_2); + return -1; + } + + if(!m_pservice_endpoint->do_send(in_buff.data(), (int)in_buff.size())) + { + LOG_PRINT_CC_RED(m_connection_context, "[LEVIN_PROTOCOL" << this << "]Failed to do_send()", LOG_LEVEL_2); + return -1; + } + CRITICAL_REGION_END(); + LOG_PRINT_CC_L4(m_connection_context, "[LEVIN_PROTOCOL" << this << "] PACKET_SENT. [len=" << head.m_cb << + ", f=" << head.m_flags << + ", r?=" << head.m_have_to_return_data << + ", cmd = " << head.m_command << + ", ver=" << head.m_protocol_version); + + return 1; + } + //------------------------------------------------------------------------------------------ + boost::uuids::uuid get_connection_id() {return m_connection_context.m_connection_id;} + //------------------------------------------------------------------------------------------ + t_connection_context& get_context_ref() {return m_connection_context;} +}; +//------------------------------------------------------------------------------------------ +template +void async_protocol_handler_config::del_connection(async_protocol_handler* pconn) +{ + CRITICAL_REGION_BEGIN(m_connects_lock); + //in case if ->close() leads to phisical erasing any connections in the same thread - just ignore it + + if (m_is_in_sendstop_loop == true) + { + //LOG_ERROR("Internal problem on close connections: attempt to erase connection object while on_send_stop_signal loop is working"); + // edit2: as soon as we added local copy of map of pointers in caller function, now we can erase it + LOG_PRINT_L0(" [LEVIN_PROTOCOL_CONFIG]NOTICE: ERASING CONNECTION FROM SAME THREAD (assuming that local copy in caller function should handle it) In case of crush look at this code."); + m_connects.erase(pconn->get_connection_id()); + } + else + { + m_connects.erase(pconn->get_connection_id()); + } + CRITICAL_REGION_END(); + m_pcommands_handler->on_connection_close(pconn->m_connection_context); +} +//------------------------------------------------------------------------------------------ +template +void async_protocol_handler_config::add_connection(async_protocol_handler* pconn) +{ + CRITICAL_REGION_BEGIN(m_connects_lock); + m_connects[pconn->get_connection_id()] = pconn; + CRITICAL_REGION_END(); + m_pcommands_handler->on_connection_new(pconn->m_connection_context); +} +//------------------------------------------------------------------------------------------ +template +async_protocol_handler* async_protocol_handler_config::find_connection(boost::uuids::uuid connection_id) const +{ + auto it = m_connects.find(connection_id); + return it == m_connects.end() ? 0 : it->second; +} +//------------------------------------------------------------------------------------------ +template +int async_protocol_handler_config::find_and_lock_connection(boost::uuids::uuid connection_id, async_protocol_handler*& aph) +{ + CRITICAL_REGION_LOCAL(m_connects_lock); + aph = find_connection(connection_id); + if(0 == aph) + return LEVIN_ERROR_CONNECTION_NOT_FOUND; + if(!aph->start_outer_call()) + return LEVIN_ERROR_CONNECTION_DESTROYED; + return LEVIN_OK; +} +//------------------------------------------------------------------------------------------ +template +int async_protocol_handler_config::invoke(int command, const std::string& in_buff, std::string& buff_out, boost::uuids::uuid connection_id) +{ + async_protocol_handler* aph; + int r = find_and_lock_connection(connection_id, aph); + return LEVIN_OK == r ? aph->invoke(command, in_buff, buff_out) : r; +} +//------------------------------------------------------------------------------------------ +template template +int async_protocol_handler_config::invoke_async(int command, const std::string& in_buff, boost::uuids::uuid connection_id, callback_t cb, size_t timeout) +{ + async_protocol_handler* aph; + int r = find_and_lock_connection(connection_id, aph); + return LEVIN_OK == r ? aph->async_invoke(command, in_buff, cb, timeout) : r; +} +//------------------------------------------------------------------------------------------ +template template +bool async_protocol_handler_config::foreach_connection(callback_t cb) +{ + CRITICAL_REGION_LOCAL(m_connects_lock); + for(auto& c: m_connects) + { + async_protocol_handler* aph = c.second; + if(!cb(aph->get_context_ref())) + return false; + } + return true; +} +//------------------------------------------------------------------------------------------ +template +void async_protocol_handler_config::on_send_stop_signal() +{ + //at the moment we put workaround here, since this sync_handler has collection of connections + CRITICAL_REGION_LOCAL(m_connects_lock); + m_is_in_sendstop_loop = true; + /* Some times aph->close() can lead to call del_connection() wich erase + item from m_connects and this leads to undefined behavior in range-based for loop. + Since connections_map is light container we just do local copy of this for enumeration + */ + connections_map local_lonnects = m_connects; + + for (auto& c : local_lonnects) + { + async_protocol_handler* aph = c.second; + aph->close(); + } + m_is_in_sendstop_loop = false; +} +//------------------------------------------------------------------------------------------ +template +size_t async_protocol_handler_config::get_connections_count() +{ + CRITICAL_REGION_LOCAL(m_connects_lock); + return m_connects.size(); +} +//------------------------------------------------------------------------------------------ +template +int async_protocol_handler_config::notify(int command, const std::string& in_buff, boost::uuids::uuid connection_id) +{ + async_protocol_handler* aph; + int r = find_and_lock_connection(connection_id, aph); + return LEVIN_OK == r ? aph->notify(command, in_buff) : r; +} +//------------------------------------------------------------------------------------------ +template +bool async_protocol_handler_config::close(boost::uuids::uuid connection_id) +{ + CRITICAL_REGION_LOCAL(m_connects_lock); + async_protocol_handler* aph = find_connection(connection_id); + return 0 != aph ? aph->close() : false; +} +//------------------------------------------------------------------------------------------ +template +bool async_protocol_handler_config::update_connection_context(const t_connection_context& contxt) +{ + CRITICAL_REGION_LOCAL(m_connects_lock); + async_protocol_handler* aph = find_connection(contxt.m_connection_id); + if(0 == aph) + return false; + aph->update_connection_context(contxt); + return true; +} +//------------------------------------------------------------------------------------------ +template +bool async_protocol_handler_config::request_callback(boost::uuids::uuid connection_id) +{ + async_protocol_handler* aph; + int r = find_and_lock_connection(connection_id, aph); + if(LEVIN_OK == r) + { + aph->request_callback(); + return true; + } + else + { + return false; + } +} +} +} + + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL NULL + + + + diff --git a/contrib/epee/include/net/levin_server_cp.h b/contrib/epee/include/net/levin_server_cp.h new file mode 100644 index 00000000..8ece3505 --- /dev/null +++ b/contrib/epee/include/net/levin_server_cp.h @@ -0,0 +1,47 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + + +#ifndef _HTTP_SERVER_CP_H_ +#define _HTTP_SERVER_CP_H_ + +#include "abstract_tcp_server_cp.h" +#include "levin_protocol_handler.h" +namespace epee +{ +namespace net_utils +{ + typedef cp_server_impl cp_levin_server; +} +} + + + +#endif + + diff --git a/contrib/epee/include/net/levin_server_cp2.h b/contrib/epee/include/net/levin_server_cp2.h new file mode 100644 index 00000000..b29d49bf --- /dev/null +++ b/contrib/epee/include/net/levin_server_cp2.h @@ -0,0 +1,49 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#ifndef _HTTP_SERVER_CP_H_ +#define _HTTP_SERVER_CP_H_ + +#include "abstract_tcp_server2.h" +#include "levin_protocol_handler.h" +#include "levin_protocol_handler_async.h" + +namespace epee +{ +namespace net_utils +{ + typedef boosted_tcp_server > boosted_levin_server; + typedef boosted_tcp_server > boosted_levin_async_server; +} +} + + + +#endif + + diff --git a/contrib/epee/include/net/local_ip.h b/contrib/epee/include/net/local_ip.h new file mode 100644 index 00000000..0d458963 --- /dev/null +++ b/contrib/epee/include/net/local_ip.h @@ -0,0 +1,72 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + +#pragma once + +namespace epee +{ + namespace net_utils + { + inline + bool is_ip_local(uint32_t ip) + { + /* + local ip area + 10.0.0.0 10.255.255.255 + 172.16.0.0 172.31.255.255 + 192.168.0.0 192.168.255.255 + */ + if( (ip | 0xffffff00) == 0xffffff0a) + return true; + + if( (ip | 0xffff0000) == 0xffffa8c0) + return true; + + if( (ip | 0xffffff00) == 0xffffffac) + { + uint32_t second_num = (ip << 8) & 0xff000000; + if(second_num >= 16 && second_num <= 31 ) + return true; + } + return false; + } + inline + bool is_ip_loopback(uint32_t ip) + { + if( (ip | 0xffffff00) == 0xffffff7f) + return true; + //MAKE_IP + /* + loopback ip + 127.0.0.0 127.255.255.255 + */ + return false; + } + + } +} + diff --git a/contrib/epee/include/net/multiprotocols_server.h b/contrib/epee/include/net/multiprotocols_server.h new file mode 100644 index 00000000..4807a442 --- /dev/null +++ b/contrib/epee/include/net/multiprotocols_server.h @@ -0,0 +1,47 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#ifndef _MULTIPROTOCOLS_SERVER_H_ +#define _MULTIPROTOCOLS_SERVER_H_ + +//#include "abstract_tcp_server_cp.h" +#include "protocol_switcher.h" +#include "abstract_tcp_server2.h" + +namespace epee +{ +namespace net_utils +{ + //typedef cp_server_impl multiprotocol_server; + typedef boosted_tcp_server boosted_multiprotocol_server; +} +} + + +#endif //_MULTIPROTOCOLS_SERVER_H_ + diff --git a/contrib/epee/include/net/munin_connection_handler.h b/contrib/epee/include/net/munin_connection_handler.h new file mode 100644 index 00000000..8579339c --- /dev/null +++ b/contrib/epee/include/net/munin_connection_handler.h @@ -0,0 +1,376 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#ifndef _MUNIN_CONNECTION_HANDLER_H_ +#define _MUNIN_CONNECTION_HANDLER_H_ + +#include +#include "net_utils_base.h" +#include "to_nonconst_iterator.h" +#include "http_base.h" +#include "reg_exp_definer.h" + +#define MUNIN_ARGS_DEFAULT(vertial_lable_str) "graph_args --base 1000 -l 0 --vertical-label " vertial_lable_str " \n" +#define MUNIN_ARGS_FORCE_AUPPER_LIMIT(vertial_lable_str, limit) "graph_args --base 1000 -l 0 --vertical-label " vertial_lable_str " --rigid --upper-limit " limit " \n" +#define MUNIN_TITLE(title_str) "graph_title " title_str "\n" +#define MUNIN_CATEGORY(category_str) "graph_category " category_str "\n" +#define MUNIN_INFO(info_str) "graph_info " info_str "\n" +#define MUNIN_ENTRY(var_name) #var_name".label " #var_name "\n" #var_name".info "#var_name".\n" +#define MUNIN_ENTRY_AREA(var_name) #var_name".label " #var_name "\n" #var_name".info "#var_name".\n" #var_name".draw AREASTACK\n" +#define MUNIN_ENTRY_ALIAS(var_name, alias) #var_name".label " #alias"\n" #var_name".info "#alias".\n" +#define BEGIN_MUNIN_SERVICE(servivece_name_str) if(servivece_name_str == pservice->m_service_name) { +#define END_MUNIN_SERVICE() } +#define MUNIN_SERVICE_PARAM(munin_var_name_str, variable) paramters_text += std::string() + munin_var_name_str ".value " + boost::lexical_cast(variable) + "\n" + + + + +namespace epee +{ +namespace net_utils +{ + namespace munin + { + + + /************************************************************************/ + /* */ + /************************************************************************/ + struct munin_service; + + struct munin_service_data_provider + { + virtual bool update_service_data(munin_service* pservice, std::string& paramters_text)=0; + }; + + struct munin_service + { + std::string m_service_name; + std::string m_service_config_string; + munin_service_data_provider* m_pdata_provider; + }; + + struct node_server_config + { + std::list m_services; + //TODO: + }; + + struct fake_send_handler: public i_service_endpoint + { + virtual bool do_send(const void* ptr, size_t cb) + { + m_cache += std::string((const char*)ptr, cb); + return true; + } + public: + + std::string m_cache; + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + class munin_node_server_connection_handler + { + public: + typedef node_server_config config_type; + typedef connection_context_base connection_context; + + munin_node_server_connection_handler(i_service_endpoint* psnd_hndlr, config_type& config, const connection_context_base& context):m_psnd_hndlr(psnd_hndlr), + m_machine_state(http_state_retriving_comand_line), + m_config(config) + { + init(); + } + virtual ~munin_node_server_connection_handler() + { + + } + + bool release_protocol() + { + return true; + } + bool after_init_connection() + { + std::string hello_str = "# munin node at "; + hello_str += m_host_name + "\n"; + send_hook(hello_str); + return true; + } + + virtual bool thread_init() + { + return true; + } + + virtual bool thread_deinit() + { + return true; + } + + void handle_qued_callback() + { + + } + + virtual bool handle_recv(const void* ptr, size_t cb) + { + + const char* pbuff = (const char*)ptr; + std::string recvd_buff(pbuff, cb); + LOG_PRINT("munin_recv: \n" << recvd_buff, LOG_LEVEL_3); + + m_cache += recvd_buff; + + bool stop_handling = false; + while(!stop_handling) + { + switch(m_machine_state) + { + case http_state_retriving_comand_line: + { + + std::string::size_type fpos = m_cache.find('\n'); + if(std::string::npos != fpos ) + { + bool res = handle_command(m_cache); + if(!res) + return false; + m_cache.erase(0, fpos+1); + continue; + } + stop_handling = true; + } + break; + case http_state_error: + stop_handling = true; + return false; + default: + LOG_ERROR("Error in munin state machine! Unkonwon state=" << m_machine_state); + stop_handling = true; + m_machine_state = http_state_error; + return false; + } + + } + + return true; + } + + private: + + + bool init() + { + char hostname[64] = {0}; + int res = gethostname(hostname, 64); + hostname[63] = 0;//be happy + m_host_name = hostname; + return true; + } + bool handle_command(const std::string& command) + { + // list, nodes, config, fetch, version or quit + STATIC_REGEXP_EXPR_1(rexp_match_command_line, "^((list)|(nodes)|(config)|(fetch)|(version)|(quit))(\\s+(\\S+))?", boost::regex::icase | boost::regex::normal); + // 12 3 4 5 6 7 8 9 + size_t match_len = 0; + boost::smatch result; + if(boost::regex_search(command, result, rexp_match_command_line, boost::match_default) && result[0].matched) + { + if(result[2].matched) + {//list command + return handle_list_command(); + }else if(result[3].matched) + {//nodes command + return handle_nodes_command(); + }else if(result[4].matched) + {//config command + if(result[9].matched) + return handle_config_command(result[9]); + else + { + send_hook("Unknown service\n"); + } + }else if(result[5].matched) + {//fetch command + if(result[9].matched) + return handle_fetch_command(result[9]); + else + { + send_hook("Unknown service\n"); + } + }else if(result[6].matched) + {//version command + return handle_version_command(); + }else if(result[7].matched) + {//quit command + return handle_quit_command(); + } + else + return send_hook("Unknown command. Try list, nodes, config, fetch, version or quit\n"); + } + + return send_hook("Unknown command. Try list, nodes, config, fetch, version or quit\n");; + } + + bool handle_list_command() + { + std::string buff_to_send; + for(std::list::const_iterator it = m_config.m_services.begin(); it!=m_config.m_services.end();it++) + { + buff_to_send += it->m_service_name + " "; + } + buff_to_send+='\n'; + return send_hook(buff_to_send); + } + bool handle_nodes_command() + { + //supports only one node - host name + send_hook(m_host_name + "\n.\n"); + return true; + } + bool handle_config_command(const std::string& service_name) + { + munin_service* psrv = get_service_by_name(service_name); + if(!psrv) + return send_hook(std::string() + "Unknown service\n"); + + + return send_hook(psrv->m_service_config_string + ".\n"); + } + + bool handle_fetch_command(const std::string& service_name) + { + munin_service* psrv = get_service_by_name(service_name); + if(!psrv) + return send_hook(std::string() + "Unknown service\n"); + + std::string buff; + psrv->m_pdata_provider->update_service_data(psrv, buff); + + buff += ".\n"; + return send_hook(buff); + } + bool handle_version_command() + { + return send_hook("Munin node component by Andrey Sabelnikov\n"); + } + bool handle_quit_command() + { + return false; + } + + bool send_hook(const std::string& buff) + { + LOG_PRINT("munin_send: \n" << buff, LOG_LEVEL_3); + + if(m_psnd_hndlr) + return m_psnd_hndlr->do_send(buff.data(), buff.size()); + else + return false; + } + + + munin_service* get_service_by_name(const std::string& srv_name) + { + std::list::iterator it = m_config.m_services.begin(); + for(; it!=m_config.m_services.end(); it++) + if(it->m_service_name == srv_name) + break; + + if(it==m_config.m_services.end()) + return NULL; + + return &(*it); + } + + enum machine_state{ + http_state_retriving_comand_line, + http_state_error + }; + + + config_type& m_config; + machine_state m_machine_state; + std::string m_cache; + std::string m_host_name; + protected: + i_service_endpoint* m_psnd_hndlr; + }; + + + inline bool test_self() + { + /*WSADATA w; + ::WSAStartup(MAKEWORD(1, 1), &w); + node_server_config sc; + sc.m_services.push_back(munin_service()); + sc.m_services.back().m_service_name = "test_service"; + + sc.m_services.back().m_service_config_string = + "graph_args --base 1000 -l 0 --vertical-label N --upper-limit 329342976\n" + "graph_title REPORTS STATICTICS\n" + "graph_category bind\n" + "graph_info This graph shows how many reports came in fixed time period.\n" + "graph_order apps free swap\n" + "apps.label apps\n" + "apps.draw AREA\n" + "apps.info Memory used by user-space applications.\n" + "swap.label swap\n" + "swap.draw STACK\n" + "swap.info Swap space used.\n" + "free.label unused\n" + "free.draw STACK\n" + "free.info Wasted memory. Memory that is not used for anything at all.\n" + "committed.label committed\n" + "committed.draw LINE2\n" + "committed.warn 625410048\n" + "committed.info The amount of memory that would be used if all the memory that's been allocated were to be used.\n"; + + + sc.m_services.push_back(munin_service()); + sc.m_services.back().m_service_name = "test_service1"; + fake_send_handler fh; + munin_node_server_connection_handler mh(&fh, sc); + + std::string buff = "list\n"; + mh.handle_recv(buff.data(), buff.size()); + + + buff = "nodes\n"; + mh.handle_recv(buff.data(), buff.size()); +*/ + return true; + } + + } +} +} +#endif//!_MUNIN_CONNECTION_HANDLER_H_ \ No newline at end of file diff --git a/contrib/epee/include/net/munin_node_server.h b/contrib/epee/include/net/munin_node_server.h new file mode 100644 index 00000000..07637f55 --- /dev/null +++ b/contrib/epee/include/net/munin_node_server.h @@ -0,0 +1,49 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#ifndef _MUNIN_NODE_SERVER_H_ +#define _MUNIN_NODE_SERVER_H_ + +#include +//#include "net_utils_base.h" +#include "munin_connection_handler.h" +//#include "abstract_tcp_server.h" +//#include "abstract_tcp_server_cp.h" +#include "abstract_tcp_server2.h" +namespace epee +{ +namespace net_utils +{ + namespace munin + { + typedef boosted_tcp_server munin_node_server; + //typedef cp_server_impl munin_node_cp_server; + } +} +} +#endif//!_MUNIN_NODE_SERVER_H_ \ No newline at end of file diff --git a/contrib/epee/include/net/net_helper.h b/contrib/epee/include/net/net_helper.h new file mode 100644 index 00000000..4f7ebfa0 --- /dev/null +++ b/contrib/epee/include/net/net_helper.h @@ -0,0 +1,683 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + + +#pragma once + +//#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "net/net_utils_base.h" +#include "misc_language.h" +//#include "profile_tools.h" +#include "../string_tools.h" + +#ifndef MAKE_IP +#define MAKE_IP( a1, a2, a3, a4 ) (a1|(a2<<8)|(a3<<16)|(a4<<24)) +#endif + + +namespace epee +{ +namespace net_utils +{ + + class blocked_mode_client + { + + + struct handler_obj + { + handler_obj(boost::system::error_code& error, size_t& bytes_transferred):ref_error(error), ref_bytes_transferred(bytes_transferred) + {} + handler_obj(const handler_obj& other_obj):ref_error(other_obj.ref_error), ref_bytes_transferred(other_obj.ref_bytes_transferred) + {} + + boost::system::error_code& ref_error; + size_t& ref_bytes_transferred; + + void operator()(const boost::system::error_code& error, // Result of operation. + std::size_t bytes_transferred // Number of bytes read. + ) + { + ref_error = error; + ref_bytes_transferred = bytes_transferred; + } + }; + + public: + inline + blocked_mode_client():m_socket(m_io_service), + m_initialized(false), + m_connected(false), + m_deadline(m_io_service), + m_shutdowned(0) + { + + + m_initialized = true; + + + // No deadline is required until the first socket operation is started. We + // set the deadline to positive infinity so that the actor takes no action + // until a specific deadline is set. + m_deadline.expires_at(boost::posix_time::pos_infin); + + // Start the persistent actor that checks for deadline expiry. + check_deadline(); + + } + inline + ~blocked_mode_client() + { + //profile_tools::local_coast lc("~blocked_mode_client()", 3); + shutdown(); + } + + inline void set_recv_timeout(int reciev_timeout) + { + m_reciev_timeout = reciev_timeout; + } + + inline + bool connect(const std::string& addr, int port, unsigned int connect_timeout, unsigned int reciev_timeout, const std::string& bind_ip = "0.0.0.0") + { + return connect(addr, std::to_string(port), connect_timeout, reciev_timeout, bind_ip); + } + + inline + bool connect(const std::string& addr, const std::string& port, unsigned int connect_timeout, unsigned int reciev_timeout, const std::string& bind_ip = "0.0.0.0") + { + m_connect_timeout = connect_timeout; + m_reciev_timeout = reciev_timeout; + m_connected = false; + if(!m_reciev_timeout) + m_reciev_timeout = m_connect_timeout; + + try + { + m_socket.close(); + // Get a list of endpoints corresponding to the server name. + + + ////////////////////////////////////////////////////////////////////////// + + boost::asio::ip::tcp::resolver resolver(m_io_service); + boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), addr, port); + boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query); + boost::asio::ip::tcp::resolver::iterator end; + if(iterator == end) + { + LOG_ERROR("Failed to resolve " << addr); + return false; + } + + ////////////////////////////////////////////////////////////////////////// + + + //boost::asio::ip::tcp::endpoint remote_endpoint(boost::asio::ip::address::from_string(addr.c_str()), port); + boost::asio::ip::tcp::endpoint remote_endpoint(*iterator); + + + m_socket.open(remote_endpoint.protocol()); + if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" ) + { + boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(addr.c_str()), 0); + m_socket.bind(local_endpoint); + } + + + m_deadline.expires_from_now(boost::posix_time::milliseconds(m_connect_timeout)); + + + boost::system::error_code ec = boost::asio::error::would_block; + + //m_socket.connect(remote_endpoint); + m_socket.async_connect(remote_endpoint, boost::lambda::var(ec) = boost::lambda::_1); + while (ec == boost::asio::error::would_block) + { + m_io_service.run_one(); + } + + if (!ec && m_socket.is_open()) + { + m_connected = true; + m_deadline.expires_at(boost::posix_time::pos_infin); + return true; + }else + { + LOG_PRINT("Some problems at connect, message: " << ec.message(), LOG_LEVEL_3); + return false; + } + + } + catch(const boost::system::system_error& er) + { + LOG_PRINT("Some problems at connect, message: " << er.what(), LOG_LEVEL_4); + return false; + } + catch(...) + { + LOG_PRINT("Some fatal problems.", LOG_LEVEL_4); + return false; + } + + return true; + } + + + inline + bool disconnect() + { + try + { + if(m_connected) + { + m_connected = false; + m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both); + + } + } + + catch(const boost::system::system_error& /*er*/) + { + //LOG_ERROR("Some problems at disconnect, message: " << er.what()); + return false; + } + catch(...) + { + //LOG_ERROR("Some fatal problems."); + return false; + } + return true; + } + + + inline + bool send(const std::string& buff) + { + + try + { + m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); + + // Set up the variable that receives the result of the asynchronous + // operation. The error code is set to would_block to signal that the + // operation is incomplete. Asio guarantees that its asynchronous + // operations will never fail with would_block, so any other value in + // ec indicates completion. + boost::system::error_code ec = boost::asio::error::would_block; + + // Start the asynchronous operation itself. The boost::lambda function + // object is used as a callback and will update the ec variable when the + // operation completes. The blocking_udp_client.cpp example shows how you + // can use boost::bind rather than boost::lambda. + boost::asio::async_write(m_socket, boost::asio::buffer(buff), boost::lambda::var(ec) = boost::lambda::_1); + + // Block until the asynchronous operation has completed. + while (ec == boost::asio::error::would_block) + { + m_io_service.run_one(); + } + + if (ec) + { + LOG_PRINT_L3("Problems at write: " << ec.message()); + m_connected = false; + return false; + }else + { + m_deadline.expires_at(boost::posix_time::pos_infin); + } + } + + catch(const boost::system::system_error& er) + { + LOG_ERROR("Some problems at connect, message: " << er.what()); + return false; + } + catch(...) + { + LOG_ERROR("Some fatal problems."); + return false; + } + + return true; + } + + inline + bool send(const void* data, size_t sz) + { + try + { + /* + m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); + + // Set up the variable that receives the result of the asynchronous + // operation. The error code is set to would_block to signal that the + // operation is incomplete. Asio guarantees that its asynchronous + // operations will never fail with would_block, so any other value in + // ec indicates completion. + boost::system::error_code ec = boost::asio::error::would_block; + + // Start the asynchronous operation itself. The boost::lambda function + // object is used as a callback and will update the ec variable when the + // operation completes. The blocking_udp_client.cpp example shows how you + // can use boost::bind rather than boost::lambda. + boost::asio::async_write(m_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1); + + // Block until the asynchronous operation has completed. + while (ec == boost::asio::error::would_block) + { + m_io_service.run_one(); + } + */ + boost::system::error_code ec; + + size_t writen = m_socket.write_some(boost::asio::buffer(data, sz), ec); + + + + if (!writen || ec) + { + LOG_PRINT_L3("Problems at write: " << ec.message()); + m_connected = false; + return false; + }else + { + m_deadline.expires_at(boost::posix_time::pos_infin); + } + } + + catch(const boost::system::system_error& er) + { + LOG_ERROR("Some problems at send, message: " << er.what()); + m_connected = false; + return false; + } + catch(...) + { + LOG_ERROR("Some fatal problems."); + return false; + } + + return true; + } + + bool is_connected() + { + return m_connected && m_socket.is_open(); + //TRY_ENTRY() + //return m_socket.is_open(); + //CATCH_ENTRY_L0("is_connected", false) + } + + inline + bool recv(std::string& buff) + { + + try + { + // Set a deadline for the asynchronous operation. Since this function uses + // a composed operation (async_read_until), the deadline applies to the + // entire operation, rather than individual reads from the socket. + m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); + + // Set up the variable that receives the result of the asynchronous + // operation. The error code is set to would_block to signal that the + // operation is incomplete. Asio guarantees that its asynchronous + // operations will never fail with would_block, so any other value in + // ec indicates completion. + //boost::system::error_code ec = boost::asio::error::would_block; + + // Start the asynchronous operation itself. The boost::lambda function + // object is used as a callback and will update the ec variable when the + // operation completes. The blocking_udp_client.cpp example shows how you + // can use boost::bind rather than boost::lambda. + + boost::system::error_code ec = boost::asio::error::would_block; + size_t bytes_transfered = 0; + + handler_obj hndlr(ec, bytes_transfered); + + char local_buff[10000] = {0}; + //m_socket.async_read_some(boost::asio::buffer(local_buff, sizeof(local_buff)), hndlr); + boost::asio::async_read(m_socket, boost::asio::buffer(local_buff, sizeof(local_buff)), boost::asio::transfer_at_least(1), hndlr); + + // Block until the asynchronous operation has completed. + while (ec == boost::asio::error::would_block && !boost::interprocess::ipcdetail::atomic_read32(&m_shutdowned)) + { + m_io_service.run_one(); + } + + + if (ec) + { + LOG_PRINT_L4("READ ENDS: Connection err_code " << ec.value()); + if(ec == boost::asio::error::eof) + { + LOG_PRINT_L4("Connection err_code eof."); + //connection closed there, empty + return true; + } + + LOG_PRINT_L3("Problems at read: " << ec.message()); + m_connected = false; + return false; + }else + { + LOG_PRINT_L4("READ ENDS: Success. bytes_tr: " << bytes_transfered); + m_deadline.expires_at(boost::posix_time::pos_infin); + } + + /*if(!bytes_transfered) + return false;*/ + + buff.assign(local_buff, bytes_transfered); + return true; + } + + catch(const boost::system::system_error& er) + { + LOG_ERROR("Some problems at read, message: " << er.what()); + m_connected = false; + return false; + } + catch(...) + { + LOG_ERROR("Some fatal problems at read."); + return false; + } + + + + return false; + + } + + inline bool recv_n(std::string& buff, int64_t sz) + { + + try + { + // Set a deadline for the asynchronous operation. Since this function uses + // a composed operation (async_read_until), the deadline applies to the + // entire operation, rather than individual reads from the socket. + m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); + + // Set up the variable that receives the result of the asynchronous + // operation. The error code is set to would_block to signal that the + // operation is incomplete. Asio guarantees that its asynchronous + // operations will never fail with would_block, so any other value in + // ec indicates completion. + //boost::system::error_code ec = boost::asio::error::would_block; + + // Start the asynchronous operation itself. The boost::lambda function + // object is used as a callback and will update the ec variable when the + // operation completes. The blocking_udp_client.cpp example shows how you + // can use boost::bind rather than boost::lambda. + + buff.resize(static_cast(sz)); + boost::system::error_code ec = boost::asio::error::would_block; + size_t bytes_transfered = 0; + + + handler_obj hndlr(ec, bytes_transfered); + + //char local_buff[10000] = {0}; + boost::asio::async_read(m_socket, boost::asio::buffer((char*)buff.data(), buff.size()), boost::asio::transfer_at_least(buff.size()), hndlr); + + // Block until the asynchronous operation has completed. + while (ec == boost::asio::error::would_block && !boost::interprocess::ipcdetail::atomic_read32(&m_shutdowned)) + { + m_io_service.run_one(); + } + + if (ec) + { + LOG_PRINT_L3("Problems at read: " << ec.message()); + m_connected = false; + return false; + }else + { + m_deadline.expires_at(boost::posix_time::pos_infin); + } + + if(bytes_transfered != buff.size()) + { + LOG_ERROR("Transferred missmatch with transfer_at_least value: m_bytes_transferred=" << bytes_transfered << " at_least value=" << buff.size()); + return false; + } + + return true; + } + + catch(const boost::system::system_error& er) + { + LOG_ERROR("Some problems at read, message: " << er.what()); + m_connected = false; + return false; + } + catch(...) + { + LOG_ERROR("Some fatal problems at read."); + return false; + } + + + + return false; + } + + bool shutdown() + { + m_deadline.cancel(); + boost::system::error_code ignored_ec; + m_socket.cancel(ignored_ec); + m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); + m_socket.close(ignored_ec); + boost::interprocess::ipcdetail::atomic_write32(&m_shutdowned, 1); + m_connected = false; + return true; + } + + void set_connected(bool connected) + { + m_connected = connected; + } + boost::asio::io_service& get_io_service() + { + return m_io_service; + } + + boost::asio::ip::tcp::socket& get_socket() + { + return m_socket; + } + + private: + + void check_deadline() + { + // Check whether the deadline has passed. We compare the deadline against + // the current time since a new asynchronous operation may have moved the + // deadline before this actor had a chance to run. + if (m_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now()) + { + // The deadline has passed. The socket is closed so that any outstanding + // asynchronous operations are cancelled. This allows the blocked + // connect(), read_line() or write_line() functions to return. + LOG_PRINT_L3("Timed out socket"); + m_connected = false; + m_socket.close(); + + // There is no longer an active deadline. The expiry is set to positive + // infinity so that the actor takes no action until a new deadline is set. + m_deadline.expires_at(boost::posix_time::pos_infin); + } + + // Put the actor back to sleep. + m_deadline.async_wait(boost::bind(&blocked_mode_client::check_deadline, this)); + } + + + + protected: + boost::asio::io_service m_io_service; + boost::asio::ip::tcp::socket m_socket; + int m_connect_timeout; + int m_reciev_timeout; + bool m_initialized; + bool m_connected; + boost::asio::deadline_timer m_deadline; + volatile uint32_t m_shutdowned; + }; + + + /************************************************************************/ + /* */ + /************************************************************************/ + class async_blocked_mode_client: public blocked_mode_client + { + public: + async_blocked_mode_client():m_send_deadline(blocked_mode_client::m_io_service) + { + + // No deadline is required until the first socket operation is started. We + // set the deadline to positive infinity so that the actor takes no action + // until a specific deadline is set. + m_send_deadline.expires_at(boost::posix_time::pos_infin); + + // Start the persistent actor that checks for deadline expiry. + check_send_deadline(); + } + ~async_blocked_mode_client() + { + m_send_deadline.cancel(); + } + + bool shutdown() + { + blocked_mode_client::shutdown(); + m_send_deadline.cancel(); + return true; + } + + inline + bool send(const void* data, size_t sz) + { + try + { + /* + m_send_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); + + // Set up the variable that receives the result of the asynchronous + // operation. The error code is set to would_block to signal that the + // operation is incomplete. Asio guarantees that its asynchronous + // operations will never fail with would_block, so any other value in + // ec indicates completion. + boost::system::error_code ec = boost::asio::error::would_block; + + // Start the asynchronous operation itself. The boost::lambda function + // object is used as a callback and will update the ec variable when the + // operation completes. The blocking_udp_client.cpp example shows how you + // can use boost::bind rather than boost::lambda. + boost::asio::async_write(m_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1); + + // Block until the asynchronous operation has completed. + while(ec == boost::asio::error::would_block) + { + m_io_service.run_one(); + }*/ + + boost::system::error_code ec; + + size_t writen = m_socket.write_some(boost::asio::buffer(data, sz), ec); + + if (!writen || ec) + { + LOG_PRINT_L3("Problems at write: " << ec.message()); + return false; + }else + { + m_send_deadline.expires_at(boost::posix_time::pos_infin); + } + } + + catch(const boost::system::system_error& er) + { + LOG_ERROR("Some problems at connect, message: " << er.what()); + return false; + } + catch(...) + { + LOG_ERROR("Some fatal problems."); + return false; + } + + return true; + } + + + private: + + boost::asio::deadline_timer m_send_deadline; + + void check_send_deadline() + { + // Check whether the deadline has passed. We compare the deadline against + // the current time since a new asynchronous operation may have moved the + // deadline before this actor had a chance to run. + if (m_send_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now()) + { + // The deadline has passed. The socket is closed so that any outstanding + // asynchronous operations are cancelled. This allows the blocked + // connect(), read_line() or write_line() functions to return. + LOG_PRINT_L3("Timed out socket"); + m_socket.close(); + + // There is no longer an active deadline. The expiry is set to positive + // infinity so that the actor takes no action until a new deadline is set. + m_send_deadline.expires_at(boost::posix_time::pos_infin); + } + + // Put the actor back to sleep. + m_send_deadline.async_wait(boost::bind(&async_blocked_mode_client::check_send_deadline, this)); + } + }; +} +} diff --git a/contrib/epee/include/net/net_parse_helpers.h b/contrib/epee/include/net/net_parse_helpers.h new file mode 100644 index 00000000..586dac98 --- /dev/null +++ b/contrib/epee/include/net/net_parse_helpers.h @@ -0,0 +1,168 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + + +#pragma once +#include "http_base.h" +#include "reg_exp_definer.h" + + +namespace epee +{ +namespace net_utils +{ + + inline bool parse_uri_query(const std::string& query, std::list >& params) + { + enum state + { + st_param_name, + st_param_val + }; + state st = st_param_name; + std::string::const_iterator start_it = query.begin(); + std::pair e; + for(std::string::const_iterator it = query.begin(); it != query.end(); it++) + { + switch(st) + { + case st_param_name: + if(*it == '=') + { + e.first.assign(start_it, it); + start_it = it;++start_it; + st = st_param_val; + } + break; + case st_param_val: + if(*it == '&') + { + e.second.assign(start_it, it); + start_it = it;++start_it; + params.push_back(e); + e.first.clear();e.second.clear(); + st = st_param_name; + } + break; + default: + LOG_ERROR("Unknown state " << (int)st); + return false; + } + } + if(st == st_param_name) + { + if(start_it != query.end()) + { + e.first.assign(start_it, query.end()); + params.push_back(e); + } + }else + { + if(start_it != query.end()) + e.second.assign(start_it, query.end()); + + if(e.first.size()) + params.push_back(e); + } + return true; + } + + inline + bool parse_uri(const std::string uri, http::uri_content& content) + { + + ///iframe_test.html?api_url=http://api.vk.com/api.php&api_id=3289090&api_settings=1&viewer_id=562964060&viewer_type=0&sid=0aad8d1c5713130f9ca0076f2b7b47e532877424961367d81e7fa92455f069be7e21bc3193cbd0be11895&secret=368ebbc0ef&access_token=668bc03f43981d883f73876ffff4aa8564254b359cc745dfa1b3cde7bdab2e94105d8f6d8250717569c0a7&user_id=0&group_id=0&is_app_user=1&auth_key=d2f7a895ca5ff3fdb2a2a8ae23fe679a&language=0&parent_language=0&ad_info=ElsdCQBaQlxiAQRdFUVUXiN2AVBzBx5pU1BXIgZUJlIEAWcgAUoLQg==&referrer=unknown&lc_name=9834b6a3&hash= + content.m_query_params.clear(); + STATIC_REGEXP_EXPR_1(rexp_match_uri, "^([^?#]*)(\\?([^#]*))?(#(.*))?", boost::regex::icase | boost::regex::normal); + + boost::smatch result; + if(!boost::regex_search(uri, result, rexp_match_uri, boost::match_default) && result[0].matched) + { + LOG_PRINT_L0("[PARSE URI] regex not matched for uri: " << uri); + content.m_path = uri; + return true; + } + if(result[1].matched) + { + content.m_path = result[1]; + } + if(result[3].matched) + { + content.m_query = result[3]; + } + if(result[5].matched) + { + content.m_fragment = result[5]; + } + if(content.m_query.size()) + { + parse_uri_query(content.m_query, content.m_query_params); + } + return true; + } + + + inline + bool parse_url(const std::string url_str, http::url_content& content) + { + + ///iframe_test.html?api_url=http://api.vk.com/api.php&api_id=3289090&api_settings=1&viewer_id=562964060&viewer_type=0&sid=0aad8d1c5713130f9ca0076f2b7b47e532877424961367d81e7fa92455f069be7e21bc3193cbd0be11895&secret=368ebbc0ef&access_token=668bc03f43981d883f73876ffff4aa8564254b359cc745dfa1b3cde7bdab2e94105d8f6d8250717569c0a7&user_id=0&group_id=0&is_app_user=1&auth_key=d2f7a895ca5ff3fdb2a2a8ae23fe679a&language=0&parent_language=0&ad_info=ElsdCQBaQlxiAQRdFUVUXiN2AVBzBx5pU1BXIgZUJlIEAWcgAUoLQg==&referrer=unknown&lc_name=9834b6a3&hash= + //STATIC_REGEXP_EXPR_1(rexp_match_uri, "^([^?#]*)(\\?([^#]*))?(#(.*))?", boost::regex::icase | boost::regex::normal); + STATIC_REGEXP_EXPR_1(rexp_match_uri, "^((.*?)://)?(([^/:]*)(:(\\d+))?)(.*)?", boost::regex::icase | boost::regex::normal); + // 12 34 5 6 7 + content.port = 0; + boost::smatch result; + if(!boost::regex_search(url_str, result, rexp_match_uri, boost::match_default) && result[0].matched) + { + LOG_PRINT_L0("[PARSE URI] regex not matched for uri: " << rexp_match_uri); + //content.m_path = uri; + return true; + } + if(result[2].matched) + { + content.schema = result[2]; + } + if(result[4].matched) + { + content.host = result[4]; + } + if(result[6].matched) + { + content.port = boost::lexical_cast(result[6]); + } + if(result[7].matched) + { + content.uri = result[7]; + return parse_uri(result[7], content.m_uri_content); + } + + return true; + } + +} +} \ No newline at end of file diff --git a/contrib/epee/include/net/net_utils_base.h b/contrib/epee/include/net/net_utils_base.h new file mode 100644 index 00000000..88586857 --- /dev/null +++ b/contrib/epee/include/net/net_utils_base.h @@ -0,0 +1,185 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#ifndef _NET_UTILS_BASE_H_ +#define _NET_UTILS_BASE_H_ + +#include +#include "string_tools.h" + +#ifndef MAKE_IP +#define MAKE_IP( a1, a2, a3, a4 ) (a1|(a2<<8)|(a3<<16)|(a4<<24)) +#endif + + +namespace epee +{ +namespace net_utils +{ + /************************************************************************/ + /* */ + /************************************************************************/ + struct connection_context_base + { + const boost::uuids::uuid m_connection_id; + const uint32_t m_remote_ip; + const uint32_t m_remote_port; + const bool m_is_income; + const time_t m_started; + time_t m_last_recv; + time_t m_last_send; + uint64_t m_recv_cnt; + uint64_t m_send_cnt; + + connection_context_base(boost::uuids::uuid connection_id, long remote_ip, int remote_port, bool is_income, time_t last_recv = 0, time_t last_send = 0, uint64_t recv_cnt = 0, uint64_t send_cnt = 0): + m_connection_id(connection_id), + m_remote_ip(remote_ip), + m_remote_port(remote_port), + m_is_income(is_income), + m_last_recv(last_recv), + m_last_send(last_send), + m_recv_cnt(recv_cnt), + m_send_cnt(send_cnt), + m_started(time(NULL)) + {} + + connection_context_base(): m_connection_id(), + m_remote_ip(0), + m_remote_port(0), + m_is_income(false), + m_last_recv(0), + m_last_send(0), + m_recv_cnt(0), + m_send_cnt(0), + m_started(time(NULL)) + {} + + connection_context_base& operator=(const connection_context_base& a) + { + set_details(a.m_connection_id, a.m_remote_ip, a.m_remote_port, a.m_is_income); + return *this; + } + + private: + template + friend class connection; + void set_details(boost::uuids::uuid connection_id, long remote_ip, int remote_port, bool is_income) + { + this->~connection_context_base(); + new(this) connection_context_base(connection_id, remote_ip, remote_port, is_income); + } + + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + struct i_service_endpoint + { + virtual bool do_send(const void* ptr, size_t cb)=0; + virtual bool close()=0; + virtual bool call_run_once_service_io()=0; + virtual bool request_callback()=0; + virtual boost::asio::io_service& get_io_service()=0; + //protect from deletion connection object(with protocol instance) during external call "invoke" + virtual bool add_ref()=0; + virtual bool release()=0; + protected: + virtual ~i_service_endpoint(){} + }; + + + //some helpers + + + inline + std::string print_connection_context(const connection_context_base& ctx) + { + std::stringstream ss; + ss << epee::string_tools::get_ip_string_from_int32(ctx.m_remote_ip) << ":" << ctx.m_remote_port << " " << epee::string_tools::get_str_from_guid_a(ctx.m_connection_id) << (ctx.m_is_income ? " INC":" OUT"); + return ss.str(); + } + + inline + void print_connection_context_short(const connection_context_base& ctx, std::stringstream& ss) + { + ss << epee::string_tools::get_ip_string_from_int32(ctx.m_remote_ip) << ":" << ctx.m_remote_port << (ctx.m_is_income ? " INC" : " OUT"); + } + + inline + std::string print_connection_context_short(const connection_context_base& ctx) + { + std::stringstream ss; + print_connection_context_short(ctx, ss); + return ss.str(); + } + + inline std::string print_connection_context_list(const std::list& contexts) + { + std::stringstream ss; + for (auto& c : contexts) + { + ss << epee::string_tools::get_ip_string_from_int32(c.m_remote_ip) << ":" << c.m_remote_port << (c.m_is_income ? " INC" : " OUT") << ENDL; + } + return ss.str(); + } + +#define LOG_PRINT_CC(ct, message, log_level) LOG_PRINT(message, log_level) +#define LOG_PRINT_CC_GREEN(ct, message, log_level) LOG_PRINT_GREEN(message, log_level) +#define LOG_PRINT_CC_RED(ct, message, log_level) LOG_PRINT_RED(message, log_level) +#define LOG_PRINT_CC_BLUE(ct, message, log_level) LOG_PRINT_BLUE(message, log_level) +#define LOG_PRINT_CC_YELLOW(ct, message, log_level) LOG_PRINT_YELLOW(message, log_level) +#define LOG_PRINT_CC_CYAN(ct, message, log_level) LOG_PRINT_CYAN(message, log_level) +#define LOG_PRINT_CC_MAGENTA(ct, message, log_level) LOG_PRINT_MAGENTA(message, log_level) +#define LOG_ERROR_CC(ct, message) LOG_ERROR(message) + +#define LOG_PRINT_CC_L0(ct, message) LOG_PRINT_L0(message) +#define LOG_PRINT_CC_L1(ct, message) LOG_PRINT_L1(message) +#define LOG_PRINT_CC_L2(ct, message) LOG_PRINT_L2(message) +#define LOG_PRINT_CC_L3(ct, message) LOG_PRINT_L3(message) +#define LOG_PRINT_CC_L4(ct, message) LOG_PRINT_L4(message) + +#define LOG_PRINT_CCONTEXT_L0(message) LOG_PRINT_CC_L0(context, message) +#define LOG_PRINT_CCONTEXT_L1(message) LOG_PRINT_CC_L1(context, message) +#define LOG_PRINT_CCONTEXT_L2(message) LOG_PRINT_CC_L2(context, message) +#define LOG_PRINT_CCONTEXT_L3(message) LOG_PRINT_CC_L3(context, message) +#define LOG_ERROR_CCONTEXT(message) LOG_ERROR_CC(context, message) + +#define LOG_PRINT_CCONTEXT_GREEN(message, log_level) LOG_PRINT_CC_GREEN(context, message, log_level) +#define LOG_PRINT_CCONTEXT_RED(message, log_level) LOG_PRINT_CC_RED(context, message, log_level) +#define LOG_PRINT_CCONTEXT_BLUE(message, log_level) LOG_PRINT_CC_BLUE(context, message, log_level) +#define LOG_PRINT_CCONTEXT_YELLOW(message, log_level) LOG_PRINT_CC_YELLOW(context, message, log_level) +#define LOG_PRINT_CCONTEXT_CYAN(message, log_level) LOG_PRINT_CC_CYAN(context, message, log_level) +#define LOG_PRINT_CCONTEXT_MAGENTA(message, log_level) LOG_PRINT_CC_MAGENTA(context, message, log_level) + +#define CHECK_AND_ASSERT_MES_CC(condition, return_val, err_message) CHECK_AND_ASSERT_MES(condition, return_val, "[" << epee::net_utils::print_connection_context_short(context) << "]" << err_message) + +} +} + +#endif //_NET_UTILS_BASE_H_ diff --git a/contrib/epee/include/net/protocol_switcher.h b/contrib/epee/include/net/protocol_switcher.h new file mode 100644 index 00000000..ca0ce6f9 --- /dev/null +++ b/contrib/epee/include/net/protocol_switcher.h @@ -0,0 +1,121 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#ifndef _PROTOCOL_SWITCHER_H_ +#define _PROTOCOL_SWITCHER_H_ + +#include "levin_base.h" +#include "http_server.h" +#include "levin_protocol_handler.h" +//#include "abstract_tcp_server.h" + +namespace epee +{ +namespace net_utils +{ + struct protocl_switcher_config + { + http::http_custom_handler::config_type m_http_config; + levin::protocol_handler::config_type m_levin_config; + }; + + + struct i_protocol_handler + { + virtual bool handle_recv(const void* ptr, size_t cb)=0; + }; + + template + class t_protocol_handler: public i_protocol_handler + { + public: + typedef t t_type; + t_protocol_handler(i_service_endpoint* psnd_hndlr, typename t_type::config_type& config, const connection_context& conn_context):m_hadler(psnd_hndlr, config, conn_context) + {} + private: + bool handle_recv(const void* ptr, size_t cb) + { + return m_hadler.handle_recv(ptr, cb); + } + t_type m_hadler; + }; + + + class protocol_switcher + { + public: + typedef protocl_switcher_config config_type; + + protocol_switcher(net_utils::i_service_endpoint* psnd_hndlr, config_type& config, const net_utils::connection_context_base& conn_context); + virtual ~protocol_switcher(){} + + virtual bool handle_recv(const void* ptr, size_t cb); + + bool after_init_connection(){return true;} + private: + t_protocol_handler m_http_handler; + t_protocol_handler m_levin_handler; + i_protocol_handler* pcurrent_handler; + + std::string m_cached_buff; + }; + + protocol_switcher::protocol_switcher(net_utils::i_service_endpoint* psnd_hndlr, config_type& config, const net_utils::connection_context_base& conn_context):m_http_handler(psnd_hndlr, config.m_http_config, conn_context), m_levin_handler(psnd_hndlr, config.m_levin_config, conn_context), pcurrent_handler(NULL) + {} + + bool protocol_switcher::handle_recv(const void* ptr, size_t cb) + { + if(pcurrent_handler) + return pcurrent_handler->handle_recv(ptr, cb); + else + { + m_cached_buff.append((const char*)ptr, cb); + if(m_cached_buff.size() < sizeof(uint64_t)) + return true; + + if(*((uint64_t*)&m_cached_buff[0]) == LEVIN_SIGNATURE) + { + pcurrent_handler = &m_levin_handler; + return pcurrent_handler->handle_recv(m_cached_buff.data(), m_cached_buff.size()); + } + if(m_cached_buff.substr(0, 4) == "GET " || m_cached_buff.substr(0, 4) == "POST") + { + pcurrent_handler = &m_http_handler; + return pcurrent_handler->handle_recv(m_cached_buff.data(), m_cached_buff.size()); + }else + { + LOG_ERROR("Wrong protocol accepted on port..."); + return false; + } + } + + return true; + } +} +} +#endif //_PROTOCOL_SWITCHER_H_ \ No newline at end of file diff --git a/contrib/epee/include/net/rpc_method_name.h b/contrib/epee/include/net/rpc_method_name.h new file mode 100644 index 00000000..cd9a6f38 --- /dev/null +++ b/contrib/epee/include/net/rpc_method_name.h @@ -0,0 +1,32 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + +#pragma once + + +#define RPC_METHOD_NAME(name) static inline const char* methodname(){return name;} + diff --git a/contrib/epee/include/net/smtp.h b/contrib/epee/include/net/smtp.h new file mode 100644 index 00000000..d2e8598f --- /dev/null +++ b/contrib/epee/include/net/smtp.h @@ -0,0 +1,181 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + + +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace epee +{ +namespace net_utils +{ + namespace smtp + { + + using boost::asio::ip::tcp; + using namespace boost::archive::iterators; + typedef base64_from_binary > base64_text; + + /************************************************************************/ + /* */ + /************************************************************************/ + class smtp_client + { + public: + smtp_client(std::string pServer,unsigned int pPort,std::string pUser,std::string pPassword): + mServer(pServer),mPort(pPort),mUserName(pUser),mPassword(pPassword),mSocket(mIOService),mResolver(mIOService) + { + tcp::resolver::query qry(mServer,boost::lexical_cast( mPort )); + mResolver.async_resolve(qry,boost::bind(&smtp_client::handleResolve,this,boost::asio::placeholders::error, + boost::asio::placeholders::iterator)); + } + bool Send(std::string pFrom,std::string pTo,std::string pSubject,std::string pMessage) + { + mHasError = true; + mFrom=pFrom; + mTo=pTo; + mSubject=pSubject; + mMessage=pMessage; + mIOService.run(); + return !mHasError; + } + private: + std::string encodeBase64(std::string pData) + { + std::stringstream os; + size_t sz=pData.size(); + std::copy(base64_text(pData.c_str()),base64_text(pData.c_str()+sz),std::ostream_iterator(os)); + return os.str(); + } + void handleResolve(const boost::system::error_code& err,tcp::resolver::iterator endpoint_iterator) + { + if(!err) + { + tcp::endpoint endpoint=*endpoint_iterator; + mSocket.async_connect(endpoint, + boost::bind(&smtp_client::handleConnect,this,boost::asio::placeholders::error,++endpoint_iterator)); + } + else + { + mHasError=true; + mErrorMsg= err.message(); + } + } + void writeLine(std::string pData) + { + std::ostream req_strm(&mRequest); + req_strm << pData << "\r\n"; + boost::asio::write(mSocket,mRequest); + req_strm.clear(); + } + void readLine(std::string& pData) + { + boost::asio::streambuf response; + boost::asio::read_until(mSocket, response, "\r\n"); + std::istream response_stream(&response); + response_stream >> pData; + } + void handleConnect(const boost::system::error_code& err,tcp::resolver::iterator endpoint_iterator) + { + if (!err) + { + std::string read_buff; + // The connection was successful. Send the request. + std::ostream req_strm(&mRequest); + writeLine("EHLO "+mServer); + readLine(read_buff);//220 + writeLine("AUTH LOGIN"); + readLine(read_buff);// + writeLine(encodeBase64(mUserName)); + readLine(read_buff); + writeLine(encodeBase64(mPassword)); + readLine(read_buff); + writeLine( "MAIL FROM:<"+mFrom+">"); + writeLine( "RCPT TO:<"+mTo+">"); + writeLine( "DATA"); + writeLine( "SUBJECT:"+mSubject); + writeLine( "From:"+mFrom); + writeLine( "To:"+mTo); + writeLine( ""); + writeLine( mMessage ); + writeLine( "\r\n.\r\n"); + readLine(read_buff); + if(read_buff == "250") + mHasError = false; + writeLine( "QUIT"); + } + else + { + mHasError=true; + mErrorMsg= err.message(); + } + } + std::string mServer; + std::string mUserName; + std::string mPassword; + std::string mFrom; + std::string mTo; + std::string mSubject; + std::string mMessage; + unsigned int mPort; + boost::asio::io_service mIOService; + tcp::resolver mResolver; + tcp::socket mSocket; + boost::asio::streambuf mRequest; + boost::asio::streambuf mResponse; + bool mHasError; + std::string mErrorMsg; + }; + + + bool send_mail(const std::string& server, int port, const std::string& login, const std::string& pass, const std::string& from_email, /*"STIL CRAWLER",*/ + const std::string& maillist, const std::string& subject, const std::string& body) + { + STD_TRY_BEGIN(); + //smtp_client mailc("yoursmtpserver.com",25,"user@yourdomain.com","password"); + //mailc.Send("from@yourdomain.com","to@somewhere.com","subject","Hello from C++ SMTP Client!"); + smtp_client mailc(server,port,login,pass); + return mailc.Send(from_email,maillist,subject,body); + STD_TRY_CATCH("at send_mail", false); + } + + } +} +} + +//#include "smtp.inl" \ No newline at end of file diff --git a/contrib/epee/include/net/smtp.inl b/contrib/epee/include/net/smtp.inl new file mode 100644 index 00000000..d42c8b95 --- /dev/null +++ b/contrib/epee/include/net/smtp.inl @@ -0,0 +1,1569 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#include "md5.h" + +namespace epee +{ +namespace net_utils +{ + namespace smtp + { + + + ////////////////////////////////////////////////////////////////////////// + inline char * convert_hex( unsigned char *in, int len ) + { + static char hex[] = "0123456789abcdef"; + char * out; + int i; + + out = (char *) malloc(len * 2 + 1); + if (out == NULL) + return NULL; + + for (i = 0; i < len; i++) { + out[i * 2] = hex[in[i] >> 4]; + out[i * 2 + 1] = hex[in[i] & 15]; + } + + out[i*2] = 0; + + return out; + } + + ////////////////////////////////////////////////////////////////////////// + inline char * hash_md5(const char * sec_key, const char * data, int len) + { + char key[65], digest[24]; + char * hash_hex; + + int sec_len, i; + + sec_len = strlen(sec_key); + + if (sec_len < 64) { + memcpy(key, sec_key, sec_len); + for (i = sec_len; i < 64; i++) { + key[i] = 0; + } + } else { + memcpy(key, sec_key, 64); + } + + md5::hmac_md5( (const unsigned char*)data, len, (const unsigned char*)key, 64, (unsigned char*)digest ); + hash_hex = convert_hex( (unsigned char*)digest, 16 ); + + return hash_hex; + } + ////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////// + inline CSMTPClient::CSMTPClient(void) + { + m_dwSupportedAuthModesCount = 0; + m_bConnected = FALSE; + m_hSocket = INVALID_SOCKET; + m_pErrorText = NULL; + + // Initialize WinSock + WORD wVer = MAKEWORD( 2, 2 ); + if ( WSAStartup( wVer, &m_wsaData ) != NO_ERROR ) + { + SetErrorText( "WSAStartup.", WSAGetLastError() ); + throw; + } + if ( LOBYTE( m_wsaData.wVersion ) != 2 || HIBYTE( m_wsaData.wVersion ) != 2 ) + { + SetErrorText( "Can't find a useable WinSock DLL." ); + WSACleanup(); + throw; + } + } + + ////////////////////////////////////////////////////////////////////////// + inline CSMTPClient::~CSMTPClient(void) + { + if ( m_pErrorText ) + { + free( m_pErrorText ); + m_pErrorText = NULL; + } + + if ( m_bConnected ) + ServerDisconnect(); + + // Cleanup + WSACleanup(); + } + + ////////////////////////////////////////////////////////////////////////// + inline void CSMTPClient::SetErrorText( LPCSTR szErrorText, DWORD dwErrorCode ) + { + if ( m_pErrorText ) + { + free( m_pErrorText ); + m_pErrorText = NULL; + } + + LPVOID lpMsgBuf = NULL; + if ( dwErrorCode ) + { + FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + dwErrorCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR) &lpMsgBuf, + 0, NULL ); + } + + if ( szErrorText && strlen( szErrorText ) ) + { + m_pErrorText = (LPBYTE)malloc( strlen( szErrorText ) + 1 ); + strcpy( (char*)m_pErrorText, szErrorText ); + + if ( lpMsgBuf ) + { + strcat( (char*)m_pErrorText, " " ); + strcpy( (char*)m_pErrorText, (char*)lpMsgBuf ); + + LocalFree( lpMsgBuf ); + } + } + } + + inline void CSMTPClient::SetErrorText( PBYTE szErrorText, DWORD dwErrorCode ) + { + SetErrorText( (LPCSTR)szErrorText, dwErrorCode ); + } + + ////////////////////////////////////////////////////////////////////////// + inline char* CSMTPClient::GetLastErrorText() + { + return (char*)m_pErrorText; + } + + ////////////////////////////////////////////////////////////////////////// + inline DWORD CSMTPClient::ReceiveData( SOCKET hSocket, PBYTE pReceiveBuffer, DWORD dwReceiveBufferSize ) + { + DWORD dwReceivedDataSize = 0; + + if ( hSocket != INVALID_SOCKET && pReceiveBuffer && dwReceiveBufferSize ) + { + int iReceived = 0; + int iLength = 0; + + iLength = recv( hSocket, (LPSTR)pReceiveBuffer + iReceived, dwReceiveBufferSize - iReceived, + NO_FLAGS ); + + if ( iLength != 0 && iLength != SOCKET_ERROR ) + iReceived += iLength; + + dwReceivedDataSize = iReceived; + + pReceiveBuffer[ iReceived ] = 0; + } + + return dwReceivedDataSize; + } + + inline ////////////////////////////////////////////////////////////////////////// + DWORD CSMTPClient::SendData( SOCKET hSocket, PBYTE pSendBuffer, DWORD dwSendBufferSize ) + { + DWORD dwSended = 0; + + if ( hSocket != INVALID_SOCKET && pSendBuffer && dwSendBufferSize ) + { + int iSended = 0; + int iLength = 0; + + while ( iLength != SOCKET_ERROR && dwSendBufferSize - iSended > 0 ) + { + iLength = send( hSocket, (LPSTR)pSendBuffer + iSended, dwSendBufferSize - iSended, + NO_FLAGS ); + + if ( iLength != 0 && iLength != SOCKET_ERROR ) + iSended += iLength; + } + + dwSended = iSended; + } + + //if ( dwSended ) + // printf( "C: %s", pSendBuffer ); + + return dwSended; + } + + ////////////////////////////////////////////////////////////////////////// + inline unsigned short CSMTPClient::GetResponseCode( LPBYTE pBuffer, DWORD dwBufferSize ) + { + unsigned short iCode = 0; + + if ( dwBufferSize >= 3 ) + { + CHAR szResponseCode[ 4 ] = { 0 }; + memcpy( szResponseCode, pBuffer, 3 ); + szResponseCode[ 3 ] = 0; + iCode = atoi( szResponseCode ); + } + + return iCode; + } + + ////////////////////////////////////////////////////////////////////////// + inline void CSMTPClient::ParseESMTPExtensions( LPBYTE pBuffer, DWORD dwBufferSize ) + { + const char *szSubstring = strstr( (const char*)pBuffer, "250-AUTH " ); + if ( !szSubstring ) + { + szSubstring = strstr( (const char*)pBuffer, "250 AUTH " ); + } + + if ( szSubstring ) + { + const char *szSubstringEnd = strstr( (const char*)szSubstring, "\r\n" ); + if ( szSubstringEnd ) + { + szSubstring += 9; + char szAuthMode[ 256 ] = { 0 }; + for ( ; szSubstring < szSubstringEnd + 1 ; szSubstring++ ) + { + if ( *szSubstring == ' ' || *szSubstring == '\r' ) + { + if ( _strcmpi( szAuthMode, SMTP_COMMAND_AUTH_PLAIN ) == 0 ) + { + m_aSupportedAuthModes[ m_dwSupportedAuthModesCount ] = AUTH_MODE_PLAIN; + m_dwSupportedAuthModesCount++; + } + else if ( _strcmpi( szAuthMode, SMTP_COMMAND_AUTH_LOGIN ) == 0 ) + { + m_aSupportedAuthModes[ m_dwSupportedAuthModesCount ] = AUTH_MODE_LOGIN; + m_dwSupportedAuthModesCount++; + } + else if ( _strcmpi( szAuthMode, SMTP_COMMAND_AUTH_CRAM_MD5 ) == 0 ) + { + m_aSupportedAuthModes[ m_dwSupportedAuthModesCount ] = AUTH_MODE_CRAM_MD5; + m_dwSupportedAuthModesCount++; + } + + szAuthMode[ 0 ] = 0; + + if ( m_dwSupportedAuthModesCount == MAX_AUTH_MODES_COUND ) + break; + } + else + { + szAuthMode[ strlen( szAuthMode ) + 1 ] = 0; + szAuthMode[ strlen( szAuthMode ) ] = *szSubstring; + } + } + } + } + } + + ////////////////////////////////////////////////////////////////////////// + inline BOOL CSMTPClient::ServerConnect( LPCSTR szServerAddress, const unsigned short iPortNumber ) + { + if ( m_bConnected ) + ServerDisconnect(); + + m_bConnected = FALSE; + m_hSocket = INVALID_SOCKET; + + m_hSocket = _connectServerSocket( szServerAddress, iPortNumber ); + + if ( m_hSocket != INVALID_SOCKET ) + { + DWORD dwReceiveBufferSize = 1024*16; + PBYTE pReceiveBuffer = (PBYTE)malloc( dwReceiveBufferSize ); + if ( pReceiveBuffer ) + { + // Connected. Wait server hello string. + DWORD iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize ); + if ( iReceived ) + { + // Check 220 + int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived ); + if ( iResponseCode != 220 ) + { + SetErrorText( pReceiveBuffer ); + free( pReceiveBuffer ); + ServerDisconnect(); + return FALSE; + } + } + else + { + SetErrorText( "ReceiveData error. ", WSAGetLastError() ); + free( pReceiveBuffer ); + ServerDisconnect(); + return FALSE; + } + + // EHLO / HELO + BYTE szHelloBuffer[ 256 ]; + sprintf( (char*)szHelloBuffer, "%s %s\r\n", (char*)SMTP_COMMAND_EHLO, (char*)szServerAddress ); + if ( SendData( m_hSocket, (PBYTE)szHelloBuffer, strlen( (const char*)szHelloBuffer ) ) == 0 ) + { + SetErrorText( "SendData error.", WSAGetLastError() ); + free( pReceiveBuffer ); + ServerDisconnect(); + return FALSE; + } + + iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize ); + if ( iReceived ) + { + // Check 250 + int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived ); + if ( iResponseCode == 500 ) + { + SetErrorText( pReceiveBuffer ); + + sprintf( (char*)szHelloBuffer, "%s %s\r\n", (char*)SMTP_COMMAND_HELO, (char*)szServerAddress ); + if ( SendData( m_hSocket, (PBYTE)szHelloBuffer, strlen( (const char*)szHelloBuffer ) ) == 0 ) + { + SetErrorText( "SendData error.", WSAGetLastError() ); + free( pReceiveBuffer ); + ServerDisconnect(); + return FALSE; + } + + iResponseCode = GetResponseCode( pReceiveBuffer, iReceived ); + if ( iResponseCode != 250 ) + { + SetErrorText( pReceiveBuffer ); + free( pReceiveBuffer ); + ServerDisconnect(); + return FALSE; + } + } + else if ( iResponseCode != 250 ) + { + SetErrorText( pReceiveBuffer ); + free( pReceiveBuffer ); + ServerDisconnect(); + return FALSE; + } + + // Parse AUTH supported modes + ParseESMTPExtensions( pReceiveBuffer, iReceived ); + } + else + { + SetErrorText( "ReceiveData error.", WSAGetLastError() ); + free( pReceiveBuffer ); + ServerDisconnect(); + return FALSE; + } + + free( pReceiveBuffer ); + } + } + else + { + return FALSE; + } + + m_bConnected = TRUE; + + return TRUE; + } + + ////////////////////////////////////////////////////////////////////////// + inline BOOL CSMTPClient::ServerConnect( LPCSTR szServerAddress, const unsigned short iPortNumber, LPCSTR szUsername, LPCSTR szPassword ) + { + BOOL bSuccess = FALSE; + + bSuccess = ServerConnect( szServerAddress, iPortNumber ); + if ( bSuccess ) + { + if ( GetAuthModeIsSupported( AUTH_MODE_CRAM_MD5 ) ) + { + ServerLogin( szUsername, szPassword, AUTH_MODE_CRAM_MD5 ); + } + else + if ( GetAuthModeIsSupported( AUTH_MODE_PLAIN ) ) + { + ServerLogin( szUsername, szPassword, AUTH_MODE_PLAIN ); + } + else + if ( GetAuthModeIsSupported( AUTH_MODE_LOGIN ) ) + { + ServerLogin( szUsername, szPassword, AUTH_MODE_LOGIN ); + } + } + + return bSuccess; + } + + ////////////////////////////////////////////////////////////////////////// + inline SOCKET CSMTPClient::_connectServerSocket( LPCSTR szServerAddress, const unsigned short iPortNumber ) + { + int nConnect; + short nProtocolPort = iPortNumber; + LPHOSTENT lpHostEnt; + SOCKADDR_IN sockAddr; + + SOCKET hServerSocket = INVALID_SOCKET; + + lpHostEnt = gethostbyname( szServerAddress ); + if (lpHostEnt) + { + hServerSocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); + if (hServerSocket != INVALID_SOCKET) + { + sockAddr.sin_family = AF_INET; + sockAddr.sin_port = htons( nProtocolPort ); + sockAddr.sin_addr = *((LPIN_ADDR)*lpHostEnt->h_addr_list); + + nConnect = connect( hServerSocket, (PSOCKADDR)&sockAddr, + sizeof(sockAddr) ); + + if ( nConnect != 0 ) + { + SetErrorText( "connect error.", WSAGetLastError() ); + hServerSocket = INVALID_SOCKET; + } + } + else + { + SetErrorText( "Invalid socket." ); + throw; + } + } + else + { + SetErrorText( "Error retrieving host by name.", WSAGetLastError() ); + } + + return hServerSocket ; + } + + ////////////////////////////////////////////////////////////////////////// + inline void CSMTPClient::ServerDisconnect() + { + if ( m_hSocket != INVALID_SOCKET ) + { + if ( SendData( m_hSocket, (PBYTE)SMTP_COMMAND_QUIT, strlen( SMTP_COMMAND_QUIT ) ) == 0 ) + { + SetErrorText( "SendData error.", WSAGetLastError() ); + return; + } + + DWORD dwReceiveBufferSize = 1024*16; + PBYTE pReceiveBuffer = (PBYTE)malloc( dwReceiveBufferSize ); + if ( pReceiveBuffer ) + { + DWORD iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize ); + + if ( iReceived ) + SetErrorText( pReceiveBuffer ); + + free( pReceiveBuffer ); + } + + m_hSocket = INVALID_SOCKET; + } + + m_bConnected = FALSE; + } + + ////////////////////////////////////////////////////////////////////////// + inline BOOL CSMTPClient::GetAuthModeIsSupported( int iMode ) + { + BOOL bSupported = FALSE; + + for ( int i = 0 ; i < m_dwSupportedAuthModesCount ; i++ ) + { + if ( m_aSupportedAuthModes[ i ] == iMode ) + { + bSupported = TRUE; + break; + } + } + + return bSupported; + } + + ////////////////////////////////////////////////////////////////////////// + inline BOOL CSMTPClient::ServerLogin( LPCSTR szUsername, LPCSTR szPassword, int iAuthMode ) + { + BOOL bSuccess = FALSE; + + if ( iAuthMode == AUTH_MODE_PLAIN ) + { + bSuccess = ServerLoginMethodPlain( szUsername, szPassword ); + } + else if ( iAuthMode == AUTH_MODE_LOGIN ) + { + bSuccess = ServerLoginMethodLogin( szUsername, szPassword ); + } + else if ( iAuthMode == AUTH_MODE_CRAM_MD5 ) + { + bSuccess = ServerLoginMethodCramMD5( szUsername, szPassword ); + } + + return bSuccess; + } + + ////////////////////////////////////////////////////////////////////////// + inline BOOL CSMTPClient::ServerLogin( LPCSTR szUsername, LPCSTR szPassword ) + { + BOOL bSuccess = FALSE; + + if ( GetAuthModeIsSupported( AUTH_MODE_CRAM_MD5 ) ) + { + bSuccess = ServerLogin( szUsername, szPassword, AUTH_MODE_CRAM_MD5 ); + } + else + if ( GetAuthModeIsSupported( AUTH_MODE_PLAIN ) ) + { + bSuccess = ServerLogin( szUsername, szPassword, AUTH_MODE_PLAIN ); + } + else + if ( GetAuthModeIsSupported( AUTH_MODE_LOGIN ) ) + { + bSuccess = ServerLogin( szUsername, szPassword, AUTH_MODE_LOGIN ); + } + + return bSuccess; + } + + ////////////////////////////////////////////////////////////////////////// + inline BOOL CSMTPClient::ServerLoginMethodPlain( LPCSTR szUsername, LPCSTR szPassword ) + { + BOOL bSuccess = FALSE; + + BYTE szCommandBuffer[ 256 ]; + sprintf( (char*)szCommandBuffer, "%s %s\r\n", (char*)SMTP_COMMAND_AUTH, (char*)SMTP_COMMAND_AUTH_PLAIN ); + if ( SendData( m_hSocket, (PBYTE)szCommandBuffer, strlen( (const char*)szCommandBuffer ) ) == 0 ) + { + SetErrorText( "SendData error.", WSAGetLastError() ); + return FALSE; + } + + DWORD dwReceiveBufferSize = 1024*16; + PBYTE pReceiveBuffer = (PBYTE)malloc( dwReceiveBufferSize ); + if ( pReceiveBuffer ) + { + // Connected. Wait server hello string. + DWORD iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize ); + if ( iReceived ) + { + SetErrorText( pReceiveBuffer ); + + // Check 334 + int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived ); + if ( iResponseCode != 334 ) + { + free( pReceiveBuffer ); + return FALSE; + } + } + else + { + SetErrorText( "ReceiveData error.", WSAGetLastError() ); + free( pReceiveBuffer ); + return FALSE; + } + + // Encode. + DWORD dwLoginBuffer = strlen( szUsername ) + strlen( szPassword ) + 3; + char *pLoginBuffer = (char*)malloc( dwLoginBuffer ); + if ( pLoginBuffer ) + { + ZeroMemory( pLoginBuffer, dwLoginBuffer ); + strcpy( pLoginBuffer + 1, szUsername ); + strcpy( pLoginBuffer + 1 + strlen( szUsername ) + 1, szPassword ); + + Base64Coder coder; + coder.Encode( (const PBYTE)pLoginBuffer, dwLoginBuffer - 1 ); + LPCSTR szLoginBufferEncoded = coder.EncodedMessage(); + + if ( szLoginBufferEncoded && strlen( szLoginBufferEncoded ) > 0 ) + { + DWORD dwSendBufferSize = strlen( szLoginBufferEncoded ) + 4; + char* pSendBuffer = (char*)malloc( dwSendBufferSize ); + if ( pSendBuffer ) + { + strcpy( pSendBuffer, szLoginBufferEncoded ); + strcat( pSendBuffer, "\r\n" ); + + if ( SendData( m_hSocket, (PBYTE)pSendBuffer, strlen( (const char*)pSendBuffer ) ) == 0 ) + { + SetErrorText( "SendData error.", WSAGetLastError() ); + free( pSendBuffer ); + free( pLoginBuffer ); + free( pReceiveBuffer ); + return FALSE; + } + + free( pSendBuffer ); + } + } + + free( pLoginBuffer ); + + // check result + iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize ); + if ( iReceived ) + { + SetErrorText( pReceiveBuffer ); + + // Check 235 + int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived ); + if ( iResponseCode != 235 ) + { + free( pReceiveBuffer ); + return FALSE; + } + + bSuccess = TRUE; + } + else + { + SetErrorText( "ReceiveData error.", WSAGetLastError() ); + free( pReceiveBuffer ); + return FALSE; + } + } + + free( pReceiveBuffer ); + } + + return bSuccess; + } + + ////////////////////////////////////////////////////////////////////////// + inline BOOL CSMTPClient::ServerLoginMethodLogin( LPCSTR szUsername, LPCSTR szPassword ) + { + BOOL bSuccess = FALSE; + + BYTE szCommandBuffer[ 256 ]; + sprintf( (char*)szCommandBuffer, "%s %s\r\n", (char*)SMTP_COMMAND_AUTH, (char*)SMTP_COMMAND_AUTH_LOGIN ); + if ( SendData( m_hSocket, (PBYTE)szCommandBuffer, strlen( (const char*)szCommandBuffer ) ) == 0 ) + { + SetErrorText( "SendData error.", WSAGetLastError() ); + return FALSE; + } + + DWORD dwReceiveBufferSize = 1024*16; + PBYTE pReceiveBuffer = (PBYTE)malloc( dwReceiveBufferSize ); + if ( pReceiveBuffer ) + { + DWORD iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize ); + if ( iReceived ) + { + SetErrorText( pReceiveBuffer ); + + // Check 334 + int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived ); + if ( iResponseCode != 334 ) + { + free( pReceiveBuffer ); + return FALSE; + } + + // Check request + if ( iReceived > 6 ) + { + Base64Coder coder; + coder.Decode( pReceiveBuffer + 4, iReceived - 6 ); + LPCSTR szRequest = coder.DecodedMessage(); + if ( szRequest && strlen( szRequest ) > 0 ) + { + if ( strcmpi( szRequest, "Username:" ) == 0 ) + { + coder.Encode( (const PBYTE)szUsername, strlen( szUsername ) ); + LPCSTR szUsernameEncoded = coder.EncodedMessage(); + + char* szLoginUsernameBuffer = (char*)malloc( strlen( szUsernameEncoded ) + 4 ); + if ( szLoginUsernameBuffer ) + { + strcpy( szLoginUsernameBuffer, szUsernameEncoded ); + strcat( szLoginUsernameBuffer, "\r\n" ); + + if ( SendData( m_hSocket, (PBYTE)szLoginUsernameBuffer, strlen( (const char*)szLoginUsernameBuffer ) ) == 0 ) + { + SetErrorText( "SendData error.", WSAGetLastError() ); + free( pReceiveBuffer ); + return FALSE; + } + + free( szLoginUsernameBuffer ); + } + else + { + free( pReceiveBuffer ); + return FALSE; + } + + iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize ); + if ( iReceived ) + { + SetErrorText( pReceiveBuffer ); + + // Check 334 + int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived ); + if ( iResponseCode != 334 ) + { + free( pReceiveBuffer ); + return FALSE; + } + + // Check request + if ( iReceived > 6 ) + { + coder.Decode( pReceiveBuffer + 4, iReceived - 6 ); + LPCSTR szRequest2 = coder.DecodedMessage(); + if ( szRequest2 && strlen( szRequest2 ) > 0 ) + { + if ( strcmpi( szRequest2, "Password:" ) == 0 ) + { + coder.Encode( (const PBYTE)szPassword, strlen( szPassword ) ); + LPCSTR szPasswordEncoded = coder.EncodedMessage(); + + char* szLoginPasswordBuffer = (char*)malloc( strlen( szPasswordEncoded ) + 4 ); + if ( szLoginPasswordBuffer ) + { + strcpy( szLoginPasswordBuffer, szPasswordEncoded ); + strcat( szLoginPasswordBuffer, "\r\n" ); + + if ( SendData( m_hSocket, (PBYTE)szLoginPasswordBuffer, strlen( (const char*)szLoginPasswordBuffer ) ) == 0 ) + { + SetErrorText( "SendData error.", WSAGetLastError() ); + free( pReceiveBuffer ); + return FALSE; + } + + free( szLoginPasswordBuffer ); + } + else + { + free( pReceiveBuffer ); + return FALSE; + } + + iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize ); + if ( iReceived ) + { + SetErrorText( pReceiveBuffer ); + + // Check 235 + int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived ); + if ( iResponseCode != 235 ) + { + free( pReceiveBuffer ); + return FALSE; + } + + bSuccess = TRUE; + } + else + { + SetErrorText( "ReceiveData error.", WSAGetLastError() ); + free( pReceiveBuffer ); + return FALSE; + } + } + } + } + } + else + { + free( pReceiveBuffer ); + return FALSE; + } + } + } + else + { + free( pReceiveBuffer ); + return FALSE; + } + } + else + { + free( pReceiveBuffer ); + return FALSE; + } + } + else + { + SetErrorText( "ReceiveData error.", WSAGetLastError() ); + free( pReceiveBuffer ); + return FALSE; + } + + free( pReceiveBuffer ); + } + + return bSuccess; + } + + ////////////////////////////////////////////////////////////////////////// + inline BOOL CSMTPClient::ServerLoginMethodCramMD5( LPCSTR szUsername, LPCSTR szPassword ) + { + BOOL bSuccess = FALSE; + + BYTE szCommandBuffer[ 256 ]; + sprintf( (char*)szCommandBuffer, "%s %s\r\n", (char*)SMTP_COMMAND_AUTH, (char*)SMTP_COMMAND_AUTH_CRAM_MD5 ); + if ( SendData( m_hSocket, (PBYTE)szCommandBuffer, strlen( (const char*)szCommandBuffer ) ) == 0 ) + { + SetErrorText( "SendData error.", WSAGetLastError() ); + return FALSE; + } + + DWORD dwReceiveBufferSize = 1024*16; + PBYTE pReceiveBuffer = (PBYTE)malloc( dwReceiveBufferSize ); + if ( pReceiveBuffer ) + { + // Connected. Wait server hello string. + DWORD iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize ); + if ( iReceived ) + { + SetErrorText( pReceiveBuffer ); + + // Check 334 + int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived ); + if ( iResponseCode != 334 ) + { + free( pReceiveBuffer ); + return FALSE; + } + + // Check request + if ( iReceived > 6 ) + { + Base64Coder coder; + coder.Decode( pReceiveBuffer + 4, iReceived - 6 ); + LPCSTR szResponse = coder.DecodedMessage(); + if ( szResponse && strlen( szResponse ) > 0 ) + { + char *auth_hex = hash_md5( szPassword, szResponse, strlen(szResponse) ); + if ( !auth_hex ) + { + free( pReceiveBuffer ); + return FALSE; + } + + char *szCommand = (char*)malloc( strlen( szUsername ) + strlen( auth_hex ) + 5 ); + if ( szCommand ) + { + sprintf( szCommand, "%s %s", szUsername, auth_hex ); + + free( auth_hex ); + + coder.Encode( (const PBYTE)szCommand, strlen( szCommand ) ); + + free( szCommand ); + + LPCSTR szAuthEncoded = coder.EncodedMessage(); + if ( szAuthEncoded == NULL ) + { + free( pReceiveBuffer ); + return FALSE; + } + + char *szAuthCommand = (char*)malloc( strlen( szAuthEncoded ) + 4 ); + if ( szAuthCommand ) + { + strcpy( szAuthCommand, szAuthEncoded ); + strcat( szAuthCommand, "\r\n" ); + + // Send auth data + if ( SendData( m_hSocket, (PBYTE)szAuthCommand, strlen( (const char*)szAuthCommand ) ) == 0 ) + { + SetErrorText( "SendData error.", WSAGetLastError() ); + free( szAuthCommand ); + free( pReceiveBuffer ); + return FALSE; + } + + // Check response + iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize ); + if ( iReceived ) + { + SetErrorText( pReceiveBuffer ); + + // Check 235 + int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived ); + if ( iResponseCode != 235 ) + { + free( pReceiveBuffer ); + return FALSE; + } + + bSuccess = TRUE; + } + else + { + SetErrorText( "ReceiveData error.", WSAGetLastError() ); + free( pReceiveBuffer ); + return FALSE; + } + + free( szAuthCommand ); + } + else + { + free( pReceiveBuffer ); + return FALSE; + } + } + else + { + free( auth_hex ); + free( pReceiveBuffer ); + return FALSE; + } + } + else + { + free( pReceiveBuffer ); + return FALSE; + } + } + + } + else + { + SetErrorText( "ReceiveData error.", WSAGetLastError() ); + free( pReceiveBuffer ); + return FALSE; + } + + free( pReceiveBuffer ); + } + else + { + SetErrorText( "malloc() failed.", GetLastError() ); + } + + return bSuccess; + } + + ////////////////////////////////////////////////////////////////////////// + inline BOOL CSMTPClient::SendMessage( LPCSTR szFromAddress, LPCSTR szFromName, LPCSTR szToAddresses, LPCSTR szSubject, LPCSTR szXMailer, LPBYTE pBodyBuffer, DWORD dwBodySize ) + { + BOOL bSuccess = FALSE; + + // Format Header + if ( !szFromAddress ) + { + SetErrorText( "SendMessage. Invalid Parameters!" ); + return NULL; + } + + char *szHeaderBuffer = (char*)malloc( 1024 * 16 ); + if ( szHeaderBuffer ) + { + // get the current date and time + char szDate[ 500 ]; + char sztTime[ 500 ]; + + SYSTEMTIME st = { 0 }; + ::GetSystemTime(&st); + + ::GetDateFormatA( MAKELCID( MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), 0, &st, "ddd',' dd MMM yyyy", szDate , sizeof( szDate ) ); + ::GetTimeFormatA( MAKELCID( MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), TIME_FORCE24HOURFORMAT, &st, "HH':'mm':'ss", sztTime, sizeof( sztTime ) ); + + sprintf( szHeaderBuffer, "DATE: %s %s\r\n", szDate, sztTime ); + + // X-Mailer Field + if ( szXMailer && strlen( szXMailer ) ) + { + strcat( szHeaderBuffer, "X-Mailer: " ); + strcat( szHeaderBuffer, szXMailer ); + strcat( szHeaderBuffer, "\r\n" ); + } + + // From: + strcat( szHeaderBuffer, "From: " ); + if ( szFromName ) + { + strcat( szHeaderBuffer, "\"" ); + strcat( szHeaderBuffer, szFromName ); + strcat( szHeaderBuffer, "\" <" ); + strcat( szHeaderBuffer, szFromAddress ); + strcat( szHeaderBuffer, ">\r\n" ); + } + else + { + strcat( szHeaderBuffer, "<" ); + strcat( szHeaderBuffer, szFromAddress ); + strcat( szHeaderBuffer, ">\r\n" ); + } + + // Subject: + if ( szSubject && strlen( szSubject ) ) + { + strcat( szHeaderBuffer, "Subject: " ); + strcat( szHeaderBuffer, szSubject ); + strcat( szHeaderBuffer, "\r\n" ); + } + + // To Fields + strcat( szHeaderBuffer, "To: " ); + strcat( szHeaderBuffer, szToAddresses ); + strcat( szHeaderBuffer, "\r\n" ); + + // MIME + strcat( szHeaderBuffer, "MIME-Version: 1.0\r\nContent-type: text/plain; charset=US-ASCII\r\n" ); + + // End Header + strcat( szHeaderBuffer, "\r\n" ); + } + else + { + SetErrorText( "malloc error.", GetLastError() ); + return FALSE; + } + + + BYTE szCommandBuffer[ 256 ]; + sprintf( (char*)szCommandBuffer, "MAIL FROM:<%s> SIZE=%u\r\n", (char*)szFromAddress, strlen( szHeaderBuffer ) + dwBodySize + 2 ); + if ( SendData( m_hSocket, (PBYTE)szCommandBuffer, strlen( (const char*)szCommandBuffer ) ) == 0 ) + { + SetErrorText( "SendData error.", WSAGetLastError() ); + free( szHeaderBuffer ); + return FALSE; + } + + DWORD dwReceiveBufferSize = 1024*16; + PBYTE pReceiveBuffer = (PBYTE)malloc( dwReceiveBufferSize ); + if ( pReceiveBuffer ) + { + DWORD iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize ); + if ( iReceived ) + { + SetErrorText( pReceiveBuffer ); + + // Check 250 + int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived ); + if ( iResponseCode != 250 ) + { + free( szHeaderBuffer ); + free( pReceiveBuffer ); + return FALSE; + } + } + else + { + SetErrorText( "ReceiveData error.", WSAGetLastError() ); + free( szHeaderBuffer ); + free( pReceiveBuffer ); + return FALSE; + } + + // Post "RCTP TO:" + char *szCurrentAddr = (char*)malloc( strlen( szToAddresses ) + 1 ); + if ( !szCurrentAddr ) + { + SetErrorText( "malloc error.", GetLastError() ); + free( szHeaderBuffer ); + free( pReceiveBuffer ); + return FALSE; + } + + const char* szToOffset = szToAddresses; + char* szZap = NULL; + + BOOL bRCPTAccepted = FALSE; + do + { + strcpy( szCurrentAddr, szToOffset ); + char *szExtractedAdress = szCurrentAddr; + szZap = strchr( szCurrentAddr, ',' ); + + if ( szZap ) + { + *szZap = 0; + szToOffset = szZap + 1; + } + + char *pSkobka1 = strchr( szCurrentAddr, '<' ); + char *pSkobka2 = strchr( szCurrentAddr, '>' ); + + if ( pSkobka1 && pSkobka2 && pSkobka2 > pSkobka1 ) + { + szExtractedAdress = pSkobka1 + 1; + *pSkobka2 = NULL; + } + + if ( szExtractedAdress && strlen( szExtractedAdress ) > 0 ) + { + sprintf( (char*)szCommandBuffer, "RCPT TO:<%s>\r\n", (char*)szExtractedAdress ); + if ( SendData( m_hSocket, (PBYTE)szCommandBuffer, strlen( (const char*)szCommandBuffer ) ) == 0 ) + { + SetErrorText( "SendData error.", WSAGetLastError() ); + free( szCurrentAddr ); + free( pReceiveBuffer ); + free( szHeaderBuffer ); + return FALSE; + } + + iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize ); + if ( iReceived ) + { + SetErrorText( pReceiveBuffer ); + + // Check 250 + int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived ); + if ( iResponseCode == 250 ) + { + bRCPTAccepted = TRUE; + } + } + else + { + SetErrorText( "ReceiveData error.", WSAGetLastError() ); + free( szCurrentAddr ); + free( pReceiveBuffer ); + free( szHeaderBuffer ); + return FALSE; + } + } + + } while( szZap ); + + free( szCurrentAddr ); + + if ( bRCPTAccepted ) + { + sprintf( (char*)szCommandBuffer, "DATA\r\n" ); + if ( SendData( m_hSocket, (PBYTE)szCommandBuffer, strlen( (const char*)szCommandBuffer ) ) == 0 ) + { + SetErrorText( "SendData error.", WSAGetLastError() ); + free( pReceiveBuffer ); + free( szHeaderBuffer ); + return FALSE; + } + + iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize ); + if ( iReceived ) + { + SetErrorText( pReceiveBuffer ); + + // Check 354 + int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived ); + if ( iResponseCode != 354 ) + { + free( pReceiveBuffer ); + free( szHeaderBuffer ); + return FALSE; + } + } + else + { + SetErrorText( "ReceiveData error.", WSAGetLastError() ); + free( pReceiveBuffer ); + free( szHeaderBuffer ); + return FALSE; + } + + // Send message data (header + body + .) + if ( SendData( m_hSocket, (PBYTE)szHeaderBuffer, strlen( (const char*)szHeaderBuffer ) ) == 0 ) + { + SetErrorText( "SendData error.", WSAGetLastError() ); + free( pReceiveBuffer ); + free( szHeaderBuffer ); + return FALSE; + } + + if ( SendData( m_hSocket, (PBYTE)pBodyBuffer, dwBodySize ) == 0 ) + { + SetErrorText( "SendData error.", WSAGetLastError() ); + free( pReceiveBuffer ); + free( szHeaderBuffer ); + return FALSE; + } + + if ( SendData( m_hSocket, (PBYTE)"\r\n.\r\n", 5 ) == 0 ) + { + SetErrorText( "SendData error.", WSAGetLastError() ); + free( pReceiveBuffer ); + free( szHeaderBuffer ); + return FALSE; + } + + iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize ); + if ( iReceived ) + { + SetErrorText( pReceiveBuffer ); + + // Check 250 + int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived ); + if ( iResponseCode == 250 ) + { + bSuccess = TRUE; + } + } + else + { + SetErrorText( "ReceiveData error.", WSAGetLastError() ); + } + } + + free( pReceiveBuffer ); + } + else + { + SetErrorText( "malloc error.", GetLastError() ); + } + + if ( szHeaderBuffer ) + free( szHeaderBuffer ); + + return bSuccess; + } + + + + ////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////// + + +#ifndef PAGESIZE +#define PAGESIZE 4096 +#endif + +#ifndef ROUNDTOPAGE +#define ROUNDTOPAGE(a) (((a/4096)+1)*4096) +#endif + + ////////////////////////////////////////////////////////////////////// + // Construction/Destruction + ////////////////////////////////////////////////////////////////////// + + inline Base64Coder::Base64Coder() + : m_pDBuffer(NULL), + m_pEBuffer(NULL), + m_nDBufLen(0), + m_nEBufLen(0) + { + + } + + inline Base64Coder::~Base64Coder() + { + if(m_pDBuffer != NULL) + delete [] m_pDBuffer; + + if(m_pEBuffer != NULL) + delete [] m_pEBuffer; + } + + inline LPCSTR Base64Coder::DecodedMessage() const + { + return (LPCSTR) m_pDBuffer; + } + + inline LPCSTR Base64Coder::EncodedMessage() const + { + return (LPCSTR) m_pEBuffer; + } + + inline void Base64Coder::AllocEncode(DWORD nSize) + { + if(m_nEBufLen < nSize) + { + if(m_pEBuffer != NULL) + delete [] m_pEBuffer; + + m_nEBufLen = ROUNDTOPAGE(nSize); + m_pEBuffer = new BYTE[m_nEBufLen]; + } + + ::ZeroMemory(m_pEBuffer, m_nEBufLen); + m_nEDataLen = 0; + } + + inline void Base64Coder::AllocDecode(DWORD nSize) + { + if(m_nDBufLen < nSize) + { + if(m_pDBuffer != NULL) + delete [] m_pDBuffer; + + m_nDBufLen = ROUNDTOPAGE(nSize); + m_pDBuffer = new BYTE[m_nDBufLen]; + } + + ::ZeroMemory(m_pDBuffer, m_nDBufLen); + m_nDDataLen = 0; + } + + inline void Base64Coder::SetEncodeBuffer(const PBYTE pBuffer, DWORD nBufLen) + { + DWORD i = 0; + + AllocEncode(nBufLen); + while(i < nBufLen) + { + if(!_IsBadMimeChar(pBuffer[i])) + { + m_pEBuffer[m_nEDataLen] = pBuffer[i]; + m_nEDataLen++; + } + + i++; + } + } + + inline void Base64Coder::SetDecodeBuffer(const PBYTE pBuffer, DWORD nBufLen) + { + AllocDecode(nBufLen); + ::CopyMemory(m_pDBuffer, pBuffer, nBufLen); + m_nDDataLen = nBufLen; + } + + inline void Base64Coder::Encode(const PBYTE pBuffer, DWORD nBufLen) + { + SetDecodeBuffer(pBuffer, nBufLen); + AllocEncode(nBufLen * 2); + + TempBucket Raw; + DWORD nIndex = 0; + + while((nIndex + 3) <= nBufLen) + { + Raw.Clear(); + ::CopyMemory(&Raw, m_pDBuffer + nIndex, 3); + Raw.nSize = 3; + _EncodeToBuffer(Raw, m_pEBuffer + m_nEDataLen); + nIndex += 3; + m_nEDataLen += 4; + } + + if(nBufLen > nIndex) + { + Raw.Clear(); + Raw.nSize = (BYTE) (nBufLen - nIndex); + ::CopyMemory(&Raw, m_pDBuffer + nIndex, nBufLen - nIndex); + _EncodeToBuffer(Raw, m_pEBuffer + m_nEDataLen); + m_nEDataLen += 4; + } + } + + inline void Base64Coder::Encode(LPCSTR szMessage) + { + if(szMessage != NULL) + Base64Coder::Encode((const PBYTE)szMessage, strlen( (const char*)szMessage)); + } + + inline void Base64Coder::Decode(const PBYTE pBuffer, DWORD dwBufLen) + { + if(is_init()) + _Init(); + + SetEncodeBuffer(pBuffer, dwBufLen); + + AllocDecode(dwBufLen); + + TempBucket Raw; + + DWORD nIndex = 0; + + while((nIndex + 4) <= m_nEDataLen) + { + Raw.Clear(); + Raw.nData[0] = DecodeTable()[m_pEBuffer[nIndex]]; + Raw.nData[1] = DecodeTable()[m_pEBuffer[nIndex + 1]]; + Raw.nData[2] = DecodeTable()[m_pEBuffer[nIndex + 2]]; + Raw.nData[3] = DecodeTable()[m_pEBuffer[nIndex + 3]]; + + if(Raw.nData[2] == 255) + Raw.nData[2] = 0; + if(Raw.nData[3] == 255) + Raw.nData[3] = 0; + + Raw.nSize = 4; + _DecodeToBuffer(Raw, m_pDBuffer + m_nDDataLen); + nIndex += 4; + m_nDDataLen += 3; + } + + // If nIndex < m_nEDataLen, then we got a decode message without padding. + // We may want to throw some kind of warning here, but we are still required + // to handle the decoding as if it was properly padded. + if(nIndex < m_nEDataLen) + { + Raw.Clear(); + for(DWORD i = nIndex; i < m_nEDataLen; i++) + { + Raw.nData[i - nIndex] = DecodeTable()[m_pEBuffer[i]]; + Raw.nSize++; + if(Raw.nData[i - nIndex] == 255) + Raw.nData[i - nIndex] = 0; + } + + _DecodeToBuffer(Raw, m_pDBuffer + m_nDDataLen); + m_nDDataLen += (m_nEDataLen - nIndex); + } + } + + inline void Base64Coder::Decode(LPCSTR szMessage) + { + if(szMessage != NULL) + Base64Coder::Decode((const PBYTE)szMessage, strlen((const char*)szMessage)); + } + + inline DWORD Base64Coder::_DecodeToBuffer(const TempBucket &Decode, PBYTE pBuffer) + { + TempBucket Data; + DWORD nCount = 0; + + _DecodeRaw(Data, Decode); + + for(int i = 0; i < 3; i++) + { + pBuffer[i] = Data.nData[i]; + if(pBuffer[i] != 255) + nCount++; + } + + return nCount; + } + + + inline void Base64Coder::_EncodeToBuffer(const TempBucket &Decode, PBYTE pBuffer) + { + TempBucket Data; + + _EncodeRaw(Data, Decode); + + for(int i = 0; i < 4; i++) + pBuffer[i] = Base64Digits()[Data.nData[i]]; + + switch(Decode.nSize) + { + case 1: + pBuffer[2] = '='; + case 2: + pBuffer[3] = '='; + } + } + + inline void Base64Coder::_DecodeRaw(TempBucket &Data, const TempBucket &Decode) + { + BYTE nTemp; + + Data.nData[0] = Decode.nData[0]; + Data.nData[0] <<= 2; + + nTemp = Decode.nData[1]; + nTemp >>= 4; + nTemp &= 0x03; + Data.nData[0] |= nTemp; + + Data.nData[1] = Decode.nData[1]; + Data.nData[1] <<= 4; + + nTemp = Decode.nData[2]; + nTemp >>= 2; + nTemp &= 0x0F; + Data.nData[1] |= nTemp; + + Data.nData[2] = Decode.nData[2]; + Data.nData[2] <<= 6; + nTemp = Decode.nData[3]; + nTemp &= 0x3F; + Data.nData[2] |= nTemp; + } + + inline void Base64Coder::_EncodeRaw(TempBucket &Data, const TempBucket &Decode) + { + BYTE nTemp; + + Data.nData[0] = Decode.nData[0]; + Data.nData[0] >>= 2; + + Data.nData[1] = Decode.nData[0]; + Data.nData[1] <<= 4; + nTemp = Decode.nData[1]; + nTemp >>= 4; + Data.nData[1] |= nTemp; + Data.nData[1] &= 0x3F; + + Data.nData[2] = Decode.nData[1]; + Data.nData[2] <<= 2; + + nTemp = Decode.nData[2]; + nTemp >>= 6; + + Data.nData[2] |= nTemp; + Data.nData[2] &= 0x3F; + + Data.nData[3] = Decode.nData[2]; + Data.nData[3] &= 0x3F; + } + + inline BOOL Base64Coder::_IsBadMimeChar(BYTE nData) + { + switch(nData) + { + case '\r': case '\n': case '\t': case ' ' : + case '\b': case '\a': case '\f': case '\v': + return TRUE; + default: + return FALSE; + } + } + + inline void Base64Coder::_Init() + { // Initialize Decoding table. + + int i; + + for(i = 0; i < 256; i++) + DecodeTable()[i] = -2; + + for(i = 0; i < 64; i++) + { + DecodeTable()[Base64Digits()[i]] = i; + DecodeTable()[Base64Digits()[i]|0x80] = i; + } + + DecodeTable()['='] = -1; + DecodeTable()['='|0x80] = -1; + + is_init() = TRUE; + } + + + } +} +} \ No newline at end of file diff --git a/contrib/epee/include/net/smtp_helper.h b/contrib/epee/include/net/smtp_helper.h new file mode 100644 index 00000000..b8252e1c --- /dev/null +++ b/contrib/epee/include/net/smtp_helper.h @@ -0,0 +1,88 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + + +#pragma once +#include "smtp.h" + +namespace epee +{ +namespace net_utils +{ + namespace smtp + { + + inline bool send_mail(const std::string& server, int port, const std::string& login, const std::string& pass, const std::string& from_addres, const std::string& from_name, const std::string& maillist, const std::string& subject, const std::string& mail_body) + { + net_utils::smtp::CSMTPClient smtp; + + if ( !smtp.ServerConnect( server.c_str(), port ) ) + { + LOG_PRINT("Reporting: Failed to connect to server " << server <<":"<< port, LOG_LEVEL_0); + return false; + } + + if(login.size() && pass.size()) + { + if ( !smtp.ServerLogin( login.c_str(), pass.c_str()) ) + { + LOG_PRINT("Reporting: Failed to auth on server " << server <<":"<< port, LOG_LEVEL_0); + return false; + + } + } + + if ( !smtp.SendMessage( from_addres.c_str(), + from_name.c_str(), + maillist.c_str(), + subject.c_str(), + "bicycle-client", + (LPBYTE)mail_body.data(), + mail_body.size())) + { + char *szErrorText = smtp.GetLastErrorText(); + if ( szErrorText ) + { + LOG_PRINT("Failed to send message, error text: " << szErrorText, LOG_LEVEL_0); + } + else + { + LOG_PRINT("Failed to send message, error text: null", LOG_LEVEL_0); + } + return false; + } + + smtp.ServerDisconnect(); + + return true; + + + } + } +} +} \ No newline at end of file diff --git a/contrib/epee/include/os_defenitions.h b/contrib/epee/include/os_defenitions.h new file mode 100644 index 00000000..0cd80a9c --- /dev/null +++ b/contrib/epee/include/os_defenitions.h @@ -0,0 +1,49 @@ + +// Copyright (c) 2006-2016, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + +#pragma once + + + +// Check windows +#if _WIN32 || _WIN64 +#if _WIN64 +#define ENV64BIT +#else +#define ENV32BIT +#endif +#endif + +// Check GCC +#if __GNUC__ +#if __x86_64__ || __ppc64__ +#define ENV64BIT +#else +#define ENV32BIT +#endif +#endif \ No newline at end of file diff --git a/contrib/epee/include/print_fixed_point_helper.h b/contrib/epee/include/print_fixed_point_helper.h new file mode 100644 index 00000000..43843618 --- /dev/null +++ b/contrib/epee/include/print_fixed_point_helper.h @@ -0,0 +1,45 @@ +// Copyright (c) 2006-2017, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + +#pragma once + +namespace epee +{ + namespace string_tools + { + inline std::string print_fixed_decimal_point(uint64_t amount, size_t decimal_point) + { + std::string s = std::to_string(amount); + if (s.size() < decimal_point + 1) + { + s.insert(0, decimal_point + 1 - s.size(), '0'); + } + s.insert(s.size() - decimal_point, "."); + return s; + } + } +} diff --git a/contrib/epee/include/profile_tools.h b/contrib/epee/include/profile_tools.h new file mode 100644 index 00000000..aec18067 --- /dev/null +++ b/contrib/epee/include/profile_tools.h @@ -0,0 +1,147 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + +#ifndef _PROFILE_TOOLS_H_ +#define _PROFILE_TOOLS_H_ + +#include +#include +#include "misc_log_ex.h" +#include "print_fixed_point_helper.h" +#define ENABLE_PROFILING + +namespace epee +{ + +#ifdef ENABLE_PROFILING +#define PROFILE_FUNC(profile_name_str) static epee::profile_tools::local_call_account lcl_acc(profile_name_str); \ + epee::profile_tools::call_frame cf(lcl_acc); + +#define PROFILE_FUNC_SECOND(profile_name_str) static epee::profile_tools::local_call_account lcl_acc2(profile_name_str); \ + epee::profile_tools::call_frame cf2(lcl_acc2); + +#define PROFILE_FUNC_THIRD(profile_name_str) static epee::profile_tools::local_call_account lcl_acc3(profile_name_str); \ + epee::profile_tools::call_frame cf3(lcl_acc3); + +#define PROFILE_FUNC_ACC(acc) \ + epee::profile_tools::call_frame cf(acc); + + +#else +#define PROFILE_FUNC(profile_name_str) +#define PROFILE_FUNC_SECOND(profile_name_str) +#define PROFILE_FUNC_THIRD(profile_name_str) +#define PROFILE_FUNC_ACC(profile_name_str) +#endif + +#define START_WAY_POINTS() uint64_t _____way_point_time = misc_utils::get_tick_count(); +#define WAY_POINT(name) {uint64_t delta = misc_utils::get_tick_count()-_____way_point_time; LOG_PRINT("Way point " << name << ": " << delta, LOG_LEVEL_2);_____way_point_time = misc_utils::get_tick_count();} +#define WAY_POINT2(name, avrg_obj) {uint64_t delta = misc_utils::get_tick_count()-_____way_point_time; avrg_obj.push(delta); LOG_PRINT("Way point " << name << ": " << delta, LOG_LEVEL_2);_____way_point_time = misc_utils::get_tick_count();} + + +#define TIME_MEASURE_START_MS(var_name) uint64_t var_name = epee::misc_utils::get_tick_count(); +#define TIME_MEASURE_FINISH_MS(var_name) var_name = epee::misc_utils::get_tick_count() - var_name; + + + +#define TIME_MEASURE_START(var_name) uint64_t var_name = 0;std::chrono::high_resolution_clock::time_point var_name##_chrono = std::chrono::high_resolution_clock::now(); +#define TIME_MEASURE_FINISH(var_name) var_name = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - var_name##_chrono).count(); + + +#define TIME_MEASURE_START_PD_MS(var_name) TIME_MEASURE_START_MS(var_name) +#define TIME_MEASURE_FINISH_PD_MS(var_name) TIME_MEASURE_FINISH_MS(var_name);m_performance_data.var_name.push(var_name); + +#define TIME_MEASURE_START_PD(var_name) TIME_MEASURE_START(var_name) +#define TIME_MEASURE_FINISH_PD(var_name) TIME_MEASURE_FINISH(var_name);m_performance_data.var_name.push(var_name); +#define TIME_MEASURE_FINISH_PD_COND(cond, var_name) if(cond){TIME_MEASURE_FINISH(var_name);m_performance_data.var_name.push(var_name);} + + + +namespace profile_tools +{ + + static inline void init_profile_session() + { + static std::atomic is_initialized(false); + if (!is_initialized) + { + is_initialized = true; + LOG_PRINT2("profile_details.log", "=================================================================================================================================================", LOG_LEVEL_0); + } + } + + struct local_call_account + { + local_call_account(const char* pstr) :m_count_of_call(0), m_summary_time_used(0), m_name(pstr) + { + init_profile_session(); + } + local_call_account() :m_count_of_call(0), m_summary_time_used(0) + { + init_profile_session(); + } + ~local_call_account() + { + LOG_PRINT2("profile_details.log", "PROFILE "<< std::left << std::setw(50) << (m_name + ":") + << "av_time:" << std::setw(15) << epee::string_tools::print_fixed_decimal_point (m_count_of_call ? (m_summary_time_used / m_count_of_call) : 0, 3) + << "sum_time: " << std::setw(15) << epee::string_tools::print_fixed_decimal_point(m_summary_time_used, 3) + << "call_count: " << std::setw(15) << m_count_of_call, LOG_LEVEL_0); + } + + size_t m_count_of_call; + uint64_t m_summary_time_used; + std::string m_name; + }; + + struct call_frame + { + + call_frame(local_call_account& cc):m_cc(cc) + { + m_call_time = boost::posix_time::microsec_clock::local_time(); + } + + ~call_frame() + { + boost::posix_time::ptime now_t(boost::posix_time::microsec_clock::local_time()); + boost::posix_time::time_duration delta_microsec = now_t - m_call_time; + uint64_t microseconds_used = delta_microsec.total_microseconds(); + m_cc.m_summary_time_used += microseconds_used; + m_cc.m_count_of_call++; + } + + private: + local_call_account& m_cc; + boost::posix_time::ptime m_call_time; + }; + + +} +} + + +#endif //_PROFILE_TOOLS_H_ diff --git a/contrib/epee/include/readwrite_lock.h b/contrib/epee/include/readwrite_lock.h new file mode 100644 index 00000000..f3152e2a --- /dev/null +++ b/contrib/epee/include/readwrite_lock.h @@ -0,0 +1,225 @@ +// Copyright (c) 2006-2017, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#pragma once + +#include +#include +#include +#include +#include +#include + + +namespace epee +{ + + template + class per_thread_data + { + typedef std::map container; + public: + std::recursive_mutex cs; + container th_data; + public: + typename container::iterator get_it() + { + std::unique_lock lk(cs); + auto it = th_data.find(std::this_thread::get_id()); + if (it == th_data.end()) + { + it = th_data.insert(std::make_pair(std::this_thread::get_id(), AUTO_VAL_INIT(t_data()))).first; + } + return it; + } + + t_data& get() + { + std::unique_lock lk(cs); + return get_it()->second; + } + + void erase(typename container::iterator it) + { + std::unique_lock lk(cs); + th_data.erase(it); + } + void erase() + { + std::unique_lock lk(cs); + auto it = th_data.find(std::this_thread::get_id()); + if (it != th_data.end()) + th_data.erase(it); + } + }; + + + /* + Naive implementation of shared recursive mutex with restriction: if you already have acquired shared ownership then + attempt to acquire exclusive ownership will cause deadlock. + */ + class shared_recursive_mutex + { + struct thread_data + { + uint64_t recursion_count; + bool is_writer_thread; + }; + + + + std::condition_variable cv; + std::atomic readers_count; + std::recursive_mutex exclusive_lock; + std::mutex cv_mutex; + per_thread_data ptc; + public: + shared_recursive_mutex() + : readers_count(0) + {} + + ~shared_recursive_mutex() + {} + + void lock() + { + exclusive_lock.lock(); + std::unique_lock lk(cv_mutex); + thread_data& thd = ptc.get(); + if (thd.recursion_count != 0 && !thd.is_writer_thread) + { + ASSERT_MES_AND_THROW("attempt to acquire exclusive ownership while shared ownership already owning"); + } + thd.is_writer_thread = true; + thd.recursion_count++; + + if (readers_count == 0) + return; + + cv.wait(lk, [&](){return readers_count == 0; }); + } + // bool try_lock(); + void unlock() + { + auto thd_it = ptc.get_it(); + thd_it->second.recursion_count--; + if (thd_it->second.recursion_count == 0) + ptc.erase(thd_it); + + exclusive_lock.unlock(); + } + void lock_shared() + { + thread_data& td = ptc.get(); + if (!td.recursion_count) + { + //lock exclusive lock only first entrance to reader lock + exclusive_lock.lock(); + + //always lock cv_mutex when modifying readers_count + std::lock_guard lk(cv_mutex); + readers_count++; + } + + td.recursion_count++; + if (td.recursion_count == 1) + exclusive_lock.unlock(); + } + // bool try_lock_shared(); + void unlock_shared() + { + bool do_notify = false; + { + //process per thread data + auto thd_it = ptc.get_it(); + thd_it->second.recursion_count--; + if (thd_it->second.recursion_count == 0) + { + { + std::lock_guard lk(cv_mutex); + readers_count--; + } + if (readers_count == 0) + do_notify = true; + + ptc.erase(thd_it); + } + } + if (do_notify) + cv.notify_all(); + } + }; + + + + /* + Shared membership for mutex + */ + template + class shared_membership + { + t_shared_mutex& m_mutex; + public: + //to make copy fake! + shared_membership(t_shared_mutex& m) :m_mutex(m) + { + } + ~shared_membership() + { + } + void lock() + { + m_mutex.lock_shared(); + } + void unlock() + { + m_mutex.unlock_shared(); + } + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + //for now ignore shared mutex stuff + template<> + class guarded_critical_region_t : public critical_region_t + { + public: + guarded_critical_region_t(epee::shared_recursive_mutex& cs, const char* /*func_name*/, const char* /*location*/, const char* /*lock_name*/, const std::string& /*thread_name*/) : critical_region_t(cs) + {} + }; + template<> + class guarded_critical_region_t > : public critical_region_t> + { + public: + guarded_critical_region_t(shared_membership& cs, const char* /*func_name*/, const char* /*location*/, const char* /*lock_name*/, const std::string& /*thread_name*/) : critical_region_t>(cs) + {} + }; + + +} diff --git a/contrib/epee/include/reg_exp_definer.h b/contrib/epee/include/reg_exp_definer.h new file mode 100644 index 00000000..e2bed5c3 --- /dev/null +++ b/contrib/epee/include/reg_exp_definer.h @@ -0,0 +1,84 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + +#ifndef _REG_EXP_DEFINER_H_ +#define _REG_EXP_DEFINER_H_ + +#include + + +namespace epee +{ + class global_regexp_critical_section + { + private: + mutable critical_section regexp_lock; + public: + global_regexp_critical_section(){} + critical_section& get_lock()const {return regexp_lock;} + }; + + const static global_regexp_critical_section gregexplock; + +#define STATIC_REGEXP_EXPR_1(var_name, xpr_text, reg_exp_flags) \ + static volatile uint32_t regexp_initialized_1 = 0;\ + volatile uint32_t local_is_initialized_1 = regexp_initialized_1;\ + if(!local_is_initialized_1)\ + gregexplock.get_lock().lock();\ + static const boost::regex var_name(xpr_text , reg_exp_flags);\ + if(!local_is_initialized_1)\ +{\ + boost::interprocess::ipcdetail::atomic_write32(®exp_initialized_1, 1);\ + gregexplock.get_lock().unlock();\ +} + +#define STATIC_REGEXP_EXPR_2(var_name, xpr_text, reg_exp_flags) \ + static volatile uint32_t regexp_initialized_2 = 0;\ + volatile uint32_t local_is_initialized_2 = regexp_initialized_2;\ + if(!local_is_initialized_2)\ + gregexplock.get_lock().lock().lock();\ + static const boost::regex var_name(xpr_text , reg_exp_flags);\ + if(!local_is_initialized_2)\ +{\ + boost::interprocess::ipcdetail::atomic_write32(®exp_initialized_2, 1);\ + gregexplock.get_lock().lock().unlock();\ +} + +#define STATIC_REGEXP_EXPR_3(var_name, xpr_text, reg_exp_flags) \ + static volatile uint32_t regexp_initialized_3 = 0;\ + volatile uint32_t local_is_initialized_3 = regexp_initialized_3;\ + if(!local_is_initialized_3)\ + gregexplock.get_lock().lock().lock();\ + static const boost::regex var_name(xpr_text , reg_exp_flags);\ + if(!local_is_initialized_3)\ +{\ + boost::interprocess::ipcdetail::atomic_write32(®exp_initialized_3, 1);\ + gregexplock.get_lock().lock().unlock();\ +} +} + +#endif //_REG_EXP_DEFINER_H_ diff --git a/contrib/epee/include/reg_utils.h b/contrib/epee/include/reg_utils.h new file mode 100644 index 00000000..22227a9b --- /dev/null +++ b/contrib/epee/include/reg_utils.h @@ -0,0 +1,249 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + +#ifndef _MUSC_UTILS_EX_H_ +#define _MUSC_UTILS_EX_H_ + +namespace epee +{ +namespace reg_utils +{ + //----------------------------------------------------------------------------------------------------------------------------------- + template + bool RegSetPODValue(HKEY hParentKey, const char* pSubKey, const char* pValName, const T& valToSave, bool force_create = true) + { + HKEY hRegKey = 0; + DWORD dw = 0; + + if( ::RegOpenKeyExA(hParentKey, pSubKey, 0, KEY_WRITE, &hRegKey) != ERROR_SUCCESS ) + if(force_create && (::RegCreateKeyExA(hParentKey, pSubKey, 0, "", REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hRegKey, &dw) != ERROR_SUCCESS) ) + return false; + + + DWORD val_type = (sizeof(valToSave) == sizeof(DWORD)) ? REG_DWORD:REG_BINARY; + + BOOL res = ::RegSetValueExA( hRegKey, pValName, 0, val_type, (LPBYTE)&valToSave, sizeof(valToSave)) == ERROR_SUCCESS; + + ::RegCloseKey(hRegKey); + return ERROR_SUCCESS==res ? true:false; + } + //----------------------------------------------------------------------------------------------------------------------------------- + template + bool RegGetPODValue(HKEY hParentKey, const char* pSubKey, const char* pValName, T& valToSave) + { + HKEY hRegKey = 0; + LONG res = 0; + + + if(::RegOpenKeyExA(hParentKey, pSubKey, 0, KEY_READ, &hRegKey) == ERROR_SUCCESS ) + { + DWORD dwType, lSize = 0; + res = ::RegQueryValueExA(hRegKey, pValName, 0, &dwType, NULL, &lSize); + if(ERROR_SUCCESS!=res || (sizeof(valToSave) < lSize) ) + { + ::RegCloseKey(hRegKey); + return false; + } + res = ::RegQueryValueExA(hRegKey, pValName, 0, &dwType, (LPBYTE)&valToSave, &lSize); + } + return ERROR_SUCCESS==res ? true:false; + } + //----------------------------------------------------------------------------------------------------------------------------------- + inline + bool RegSetANSIString(HKEY hParentKey, const char* pSubKey, const char* pValName, const std::string& strToSave) + { + HKEY hRegKey = 0; + DWORD dw = 0; + DWORD res_ = 0; + if( (res_ = ::RegCreateKeyExA(hParentKey, pSubKey, 0, "", REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hRegKey, &dw)) != ERROR_SUCCESS ) + if( (res_= ::RegOpenKeyExA(hParentKey, pSubKey, 0, KEY_WRITE, &hRegKey)) != ERROR_SUCCESS ) + return false; + + DWORD valType = REG_SZ; + const char* pStr = strToSave.c_str(); + DWORD sizeOfStr = (DWORD)strToSave.size()+1; + LSTATUS res = ::RegSetValueExA(hRegKey, pValName, 0, valType, (LPBYTE)pStr, sizeOfStr); + + ::RegCloseKey(hRegKey); + return ERROR_SUCCESS==res ? true:false; + } + //----------------------------------------------------------------------------------------------------------------------------------- + inline + bool RegGetANSIString(HKEY hParentKey, const char* pSubKey, const char* pValName, std::string& strToSave) + { + HKEY hRegKey = 0; + LONG res = 0; + + + if((res = ::RegOpenKeyExA(hParentKey, pSubKey, 0, KEY_READ, &hRegKey)) == ERROR_SUCCESS ) + { + DWORD dwType, lSize = 0; + res = ::RegQueryValueExA(hRegKey, pValName, 0, &dwType, NULL, &lSize); + if(ERROR_SUCCESS!=res) + { + + ::RegCloseKey(hRegKey); + return false; + } + char* pTmpStr = new char[lSize+2]; + memset(pTmpStr, 0, lSize+2); + res = ::RegQueryValueExA(hRegKey, pValName, 0, &dwType, (LPBYTE)pTmpStr, &lSize); + pTmpStr[lSize+1] = 0; //be happy ;) + strToSave = pTmpStr; + delete [] pTmpStr; + ::RegCloseKey(hRegKey); + } + return ERROR_SUCCESS==res ? true:false; + } + //----------------------------------------------------------------------------------------------------------------------------------- + template + bool RegSetRAWValue(HKEY hKey, const char* pValName, const TMemoryObject& valToSave, DWORD valType = REG_BINARY) + { + LONG res = ::RegSetValueExA( hKey, pValName, 0, valType, (CONST BYTE*)valToSave.get(0), (DWORD)valToSave.get_size()); + + return ERROR_SUCCESS==res ? true:false; + } + //---------------------------------------------------------------------------------------------------------------------------------- + bool RegSetRAWValue(HKEY hKey, const char* pValName, const std::string & valToSave, DWORD valType = REG_BINARY) + { + LONG res = ::RegSetValueExA( hKey, pValName, 0, valType, (CONST BYTE*)valToSave.data(), (DWORD)valToSave.size()); + + return ERROR_SUCCESS==res ? true:false; + } + //----------------------------------------------------------------------------------------------------------------------------------- + template + bool RegGetRAWValue(HKEY hKey, const char* pValName, TMemoryObject& valToSave, DWORD* pRegType) + { + DWORD dwType, lSize = 0; + LONG res = ::RegQueryValueExA(hKey, pValName, 0, &dwType, NULL, &lSize); + if(ERROR_SUCCESS!=res || 0 >= lSize) + { + valToSave.release(); + return false; + } + if(valToSave.get_size() < lSize) + valToSave.alloc_buff(lSize); + res = ::RegQueryValueExA(hKey, pValName, 0, &dwType, (LPBYTE)valToSave.get(0), &lSize); + if(pRegType) *pRegType = dwType; + + return ERROR_SUCCESS==res ? true:false; + } + //----------------------------------------------------------------------------------------------------------------------------------- + bool RegGetRAWValue(HKEY hKey, const char* pValName, std::string& valToSave, DWORD* pRegType) + { + DWORD dwType, lSize = 0; + LONG res = ::RegQueryValueExA(hKey, pValName, 0, &dwType, NULL, &lSize); + if(ERROR_SUCCESS!=res || 0 >= lSize) + { + return false; + } + + valToSave.resize(lSize); + res = ::RegQueryValueExA(hKey, pValName, 0, &dwType, (LPBYTE)valToSave.data(), &lSize); + if(pRegType) *pRegType = dwType; + + return ERROR_SUCCESS==res ? true:false; + } + //----------------------------------------------------------------------------------------------------------------------------------- + template + bool RegSetRAWValue(HKEY hParentKey, const char* pSubKey, const char* pValName, const TMemoryObject& valToSave, DWORD valType = REG_BINARY) + { + HKEY hRegKey = 0; + DWORD dw = 0; + bool res = false; + + if( ::RegCreateKeyExA(hParentKey, pSubKey, 0, "", REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hRegKey, &dw) != ERROR_SUCCESS ) + if( ::RegOpenKeyExA(hParentKey, pSubKey, 0, KEY_WRITE, &hRegKey) != ERROR_SUCCESS ) + return false; + + res = RegSetRAWValue(hRegKey, pValName, valToSave, valType); + + ::RegCloseKey(hRegKey); + return res; + } + //----------------------------------------------------------------------------------------------------------------------------------- + bool RegSetRAWValue(HKEY hParentKey, const char* pSubKey, const char* pValName, const std::string& valToSave, DWORD valType = REG_BINARY) + { + HKEY hRegKey = 0; + DWORD dw = 0; + bool res = false; + + if( ::RegCreateKeyExA(hParentKey, pSubKey, 0, "", REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hRegKey, &dw) != ERROR_SUCCESS ) + if( ::RegOpenKeyExA(hParentKey, pSubKey, 0, KEY_WRITE, &hRegKey) != ERROR_SUCCESS ) + return false; + + res = RegSetRAWValue(hRegKey, pValName, valToSave, valType); + + ::RegCloseKey(hRegKey); + return res; + } + //----------------------------------------------------------------------------------------------------------------------------------- + template + bool RegGetRAWValue(HKEY hParentKey, const char* pSubKey, const char* pValName, TMemoryObject& valToSave, DWORD* pRegType) + { + HKEY hRegKey = 0; + bool res = false; + + if(::RegOpenKeyExA(hParentKey, pSubKey, 0, KEY_READ, &hRegKey) == ERROR_SUCCESS ) + { + res = RegGetRAWValue(hRegKey, pValName, valToSave, pRegType); + ::RegCloseKey(hRegKey); + } + return res; + } + //----------------------------------------------------------------------------------------------------------------------------------- + inline + bool RegGetRAWValue(HKEY hParentKey, const char* pSubKey, const char* pValName, std::string& valToSave, DWORD* pRegType) + { + HKEY hRegKey = 0; + bool res = false; + + if(::RegOpenKeyExA(hParentKey, pSubKey, 0, KEY_READ, &hRegKey) == ERROR_SUCCESS ) + { + res = RegGetRAWValue(hRegKey, pValName, valToSave, pRegType); + ::RegCloseKey(hRegKey); + } + return res; + } + //----------------------------------------------------------------------------------------------------------------------------------- + inline + bool RegRemoveValue(HKEY hParentKey, const char* pValName) + { + //CHECK_AND_ASSERT(hParentKey&&pValName, false); + return ::RegDeleteValueA(hParentKey, pValName)==ERROR_SUCCESS ? true:false; + } + //----------------------------------------------------------------------------------------------------------------------------------- + inline + bool RegRemoveKey(HKEY hParentKey, const char* pKeyName) + { + //CHECK_AND_ASSERT(hParentKey&&pKeyName, false); + return ::RegDeleteKeyA(hParentKey, pKeyName)==ERROR_SUCCESS ? true:false; + } + +} +} +#endif //_MUSC_UTILS_EX_H_ diff --git a/contrib/epee/include/serialization/keyvalue_helpers.h b/contrib/epee/include/serialization/keyvalue_helpers.h new file mode 100644 index 00000000..924ab892 --- /dev/null +++ b/contrib/epee/include/serialization/keyvalue_helpers.h @@ -0,0 +1,70 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + +#pragma once +#include "misc_language.h" +namespace epee +{ + + template + struct enableable + { + t_obj v; + bool enabled; + + enableable() + : v(t_obj()), enabled(true) + { // construct from defaults + } + + enableable(const t_obj& _v) + : v(_v), enabled(true) + { // construct from specified values + } + + enableable(const enableable& _v) + : v(_v.v), enabled(_v.enabled) + { // construct from specified values + } + }; + + //basic helpers for pod-to-hex serialization + template + std::string transform_t_pod_to_str(const t_pod_type & a) + { + return epee::string_tools::pod_to_hex(a); + } + template + t_pod_type transform_str_to_t_pod(const std::string& a) + { + t_pod_type res = AUTO_VAL_INIT(res); + epee::string_tools::hex_to_pod(a, res); + return res; + } + //------------------------------------------------------------------------------------------------------------------- + + +} \ No newline at end of file diff --git a/contrib/epee/include/serialization/keyvalue_serialization.h b/contrib/epee/include/serialization/keyvalue_serialization.h new file mode 100644 index 00000000..a73c6b87 --- /dev/null +++ b/contrib/epee/include/serialization/keyvalue_serialization.h @@ -0,0 +1,116 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + +#pragma once + +#include +#include +#include "misc_log_ex.h" +#include "keyvalue_helpers.h" +#include "keyvalue_serialization_overloads.h" +namespace epee +{ + /************************************************************************/ + /* Serialize map declarations */ + /************************************************************************/ +#define BEGIN_KV_SERIALIZE_MAP() \ +public: \ + template \ + bool store(t_storage& st, typename t_storage::hsection hparent_section = nullptr) const\ + {\ + return serialize_map(*this, st, hparent_section); \ +}\ + template \ + bool _load(t_storage& stg, typename t_storage::hsection hparent_section = nullptr)\ + {\ + return serialize_map(*this, stg, hparent_section); \ +}\ + template \ + bool load(t_storage& stg, typename t_storage::hsection hparent_section = nullptr)\ + {\ + try{\ + return serialize_map(*this, stg, hparent_section); \ +}\ + catch (const std::exception& err) \ + { \ + (void)(err); \ + LOG_ERROR("Exception on unserializing: " << err.what()); \ + return false; \ + }\ +}\ + template \ + static bool serialize_map(this_type& this_ref, t_storage& stg, typename t_storage::hsection hparent_section) \ +{ + +#define KV_SERIALIZE_N(varialble, val_name) \ + epee::serialization::selector::serialize(this_ref.varialble, stg, hparent_section, val_name); + +#define KV_SERIALIZE_CUSTOM_N(varialble, stored_type, from_v_to_stored, from_stored_to_v, val_name) \ + epee::serialization::selector::template serialize_custom(this_ref.varialble, stg, hparent_section, val_name, from_v_to_stored, from_stored_to_v); + +#define KV_SERIALIZE_EPHEMERAL_N(stored_type, from_v_to_stored, val_name) \ + epee::serialization::selector::template serialize_ephemeral(this_ref, stg, hparent_section, val_name, from_v_to_stored); + + +#define KV_SERIALIZE_POD_AS_HEX_STRING_N(varialble, val_name) \ + KV_SERIALIZE_CUSTOM_N(varialble, std::string, epee::transform_t_pod_to_str, epee::transform_str_to_t_pod, val_name) + + + + +#define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, val_name) \ + epee::serialization::selector::serialize_t_val_as_blob(this_ref.varialble, stg, hparent_section, val_name); + +#define KV_SERIALIZE_VAL_POD_AS_BLOB_N(varialble, val_name) \ + static_assert(std::is_pod::value, "t_type must be a POD type."); \ + KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, val_name) + +#define KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(varialble, val_name) \ + epee::serialization::selector::serialize_stl_container_pod_val_as_blob(this_ref.varialble, stg, hparent_section, val_name); + +#define END_KV_SERIALIZE_MAP() return true;} + +#define KV_SERIALIZE(varialble) KV_SERIALIZE_N(varialble, #varialble) +#define KV_SERIALIZE_VAL_POD_AS_BLOB(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_N(varialble, #varialble) +#define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, #varialble) //skip is_pod compile time check +#define KV_SERIALIZE_CONTAINER_POD_AS_BLOB(varialble) KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(varialble, #varialble) +#define KV_SERIALIZE_CUSTOM(varialble, stored_type, from_v_to_stored, from_stored_to_v) KV_SERIALIZE_CUSTOM_N(varialble, stored_type, from_v_to_stored, from_stored_to_v, #varialble) +#define KV_SERIALIZE_POD_AS_HEX_STRING(varialble) KV_SERIALIZE_POD_AS_HEX_STRING_N(varialble, #varialble) + + +#define KV_CHAIN_MAP(variable_obj) epee::namespace_accessor::template serialize_map(this_ref.variable_obj, stg, hparent_section); +#define KV_CHAIN_BASE(base_type) base_type::serialize_map(static_cast(const_cast::type&>(this_ref)), stg, hparent_section); + + + + + + +} + + + + diff --git a/contrib/epee/include/serialization/keyvalue_serialization_boost_variant.h b/contrib/epee/include/serialization/keyvalue_serialization_boost_variant.h new file mode 100644 index 00000000..ecb44ddd --- /dev/null +++ b/contrib/epee/include/serialization/keyvalue_serialization_boost_variant.h @@ -0,0 +1,67 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + +#pragma once + +#include + +namespace epee +{ + namespace serialization + { + + template + struct serialize_variant_visitor : public boost::static_visitor + { + serialize_variant_visitor(t_storage& rstg, typename t_storage::hsection hsection, const char* pn) + :stg(rstg), hparent_section(hsection), pname(pn) + {} + t_storage& stg; + typename t_storage::hsection hparent_section; + const char* pname; + + template + bool operator()(const t_type& v) const + { + return kv_serialization_overloads_impl_is_base_serializable_types, typename std::remove_const::type>::value>::kv_serialize(v, stg, hparent_section, pname); + } + }; + + template + bool kv_serialize(const boost::variant& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + serialize_variant_visitor sv(stg, hparent_section, pname); + return boost::apply_visitor(sv, d); + } + //------------------------------------------------------------------------------------------------------------------- + template + bool kv_unserialize(boost::variant &d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + LOG_ERROR("kv_unserialize on boost::variant call not allowed"); + return false; + } + } +} diff --git a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h new file mode 100644 index 00000000..073fd441 --- /dev/null +++ b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h @@ -0,0 +1,430 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + +#pragma once + +#include + +namespace epee +{ + namespace serialization + { + template + static bool serialize_t_val(const t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return stg.set_value(pname, d, hparent_section); + } + //------------------------------------------------------------------------------------------------------------------- + template + static bool unserialize_t_val(t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return stg.get_value(pname, d, hparent_section); + } + //------------------------------------------------------------------------------------------------------------------- + template + static bool serialize_t_val_as_blob(const t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + std::string blob((const char *)&d, sizeof(d)); + return stg.set_value(pname, blob, hparent_section); + } + //------------------------------------------------------------------------------------------------------------------- + template + static bool unserialize_t_val_as_blob(t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + std::string blob; + if(!stg.get_value(pname, blob, hparent_section)) + return false; + CHECK_AND_ASSERT_MES(blob.size() == sizeof(d), false, "unserialize_t_val_as_blob: size of " << typeid(t_type).name() << " = " << sizeof(t_type) << ", but stored blod size = " << blob.size() << ", value name = " << pname); + d = *(const t_type*)blob.data(); + return true; + } + //------------------------------------------------------------------------------------------------------------------- + template + static bool serialize_t_obj(const serializible_type& obj, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + typename t_storage::hsection hchild_section = stg.open_section(pname, hparent_section, true); + CHECK_AND_ASSERT_MES(hchild_section, false, "serialize_t_obj: failed to open/create section " << pname); + return obj.store(stg, hchild_section); + } + //------------------------------------------------------------------------------------------------------------------- + template + static bool unserialize_t_obj(serializible_type& obj, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + typename t_storage::hsection hchild_section = stg.open_section(pname, hparent_section, true); + if(!hchild_section) return false; + return obj._load(stg, hchild_section); + } + //------------------------------------------------------------------------------------------------------------------- + template + static bool serialize_t_obj(enableable& obj, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + if(!obj.enabled) + return true; + return serialize_t_obj(obj.v, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template + static bool unserialize_t_obj(enableable& obj, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + obj.enabled = false; + typename t_storage::hsection hchild_section = stg.open_section(pname, hparent_section, true); + if(!hchild_section) return false; + obj.enabled = true; + return obj.v._load(stg, hchild_section); + } + //------------------------------------------------------------------------------------------------------------------- + template + static bool serialize_stl_container_t_val (const stl_container& container, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + if(!container.size()) return true; + typename stl_container::const_iterator it = container.begin(); + typename t_storage::harray hval_array = stg.insert_first_value(pname, *it, hparent_section); + CHECK_AND_ASSERT_MES(hval_array, false, "failed to insert first value to storage"); + it++; + for(;it!= container.end();it++) + stg.insert_next_value(hval_array, *it); + + return true; + } + //-------------------------------------------------------------------------------------------------------------------- + template + static bool unserialize_stl_container_t_val(stl_container& container, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + container.clear(); + typename stl_container::value_type exchange_val; + typename t_storage::harray hval_array = stg.get_first_value(pname, exchange_val, hparent_section); + if(!hval_array) return false; + container.push_back(std::move(exchange_val)); + while(stg.get_next_value(hval_array, exchange_val)) + container.push_back(std::move(exchange_val)); + return true; + }//-------------------------------------------------------------------------------------------------------------------- + template + static bool serialize_stl_container_pod_val_as_blob(const stl_container& container, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + if(!container.size()) return true; + std::string mb; + mb.resize(sizeof(typename stl_container::value_type)*container.size()); + typename stl_container::value_type* p_elem = (typename stl_container::value_type*)mb.data(); + BOOST_FOREACH(const typename stl_container::value_type& v, container) + { + *p_elem = v; + p_elem++; + } + return stg.set_value(pname, mb, hparent_section); + } + //-------------------------------------------------------------------------------------------------------------------- + template + static bool unserialize_stl_container_pod_val_as_blob(stl_container& container, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + container.clear(); + std::string buff; + bool res = stg.get_value(pname, buff, hparent_section); + if(res) + { + size_t loaded_size = buff.size(); + typename stl_container::value_type* pelem = (typename stl_container::value_type*)buff.data(); + CHECK_AND_ASSERT_MES(!(loaded_size%sizeof(typename stl_container::value_type)), + false, + "size in blob " << loaded_size << " not have not zero modulo for sizeof(value_type) = " << sizeof(typename stl_container::value_type)); + size_t count = (loaded_size/sizeof(typename stl_container::value_type)); + for(size_t i = 0; i < count; i++) + container.push_back(*(pelem++)); + } + return res; + } + //-------------------------------------------------------------------------------------------------------------------- + template + static bool serialize_stl_container_t_obj (const stl_container& container, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + bool res = false; + if(!container.size()) return true; + typename stl_container::const_iterator it = container.begin(); + typename t_storage::hsection hchild_section = nullptr; + typename t_storage::harray hsec_array = stg.insert_first_section(pname, hchild_section, hparent_section); + CHECK_AND_ASSERT_MES(hsec_array && hchild_section, false, "failed to insert first section with section name " << pname); + res = it->store(stg, hchild_section); + it++; + for(;it!= container.end();it++) + { + stg.insert_next_section(hsec_array, hchild_section); + res |= it->store(stg, hchild_section); + } + return res; + } + //-------------------------------------------------------------------------------------------------------------------- + template + static bool unserialize_stl_container_t_obj(stl_container& container, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + bool res = false; + container.clear(); + typename stl_container::value_type val = typename stl_container::value_type(); + typename t_storage::hsection hchild_section = nullptr; + typename t_storage::harray hsec_array = stg.get_first_section(pname, hchild_section, hparent_section); + if(!hsec_array || !hchild_section) return false; + res = val._load(stg, hchild_section); + container.push_back(val); + while(stg.get_next_section(hsec_array, hchild_section)) + { + typename stl_container::value_type val_l = typename stl_container::value_type(); + res |= val_l._load(stg, hchild_section); + container.push_back(std::move(val_l)); + } + return res; + } + //-------------------------------------------------------------------------------------------------------------------- + template + struct kv_serialization_overloads_impl_is_base_serializable_types; + + template<> + struct kv_serialization_overloads_impl_is_base_serializable_types + { + template + static bool kv_serialize(const t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return stg.set_value(pname, d, hparent_section); + } + //------------------------------------------------------------------------------------------------------------------- + template + static bool kv_unserialize(t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return stg.get_value(pname, d, hparent_section); + } + //------------------------------------------------------------------------------------------------------------------- + template + static bool kv_serialize(const std::vector& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return serialize_stl_container_t_val(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template + static bool kv_unserialize(std::vector& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return unserialize_stl_container_t_val(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template + static bool kv_serialize(const std::list& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return serialize_stl_container_t_val(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template + static bool kv_unserialize(std::list& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return unserialize_stl_container_t_val(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template + static bool kv_serialize(const std::deque& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return serialize_stl_container_t_val(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template + static bool kv_unserialize(std::deque& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return unserialize_stl_container_t_val(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + }; + template<> + struct kv_serialization_overloads_impl_is_base_serializable_types + { + template + static bool kv_serialize(const t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return serialize_t_obj(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template + static bool kv_unserialize(t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return unserialize_t_obj(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template + static bool kv_serialize(const std::vector& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return serialize_stl_container_t_obj(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template + static bool kv_unserialize(std::vector& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return unserialize_stl_container_t_obj(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template + static bool kv_serialize(const std::list& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return serialize_stl_container_t_obj(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template + static bool kv_unserialize(std::list& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return unserialize_stl_container_t_obj(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template + static bool kv_serialize(const std::deque& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return serialize_stl_container_t_obj(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template + static bool kv_unserialize(std::deque& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return unserialize_stl_container_t_obj(d, stg, hparent_section, pname); + } + }; + template + struct base_serializable_types: public boost::mpl::vector::type + {}; + //------------------------------------------------------------------------------------------------------------------- + template struct selector; + template<> + struct selector + { + template + static bool serialize(const t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return kv_serialize(d, stg, hparent_section, pname); + } + + template + static bool serialize_stl_container_pod_val_as_blob(const t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return epee::serialization::serialize_stl_container_pod_val_as_blob(d, stg, hparent_section, pname); + } + + template + static bool serialize_t_val_as_blob(const t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return epee::serialization::serialize_t_val_as_blob(d, stg, hparent_section, pname); + } + template< class t_type_stored, class t_type, class t_storage, typename cb_serialize, typename cb_unserialize> + static bool serialize_custom(const t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname, cb_serialize cb_s, cb_unserialize cb_us) + { + t_type_stored a = cb_s(d); + return epee::serialization::selector::serialize(a, stg, hparent_section, pname); + } + template< class t_type_stored, class t_type, class t_storage, typename cb_serialize> + static bool serialize_ephemeral(const t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname, cb_serialize cb_s) + { + t_type_stored a = cb_s(d); + return epee::serialization::selector::serialize(a, stg, hparent_section, pname); + } + + }; + template<> + struct selector + { + template + static bool serialize(t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return kv_unserialize(d, stg, hparent_section, pname); + } + template + static bool serialize_stl_container_pod_val_as_blob(t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return epee::serialization::unserialize_stl_container_pod_val_as_blob(d, stg, hparent_section, pname); + } + + template + static bool serialize_t_val_as_blob(t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return epee::serialization::unserialize_t_val_as_blob(d, stg, hparent_section, pname); + } + template< class t_type_stored, class t_type, class t_storage, typename cb_serialize, typename cb_unserialize> + static bool serialize_custom(t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname, cb_serialize cb_s, cb_unserialize cb_us) + { + t_type_stored a; + bool r = epee::serialization::selector::serialize(a, stg, hparent_section, pname); + if (!r) + return r; + d = cb_us(a); + return r; + } + + template< class t_type_stored, class t_type, class t_storage, typename cb_serialize> + static bool serialize_ephemeral(t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname, cb_serialize cb_s) + { + //just a stub here + return true; + } + }; + + template + bool kv_serialize(const t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return kv_serialization_overloads_impl_is_base_serializable_types, typename std::remove_const::type>::value>::kv_serialize(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template + bool kv_unserialize(t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return kv_serialization_overloads_impl_is_base_serializable_types, typename std::remove_const::type>::value>::kv_unserialize(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template + bool kv_serialize(const std::vector& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return kv_serialization_overloads_impl_is_base_serializable_types, typename std::remove_const::type>::value>::kv_serialize(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template + bool kv_unserialize(std::vector& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return kv_serialization_overloads_impl_is_base_serializable_types, typename std::remove_const::type>::value>::kv_unserialize(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template + bool kv_serialize(const std::list& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return kv_serialization_overloads_impl_is_base_serializable_types, typename std::remove_const::type>::value>::kv_serialize(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template + bool kv_unserialize(std::list& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return kv_serialization_overloads_impl_is_base_serializable_types, typename std::remove_const::type>::value>::kv_unserialize(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template + bool kv_serialize(const std::deque& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return kv_serialization_overloads_impl_is_base_serializable_types, typename std::remove_const::type>::value>::kv_serialize(d, stg, hparent_section, pname); + } + //------------------------------------------------------------------------------------------------------------------- + template + bool kv_unserialize(std::deque& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + return kv_serialization_overloads_impl_is_base_serializable_types, typename std::remove_const::type>::value>::kv_unserialize(d, stg, hparent_section, pname); + } + } +} \ No newline at end of file diff --git a/contrib/epee/include/serialization/serialize_base.h b/contrib/epee/include/serialization/serialize_base.h new file mode 100644 index 00000000..84a1624c --- /dev/null +++ b/contrib/epee/include/serialization/serialize_base.h @@ -0,0 +1,2 @@ +#pragma once + diff --git a/contrib/epee/include/service_impl_base.h b/contrib/epee/include/service_impl_base.h new file mode 100644 index 00000000..6e9aefc4 --- /dev/null +++ b/contrib/epee/include/service_impl_base.h @@ -0,0 +1,323 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + +#ifndef _SERVICE_IMPL_BASE_H_ +#define _SERVICE_IMPL_BASE_H_ + +#pragma comment(lib, "advapi32.lib") + + +namespace epee +{ +class service_impl_base { + public: + service_impl_base(); + virtual ~service_impl_base(); + + virtual const char *get_name() = 0; + virtual const char *get_caption() = 0; + virtual const char *get_description() = 0; + + bool run_service(); + virtual bool install(); + virtual bool remove(); + virtual bool init(); + void set_control_accepted(unsigned controls); + void set_status(unsigned state, unsigned pending = 0); + unsigned get_control_accepted(); + + private: + virtual void service_main() = 0; + virtual unsigned service_handler(unsigned control, unsigned event_code, + void *pdata) = 0; + //------------------------------------------------------------------------- + static service_impl_base*& instance(); + //------------------------------------------------------------------------- + static DWORD __stdcall _service_handler(DWORD control, DWORD event, + void *pdata, void *pcontext); + static void __stdcall service_entry(DWORD argc, char **pargs); + virtual SERVICE_FAILURE_ACTIONSA* get_failure_actions(); + + private: + SC_HANDLE m_manager; + SC_HANDLE m_service; + SERVICE_STATUS_HANDLE m_status_handle; + DWORD m_accepted_control; +}; + +inline service_impl_base::service_impl_base() { + m_manager = 0; + m_service = 0; + m_status_handle = 0; + m_accepted_control = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN + | SERVICE_ACCEPT_PAUSE_CONTINUE; + + instance() = this; +} +//----------------------------------------------------------------------------- +inline service_impl_base::~service_impl_base() { + if (m_service) { + ::CloseServiceHandle(m_service); + } + m_service = 0; + if (m_manager) { + ::CloseServiceHandle(m_manager); + } + m_manager = 0; + instance() = 0; +} +//----------------------------------------------------------------------------- +inline service_impl_base*& service_impl_base::instance() { + static service_impl_base *pservice = NULL; + return pservice; +} +//----------------------------------------------------------------------------- +inline +bool service_impl_base::install() { + CHECK_AND_ASSERT(!m_service, false); + const char *psz_descr = get_description(); + SERVICE_FAILURE_ACTIONSA* fail_acts = get_failure_actions(); + + char sz_path[MAX_PATH]; + ::GetModuleFileNameA(0, sz_path, sizeof(sz_path)); + ::GetShortPathNameA(sz_path, sz_path, sizeof(sz_path)); + + while (TRUE) { + if (!m_manager) { + m_manager = ::OpenSCManager(NULL, NULL, GENERIC_ALL); + if (!m_manager) { + int err = GetLastError(); + LOG_ERROR( + "Failed to OpenSCManager(), last err=" + << log_space::get_win32_err_descr(err)); + break; + } + } + m_service = ::CreateServiceA(m_manager, get_name(), get_caption(), + SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, + SERVICE_ERROR_IGNORE, sz_path, 0, 0, 0, 0, 0); + if (!m_service) { + int err = GetLastError(); + LOG_ERROR( + "Failed to CreateService(), last err=" + << log_space::get_win32_err_descr(err)); + break; + } + + if (psz_descr) { + SERVICE_DESCRIPTIONA sd = { (char*) psz_descr }; + if (!::ChangeServiceConfig2A(m_service, SERVICE_CONFIG_DESCRIPTION, + &sd)) { + int err = GetLastError(); + LOG_ERROR( + "Failed to ChangeServiceConfig2(SERVICE_CONFIG_DESCRIPTION), last err=" + << log_space::get_win32_err_descr(err)); + break; + } + } + + if (fail_acts) { + if (!::ChangeServiceConfig2A(m_service, SERVICE_CONFIG_FAILURE_ACTIONS, + fail_acts)) { + int err = GetLastError(); + LOG_ERROR( + "Failed to ChangeServiceConfig2(SERVICE_CONFIG_FAILURE_ACTIONS), last err=" + << log_space::get_win32_err_descr(err)); + break; + } + } + LOG_PRINT("Installed succesfully.", LOG_LEVEL_0); + return true; + } + LOG_PRINT("Failed to install.", LOG_LEVEL_0); + return false; +} +//----------------------------------------------------------------------------- +inline +bool service_impl_base::remove() { + CHECK_AND_ASSERT(!m_service, false); + + while (TRUE) { + if (!m_manager) { + m_manager = ::OpenSCManager(0, 0, GENERIC_ALL); + if (!m_manager) { + int err = GetLastError(); + LOG_ERROR( + "Failed to OpenSCManager(), last err=" + << log_space::get_win32_err_descr(err)); + break; + } + } + + if (!m_service) { + m_service = ::OpenServiceA(m_manager, get_name(), SERVICE_STOP | DELETE); + if (!m_service) { + int err = GetLastError(); + LOG_ERROR( + "Failed to OpenService(), last err=" + << log_space::get_win32_err_descr(err)); + break; + } + } + + SERVICE_STATUS status = { }; + if (!::ControlService(m_service, SERVICE_CONTROL_STOP, &status)) { + int err = ::GetLastError(); + if (err == ERROR_SHUTDOWN_IN_PROGRESS) + continue; + else if (err != ERROR_SERVICE_NOT_ACTIVE) { + LOG_ERROR( + "Failed to ControlService(SERVICE_CONTROL_STOP), last err=" + << log_space::get_win32_err_descr(err)); + break; + } + } + + if (!::DeleteService(m_service)) { + int err = ::GetLastError(); + LOG_ERROR( + "Failed to ControlService(SERVICE_CONTROL_STOP), last err=" + << log_space::get_win32_err_descr(err)); + break; + } + + LOG_PRINT("Removed successfully.", LOG_LEVEL_0); + break; + } + + return true; +} +//----------------------------------------------------------------------------- +inline +bool service_impl_base::init() { + return true; +} +//----------------------------------------------------------------------------- +inline +bool service_impl_base::run_service() { + CHECK_AND_ASSERT(!m_service, false); + + long error_code = 0; + + SERVICE_TABLE_ENTRYA service_table[2]; + ZeroMemory(&service_table, sizeof(service_table)); + + service_table->lpServiceName = (char*) get_name(); + service_table->lpServiceProc = service_entry; + + LOG_PRINT("[+] Start service control dispatcher for \"" << get_name() << "\"", + LOG_LEVEL_1); + + error_code = 1; + BOOL res = ::StartServiceCtrlDispatcherA(service_table); + if (!res) { + int err = GetLastError(); + LOG_PRINT( + "[+] Error starting service control dispatcher, err=" + << log_space::get_win32_err_descr(err), LOG_LEVEL_1); + return false; + } else { + LOG_PRINT("[+] End service control dispatcher for \"" << get_name() << "\"", + LOG_LEVEL_1); + } + return true; +} +//----------------------------------------------------------------------------- +inline DWORD __stdcall service_impl_base::_service_handler(DWORD control, + DWORD event, void *pdata, void *pcontext) { + CHECK_AND_ASSERT(pcontext, ERROR_CALL_NOT_IMPLEMENTED); + + service_impl_base *pservice = (service_impl_base*) pcontext; + return pservice->service_handler(control, event, pdata); +} +//----------------------------------------------------------------------------- +inline +void __stdcall service_impl_base::service_entry(DWORD argc, char **pargs) { + service_impl_base *pme = instance(); + LOG_PRINT("instance: " << pme, LOG_LEVEL_4); + if (!pme) { + LOG_ERROR("Error: at service_entry() pme = NULL"); + return; + } + pme->m_status_handle = ::RegisterServiceCtrlHandlerExA(pme->get_name(), + _service_handler, pme); + + pme->set_status(SERVICE_RUNNING); + pme->service_main(); + pme->set_status(SERVICE_STOPPED); +} +//----------------------------------------------------------------------------- +inline +void service_impl_base::set_status(unsigned state, unsigned pending) { + if (!m_status_handle) + return; + + SERVICE_STATUS status = { 0 }; + status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + status.dwCurrentState = state; + status.dwControlsAccepted = m_accepted_control; + /*status.dwWin32ExitCode = NO_ERROR; + status.dwServiceSpecificExitCode = ERROR_SERVICE_SPECIFIC_ERROR; + status.dwCheckPoint = 0; + status.dwWaitHint = 0; + + status.dwCurrentState = state;*/ + + if (state == SERVICE_START_PENDING || state == SERVICE_STOP_PENDING + || state == SERVICE_CONTINUE_PENDING || state == SERVICE_PAUSE_PENDING) { + status.dwWaitHint = 2000; + status.dwCheckPoint = pending; + } + ::SetServiceStatus(m_status_handle, &status); +} +//----------------------------------------------------------------------------------------- +inline +void service_impl_base::set_control_accepted(unsigned controls) { + m_accepted_control = controls; +} +//----------------------------------------------------------------------------------------- +inline +unsigned service_impl_base::get_control_accepted() { + return m_accepted_control; +} +//----------------------------------------------------------------------------------------- +inline SERVICE_FAILURE_ACTIONSA* service_impl_base::get_failure_actions() { + // first 3 failures in 30 minutes. Service will be restarted. + // do nothing for next failures + static SC_ACTION sa[] = { { SC_ACTION_RESTART, 3 * 1000 }, { + SC_ACTION_RESTART, 3 * 1000 }, { SC_ACTION_RESTART, 3 * 1000 }, { + SC_ACTION_NONE, 0 } }; + + static SERVICE_FAILURE_ACTIONSA sfa = { 1800, // interval for failures counter - 30 min + "", NULL, 4, (SC_ACTION*) &sa }; + + // TODO: refactor this code, really unsafe! + return &sfa; +} +} + +#endif //_SERVICE_IMPL_BASE_H_ diff --git a/contrib/epee/include/sha1.h b/contrib/epee/include/sha1.h new file mode 100644 index 00000000..ce42082f --- /dev/null +++ b/contrib/epee/include/sha1.h @@ -0,0 +1,51 @@ + +/* + Copyright (c) 2011, Micael Hildenborg + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * 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. + * Neither the name of Micael Hildenborg 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 Micael Hildenborg ''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 Micael Hildenborg 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. + */ + +#ifndef SHA1_DEFINED +#define SHA1_DEFINED + +namespace sha1 { + + /** + @param src points to any kind of data to be hashed. + @param bytelength the number of bytes to hash from the src pointer. + @param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in. + */ + void calc(const void* src, const int bytelength, unsigned char* hash); + + /** + @param hash is 20 bytes of sha1 hash. This is the same data that is the result from the calc function. + @param hexstring should point to a buffer of at least 41 bytes of size for storing the hexadecimal representation of the hash. A zero will be written at position 40, so the buffer will be a valid zero ended string. + */ + void toHexString(const unsigned char* hash, char* hexstring); + +} // namespace sha1 + +#include "sha1.inl" + +#endif // SHA1_DEFINED diff --git a/contrib/epee/include/sha1.inl b/contrib/epee/include/sha1.inl new file mode 100644 index 00000000..d3320272 --- /dev/null +++ b/contrib/epee/include/sha1.inl @@ -0,0 +1,179 @@ + +/* + Copyright (c) 2011, Micael Hildenborg + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * 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. + * Neither the name of Micael Hildenborg 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 Micael Hildenborg ''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 Micael Hildenborg 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. + */ + +/* + Contributors: + Gustav + Several members in the gamedev.se forum. + Gregory Petrosyan + */ + +#include "sha1.h" + +namespace sha1 { +namespace {// local +// Rotate an integer value to left. +inline const unsigned int rol(const unsigned int value, + const unsigned int steps) { + return ((value << steps) | (value >> (32 - steps))); +} + +// Sets the first 16 integers in the buffert to zero. +// Used for clearing the W buffert. +inline void clearWBuffert(unsigned int* buffert) { + for (int pos = 16; --pos >= 0;) + { + buffert[pos] = 0; + } +} + +inline +void innerHash(unsigned int* result, unsigned int* w) { + unsigned int a = result[0]; + unsigned int b = result[1]; + unsigned int c = result[2]; + unsigned int d = result[3]; + unsigned int e = result[4]; + + int round = 0; + +#define sha1macro(func,val) \ + { \ + const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \ + e = d; \ + d = c; \ + c = rol(b, 30); \ + b = a; \ + a = t; \ + } + + while (round < 16) { + sha1macro((b & c) | (~b & d), 0x5a827999) + ++round; + } + while (round < 20) { + w[round] = rol( + (w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro((b & c) | (~b & d), 0x5a827999) + ++round; + } + while (round < 40) { + w[round] = rol( + (w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro(b ^ c ^ d, 0x6ed9eba1) + ++round; + } + while (round < 60) { + w[round] = rol( + (w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc) + ++round; + } + while (round < 80) { + w[round] = rol( + (w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro(b ^ c ^ d, 0xca62c1d6) + ++round; + } + +#undef sha1macro + + result[0] += a; + result[1] += b; + result[2] += c; + result[3] += d; + result[4] += e; +} +} // namespace + +inline +void calc(const void* src, const int bytelength, unsigned char* hash) { + // Init the result array. + unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, + 0xc3d2e1f0 }; + + // Cast the void src pointer to be the byte array we can work with. + const unsigned char* sarray = (const unsigned char*) src; + + // The reusable round buffer + unsigned int w[80]; + + // Loop through all complete 64byte blocks. + const int endOfFullBlocks = bytelength - 64; + int endCurrentBlock; + int currentBlock(0); + + while (currentBlock <= endOfFullBlocks) { + endCurrentBlock = currentBlock + 64; + + // Init the round buffer with the 64 byte block data. + for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4) + { + // This line will swap endian on big endian and keep endian on little endian. + w[roundPos++] = (unsigned int) sarray[currentBlock + 3] + | (((unsigned int) sarray[currentBlock + 2]) << 8) + | (((unsigned int) sarray[currentBlock + 1]) << 16) + | (((unsigned int) sarray[currentBlock]) << 24); + } + innerHash(result, w); + } + + // Handle the last and not full 64 byte block if existing. + endCurrentBlock = bytelength - currentBlock; + clearWBuffert(w); + int lastBlockBytes = 0; + for (; lastBlockBytes < endCurrentBlock; ++lastBlockBytes) { + w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3); + } + w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3); + if (endCurrentBlock >= 56) { + innerHash(result, w); + clearWBuffert(w); + } + w[15] = bytelength << 3; + innerHash(result, w); + + // Store hash in result pointer, and make sure we get in in the correct order on both endian models. + for (int hashByte = 20; --hashByte >= 0;) { + hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) + & 0xff; + } +} +inline +void toHexString(const unsigned char* hash, char* hexstring) { + const char hexDigits[] = { "0123456789abcdef" }; + + for (int hashByte = 20; --hashByte >= 0;) + { + hexstring[hashByte << 1] = hexDigits[(hash[hashByte] >> 4) & 0xf]; + hexstring[(hashByte << 1) + 1] = hexDigits[hash[hashByte] & 0xf]; + } + hexstring[40] = 0; +} +} // namespace sha1 diff --git a/contrib/epee/include/singleton.h b/contrib/epee/include/singleton.h new file mode 100644 index 00000000..f510c9a6 --- /dev/null +++ b/contrib/epee/include/singleton.h @@ -0,0 +1,84 @@ + +// Copyright (c) 2006-2018, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + + +#pragma once + +#include + + +template +class abstract_singleton +{ + + static std::shared_ptr get_set_instance_internal(bool is_need_set = false, owned_object_t* pnew_obj = nullptr) + { + static std::shared_ptr val_pobj; + + if (is_need_set) + val_pobj.reset(pnew_obj); + + return val_pobj; + } + + static bool get_is_deinitialized(bool need_to_set = false, bool val_to_set = false) + { + static bool is_deintialized = false; + if (need_to_set) + is_deintialized = val_to_set; + return is_deintialized; + } + + +public: + inline static bool init() + { + //better to call before multiple threads start to call it + get_instance(); + return true;/*do nothing here*/ + } + inline static bool un_init() + { + get_is_deinitialized(true, true); + get_set_instance_internal(true, nullptr); + return true; + } + + static std::shared_ptr get_instance() + { + std::shared_ptr val_pobj = get_set_instance_internal(); + if (!val_pobj.get() && !get_is_deinitialized()) + { + owned_object_t*pnewobj = new owned_object_t(); + get_set_instance_internal(true, pnewobj); + val_pobj = get_set_instance_internal(); + } + return val_pobj; + } +}; \ No newline at end of file diff --git a/contrib/epee/include/soci_helper.h b/contrib/epee/include/soci_helper.h new file mode 100644 index 00000000..813edc1f --- /dev/null +++ b/contrib/epee/include/soci_helper.h @@ -0,0 +1,142 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + +#pragma once +#include "soci.h" +#include "soci-postgresql.h" + +using namespace epee; +namespace soci +{ + + template <> + struct type_conversion + { + typedef long long base_type; + + static void from_base(base_type a_, indicator ind, uint64_t & mi) + { + if (ind == i_null) + { + mi = 0; + //throw soci_error("Null value not allowed for this type"); + } + mi = (uint64_t)a_; + //mi.set(i); + } + + static void to_base(const uint64_t & mi, base_type & i, indicator & ind) + { + i = (base_type)mi; + ind = i_ok; + } + }; + + + + template <> + struct type_conversion + { + typedef int base_type; + + static void from_base(base_type a_, indicator ind, bool& mi) + { + if (ind == i_null) + { + mi = false; + //throw soci_error("Null value not allowed for this type"); + } + mi = a_? true:false; + //mi.set(i); + } + + static void to_base(const bool & mi, base_type & i, indicator & ind) + { + i = mi? 1:0; + ind = i_ok; + } + }; + + + + class per_thread_session + { + public: + bool init(const std::string& connection_string) + { + m_connection_string = connection_string; + + return true; + } + + soci::session& get() + { + + //soci::session + + m_db_connections_lock.lock(); + boost::shared_ptr& conn_ptr = m_db_connections[epee::misc_utils::get_thread_string_id()]; + m_db_connections_lock.unlock(); + if(!conn_ptr.get()) + { + conn_ptr.reset(new soci::session(soci::postgresql, m_connection_string)); + } + //init new connection + return *conn_ptr.get(); + } + + bool reopen() + { + //soci::session + + m_db_connections_lock.lock(); + boost::shared_ptr& conn_ptr = m_db_connections[misc_utils::get_thread_string_id()]; + m_db_connections_lock.unlock(); + if(conn_ptr.get()) + { + conn_ptr->close(); + conn_ptr.reset(new soci::session(soci::postgresql, m_connection_string)); + } + + //init new connection + return true; + } + + //---------------------------------------------------------------------------------------------- + bool check_status() + { + return true; + } + + protected: + private: + std::map > m_db_connections; + epee::critical_section m_db_connections_lock; + std::string m_connection_string; + }; +} +/*}*/ \ No newline at end of file diff --git a/contrib/epee/include/static_initializer.h b/contrib/epee/include/static_initializer.h new file mode 100644 index 00000000..43ccff60 --- /dev/null +++ b/contrib/epee/include/static_initializer.h @@ -0,0 +1,84 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#ifndef _STATIC_INITIALIZER_H_ +#define _STATIC_INITIALIZER_H_ + + +namespace epee +{ +/*********************************************************************** +class initializer - useful to initialize some static classes + which have init() and un_init() static members +************************************************************************/ + + + +template +class initializer +{ +public: + initializer() + { + to_initialize::init(); + //get_set_is_initialized(true, true); + } + ~initializer() + { + to_initialize::un_init(); + //get_set_is_uninitialized(true, true); + } + + /*static inline bool is_initialized() + { + return get_set_is_initialized(); + } + static inline bool is_uninitialized() + { + return get_set_is_uninitialized(); + } + +private: + static inline bool get_set_is_initialized(bool need_to_set = false, bool val_to_set= false) + { + static bool val_is_initialized = false; + if(need_to_set) + val_is_initialized = val_to_set; + return val_is_initialized; + } + static inline bool get_set_is_uninitialized(bool need_to_set = false, bool val_to_set = false) + { + static bool val_is_uninitialized = false; + if(need_to_set) + val_is_uninitialized = val_to_set; + return val_is_uninitialized; + }*/ +}; + +} +#endif //_STATIC_INITIALIZER_H_ diff --git a/contrib/epee/include/storages/activity_notifier.h b/contrib/epee/include/storages/activity_notifier.h new file mode 100644 index 00000000..14b6ebbf --- /dev/null +++ b/contrib/epee/include/storages/activity_notifier.h @@ -0,0 +1,132 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#pragma once + +#include "inmemtoxml.h" + +//#include "levin/levin_server.h" + +namespace epee +{ + +class activity_printer_base +{ +public: + activity_printer_base(){} + virtual ~activity_printer_base(){} +}; + +template +class notify_activity_printer: public activity_printer_base +{ +public: + notify_activity_printer(int level, A& arg, bool is_notify_mode = true):m_ref_arg(arg), m_level(level), m_is_notify_mode(is_notify_mode) + { + m_command_name = typeid(m_ref_arg).name(); + m_command_name.erase(0, 7); + m_command_name.erase(m_command_name.size()-10, m_command_name.size()-1); + if(level == log_space::get_set_log_detalisation_level()) + { + LOG_PRINT(m_command_name, level); + } + else if(level+1 == log_space::get_set_log_detalisation_level()) + { + LOG_PRINT(" -->>" << m_command_name, level); + } + else if(level+2 == log_space::get_set_log_detalisation_level()) + { + LOG_PRINT(" -->>" << m_command_name << "\n" << StorageNamed::xml::get_t_as_xml(m_ref_arg), level); + } + } + + virtual ~notify_activity_printer() + { + if(m_is_notify_mode) + { + if(m_level+1 == log_space::get_set_log_detalisation_level()) + { + LOG_PRINT(" <<--" << m_command_name, m_level); + } + } + } +protected: + std::string m_command_name; + A& m_ref_arg; + int m_level; + bool m_is_notify_mode; +}; + +template +class command_activity_printer: public notify_activity_printer +{ +public: + command_activity_printer(int level, A& arg, R& rsp):notify_activity_printer(level, arg, false), m_ref_rsp(rsp) + { + } + + virtual ~command_activity_printer() + { + if(m_level+1 == log_space::get_set_log_detalisation_level()) + { + LOG_PRINT(" <<--" << m_command_name, m_level); + } + else if(m_level+2 == log_space::get_set_log_detalisation_level()) + { + LOG_PRINT(" <<--" << m_command_name << "\n" << StorageNamed::trace_as_xml(m_ref_rsp), m_level); + } + } +private: + R& m_ref_rsp; +}; + +template +activity_printer_base* create_activity_printer(int level, A& arg, R& rsp) +{ + return new command_activity_printer(level, arg, rsp); +} + +template +activity_printer_base* create_activity_printer(int level, A& arg) +{ + return new notify_activity_printer(level, arg); +} + +} + +#define PRINT_COMMAND_ACTIVITY(level) boost::shared_ptr local_activity_printer(create_activity_printer(level, in_struct, out_struct)); +#define PRINT_NOTIFY_ACTIVITY(level) boost::shared_ptr local_activity_printer(create_activity_printer(level, in_struct)); + +#define PRINT_ACTIVITY(level) \ +{std::string some_str = typeid(in_struct).name(); \ + some_str.erase(0, 7); \ + some_str.erase(some_str.size()-10, some_str.size()-1); \ + LOG_PRINT(some_str, level);} + +} + diff --git a/contrib/epee/include/storages/crypted_storage.h b/contrib/epee/include/storages/crypted_storage.h new file mode 100644 index 00000000..d6e6edcb --- /dev/null +++ b/contrib/epee/include/storages/crypted_storage.h @@ -0,0 +1,62 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + +#ifndef _CRYPTED_STORAGE_H_ +#define _CRYPTED_STORAGE_H_ + +#include "cryptopp_helper.h" + +namespace epee +{ +template +class crypted_storage: public t_base_storage +{ +public: + size_t PackToSolidBuffer(std::string& targetObj) + { + size_t res = t_base_storage::PackToSolidBuffer(targetObj); + if(res <= 0) + return res; + + if(!crypt_provider::encrypt(targetObj, t_key_provider::get_storage_default_key())) + return 0; + + return targetObj.size(); + } + + size_t LoadFromSolidBuffer(const std::string& pTargetObj) + { + std::string buff_to_decrypt = pTargetObj; + if(crypt_provider::decrypt(buff_to_decrypt, t_key_provider::get_storage_default_key())) + return t_base_storage::LoadFromSolidBuffer(buff_to_decrypt); + + return 0; + } +}; +} + +#endif //_CRYPTED_STORAGE_H_ \ No newline at end of file diff --git a/contrib/epee/include/storages/gzipped_inmemstorage.h b/contrib/epee/include/storages/gzipped_inmemstorage.h new file mode 100644 index 00000000..5c53fffa --- /dev/null +++ b/contrib/epee/include/storages/gzipped_inmemstorage.h @@ -0,0 +1,68 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + +#ifndef _GZIPPED_INMEMSTORAGE_H_ +#define _GZIPPED_INMEMSTORAGE_H_ + +#include "zlib_helper.h" +namespace epee +{ +namespace StorageNamed +{ + + template + class gziped_storage: public t_base_storage + { + public: + size_t PackToSolidBuffer(std::string& targetObj) + { + size_t res = t_base_storage::PackToSolidBuffer(targetObj); + if(res <= 0) + return res; + + if(!zlib_helper::pack(targetObj)) + return 0; + + return targetObj.size(); + } + + size_t LoadFromSolidBuffer(const std::string& pTargetObj) + { + std::string buff_to_ungzip = pTargetObj; + if(zlib_helper::unpack(buff_to_ungzip)) + return t_base_storage::LoadFromSolidBuffer(buff_to_ungzip); + + return 0; + } + + private: + }; + +} +} + +#endif \ No newline at end of file diff --git a/contrib/epee/include/storages/http_abstract_invoke.h b/contrib/epee/include/storages/http_abstract_invoke.h new file mode 100644 index 00000000..5305c543 --- /dev/null +++ b/contrib/epee/include/storages/http_abstract_invoke.h @@ -0,0 +1,126 @@ + +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + +#pragma once +#include "portable_storage_template_helper.h" +#include "net/http_base.h" +#include "net/http_server_handlers_map2.h" + +namespace epee +{ + namespace net_utils + { + template + bool invoke_http_json_remote_command2(const std::string& url, t_request& out_struct, t_response& result_struct, t_transport& transport, unsigned int timeout = 5000, const std::string& method = "GET") + { + std::string req_param; + if(!serialization::store_t_to_json(out_struct, req_param)) + return false; + + const http::http_response_info* pri = NULL; + if(!invoke_request(url, transport, timeout, &pri, method, req_param)) + { + LOG_PRINT_L1("Failed to invoke http request to " << url); + return false; + } + + if(!pri->m_response_code) + { + LOG_PRINT_L1("Failed to invoke http request to " << url << ", internal error (null response ptr)"); + return false; + } + + if(pri->m_response_code != 200) + { + LOG_PRINT_L1("Failed to invoke http request to " << url << ", wrong response code: " << pri->m_response_code); + return false; + } + + return serialization::load_t_from_json(result_struct, pri->m_body); + } + + + + template + bool invoke_http_bin_remote_command2(const std::string& url, t_request& out_struct, t_response& result_struct, t_transport& transport, unsigned int timeout = 5000, const std::string& method = "GET") + { + std::string req_param; + if(!serialization::store_t_to_binary(out_struct, req_param)) + return false; + + const http::http_response_info* pri = NULL; + if(!invoke_request(url, transport, timeout, &pri, method, req_param)) + { + LOG_PRINT_L1("Failed to invoke http request to " << url); + return false; + } + + if(!pri->m_response_code) + { + LOG_PRINT_L1("Failed to invoke http request to " << url << ", internal error (null response ptr)"); + return false; + } + + if(pri->m_response_code != 200) + { + LOG_PRINT_L1("Failed to invoke http request to " << url << ", wrong response code: " << pri->m_response_code); + return false; + } + + return serialization::load_t_from_binary(result_struct, pri->m_body); + } + + template + bool invoke_http_json_rpc(const std::string& url, const std::string& method_name, const t_request& out_struct, t_response& result_struct, t_transport& transport, unsigned int timeout = 5000, const std::string& http_method = "GET", const std::string& req_id = "0") + { + epee::json_rpc::request req_t = AUTO_VAL_INIT(req_t); + req_t.jsonrpc = "2.0"; + req_t.id = req_id; + req_t.method = method_name; + req_t.params = out_struct; + epee::json_rpc::response resp_t = AUTO_VAL_INIT(resp_t); + if(!epee::net_utils::invoke_http_json_remote_command2(url, req_t, resp_t, transport, timeout, http_method)) + { + return false; + } + if(resp_t.error.code || resp_t.error.message.size()) + { + LOG_PRINT_L0("RPC call of \"" << method_name << "\" returned error: " << resp_t.error.code << ", message: " << resp_t.error.message); + return false; + } + result_struct = resp_t.result; + return true; + } + + template + bool invoke_http_json_rpc(const std::string& url, typename t_command::request& out_struct, typename t_command::response& result_struct, t_transport& transport, unsigned int timeout = 5000, const std::string& http_method = "GET", const std::string& req_id = "0") + { + return invoke_http_json_rpc(url, t_command::methodname(), out_struct, result_struct, transport, timeout, http_method, req_id); + } + + } +} diff --git a/contrib/epee/include/storages/levin_abstract_invoke2.h b/contrib/epee/include/storages/levin_abstract_invoke2.h new file mode 100644 index 00000000..4ec014b4 --- /dev/null +++ b/contrib/epee/include/storages/levin_abstract_invoke2.h @@ -0,0 +1,310 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + +#pragma once + +#include "portable_storage_template_helper.h" +#include +#include "net/levin_base.h" + +namespace epee +{ + namespace net_utils + { + template + bool invoke_remote_command2(int command, const t_arg& out_struct, t_result& result_struct, t_transport& transport) + { + if(!transport.is_connected()) + return false; + + serialization::portable_storage stg; + out_struct.store(stg); + std::string buff_to_send, buff_to_recv; + stg.store_to_binary(buff_to_send); + int res = 0; + TRY_ENTRY() + res = transport.invoke(command, buff_to_send, buff_to_recv); + CATCH_ENTRY2(false) + if( res <=0 ) + { + LOG_PRINT_RED("Failed to invoke command " << command << " return code " << res << "(" << epee::levin::get_err_descr(res) << ")", LOG_LEVEL_1); + return false; + } + serialization::portable_storage stg_ret; + if(!stg_ret.load_from_binary(buff_to_recv)) + { + LOG_ERROR("Failed to load_from_binary on command " << command); + return false; + } + result_struct.load(stg_ret); + return true; + } + + template + bool notify_remote_command2(int command, const t_arg& out_struct, t_transport& transport) + { + if(!transport.is_connected()) + return false; + + serialization::portable_storage stg; + out_struct.store(&stg); + std::string buff_to_send; + stg.store_to_binary(buff_to_send); + int res = 0; + TRY_ENTRY() + res = transport.notify(command, buff_to_send); + CATCH_ENTRY2(false) + if(res <=0 ) + { + LOG_ERROR("Failed to notify command " << command << " return code " << res << "(" << epee::levin::get_err_descr(res) << ")"); + return false; + } + return true; + } + + template + bool invoke_remote_command2(boost::uuids::uuid conn_id, int command, const t_arg& out_struct, t_result& result_struct, t_transport& transport) + { + + typename serialization::portable_storage stg; + out_struct.store(stg); + std::string buff_to_send, buff_to_recv; + stg.store_to_binary(buff_to_send); + int res = 0; + TRY_ENTRY() + res = transport.invoke(command, buff_to_send, buff_to_recv, conn_id); + CATCH_ENTRY2(false) + if( res <=0 ) + { + LOG_PRINT_L1("Failed to invoke command " << command << " return code " << res << "(" << epee::levin::get_err_descr(res) << ")"); + return false; + } + typename serialization::portable_storage stg_ret; + if(!stg_ret.load_from_binary(buff_to_recv)) + { + LOG_ERROR("Failed to load_from_binary on command " << command); + return false; + } + result_struct.load(stg_ret); + + return true; + } + + template + bool async_invoke_remote_command2(boost::uuids::uuid conn_id, int command, const t_arg& out_struct, t_transport& transport, callback_t cb, size_t inv_timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED) + { + typename serialization::portable_storage stg; + const_cast(out_struct).store(stg);//TODO: add true const support to searilzation + std::string buff_to_send, buff_to_recv; + stg.store_to_binary(buff_to_send); + int res = transport.invoke_async(command, buff_to_send, conn_id, [cb, command](int code, const std::string& buff, typename t_transport::connection_context& context)->bool + { + t_result result_struct = AUTO_VAL_INIT(result_struct); + if( code <=0 ) + { + LOG_PRINT_L1("Failed to invoke command " << command << " return code " << code << "(" << epee::levin::get_err_descr(code) << ")"); + TRY_ENTRY() + cb(code, result_struct, context); + CATCH_ENTRY2(true) + return false; + } + serialization::portable_storage stg_ret; + if(!stg_ret.load_from_binary(buff)) + { + LOG_ERROR("Failed to load_from_binary on command " << command); + TRY_ENTRY(); + cb(LEVIN_ERROR_FORMAT, result_struct, context); + CATCH_ENTRY2(true); + return false; + } + result_struct.load(stg_ret); + TRY_ENTRY() + cb(code, result_struct, context); + CATCH_ENTRY2(true) + return true; + }, inv_timeout); + if( res <=0 ) + { + LOG_PRINT_L1("Failed to invoke command " << command << " return code " << res << "(" << epee::levin::get_err_descr(res)<< ")"); + return false; + } + return true; + } + + template + bool notify_remote_command2(boost::uuids::uuid conn_id, int command, const t_arg& out_struct, t_transport& transport) + { + + serialization::portable_storage stg; + out_struct.store(stg); + std::string buff_to_send, buff_to_recv; + stg.store_to_binary(buff_to_send); + int res = LEVIN_ERROR_UNKNOWN_ERROR; + TRY_ENTRY() + res = transport.notify(command, buff_to_send, conn_id); + CATCH_ENTRY2(false) + if(res <=0 ) + { + LOG_PRINT_RED_L0("Failed to notify command " << command << " return code " << res << "(" << epee::levin::get_err_descr(res) << ")"); + return false; + } + return true; + } + //---------------------------------------------------------------------------------------------------- + //---------------------------------------------------------------------------------------------------- + template + int buff_to_t_adapter(int command, const std::string& in_buff, std::string& buff_out, callback_t cb, t_context& context ) + { + serialization::portable_storage strg; + if(!strg.load_from_binary(in_buff)) + { + LOG_ERROR("Failed to load_from_binary in command " << command); + return LEVIN_ERROR_FORMAT; + } + boost::value_initialized in_struct; + boost::value_initialized out_struct; + + static_cast(in_struct).load(strg); + int res = LEVIN_ERROR_UNKNOWN_ERROR; + TRY_ENTRY() + res = cb(command, static_cast(in_struct), static_cast(out_struct), context); + CATCH_ENTRY2(LEVIN_ERROR_EXCEPTION) + serialization::portable_storage strg_out; + static_cast(out_struct).store(strg_out); + + if(!strg_out.store_to_binary(buff_out)) + { + LOG_ERROR("Failed to store_to_binary in command" << command); + return LEVIN_ERROR_INTERNAL; + } + + return res; + }; + + template + int buff_to_t_adapter(t_owner* powner, int command, const std::string& in_buff, callback_t cb, t_context& context) + { + serialization::portable_storage strg; + if(!strg.load_from_binary(in_buff)) + { + LOG_ERROR("Failed to load_from_binary in notify " << command); + return LEVIN_ERROR_FORMAT; + } + boost::value_initialized in_struct; + static_cast(in_struct).load(strg); + int res = LEVIN_ERROR_UNKNOWN_ERROR; + TRY_ENTRY() + res = cb(command, in_struct, context); + CATCH_ENTRY2(LEVIN_ERROR_EXCEPTION) + return res; + }; + +#define CHAIN_LEVIN_INVOKE_MAP2(context_type) \ + int invoke(int command, const std::string& in_buff, std::string& buff_out, context_type& context) \ + { \ + bool handled = false; \ + return handle_invoke_map(false, command, in_buff, buff_out, context, handled); \ + } + +#define CHAIN_LEVIN_NOTIFY_MAP2(context_type) \ + int notify(int command, const std::string& in_buff, context_type& context) \ + { \ + bool handled = false; std::string fake_str;\ + return handle_invoke_map(true, command, in_buff, fake_str, context, handled); \ + } + + +#define CHAIN_LEVIN_INVOKE_MAP() \ + int invoke(int command, const std::string& in_buff, std::string& buff_out, epee::net_utils::connection_context_base& context) \ + { \ + bool handled = false; \ + return handle_invoke_map(false, command, in_buff, buff_out, context, handled); \ + } + +#define CHAIN_LEVIN_NOTIFY_MAP() \ + int notify(int command, const std::string& in_buff, epee::net_utils::connection_context_base& context) \ + { \ + bool handled = false; std::string fake_str;\ + return handle_invoke_map(true, command, in_buff, fake_str, context, handled); \ + } + +#define CHAIN_LEVIN_NOTIFY_STUB() \ + int notify(int command, const std::string& in_buff, epee::net_utils::connection_context_base& context) \ + { \ + return -1; \ + } + +#define BEGIN_INVOKE_MAP2(owner_type) \ + template int handle_invoke_map(bool is_notify, int command, const std::string& in_buff, std::string& buff_out, t_context& context, bool& handled) \ + { \ + typedef owner_type internal_owner_type_name; + +#define HANDLE_INVOKE2(command_id, func, type_name_in, typename_out) \ + if(!is_notify && command_id == command) \ + {handled=true;return epee::net_utils::buff_to_t_adapter(this, command, in_buff, buff_out, boost::bind(func, this, _1, _2, _3, _4), context);} + +#define HANDLE_INVOKE_T2(COMMAND, func) \ + if(!is_notify && COMMAND::ID == command) \ + {handled=true;return epee::net_utils::buff_to_t_adapter(command, in_buff, buff_out, boost::bind(func, this, _1, _2, _3, _4), context);} + + +#define HANDLE_NOTIFY2(command_id, func, type_name_in) \ + if(is_notify && command_id == command) \ + {handled=true;return epee::net_utils::buff_to_t_adapter(this, command, in_buff, boost::bind(func, this, _1, _2, _3), context);} + +#define HANDLE_NOTIFY_T2(NOTIFY, func) \ + if(is_notify && NOTIFY::ID == command) \ + {handled=true;return epee::net_utils::buff_to_t_adapter(this, command, in_buff, boost::bind(func, this, _1, _2, _3), context);} + + +#define CHAIN_INVOKE_MAP2(func) \ + { \ + int res = func(is_notify, command, in_buff, buff_out, context, handled); \ + if(handled) \ + return res; \ + } + +#define CHAIN_INVOKE_MAP_TO_OBJ2(obj) \ + { \ + int res = obj.handle_invoke_map(is_notify, command, in_buff, buff_out, context, handled); \ + if(handled) \ + return res; \ + } + +#define CHAIN_INVOKE_MAP_TO_OBJ_FORCE_CONTEXT(obj, context_type) \ + { \ + int res = obj.handle_invoke_map(is_notify, command, in_buff, buff_out, static_cast(context), handled); \ + if(handled) return res; \ + } + + +#define END_INVOKE_MAP2() \ + LOG_ERROR("Unkonown command:" << command); \ + return LEVIN_ERROR_CONNECTION_HANDLER_NOT_DEFINED; \ + } + } +} + diff --git a/contrib/epee/include/storages/parserse_base_utils.h b/contrib/epee/include/storages/parserse_base_utils.h new file mode 100644 index 00000000..bd40c688 --- /dev/null +++ b/contrib/epee/include/storages/parserse_base_utils.h @@ -0,0 +1,337 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#pragma once + +namespace epee +{ +namespace misc_utils +{ + namespace parse + { + inline std::string transform_to_escape_sequence(const std::string& src) + { + //std::stringstream res; + std::string res; + for(std::string::const_iterator it = src.begin(); it!=src.end(); ++it) + { + switch(*it) + { + case '\b': //Backspace (ascii code 08) + res+="\\b"; break; + case '\f': //Form feed (ascii code 0C) + res+="\\f"; break; + case '\n': //New line + res+="\\n"; break; + case '\r': //Carriage return + res+="\\r"; break; + case '\t': //Tab + res+="\\t"; break; + case '\v': //Vertical tab + res+="\\v"; break; + //case '\'': //Apostrophe or single quote + // res+="\\'"; break; + case '"': //Double quote + res+="\\\""; break; + case '\\': //Backslash caracter + res+="\\\\"; break; + case '/': //Backslash caracter + res+="\\/"; break; + default: + res.push_back(*it); + } + } + return res; + } + + /* Escapes JSON control characters and ASCII control characters (00h-1Fh => \u00XX) according to JSON reference. + UTF-8-safe. + from https://www.json.org/ : + char -- any-Unicode-character-except-"-or-\-or-control-character: \" \\ \/ \b \f \n \r \t \uDDDD + */ + inline std::string transform_to_json_escape_sequence(const std::string& str) + { + std::string result; + + static const char hex_map[17] = "0123456789abcdef"; + static const std::string su00 = "\\u00"; + + const char* c_str = str.c_str(); + for(size_t i = 0, len = str.length(); i < len; ++i) + { + char c = c_str[i]; + switch(c) + { + case '\b': // ASCII 08h + result += "\\b"; + break; + case '\t': // ASCII 09h + result += "\\t"; + break; + case '\n': // ASCII 0Ah + result += "\\n"; + break; + case '\f': // ASCII 0Ch + result += "\\f"; + break; + case '\r': // ASCII 0Dh + result += "\\r"; + break; + case '"': // ASCII 22h + case '\\': // ASCII 5Ch + case '/': // ASCII 2Fh + result.push_back('\\'); + result.push_back(c); + break; + + default: + if (static_cast(c) < 0x20) + result += su00 + hex_map[(c >> 4) & 0xf] + hex_map[c & 0xf]; // encode all other control characters as \uDDDD + else + result.push_back(c); + } + } + return result; + } + + /* + + \b Backspace (ascii code 08) + \f Form feed (ascii code 0C) + \n New line + \r Carriage return + \t Tab + \v Vertical tab + \' Apostrophe or single quote + \" Double quote + \\ Backslash character + \u00XY ASCII character with code 0xXY + + */ + inline void match_string2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val) + { + val.clear(); + bool escape_mode = false; + val.reserve(buf_end - star_end_string); + std::string::const_iterator it = star_end_string; + ++it; + for(;it != buf_end;it++) + { + if(escape_mode/*prev_ch == '\\'*/) + { + switch(*it) + { + case 'b': //Backspace (ascii code 08) + val.push_back(0x08);break; + case 'f': //Form feed (ascii code 0C) + val.push_back(0x0C);break; + case 'n': //New line + val.push_back('\n');break; + case 'r': //Carriage return + val.push_back('\r');break; + case 't': //Tab + val.push_back('\t');break; + case 'v': //Vertical tab + val.push_back('\v');break; + case '\'': //Apostrophe or single quote + val.push_back('\'');break; + case '"': //Double quote + val.push_back('"');break; + case '\\': //Backslash character + val.push_back('\\');break; + case '/': //Slash character + val.push_back('/');break; + case 'u': // \uDDDD sequence + { + bool ok = false; + size_t chars_left = buf_end - it - 1; + size_t chars_to_get = std::min(static_cast(4), chars_left); // in [0, 4] + char tmp[10] = {0}; + memcpy(tmp, &(*(it+1)), chars_to_get); + it = it + chars_to_get; // move forward to skip 0..4 digits + if (chars_to_get == 4) + { + char *p_last_decoded_char = nullptr; + unsigned long value = strtoul(tmp, &p_last_decoded_char, 16); // expected value is from 0x0000 (\u0000) to 0x00ff (\u00ff) + if (value <= 0xff && p_last_decoded_char - tmp == 4) + { + val.push_back(static_cast(value)); + ok = true; + } + } + if (!ok) + { + LOG_PRINT_L0("JSON invalid escape sequence: \\u" << tmp); + } + } + break; + default: + val.push_back(*it); + LOG_PRINT_L0("JSON unknown escape sequence :\"\\" << *it << "\""); + } + escape_mode = false; + }else if(*it == '"') + { + star_end_string = it; + return; + }else if(*it == '\\') + { + escape_mode = true; + } + else + { + val.push_back(*it); + } + } + ASSERT_MES_AND_THROW("Failed to match string in json entry: " << std::string(star_end_string, buf_end)); + } + inline bool match_string(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val) + { + try + { + + match_string2(star_end_string, buf_end, val); + return true; + } + catch(...) + { + return false; + } + } + inline void match_number2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val, bool& is_float_val, bool& is_signed_val) + { + val.clear(); + is_float_val = false; + for(std::string::const_iterator it = star_end_string;it != buf_end;it++) + { + if(isdigit(*it) || (it == star_end_string && *it == '-') || (val.size() && *it == '.' ) || (is_float_val && (*it == 'e' || *it == 'E' || *it == '-' || *it == '+' )) ) + { + if(!val.size() && *it == '-') + is_signed_val = true; + if(*it == '.' ) + is_float_val = true; + val.push_back(*it); + } + else + { + if(val.size()) + { + star_end_string = --it; + return; + } + else + ASSERT_MES_AND_THROW("wrong number in json entry: " << std::string(star_end_string, buf_end)); + } + } + ASSERT_MES_AND_THROW("wrong number in json entry: " << std::string(star_end_string, buf_end)); + } + inline bool match_number(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val) + { + try + { + bool is_v_float = false;bool is_signed_val = false; + match_number2(star_end_string, buf_end, val, is_v_float, is_signed_val); + return !is_v_float; + } + catch(...) + { + return false; + } + } + inline void match_word2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val) + { + val.clear(); + + for(std::string::const_iterator it = star_end_string;it != buf_end;it++) + { + if(!isalpha(*it)) + { + val.assign(star_end_string, it); + if(val.size()) + { + star_end_string = --it; + return; + }else + ASSERT_MES_AND_THROW("failed to match word number in json entry: " << std::string(star_end_string, buf_end)); + } + } + ASSERT_MES_AND_THROW("failed to match word number in json entry: " << std::string(star_end_string, buf_end)); + } + inline bool match_word(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val) + { + try + { + match_word2(star_end_string, buf_end, val); + return true; + } + catch(...) + { + return false; + } + } + inline bool match_word_with_extrasymb(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val) + { + val.clear(); + + for(std::string::const_iterator it = star_end_string;it != buf_end;it++) + { + if(!isalnum(*it) && *it != '-' && *it != '_') + { + val.assign(star_end_string, it); + if(val.size()) + { + star_end_string = --it; + return true; + }else + return false; + } + } + return false; + } + inline bool match_word_til_equal_mark(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string::const_iterator& word_end) + { + word_end = star_end_string; + + for(std::string::const_iterator it = star_end_string;it != buf_end;it++) + { + if(isspace(*it)) + { + + continue; + }else if( *it == '=' ) + { + star_end_string = it; + word_end = it; + return true; + } + } + return false; + } + } +} +} \ No newline at end of file diff --git a/contrib/epee/include/storages/portable_storage.h b/contrib/epee/include/storages/portable_storage.h new file mode 100644 index 00000000..b9b7aba9 --- /dev/null +++ b/contrib/epee/include/storages/portable_storage.h @@ -0,0 +1,479 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#pragma once + +#include "misc_language.h" +#include "portable_storage_base.h" +#include "portable_storage_to_bin.h" +#include "portable_storage_from_bin.h" +#include "portable_storage_to_json.h" +#include "portable_storage_from_json.h" +#include "portable_storage_val_converters.h" + +namespace epee +{ + namespace serialization + { + /************************************************************************/ + /* */ + /************************************************************************/ + class portable_storage + { + public: + typedef epee::serialization::hsection hsection; + typedef epee::serialization::harray harray; + typedef storage_entry meta_entry; + + portable_storage(){} + virtual ~portable_storage(){} + hsection open_section(const std::string& section_name, hsection hparent_section, bool create_if_notexist = false); + template + bool get_value(const std::string& value_name, t_value& val, hsection hparent_section); + bool get_value(const std::string& value_name, storage_entry& val, hsection hparent_section); + template + bool set_value(const std::string& value_name, const t_value& target, hsection hparent_section); + + //serial access for arrays of values -------------------------------------- + //values + template + harray get_first_value(const std::string& value_name, t_value& target, hsection hparent_section); + template + bool get_next_value(harray hval_array, t_value& target); + template + harray insert_first_value(const std::string& value_name, const t_value& target, hsection hparent_section); + template + bool insert_next_value(harray hval_array, const t_value& target); + //sections + harray get_first_section(const std::string& pSectionName, hsection& h_child_section, hsection hparent_section); + bool get_next_section(harray hSecArray, hsection& h_child_section); + harray insert_first_section(const std::string& pSectionName, hsection& hinserted_childsection, hsection hparent_section); + bool insert_next_section(harray hSecArray, hsection& hinserted_childsection); + //------------------------------------------------------------------------ + //delete entry (section, value or array) + bool delete_entry(const std::string& pentry_name, hsection hparent_section = nullptr); + + //------------------------------------------------------------------------------- + bool store_to_binary(binarybuffer& target); + bool load_from_binary(const binarybuffer& target); + template + bool dump_as_xml(std::string& targetObj, const std::string& root_name = ""); + bool dump_as_json(std::string& targetObj, size_t indent = 0); + bool load_from_json(const std::string& source); + + private: + section m_root; + hsection get_root_section() {return &m_root;} + storage_entry* find_storage_entry(const std::string& pentry_name, hsection psection); + template + storage_entry* insert_new_entry_get_storage_entry(const std::string& pentry_name, hsection psection, const entry_type& entry); + + hsection insert_new_section(const std::string& pentry_name, hsection psection); + +#pragma pack(push) +#pragma pack(1) + struct storage_block_header + { + uint32_t m_signature_a; + uint32_t m_signature_b; + uint8_t m_ver; + }; +#pragma pack(pop) + }; + inline + bool portable_storage::dump_as_json(std::string& buff, size_t indent) + { + TRY_ENTRY(); + std::stringstream ss; + epee::serialization::dump_as_json(ss, m_root, indent); + buff = ss.str(); + return true; + CATCH_ENTRY("portable_storage::dump_as_json", false) + } + inline + bool portable_storage::load_from_json(const std::string& source) + { + TRY_ENTRY(); + return json::load_from_json(source, *this); + CATCH_ENTRY("portable_storage::load_from_json", false) + } + + template + bool portable_storage::dump_as_xml(std::string& targetObj, const std::string& root_name) + { + return false;//TODO: don't think i ever again will use xml - ambiguous and "overtagged" format + } + + inline + bool portable_storage::store_to_binary(binarybuffer& target) + { + TRY_ENTRY(); + std::stringstream ss; + storage_block_header sbh = AUTO_VAL_INIT(sbh); + sbh.m_signature_a = PORTABLE_STORAGE_SIGNATUREA; + sbh.m_signature_b = PORTABLE_STORAGE_SIGNATUREB; + sbh.m_ver = PORTABLE_STORAGE_FORMAT_VER; + ss.write((const char*)&sbh, sizeof(storage_block_header)); + pack_entry_to_buff(ss, m_root); + target = ss.str(); + return true; + CATCH_ENTRY("portable_storage::store_to_binary", false) + } + inline + bool portable_storage::load_from_binary(const binarybuffer& source) + { + m_root.m_entries.clear(); + if(source.size() < sizeof(storage_block_header)) + { + LOG_ERROR("portable_storage: wrong binary format, packet size = " << source.size() << " less than expected sizeof(storage_block_header)=" << sizeof(storage_block_header)); + return false; + } + storage_block_header* pbuff = (storage_block_header*)source.data(); + if(pbuff->m_signature_a != PORTABLE_STORAGE_SIGNATUREA || + pbuff->m_signature_b != PORTABLE_STORAGE_SIGNATUREB + ) + { + LOG_PRINT_RED_L0("portable_storage: wrong binary format - signature missmatch"); + return false; + } + if(pbuff->m_ver != PORTABLE_STORAGE_FORMAT_VER) + { + LOG_ERROR("portable_storage: wrong binary format - unknown format ver = " << pbuff->m_ver); + return false; + } + TRY_ENTRY(); + throwable_buffer_reader buf_reader(source.data()+sizeof(storage_block_header), source.size()-sizeof(storage_block_header)); + buf_reader.read(m_root); + return true;//TODO: + CATCH_ENTRY("portable_storage::load_from_binary", false); + } + //--------------------------------------------------------------------------------------------------------------- + inline + hsection portable_storage::open_section(const std::string& section_name, hsection hparent_section, bool create_if_notexist) + { + TRY_ENTRY(); + hparent_section = hparent_section ? hparent_section:&m_root; + storage_entry* pentry = find_storage_entry(section_name, hparent_section); + if(!pentry) + { + if(!create_if_notexist) + return nullptr; + return insert_new_section(section_name, hparent_section); + } + CHECK_AND_ASSERT(pentry , nullptr); + //check that section_entry we find is real "CSSection" + if(pentry->type() != typeid(section)) + { + if(create_if_notexist) + *pentry = storage_entry(section());//replace + else + return nullptr; + } + return &boost::get
(*pentry); + CATCH_ENTRY("portable_storage::open_section", nullptr); + } + //--------------------------------------------------------------------------------------------------------------- + template + struct get_value_visitor: boost::static_visitor + { + to_type& m_target; + get_value_visitor(to_type& target):m_target(target){} + template + void operator()(const from_type& v){convert_t(v, m_target);} + }; + + template + bool portable_storage::get_value(const std::string& value_name, t_value& val, hsection hparent_section) + { + BOOST_MPL_ASSERT(( boost::mpl::contains )); + //TRY_ENTRY(); + if(!hparent_section) hparent_section = &m_root; + storage_entry* pentry = find_storage_entry(value_name, hparent_section); + if(!pentry) + return false; + + get_value_visitor gvv(val); + boost::apply_visitor(gvv, *pentry); + return true; + //CATCH_ENTRY("portable_storage::template<>get_value", false); + } + //--------------------------------------------------------------------------------------------------------------- + inline + bool portable_storage::get_value(const std::string& value_name, storage_entry& val, hsection hparent_section) + { + //TRY_ENTRY(); + if(!hparent_section) hparent_section = &m_root; + storage_entry* pentry = find_storage_entry(value_name, hparent_section); + if(!pentry) + return false; + + val = *pentry; + return true; + //CATCH_ENTRY("portable_storage::template<>get_value", false); + } + //--------------------------------------------------------------------------------------------------------------- + template + bool portable_storage::set_value(const std::string& value_name, const t_value& v, hsection hparent_section) + { + BOOST_MPL_ASSERT(( boost::mpl::contains::type, t_value> )); + TRY_ENTRY(); + if(!hparent_section) + hparent_section = &m_root; + storage_entry* pentry = find_storage_entry(value_name, hparent_section); + if(!pentry) + { + pentry = insert_new_entry_get_storage_entry(value_name, hparent_section, v); + if(!pentry) + return false; + return true; + } + *pentry = storage_entry(v); + return true; + CATCH_ENTRY("portable_storage::template<>set_value", false); + } + //--------------------------------------------------------------------------------------------------------------- + inline + storage_entry* portable_storage::find_storage_entry(const std::string& pentry_name, hsection psection) + { + TRY_ENTRY(); + CHECK_AND_ASSERT(psection, nullptr); + auto it = psection->m_entries.find(pentry_name); + if(it == psection->m_entries.end()) + return nullptr; + + return &it->second; + CATCH_ENTRY("portable_storage::find_storage_entry", nullptr); + } + //--------------------------------------------------------------------------------------------------------------- + template + storage_entry* portable_storage::insert_new_entry_get_storage_entry(const std::string& pentry_name, hsection psection, const entry_type& entry) + { + TRY_ENTRY(); + CHECK_AND_ASSERT(psection, nullptr); + auto ins_res = psection->m_entries.insert(std::pair(pentry_name, entry)); + return &ins_res.first->second; + CATCH_ENTRY("portable_storage::insert_new_entry_get_storage_entry", nullptr); + } + //--------------------------------------------------------------------------------------------------------------- + inline + hsection portable_storage::insert_new_section(const std::string& pentry_name, hsection psection) + { + TRY_ENTRY(); + storage_entry* pse = insert_new_entry_get_storage_entry(pentry_name, psection, section()); + if(!pse) return nullptr; + return &boost::get
(*pse); + CATCH_ENTRY("portable_storage::insert_new_section", nullptr); + } + //--------------------------------------------------------------------------------------------------------------- + template + struct get_first_value_visitor: boost::static_visitor + { + to_type& m_target; + get_first_value_visitor(to_type& target):m_target(target){} + template + bool operator()(const array_entry_t& a) + { + const from_type* pv = a.get_first_val(); + if(!pv) + return false; + convert_t(*pv, m_target); + return true; + } + }; + //--------------------------------------------------------------------------------------------------------------- + template + harray portable_storage::get_first_value(const std::string& value_name, t_value& target, hsection hparent_section) + { + BOOST_MPL_ASSERT(( boost::mpl::contains )); + //TRY_ENTRY(); + if(!hparent_section) hparent_section = &m_root; + storage_entry* pentry = find_storage_entry(value_name, hparent_section); + if(!pentry) + return nullptr; + if(pentry->type() != typeid(array_entry)) + return nullptr; + array_entry& ar_entry = boost::get(*pentry); + + get_first_value_visitor gfv(target); + if(!boost::apply_visitor(gfv, ar_entry)) + return nullptr; + return &ar_entry; + //CATCH_ENTRY("portable_storage::get_first_value", nullptr); + } + //--------------------------------------------------------------------------------------------------------------- + template + struct get_next_value_visitor: boost::static_visitor + { + to_type& m_target; + get_next_value_visitor(to_type& target):m_target(target){} + template + bool operator()(const array_entry_t& a) + { + //TODO: optimize code here: work without get_next_val function + const from_type* pv = a.get_next_val(); + if(!pv) + return false; + convert_t(*pv, m_target); + return true; + } + }; + + + template + bool portable_storage::get_next_value(harray hval_array, t_value& target) + { + BOOST_MPL_ASSERT(( boost::mpl::contains )); + //TRY_ENTRY(); + CHECK_AND_ASSERT(hval_array, false); + array_entry& ar_entry = *hval_array; + get_next_value_visitor gnv(target); + if(!boost::apply_visitor(gnv, ar_entry)) + return false; + return true; + //CATCH_ENTRY("portable_storage::get_next_value", false); + } + //--------------------------------------------------------------------------------------------------------------- + template + harray portable_storage::insert_first_value(const std::string& value_name, const t_value& target, hsection hparent_section) + { + TRY_ENTRY(); + if(!hparent_section) hparent_section = &m_root; + storage_entry* pentry = find_storage_entry(value_name, hparent_section); + if(!pentry) + { + pentry = insert_new_entry_get_storage_entry(value_name, hparent_section, array_entry(array_entry_t())); + if(!pentry) + return nullptr; + } + if(pentry->type() != typeid(array_entry)) + *pentry = storage_entry(array_entry(array_entry_t())); + + array_entry& arr = boost::get(*pentry); + if(arr.type() != typeid(array_entry_t)) + arr = array_entry(array_entry_t()); + + array_entry_t& arr_typed = boost::get >(arr); + arr_typed.insert_first_val(target); + return &arr; + CATCH_ENTRY("portable_storage::insert_first_value", nullptr); + } + //--------------------------------------------------------------------------------------------------------------- + template + bool portable_storage::insert_next_value(harray hval_array, const t_value& target) + { + TRY_ENTRY(); + CHECK_AND_ASSERT(hval_array, false); + + CHECK_AND_ASSERT_MES(hval_array->type() == typeid(array_entry_t), + false, "unexpected type in insert_next_value: " << typeid(array_entry_t).name()); + + array_entry_t& arr_typed = boost::get >(*hval_array); + arr_typed.insert_next_value(target); + return true; + CATCH_ENTRY("portable_storage::insert_next_value", false); + } + //--------------------------------------------------------------------------------------------------------------- + //sections + inline + harray portable_storage::get_first_section(const std::string& sec_name, hsection& h_child_section, hsection hparent_section) + { + TRY_ENTRY(); + if(!hparent_section) hparent_section = &m_root; + storage_entry* pentry = find_storage_entry(sec_name, hparent_section); + if(!pentry) + return nullptr; + if(pentry->type() != typeid(array_entry)) + return nullptr; + array_entry& ar_entry = boost::get(*pentry); + if(ar_entry.type() != typeid(array_entry_t
)) + return nullptr; + array_entry_t
& sec_array = boost::get>(ar_entry); + section* psec = sec_array.get_first_val(); + if(!psec) + return nullptr; + h_child_section = psec; + return &ar_entry; + CATCH_ENTRY("portable_storage::get_first_section", nullptr); + } + //--------------------------------------------------------------------------------------------------------------- + inline + bool portable_storage::get_next_section(harray hsec_array, hsection& h_child_section) + { + TRY_ENTRY(); + CHECK_AND_ASSERT(hsec_array, false); + if(hsec_array->type() != typeid(array_entry_t
)) + return false; + array_entry_t
& sec_array = boost::get>(*hsec_array); + h_child_section = sec_array.get_next_val(); + if(!h_child_section) + return false; + return true; + CATCH_ENTRY("portable_storage::get_next_section", false); + } + //--------------------------------------------------------------------------------------------------------------- + inline + harray portable_storage::insert_first_section(const std::string& sec_name, hsection& hinserted_childsection, hsection hparent_section) + { + TRY_ENTRY(); + if(!hparent_section) hparent_section = &m_root; + storage_entry* pentry = find_storage_entry(sec_name, hparent_section); + if(!pentry) + { + pentry = insert_new_entry_get_storage_entry(sec_name, hparent_section, array_entry(array_entry_t
())); + if(!pentry) + return nullptr; + } + if(pentry->type() != typeid(array_entry)) + *pentry = storage_entry(array_entry(array_entry_t
())); + + array_entry& ar_entry = boost::get(*pentry); + if(ar_entry.type() != typeid(array_entry_t
)) + ar_entry = array_entry(array_entry_t
()); + + array_entry_t
& sec_array = boost::get>(ar_entry); + hinserted_childsection = &sec_array.insert_first_val(section()); + return &ar_entry; + CATCH_ENTRY("portable_storage::insert_first_section", nullptr); + } + //--------------------------------------------------------------------------------------------------------------- + inline + bool portable_storage::insert_next_section(harray hsec_array, hsection& hinserted_childsection) + { + TRY_ENTRY(); + CHECK_AND_ASSERT(hsec_array, false); + CHECK_AND_ASSERT_MES(hsec_array->type() == typeid(array_entry_t
), + false, "unexpected type(not 'section') in insert_next_section, type: " << hsec_array->type().name()); + + array_entry_t
& sec_array = boost::get>(*hsec_array); + hinserted_childsection = &sec_array.insert_next_value(section()); + return true; + CATCH_ENTRY("portable_storage::insert_next_section", false); + } + //--------------------------------------------------------------------------------------------------------------- + } +} diff --git a/contrib/epee/include/storages/portable_storage_base.h b/contrib/epee/include/storages/portable_storage_base.h new file mode 100644 index 00000000..3f163753 --- /dev/null +++ b/contrib/epee/include/storages/portable_storage_base.h @@ -0,0 +1,160 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#pragma once + +#include +#include +#include +#include + +#define PORTABLE_STORAGE_SIGNATUREA 0x01011101 +#define PORTABLE_STORAGE_SIGNATUREB 0x01020101 // bender's nightmare +#define PORTABLE_STORAGE_FORMAT_VER 1 + +#define PORTABLE_RAW_SIZE_MARK_MASK 0x03 +#define PORTABLE_RAW_SIZE_MARK_BYTE 0 +#define PORTABLE_RAW_SIZE_MARK_WORD 1 +#define PORTABLE_RAW_SIZE_MARK_DWORD 2 +#define PORTABLE_RAW_SIZE_MARK_INT64 3 + +#ifndef MAX_STRING_LEN_POSSIBLE +#define MAX_STRING_LEN_POSSIBLE 2000000000 //do not let string be so big +#endif + +//data types +#define SERIALIZE_TYPE_INT64 1 +#define SERIALIZE_TYPE_INT32 2 +#define SERIALIZE_TYPE_INT16 3 +#define SERIALIZE_TYPE_INT8 4 +#define SERIALIZE_TYPE_UINT64 5 +#define SERIALIZE_TYPE_UINT32 6 +#define SERIALIZE_TYPE_UINT16 7 +#define SERIALIZE_TYPE_UINT8 8 +#define SERIALIZE_TYPE_DUOBLE 9 +#define SERIALIZE_TYPE_STRING 10 +#define SERIALIZE_TYPE_BOOL 11 +#define SERIALIZE_TYPE_OBJECT 12 +#define SERIALIZE_TYPE_ARRAY 13 + +#define SERIALIZE_FLAG_ARRAY 0x80 + + +namespace epee +{ + namespace serialization + { + struct section; + + /************************************************************************/ + /* */ + /************************************************************************/ + template + struct array_entry_t + { + array_entry_t():m_it(m_array.end()){} + + const t_entry_type* get_first_val() const + { + m_it = m_array.begin(); + return get_next_val(); + } + + t_entry_type* get_first_val() + { + m_it = m_array.begin(); + return get_next_val(); + } + + + const t_entry_type* get_next_val() const + { + if(m_it == m_array.end()) + return nullptr; + return &(*(m_it++)); + } + + t_entry_type* get_next_val() + { + if(m_it == m_array.end()) + return nullptr; + return (t_entry_type*)&(*(m_it++));//fuckoff + } + + t_entry_type& insert_first_val(const t_entry_type& v) + { + m_array.clear(); + m_it = m_array.end(); + return insert_next_value(v); + } + + t_entry_type& insert_next_value(const t_entry_type& v) + { + m_array.push_back(v); + return m_array.back(); + } + + std::list m_array; + mutable typename std::list::const_iterator m_it; + }; + + + typedef boost::make_recursive_variant< + array_entry_t
, + array_entry_t, + array_entry_t, + array_entry_t, + array_entry_t, + array_entry_t, + array_entry_t, + array_entry_t, + array_entry_t, + array_entry_t, + array_entry_t, + array_entry_t, + array_entry_t
, + array_entry_t + >::type array_entry; + + typedef boost::variant storage_entry; + + typedef std::string binarybuffer;//it's ok + + /************************************************************************/ + /* */ + /************************************************************************/ + struct section + { + std::map m_entries; + }; + + //handle-like aliases + typedef section* hsection; + typedef array_entry* harray; + } +} \ No newline at end of file diff --git a/contrib/epee/include/storages/portable_storage_from_bin.h b/contrib/epee/include/storages/portable_storage_from_bin.h new file mode 100644 index 00000000..2f84d4be --- /dev/null +++ b/contrib/epee/include/storages/portable_storage_from_bin.h @@ -0,0 +1,281 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#pragma once + +#include "misc_language.h" +#include "portable_storage_base.h" + +#ifdef EPEE_PORTABLE_STORAGE_RECURSION_LIMIT +#define EPEE_PORTABLE_STORAGE_RECURSION_LIMIT_INTERNAL EPEE_PORTABLE_STORAGE_RECURSION_LIMIT +#else +#define EPEE_PORTABLE_STORAGE_RECURSION_LIMIT_INTERNAL 100 +#endif + +namespace epee +{ + namespace serialization + { + struct throwable_buffer_reader + { + throwable_buffer_reader(const void* ptr, size_t sz); + void read(void* target, size_t count); + void read_sec_name(std::string& sce_name); + template + void read(t_pod_type& pod_val); + template + t_type read(); + template + storage_entry read_ae(); + storage_entry load_storage_array_entry(uint8_t type); + uint64_t read_varint(); + template + storage_entry read_se(); + storage_entry load_storage_entry(); + void read(section& sec); + void read(std::string& str); + private: + struct recursuion_limitation_guard + { + size_t& m_counter_ref; + recursuion_limitation_guard(size_t& counter):m_counter_ref(counter) + { + ++m_counter_ref; + CHECK_AND_ASSERT_THROW_MES(m_counter_ref < EPEE_PORTABLE_STORAGE_RECURSION_LIMIT_INTERNAL, "Wrong blob data in portable storage: recursion limitation (" << EPEE_PORTABLE_STORAGE_RECURSION_LIMIT_INTERNAL << ") exceeded"); + } + ~recursuion_limitation_guard() BOOST_NOEXCEPT_IF(false) + { + CHECK_AND_ASSERT_THROW_MES(m_counter_ref != 0, "Internal error: m_counter_ref == 0 while ~recursuion_limitation_guard()"); + --m_counter_ref; + } + }; +#define RECURSION_LIMITATION() recursuion_limitation_guard rl(m_recursion_count) + + const uint8_t* m_ptr; + size_t m_count; + size_t m_recursion_count; + }; + + inline throwable_buffer_reader::throwable_buffer_reader(const void* ptr, size_t sz) + { + if(!ptr) + throw std::runtime_error("throwable_buffer_reader: ptr==nullptr"); + if(!sz) + throw std::runtime_error("throwable_buffer_reader: sz==0"); + m_ptr = (uint8_t*)ptr; + m_count = sz; + m_recursion_count = 0; + } + inline + void throwable_buffer_reader::read(void* target, size_t count) + { + RECURSION_LIMITATION(); + CHECK_AND_ASSERT_THROW_MES(m_count >= count, " attempt to read " << count << " bytes from buffer with " << m_count << " bytes remained"); + memcpy(target, m_ptr, count); + m_ptr += count; + m_count -= count; + } + inline + void throwable_buffer_reader::read_sec_name(std::string& sce_name) + { + RECURSION_LIMITATION(); + uint8_t name_len = 0; + read(name_len); + sce_name.resize(name_len); + read((void*)sce_name.data(), name_len); + } + + template + void throwable_buffer_reader::read(t_pod_type& pod_val) + { + RECURSION_LIMITATION(); + read(&pod_val, sizeof(pod_val)); + } + + template + t_type throwable_buffer_reader::read() + { + RECURSION_LIMITATION(); + t_type v; + read(v); + return v; + } + + + template + storage_entry throwable_buffer_reader::read_ae() + { + RECURSION_LIMITATION(); + //for pod types + array_entry_t sa; + uint64_t size = read_varint(); + //TODO: add some optimization here later + while(size--) + sa.m_array.push_back(read()); + return storage_entry(array_entry(sa)); + } + + inline + storage_entry throwable_buffer_reader::load_storage_array_entry(uint8_t type) + { + RECURSION_LIMITATION(); + type &= ~SERIALIZE_FLAG_ARRAY; + switch(type) + { + case SERIALIZE_TYPE_INT64: return read_ae(); + case SERIALIZE_TYPE_INT32: return read_ae(); + case SERIALIZE_TYPE_INT16: return read_ae(); + case SERIALIZE_TYPE_INT8: return read_ae(); + case SERIALIZE_TYPE_UINT64: return read_ae(); + case SERIALIZE_TYPE_UINT32: return read_ae(); + case SERIALIZE_TYPE_UINT16: return read_ae(); + case SERIALIZE_TYPE_UINT8: return read_ae(); + case SERIALIZE_TYPE_DUOBLE: return read_ae(); + case SERIALIZE_TYPE_BOOL: return read_ae(); + case SERIALIZE_TYPE_STRING: return read_ae(); + case SERIALIZE_TYPE_OBJECT: return read_ae
(); + case SERIALIZE_TYPE_ARRAY: return read_ae(); + default: + CHECK_AND_ASSERT_THROW_MES(false, "unknown entry_type code = " << type); + } + } + + inline + uint64_t throwable_buffer_reader::read_varint() + { + RECURSION_LIMITATION(); + CHECK_AND_ASSERT_THROW_MES(m_count >= 1, "empty buff, expected place for varint"); + uint64_t v = 0; + uint8_t size_mask = (*(uint8_t*)m_ptr) &PORTABLE_RAW_SIZE_MARK_MASK; + switch (size_mask) + { + case PORTABLE_RAW_SIZE_MARK_BYTE: v = read();break; + case PORTABLE_RAW_SIZE_MARK_WORD: v = read();break; + case PORTABLE_RAW_SIZE_MARK_DWORD: v = read();break; + case PORTABLE_RAW_SIZE_MARK_INT64: v = read();break; + default: + CHECK_AND_ASSERT_THROW_MES(false, "unknown varint size_mask = " << size_mask); + } + v >>= 2; + return v; + } + + template + storage_entry throwable_buffer_reader::read_se() + { + RECURSION_LIMITATION(); + t_type v; + read(v); + return storage_entry(v); + } + + template<> + inline storage_entry throwable_buffer_reader::read_se() + { + RECURSION_LIMITATION(); + return storage_entry(read()); + } + + + template<> + inline storage_entry throwable_buffer_reader::read_se
() + { + RECURSION_LIMITATION(); + section s;//use extra variable due to vs bug, line "storage_entry se(section()); " can't be compiled in visual studio + storage_entry se(s); + section& section_entry = boost::get
(se); + read(section_entry); + return se; + } + + template<> + inline storage_entry throwable_buffer_reader::read_se() + { + RECURSION_LIMITATION(); + uint8_t ent_type = 0; + read(ent_type); + CHECK_AND_ASSERT_THROW_MES(ent_type&SERIALIZE_FLAG_ARRAY, "wrong type sequenses"); + return load_storage_array_entry(ent_type); + } + + inline + storage_entry throwable_buffer_reader::load_storage_entry() + { + RECURSION_LIMITATION(); + uint8_t ent_type = 0; + read(ent_type); + if(ent_type&SERIALIZE_FLAG_ARRAY) + return load_storage_array_entry(ent_type); + + switch(ent_type) + { + case SERIALIZE_TYPE_INT64: return read_se(); + case SERIALIZE_TYPE_INT32: return read_se(); + case SERIALIZE_TYPE_INT16: return read_se(); + case SERIALIZE_TYPE_INT8: return read_se(); + case SERIALIZE_TYPE_UINT64: return read_se(); + case SERIALIZE_TYPE_UINT32: return read_se(); + case SERIALIZE_TYPE_UINT16: return read_se(); + case SERIALIZE_TYPE_UINT8: return read_se(); + case SERIALIZE_TYPE_DUOBLE: return read_se(); + case SERIALIZE_TYPE_BOOL: return read_se(); + case SERIALIZE_TYPE_STRING: return read_se(); + case SERIALIZE_TYPE_OBJECT: return read_se
(); + case SERIALIZE_TYPE_ARRAY: return read_se(); + default: + CHECK_AND_ASSERT_THROW_MES(false, "unknown entry_type code = " << ent_type); + } + } + inline + void throwable_buffer_reader::read(section& sec) + { + RECURSION_LIMITATION(); + sec.m_entries.clear(); + uint64_t count = read_varint(); + while(count--) + { + //read section name string + std::string sec_name; + read_sec_name(sec_name); + sec.m_entries.insert(std::make_pair(sec_name, load_storage_entry())); + } + } + inline + void throwable_buffer_reader::read(std::string& str) + { + RECURSION_LIMITATION(); + size_t len = static_cast(read_varint()); + CHECK_AND_ASSERT_THROW_MES(len < MAX_STRING_LEN_POSSIBLE, "to big string len value in storage: " << len); + CHECK_AND_ASSERT_THROW_MES(m_count >= len, "string len count value " << len << " goes out of remain storage len " << m_count); + //do this manually to avoid double memory write in huge strings (first time at resize, second at read) + str.assign((const char*)m_ptr, len); + m_ptr+=len; + m_count -= len; + } + } +} \ No newline at end of file diff --git a/contrib/epee/include/storages/portable_storage_from_json.h b/contrib/epee/include/storages/portable_storage_from_json.h new file mode 100644 index 00000000..4e74fb7a --- /dev/null +++ b/contrib/epee/include/storages/portable_storage_from_json.h @@ -0,0 +1,379 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + +#pragma once +#include "parserse_base_utils.h" +#include "file_io_utils.h" + +namespace epee +{ + using namespace misc_utils::parse; + namespace serialization + { + namespace json + { +#define CHECK_ISSPACE() if(!isspace(*it)){ ASSERT_MES_AND_THROW("Wrong JSON character at: " << std::string(it, buf_end));} + + /*inline void parse_error() + { + ASSERT_MES_AND_THROW("json parse error"); + }*/ + template + inline void run_handler(typename t_storage::hsection current_section, std::string::const_iterator& sec_buf_begin, std::string::const_iterator buf_end, t_storage& stg) + { + + std::string::const_iterator sub_element_start; + std::string name; + typename t_storage::harray h_array = nullptr; + enum match_state + { + match_state_lookup_for_section_start, + match_state_lookup_for_name, + match_state_waiting_separator, + match_state_wonder_after_separator, + match_state_wonder_after_value, + match_state_wonder_array, + match_state_array_after_value, + match_state_array_waiting_value, + match_state_error + }; + + enum array_mode + { + array_mode_undifined = 0, + array_mode_sections, + array_mode_string, + array_mode_numbers, + array_mode_booleans + }; + + match_state state = match_state_lookup_for_section_start; + array_mode array_md = array_mode_undifined; + std::string::const_iterator it = sec_buf_begin; + for(;it != buf_end;it++) + { + switch (state) + { + case match_state_lookup_for_section_start: + if(*it == '{') + state = match_state_lookup_for_name; + else CHECK_ISSPACE(); + break; + case match_state_lookup_for_name: + switch(*it) + { + case '"': + match_string2(it, buf_end, name); + state = match_state_waiting_separator; + break; + case '}': + //this is it! section ends here. + //seems that it is empty section + sec_buf_begin = it; + return; + default: + CHECK_ISSPACE(); + } + break; + case match_state_waiting_separator: + if(*it == ':') + state = match_state_wonder_after_separator; + else CHECK_ISSPACE(); + break; + case match_state_wonder_after_separator: + if(*it == '"') + {//just a named string value started + std::string val; + match_string2(it, buf_end, val); + //insert text value + stg.set_value(name, val, current_section); + state = match_state_wonder_after_value; + }else if (isdigit(*it) || *it == '-') + {//just a named number value started + std::string val; + bool is_v_float = false;bool is_signed = false; + match_number2(it, buf_end, val, is_v_float, is_signed); + if(!is_v_float) + { + if(is_signed) + { + int64_t nval = boost::lexical_cast(val); + stg.set_value(name, nval, current_section); + }else + { + uint64_t nval = boost::lexical_cast(val); + stg.set_value(name, nval, current_section); + } + }else + { + double nval = boost::lexical_cast(val); + stg.set_value(name, nval, current_section); + } + state = match_state_wonder_after_value; + }else if(isalpha(*it) ) + {// could be null, true or false + std::string word; + match_word2(it, buf_end, word); + if(boost::iequals(word, "null")) + { + state = match_state_wonder_after_value; + //just skip this, + }else if(boost::iequals(word, "true")) + { + stg.set_value(name, true, current_section); + state = match_state_wonder_after_value; + }else if(boost::iequals(word, "false")) + { + stg.set_value(name, false, current_section); + state = match_state_wonder_after_value; + }else ASSERT_MES_AND_THROW("Unknown value keyword " << word); + }else if(*it == '{') + { + //sub section here + typename t_storage::hsection new_sec = stg.open_section(name, current_section, true); + CHECK_AND_ASSERT_THROW_MES(new_sec, "Failed to insert new section in json: " << std::string(it, buf_end)); + run_handler(new_sec, it, buf_end, stg); + state = match_state_wonder_after_value; + }else if(*it == '[') + {//array of something + state = match_state_wonder_array; + }else CHECK_ISSPACE(); + break; + case match_state_wonder_after_value: + if(*it == ',') + state = match_state_lookup_for_name; + else if(*it == '}') + { + //this is it! section ends here. + sec_buf_begin = it; + return; + }else CHECK_ISSPACE(); + break; + case match_state_wonder_array: + if(*it == '[') + { + ASSERT_MES_AND_THROW("array of array not suppoerted yet :( sorry"); + //mean array of array + } + if(*it == '{') + { + //mean array of sections + typename t_storage::hsection new_sec = nullptr; + h_array = stg.insert_first_section(name, new_sec, current_section); + CHECK_AND_ASSERT_THROW_MES(h_array&&new_sec, "failed to create new section"); + run_handler(new_sec, it, buf_end, stg); + state = match_state_array_after_value; + array_md = array_mode_sections; + }else if(*it == '"') + { + //mean array of strings + std::string val; + match_string2(it, buf_end, val); + h_array = stg.insert_first_value(name, val, current_section); + CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values entry"); + state = match_state_array_after_value; + array_md = array_mode_string; + }else if (isdigit(*it) || *it == '-') + {//array of numbers value started + std::string val; + bool is_v_float = false;bool is_signed_val = false; + match_number2(it, buf_end, val, is_v_float, is_signed_val); + if(!is_v_float) + { + int64_t nval = boost::lexical_cast(val);//bool res = string_tools::string_to_num_fast(val, nval); + h_array = stg.insert_first_value(name, nval, current_section); + CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values section entry"); + }else + { + double nval = boost::lexical_cast(val);//bool res = string_tools::string_to_num_fast(val, nval); + h_array = stg.insert_first_value(name, nval, current_section); + CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values section entry"); + } + + state = match_state_array_after_value; + array_md = array_mode_numbers; + }else if(*it == ']')//empty array + { + array_md = array_mode_undifined; + state = match_state_wonder_after_value; + }else if(isalpha(*it) ) + {// array of booleans + std::string word; + match_word2(it, buf_end, word); + if(boost::iequals(word, "true")) + { + h_array = stg.insert_first_value(name, true, current_section); + CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values section entry"); + state = match_state_array_after_value; + array_md = array_mode_booleans; + }else if(boost::iequals(word, "false")) + { + h_array = stg.insert_first_value(name, false, current_section); + CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values section entry"); + state = match_state_array_after_value; + array_md = array_mode_booleans; + + }else ASSERT_MES_AND_THROW("Unknown value keyword " << word) + }else CHECK_ISSPACE(); + break; + case match_state_array_after_value: + if(*it == ',') + state = match_state_array_waiting_value; + else if(*it == ']') + { + h_array = nullptr; + array_md = array_mode_undifined; + state = match_state_wonder_after_value; + }else CHECK_ISSPACE(); + break; + case match_state_array_waiting_value: + switch(array_md) + { + case array_mode_sections: + if(*it == '{') + { + typename t_storage::hsection new_sec = NULL; + bool res = stg.insert_next_section(h_array, new_sec); + CHECK_AND_ASSERT_THROW_MES(res&&new_sec, "failed to insert next section"); + run_handler(new_sec, it, buf_end, stg); + state = match_state_array_after_value; + }else CHECK_ISSPACE(); + break; + case array_mode_string: + if(*it == '"') + { + std::string val; + match_string2(it, buf_end, val); + bool res = stg.insert_next_value(h_array, val); + CHECK_AND_ASSERT_THROW_MES(res, "failed to insert values"); + state = match_state_array_after_value; + }else CHECK_ISSPACE(); + break; + case array_mode_numbers: + if (isdigit(*it) || *it == '-') + {//array of numbers value started + std::string val; + bool is_v_float = false;bool is_signed_val = false; + match_number2(it, buf_end, val, is_v_float, is_signed_val); + bool insert_res = false; + if(!is_v_float) + { + int64_t nval = boost::lexical_cast(val); //bool res = string_tools::string_to_num_fast(val, nval); + insert_res = stg.insert_next_value(h_array, nval); + + }else + { + //TODO: optimize here if need + double nval = boost::lexical_cast(val); //string_tools::string_to_num_fast(val, nval); + insert_res = stg.insert_next_value(h_array, nval); + } + CHECK_AND_ASSERT_THROW_MES(insert_res, "Failed to insert next value"); + state = match_state_array_after_value; + array_md = array_mode_numbers; + }else CHECK_ISSPACE(); + break; + case array_mode_booleans: + if(isalpha(*it) ) + {// array of booleans + std::string word; + match_word2(it, buf_end, word); + if(boost::iequals(word, "true")) + { + bool r = stg.insert_next_value(h_array, true); + CHECK_AND_ASSERT_THROW_MES(r, " failed to insert values section entry"); + state = match_state_array_after_value; + }else if(boost::iequals(word, "false")) + { + bool r = stg.insert_next_value(h_array, false); + CHECK_AND_ASSERT_THROW_MES(r, " failed to insert values section entry"); + state = match_state_array_after_value; + } + else ASSERT_MES_AND_THROW("Unknown value keyword " << word); + }else CHECK_ISSPACE(); + break; + case array_mode_undifined: + default: + ASSERT_MES_AND_THROW("Bad array state"); + } + break; + case match_state_error: + default: + ASSERT_MES_AND_THROW("WRONG JSON STATE"); + } + } + } +/* +{ + "firstName": "John", + "lastName": "Smith", + "age": 25, + "address": { + "streetAddress": "21 2nd Street", + "city": "New York", + "state": "NY", + "postalCode": -10021, + "have_boobs": true, + "have_balls": false + }, + "phoneNumber": [ + { + "type": "home", + "number": "212 555-1234" + }, + { + "type": "fax", + "number": "646 555-4567" + } + ], + "phoneNumbers": [ + "812 123-1234", + "916 123-4567" + ] +} +*/ + template + inline bool load_from_json(const std::string& buff_json, t_storage& stg) + { + std::string::const_iterator sec_buf_begin = buff_json.begin(); + try + { + run_handler(nullptr, sec_buf_begin, buff_json.end(), stg); + return true; + } + catch(const std::exception& ex) + { + LOG_PRINT_RED_L0("Failed to parse json, what: " << ex.what()); + return false; + } + catch(...) + { + LOG_PRINT_RED_L0("Failed to parse json"); + return false; + } + } + } + } +} \ No newline at end of file diff --git a/contrib/epee/include/storages/portable_storage_template_helper.h b/contrib/epee/include/storages/portable_storage_template_helper.h new file mode 100644 index 00000000..4f91e081 --- /dev/null +++ b/contrib/epee/include/storages/portable_storage_template_helper.h @@ -0,0 +1,123 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + +#pragma once +#include "parserse_base_utils.h" +#include "portable_storage.h" +#include "file_io_utils.h" + +namespace epee +{ + namespace serialization + { + //----------------------------------------------------------------------------------------------------------- + template + bool load_t_from_json(t_struct& out, const std::string& json_buff) + { + portable_storage ps; + bool rs = ps.load_from_json(json_buff); + if(!rs) + return false; + + return out.load(ps); + } + //----------------------------------------------------------------------------------------------------------- + template + bool load_t_from_json_file(t_struct& out, const std::string& json_file) + { + std::string f_buff; + if(!file_io_utils::load_file_to_string(json_file, f_buff)) + return false; + + return load_t_from_json(out, f_buff); + } + //----------------------------------------------------------------------------------------------------------- + template + bool store_t_to_json(const t_struct& str_in, std::string& json_buff, size_t indent = 0) + { + portable_storage ps; + str_in.store(ps); + ps.dump_as_json(json_buff, indent); + return true; + } + //----------------------------------------------------------------------------------------------------------- + template + std::string store_t_to_json(const t_struct& str_in, size_t indent = 0) + { + std::string json_buff; + store_t_to_json(str_in, json_buff, indent); + return json_buff; + } + //----------------------------------------------------------------------------------------------------------- + template + bool store_t_to_json_file(const t_struct& str_in, const std::string& fpath) + { + std::string json_buff; + store_t_to_json(str_in, json_buff); + return file_io_utils::save_string_to_file(fpath, json_buff); + } + //----------------------------------------------------------------------------------------------------------- + template + bool load_t_from_binary(t_struct& out, const std::string& binary_buff) + { + portable_storage ps; + bool rs = ps.load_from_binary(binary_buff); + if(!rs) + return false; + + return out.load(ps); + } + //----------------------------------------------------------------------------------------------------------- + template + bool load_t_from_binary_file(t_struct& out, const std::string& binary_file) + { + std::string f_buff; + if(!file_io_utils::load_file_to_string(binary_file, f_buff)) + return false; + + return load_t_from_binary(out, f_buff); + } + //----------------------------------------------------------------------------------------------------------- +PUSH_WARNINGS +DISABLE_VS_WARNINGS(4100) + template + bool store_t_to_binary(const t_struct& str_in, std::string& binary_buff, size_t indent = 0) + { + portable_storage ps; + str_in.store(ps); + return ps.store_to_binary(binary_buff); + } +POP_WARNINGS + //----------------------------------------------------------------------------------------------------------- + template + std::string store_t_to_binary(const t_struct& str_in, size_t indent = 0) + { + std::string binary_buff; + store_t_to_binary(str_in, binary_buff, indent); + return binary_buff; + } + } +} diff --git a/contrib/epee/include/storages/portable_storage_to_bin.h b/contrib/epee/include/storages/portable_storage_to_bin.h new file mode 100644 index 00000000..cb74bc03 --- /dev/null +++ b/contrib/epee/include/storages/portable_storage_to_bin.h @@ -0,0 +1,212 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#pragma once + +#include "misc_language.h" +#include "portable_storage_base.h" + +namespace epee +{ + namespace serialization + { + + template + size_t pack_varint_t(t_stream& strm, uint8_t type_or, size_t& pv) + { + pack_value v = (*((pack_value*)&pv)) << 2; + v |= type_or; + strm.write((const char*)&v, sizeof(pack_value)); + return sizeof(pack_value); + } + + PUSH_WARNINGS + DISABLE_GCC_WARNING(strict-aliasing) + template + size_t pack_varint(t_stream& strm, size_t val) + { //the first two bits always reserved for size information + + if(val <= 63) + {//mean enough one byte + return pack_varint_t(strm, PORTABLE_RAW_SIZE_MARK_BYTE, val); + } + else if(val <= 16383) + {//mean need word + return pack_varint_t(strm, PORTABLE_RAW_SIZE_MARK_WORD, val); + }else if(val <= 1073741823) + {//mean need dword + return pack_varint_t(strm, PORTABLE_RAW_SIZE_MARK_DWORD, val); + }else + { + CHECK_AND_ASSERT_THROW_MES(val <= 4611686018427387903, "failed to pack varint - too big amount = " << val); + return pack_varint_t(strm, PORTABLE_RAW_SIZE_MARK_INT64, val); + } + } + POP_WARNINGS + + template + bool put_string(t_stream& strm, const std::string& v) + { + pack_varint(strm, v.size()); + if(v.size()) + strm.write((const char*)v.data(), v.size()); + return true; + } + + template + struct array_entry_store_visitor: public boost::static_visitor + { + t_stream& m_strm; + + template + bool pack_pod_array_type(uint8_t contained_type, const array_entry_t& arr_pod) + { + uint8_t type = contained_type|SERIALIZE_FLAG_ARRAY; + m_strm.write((const char*)&type, 1); + pack_varint(m_strm, arr_pod.m_array.size()); + for(const t_pod_type& x: arr_pod.m_array) + m_strm.write((const char*)&x, sizeof(t_pod_type)); + return true; + } + + array_entry_store_visitor(t_stream& strm):m_strm(strm){} + bool operator()(const array_entry_t& v){ return pack_pod_array_type(SERIALIZE_TYPE_UINT64, v);} + bool operator()(const array_entry_t& v){ return pack_pod_array_type(SERIALIZE_TYPE_UINT32, v);} + bool operator()(const array_entry_t& v){ return pack_pod_array_type(SERIALIZE_TYPE_UINT16, v);} + bool operator()(const array_entry_t& v) { return pack_pod_array_type(SERIALIZE_TYPE_UINT8, v);} + bool operator()(const array_entry_t& v) { return pack_pod_array_type(SERIALIZE_TYPE_INT64, v);} + bool operator()(const array_entry_t& v) { return pack_pod_array_type(SERIALIZE_TYPE_INT32, v);} + bool operator()(const array_entry_t& v) { return pack_pod_array_type(SERIALIZE_TYPE_INT16, v);} + bool operator()(const array_entry_t& v) { return pack_pod_array_type(SERIALIZE_TYPE_INT8, v);} + bool operator()(const array_entry_t& v) { return pack_pod_array_type(SERIALIZE_TYPE_DUOBLE, v);} + bool operator()(const array_entry_t& v) { return pack_pod_array_type(SERIALIZE_TYPE_BOOL, v);} + bool operator()(const array_entry_t& arr_str) + { + uint8_t type = SERIALIZE_TYPE_STRING|SERIALIZE_FLAG_ARRAY; + m_strm.write((const char*)&type, 1); + pack_varint(m_strm, arr_str.m_array.size()); + for(const std::string& s: arr_str.m_array) + put_string(m_strm, s); + return true; + } + bool operator()(const array_entry_t
& arr_sec) + { + uint8_t type = SERIALIZE_TYPE_OBJECT|SERIALIZE_FLAG_ARRAY; + m_strm.write((const char*)&type, 1); + pack_varint(m_strm, arr_sec.m_array.size()); + for(const section& s: arr_sec.m_array) + pack_entry_to_buff(m_strm, s); + return true; + } + bool operator()(const array_entry_t& arra_ar) + { + uint8_t type = SERIALIZE_TYPE_ARRAY|SERIALIZE_FLAG_ARRAY; + m_strm.write((const char*)&type, 1); + pack_varint(m_strm, arra_ar.m_array.size()); + for(const array_entry& s: arra_ar.m_array) + pack_entry_to_buff(m_strm, s); + return true; + } + }; + + template + struct storage_entry_store_visitor: public boost::static_visitor + { + t_stream& m_strm; + storage_entry_store_visitor(t_stream& strm):m_strm(strm){} + template + bool pack_pod_type(uint8_t type, const pod_type& v) + { + m_strm.write((const char*)&type, 1); + m_strm.write((const char*)&v, sizeof(pod_type)); + return true; + } + //section, array_entry + bool operator()(const uint64_t& v){ return pack_pod_type(SERIALIZE_TYPE_UINT64, v);} + bool operator()(const uint32_t& v){ return pack_pod_type(SERIALIZE_TYPE_UINT32, v);} + bool operator()(const uint16_t& v){ return pack_pod_type(SERIALIZE_TYPE_UINT16, v);} + bool operator()(const uint8_t& v) { return pack_pod_type(SERIALIZE_TYPE_UINT8, v);} + bool operator()(const int64_t& v) { return pack_pod_type(SERIALIZE_TYPE_INT64, v);} + bool operator()(const int32_t& v) { return pack_pod_type(SERIALIZE_TYPE_INT32, v);} + bool operator()(const int16_t& v) { return pack_pod_type(SERIALIZE_TYPE_INT16, v);} + bool operator()(const int8_t& v) { return pack_pod_type(SERIALIZE_TYPE_INT8, v);} + bool operator()(const double& v) { return pack_pod_type(SERIALIZE_TYPE_DUOBLE, v);} + bool operator()(const bool& v) { return pack_pod_type(SERIALIZE_TYPE_BOOL, v);} + bool operator()(const std::string& v) + { + uint8_t type = SERIALIZE_TYPE_STRING; + m_strm.write((const char*)&type, 1); + put_string(m_strm, v); + return true; + } + bool operator()(const section& v) + { + uint8_t type = SERIALIZE_TYPE_OBJECT; + m_strm.write((const char*)&type, 1); + return pack_entry_to_buff(m_strm, v); + } + + bool operator()(const array_entry& v) + { + //uint8_t type = SERIALIZE_TYPE_ARRAY; + //m_strm.write((const char*)&type, 1); + return pack_entry_to_buff(m_strm, v); + } + }; + + template + bool pack_entry_to_buff(t_stream& strm, const array_entry& ae) + { + array_entry_store_visitor aesv(strm); + return boost::apply_visitor(aesv, ae); + } + + template + bool pack_entry_to_buff(t_stream& strm, const storage_entry& se) + { + storage_entry_store_visitor sv(strm); + return boost::apply_visitor(sv, se); + } + + template + bool pack_entry_to_buff(t_stream& strm, const section& sec) + { + typedef std::map::value_type section_pair; + pack_varint(strm, sec.m_entries.size()); + for(const section_pair& se: sec.m_entries) + { + CHECK_AND_ASSERT_THROW_MES(se.first.size() < std::numeric_limits::max(), "storage_entry_name is too long: " << se.first.size() << ", val: " << se.first); + uint8_t len = static_cast(se.first.size()); + strm.write((const char*)&len, sizeof(len)); + strm.write(se.first.data(), size_t(len)); + pack_entry_to_buff(strm, se.second); + } + return true; + } + } +} \ No newline at end of file diff --git a/contrib/epee/include/storages/portable_storage_to_json.h b/contrib/epee/include/storages/portable_storage_to_json.h new file mode 100644 index 00000000..7c22f30c --- /dev/null +++ b/contrib/epee/include/storages/portable_storage_to_json.h @@ -0,0 +1,179 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#pragma once + +#include "misc_language.h" +#include "portable_storage_base.h" + +namespace epee +{ + namespace serialization + { + + template + void dump_as_json(t_stream& strm, const array_entry& ae, size_t indent); + template + void dump_as_json(t_stream& strm, const storage_entry& se, size_t indent); + template + void dump_as_json(t_stream& strm, const std::string& v, size_t indent); + template + void dump_as_json(t_stream& strm, const int8_t& v, size_t indent); + template + void dump_as_json(t_stream& strm, const uint8_t& v, size_t indent); + template + void dump_as_json(t_stream& strm, const bool& v, size_t indent); + template + void dump_as_json(t_stream& strm, const double& v, size_t indent); + template + void dump_as_json(t_stream& strm, const t_type& v, size_t indent); + template + void dump_as_json(t_stream& strm, const section& sec, size_t indent); + + + inline std::string make_indent(size_t indent) + { + return std::string(indent*2, ' '); + } + + template + struct array_entry_store_to_json_visitor: public boost::static_visitor + { + t_stream& m_strm; + size_t m_indent; + array_entry_store_to_json_visitor(t_stream& strm, size_t indent):m_strm(strm), m_indent(indent){} + + template + void operator()(const array_entry_t& a) + { + m_strm << "["; + if(a.m_array.size()) + { + auto last_it = --a.m_array.end(); + for(auto it = a.m_array.begin(); it != a.m_array.end(); it++) + { + dump_as_json(m_strm, *it, m_indent); + if(it != last_it) + m_strm << ","; + } + } + m_strm << "]"; + } + }; + + template + struct storage_entry_store_to_json_visitor: public boost::static_visitor + { + t_stream& m_strm; + size_t m_indent; + storage_entry_store_to_json_visitor(t_stream& strm, size_t indent):m_strm(strm), m_indent(indent) + {} + //section, array_entry + template + void operator()(const visited_type& v) + { + dump_as_json(m_strm, v, m_indent); + } + }; + + template + void dump_as_json(t_stream& strm, const array_entry& ae, size_t indent) + { + array_entry_store_to_json_visitor aesv(strm, indent); + boost::apply_visitor(aesv, ae); + } + + template + void dump_as_json(t_stream& strm, const storage_entry& se, size_t indent) + { + storage_entry_store_to_json_visitor sv(strm, indent); + boost::apply_visitor(sv, se); + } + + template + void dump_as_json(t_stream& strm, const std::string& v, size_t indent) + { + strm << "\"" << misc_utils::parse::transform_to_json_escape_sequence(v) << "\""; + } + + template + void dump_as_json(t_stream& strm, const int8_t& v, size_t indent) + { + strm << static_cast(v); + } + + template + void dump_as_json(t_stream& strm, const uint8_t& v, size_t indent) + { + strm << static_cast(v); + } + + template + void dump_as_json(t_stream& strm, const bool& v, size_t indent) + { + if(v) + strm << "true"; + else + strm << "false"; + } + + template + void dump_as_json(t_stream& strm, const double& v, size_t indent) + { + strm.precision(8); + strm << std::fixed << v; + } + + template + void dump_as_json(t_stream& strm, const t_type& v, size_t /*indent*/) + { + strm << v; + } + + template + void dump_as_json(t_stream& strm, const section& sec, size_t indent) + { + size_t local_indent = indent + 1; + strm << "{\r\n"; + std::string indent_str = make_indent(local_indent); + if(sec.m_entries.size()) + { + auto it_last = --sec.m_entries.end(); + for(auto it = sec.m_entries.begin(); it!= sec.m_entries.end();it++) + { + strm << indent_str << "\"" << misc_utils::parse::transform_to_json_escape_sequence(it->first) << "\"" << ": "; + dump_as_json(strm, it->second, local_indent); + if(it_last != it) + strm << ","; + strm << "\r\n"; + } + } + strm << make_indent(indent) << "}"; + } + } +} diff --git a/contrib/epee/include/storages/portable_storage_val_converters.h b/contrib/epee/include/storages/portable_storage_val_converters.h new file mode 100644 index 00000000..e58ae349 --- /dev/null +++ b/contrib/epee/include/storages/portable_storage_val_converters.h @@ -0,0 +1,177 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#pragma once + +#include "misc_language.h" +#include "portable_storage_base.h" +#include "warnings.h" + +namespace epee +{ + namespace serialization + { +#define ASSERT_AND_THROW_WRONG_CONVERSION() ASSERT_MES_AND_THROW("WRONG DATA CONVERSION: from type=" << typeid(from).name() << " to type " << typeid(to).name()) + + template + void convert_int_to_uint(const from_type& from, to_type& to) + { +PUSH_WARNINGS +DISABLE_VS_WARNINGS(4018) + CHECK_AND_ASSERT_THROW_MES(from >=0, "unexpected int value with signed storage value less than 0, and unsigned receiver value: " << from); +DISABLE_GCC_AND_CLANG_WARNING(sign-compare) + CHECK_AND_ASSERT_THROW_MES(from <= std::numeric_limits::max(), "int value overhead: try to set value " << from << " to type " << typeid(to_type).name() << " with max possible value = " << std::numeric_limits::max()); + to = static_cast(from); +POP_WARNINGS + } + template + void convert_int_to_int(const from_type& from, to_type& to) + { + CHECK_AND_ASSERT_THROW_MES(from >= boost::numeric::bounds::lowest(), "int value overhead: try to set value " << from << " to type " << typeid(to_type).name() << " with lowest possible value = " << boost::numeric::bounds::lowest()); +PUSH_WARNINGS +DISABLE_CLANG_WARNING(tautological-constant-out-of-range-compare) + CHECK_AND_ASSERT_THROW_MES(from <= std::numeric_limits::max(), "int value overhead: try to set value " << from << " to type " << typeid(to_type).name() << " with max possible value = " << std::numeric_limits::max()); +POP_WARNINGS + to = static_cast(from); + } + template + void convert_uint_to_any_int(const from_type& from, to_type& to) + { +PUSH_WARNINGS +DISABLE_VS_WARNINGS(4018) +DISABLE_CLANG_WARNING(tautological-constant-out-of-range-compare) + CHECK_AND_ASSERT_THROW_MES(from <= std::numeric_limits::max(), "uint value overhead: try to set value " << from << " to type " << typeid(to_type).name() << " with max possible value = " << std::numeric_limits::max()); + to = static_cast(from); +POP_WARNINGS + } + + template //is from signed, is from to signed + struct convert_to_signed_unsigned; + + template + struct convert_to_signed_unsigned + { + static void convert(const from_type& from, to_type& to) + {//from signed to signed + convert_int_to_int(from, to); + } + }; + + template + struct convert_to_signed_unsigned + { + static void convert(const from_type& from, to_type& to) + {//from signed to unsigned + convert_int_to_uint(from, to); + } + }; + + template + struct convert_to_signed_unsigned + { + static void convert(const from_type& from, to_type& to) + {//from unsigned to signed + convert_uint_to_any_int(from, to); + } + }; + + template + struct convert_to_signed_unsigned + { + static void convert(const from_type& from, to_type& to) + { + //from unsigned to unsigned + convert_uint_to_any_int(from, to); + } + }; + + template + struct convert_to_integral; + + template + struct convert_to_integral + { + static void convert(const from_type& from, to_type& to) + { + convert_to_signed_unsigned::value, std::is_signed::value>::convert(from, to); + } + }; + + template + struct convert_to_integral + { + static void convert(const from_type& from, to_type& to) + { + ASSERT_AND_THROW_WRONG_CONVERSION(); + } + }; + + template + struct is_convertable: std::integral_constant::value && + std::is_integral::value && + !std::is_same::value && + !std::is_same::value > {}; + + template + struct convert_to_same; + + template + struct convert_to_same + { + static void convert(const from_type& from, to_type& to) + { + to = from; + } + }; + + template + struct convert_to_same + { + static void convert(const from_type& from, to_type& to) + { + convert_to_integral::value>::convert(from, to);// ASSERT_AND_THROW_WRONG_CONVERSION(); + } + }; + + inline void convert_t(const uint64_t& from, double& to) + { + to = static_cast(from); + } + inline void convert_t(const int64_t& from, double& to) + { + to = static_cast(from); + } + + template + void convert_t(const from_type& from, to_type& to) + { + convert_to_same::value>::convert(from, to); + } + } +} \ No newline at end of file diff --git a/contrib/epee/include/string_coding.h b/contrib/epee/include/string_coding.h new file mode 100644 index 00000000..a6d2acf4 --- /dev/null +++ b/contrib/epee/include/string_coding.h @@ -0,0 +1,314 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + +#ifndef _STRING_CODING_H_ +#define _STRING_CODING_H_ + +#include +#include +#include +#ifdef WIN32 + #ifndef NOMINMAX + #define NOMINMAX + #endif + #include +#endif + +namespace epee +{ +namespace string_encoding +{ + + inline std::wstring utf8_to_wstring(const std::string& str) + { + return boost::locale::conv::utf_to_utf(str.c_str(), str.c_str() + str.size()); + } + + inline std::string wstring_to_utf8(const std::wstring& str) + { + return boost::locale::conv::utf_to_utf(str.c_str(), str.c_str() + str.size()); + } + + + + + + inline std::string convert_to_ansii(const std::wstring& str_from) + { + + std::string res(str_from.begin(), str_from.end()); + return res; + } +#ifdef WIN32 + inline std::string convert_to_ansii_win(const std::wstring& str_from) + { + + int code_page = CP_ACP; + std::string str_trgt; + if(!str_from.size()) + return str_trgt; + int cb = ::WideCharToMultiByte( code_page, 0, str_from.data(), (__int32)str_from.size(), 0, 0, 0, 0 ); + if(!cb) + return str_trgt; + str_trgt.resize(cb); + ::WideCharToMultiByte( code_page, 0, str_from.data(), (int)str_from.size(), + (char*)str_trgt.data(), (int)str_trgt.size(), 0, 0); + return str_trgt; + } +#endif + + inline std::string convert_to_ansii(const std::string& str_from) + { + return str_from; + } +#ifdef WIN32 + inline std::wstring convert_to_unicode(const std::string& str_from) + { + std::wstring str_trgt; + if(!str_from.size()) + return str_trgt; + + int cb = ::MultiByteToWideChar(CP_ACP, 0, str_from.data(), (int)str_from.size(), 0, 0); + if(!cb) + return str_trgt; + + str_trgt.resize(cb); + ::MultiByteToWideChar(CP_ACP, 0, str_from.data(), (int)str_from.size(), + (wchar_t*)str_trgt.data(),(int)str_trgt.size()); + return str_trgt; + } +#else + inline std::wstring convert_to_unicode(const std::string& str_from) + { + std::wstring result; + std::locale loc__; + for (unsigned int i = 0; i < str_from.size(); ++i) + { + result += std::use_facet >(loc__).widen(str_from[i]); + } + return result; + } +#endif + inline std::wstring convert_to_unicode(const std::wstring& str_from) + { + return str_from; + } + + template + inline target_string convert_to_t(const std::wstring& str_from); + + template<> + inline std::string convert_to_t(const std::wstring& str_from) + { + return convert_to_ansii(str_from); + } + + template<> + inline std::wstring convert_to_t(const std::wstring& str_from) + { + return str_from; + } + + template + inline target_string convert_to_t(const std::string& str_from); + + template<> + inline std::string convert_to_t(const std::string& str_from) + { + return str_from; + } + + template<> + inline std::wstring convert_to_t(const std::string& str_from) + { + return convert_to_unicode(str_from); + } + +#ifdef WIN32 + inline std::string convert_ansii_to_utf8(const std::string& str_from) + { + try + { + + std::wstring wstr = epee::string_encoding::convert_to_unicode(str_from); + return epee::string_encoding::wstring_to_utf8(wstr); + } + catch(...) + { + return "BAD_CAST"; + } + } +#endif + + inline + std::string& base64_chars() + { + + static std::string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + return chars; + + } + + inline + std::string base64_encode(unsigned char const* bytes_to_encode, size_t in_len) { + std::string ret; + int i = 0; + int j = 0; + unsigned char char_array_3[3]; + unsigned char char_array_4[4]; + + while (in_len--) { + char_array_3[i++] = *(bytes_to_encode++); + if (i == 3) { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for(i = 0; (i <4) ; i++) + ret += base64_chars()[char_array_4[i]]; + i = 0; + } + } + + if (i) + { + for(j = i; j < 3; j++) + char_array_3[j] = '\0'; + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (j = 0; (j < i + 1); j++) + ret += base64_chars()[char_array_4[j]]; + + while((i++ < 3)) + ret += '='; + + } + + return ret; + + } + + inline + std::string base64_encode(const std::string& str) + { + return base64_encode((unsigned char const* )str.data(), str.size()); + } + + inline bool is_base64(unsigned char c) { + return (isalnum(c) || (c == '+') || (c == '/')); + } + + + inline + std::string base64_decode(std::string const& encoded_string) { + size_t in_len = encoded_string.size(); + size_t i = 0; + size_t j = 0; + size_t in_ = 0; + unsigned char char_array_4[4], char_array_3[3]; + std::string ret; + + while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { + char_array_4[i++] = encoded_string[in_]; in_++; + if (i ==4) { + for (i = 0; i <4; i++) + char_array_4[i] = (unsigned char)base64_chars().find(char_array_4[i]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (i = 0; (i < 3); i++) + ret += char_array_3[i]; + i = 0; + } + } + + if (i) { + for (j = i; j <4; j++) + char_array_4[j] = 0; + + for (j = 0; j <4; j++) + char_array_4[j] = (unsigned char)base64_chars().find(char_array_4[j]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; + } + + return ret; + } + + //md5 +#ifdef MD5_H + inline + std::string get_buf_as_hex_string(const void* pbuf, size_t len) + { + std::ostringstream result; + + const unsigned char* p_buff = (const unsigned char*)pbuf; + + for(unsigned int i=0;i(len), output); + return get_buf_as_hex_string(output, sizeof(output)); + } + + inline + std::string get_md5_as_hexstring(const std::string& src) + { + return get_md5_as_hexstring(src.data(), src.size()); + } +#endif + + +} +} + +#endif //_STRING_CODING_H_ diff --git a/contrib/epee/include/string_tools.h b/contrib/epee/include/string_tools.h new file mode 100644 index 00000000..f66abfcf --- /dev/null +++ b/contrib/epee/include/string_tools.h @@ -0,0 +1,807 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#ifndef _STRING_TOOLS_H_ +#define _STRING_TOOLS_H_ + +//#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include "warnings.h" +#include "auto_val_init.h" + + +#ifndef OUT + #define OUT +#endif + +#ifdef WINDOWS_PLATFORM +#pragma comment (lib, "Rpcrt4.lib") +#endif + +namespace epee +{ +namespace string_tools +{ + + + inline std::wstring get_str_from_guid(const boost::uuids::uuid& rid) + { + return boost::lexical_cast(rid); + } + //---------------------------------------------------------------------------- + inline std::string get_str_from_guid_a(const boost::uuids::uuid& rid) + { + return boost::lexical_cast(rid); + } + //---------------------------------------------------------------------------- + inline bool get_guid_from_string( boost::uuids::uuid& inetifer, std::wstring str_id) + { + if(str_id.size() < 36) + return false; + + if('{' == *str_id.begin()) + str_id.erase(0, 1); + + if('}' == *(--str_id.end())) + str_id.erase(--str_id.end()); + + try + { + inetifer = boost::lexical_cast(str_id); + return true; + } + catch(...) + { + return false; + } + } + //---------------------------------------------------------------------------- + inline + std::string get_user_home_dir(std::string path) + { + const char* phomedir = getenv("HOME"); + if (phomedir) + return phomedir; + else + return "~"; + } + //---------------------------------------------------------------------------- + inline bool get_guid_from_string(OUT boost::uuids::uuid& inetifer, const std::string& str_id) + { + std::string local_str_id = str_id; + if(local_str_id.size() < 36) + return false; + + if('{' == *local_str_id.begin()) + local_str_id.erase(0, 1); + + if('}' == *(--local_str_id.end())) + local_str_id.erase(--local_str_id.end()); + + try + { + inetifer = boost::lexical_cast(local_str_id); + return true; + } + catch(...) + { + return false; + } + } + //---------------------------------------------------------------------------- + template< typename T > + std::string int_to_hex(T i) + { + std::stringstream stream; + stream << "0x" + << std::setfill('0') << std::setw(sizeof(T)* 2) + << std::hex << i; + return stream.str(); + } + //---------------------------------------------------------------------------- + template + std::basic_string buff_to_hex(const std::basic_string& s) + { + using namespace std; + basic_stringstream hexStream; + hexStream << hex << noshowbase << setw(2); + + for(typename std::basic_string::const_iterator it = s.begin(); it != s.end(); it++) + { + hexStream << "0x"<< static_cast(static_cast(*it)) << " "; + } + return hexStream.str(); + } + //---------------------------------------------------------------------------- + template + std::basic_string buff_to_hex_nodelimer(const std::basic_string& s) + { + using namespace std; + basic_stringstream hexStream; + hexStream << hex << noshowbase; + + for(typename std::basic_string::const_iterator it = s.begin(); it != s.end(); it++) + { + hexStream << setw(2) << setfill('0') << static_cast(static_cast(*it)); + } + return hexStream.str(); + } + + + //---------------------------------------------------------------------------- + template + bool parse_hexstr_to_binbuff(const std::basic_string& s, std::basic_string& res) + { + res.clear(); + try + { + long v = 0; + for(size_t i = 0; i < (s.size() + 1) / 2; i++) + { + CharT byte_str[3]; + size_t copied = s.copy(byte_str, 2, 2 * i); + byte_str[copied] = CharT(0); + CharT* endptr; + v = strtoul(byte_str, &endptr, 16); + if (v < 0 || 0xFF < v || endptr != byte_str + copied) + { + return false; + } + res.push_back(static_cast(v)); + } + + return true; + }catch(...) + { + return false; + } + } + //---------------------------------------------------------------------------- + template + bool parse_tpod_from_hex_string(const std::string& str_hash, t_pod_type& t_pod) + { + std::string buf; + bool res = epee::string_tools::parse_hexstr_to_binbuff(str_hash, buf); + if (!res || buf.size() != sizeof(t_pod_type)) + { + return false; + } + else + { + buf.copy(reinterpret_cast(&t_pod), sizeof(t_pod_type)); + return true; + } + } + //---------------------------------------------------------------------------- + template + t_pod_type parse_tpod_from_hex_string(const std::string& str_hash) + { + t_pod_type t_pod = AUTO_VAL_INIT(t_pod); + parse_tpod_from_hex_string(str_hash, t_pod); + return t_pod; + } + //---------------------------------------------------------------------------- +PUSH_WARNINGS +DISABLE_GCC_WARNING(maybe-uninitialized) + template + inline bool get_xtype_from_string(OUT XType& val, const std::string& str_id) + { + if (std::is_integral::value && !std::numeric_limits::is_signed && !std::is_same::value) + { + for (char c : str_id) + { + if (!std::isdigit(c)) + return false; + } + } + + try + { + val = boost::lexical_cast(str_id); + return true; + } + catch(std::exception& /*e*/) + { + //const char* pmsg = e.what(); + return false; + } + catch(...) + { + return false; + } + + return true; + } +POP_WARNINGS + //--------------------------------------------------- + template + bool get_xnum_from_hex_string(const std::string str, int_t& res ) + { + try + { + std::stringstream ss; + ss << std::hex << str; + ss >> res; + return true; + } + catch(...) + { + return false; + } + } + //---------------------------------------------------------------------------- + template + inline bool xtype_to_string(const XType& val, std::string& str) + { + try + { + str = boost::lexical_cast(val); + } + catch(...) + { + return false; + } + + return true; + } + + typedef std::map command_line_params_a; + typedef std::map command_line_params_w; + + template + void apped_pod_to_strbuff(std::string& buff, const t_pod_data& pod) + { + buff.append(reinterpret_cast(&pod), sizeof(pod)); + } + + + + template + bool parse_commandline(std::map& res, int argc, char** argv) + { + t_string key; + for(int i = 1; i < argc; i++) + { + if(!argv[i]) + break; + t_string s = argv[i]; + std::string::size_type p = s.find('='); + if(std::string::npos == p) + { + res[s] = ""; + }else + { + std::string ss; + t_string nm = s.substr(0, p); + t_string vl = s.substr(p+1, s.size()); + res[nm] = vl; + } + } + return true; + } + +/* template + bool get_xparam_from_command_line(const std::map& res, const std::basic_string & key, t_type& val) + { + + } + */ + + template + bool get_xparam_from_command_line(const std::map& res, const t_string & key, t_type& val) + { + typename std::map::const_iterator it = res.find(key); + if(it == res.end()) + return false; + + if(it->second.size()) + { + return get_xtype_from_string(val, it->second); + } + + return true; + } + + template + t_type get_xparam_from_command_line(const std::map& res, const t_string & key, const t_type& default_value) + { + typename std::map::const_iterator it = res.find(key); + if(it == res.end()) + return default_value; + + if(it->second.size()) + { + t_type s; + get_xtype_from_string(s, it->second); + return s; + } + + return default_value; + } + + template + bool have_in_command_line(const std::map& res, const std::basic_string& key) + { + typename std::map::const_iterator it = res.find(key); + if(it == res.end()) + return false; + + return true; + } + + //---------------------------------------------------------------------------- +//#ifdef _WINSOCK2API_ + inline std::string get_ip_string_from_int32(uint32_t ip) + { + in_addr adr; + adr.s_addr = ip; + const char* pbuf = inet_ntoa(adr); + if(pbuf) + return pbuf; + else + return "[failed]"; + } + //---------------------------------------------------------------------------- + inline bool get_ip_int32_from_string(uint32_t& ip, const std::string& ip_str) + { + ip = inet_addr(ip_str.c_str()); + if(INADDR_NONE == ip) + return false; + + return true; + } + //---------------------------------------------------------------------------- + inline bool parse_peer_from_string(uint32_t& ip, uint32_t& port, const std::string& addres) + { + //parse ip and address + std::string::size_type p = addres.find(':'); + if(p == std::string::npos) + { + return false; + } + std::string ip_str = addres.substr(0, p); + std::string port_str = addres.substr(p+1, addres.size()); + + if(!get_ip_int32_from_string(ip, ip_str)) + { + return false; + } + + if(!get_xtype_from_string(port, port_str)) + { + return false; + } + return true; + } + +//#endif + //---------------------------------------------------------------------------- + template + inline std::string get_t_as_hex_nwidth(const t& v, std::streamsize w = 8) + { + std::stringstream ss; + ss << std::setfill ('0') << std::setw (w) << std::hex << std::noshowbase; + ss << v; + return ss.str(); + } + + inline std::string num_to_string_fast(int64_t val) + { + /* + char buff[30] = {0}; + i64toa_s(val, buff, sizeof(buff)-1, 10); + return buff;*/ + return boost::lexical_cast(val); + } + //---------------------------------------------------------------------------- + inline bool string_to_num_fast(const std::string& buff, int64_t& val) + { + //return get_xtype_from_string(val, buff); +#if (defined _MSC_VER) + val = _atoi64(buff.c_str()); +#else + val = atoll(buff.c_str()); +#endif + /* + * val = atoi64(buff.c_str()); + */ + if(buff != "0" && val == 0) + return false; + return true; + } + //---------------------------------------------------------------------------- + inline bool string_to_num_fast(const std::string& buff, int& val) + { + val = atoi(buff.c_str()); + if(buff != "0" && val == 0) + return false; + + return true; + } + //---------------------------------------------------------------------------- +#ifdef WINDOWS_PLATFORM + inline std::string system_time_to_string(const SYSTEMTIME& st) + { + + /* + TIME_ZONE_INFORMATION tzi; + GetTimeZoneInformation(&tzi); + SystemTimeToTzSpecificLocalTime(&tzi, &stUTC, &stLocal); + */ + + char szTime[25], szDate[25]; + ::GetTimeFormatA( + LOCALE_USER_DEFAULT, // locale + TIME_FORCE24HOURFORMAT, // options + &st, // time + NULL, // time format string + szTime, // formatted string buffer + 25 // size of string buffer + ); + + ::GetDateFormatA( + LOCALE_USER_DEFAULT, // locale + NULL, // options + &st, // date + NULL, // date format + szDate, // formatted string buffer + 25 // size of buffer + ); + szTime[24] = szDate[24] = 0; //be happy :) + + std::string res = szDate; + (res += " " )+= szTime; + return res; + + } +#endif + //---------------------------------------------------------------------------- + + inline bool compare_no_case(const std::string& str1, const std::string& str2) + { + + return !boost::iequals(str1, str2); + } + //---------------------------------------------------------------------------- + inline bool compare_no_case(const std::wstring& str1, const std::wstring& str2) + { + return !boost::iequals(str1, str2); + } + //---------------------------------------------------------------------------- + inline bool is_match_prefix(const std::wstring& str1, const std::wstring& prefix) + { + if(prefix.size()>str1.size()) + return false; + + if(!compare_no_case(str1.substr(0, prefix.size()), prefix)) + return true; + else + return false; + } + //---------------------------------------------------------------------------- + inline bool is_match_prefix(const std::string& str1, const std::string& prefix) + { + if(prefix.size()>str1.size()) + return false; + + if(!compare_no_case(str1.substr(0, prefix.size()), prefix)) + return true; + else + return false; + } + //---------------------------------------------------------------------------- + inline std::string& get_current_module_name() + { + static std::string module_name; + return module_name; + } + //---------------------------------------------------------------------------- + inline std::string& get_current_module_folder() + { + static std::string module_folder; + return module_folder; + } + //---------------------------------------------------------------------------- +#ifdef _WIN32 + inline std::string get_current_module_path() + { + char pname [5000] = {0}; + GetModuleFileNameA( NULL, pname, sizeof(pname)); + pname[sizeof(pname)-1] = 0; //be happy ;) + return pname; + } +#endif + //---------------------------------------------------------------------------- + inline bool set_module_name_and_folder(const std::string& path_to_process_) + { + std::string path_to_process = path_to_process_; + boost::system::error_code ec; + path_to_process = boost::filesystem::canonical(path_to_process, ec).string(); + #ifdef _WIN32 + path_to_process = get_current_module_path(); + #endif + std::string::size_type a = path_to_process.rfind( '\\' ); + if(a == std::string::npos ) + { + a = path_to_process.rfind( '/' ); + } + if ( a != std::string::npos ) + { + get_current_module_name() = path_to_process.substr(a+1, path_to_process.size()); + get_current_module_folder() = path_to_process.substr(0, a); + return true; + }else + return false; + + } + //---------------------------------------------------------------------------- + inline bool trim_left(std::string& str) + { + for(std::string::iterator it = str.begin(); it!= str.end() && isspace(static_cast(*it));) + str.erase(str.begin()); + + return true; + } + //---------------------------------------------------------------------------- + inline bool trim_right(std::string& str) + { + + for(std::string::reverse_iterator it = str.rbegin(); it!= str.rend() && isspace(static_cast(*it));) + str.erase( --((it++).base())); + + return true; + } + //---------------------------------------------------------------------------- + inline std::string& trim(std::string& str) + { + + trim_left(str); + trim_right(str); + return str; + } + //---------------------------------------------------------------------------- + inline std::string trim(const std::string& str_) + { + std::string str = str_; + trim_left(str); + trim_right(str); + return str; + } + //---------------------------------------------------------------------------- + template + std::string pod_to_hex(const t_pod_type& s) + { + std::string buff; + buff.assign(reinterpret_cast(&s), sizeof(s)); + return buff_to_hex_nodelimer(buff); + } + //---------------------------------------------------------------------------- + template + bool hex_to_pod(const std::string& hex_str, t_pod_type& s) + { + std::string hex_str_tr = trim(hex_str); + if(sizeof(s)*2 != hex_str.size()) + return false; + std::string bin_buff; + if(!parse_hexstr_to_binbuff(hex_str_tr, bin_buff)) + return false; + if(bin_buff.size()!=sizeof(s)) + return false; + + s = *(t_pod_type*)bin_buff.data(); + return true; + } + //---------------------------------------------------------------------------- + inline std::string get_extension(const std::string& str) + { + std::string res; + std::string::size_type pos = str.rfind('.'); + if(std::string::npos == pos) + return res; + + res = str.substr(pos+1, str.size()-pos); + return res; + } + //---------------------------------------------------------------------------- + inline std::string get_filename_from_path(const std::string& str) + { + std::string res; + std::string::size_type pos = str.rfind('\\'); + if(std::string::npos == pos) + return str; + + res = str.substr(pos+1, str.size()-pos); + return res; + } + //---------------------------------------------------------------------------- + + + + inline std::string cut_off_extension(const std::string& str) + { + std::string res; + std::string::size_type pos = str.rfind('.'); + if(std::string::npos == pos) + return str; + + res = str.substr(0, pos); + return res; + } + + //---------------------------------------------------------------------------- + // replaces all non-ascii characters with mask_character + inline std::string mask_non_ascii_chars(const std::string& str, const char mask_character = '?') + { + std::string result; + result.reserve(str.size()); + for (char c : str) + { + if ((unsigned char)c >= (unsigned char)' ' && + (unsigned char)c <= (unsigned char)'~') + { + result += c; + } + else + { + result += mask_character; + } + } + return result; + } + //---------------------------------------------------------------------------- +#ifdef _WININET_ + inline std::string get_string_from_systemtime(const SYSTEMTIME& sys_time) + { + std::string result_string; + + char buff[100] = {0}; + BOOL res = ::InternetTimeFromSystemTimeA(&sys_time, INTERNET_RFC1123_FORMAT, buff, 99); + if(!res) + { + LOG_ERROR("Failed to load SytemTime to string"); + } + + result_string = buff; + return result_string; + + } + //------------------------------------------------------------------------------------- + inline SYSTEMTIME get_systemtime_from_string(const std::string& buff) + { + SYSTEMTIME result_time = {0}; + + BOOL res = ::InternetTimeToSystemTimeA(buff.c_str(), &result_time, NULL); + if(!res) + { + LOG_ERROR("Failed to load SytemTime from string " << buff << "interval set to 15 minutes"); + } + + return result_time; + } +#endif + +#ifdef WINDOWS_PLATFORM + static const DWORD INFO_BUFFER_SIZE = 10000; + + static const wchar_t* get_pc_name() + { + static wchar_t info[INFO_BUFFER_SIZE]; + static DWORD bufCharCount = INFO_BUFFER_SIZE; + static bool init = false; + + if (!init) { + if (!GetComputerNameW( info, &bufCharCount )) + info[0] = 0; + else + init = true; + } + + return info; + } + + static const wchar_t* get_user_name() + { + static wchar_t info[INFO_BUFFER_SIZE]; + static DWORD bufCharCount = INFO_BUFFER_SIZE; + static bool init = false; + + if (!init) { + if (!GetUserNameW( info, &bufCharCount )) + info[0] = 0; + else + init = true; + } + + return info; + } +#endif + +#ifdef _LM_ + static const wchar_t* get_domain_name() + { + static wchar_t info[INFO_BUFFER_SIZE]; + static DWORD bufCharCount = 0; + static bool init = false; + + if (!init) { + LPWSTR domain( NULL ); + NETSETUP_JOIN_STATUS status; + info[0] = 0; + + if (NET_API_STATUS result = NetGetJoinInformation( NULL, &domain, &status )) + { + LOG_ERROR("get_domain_name error: " << log_space::get_win32_err_descr(result)); + } else + { + StringCchCopyW( info, sizeof(info)/sizeof( info[0] ), domain ); + NetApiBufferFree((void*)domain); + init = true; + } + } + + return info; + } +#endif +#ifdef WINDOWS_PLATFORM + inline + std::string load_resource_string_a(int id, const char* pmodule_name = NULL) + { + //slow realization + HMODULE h = ::GetModuleHandleA( pmodule_name ); + + char buff[2000] = {0}; + + ::LoadStringA( h, id, buff, sizeof(buff)); + buff[sizeof(buff)-1] = 0; //be happy :) + return buff; + } + inline + std::wstring load_resource_string_w(int id, const char* pmodule_name = NULL) + { + //slow realization + HMODULE h = ::GetModuleHandleA( pmodule_name ); + + wchar_t buff[2000] = {0}; + + ::LoadStringW( h, id, buff, sizeof(buff) / sizeof( buff[0] ) ); + buff[(sizeof(buff)/sizeof(buff[0]))-1] = 0; //be happy :) + return buff; + } +#endif +} +} +#endif //_STRING_TOOLS_H_ diff --git a/contrib/epee/include/sync_locked_object.h b/contrib/epee/include/sync_locked_object.h new file mode 100644 index 00000000..1a60b7dc --- /dev/null +++ b/contrib/epee/include/sync_locked_object.h @@ -0,0 +1,114 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#pragma once + +#include "syncobj.h" +#include "misc_log_ex.h" + +namespace epee +{ + /************************************************************************/ + /* */ + /************************************************************************/ + struct default_lock_time_watching_policy + { + inline static void watch_lock_time(uint64_t lock_time) {} + }; + + template + class locked_object_proxy + { + uint64_t start_lock_time; + t_object& rt; + std::unique_lock lock; + public: + locked_object_proxy(t_object& t, std::recursive_mutex& m) :rt(t), lock(m), start_lock_time(epee::misc_utils::get_tick_count()) + {} + locked_object_proxy(const locked_object_proxy& lop) :rt(lop.rt), lock(*lop.lock.mutex()), start_lock_time(epee::misc_utils::get_tick_count()) + {} + ~locked_object_proxy() + { + uint64_t lock_time = epee::misc_utils::get_tick_count() - start_lock_time; + lock_time_watching_policy::watch_lock_time(lock_time); + } + + /* + t_object& operator()() + { + return rt; + }*/ + t_object* operator ->() + { + return &rt; + } + t_object& operator *() + { + return rt; + } + }; + + template + class locked_object + { + + t_object t; + std::recursive_mutex m; + template + friend class locked_object_proxy; + public: + std::shared_ptr> try_lock() + { + std::shared_ptr> res; + if (CRITICAL_SECTION_TRY_LOCK(m)) + { + res.reset(new locked_object_proxy(t, m)); + CRITICAL_SECTION_UNLOCK(m); + } + return res; + } + t_object& unlocked_get() + { + return t; + } + + locked_object_proxy operator->() + { + return locked_object_proxy(t, m); + } + locked_object_proxy operator*() + { + return locked_object_proxy(t, m); + } + + /*locked_object_proxy operator()() + { + return locked_object_proxy(t, m); + }*/ + }; +} \ No newline at end of file diff --git a/contrib/epee/include/syncobj.h b/contrib/epee/include/syncobj.h new file mode 100644 index 00000000..f20bff07 --- /dev/null +++ b/contrib/epee/include/syncobj.h @@ -0,0 +1,709 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + + +#ifndef __WINH_OBJ_H__ +#define __WINH_OBJ_H__ +#include +#include +#include +#include +#include +#include +#include + +#include "singleton.h" +#include "static_initializer.h" + + +//#define DISABLE_DEADLOCK_GUARD + + +#define VALIDATE_MUTEX_IS_FREE(mutex_mame) \ + if (mutex_mame.try_lock()) \ + { \ + mutex_mame.unlock(); \ + return; \ + } \ + else \ + { \ + LOG_ERROR("MUTEX IS NOT FREE ON DESTRUCTOR: " << #mutex_mame); \ + } + + + + + +namespace epee +{ + + struct simple_event + { + simple_event() : m_rised(false) + { + } + + void raise() + { + std::unique_lock lock(m_mx); + m_rised = true; + m_cond_var.notify_one(); + } + + void wait() + { + std::unique_lock lock(m_mx); + while (!m_rised) + m_cond_var.wait(lock); + m_rised = false; + } + + private: + std::mutex m_mx; + std::condition_variable m_cond_var; + bool m_rised; + }; + + + class critical_region; + + class critical_section + { + boost::recursive_mutex m_section; + + public: + //to make copy fake! + critical_section(const critical_section& section) + { + } + + critical_section() + { + } + + ~critical_section() + { + } + + void lock() + { + m_section.lock(); + //EnterCriticalSection( &m_section ); + } + + void unlock() + { + m_section.unlock(); + } + + bool try_lock() + { + return m_section.try_lock(); + } + + // to make copy fake + critical_section& operator=(const critical_section& section) + { + return *this; + } + }; + + class dummy_critical_section + { + + public: + //to make copy fake! + dummy_critical_section(const critical_section& section) + { + } + dummy_critical_section() + { + } + ~dummy_critical_section() + { + } + void lock(){} + void unlock(){} + void lock_exclusive(){} + void unlock_exclusive(){} + + bool tryLock(){ return true; } + + // to make copy fake + dummy_critical_section& operator=(const dummy_critical_section& section) + { + return *this; + } + }; + + + + + template + class critical_region_t + { + t_lock& m_locker; + bool m_unlocked; + + critical_region_t(const critical_region_t&) {} + + public: + critical_region_t(t_lock& cs): m_locker(cs), m_unlocked(false) + { + m_locker.lock(); + } + + ~critical_region_t() + { + unlock(); + } + + void unlock() + { + if (!m_unlocked) + { + m_locker.unlock(); + m_unlocked = true; + } + } + }; + + + +#if defined(WINDWOS_PLATFORM) + class shared_critical_section + { + public: + shared_critical_section() + { + ::InitializeSRWLock(&m_srw_lock); + } + ~shared_critical_section() + {} + + bool lock_shared() + { + AcquireSRWLockShared(&m_srw_lock); + return true; + } + bool unlock_shared() + { + ReleaseSRWLockShared(&m_srw_lock); + return true; + } + bool lock_exclusive() + { + ::AcquireSRWLockExclusive(&m_srw_lock); + return true; + } + bool unlock_exclusive() + { + ::ReleaseSRWLockExclusive(&m_srw_lock); + return true; + } + private: + SRWLOCK m_srw_lock; + }; + + + class shared_guard + { + public: + shared_guard(shared_critical_section& ref_sec):m_ref_sec(ref_sec) + { + m_ref_sec.lock_shared(); + } + + ~shared_guard() + { + m_ref_sec.unlock_shared(); + } + + private: + shared_critical_section& m_ref_sec; + }; + + + class exclusive_guard + { + public: + exclusive_guard(shared_critical_section& ref_sec):m_ref_sec(ref_sec) + { + m_ref_sec.lock_exclusive(); + } + + ~exclusive_guard() + { + m_ref_sec.unlock_exclusive(); + } + + private: + shared_critical_section& m_ref_sec; + }; + +#endif + + + + + +#if defined(WINDWOS_PLATFORM) + inline const char* get_wait_for_result_as_text(DWORD res) + { + switch(res) + { + case WAIT_ABANDONED: return "WAIT_ABANDONED"; + case WAIT_TIMEOUT: return "WAIT_TIMEOUT"; + case WAIT_OBJECT_0: return "WAIT_OBJECT_0"; + case WAIT_OBJECT_0+1: return "WAIT_OBJECT_1"; + case WAIT_OBJECT_0+2: return "WAIT_OBJECT_2"; + default: return "UNKNOWN CODE"; + } + } +#endif + +#ifdef ENABLE_DLG_DEBUG_MESSAGES +#define DO_DEBUG_COUT(mes) std::cout << mes; +#else +#define DO_DEBUG_COUT(mes) +#endif + +#define POTENTIAL_HANG_PREVENT_LIMIT 1000 + + + + /************************************************************************/ + /* */ + /************************************************************************/ + class deadlock_guard + { + public: + typedef void* lock_reference_type; + private: + struct thread_info + { + std::map m_owned_objects; + bool is_blocked; + lock_reference_type blocker_lock; + const char* block_location; + const char* func_name; + const char* lock_name; + std::string thread_name; + }; + + std::recursive_mutex m_lock; + + //thread_id -> owned locks(lock_id, recursion_count) + typedef std::map thread_id_to_info_map; + std::map m_thread_owned_locks; + //lock -> owner thread it + std::map m_owned_locks_to_thread; + // deadlock journal + std::list m_deadlock_journal; + + public: + void on_before_lock(lock_reference_type lock, const char* func_name, const char* loction, const char* lock_name, const std::string& thread_name) + { + std::lock_guard gd(m_lock); + DO_DEBUG_COUT("[" << std::this_thread::get_id() << "][BEFORE_LOCK]:" << lock << std::endl); + std::thread::id this_id = std::this_thread::get_id(); + is_lock_safe(lock, this_id, func_name, loction, lock_name, thread_name);//can return only true, if false throw exception + + thread_info& ti = m_thread_owned_locks[this_id]; + ti.is_blocked = true; + ti.blocker_lock = lock; + ti.block_location = loction; + ti.func_name = func_name; + ti.lock_name = lock_name; + ti.thread_name = thread_name; + } + void on_after_lock(lock_reference_type lock) + { + std::lock_guard gd(m_lock); + DO_DEBUG_COUT("[" << std::this_thread::get_id() << "][AFTER_LOCK]:" << lock << std::endl); + add_ownership(lock); + } + + void on_unlock(lock_reference_type lock) + { + std::lock_guard gd(m_lock); + DO_DEBUG_COUT("[" << std::this_thread::get_id() << "][UNLOCK]:" << lock << std::endl); + std::thread::id this_id = std::this_thread::get_id(); + auto it = m_thread_owned_locks.find(this_id); + if (it == m_thread_owned_locks.end()) + { + throw std::runtime_error("Internal error: unknown thread is unlocking mutex"); + } + + if (it->second.is_blocked) + { + throw std::runtime_error("Internal error: thread is trying to unlock while is_blocked = true"); + } + auto ownership_it = it->second.m_owned_objects.find(lock); + if (ownership_it == it->second.m_owned_objects.end()) + { + throw std::runtime_error("Internal error: can't find ownership for locker on unlock"); + } + + ownership_it->second--; + if (!ownership_it->second) + { + // ownership liquidation + auto lock_to_thread_it = m_owned_locks_to_thread.find(lock); + if (lock_to_thread_it == m_owned_locks_to_thread.end()) + { + throw std::runtime_error("Internal error: can't find ownership for locker on unlock"); + } + else + { + m_owned_locks_to_thread.erase(lock_to_thread_it); + } + it->second.m_owned_objects.erase(ownership_it); + DO_DEBUG_COUT("[" << std::this_thread::get_id() << "][REMOVED_OWNERSHIP]: " << lock << std::endl); + } + } + + std::string get_dlg_state() + { + std::lock_guard gd(m_lock); + std::stringstream ss; + ss << "Threads lockers ownership:" << std::endl; + for (auto& tol : m_thread_owned_locks) + { + ss << tol.second.thread_name << "(tid:" << tol.first << ") owned: "; + for (auto& owned_obj: tol.second.m_owned_objects) + { + ss << "(" << owned_obj.first << ":" << owned_obj.second << ")"; + } + if (tol.second.is_blocked) + { + ss << "BLOCKED BY: \"" << tol.second.lock_name << "\"(" << tol.second.blocker_lock << ") at " << tol.second.func_name << " @ " << tol.second.block_location; + } + ss << std::endl; + } + + ss << "Lockers to threads links:" << std::endl; + for(auto& lock_to_thread: m_owned_locks_to_thread) + { + ss << "locker: " << lock_to_thread.first << " owned by " << lock_to_thread.second->first << std::endl; + } + ss << "Deadlocks history:" << std::endl; + for (auto err : m_deadlock_journal) + { + ss << "-----------------------------------------------------------------------" << std::endl << err << std::endl; + } + + return ss.str(); + } + + std::list get_deadlock_journal() + { + return m_deadlock_journal; + } + + private: + void add_ownership(lock_reference_type lock) + { + std::thread::id this_id = std::this_thread::get_id(); + auto it = m_thread_owned_locks.find(this_id); + if (it == m_thread_owned_locks.end()) + { + // it's ok, probably someone used try_lock and didn't call on_before_lock + auto r = m_thread_owned_locks.insert(std::make_pair(this_id, thread_info())); + it = r.first; + } + thread_info& ti = it->second; + ti.is_blocked = false; + auto lock_it = ti.m_owned_objects.find(lock); + if (lock_it == ti.m_owned_objects.end()) + { + //non-recursive ownership + ti.m_owned_objects[lock] = 1; + //need to add lock-to-thread reccord + m_owned_locks_to_thread[lock] = it; + DO_DEBUG_COUT("[" << std::this_thread::get_id() << "][ADDED_OWNERSHIP]: " << lock << std::endl); + } + else + { + lock_it->second++; + DO_DEBUG_COUT("[" << std::this_thread::get_id() << "][INC_OWNERSHIP]: " << lock << std::endl); + } + } + + bool is_lock_safe(lock_reference_type lock, const std::thread::id& this_id, const char* func_name, const char* location, const char* lock_name, const std::string& thread_name) + { + //lookup if this lock is already owned by someone + auto it_th_owned_locks = m_thread_owned_locks.find(this_id); + if (it_th_owned_locks == m_thread_owned_locks.end()) + { + return true; + } + //we already own some locks, let's figure out if this lock is owned by someone + auto it_to_owner_thread = m_owned_locks_to_thread.find(lock); + if (it_to_owner_thread == m_owned_locks_to_thread.end() || it_to_owner_thread->second->first == this_id) + { + //lock is free or owned by this thread + return true; + } + std::listsecond)> threads_chain; + threads_chain.push_back(it_to_owner_thread->second); + + //lookup loop + while (true) + { + if (!it_to_owner_thread->second->second.is_blocked) + { + return true; + } + if (it_to_owner_thread->second->second.m_owned_objects.count(it_to_owner_thread->second->second.blocker_lock)) + { + //recursive lock is happening + return true; + } + + auto new_it_to_owner_thread = m_owned_locks_to_thread.find(it_to_owner_thread->second->second.blocker_lock); + if (new_it_to_owner_thread == m_owned_locks_to_thread.end()) + { + //this could happen when on_before_lock already worked and on_after_lock not called yet, but mutex itself is free, + //still theoretically possible deadlock that can be missed(or not ?) + return true; + } + if (it_to_owner_thread == new_it_to_owner_thread) + { + //newer should happen + throw std::runtime_error("Internal error: thread referred to itself, despite the the check in m_owned_locks_to_thread.find(it_to_owner_thread->second->second.blocker_lock); "); + } + it_to_owner_thread = new_it_to_owner_thread; + + threads_chain.push_back(it_to_owner_thread->second); + if (threads_chain.size() > POTENTIAL_HANG_PREVENT_LIMIT) + { + throw std::runtime_error("Internal error: threads_chain size is too big, endless loop detected"); + } + if (it_to_owner_thread->second->first == this_id) + { + //got deadlock! + std::stringstream ss; + ss << "Deadlock detected at: " << std::endl << std::endl; + auto prev_it = m_thread_owned_locks.end(); + auto current_it = *threads_chain.begin(); + for (auto it = threads_chain.begin(); it != threads_chain.end(); it++) + { + current_it = *it; + if (prev_it == m_thread_owned_locks.end()) + { + prev_it = current_it; + continue; + } + ss << prev_it->second.thread_name << "(tid:" << prev_it->first << ") blocked by locker \"" << prev_it->second.lock_name + << "\"(owned by " << current_it->second.thread_name << " tid:" << current_it->first << ")] at " + << prev_it->second.func_name << " @ " << prev_it->second.block_location << std::endl << " |" << std::endl << " V" << std::endl; + prev_it = current_it; + } + + ss << prev_it->second.thread_name << "(tid:" << prev_it->first << ") blocked by locker \"" << lock_name << "(owned by " << (*threads_chain.begin())->second.thread_name << " tid:" << (*threads_chain.begin())->first << ")] at " + << func_name << " @ " << location << std::endl; + m_deadlock_journal.push_back(ss.str()); + throw std::runtime_error(ss.str()); + } + + } + } + }; + + const static initializer > singleton_initializer; + + /************************************************************************/ + /* */ + /************************************************************************/ + class deadlock_guard_singleton + { + public: + static void on_before_lock(deadlock_guard::lock_reference_type lock, const char* func_name, const char* loction, const char* lock_name, const std::string& thread_name) + { + auto dlg_ptr = abstract_singleton::get_instance(); + if (dlg_ptr) + dlg_ptr->on_before_lock(lock, func_name, loction, lock_name, thread_name); + } + static void on_after_lock(deadlock_guard::lock_reference_type lock) + { + auto dlg_ptr = abstract_singleton::get_instance(); + if (dlg_ptr) + dlg_ptr->on_after_lock(lock); + } + static void on_unlock(deadlock_guard::lock_reference_type lock) + { + auto dlg_ptr = abstract_singleton::get_instance(); + if (dlg_ptr) + dlg_ptr->on_unlock(lock); + } + + static std::string get_dlg_state() + { + auto dlg_ptr = abstract_singleton::get_instance(); + if (dlg_ptr) + return dlg_ptr->get_dlg_state(); + return ""; + } + + static std::list get_deadlock_journal() + { + auto dlg_ptr = abstract_singleton::get_instance(); + if (dlg_ptr) + return dlg_ptr->get_deadlock_journal(); + return std::list(); + } + }; + + + + /************************************************************************/ + /* */ + /************************************************************************/ + + template + class guarded_critical_region_t + { + t_lock& m_locker; + std::atomic m_unlocked; + + guarded_critical_region_t(const guarded_critical_region_t&) {} + + public: + guarded_critical_region_t(t_lock& cs, const char* func_name, const char* location, const char* lock_name, const std::string& thread_name) : m_locker(cs), m_unlocked(false) + { + deadlock_guard_singleton::on_before_lock(&m_locker, func_name, location, lock_name, thread_name); + m_locker.lock(); + deadlock_guard_singleton::on_after_lock(&m_locker); + } + + ~guarded_critical_region_t() + { + unlock(); + + } + + void unlock() + { + if (!m_unlocked) + { + deadlock_guard_singleton::on_unlock(&m_locker); + m_locker.unlock(); + m_unlocked = true; + } + } + }; + + template + inline bool dlg_try_lock_locker(locker_t& lock) + { + bool res = lock.try_lock(); + if (res) + { + deadlock_guard_singleton::on_after_lock(&lock); + } + return res; + } + + + +#define _DEADLOCK_STRINGIFY(X) #X +#define DEADLOCK_STRINGIFY(X) _DEADLOCK_STRINGIFY(X) + +#if defined(_MSC_VER) +#define DEADLOCK_FUNCTION_DEF __FUNCTION__ +#else +#define DEADLOCK_FUNCTION_DEF __PRETTY_FUNCTION__ +#endif + +#define DEADLOCK_LOCATION __FILE__ ":" DEADLOCK_STRINGIFY(__LINE__) + +/* + + We do DEADLOCK_LOCATION and DEADLOCK_FUNCTION_DEF as separate variables passed into deadlock_guard + because in GCC __PRETTY_FUNCTION__ is not a literal (like __FILE__ macro) but const variable, and + can't concatenate it with other macro like we did in DEADLOCK_LOCATION. + +*/ + +#define DLG_CRITICAL_REGION_LOCAL_VAR(lock, varname) epee::guarded_critical_region_t varname(lock, DEADLOCK_FUNCTION_DEF, DEADLOCK_LOCATION, #lock, epee::log_space::log_singletone::get_thread_log_prefix()) +#define DLG_CRITICAL_REGION_BEGIN_VAR(lock, varname) { epee::guarded_critical_region_t varname(lock, DEADLOCK_FUNCTION_DEF, DEADLOCK_LOCATION, #lock, epee::log_space::log_singletone::get_thread_log_prefix()) + +#define DLG_CRITICAL_SECTION_LOCK(lck) epee::deadlock_guard_singleton::on_before_lock(&lck, DEADLOCK_FUNCTION_DEF, DEADLOCK_LOCATION, #lck, epee::log_space::log_singletone::get_thread_log_prefix());\ + lck.lock();\ + epee::deadlock_guard_singleton::on_after_lock(&lck) + +#define DLG_CRITICAL_SECTION_TRY_LOCK(lock) dlg_try_lock_locker(lock) + +#define DLG_CRITICAL_SECTION_UNLOCK(lock) epee::deadlock_guard_singleton::on_unlock(&lock);\ + lock.unlock(); + + + +#define FAST_CRITICAL_REGION_LOCAL_VAR(x, varname) epee::critical_region_t varname(x) +#define FAST_CRITICAL_REGION_BEGIN_VAR(x, varname) {epee::critical_region_t varname(x) +#define FAST_CRITICAL_REGION_LOCAL(x) FAST_CRITICAL_REGION_LOCAL_VAR(x, critical_region_var) +#define FAST_CRITICAL_REGION_BEGIN(x) FAST_CRITICAL_REGION_BEGIN_VAR(x, critical_region_var) +#define FAST_CRITICAL_REGION_END() } + +#define FAST_CRITICAL_SECTION_LOCK(x) x.lock() +#define FAST_CRITICAL_SECTION_TRY_LOCK(x) x.try_lock() +#define FAST_CRITICAL_SECTION_UNLOCK(x) x.unlock() + + +//#define DISABLE_DEADLOCK_GUARD + +#ifdef DISABLE_DEADLOCK_GUARD +#define CRITICAL_REGION_LOCAL_VAR(x, varname) FAST_CRITICAL_REGION_LOCAL_VAR(x, varname) +#define CRITICAL_REGION_BEGIN_VAR(x, varname) FAST_CRITICAL_REGION_BEGIN_VAR(x, varname) + +#define CRITICAL_SECTION_LOCK(x) FAST_CRITICAL_SECTION_LOCK(x) +#define CRITICAL_SECTION_TRY_LOCK(x) FAST_CRITICAL_SECTION_TRY_LOCK(x) +#define CRITICAL_SECTION_UNLOCK(x) FAST_CRITICAL_SECTION_UNLOCK(x) +#else +#define CRITICAL_REGION_LOCAL_VAR(x, varname) DLG_CRITICAL_REGION_LOCAL_VAR(x, varname) +#define CRITICAL_REGION_BEGIN_VAR(x, varname) DLG_CRITICAL_REGION_BEGIN_VAR(x, varname) + +#define CRITICAL_SECTION_LOCK(x) DLG_CRITICAL_SECTION_LOCK(x) +#define CRITICAL_SECTION_TRY_LOCK(x) DLG_CRITICAL_SECTION_TRY_LOCK(x) +#define CRITICAL_SECTION_UNLOCK(x) DLG_CRITICAL_SECTION_UNLOCK(x) +#endif + + +#define CRITICAL_REGION_LOCAL(x) CRITICAL_REGION_LOCAL_VAR(x, critical_region_var) +#define CRITICAL_REGION_LOCAL1(x) CRITICAL_REGION_LOCAL_VAR(x, critical_region_var1) +#define CRITICAL_REGION_BEGIN(x) CRITICAL_REGION_BEGIN_VAR(x, critical_region_var) +#define CRITICAL_REGION_BEGIN1(x) CRITICAL_REGION_BEGIN_VAR(x, critical_region_var1) +#define CRITICAL_REGION_END() } + + + +} + +#endif + diff --git a/contrib/epee/include/time_helper.h b/contrib/epee/include/time_helper.h new file mode 100644 index 00000000..457f0b2b --- /dev/null +++ b/contrib/epee/include/time_helper.h @@ -0,0 +1,164 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#pragma once + +//#include +//#include +#include +#include +#include "warnings.h" + +namespace epee +{ +namespace misc_utils +{ + +#ifdef __ATLTIME_H__ + + inline + bool get_time_t_from_ole_date(DATE src, time_t& res) + { + SYSTEMTIME st = {0}; + if(TRUE != ::VariantTimeToSystemTime(src, &st)) + return false; + ATL::CTime ss(st); + res = ss.GetTime(); + return true; + } +#endif + inline + std::string get_time_str(const time_t& time_) + { + + + char tmpbuf[200] = {0}; + tm* pt = NULL; +PUSH_WARNINGS +DISABLE_VS_WARNINGS(4996) + pt = localtime(&time_); +POP_WARNINGS + + if(pt) + strftime( tmpbuf, 199, "%d.%m.%Y %H:%M:%S", pt ); + else + { + std::stringstream strs; + strs << "[wrong_time: " << std::hex << time_ << "]"; + return strs.str(); + } + return tmpbuf; + } + + inline + std::string get_time_str_v2(const time_t& time_) + { + + char tmpbuf[200] = {0}; + tm* pt = NULL; +PUSH_WARNINGS +DISABLE_VS_WARNINGS(4996) + pt = localtime(&time_); +POP_WARNINGS + + if(pt) + strftime( tmpbuf, 199, "%Y_%m_%d %H_%M_%S", pt ); + else + { + std::stringstream strs; + strs << "[wrong_time: " << std::hex << time_ << "]"; + return strs.str(); + } + return tmpbuf; + } + + inline + std::string get_time_str_v3(const boost::posix_time::ptime& time_) + { + return boost::posix_time::to_simple_string(time_); + } + + + + inline std::string get_internet_time_str(const time_t& time_) + { + char tmpbuf[200] = {0}; + tm* pt = NULL; +PUSH_WARNINGS +DISABLE_VS_WARNINGS(4996) + pt = gmtime(&time_); +POP_WARNINGS + strftime( tmpbuf, 199, "%a, %d %b %Y %H:%M:%S GMT", pt ); + return tmpbuf; + } + + inline std::string get_time_interval_string(const time_t& time_) + { + std::string res; + time_t tail = time_; + if (tail < 0) + { + tail = -tail; + res = "-"; + } +PUSH_WARNINGS +DISABLE_VS_WARNINGS(4244) + int days = tail/(60*60*24); + tail = tail%(60*60*24); + int hours = tail/(60*60); + tail = tail%(60*60); + int minutes = tail/(60); + tail = tail%(60); + int seconds = tail; +POP_WARNINGS + res += std::string("d") + boost::lexical_cast(days) + ".h" + boost::lexical_cast(hours) + ".m" + boost::lexical_cast(minutes) + ".s" + boost::lexical_cast(seconds); + return res; + } + +#ifdef __SQLEXT + inline + bool odbc_time_to_oledb_taime(const SQL_TIMESTAMP_STRUCT& odbc_timestamp, DATE& oledb_date) + { + + SYSTEMTIME st = {0}; + st.wYear = odbc_timestamp.year; + st.wDay = odbc_timestamp.day; + st.wHour = odbc_timestamp.hour ; + st.wMilliseconds = (WORD)odbc_timestamp.fraction ; + st.wMinute = odbc_timestamp.minute ; + st.wMonth = odbc_timestamp.month ; + st.wSecond = odbc_timestamp.second ; + + if(TRUE != ::SystemTimeToVariantTime(&st, &oledb_date)) + return false; + return true; + } + +#endif +} +} \ No newline at end of file diff --git a/contrib/epee/include/tiny_ini.h b/contrib/epee/include/tiny_ini.h new file mode 100644 index 00000000..2bc71fc1 --- /dev/null +++ b/contrib/epee/include/tiny_ini.h @@ -0,0 +1,75 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + +#ifndef _TINY_INI_H_ +#define _TINY_INI_H_ + +#include +#include +#include "string_tools.h" + +namespace epee +{ +namespace tiny_ini +{ + + inline + bool get_param_value(const std::string& param_name, const std::string& ini_entry, std::string& res) + { + std::string expr_str = std::string() + "^("+ param_name +") *=(.*?)$"; + const boost::regex match_ini_entry( expr_str, boost::regex::icase | boost::regex::normal); + boost::smatch result; + if(!boost::regex_search(ini_entry, result, match_ini_entry, boost::match_default)) + return false; + res = result[2]; + string_tools::trim(res); + return true; + } + inline + std::string get_param_value(const std::string& param_name, const std::string& ini_entry) + { + std::string buff; + get_param_value(param_name, ini_entry, buff); + return buff; + } + + template + bool get_param_value_as_t(const std::string& param_name, const std::string& ini_entry, T& res) + { + std::string str_res = get_param_value(param_name, ini_entry); + + string_tools::trim(str_res); + if(!str_res.size()) + return false; + + return string_tools::get_xtype_from_string(res, str_res); + } + +} +} + +#endif //_TINY_INI_H_ diff --git a/contrib/epee/include/to_nonconst_iterator.h b/contrib/epee/include/to_nonconst_iterator.h new file mode 100644 index 00000000..729b0e8b --- /dev/null +++ b/contrib/epee/include/to_nonconst_iterator.h @@ -0,0 +1,52 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#ifndef _TO_NONCONST_ITERATOR_H_ +#define _TO_NONCONST_ITERATOR_H_ + +namespace epee +{ + +template +typename Type::iterator to_nonsonst_iterator(Type& obj, typename Type::const_iterator it) +{ + typename Type::difference_type dist = std::distance(static_cast(obj.begin()), it); + typename Type::iterator res_it = obj.begin()+dist; + return res_it; +} + + +template +typename Type::iterator to_nonsonst_iterator(typename Type::iterator base_it, typename Type::const_iterator it) +{ + typename Type::difference_type dist = std::distance(static_cast(base_it), it); + typename Type::iterator res_it = base_it+dist; + return res_it; +} +}//namespace epee +#endif //_TO_NONCONST_ITERATOR_H_ diff --git a/contrib/epee/include/warnings.h b/contrib/epee/include/warnings.h new file mode 100644 index 00000000..89f2ec79 --- /dev/null +++ b/contrib/epee/include/warnings.h @@ -0,0 +1,34 @@ +#pragma once + +#if defined(_MSC_VER) + +#define PUSH_WARNINGS __pragma(warning(push)) +#define POP_WARNINGS __pragma(warning(pop)) +#define DISABLE_VS_WARNINGS(w) __pragma(warning(disable: w)) +#define DISABLE_GCC_WARNING(w) +#define DISABLE_CLANG_WARNING(w) +#define DISABLE_GCC_AND_CLANG_WARNING(w) + +#else + +#include + +#define PUSH_WARNINGS _Pragma("GCC diagnostic push") +#define POP_WARNINGS _Pragma("GCC diagnostic pop") +#define DISABLE_VS_WARNINGS(w) + +#if defined(__clang__) +#define DISABLE_GCC_WARNING(w) +#define DISABLE_CLANG_WARNING DISABLE_GCC_AND_CLANG_WARNING +#else +#define DISABLE_GCC_WARNING DISABLE_GCC_AND_CLANG_WARNING +#define DISABLE_CLANG_WARNING(w) +#endif + +#define DISABLE_GCC_AND_CLANG_WARNING(w) _Pragma(BOOST_PP_STRINGIZE(GCC diagnostic ignored BOOST_PP_STRINGIZE(-W##w))) + +#endif + + + + diff --git a/contrib/epee/include/zlib_helper.h b/contrib/epee/include/zlib_helper.h new file mode 100644 index 00000000..86f5f2c0 --- /dev/null +++ b/contrib/epee/include/zlib_helper.h @@ -0,0 +1,153 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + +#pragma once +extern "C" { +#include "zlib/zlib.h" +} + +namespace epee +{ +namespace zlib_helper +{ + inline bool pack(const std::string& target, std::string& result_packed_buff) +{ + result_packed_buff.clear(); + + z_stream zstream = {0}; + int ret = deflateInit(&zstream, Z_DEFAULT_COMPRESSION); + if(target.size()) + { + + + result_packed_buff.resize(target.size()*2, 'X'); + + zstream.next_in = (Bytef*)target.data(); + zstream.avail_in = (uInt)target.size(); + zstream.next_out = (Bytef*)result_packed_buff.data(); + zstream.avail_out = (uInt)result_packed_buff.size(); + + ret = deflate(&zstream, Z_FINISH); + CHECK_AND_ASSERT_MES(ret>=0, false, "Failed to deflate. err = " << ret); + + if(result_packed_buff.size() != zstream.avail_out) + result_packed_buff.resize(result_packed_buff.size()-zstream.avail_out); + + + result_packed_buff.erase(0, 2); + } + + deflateEnd(& zstream ); + return true; + } + + inline bool pack(std::string& target) + { + std::string result_packed_buff; + bool r = pack(target, result_packed_buff); + if (r) + result_packed_buff.swap(target); + return r; + } + + inline bool unpack(const std::string& target, std::string& decode_summary_buff) + { + z_stream zstream = {0}; + int ret = inflateInit(&zstream);// + + decode_summary_buff.clear(); + size_t ungzip_buff_size = target.size() * 0x30; + std::string current_decode_buff(ungzip_buff_size, 'X'); + + uInt current_offset = 0; + + while (target.size() > current_offset) + { + zstream.next_out = (Bytef*)current_decode_buff.data(); + zstream.avail_out = (uInt)ungzip_buff_size; + + static char dummy_head[2] = + { + 0x8 + 0x7 * 0x10, + (((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF, + }; + zstream.next_in = (Bytef*) dummy_head; + zstream.avail_in = sizeof(dummy_head); + ret = inflate(&zstream, Z_NO_FLUSH); + if (ret != Z_OK) + { + LOCAL_ASSERT(0); + return false; + } + + zstream.next_in = (Bytef*)target.data() + current_offset; + zstream.avail_in = (uInt)target.size() - current_offset; + + ret = inflate(&zstream, Z_SYNC_FLUSH); + if (ret != Z_OK && ret != Z_STREAM_END) + { + LOCAL_ASSERT(0); + return false; + } + + + //target.erase(0, target.size()-zstream.avail_in); + current_offset += zstream.total_in; + + if(ungzip_buff_size == zstream.avail_out) + { + LOG_ERROR("Can't unpack buffer"); + return false; + } + + + current_decode_buff.resize(ungzip_buff_size - zstream.avail_out); + if(decode_summary_buff.size()) + decode_summary_buff += current_decode_buff; + else + current_decode_buff.swap(decode_summary_buff); + + current_decode_buff.resize(ungzip_buff_size); + } + + inflateEnd(&zstream ); + + + return true; + } + + inline bool unpack(std::string& target) + { + std::string decode_summary_buff; + bool r = unpack(target, decode_summary_buff); + if (r) + decode_summary_buff.swap(target); + return r; + } + +}; +}//namespace epee diff --git a/contrib/epee/tests/.gitignore b/contrib/epee/tests/.gitignore new file mode 100644 index 00000000..d9b4f015 --- /dev/null +++ b/contrib/epee/tests/.gitignore @@ -0,0 +1 @@ +/build/* diff --git a/contrib/epee/tests/data/storages/invalid_storage_1.bin b/contrib/epee/tests/data/storages/invalid_storage_1.bin new file mode 100644 index 00000000..fac7b3e9 Binary files /dev/null and b/contrib/epee/tests/data/storages/invalid_storage_1.bin differ diff --git a/contrib/epee/tests/data/storages/invalid_storage_2.bin b/contrib/epee/tests/data/storages/invalid_storage_2.bin new file mode 100644 index 00000000..a8c29f15 Binary files /dev/null and b/contrib/epee/tests/data/storages/invalid_storage_2.bin differ diff --git a/contrib/epee/tests/data/storages/invalid_storage_3.bin b/contrib/epee/tests/data/storages/invalid_storage_3.bin new file mode 100644 index 00000000..b5c31aa0 --- /dev/null +++ b/contrib/epee/tests/data/storages/invalid_storage_3.bin @@ -0,0 +1 @@ +IMm_bo \ No newline at end of file diff --git a/contrib/epee/tests/data/storages/invalid_storage_4.bin b/contrib/epee/tests/data/storages/invalid_storage_4.bin new file mode 100644 index 00000000..4f8372d1 Binary files /dev/null and b/contrib/epee/tests/data/storages/invalid_storage_4.bin differ diff --git a/contrib/epee/tests/data/storages/valid_storage.bin b/contrib/epee/tests/data/storages/valid_storage.bin new file mode 100644 index 00000000..e13f780b Binary files /dev/null and b/contrib/epee/tests/data/storages/valid_storage.bin differ diff --git a/contrib/epee/tests/generate_vc_proj.bat b/contrib/epee/tests/generate_vc_proj.bat new file mode 100644 index 00000000..a81bdce0 --- /dev/null +++ b/contrib/epee/tests/generate_vc_proj.bat @@ -0,0 +1,5 @@ +mkdir build +cd build +cmake "-DBoost_USE_STATIC_LIBS=TRUE" -G "Visual Studio 11 Win64" ../src +cd .. +pause \ No newline at end of file diff --git a/contrib/epee/tests/src/CMakeLists.txt b/contrib/epee/tests/src/CMakeLists.txt new file mode 100644 index 00000000..59e413b7 --- /dev/null +++ b/contrib/epee/tests/src/CMakeLists.txt @@ -0,0 +1,34 @@ + +cmake_minimum_required(VERSION 2.8) + +set(Boost_USE_MULTITHREADED ON) + +include_directories(.) +include_directories(../../include) + +find_package(Boost COMPONENTS system filesystem thread date_time chrono regex) +include_directories( ${Boost_INCLUDE_DIRS} ) + +IF (MSVC) + add_definitions( "/W3 /D_CRT_SECURE_NO_WARNINGS /wd4996 /wd4345 /nologo /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /bigobj" ) + include_directories(SYSTEM platform/msvc) +ELSE() + # set stuff for other systems + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -Wall -Werror") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes") # needed for AES + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Werror -Wno-reorder") +ENDIF() + + +# Add folders to filters +file(GLOB_RECURSE SRC RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/*.inl + ${CMAKE_CURRENT_SOURCE_DIR}/*.h) + +source_group(general FILES ${SRC}) + + +add_executable(tests ${SRC} ) +target_link_libraries( tests ${Boost_LIBRARIES} ) + diff --git a/contrib/epee/tests/src/misc/test_math.h b/contrib/epee/tests/src/misc/test_math.h new file mode 100644 index 00000000..8b3064c2 --- /dev/null +++ b/contrib/epee/tests/src/misc/test_math.h @@ -0,0 +1,82 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#pragma once + +#include "misc_language.h" + +namespace epee +{ + namespace tests + { + bool test_median() + { + LOG_PRINT_L0("Testing median"); + std::vector sz; + size_t m = misc_utils::median(sz); + CHECK_AND_ASSERT_MES(m == 0, false, "test failed"); + sz.push_back(1); + m = misc_utils::median(sz); + CHECK_AND_ASSERT_MES(m == 1, false, "test failed"); + sz.push_back(10); + m = misc_utils::median(sz); + CHECK_AND_ASSERT_MES(m == 5, false, "test failed"); + + sz.clear(); + sz.resize(3); + sz[0] = 0; + sz[1] = 9; + sz[2] = 3; + m = misc_utils::median(sz); + CHECK_AND_ASSERT_MES(m == 3, false, "test failed"); + + sz.clear(); + sz.resize(4); + sz[0] = 77; + sz[1] = 9; + sz[2] = 22; + sz[3] = 60; + m = misc_utils::median(sz); + CHECK_AND_ASSERT_MES(m == 41, false, "test failed"); + + + + sz.clear(); + sz.resize(5); + sz[0] = 77; + sz[1] = 9; + sz[2] = 22; + sz[3] = 60; + sz[4] = 11; + m = misc_utils::median(sz); + CHECK_AND_ASSERT_MES(m == 22, false, "test failed"); + return true; + } + } +} + diff --git a/contrib/epee/tests/src/net/test_net.h b/contrib/epee/tests/src/net/test_net.h new file mode 100644 index 00000000..ddcae6d1 --- /dev/null +++ b/contrib/epee/tests/src/net/test_net.h @@ -0,0 +1,403 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + +#pragma once + +#include +#include + +#include "net/levin_server_cp2.h" +#include "storages/abstract_invoke.h" + +namespace epee +{ +namespace StorageNamed +{ + typedef CInMemStorage DefaultStorageType; +} +namespace tests +{ + struct some_subdata + { + + std::string str1; + std::list array_of_id; + + BEGIN_NAMED_SERIALIZE_MAP() + SERIALIZE_STL_ANSI_STRING(str1) + SERIALIZE_STL_CONTAINER_POD(array_of_id) + END_NAMED_SERIALIZE_MAP() + }; + + + /************************************************************************/ + /* */ + /************************************************************************/ + struct COMMAND_EXAMPLE_1 + { + const static int ID = 1000; + + struct request + { + + std::string example_string_data; + uint64_t example_id_data; + some_subdata sub; + + BEGIN_NAMED_SERIALIZE_MAP() + SERIALIZE_STL_ANSI_STRING(example_string_data) + SERIALIZE_POD(example_id_data) + SERIALIZE_T(sub) + END_NAMED_SERIALIZE_MAP() + }; + + + struct response + { + bool m_success; + uint64_t example_id_data; + std::list subs; + + BEGIN_NAMED_SERIALIZE_MAP() + SERIALIZE_POD(m_success) + SERIALIZE_POD(example_id_data) + SERIALIZE_STL_CONTAINER_T(subs) + END_NAMED_SERIALIZE_MAP() + }; + }; + + struct COMMAND_EXAMPLE_2 + { + const static int ID = 1001; + + struct request + { + std::string example_string_data2; + uint64_t example_id_data; + + BEGIN_NAMED_SERIALIZE_MAP() + SERIALIZE_POD(example_id_data) + SERIALIZE_STL_ANSI_STRING(example_string_data2) + END_NAMED_SERIALIZE_MAP() + }; + + struct response + { + bool m_success; + uint64_t example_id_data; + + BEGIN_NAMED_SERIALIZE_MAP() + SERIALIZE_POD(example_id_data) + SERIALIZE_POD(m_success) + END_NAMED_SERIALIZE_MAP() + }; + }; + typedef boost::uuids::uuid uuid; + + class test_levin_server: public levin::levin_commands_handler<> + { + test_levin_server(const test_levin_server&){} + public: + test_levin_server(){} + void set_thread_prefix(const std::string& pref) + { + m_net_server.set_threads_prefix(pref); + } + template + bool connect_async(const std::string adr, const std::string& port, uint32_t conn_timeot, calback_t cb, const std::string& bind_ip = "0.0.0.0") + { + return m_net_server.connect_async(adr, port, conn_timeot, cb, bind_ip); + } + + bool connect(const std::string adr, const std::string& port, uint32_t conn_timeot, net_utils::connection_context_base& cn, const std::string& bind_ip = "0.0.0.0") + { + return m_net_server.connect(adr, port, conn_timeot, cn, bind_ip); + } + void close(net_utils::connection_context_base& cn) + { + m_net_server.get_config_object().close(cn.m_connection_id); + } + + template + bool invoke(uuid con_id, int command, t_request& req, t_response& resp) + { + return invoke_remote_command(con_id, command, req, resp, m_net_server.get_config_object()); + } + + template< class t_response, class t_request, class callback_t> + bool invoke_async(uuid con_id, int command, t_request& req, callback_t cb) + { + return async_invoke_remote_command(con_id, command, req, m_net_server.get_config_object(), cb); + } + + bool init(const std::string& bind_port = "", const std::string& bind_ip = "0.0.0.0") + { + m_net_server.get_config_object().m_pcommands_handler = this; + m_net_server.get_config_object().m_invoke_timeout = 1000; + LOG_PRINT_L0("Binding on " << bind_ip << ":" << bind_port); + return m_net_server.init_server(bind_port, bind_ip); + } + + bool run() + { + //here you can set worker threads count + int thrds_count = 4; + + //go to loop + LOG_PRINT("Run net_service loop( " << thrds_count << " threads)...", LOG_LEVEL_0); + if(!m_net_server.run_server(thrds_count)) + { + LOG_ERROR("Failed to run net tcp server!"); + } + + LOG_PRINT("net_service loop stopped.", LOG_LEVEL_0); + return true; + } + + bool deinit() + { + return m_net_server.deinit_server(); + } + + bool send_stop_signal() + { + m_net_server.send_stop_signal(); + return true; + } + + uint32_t get_binded_port() + { + return m_net_server.get_binded_port(); + } + private: + + + CHAIN_LEVIN_INVOKE_TO_MAP(); //move levin_commands_handler interface invoke(...) callbacks into invoke map + CHAIN_LEVIN_NOTIFY_TO_STUB(); //move levin_commands_handler interface notify(...) callbacks into nothing + + BEGIN_INVOKE_MAP(test_levin_server) + HANDLE_INVOKE_T(COMMAND_EXAMPLE_1, &test_levin_server::handle_1) + HANDLE_INVOKE_T(COMMAND_EXAMPLE_2, &test_levin_server::handle_2) + END_INVOKE_MAP() + + //----------------- commands handlers ---------------------------------------------- + int handle_1(int command, COMMAND_EXAMPLE_1::request& arg, COMMAND_EXAMPLE_1::response& rsp, const net_utils::connection_context_base& context) + { + LOG_PRINT_L0("on_command_1: id " << arg.example_id_data << "---->>"); + COMMAND_EXAMPLE_2::request arg_ = AUTO_VAL_INIT(arg_); + arg_.example_id_data = arg.example_id_data; + COMMAND_EXAMPLE_2::response rsp_ = AUTO_VAL_INIT(rsp_); + invoke_async(context.m_connection_id, COMMAND_EXAMPLE_2::ID, arg_, [](int code, const COMMAND_EXAMPLE_2::response& rsp, const net_utils::connection_context_base& context) + { + if(code < 0) + {LOG_PRINT_RED_L0("on_command_1: command_2 failed to invoke");} + else + {LOG_PRINT_L0("on_command_1: command_2 response " << rsp.example_id_data);} + }); + rsp.example_id_data = arg.example_id_data; + LOG_PRINT_L0("on_command_1: id " << arg.example_id_data << "<<----"); + return true; + } + int handle_2(int command, COMMAND_EXAMPLE_2::request& arg, COMMAND_EXAMPLE_2::response& rsp, const net_utils::connection_context_base& context) + { + LOG_PRINT_L0("on_command_2: id "<< arg.example_id_data); + rsp.example_id_data = arg.example_id_data; + //misc_utils::sleep_no_w(6000); + return true; + } + //---------------------------------------------------------------------------------- + net_utils::boosted_levin_async_server m_net_server; + }; + + + inline + bool do_run_test_server() + { + + test_levin_server srv1, srv2; + + + std::string bind_param = "0.0.0.0"; + std::string port = ""; + + if(!srv1.init(port, bind_param)) + { + LOG_ERROR("Failed to initialize srv!"); + return 1; + } + + if(!srv2.init(port, bind_param)) + { + LOG_ERROR("Failed to initialize srv!"); + return 1; + } + + srv1.set_thread_prefix("SRV_A"); + srv2.set_thread_prefix("SRV_B"); + + boost::thread th1( boost::bind(&test_levin_server::run, &srv1)); + boost::thread th2( boost::bind(&test_levin_server::run, &srv2)); + + LOG_PRINT_L0("Initalized servers, waiting for worker threads started..."); + misc_utils::sleep_no_w(1000); + + + LOG_PRINT_L0("Connecting to each other..."); + uint32_t port1 = srv1.get_binded_port(); + uint32_t port2 = srv2.get_binded_port(); + + COMMAND_EXAMPLE_1::request arg; + COMMAND_EXAMPLE_1::request resp; + + net_utils::connection_context_base cntxt_1; + bool r = srv1.connect("127.0.0.1", string_tools::num_to_string_fast(port2), 5000, cntxt_1); + CHECK_AND_ASSERT_MES(r, false, "connect to server failed"); + + net_utils::connection_context_base cntxt_2; + r = srv2.connect("127.0.0.1", string_tools::num_to_string_fast(port1), 5000, cntxt_2); + CHECK_AND_ASSERT_MES(r, false, "connect to server failed"); + + while(true) + { + LOG_PRINT_L0("Invoking from A to B..."); + int r = srv1.invoke(cntxt_1.m_connection_id, COMMAND_EXAMPLE_1::ID, arg, resp); + if(r<=0) + { + LOG_ERROR("Failed tp invoke A to B"); + break; + } + + LOG_PRINT_L0("Invoking from B to A..."); + r = srv2.invoke(cntxt_2.m_connection_id, COMMAND_EXAMPLE_1::ID, arg, resp); + if(r<=0) + { + LOG_ERROR("Failed tp invoke B to A"); + break; + } + } + srv1.send_stop_signal(); + srv2.send_stop_signal(); + th1.join(); + th1.join(); + + return true; + } + + + + inline bool do_test2_work_with_srv(test_levin_server& srv, int port) + { + uint64_t i = 0; + boost::mutex wait_event; + CRITICAL_SECTION_LOCK(wait_event); + while(true) + { + net_utils::connection_context_base cntxt_local = AUTO_VAL_INIT(cntxt_local); + bool r = srv.connect_async("127.0.0.1", string_tools::num_to_string_fast(port), 5000, [&srv, &port, &wait_event, &i, &cntxt_local](const net_utils::connection_context_base& cntxt, const boost::system::error_code& ec) + { + CHECK_AND_ASSERT_MES(!ec, void(), "Some problems at connect, message: " << ec.message() ); + cntxt_local = cntxt; + LOG_PRINT_L0("Invoking command 1 to " << port); + COMMAND_EXAMPLE_1::request arg = AUTO_VAL_INIT(arg); + arg.example_id_data = i; + /*vc2010 workaround*/ + int port_ = port; + boost::mutex& wait_event_ = wait_event; + int r = srv.invoke_async(cntxt.m_connection_id, COMMAND_EXAMPLE_1::ID, arg, [port_, &wait_event_](int code, const COMMAND_EXAMPLE_1::request& rsp, const net_utils::connection_context_base& cntxt) + { + CHECK_AND_ASSERT_MES(code > 0, void(), "Failed to invoke"); + LOG_PRINT_L0("command 1 invoke to " << port_ << " OK."); + CRITICAL_SECTION_UNLOCK(wait_event_); + }); + }); + CRITICAL_SECTION_LOCK(wait_event); + srv.close(cntxt_local); + ++i; + } + return true; + } + + inline + bool do_run_test_server_async_connect() + { + test_levin_server srv1, srv2; + + + std::string bind_param = "0.0.0.0"; + std::string port = ""; + + if(!srv1.init(port, bind_param)) + { + LOG_ERROR("Failed to initialize srv!"); + return 1; + } + + if(!srv2.init(port, bind_param)) + { + LOG_ERROR("Failed to initialize srv!"); + return 1; + } + + srv1.set_thread_prefix("SRV_A"); + srv2.set_thread_prefix("SRV_B"); + + boost::thread thmain1( boost::bind(&test_levin_server::run, &srv1)); + boost::thread thmain2( boost::bind(&test_levin_server::run, &srv2)); + + LOG_PRINT_L0("Initalized servers, waiting for worker threads started..."); + misc_utils::sleep_no_w(1000); + + + LOG_PRINT_L0("Connecting to each other..."); + uint32_t port1 = srv1.get_binded_port(); + uint32_t port2 = srv2.get_binded_port(); + + COMMAND_EXAMPLE_1::request arg; + COMMAND_EXAMPLE_1::request resp; + + + boost::thread work_1( boost::bind(do_test2_work_with_srv, boost::ref(srv1), port2)); + boost::thread work_2( boost::bind(do_test2_work_with_srv, boost::ref(srv2), port1)); + boost::thread work_3( boost::bind(do_test2_work_with_srv, boost::ref(srv1), port2)); + boost::thread work_4( boost::bind(do_test2_work_with_srv, boost::ref(srv2), port1)); + boost::thread work_5( boost::bind(do_test2_work_with_srv, boost::ref(srv1), port2)); + boost::thread work_6( boost::bind(do_test2_work_with_srv, boost::ref(srv2), port1)); + boost::thread work_7( boost::bind(do_test2_work_with_srv, boost::ref(srv1), port2)); + boost::thread work_8( boost::bind(do_test2_work_with_srv, boost::ref(srv2), port1)); + + + work_1.join(); + work_2.join(); + srv1.send_stop_signal(); + srv2.send_stop_signal(); + thmain1.join(); + thmain2.join(); + + return true; + } + +} +} \ No newline at end of file diff --git a/contrib/epee/tests/src/storages/portable_storages_test.h b/contrib/epee/tests/src/storages/portable_storages_test.h new file mode 100644 index 00000000..ecded8da --- /dev/null +++ b/contrib/epee/tests/src/storages/portable_storages_test.h @@ -0,0 +1,232 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#pragma once + +#include +#include +#include "storages/serializeble_struct_helper.h" +#include "serialization/keyvalue_serialization.h" +#include "storages/portable_storage.h" +#include "storages/portable_storage_template_helper.h" + +namespace epee +{ + namespace tests + { + + struct port_test_struct_sub + { + std::string m_str; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_VAL(m_str) + END_KV_SERIALIZE_MAP() + }; + +#pragma pack (push, 1) + struct some_pod_struct + { + uint64_t a; + int32_t b; + }; +#pragma pack(pop) + + struct port_test_struct + { + std::string m_str; + uint64_t m_uint64; + uint32_t m_uint32; + uint16_t m_uint16; + uint8_t m_uint8; + int64_t m_int64; + int32_t m_int32; + int16_t m_int16; + int8_t m_int8; + double m_double; + bool m_bool; + some_pod_struct m_pod; + std::list m_list_of_str; + std::list m_list_of_uint64_t; + std::list m_list_of_uint32_t; + std::list m_list_of_uint16_t; + std::list m_list_of_uint8_t; + std::list m_list_of_int64_t; + std::list m_list_of_int32_t; + std::list m_list_of_int16_t; + std::list m_list_of_int8_t; + std::list m_list_of_double; + std::list m_list_of_bool; + port_test_struct_sub m_subobj; + std::list m_list_of_self; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_VAL(m_str) + KV_SERIALIZE_VAL(m_uint64) + KV_SERIALIZE_VAL(m_uint32) + KV_SERIALIZE_VAL(m_uint16) + KV_SERIALIZE_VAL(m_uint8) + KV_SERIALIZE_VAL(m_int64) + KV_SERIALIZE_VAL(m_int32) + KV_SERIALIZE_VAL(m_int16) + KV_SERIALIZE_VAL(m_int8) + KV_SERIALIZE_VAL(m_double) + KV_SERIALIZE_VAL(m_bool) + KV_SERIALIZE_VAL_POD_AS_BLOB(m_pod) + KV_SERIALIZE_OBJ(m_subobj) + KV_SERIALIZE_CONTAINER_VAL(m_list_of_str) + KV_SERIALIZE_CONTAINER_VAL(m_list_of_uint64_t) + KV_SERIALIZE_CONTAINER_VAL(m_list_of_uint32_t) + KV_SERIALIZE_CONTAINER_VAL(m_list_of_uint16_t) + KV_SERIALIZE_CONTAINER_VAL(m_list_of_uint8_t) + KV_SERIALIZE_CONTAINER_VAL(m_list_of_int64_t) + KV_SERIALIZE_CONTAINER_VAL(m_list_of_int32_t) + KV_SERIALIZE_CONTAINER_VAL(m_list_of_int16_t) + KV_SERIALIZE_CONTAINER_VAL(m_list_of_int8_t) + KV_SERIALIZE_CONTAINER_VAL(m_list_of_double) + KV_SERIALIZE_CONTAINER_VAL(m_list_of_bool) + KV_SERIALIZE_CONTAINER_OBJ(m_list_of_self) + END_KV_SERIALIZE_MAP() + }; + + bool operator != (const port_test_struct_sub& a, const port_test_struct_sub& b) + { + return b.m_str != a.m_str; + } + + bool operator == (const port_test_struct& a, const port_test_struct& b) + { + if( b.m_str != a.m_str + || b.m_uint64 != a.m_uint64 + || b.m_uint32 != a.m_uint32 + || b.m_uint16 != a.m_uint16 + || b.m_uint8 != a.m_uint8 + || b.m_int64 != a.m_int64 + || b.m_int32 != a.m_int32 + || b.m_int16 != a.m_int16 + || b.m_int8 != a.m_int8 + || b.m_double != a.m_double + || b.m_bool != a.m_bool + || b.m_pod.a != a.m_pod.a + || b.m_pod.b != a.m_pod.b + || b.m_list_of_str != a.m_list_of_str + || b.m_list_of_uint64_t != a.m_list_of_uint64_t + || b.m_list_of_uint32_t != a.m_list_of_uint32_t + || b.m_list_of_uint16_t != a.m_list_of_uint16_t + || b.m_list_of_uint8_t != a.m_list_of_uint8_t + || b.m_list_of_int64_t != a.m_list_of_int64_t + || b.m_list_of_int32_t != a.m_list_of_int32_t + || b.m_list_of_int16_t != a.m_list_of_int16_t + || b.m_list_of_int8_t != a.m_list_of_int8_t + || b.m_list_of_double != a.m_list_of_double + || b.m_list_of_bool != a.m_list_of_bool + || b.m_subobj != a.m_subobj + || b.m_list_of_self != a.m_list_of_self + ) + return false; + return true; + } + + void fill_struct_with_test_values(port_test_struct& s) + { + s.m_str = "zuzuzuzuzuz"; + s.m_uint64 = 111111111111111; + s.m_uint32 = 2222222; + s.m_uint16 = 2222; + s.m_uint8 = 22; + s.m_int64 = -111111111111111; + s.m_int32 = -2222222; + s.m_int16 = -2222; + s.m_int8 = -24; + s.m_double = 0.11111; + s.m_bool = true; + s.m_pod.a = 32342342342342; + s.m_pod.b = -342342; + s.m_list_of_str.push_back("1112121"); + s.m_list_of_uint64_t.push_back(1111111111); + s.m_list_of_uint64_t.push_back(2222222222); + s.m_list_of_uint32_t.push_back(1111111); + s.m_list_of_uint32_t.push_back(2222222); + s.m_list_of_uint16_t.push_back(1111); + s.m_list_of_uint16_t.push_back(2222); + s.m_list_of_uint8_t.push_back(11); + s.m_list_of_uint8_t.push_back(22); + + + s.m_list_of_int64_t.push_back(-1111111111); + s.m_list_of_int64_t.push_back(-222222222); + s.m_list_of_int32_t.push_back(-1111111); + s.m_list_of_int32_t.push_back(-2222222); + s.m_list_of_int16_t.push_back(-1111); + s.m_list_of_int16_t.push_back(-2222); + s.m_list_of_int8_t.push_back(-11); + s.m_list_of_int8_t.push_back(-22); + + s.m_list_of_double.push_back(0.11111); + s.m_list_of_double.push_back(0.22222); + s.m_list_of_bool.push_back(true); + s.m_list_of_bool.push_back(false); + + s.m_subobj.m_str = "subszzzzzzzz"; + s.m_list_of_self.push_back(s); + } + + bool test_portable_storages(const std::string& tests_folder) + { + serialization::portable_storage ps, ps2; + port_test_struct s1, s2; + fill_struct_with_test_values(s1); + + s1.store(ps); + std::string binbuf; + bool r = ps.store_to_binary(binbuf); + + ps2.load_from_binary(binbuf); + s2.load(ps2); + if(!(s1 == s2)) + { + LOG_ERROR("Portable storage test failed!"); + return false; + } + + + port_test_struct ss1, ss2; + fill_struct_with_test_values(ss1); + std::string json_buff = epee::serialization::store_t_to_json(ss1); + epee::serialization::load_t_from_json(ss2, json_buff); + if(!(ss1 == ss2)) + { + LOG_ERROR("Portable storage test failed!"); + return false; + } + + return true; + } + + } +} \ No newline at end of file diff --git a/contrib/epee/tests/src/storages/storage_tests.h b/contrib/epee/tests/src/storages/storage_tests.h new file mode 100644 index 00000000..522e589c --- /dev/null +++ b/contrib/epee/tests/src/storages/storage_tests.h @@ -0,0 +1,142 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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. +// + + + +#pragma once + +#include "storages/serializeble_struct_helper.h" +#include "storages/portable_storage.h" + +namespace epee +{ + namespace tests + { + + + struct test_struct + { + + std::string m_str; + unsigned int m_uint; + bool m_bool; + std::list m_list_of_str; + std::list m_list_of_int; + std::list m_list_of_self; + + + BEGIN_NAMED_SERIALIZE_MAP() + SERIALIZE_STL_ANSI_STRING(m_str) + SERIALIZE_POD(m_uint) + SERIALIZE_POD(m_bool) + SERIALIZE_STL_CONTAINER_ANSII_STRING(m_list_of_str) + SERIALIZE_STL_CONTAINER_POD(m_list_of_int) + SERIALIZE_STL_CONTAINER_T(m_list_of_self) + END_NAMED_SERIALIZE_MAP() + + }; + + + bool operator == (const test_struct& a, const test_struct& b) + { + if( b.m_str != a.m_str + || b.m_uint != a.m_uint + || b.m_bool != a.m_bool + || b.m_list_of_str != a.m_list_of_str + || b.m_list_of_int != a.m_list_of_int + || b.m_list_of_self != a.m_list_of_self + ) + return false; + return true; + } + + inline test_struct get_test_struct() + { + test_struct t = boost::value_initialized(); + t.m_bool = true; + t.m_str = "ackamdc'kmecemcececmacmecmcm[aicm[oeicm[oeicm[qaicm[qoe"; + t.m_uint = 233242; + for(int i = 0; i!=500; i++) + t.m_list_of_int.push_back(i); + + for(int i = 0; i!=500; i++) + t.m_list_of_str.push_back("ssccd"); + + for(int i = 0; i!=5; i++) + { + t.m_list_of_self.push_back(t); + } + return t; + } + + bool test_storages(const std::string& tests_folder) + { + + epee::serialization::portable_storage ps; + auto s = ps.open_section("zzz", nullptr); + uint64_t i = 0; + ps.get_value("afdsdf", i, s); + + + LOG_PRINT_L0("Generating test struct..."); + boost::filesystem::path storage_folder = tests_folder; + storage_folder /= "storages"; + + + test_struct t = get_test_struct(); + + LOG_PRINT_L0("Loading test struct from storage..."); + test_struct t2; + bool res = epee::StorageNamed::load_struct_from_storage_file(t2, (storage_folder /+ "valid_storage.bin").string()); + CHECK_AND_ASSERT_MES(res, false, "Failed to load valid_storage.bin"); + + LOG_PRINT_L0("Comparing generated and loaded test struct..."); + if(!(t == t2)) + return false; + + LOG_PRINT_L0("Loading broken archive 1..."); + test_struct t3; + res = epee::StorageNamed::load_struct_from_storage_file(t3, (storage_folder /+ "invalid_storage_1.bin").string()); + CHECK_AND_ASSERT_MES(!res, false, "invalid_storage_1.bin loaded, but should not "); + + + LOG_PRINT_L0("Loading broken archive 2..."); + res = epee::StorageNamed::load_struct_from_storage_file(t3, (storage_folder /+ "invalid_storage_2.bin").string()); + CHECK_AND_ASSERT_MES(!res, false, "invalid_storage_2.bin loaded, but should not "); + + LOG_PRINT_L0("Loading broken archive 3..."); + res = epee::StorageNamed::load_struct_from_storage_file(t3, (storage_folder /+ "invalid_storage_3.bin").string()); + CHECK_AND_ASSERT_MES(!res, false, "invalid_storage_3.bin loaded, but should not "); + + LOG_PRINT_L0("Loading broken archive 4..."); + res = epee::StorageNamed::load_struct_from_storage_file(t3, (storage_folder /+ "invalid_storage_4.bin").string()); + CHECK_AND_ASSERT_MES(!res, false, "invalid_storage_3.bin loaded, but should not "); + + return true; + } + } +} + diff --git a/contrib/epee/tests/src/tests.cpp b/contrib/epee/tests/src/tests.cpp new file mode 100644 index 00000000..ed045d83 --- /dev/null +++ b/contrib/epee/tests/src/tests.cpp @@ -0,0 +1,59 @@ + +#include "include_base_utils.h" +#include "storages/storage_tests.h" +#include "misc/test_math.h" +#include "storages/portable_storages_test.h" +#include "net/test_net.h" + +using namespace epee; + +int main(int argc, char* argv[]) +{ + + string_tools::set_module_name_and_folder(argv[0]); + + //set up logging options + log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2); + log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL); + log_space::log_singletone::add_logger(LOGGER_FILE, + log_space::log_singletone::get_default_log_file().c_str(), + log_space::log_singletone::get_default_log_folder().c_str()); + + + string_tools::command_line_params_a start_params; + string_tools::parse_commandline(start_params, argc, argv); + std::string tests_data_path; + string_tools::get_xparam_from_command_line(start_params, std::string("/tests_folder"), tests_data_path); + + if(string_tools::have_in_command_line(start_params, std::string("/run_net_tests"))) + { + if(!tests::do_run_test_server()) + { + LOG_ERROR("net tests failed"); + return 1; + } + if(!tests::do_run_test_server_async_connect() ) + { + LOG_ERROR("net tests failed"); + return 1; + } + }else if(string_tools::have_in_command_line(start_params, std::string("/run_unit_tests"))) + { + if(!tests::test_median()) + { + LOG_ERROR("median test failed"); + return 1; + } + + + if(!tests::test_storages(tests_data_path)) + { + LOG_ERROR("storage test failed"); + return 1; + } + }else if(string_tools::have_in_command_line(start_params, std::string("/run_portable_storage_test"))) + { + tests::test_portable_storages(tests_data_path); + } + return 1; +} \ No newline at end of file diff --git a/contrib/miniupnpc/CMakeLists.txt b/contrib/miniupnpc/CMakeLists.txt new file mode 100644 index 00000000..464ae74b --- /dev/null +++ b/contrib/miniupnpc/CMakeLists.txt @@ -0,0 +1,176 @@ +cmake_minimum_required (VERSION 2.6) + +project (miniupnpc C) +set (MINIUPNPC_VERSION 1.9) +set (MINIUPNPC_API_VERSION 10) + +if (NOT CMAKE_BUILD_TYPE) + if (WIN32) + set (DEFAULT_BUILD_TYPE MinSizeRel) + else (WIN32) + set (DEFAULT_BUILD_TYPE RelWithDebInfo) + endif(WIN32) + set (CMAKE_BUILD_TYPE ${DEFAULT_BUILD_TYPE} CACHE STRING + "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." + FORCE) +endif() + +option (UPNPC_BUILD_STATIC "Build static library" TRUE) +option (UPNPC_BUILD_SHARED "Build shared library" TRUE) +if (NOT WIN32) + option (UPNPC_BUILD_TESTS "Build test executables" TRUE) +endif (NOT WIN32) +option (NO_GETADDRINFO "Define NO_GETADDRINFO" FALSE) + +mark_as_advanced (NO_GETADDRINFO) + +if (NO_GETADDRINFO) + add_definitions (-DNO_GETADDRINFO) +endif (NO_GETADDRINFO) + +if (NOT WIN32) + add_definitions (-DMINIUPNPC_SET_SOCKET_TIMEOUT) + add_definitions (-D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=1) +else (NOT WIN32) + add_definitions (-D_WIN32_WINNT=0x0501) # XP or higher for getnameinfo and friends +endif (NOT WIN32) + +if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") + add_definitions (-DMACOSX -D_DARWIN_C_SOURCE) +endif () + +# Set compiler specific build flags +if (CMAKE_COMPILER_IS_GNUC) + # Set our own default flags at first run. + if (NOT CONFIGURED) + + if (NOT CMAKE_SYSTEM_NAME STREQUAL "AmigaOS") + set (_PIC -fPIC) + endif (CMAKE_SYSTEM_NAME STREQUAL "AmigaOS") + + set (CMAKE_C_FLAGS "${_PIC} -Wall $ENV{CFLAGS}" # CMAKE_C_FLAGS gets appended to the other C flags + CACHE STRING "Flags used by the C compiler during normal builds." FORCE) + set (CMAKE_C_FLAGS_DEBUG "-g -DDDEBUG" + CACHE STRING "Flags used by the C compiler during debug builds." FORCE) + set (CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG" + CACHE STRING "Flags used by the C compiler during release builds." FORCE) + set (CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g -DNDEBUG" + CACHE STRING "Flags used by the C compiler during release builds." FORCE) + set (CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG" + CACHE STRING "Flags used by the C compiler during release builds." FORCE) + + endif (NOT CONFIGURED) +endif () + +configure_file (miniupnpcstrings.h.cmake ${CMAKE_BINARY_DIR}/miniupnpcstrings.h) +include_directories (${CMAKE_BINARY_DIR}) + +set (MINIUPNPC_SOURCES + igd_desc_parse.c + miniupnpc.c + minixml.c + minisoap.c + miniwget.c + upnpc.c + upnpcommands.c + upnpreplyparse.c + upnperrors.c + connecthostport.c + portlistingparse.c + receivedata.c +) + +if (NOT WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "AmigaOS") + set (MINIUPNPC_SOURCES ${MINIUPNPC_SOURCES} minissdpc.c) +endif (NOT WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "AmigaOS") + +if (WIN32) + set_source_files_properties (${MINIUPNPC_SOURCES} PROPERTIES + COMPILE_DEFINITIONS STATICLIB + COMPILE_DEFINITIONS MINIUPNP_EXPORTS + ) +endif (WIN32) + +if (WIN32) +# find_library (WINSOCK2_LIBRARY NAMES ws2_32 WS2_32 Ws2_32) +# find_library (IPHLPAPI_LIBRARY NAMES iphlpapi) + set(WINSOCK2_LIBRARY ws2_32) + set(IPHLPAPI_LIBRARY iphlpapi) + set (LDLIBS ${WINSOCK2_LIBRARY} ${IPHLPAPI_LIBRARY} ${LDLIBS}) +#elseif (CMAKE_SYSTEM_NAME STREQUAL "Solaris") +# find_library (SOCKET_LIBRARY NAMES socket) +# find_library (NSL_LIBRARY NAMES nsl) +# find_library (RESOLV_LIBRARY NAMES resolv) +# set (LDLIBS ${SOCKET_LIBRARY} ${NSL_LIBRARY} ${RESOLV_LIBRARY} ${LDLIBS}) +endif (WIN32) + +if (NOT UPNPC_BUILD_STATIC AND NOT UPNPC_BUILD_SHARED) + message (FATAL "Both shared and static libraries are disabled!") +endif (NOT UPNPC_BUILD_STATIC AND NOT UPNPC_BUILD_SHARED) + +if (UPNPC_BUILD_STATIC) + add_library (upnpc-static STATIC ${MINIUPNPC_SOURCES}) + set_target_properties (upnpc-static PROPERTIES OUTPUT_NAME "miniupnpc") + target_link_libraries (upnpc-static ${LDLIBS}) + set (UPNPC_INSTALL_TARGETS ${UPNPC_INSTALL_TARGETS} upnpc-static) + set (UPNPC_LIBRARY_TARGET upnpc-static) +endif (UPNPC_BUILD_STATIC) + +if (UPNPC_BUILD_SHARED) + add_library (upnpc-shared SHARED ${MINIUPNPC_SOURCES}) + set_target_properties (upnpc-shared PROPERTIES OUTPUT_NAME "miniupnpc") + set_target_properties (upnpc-shared PROPERTIES VERSION ${MINIUPNPC_VERSION}) + set_target_properties (upnpc-shared PROPERTIES SOVERSION ${MINIUPNPC_API_VERSION}) + target_link_libraries (upnpc-shared ${LDLIBS}) + set (UPNPC_INSTALL_TARGETS ${UPNPC_INSTALL_TARGETS} upnpc-shared) + set (UPNPC_LIBRARY_TARGET upnpc-shared) +endif (UPNPC_BUILD_SHARED) + +if (UPNPC_BUILD_TESTS) + add_executable (testminixml testminixml.c minixml.c igd_desc_parse.c) + target_link_libraries (testminixml ${LDLIBS}) + + add_executable (minixmlvalid minixmlvalid.c minixml.c) + target_link_libraries (minixmlvalid ${LDLIBS}) + + add_executable (testupnpreplyparse testupnpreplyparse.c + minixml.c upnpreplyparse.c) + target_link_libraries (testupnpreplyparse ${LDLIBS}) + + add_executable (testigddescparse testigddescparse.c + igd_desc_parse.c minixml.c miniupnpc.c miniwget.c minissdpc.c + upnpcommands.c upnpreplyparse.c minisoap.c connecthostport.c + portlistingparse.c receivedata.c + ) + target_link_libraries (testigddescparse ${LDLIBS}) + + add_executable (testminiwget testminiwget.c + miniwget.c miniupnpc.c minisoap.c upnpcommands.c minissdpc.c + upnpreplyparse.c minixml.c igd_desc_parse.c connecthostport.c + portlistingparse.c receivedata.c + ) + target_link_libraries (testminiwget ${LDLIBS}) + +# set (UPNPC_INSTALL_TARGETS ${UPNPC_INSTALL_TARGETS} testminixml minixmlvalid testupnpreplyparse testigddescparse testminiwget) +endif (UPNPC_BUILD_TESTS) + + +install (TARGETS ${UPNPC_INSTALL_TARGETS} + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib${LIB_SUFFIX} + ARCHIVE DESTINATION lib${LIB_SUFFIX} +) +install (FILES + miniupnpc.h + miniwget.h + upnpcommands.h + igd_desc_parse.h + upnpreplyparse.h + upnperrors.h + declspec.h + DESTINATION include/miniupnpc +) + +set (CONFIGURED YES CACHE INTERNAL "") + +# vim: ts=2:sw=2 diff --git a/contrib/miniupnpc/Changelog.txt b/contrib/miniupnpc/Changelog.txt new file mode 100644 index 00000000..53e9a112 --- /dev/null +++ b/contrib/miniupnpc/Changelog.txt @@ -0,0 +1,585 @@ +$Id: Changelog.txt,v 1.193 2014/02/05 17:26:45 nanard Exp $ +miniUPnP client Changelog. + +2014/02/05: + handle EINPROGRESS after connect() + +2014/02/03: + minixml now handle XML comments + +VERSION 1.9 : released 2014/01/31 + +2014/01/31: + added argument remoteHost to UPNP_GetSpecificPortMappingEntry() + increment API_VERSION to 10 + +2013/12/09: + --help and -h arguments in upnpc.c + +2013/10/07: + fixed potential buffer overrun in miniwget.c + Modified UPNP_GetValidIGD() to check for ExternalIpAddress + +2013/08/01: + define MAXHOSTNAMELEN if not already done + +2013/06/06: + update upnpreplyparse to allow larger values (128 chars instead of 64) + +2013/05/14: + Update upnpreplyparse to take into account "empty" elements + validate upnpreplyparse.c code with "make check" + +2013/05/03: + Fix Solaris build thanks to Maciej Małecki + +2013/04/27: + Fix testminiwget.sh for BSD + +2013/03/23: + Fixed Makefile for *BSD + +2013/03/11: + Update Makefile to use JNAerator version 0.11 + +2013/02/11: + Fix testminiwget.sh for use with dash + Use $(DESTDIR) in Makefile + +VERSION 1.8 : released 2013/02/06 + +2012/10/16: + fix testminiwget with no IPv6 support + +2012/09/27: + Rename all include guards to not clash with C99 + (7.1.3 Reserved identifiers). + +2012/08/30: + Added -e option to upnpc program (set description for port mappings) + +2012/08/29: + Python 3 support (thanks to Christopher Foo) + +2012/08/11: + Fix a memory link in UPNP_GetValidIGD() + Try to handle scope id in link local IPv6 URL under MS Windows + +2012/07/20: + Disable HAS_IP_MREQN on DragonFly BSD + +2012/06/28: + GetUPNPUrls() now inserts scope into link-local IPv6 addresses + +2012/06/23: + More error return checks in upnpc.c + #define MINIUPNPC_GET_SRC_ADDR enables receivedata() to get scope_id + parseURL() now parses IPv6 addresses scope + new parameter for miniwget() : IPv6 address scope + increment API_VERSION to 9 + +2012/06/20: + fixed CMakeLists.txt + +2012/05/29 + Improvements in testminiwget.sh + +VERSION 1.7 : released 2012/05/24 + +2012/05/01: + Cleanup settings of CFLAGS in Makefile + Fix signed/unsigned integer comparaisons + +2012/04/20: + Allow to specify protocol with TCP or UDP for -A option + +2012/04/09: + Only try to fetch XML description once in UPNP_GetValidIGD() + Added -ansi flag to compilation, and fixed C++ comments to ANSI C comments. + +2012/04/05: + minor improvements to minihttptestserver.c + +2012/03/15: + upnperrors.c returns valid error string for unrecognized error codes + +2012/03/08: + make minihttptestserver listen on loopback interface instead of 0.0.0.0 + +2012/01/25: + Maven installation thanks to Alexey Kuznetsov + +2012/01/21: + Replace WIN32 macro by _WIN32 + +2012/01/19: + Fixes in java wrappers thanks to Alexey Kuznetsov : + https://github.com/axet/miniupnp/tree/fix-javatest/miniupnpc + Make and install .deb packages (python) thanks to Alexey Kuznetsov : + https://github.com/axet/miniupnp/tree/feature-debbuild/miniupnpc + +2012/01/07: + The multicast interface can now be specified by name with IPv4. + +2012/01/02: + Install man page + +2011/11/25: + added header to Port Mappings list in upnpc.c + +2011/10/09: + Makefile : make clean now removes jnaerator generated files. + MINIUPNPC_VERSION in miniupnpc.h (updated by make) + +2011/09/12: + added rootdescURL to UPNPUrls structure. + +VERSION 1.6 : released 2011/07/25 + +2011/07/25: + Update doc for version 1.6 release + +2011/06/18: + Fix for windows in miniwget.c + +2011/06/04: + display remote host in port mapping listing + +2011/06/03: + Fix in make install : there were missing headers + +2011/05/26: + Fix the socket leak in miniwget thanks to Richard Marsh. + Permit to add leaseduration in -a command. Display lease duration. + +2011/05/15: + Try both LinkLocal and SiteLocal multicast address for SSDP in IPv6 + +2011/05/09: + add a test in testminiwget.sh. + more error checking in miniwget.c + +2011/05/06: + Adding some tool to test and validate miniwget.c + simplified and debugged miniwget.c + +2011/04/11: + moving ReceiveData() to a receivedata.c file. + parsing presentation url + adding IGD v2 WANIPv6FirewallControl commands + +2011/04/10: + update of miniupnpcmodule.c + comments in miniwget.c, update in testminiwget + Adding errors codes from IGD v2 + new functions in upnpc.c for IGD v2 + +2011/04/09: + Support for litteral ip v6 address in miniwget + +2011/04/08: + Adding support for urn:schemas-upnp-org:service:WANIPv6FirewallControl:1 + Updating APIVERSION + Supporting IPV6 in upnpDiscover() + Adding a -6 option to upnpc command line tool + +2011/03/18: + miniwget/parseURL() : return an error when url param is null. + fixing GetListOfPortMappings() + +2011/03/14: + upnpDiscover() now reporting an error code. + improvements in comments. + +2011/03/11: + adding miniupnpcstrings.h.cmake and CMakeLists.txt files. + +2011/02/15: + Implementation of GetListOfPortMappings() + +2011/02/07: + updates to minixml to support character data starting with spaces + minixml now support CDATA + upnpreplyparse treats specificaly + change in simpleUPnPcommand to return the buffer (simplification) + +2011/02/06: + Added leaseDuration argument to AddPortMapping() + Starting to implement GetListOfPortMappings() + +2011/01/11: + updating wingenminiupnpcstrings.c + +2011/01/04: + improving updateminiupnpcstrings.sh + +VERSION 1.5 : released 2011/01/01 + +2010/12/21: + use NO_GETADDRINFO macro to disable the use of getaddrinfo/freeaddrinfo + +2010/12/11: + Improvements on getHTTPResponse() code. + +2010/12/09: + new code for miniwget that handle Chunked transfer encoding + using getHTTPResponse() in SOAP call code + Adding MANIFEST.in for 'python setup.py bdist_rpm' + +2010/11/25: + changes to minissdpc.c to compile under Win32. + see http://miniupnp.tuxfamily.org/forum/viewtopic.php?t=729 + +2010/09/17: + Various improvement to Makefile from Michał Górny + +2010/08/05: + Adding the script "external-ip.sh" from Reuben Hawkins + +2010/06/09: + update to python module to match modification made on 2010/04/05 + update to Java test code to match modification made on 2010/04/05 + all UPNP_* function now return an error if the SOAP request failed + at HTTP level. + +2010/04/17: + Using GetBestRoute() under win32 in order to find the + right interface to use. + +2010/04/12: + Retrying with HTTP/1.1 if HTTP/1.0 failed. see + http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1703 + +2010/04/07: + avoid returning duplicates in upnpDiscover() + +2010/04/05: + Create a connecthostport.h/.c with connecthostport() function + and use it in miniwget and miniupnpc. + Use getnameinfo() instead of inet_ntop or inet_ntoa + Work to make miniupnpc IPV6 compatible... + Add java test code. + Big changes in order to support device having both WANIPConnection + and WANPPPConnection. + +2010/04/04: + Use getaddrinfo() instead of gethostbyname() in miniwget. + +2010/01/06: + #define _DARWIN_C_SOURCE for Mac OS X + +2009/12/19: + Improve MinGW32 build + +2009/12/11: + adding a MSVC9 project to build the static library and executable + +2009/12/10: + Fixing some compilation stuff for Windows/MinGW + +2009/12/07: + adaptations in Makefile and updateminiupnpcstring.sh for AmigaOS + some fixes for Windows when using virtual ethernet adapters (it is the + case with VMWare installed). + +2009/12/04: + some fixes for AmigaOS compilation + Changed HTTP version to HTTP/1.0 for Soap too (to prevent chunked + transfer encoding) + +2009/12/03: + updating printIDG and testigddescparse.c for debug. + modifications to compile under AmigaOS + adding a testminiwget program + Changed miniwget to advertise itself as HTTP/1.0 to prevent chunked + transfer encoding + +2009/11/26: + fixing updateminiupnpcstrings.sh to take into account + which command that does not return an error code. + +VERSION 1.4 : released 2009/10/30 + +2009/10/16: + using Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS in python module. + +2009/10/10: + Some fixes for compilation under Solaris + compilation fixes : http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1464 + +2009/09/21: + fixing the code to ignore EINTR during connect() calls. + +2009/08/07: + Set socket timeout for connect() + Some cleanup in miniwget.c + +2009/08/04: + remove multiple redirections with -d in upnpc.c + Print textual error code in upnpc.c + Ignore EINTR during the connect() and poll() calls. + +2009/07/29: + fix in updateminiupnpcstrings.sh if OS name contains "/" + Sending a correct value for MX: field in SSDP request + +2009/07/20: + Change the Makefile to compile under Mac OS X + Fixed a stackoverflow in getDevicesFromMiniSSDPD() + +2009/07/09: + Compile under Haiku + generate miniupnpcstrings.h.in from miniupnpcstrings.h + +2009/06/04: + patching to compile under CygWin and cross compile for minGW + +VERSION 1.3 : + +2009/04/17: + updating python module + Use strtoull() when using C99 + +2009/02/28: + Fixed miniwget.c for compiling under sun + +2008/12/18: + cleanup in Makefile (thanks to Paul de Weerd) + minissdpc.c : win32 compatibility + miniupnpc.c : changed xmlns prefix from 'm' to 'u' + Removed NDEBUG (using DEBUG) + +2008/10/14: + Added the ExternalHost argument to DeletePortMapping() + +2008/10/11: + Added the ExternalHost argument to AddPortMapping() + Put a correct User-Agent: header in HTTP requests. + +VERSION 1.2 : + +2008/10/07: + Update docs + +2008/09/25: + Integrated sameport patch from Dario Meloni : Added a "sameport" + argument to upnpDiscover(). + +2008/07/18: + small modif to make Clang happy :) + +2008/07/17: + #define SOAPPREFIX "s" in miniupnpc.c in order to remove SOAP-ENV... + +2008/07/14: + include declspec.h in installation (to /usr/include/miniupnpc) + +VERSION 1.1 : + +2008/07/04: + standard options for install/ln instead of gnu-specific stuff. + +2008/07/03: + now builds a .dll and .lib with win32. (mingw32) + +2008/04/28: + make install now install the binary of the upnpc tool + +2008/04/27: + added testupnpigd.py + added error strings for miniupnpc "internal" errors + improved python module error/exception reporting. + +2008/04/23: + Completely rewrite igd_desc_parse.c in order to be compatible with + Linksys WAG200G + Added testigddescparse + updated python module + +VERSION 1.0 : + +2008/02/21: + put some #ifdef DEBUG around DisplayNameValueList() + +2008/02/18: + Improved error reporting in upnpcommands.c + UPNP_GetStatusInfo() returns LastConnectionError + +2008/02/16: + better error handling in minisoap.c + improving display of "valid IGD found" in upnpc.c + +2008/02/03: + Fixing UPNP_GetValidIGD() + improved make install :) + +2007/12/22: + Adding upnperrors.c/h to provide a strupnperror() function + used to translate UPnP error codes to string. + +2007/12/19: + Fixing getDevicesFromMiniSSDPD() + improved error reporting of UPnP functions + +2007/12/18: + It is now possible to specify a different location for MiniSSDPd socket. + working with MiniSSDPd is now more efficient. + python module improved. + +2007/12/16: + improving error reporting + +2007/12/13: + Try to improve compatibility by using HTTP/1.0 instead of 1.1 and + XML a bit different for SOAP. + +2007/11/25: + fixed select() call for linux + +2007/11/15: + Added -fPIC to CFLAG for better shared library code. + +2007/11/02: + Fixed a potential socket leak in miniwget2() + +2007/10/16: + added a parameter to upnpDiscover() in order to allow the use of another + interface than the default multicast interface. + +2007/10/12: + Fixed the creation of symbolic link in Makefile + +2007/10/08: + Added man page + +2007/10/02: + fixed memory bug in GetUPNPUrls() + +2007/10/01: + fixes in the Makefile + Added UPNP_GetIGDFromUrl() and adapted the sample program accordingly. + Added SONAME in the shared library to please debian :) + fixed MS Windows compilation (minissdpd is not available under MS Windows). + +2007/09/25: + small change to Makefile to be able to install in a different location + (default is /usr) + +2007/09/24: + now compiling both shared and static library + +2007/09/19: + Cosmetic changes on upnpc.c + +2007/09/02: + adapting to new miniSSDPd (release version ?) + +2007/08/31: + Usage of miniSSDPd to skip discovery process. + +2007/08/27: + fixed python module to allow compilation with Python older than Python 2.4 + +2007/06/12: + Added a python module. + +2007/05/19: + Fixed compilation under MinGW + +2007/05/15: + fixed a memory leak in AddPortMapping() + Added testupnpreplyparse executable to check the parsing of + upnp soap messages + minixml now ignore namespace prefixes. + +2007/04/26: + upnpc now displays external ip address with -s or -l + +2007/04/11: + changed MINIUPNPC_URL_MAXSIZE to 128 to accomodate the "BT Voyager 210" + +2007/03/19: + cleanup in miniwget.c + +2007/03/01: + Small typo fix... + +2007/01/30: + Now parsing the HTTP header from SOAP responses in order to + get content-length value. + +2007/01/29: + Fixed the Soap Query to speedup the HTTP request. + added some Win32 DLL stuff... + +2007/01/27: + Fixed some WIN32 compatibility issues + +2006/12/14: + Added UPNPIGD_IsConnected() function in miniupnp.c/.h + Added UPNP_GetValidIGD() in miniupnp.c/.h + cleaned upnpc.c main(). now using UPNP_GetValidIGD() + +2006/12/07: + Version 1.0-RC1 released + +2006/12/03: + Minor changes to compile under SunOS/Solaris + +2006/11/30: + made a minixml parser validator program + updated minixml to handle attributes correctly + +2006/11/22: + Added a -r option to the upnpc sample thanks to Alexander Hubmann. + +2006/11/19: + Cleanup code to make it more ANSI C compliant + +2006/11/10: + detect and display local lan address. + +2006/11/04: + Packets and Bytes Sent/Received are now unsigned int. + +2006/11/01: + Bug fix thanks to Giuseppe D'Angelo + +2006/10/31: + C++ compatibility for .h files. + Added a way to get ip Address on the LAN used to reach the IGD. + +2006/10/25: + Added M-SEARCH to the services in the discovery process. + +2006/10/22: + updated the Makefile to use makedepend, added a "make install" + update Makefile + +2006/10/20: + fixing the description url parsing thanks to patch sent by + Wayne Dawe. + Fixed/translated some comments. + Implemented a better discover process, first looking + for IGD then for root devices (as some devices only reply to + M-SEARCH for root devices). + +2006/09/02: + added freeUPNPDevlist() function. + +2006/08/04: + More command line arguments checking + +2006/08/01: + Added the .bat file to compile under Win32 with minGW32 + +2006/07/31: + Fixed the rootdesc parser (igd_desc_parse.c) + +2006/07/20: + parseMSEARCHReply() is now returning the ST: line as well + starting changes to detect several UPnP devices on the network + +2006/07/19: + using GetCommonLinkProperties to get down/upload bitrate + diff --git a/contrib/miniupnpc/LICENSE b/contrib/miniupnpc/LICENSE new file mode 100644 index 00000000..ac89a751 --- /dev/null +++ b/contrib/miniupnpc/LICENSE @@ -0,0 +1,27 @@ +MiniUPnPc +Copyright (c) 2005-2011, Thomas BERNARD +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * 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. + * The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + diff --git a/contrib/miniupnpc/MANIFEST.in b/contrib/miniupnpc/MANIFEST.in new file mode 100644 index 00000000..54b86f95 --- /dev/null +++ b/contrib/miniupnpc/MANIFEST.in @@ -0,0 +1,5 @@ +include README +include miniupnpcmodule.c +include setup.py +include *.h +include libminiupnpc.a diff --git a/contrib/miniupnpc/Makefile b/contrib/miniupnpc/Makefile new file mode 100644 index 00000000..eaf42f05 --- /dev/null +++ b/contrib/miniupnpc/Makefile @@ -0,0 +1,319 @@ +# $Id: Makefile,v 1.107 2014/01/31 14:19:12 nanard Exp $ +# MiniUPnP Project +# http://miniupnp.free.fr/ +# http://miniupnp.tuxfamily.org/ +# https://github.com/miniupnp/miniupnp +# (c) 2005-2014 Thomas Bernard +# to install use : +# $ make DESTDIR=/tmp/dummylocation install +# or +# $ INSTALLPREFIX=/usr/local make install +# or +# $ make install (default INSTALLPREFIX is /usr) +OS = $(shell uname -s) +VERSION = $(shell cat VERSION) + +ifeq ($(OS), Darwin) +JARSUFFIX=mac +endif +ifeq ($(OS), Linux) +JARSUFFIX=linux +endif +ifneq (,$(findstring NT-5.1,$(OS))) +JARSUFFIX=win32 +endif + +HAVE_IPV6 ?= yes +export HAVE_IPV6 + +CC ?= gcc +#AR = gar +#CFLAGS = -O -g -DDEBUG +CFLAGS ?= -O +CFLAGS += -Wall +CFLAGS += -W -Wstrict-prototypes +CFLAGS += -fno-common +CFLAGS += -DMINIUPNPC_SET_SOCKET_TIMEOUT +CFLAGS += -DMINIUPNPC_GET_SRC_ADDR +CFLAGS += -D_BSD_SOURCE -D_POSIX_C_SOURCE=1 +CFLAGS += -ansi +# -DNO_GETADDRINFO +INSTALL = install +SH = /bin/sh +JAVA = java +# see http://code.google.com/p/jnaerator/ +#JNAERATOR = jnaerator-0.9.7.jar +#JNAERATOR = jnaerator-0.9.8-shaded.jar +#JNAERATORARGS = -library miniupnpc +#JNAERATOR = jnaerator-0.10-shaded.jar +JNAERATOR = jnaerator-0.11-shaded.jar +JNAERATORARGS = -mode StandaloneJar -runtime JNAerator -library miniupnpc +JNAERATORBASEURL = http://jnaerator.googlecode.com/files/ + +ifeq (SunOS, $(OS)) + LDFLAGS=-lsocket -lnsl -lresolv +endif + +# APIVERSION is used to build SONAME +APIVERSION = 10 + +SRCS = igd_desc_parse.c miniupnpc.c minixml.c minisoap.c miniwget.c \ + upnpc.c upnpcommands.c upnpreplyparse.c testminixml.c \ + minixmlvalid.c testupnpreplyparse.c minissdpc.c \ + upnperrors.c testigddescparse.c testminiwget.c \ + connecthostport.c portlistingparse.c receivedata.c + +LIBOBJS = miniwget.o minixml.o igd_desc_parse.o minisoap.o \ + miniupnpc.o upnpreplyparse.o upnpcommands.o upnperrors.o \ + connecthostport.o portlistingparse.o receivedata.o + +ifneq ($(OS), AmigaOS) +CFLAGS := -fPIC $(CFLAGS) +LIBOBJS := $(LIBOBJS) minissdpc.o +endif + +OBJS = $(patsubst %.c,%.o,$(SRCS)) + +# HEADERS to install +HEADERS = miniupnpc.h miniwget.h upnpcommands.h igd_desc_parse.h \ + upnpreplyparse.h upnperrors.h miniupnpctypes.h \ + portlistingparse.h \ + declspec.h + +# library names +LIBRARY = libminiupnpc.a +ifeq ($(OS), Darwin) + SHAREDLIBRARY = libminiupnpc.dylib + SONAME = $(basename $(SHAREDLIBRARY)).$(APIVERSION).dylib + CFLAGS := -DMACOSX -D_DARWIN_C_SOURCE $(CFLAGS) +else +ifeq ($(JARSUFFIX), win32) + SHAREDLIBRARY = miniupnpc.dll +else + # Linux/BSD/etc. + SHAREDLIBRARY = libminiupnpc.so + SONAME = $(SHAREDLIBRARY).$(APIVERSION) +endif +endif + +EXECUTABLES = upnpc-static +EXECUTABLES_ADDTESTS = testminixml minixmlvalid testupnpreplyparse \ + testigddescparse testminiwget + +TESTMINIXMLOBJS = minixml.o igd_desc_parse.o testminixml.o + +TESTMINIWGETOBJS = miniwget.o testminiwget.o connecthostport.o receivedata.o + +TESTUPNPREPLYPARSE = testupnpreplyparse.o minixml.o upnpreplyparse.o + +TESTIGDDESCPARSE = testigddescparse.o igd_desc_parse.o minixml.o \ + miniupnpc.o miniwget.o upnpcommands.o upnpreplyparse.o \ + minisoap.o connecthostport.o receivedata.o \ + portlistingparse.o + +ifneq ($(OS), AmigaOS) +EXECUTABLES := $(EXECUTABLES) upnpc-shared +TESTMINIWGETOBJS := $(TESTMINIWGETOBJS) minissdpc.o +TESTIGDDESCPARSE := $(TESTIGDDESCPARSE) minissdpc.o +endif + +LIBDIR ?= lib +# install directories +INSTALLPREFIX ?= $(PREFIX)/usr +INSTALLDIRINC = $(INSTALLPREFIX)/include/miniupnpc +INSTALLDIRLIB = $(INSTALLPREFIX)/$(LIBDIR) +INSTALLDIRBIN = $(INSTALLPREFIX)/bin +INSTALLDIRMAN = $(INSTALLPREFIX)/share/man + +FILESTOINSTALL = $(LIBRARY) $(EXECUTABLES) +ifneq ($(OS), AmigaOS) +FILESTOINSTALL := $(FILESTOINSTALL) $(SHAREDLIBRARY) +endif + + +.PHONY: install clean depend all check test everything \ + installpythonmodule updateversion +# validateminixml validateminiwget + +all: $(LIBRARY) $(EXECUTABLES) + +test: check + +check: validateminixml validateminiwget validateupnpreplyparse + +everything: all $(EXECUTABLES_ADDTESTS) + +pythonmodule: $(LIBRARY) miniupnpcmodule.c setup.py + python setup.py build + touch $@ + +installpythonmodule: pythonmodule + python setup.py install + +pythonmodule3: $(LIBRARY) miniupnpcmodule.c setup.py + python3 setup.py build + touch $@ + +installpythonmodule3: pythonmodule3 + python3 setup.py install + +validateminixml: minixmlvalid + @echo "minixml validation test" + ./minixmlvalid + touch $@ + +validateminiwget: testminiwget minihttptestserver testminiwget.sh + @echo "miniwget validation test" + ./testminiwget.sh + touch $@ + +validateupnpreplyparse: testupnpreplyparse testupnpreplyparse.sh + @echo "upnpreplyparse validation test" + ./testupnpreplyparse.sh + touch $@ + +clean: + $(RM) $(LIBRARY) $(SHAREDLIBRARY) $(EXECUTABLES) $(OBJS) miniupnpcstrings.h + # clean python stuff + $(RM) pythonmodule pythonmodule3 + $(RM) validateminixml validateminiwget validateupnpreplyparse + $(RM) -r build/ dist/ + #python setup.py clean + # clean jnaerator stuff + $(RM) _jnaerator.* java/miniupnpc_$(OS).jar + +distclean: clean + $(RM) $(JNAERATOR) java/*.jar java/*.class out.errors.txt + +updateversion: miniupnpc.h + cp miniupnpc.h miniupnpc.h.bak + sed 's/\(.*MINIUPNPC_API_VERSION\s\+\)[0-9]\+/\1$(APIVERSION)/' < miniupnpc.h.bak > miniupnpc.h + +install: updateversion $(FILESTOINSTALL) + $(INSTALL) -d $(DESTDIR)$(INSTALLDIRINC) + $(INSTALL) -m 644 $(HEADERS) $(DESTDIR)$(INSTALLDIRINC) + $(INSTALL) -d $(DESTDIR)$(INSTALLDIRLIB) + $(INSTALL) -m 644 $(LIBRARY) $(DESTDIR)$(INSTALLDIRLIB) +ifneq ($(OS), AmigaOS) + $(INSTALL) -m 644 $(SHAREDLIBRARY) $(DESTDIR)$(INSTALLDIRLIB)/$(SONAME) + ln -fs $(SONAME) $(DESTDIR)$(INSTALLDIRLIB)/$(SHAREDLIBRARY) +endif + $(INSTALL) -d $(DESTDIR)$(INSTALLDIRBIN) +ifeq ($(OS), AmigaOS) + $(INSTALL) -m 755 upnpc-static $(DESTDIR)$(INSTALLDIRBIN)/upnpc +else + $(INSTALL) -m 755 upnpc-shared $(DESTDIR)$(INSTALLDIRBIN)/upnpc +endif + $(INSTALL) -m 755 external-ip.sh $(DESTDIR)$(INSTALLDIRBIN)/external-ip +ifneq ($(OS), AmigaOS) + $(INSTALL) -d $(DESTDIR)$(INSTALLDIRMAN)/man3 + $(INSTALL) man3/miniupnpc.3 $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3 +ifeq ($(OS), Linux) + gzip $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3 +endif +endif + + +cleaninstall: + $(RM) -r $(DESTDIR)$(INSTALLDIRINC) + $(RM) $(DESTDIR)$(INSTALLDIRLIB)/$(LIBRARY) + $(RM) $(DESTDIR)$(INSTALLDIRLIB)/$(SHAREDLIBRARY) + +depend: + makedepend -Y -- $(CFLAGS) -- $(SRCS) 2>/dev/null + +$(LIBRARY): $(LIBOBJS) + $(AR) crs $@ $? + +$(SHAREDLIBRARY): $(LIBOBJS) +ifeq ($(OS), Darwin) +# $(CC) -dynamiclib $(LDFLAGS) -Wl,-install_name,$(SONAME) -o $@ $^ + $(CC) -dynamiclib $(LDFLAGS) -Wl,-install_name,$(INSTALLDIRLIB)/$(SONAME) -o $@ $^ +else + $(CC) -shared $(LDFLAGS) -Wl,-soname,$(SONAME) -o $@ $^ +endif + +upnpc-static: upnpc.o $(LIBRARY) + $(CC) $(LDFLAGS) -o $@ $^ + +upnpc-shared: upnpc.o $(SHAREDLIBRARY) + $(CC) $(LDFLAGS) -o $@ $^ + +testminixml: $(TESTMINIXMLOBJS) + +testminiwget: $(TESTMINIWGETOBJS) + +minixmlvalid: minixml.o minixmlvalid.o + +testupnpreplyparse: $(TESTUPNPREPLYPARSE) + +testigddescparse: $(TESTIGDDESCPARSE) + +miniupnpcstrings.h: miniupnpcstrings.h.in updateminiupnpcstrings.sh VERSION + $(SH) updateminiupnpcstrings.sh + +# ftp tool supplied with OpenBSD can download files from http. +jnaerator-%.jar: + wget $(JNAERATORBASEURL)/$@ || \ + curl -o $@ $(JNAERATORBASEURL)/$@ || \ + ftp $(JNAERATORBASEURL)/$@ + +jar: $(SHAREDLIBRARY) $(JNAERATOR) + $(JAVA) -jar $(JNAERATOR) $(JNAERATORARGS) \ + miniupnpc.h declspec.h upnpcommands.h upnpreplyparse.h \ + igd_desc_parse.h miniwget.h upnperrors.h $(SHAREDLIBRARY) \ + -package fr.free.miniupnp -o . -jar java/miniupnpc_$(JARSUFFIX).jar -v + +mvn_install: + mvn install:install-file -Dfile=java/miniupnpc_$(JARSUFFIX).jar \ + -DgroupId=com.github \ + -DartifactId=miniupnp \ + -Dversion=$(VERSION) \ + -Dpackaging=jar \ + -Dclassifier=$(JARSUFFIX) \ + -DgeneratePom=true \ + -DcreateChecksum=true + +# make .deb packages +deb: /usr/share/pyshared/stdeb all + (python setup.py --command-packages=stdeb.command bdist_deb) + +# install .deb packages +ideb: + (sudo dpkg -i deb_dist/*.deb) + +/usr/share/pyshared/stdeb: /usr/share/doc/python-all-dev + (sudo apt-get install python-stdeb) + +/usr/share/doc/python-all-dev: + (sudo apt-get install python-all-dev) + +minihttptestserver: minihttptestserver.o + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +igd_desc_parse.o: igd_desc_parse.h +miniupnpc.o: miniupnpc.h declspec.h igd_desc_parse.h minissdpc.h miniwget.h +miniupnpc.o: minisoap.h minixml.h upnpcommands.h upnpreplyparse.h +miniupnpc.o: portlistingparse.h miniupnpctypes.h connecthostport.h +miniupnpc.o: receivedata.h +minixml.o: minixml.h +minisoap.o: minisoap.h miniupnpcstrings.h +miniwget.o: miniupnpcstrings.h miniwget.h declspec.h connecthostport.h +miniwget.o: receivedata.h +upnpc.o: miniwget.h declspec.h miniupnpc.h igd_desc_parse.h upnpcommands.h +upnpc.o: upnpreplyparse.h portlistingparse.h miniupnpctypes.h upnperrors.h +upnpcommands.o: upnpcommands.h upnpreplyparse.h portlistingparse.h declspec.h +upnpcommands.o: miniupnpctypes.h miniupnpc.h igd_desc_parse.h +upnpreplyparse.o: upnpreplyparse.h minixml.h +testminixml.o: minixml.h igd_desc_parse.h +minixmlvalid.o: minixml.h +testupnpreplyparse.o: upnpreplyparse.h +minissdpc.o: minissdpc.h miniupnpc.h declspec.h igd_desc_parse.h codelength.h +upnperrors.o: upnperrors.h declspec.h upnpcommands.h upnpreplyparse.h +upnperrors.o: portlistingparse.h miniupnpctypes.h miniupnpc.h +upnperrors.o: igd_desc_parse.h +testigddescparse.o: igd_desc_parse.h minixml.h miniupnpc.h declspec.h +testminiwget.o: miniwget.h declspec.h +connecthostport.o: connecthostport.h +receivedata.o: receivedata.h diff --git a/contrib/miniupnpc/Makefile.mingw b/contrib/miniupnpc/Makefile.mingw new file mode 100644 index 00000000..60b3f1b1 --- /dev/null +++ b/contrib/miniupnpc/Makefile.mingw @@ -0,0 +1,91 @@ +# $Id: Makefile.mingw,v 1.18 2014/01/17 09:04:01 nanard Exp $ +# Miniupnp project. +# http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ +# (c) 2005-2014 Thomas Bernard +# This Makefile is made for MinGW +# +CC = gcc +#CFLAGS = -Wall -g -DDEBUG -D_WIN32_WINNT=0X501 +CFLAGS = -Wall -Os -DNDEBUG -D_WIN32_WINNT=0X501 +LDLIBS = -lws2_32 -liphlpapi +# -lwsock32 +# -liphlpapi is needed for GetBestRoute() and GetIpAddrTable() +PYTHON=\utils\python25\python +OBJS=miniwget.o minixml.o igd_desc_parse.o minisoap.o \ + miniupnpc.o upnpreplyparse.o upnpcommands.o upnperrors.o \ + connecthostport.o portlistingparse.o receivedata.o +OBJSDLL=$(addprefix dll/, $(OBJS)) + +all: init upnpc-static upnpc-shared testminixml libminiupnpc.a miniupnpc.dll + +init: + mkdir dll + echo init > init + +clean: + del upnpc testminixml *.o + del dll\*.o + del *.exe + del miniupnpc.dll + del libminiupnpc.a + +libminiupnpc.a: $(OBJS) + $(AR) cr $@ $? + +pythonmodule: libminiupnpc.a + $(PYTHON) setupmingw32.py build --compiler=mingw32 + $(PYTHON) setupmingw32.py install --skip-build + +miniupnpc.dll: libminiupnpc.a $(OBJSDLL) + dllwrap -k --driver-name gcc \ + --def miniupnpc.def \ + --output-def miniupnpc.dll.def \ + --implib miniupnpc.lib -o $@ \ + $(OBJSDLL) $(LDLIBS) + +miniupnpc.lib: miniupnpc.dll + echo $@ generated with $< + +dll/upnpc.o: upnpc.o + echo $@ generated with $< + +.c.o: + $(CC) $(CFLAGS) -DSTATICLIB -c -o $@ $< + $(CC) $(CFLAGS) -DMINIUPNP_EXPORTS -c -o dll/$@ $< + +upnpc.o: + $(CC) $(CFLAGS) -DSTATICLIB -c -o $@ $< + $(CC) $(CFLAGS) -c -o dll/$@ $< + +# --enable-stdcall-fixup +upnpc-static: upnpc.o libminiupnpc.a + $(CC) -o $@ $^ $(LDLIBS) + +upnpc-shared: dll/upnpc.o miniupnpc.lib + $(CC) -o $@ $^ $(LDLIBS) + +wingenminiupnpcstrings: wingenminiupnpcstrings.o + +wingenminiupnpcstrings.o: wingenminiupnpcstrings.c + +miniupnpcstrings.h: miniupnpcstrings.h.in wingenminiupnpcstrings + wingenminiupnpcstrings $< $@ + +minixml.o: minixml.c minixml.h miniupnpcstrings.h + +upnpc.o: upnpc.c miniwget.h minisoap.h miniupnpc.h igd_desc_parse.h upnpreplyparse.h upnpcommands.h upnperrors.h + +miniwget.o: miniwget.c miniwget.h miniupnpcstrings.h connecthostport.h + +minisoap.o: minisoap.c minisoap.h miniupnpcstrings.h + +miniupnpc.o: miniupnpc.c miniupnpc.h minisoap.h miniwget.h minixml.h + +igd_desc_parse.o: igd_desc_parse.c igd_desc_parse.h + +testminixml: minixml.o igd_desc_parse.o testminixml.c + +upnpreplyparse.o: upnpreplyparse.c upnpreplyparse.h minixml.h + +upnpcommands.o: upnpcommands.c upnpcommands.h upnpreplyparse.h miniupnpc.h portlistingparse.h + diff --git a/contrib/miniupnpc/README b/contrib/miniupnpc/README new file mode 100644 index 00000000..b23478de --- /dev/null +++ b/contrib/miniupnpc/README @@ -0,0 +1,66 @@ +Project: miniupnp +Project web page: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ +github: https://github.com/miniupnp/miniupnp +freecode: http://freecode.com/projects/miniupnp +Author: Thomas Bernard +Copyright (c) 2005-2012 Thomas Bernard +This software is subject to the conditions detailed in the +LICENSE file provided within this distribution. + + +For the comfort of Win32 users, bsdqueue.h is included in the distribution. +Its licence is included in the header of the file. +bsdqueue.h is a copy of the sys/queue.h of an OpenBSD system. + + +* miniUPnP Client - miniUPnPc * + +To compile, simply run 'gmake' (could be 'make' on your system). +Under win32, to compile with MinGW, type "mingw32make.bat". +MS Visual C solution and project files are supplied in the msvc/ subdirectory. + +The compilation is known to work under linux, FreeBSD, +OpenBSD, MacOS X, AmigaOS and cygwin. +The official AmigaOS4.1 SDK was used for AmigaOS4 and GeekGadgets for AmigaOS3. +upx (http://upx.sourceforge.net) is used to compress the win32 .exe files. + +To install the library and headers on the system use : +> su +> make install +> exit + +alternatively, to install into a specific location, use : +> INSTALLPREFIX=/usr/local make install + +upnpc.c is a sample client using the libminiupnpc. +To use the libminiupnpc in your application, link it with +libminiupnpc.a (or .so) and use the following functions found in miniupnpc.h, +upnpcommands.h and miniwget.h : +- upnpDiscover() +- miniwget() +- parserootdesc() +- GetUPNPUrls() +- UPNP_* (calling UPNP methods) + +Note : use #include etc... for the includes +and -lminiupnpc for the link + +Discovery process is speeded up when MiniSSDPd is running on the machine. + + +* Python module * + +you can build a python module with 'make pythonmodule' +and install it with 'make installpythonmodule'. +setup.py (and setupmingw32.py) are included in the distribution. + + +Feel free to contact me if you have any problem : +e-mail : miniupnp@free.fr + +If you are using libminiupnpc in your application, please +send me an email ! + +For any question, you can use the web forum : +http://miniupnp.tuxfamily.org/forum/ + diff --git a/contrib/miniupnpc/VERSION b/contrib/miniupnpc/VERSION new file mode 100644 index 00000000..2e0e38c6 --- /dev/null +++ b/contrib/miniupnpc/VERSION @@ -0,0 +1 @@ +1.9 diff --git a/contrib/miniupnpc/apiversions.txt b/contrib/miniupnpc/apiversions.txt new file mode 100644 index 00000000..69f61c79 --- /dev/null +++ b/contrib/miniupnpc/apiversions.txt @@ -0,0 +1,127 @@ +$Id: apiversions.txt,v 1.3 2014/01/31 13:14:32 nanard Exp $ + +Differences in API between miniUPnPc versions + +====================== miniUPnPc version 1.9 ====================== +API version 10 + +upnpcommands.h: + added argument remoteHost to UPNP_GetSpecificPortMappingEntry() + +miniupnpc.h: + updated macros : + #define MINIUPNPC_VERSION "1.9" + #define MINIUPNPC_API_VERSION 10 + +====================== miniUPnPc version 1.8 ====================== +API version 9 + +miniupnpc.h: + updated macros : + #define MINIUPNPC_VERSION "1.8" + #define MINIUPNPC_API_VERSION 9 + added "unsigned int scope_id;" to struct UPNPDev + added scope_id argument to GetUPNPUrls() + + + +====================== miniUPnPc version 1.7 ====================== +API version 8 + +miniupnpc.h : + add new macros : + #define MINIUPNPC_VERSION "1.7" + #define MINIUPNPC_API_VERSION 8 + add rootdescURL to struct UPNPUrls + + + +====================== miniUPnPc version 1.6 ====================== +API version 8 + +Adding support for IPv6. +igd_desc_parse.h : + struct IGDdatas_service : + add char presentationurl[MINIUPNPC_URL_MAXSIZE]; + struct IGDdatas : + add struct IGDdatas_service IPv6FC; +miniupnpc.h : + new macros : + #define UPNPDISCOVER_SUCCESS (0) + #define UPNPDISCOVER_UNKNOWN_ERROR (-1) + #define UPNPDISCOVER_SOCKET_ERROR (-101) + #define UPNPDISCOVER_MEMORY_ERROR (-102) + simpleUPnPcommand() prototype changed (but is normaly not used by API users) + add arguments ipv6 and error to upnpDiscover() : + struct UPNPDev * + upnpDiscover(int delay, const char * multicastif, + const char * minissdpdsock, int sameport, + int ipv6, + int * error); + add controlURL_6FC member to struct UPNPUrls : + struct UPNPUrls { + char * controlURL; + char * ipcondescURL; + char * controlURL_CIF; + char * controlURL_6FC; + }; + +upnpcommands.h : + add leaseDuration argument to UPNP_AddPortMapping() + add desc, enabled and leaseDuration arguments to UPNP_GetSpecificPortMappingEntry() + add UPNP_GetListOfPortMappings() function (IGDv2) + add IGDv2 IPv6 related functions : + UPNP_GetFirewallStatus() + UPNP_GetOutboundPinholeTimeout() + UPNP_AddPinhole() + UPNP_UpdatePinhole() + UPNP_DeletePinhole() + UPNP_CheckPinholeWorking() + UPNP_GetPinholePackets() + + + +====================== miniUPnPc version 1.5 ====================== +API version 5 + +new function : +int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *); +new macro in upnpcommands.h : +#define UPNPCOMMAND_HTTP_ERROR + +====================== miniUPnPc version 1.4 ====================== +Same API as version 1.3 + +====================== miniUPnPc version 1.3 ====================== +API version 4 + +Use UNSIGNED_INTEGER type for +UPNP_GetTotalBytesSent(), UPNP_GetTotalBytesReceived(), +UPNP_GetTotalPacketsSent(), UPNP_GetTotalPacketsReceived() +Add remoteHost argument to UPNP_AddPortMapping() and UPNP_DeletePortMapping() + +====================== miniUPnPc version 1.2 ====================== +API version 3 + +added sameport argument to upnpDiscover() +struct UPNPDev * +upnpDiscover(int delay, const char * multicastif, + const char * minissdpdsock, int sameport); + +====================== miniUPnPc Version 1.1 ====================== +Same API as 1.0 + + +====================== miniUPnPc Version 1.0 ====================== +API version 2 + + +struct UPNPDev { + struct UPNPDev * pNext; + char * descURL; + char * st; + char buffer[2]; +}; +struct UPNPDev * upnpDiscover(int delay, const char * multicastif, + const char * minissdpdsock); + diff --git a/contrib/miniupnpc/bsdqueue.h b/contrib/miniupnpc/bsdqueue.h new file mode 100644 index 00000000..c6afe1f7 --- /dev/null +++ b/contrib/miniupnpc/bsdqueue.h @@ -0,0 +1,531 @@ +/* $OpenBSD: queue.h,v 1.31 2005/11/25 08:06:25 otto Exp $ */ +/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +#ifdef QUEUE_MACRO_DEBUG +#define _Q_INVALIDATE(a) (a) = ((void *)-1) +#else +#define _Q_INVALIDATE(a) +#endif + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#ifdef SLIST_ENTRY +#undef SLIST_ENTRY +#endif + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List access methods. + */ +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_END(head) NULL +#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = SLIST_FIRST(head); \ + (var) != SLIST_END(head); \ + (var) = SLIST_NEXT(var, field)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != SLIST_END(head); \ + (varp) = &SLIST_NEXT((var), field)) + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) { \ + SLIST_FIRST(head) = SLIST_END(head); \ +} + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (0) + +#define SLIST_REMOVE_NEXT(head, elm, field) do { \ + (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->slh_first; \ + \ + while (curelm->field.sle_next != (elm)) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + _Q_INVALIDATE((elm)->field.sle_next); \ + } \ +} while (0) + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List access methods + */ +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_END(head) NULL +#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_FOREACH(var, head, field) \ + for((var) = LIST_FIRST(head); \ + (var)!= LIST_END(head); \ + (var) = LIST_NEXT(var, field)) + +/* + * List functions. + */ +#define LIST_INIT(head) do { \ + LIST_FIRST(head) = LIST_END(head); \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (0) + +#define LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ + _Q_INVALIDATE((elm)->field.le_prev); \ + _Q_INVALIDATE((elm)->field.le_next); \ +} while (0) + +#define LIST_REPLACE(elm, elm2, field) do { \ + if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ + (elm2)->field.le_next->field.le_prev = \ + &(elm2)->field.le_next; \ + (elm2)->field.le_prev = (elm)->field.le_prev; \ + *(elm2)->field.le_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.le_prev); \ + _Q_INVALIDATE((elm)->field.le_next); \ +} while (0) + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_END(head) NULL +#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for((var) = SIMPLEQ_FIRST(head); \ + (var) != SIMPLEQ_END(head); \ + (var) = SIMPLEQ_NEXT(var, field)) + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (0) + +#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +/* + * Tail queue definitions. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * tail queue access methods + */ +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_END(head) NULL +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +/* XXX */ +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) +#define TAILQ_EMPTY(head) \ + (TAILQ_FIRST(head) == TAILQ_END(head)) + +#define TAILQ_FOREACH(var, head, field) \ + for((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_NEXT(var, field)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_PREV(var, headname, field)) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +#define TAILQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ + (elm2)->field.tqe_next->field.tqe_prev = \ + &(elm2)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm2)->field.tqe_next; \ + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ + *(elm2)->field.tqe_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue access methods + */ +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_END(head) ((void *)(head)) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) +#define CIRCLEQ_EMPTY(head) \ + (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for((var) = CIRCLEQ_FIRST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_NEXT(var, field)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for((var) = CIRCLEQ_LAST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_PREV(var, field)) + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = CIRCLEQ_END(head); \ + (head)->cqh_last = CIRCLEQ_END(head); \ +} while (0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = CIRCLEQ_END(head); \ + if ((head)->cqh_last == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = CIRCLEQ_END(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ + _Q_INVALIDATE((elm)->field.cqe_prev); \ + _Q_INVALIDATE((elm)->field.cqe_next); \ +} while (0) + +#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ + CIRCLEQ_END(head)) \ + (head).cqh_last = (elm2); \ + else \ + (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ + if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ + CIRCLEQ_END(head)) \ + (head).cqh_first = (elm2); \ + else \ + (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ + _Q_INVALIDATE((elm)->field.cqe_prev); \ + _Q_INVALIDATE((elm)->field.cqe_next); \ +} while (0) + +#endif /* !_SYS_QUEUE_H_ */ diff --git a/contrib/miniupnpc/codelength.h b/contrib/miniupnpc/codelength.h new file mode 100644 index 00000000..d342bd14 --- /dev/null +++ b/contrib/miniupnpc/codelength.h @@ -0,0 +1,31 @@ +/* $Id: codelength.h,v 1.4 2012/09/27 15:40:29 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas BERNARD + * copyright (c) 2005-2011 Thomas Bernard + * This software is subjet to the conditions detailed in the + * provided LICENCE file. */ +#ifndef CODELENGTH_H_INCLUDED +#define CODELENGTH_H_INCLUDED + +/* Encode length by using 7bit per Byte : + * Most significant bit of each byte specifies that the + * following byte is part of the code */ +#define DECODELENGTH(n, p) n = 0; \ + do { n = (n << 7) | (*p & 0x7f); } \ + while((*(p++)&0x80) && (n<(1<<25))); + +#define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \ + n = 0; \ + do { \ + if((p) >= (p_limit)) break; \ + n = (n << 7) | (*(p) & 0x7f); \ + } while((*((p)++)&0x80) && (n<(1<<25))); + +#define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \ + if(n>=2097152) *(p++) = (n >> 21) | 0x80; \ + if(n>=16384) *(p++) = (n >> 14) | 0x80; \ + if(n>=128) *(p++) = (n >> 7) | 0x80; \ + *(p++) = n & 0x7f; + +#endif + diff --git a/contrib/miniupnpc/connecthostport.c b/contrib/miniupnpc/connecthostport.c new file mode 100644 index 00000000..d66ae315 --- /dev/null +++ b/contrib/miniupnpc/connecthostport.c @@ -0,0 +1,261 @@ +/* $Id: connecthostport.c,v 1.13 2014/03/31 12:36:36 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2010-2014 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. */ + +/* use getaddrinfo() or gethostbyname() + * uncomment the following line in order to use gethostbyname() */ +#ifdef NO_GETADDRINFO +#define USE_GETHOSTBYNAME +#endif + +#include +#include +#ifdef _WIN32 +#include +#include +#include +#define MAXHOSTNAMELEN 64 +#define snprintf _snprintf +#define herror +#define socklen_t int +#else /* #ifdef _WIN32 */ +#include +#include +#include +#include +#define closesocket close +#include +#include +/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions + * during the connect() call */ +#define MINIUPNPC_IGNORE_EINTR +#ifndef USE_GETHOSTBYNAME +#include +#include +#include +#endif /* #ifndef USE_GETHOSTBYNAME */ +#endif /* #else _WIN32 */ + +/* definition of PRINT_SOCKET_ERROR */ +#ifdef _WIN32 +#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); +#else +#define PRINT_SOCKET_ERROR(x) perror(x) +#endif + +#if defined(__amigaos__) || defined(__amigaos4__) +#define herror(A) printf("%s\n", A) +#endif + +#include "connecthostport.h" + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif + +/* connecthostport() + * return a socket connected (TCP) to the host and port + * or -1 in case of error */ +int connecthostport(const char * host, unsigned short port, + unsigned int scope_id) +{ + int s, n; +#ifdef USE_GETHOSTBYNAME + struct sockaddr_in dest; + struct hostent *hp; +#else /* #ifdef USE_GETHOSTBYNAME */ + char tmp_host[MAXHOSTNAMELEN+1]; + char port_str[8]; + struct addrinfo *ai, *p; + struct addrinfo hints; +#endif /* #ifdef USE_GETHOSTBYNAME */ +#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT + struct timeval timeout; +#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ + +#ifdef USE_GETHOSTBYNAME + hp = gethostbyname(host); + if(hp == NULL) + { + herror(host); + return -1; + } + memcpy(&dest.sin_addr, hp->h_addr, sizeof(dest.sin_addr)); + memset(dest.sin_zero, 0, sizeof(dest.sin_zero)); + s = socket(PF_INET, SOCK_STREAM, 0); + if(s < 0) + { + PRINT_SOCKET_ERROR("socket"); + return -1; + } +#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT + /* setting a 3 seconds timeout for the connect() call */ + timeout.tv_sec = 3; + timeout.tv_usec = 0; + if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt"); + } + timeout.tv_sec = 3; + timeout.tv_usec = 0; + if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt"); + } +#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ + dest.sin_family = AF_INET; + dest.sin_port = htons(port); + n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in)); +#ifdef MINIUPNPC_IGNORE_EINTR + /* EINTR The system call was interrupted by a signal that was caught + * EINPROGRESS The socket is nonblocking and the connection cannot + * be completed immediately. */ + while(n < 0 && (errno == EINTR || errno = EINPROGRESS)) + { + socklen_t len; + fd_set wset; + int err; + FD_ZERO(&wset); + FD_SET(s, &wset); + if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR) + continue; + /*len = 0;*/ + /*n = getpeername(s, NULL, &len);*/ + len = sizeof(err); + if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { + PRINT_SOCKET_ERROR("getsockopt"); + closesocket(s); + return -1; + } + if(err != 0) { + errno = err; + n = -1; + } + } +#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */ + if(n<0) + { + PRINT_SOCKET_ERROR("connect"); + closesocket(s); + return -1; + } +#else /* #ifdef USE_GETHOSTBYNAME */ + /* use getaddrinfo() instead of gethostbyname() */ + memset(&hints, 0, sizeof(hints)); + /* hints.ai_flags = AI_ADDRCONFIG; */ +#ifdef AI_NUMERICSERV + hints.ai_flags = AI_NUMERICSERV; +#endif + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */ + /* hints.ai_protocol = IPPROTO_TCP; */ + snprintf(port_str, sizeof(port_str), "%hu", port); + if(host[0] == '[') + { + /* literal ip v6 address */ + int i, j; + for(i = 0, j = 1; host[j] && (host[j] != ']') && i < MAXHOSTNAMELEN; i++, j++) + { + tmp_host[i] = host[j]; + if(0 == memcmp(host+j, "%25", 3)) /* %25 is just url encoding for '%' */ + j+=2; /* skip "25" */ + } + tmp_host[i] = '\0'; + } + else + { + strncpy(tmp_host, host, MAXHOSTNAMELEN); + } + tmp_host[MAXHOSTNAMELEN] = '\0'; + n = getaddrinfo(tmp_host, port_str, &hints, &ai); + if(n != 0) + { +#ifdef _WIN32 + fprintf(stderr, "getaddrinfo() error : %d\n", n); +#else + fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n)); +#endif + return -1; + } + s = -1; + for(p = ai; p; p = p->ai_next) + { + s = socket(p->ai_family, p->ai_socktype, p->ai_protocol); + if(s < 0) + continue; + if(p->ai_addr->sa_family == AF_INET6 && scope_id > 0) { + struct sockaddr_in6 * addr6 = (struct sockaddr_in6 *)p->ai_addr; + addr6->sin6_scope_id = scope_id; + } +#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT + /* setting a 3 seconds timeout for the connect() call */ + timeout.tv_sec = 3; + timeout.tv_usec = 0; + if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt"); + } + timeout.tv_sec = 3; + timeout.tv_usec = 0; + if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt"); + } +#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ + n = connect(s, p->ai_addr, p->ai_addrlen); +#ifdef MINIUPNPC_IGNORE_EINTR + /* EINTR The system call was interrupted by a signal that was caught + * EINPROGRESS The socket is nonblocking and the connection cannot + * be completed immediately. */ + while(n < 0 && (errno == EINTR || errno == EINPROGRESS)) + { + socklen_t len; + fd_set wset; + int err; + FD_ZERO(&wset); + FD_SET(s, &wset); + if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR) + continue; + /*len = 0;*/ + /*n = getpeername(s, NULL, &len);*/ + len = sizeof(err); + if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { + PRINT_SOCKET_ERROR("getsockopt"); + closesocket(s); + freeaddrinfo(ai); + return -1; + } + if(err != 0) { + errno = err; + n = -1; + } + } +#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */ + if(n < 0) + { + closesocket(s); + continue; + } + else + { + break; + } + } + freeaddrinfo(ai); + if(s < 0) + { + PRINT_SOCKET_ERROR("socket"); + return -1; + } + if(n < 0) + { + PRINT_SOCKET_ERROR("connect"); + return -1; + } +#endif /* #ifdef USE_GETHOSTBYNAME */ + return s; +} + diff --git a/contrib/miniupnpc/connecthostport.h b/contrib/miniupnpc/connecthostport.h new file mode 100644 index 00000000..56941d6f --- /dev/null +++ b/contrib/miniupnpc/connecthostport.h @@ -0,0 +1,18 @@ +/* $Id: connecthostport.h,v 1.3 2012/09/27 15:42:10 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ + * Author: Thomas Bernard + * Copyright (c) 2010-2012 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef CONNECTHOSTPORT_H_INCLUDED +#define CONNECTHOSTPORT_H_INCLUDED + +/* connecthostport() + * return a socket connected (TCP) to the host and port + * or -1 in case of error */ +int connecthostport(const char * host, unsigned short port, + unsigned int scope_id); + +#endif + diff --git a/contrib/miniupnpc/declspec.h b/contrib/miniupnpc/declspec.h new file mode 100644 index 00000000..77299693 --- /dev/null +++ b/contrib/miniupnpc/declspec.h @@ -0,0 +1,21 @@ +#ifndef DECLSPEC_H_INCLUDED +#define DECLSPEC_H_INCLUDED + +#if defined(_WIN32) && !defined(STATICLIB) + /* for windows dll */ + #ifdef MINIUPNP_EXPORTS + #define LIBSPEC __declspec(dllexport) + #else + #define LIBSPEC __declspec(dllimport) + #endif +#else + #if defined(__GNUC__) && __GNUC__ >= 4 + /* fix dynlib for OS X 10.9.2 and Apple LLVM version 5.0 */ + #define LIBSPEC __attribute__ ((visibility ("default"))) + #else + #define LIBSPEC + #endif +#endif + +#endif + diff --git a/contrib/miniupnpc/external-ip.sh b/contrib/miniupnpc/external-ip.sh new file mode 100644 index 00000000..965d86b2 --- /dev/null +++ b/contrib/miniupnpc/external-ip.sh @@ -0,0 +1,4 @@ +#!/bin/sh +# $Id: external-ip.sh,v 1.1 2010/08/05 12:57:41 nanard Exp $ +# (c) 2010 Reuben Hawkins +upnpc -s | grep ExternalIPAddress | sed 's/[^0-9\.]//g' diff --git a/contrib/miniupnpc/igd_desc_parse.c b/contrib/miniupnpc/igd_desc_parse.c new file mode 100644 index 00000000..6c3e6567 --- /dev/null +++ b/contrib/miniupnpc/igd_desc_parse.c @@ -0,0 +1,125 @@ +/* $Id: igd_desc_parse.c,v 1.14 2011/04/11 09:19:24 nanard Exp $ */ +/* Project : miniupnp + * http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2005-2010 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. */ + +#include "igd_desc_parse.h" +#include +#include + +/* Start element handler : + * update nesting level counter and copy element name */ +void IGDstartelt(void * d, const char * name, int l) +{ + struct IGDdatas * datas = (struct IGDdatas *)d; + memcpy( datas->cureltname, name, l); + datas->cureltname[l] = '\0'; + datas->level++; + if( (l==7) && !memcmp(name, "service", l) ) { + datas->tmp.controlurl[0] = '\0'; + datas->tmp.eventsuburl[0] = '\0'; + datas->tmp.scpdurl[0] = '\0'; + datas->tmp.servicetype[0] = '\0'; + } +} + +/* End element handler : + * update nesting level counter and update parser state if + * service element is parsed */ +void IGDendelt(void * d, const char * name, int l) +{ + struct IGDdatas * datas = (struct IGDdatas *)d; + datas->level--; + /*printf("endelt %2d %.*s\n", datas->level, l, name);*/ + if( (l==7) && !memcmp(name, "service", l) ) + { + /* + if( datas->state < 1 + && !strcmp(datas->servicetype, + // "urn:schemas-upnp-org:service:WANIPConnection:1") ) + "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")) + datas->state ++; + */ + if(0==strcmp(datas->tmp.servicetype, + "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")) { + memcpy(&datas->CIF, &datas->tmp, sizeof(struct IGDdatas_service)); + } else if(0==strcmp(datas->tmp.servicetype, + "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1")) { + memcpy(&datas->IPv6FC, &datas->tmp, sizeof(struct IGDdatas_service)); + } else if(0==strcmp(datas->tmp.servicetype, + "urn:schemas-upnp-org:service:WANIPConnection:1") + || 0==strcmp(datas->tmp.servicetype, + "urn:schemas-upnp-org:service:WANPPPConnection:1") ) { + if(datas->first.servicetype[0] == '\0') { + memcpy(&datas->first, &datas->tmp, sizeof(struct IGDdatas_service)); + } else { + memcpy(&datas->second, &datas->tmp, sizeof(struct IGDdatas_service)); + } + } + } +} + +/* Data handler : + * copy data depending on the current element name and state */ +void IGDdata(void * d, const char * data, int l) +{ + struct IGDdatas * datas = (struct IGDdatas *)d; + char * dstmember = 0; + /*printf("%2d %s : %.*s\n", + datas->level, datas->cureltname, l, data); */ + if( !strcmp(datas->cureltname, "URLBase") ) + dstmember = datas->urlbase; + else if( !strcmp(datas->cureltname, "presentationURL") ) + dstmember = datas->presentationurl; + else if( !strcmp(datas->cureltname, "serviceType") ) + dstmember = datas->tmp.servicetype; + else if( !strcmp(datas->cureltname, "controlURL") ) + dstmember = datas->tmp.controlurl; + else if( !strcmp(datas->cureltname, "eventSubURL") ) + dstmember = datas->tmp.eventsuburl; + else if( !strcmp(datas->cureltname, "SCPDURL") ) + dstmember = datas->tmp.scpdurl; +/* else if( !strcmp(datas->cureltname, "deviceType") ) + dstmember = datas->devicetype_tmp;*/ + if(dstmember) + { + if(l>=MINIUPNPC_URL_MAXSIZE) + l = MINIUPNPC_URL_MAXSIZE-1; + memcpy(dstmember, data, l); + dstmember[l] = '\0'; + } +} + +void printIGD(struct IGDdatas * d) +{ + printf("urlbase = '%s'\n", d->urlbase); + printf("WAN Device (Common interface config) :\n"); + /*printf(" deviceType = '%s'\n", d->CIF.devicetype);*/ + printf(" serviceType = '%s'\n", d->CIF.servicetype); + printf(" controlURL = '%s'\n", d->CIF.controlurl); + printf(" eventSubURL = '%s'\n", d->CIF.eventsuburl); + printf(" SCPDURL = '%s'\n", d->CIF.scpdurl); + printf("primary WAN Connection Device (IP or PPP Connection):\n"); + /*printf(" deviceType = '%s'\n", d->first.devicetype);*/ + printf(" servicetype = '%s'\n", d->first.servicetype); + printf(" controlURL = '%s'\n", d->first.controlurl); + printf(" eventSubURL = '%s'\n", d->first.eventsuburl); + printf(" SCPDURL = '%s'\n", d->first.scpdurl); + printf("secondary WAN Connection Device (IP or PPP Connection):\n"); + /*printf(" deviceType = '%s'\n", d->second.devicetype);*/ + printf(" servicetype = '%s'\n", d->second.servicetype); + printf(" controlURL = '%s'\n", d->second.controlurl); + printf(" eventSubURL = '%s'\n", d->second.eventsuburl); + printf(" SCPDURL = '%s'\n", d->second.scpdurl); + printf("WAN IPv6 Firewall Control :\n"); + /*printf(" deviceType = '%s'\n", d->IPv6FC.devicetype);*/ + printf(" servicetype = '%s'\n", d->IPv6FC.servicetype); + printf(" controlURL = '%s'\n", d->IPv6FC.controlurl); + printf(" eventSubURL = '%s'\n", d->IPv6FC.eventsuburl); + printf(" SCPDURL = '%s'\n", d->IPv6FC.scpdurl); +} + + diff --git a/contrib/miniupnpc/igd_desc_parse.h b/contrib/miniupnpc/igd_desc_parse.h new file mode 100644 index 00000000..0a49b019 --- /dev/null +++ b/contrib/miniupnpc/igd_desc_parse.h @@ -0,0 +1,48 @@ +/* $Id: igd_desc_parse.h,v 1.11 2012/10/16 16:49:02 nanard Exp $ */ +/* Project : miniupnp + * http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2005-2010 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * */ +#ifndef IGD_DESC_PARSE_H_INCLUDED +#define IGD_DESC_PARSE_H_INCLUDED + +/* Structure to store the result of the parsing of UPnP + * descriptions of Internet Gateway Devices */ +#define MINIUPNPC_URL_MAXSIZE (128) +struct IGDdatas_service { + char controlurl[MINIUPNPC_URL_MAXSIZE]; + char eventsuburl[MINIUPNPC_URL_MAXSIZE]; + char scpdurl[MINIUPNPC_URL_MAXSIZE]; + char servicetype[MINIUPNPC_URL_MAXSIZE]; + /*char devicetype[MINIUPNPC_URL_MAXSIZE];*/ +}; + +struct IGDdatas { + char cureltname[MINIUPNPC_URL_MAXSIZE]; + char urlbase[MINIUPNPC_URL_MAXSIZE]; + char presentationurl[MINIUPNPC_URL_MAXSIZE]; + int level; + /*int state;*/ + /* "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */ + struct IGDdatas_service CIF; + /* "urn:schemas-upnp-org:service:WANIPConnection:1" + * "urn:schemas-upnp-org:service:WANPPPConnection:1" */ + struct IGDdatas_service first; + /* if both WANIPConnection and WANPPPConnection are present */ + struct IGDdatas_service second; + /* "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1" */ + struct IGDdatas_service IPv6FC; + /* tmp */ + struct IGDdatas_service tmp; +}; + +void IGDstartelt(void *, const char *, int); +void IGDendelt(void *, const char *, int); +void IGDdata(void *, const char *, int); +void printIGD(struct IGDdatas *); + +#endif + diff --git a/contrib/miniupnpc/java/JavaBridgeTest.java b/contrib/miniupnpc/java/JavaBridgeTest.java new file mode 100644 index 00000000..a7fa56d8 --- /dev/null +++ b/contrib/miniupnpc/java/JavaBridgeTest.java @@ -0,0 +1,97 @@ +import java.nio.ByteBuffer; +import java.nio.IntBuffer; + +import fr.free.miniupnp.*; + +/** + * + * @author syuu + */ +public class JavaBridgeTest { + public static void main(String[] args) { + int UPNP_DELAY = 2000; + MiniupnpcLibrary miniupnpc = MiniupnpcLibrary.INSTANCE; + UPNPDev devlist = null; + UPNPUrls urls = new UPNPUrls(); + IGDdatas data = new IGDdatas(); + ByteBuffer lanaddr = ByteBuffer.allocate(16); + ByteBuffer intClient = ByteBuffer.allocate(16); + ByteBuffer intPort = ByteBuffer.allocate(6); + ByteBuffer desc = ByteBuffer.allocate(80); + ByteBuffer enabled = ByteBuffer.allocate(4); + ByteBuffer leaseDuration = ByteBuffer.allocate(16); + int ret; + int i; + + if(args.length < 2) { + System.err.println("Usage : java [...] JavaBridgeTest port protocol"); + System.out.println(" port is numeric, protocol is TCP or UDP"); + return; + } + + devlist = miniupnpc.upnpDiscover(UPNP_DELAY, (String) null, (String) null, 0, 0, IntBuffer.allocate(1)); + if (devlist != null) { + System.out.println("List of UPNP devices found on the network :"); + for (UPNPDev device = devlist; device != null; device = device.pNext) { + System.out.println("desc: " + device.descURL.getString(0) + " st: " + device.st.getString(0)); + } + if ((i = miniupnpc.UPNP_GetValidIGD(devlist, urls, data, lanaddr, 16)) != 0) { + switch (i) { + case 1: + System.out.println("Found valid IGD : " + urls.controlURL.getString(0)); + break; + case 2: + System.out.println("Found a (not connected?) IGD : " + urls.controlURL.getString(0)); + System.out.println("Trying to continue anyway"); + break; + case 3: + System.out.println("UPnP device found. Is it an IGD ? : " + urls.controlURL.getString(0)); + System.out.println("Trying to continue anyway"); + break; + default: + System.out.println("Found device (igd ?) : " + urls.controlURL.getString(0)); + System.out.println("Trying to continue anyway"); + + } + System.out.println("Local LAN ip address : " + new String(lanaddr.array())); + ByteBuffer externalAddress = ByteBuffer.allocate(16); + miniupnpc.UPNP_GetExternalIPAddress(urls.controlURL.getString(0), + new String(data.first.servicetype), externalAddress); + System.out.println("ExternalIPAddress = " + new String(externalAddress.array())); + ret = miniupnpc.UPNP_AddPortMapping( + urls.controlURL.getString(0), // controlURL + new String(data.first.servicetype), // servicetype + args[0], // external Port + args[0], // internal Port + new String(lanaddr.array()), // internal client + "added via miniupnpc/JAVA !", // description + args[1], // protocol UDP or TCP + null, // remote host (useless) + "0"); // leaseDuration + if (ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS) + System.out.println("AddPortMapping() failed with code " + ret); + ret = miniupnpc.UPNP_GetSpecificPortMappingEntry( + urls.controlURL.getString(0), new String(data.first.servicetype), + args[0], args[1], null, intClient, intPort, + desc, enabled, leaseDuration); + if (ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS) + System.out.println("GetSpecificPortMappingEntry() failed with code " + ret); + System.out.println("InternalIP:Port = " + + new String(intClient.array()) + ":" + new String(intPort.array()) + + " (" + new String(desc.array()) + ")"); + ret = miniupnpc.UPNP_DeletePortMapping( + urls.controlURL.getString(0), + new String(data.first.servicetype), + args[0], args[1], null); + if (ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS) + System.out.println("DelPortMapping() failed with code " + ret); + miniupnpc.FreeUPNPUrls(urls); + } else { + System.out.println("No valid UPNP Internet Gateway Device found."); + } + miniupnpc.freeUPNPDevlist(devlist); + } else { + System.out.println("No IGD UPnP Device found on the network !\n"); + } + } +} diff --git a/contrib/miniupnpc/java/testjava.bat b/contrib/miniupnpc/java/testjava.bat new file mode 100644 index 00000000..b836da14 --- /dev/null +++ b/contrib/miniupnpc/java/testjava.bat @@ -0,0 +1,8 @@ +@echo off +set JAVA=java +set JAVAC=javac +REM notice the semicolon for Windows. Write once, run ... oh nevermind +set CP=miniupnpc_win32.jar;. + +%JAVAC% -cp "%CP%" JavaBridgeTest.java || exit 1 +%JAVA% -cp "%CP%" JavaBridgeTest 12345 UDP || exit 1 diff --git a/contrib/miniupnpc/java/testjava.sh b/contrib/miniupnpc/java/testjava.sh new file mode 100644 index 00000000..9880523a --- /dev/null +++ b/contrib/miniupnpc/java/testjava.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +JAVA=java +JAVAC=javac +CP=$(for i in *.jar; do echo -n $i:; done). + +$JAVAC -cp $CP JavaBridgeTest.java || exit 1 +$JAVA -cp $CP JavaBridgeTest 12345 UDP || exit 1 diff --git a/contrib/miniupnpc/man3/miniupnpc.3 b/contrib/miniupnpc/man3/miniupnpc.3 new file mode 100644 index 00000000..1b166474 --- /dev/null +++ b/contrib/miniupnpc/man3/miniupnpc.3 @@ -0,0 +1,52 @@ +.TH MINIUPNPC 3 +.SH NAME +miniupnpc \- UPnP client library +.SH SYNOPSIS +.SH DESCRIPTION +The miniupnpc library implement the UPnP protocol defined +to dialog with Internet Gateway Devices. It also has +the ability to use data gathered by minissdpd(1) about +UPnP devices up on the network in order to skip the +long UPnP device discovery process. +.PP +At first, upnpDiscover(3) has to be used to discover UPnP IGD present +on the network. Then UPNP_GetValidIGD(3) to select the right one. +Alternatively, UPNP_GetIGDFromUrl(3) could be used to bypass discovery +process if the root description url of the device to use is known. +Then all the UPNP_* functions can be used, such as +UPNP_GetConnectionTypeInfo(3), UPNP_AddPortMapping(3), etc... +.SH "HEADER FILES" +.IP miniupnpc.h +That's the main header file for the miniupnpc library API. +It contains all the functions and structures related to device discovery. +.IP upnpcommands.h +This header file contain the UPnP IGD methods that are accessible +through the miniupnpc API. The name of the C functions are matching +the UPnP methods names. ie: GetGenericPortMappingEntry is +UPNP_GetGenericPortMappingEntry. +.SH "API FUNCTIONS" +.IP "struct UPNPDev * upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int sameport, int ipv6, int * error);" +execute the discovery process. +delay (in millisecond) is the maximum time for waiting any device response. +If available, device list will be obtained from MiniSSDPd. +Default path for minissdpd socket will be used if minissdpdsock argument is NULL. +If multicastif is not NULL, it will be used instead of the default multicast interface for sending SSDP discover packets. +If sameport is not null, SSDP packets will be sent from the source port 1900 (same as destination port) otherwise system assign a source port. +If ipv6 is not 0, IPv6 is used instead of IPv4 for the discovery process. +.IP "void freeUPNPDevlist(struct UPNPDev * devlist);" +free the list returned by upnpDiscover(). +.IP "int UPNP_GetValidIGD(struct UPNPDev * devlist, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen);" +browse the list of device returned by upnpDiscover(), find +a live UPnP internet gateway device and fill structures passed as arguments +with data used for UPNP methods invokation. +.IP "int UPNP_GetIGDFromUrl(const char * rootdescurl, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen);" +permit to bypass the upnpDiscover() call if the xml root description +URL of the UPnP IGD is known. +Fill structures passed as arguments +with data used for UPNP methods invokation. +.IP "void GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, const char *);" +.IP "void FreeUPNPUrls(struct UPNPUrls *);" + +.SH "SEE ALSO" +minissdpd(1) +.SH BUGS diff --git a/contrib/miniupnpc/mingw32make.bat b/contrib/miniupnpc/mingw32make.bat new file mode 100644 index 00000000..c5d3cc4f --- /dev/null +++ b/contrib/miniupnpc/mingw32make.bat @@ -0,0 +1,8 @@ +@mingw32-make -f Makefile.mingw %1 +@if errorlevel 1 goto end +@if not exist upnpc-static.exe goto end +@strip upnpc-static.exe +@upx --best upnpc-static.exe +@strip upnpc-shared.exe +@upx --best upnpc-shared.exe +:end diff --git a/contrib/miniupnpc/minihttptestserver.c b/contrib/miniupnpc/minihttptestserver.c new file mode 100644 index 00000000..b7193611 --- /dev/null +++ b/contrib/miniupnpc/minihttptestserver.c @@ -0,0 +1,486 @@ +/* $Id: minihttptestserver.c,v 1.13 2012/05/29 13:03:07 nanard Exp $ */ +/* Project : miniUPnP + * Author : Thomas Bernard + * Copyright (c) 2011-2012 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CRAP_LENGTH (2048) + +volatile sig_atomic_t quit = 0; +volatile sig_atomic_t child_to_wait_for = 0; + +/** + * signal handler for SIGCHLD (child status has changed) + */ +void handle_signal_chld(int sig) +{ + printf("handle_signal_chld(%d)\n", sig); + ++child_to_wait_for; +} + +/** + * signal handler for SIGINT (CRTL C) + */ +#if 0 +void handle_signal_int(int sig) +{ + printf("handle_signal_int(%d)\n", sig); + quit = 1; +} +#endif + +/** + * build a text/plain content of the specified length + */ +void build_content(char * p, int n) +{ + char line_buffer[80]; + int k; + int i = 0; + + while(n > 0) { + k = snprintf(line_buffer, sizeof(line_buffer), + "%04d_ABCDEFGHIJKL_This_line_is_64_bytes_long_ABCDEFGHIJKL_%04d\r\n", + i, i); + if(k != 64) { + fprintf(stderr, "snprintf() returned %d in build_content()\n", k); + } + ++i; + if(n >= 64) { + memcpy(p, line_buffer, 64); + p += 64; + n -= 64; + } else { + memcpy(p, line_buffer, n); + p += n; + n = 0; + } + } +} + +/** + * build crappy content + */ +void build_crap(char * p, int n) +{ + static const char crap[] = "_CRAP_\r\n"; + int i; + + while(n > 0) { + i = sizeof(crap) - 1; + if(i > n) + i = n; + memcpy(p, crap, i); + p += i; + n -= i; + } +} + +/** + * build chunked response. + * return a malloc'ed buffer + */ +char * build_chunked_response(int content_length, int * response_len) { + char * response_buffer; + char * content_buffer; + int buffer_length; + int i, n; + + /* allocate to have some margin */ + buffer_length = 256 + content_length + (content_length >> 4); + response_buffer = malloc(buffer_length); + *response_len = snprintf(response_buffer, buffer_length, + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n"); + + /* build the content */ + content_buffer = malloc(content_length); + build_content(content_buffer, content_length); + + /* chunk it */ + i = 0; + while(i < content_length) { + n = (rand() % 199) + 1; + if(i + n > content_length) { + n = content_length - i; + } + /* TODO : check buffer size ! */ + *response_len += snprintf(response_buffer + *response_len, + buffer_length - *response_len, + "%x\r\n", n); + memcpy(response_buffer + *response_len, content_buffer + i, n); + *response_len += n; + i += n; + response_buffer[(*response_len)++] = '\r'; + response_buffer[(*response_len)++] = '\n'; + } + /* the last chunk : "0\r\n" a empty body and then + * the final "\r\n" */ + memcpy(response_buffer + *response_len, "0\r\n\r\n", 5); + *response_len += 5; + free(content_buffer); + + printf("resp_length=%d buffer_length=%d content_length=%d\n", + *response_len, buffer_length, content_length); + return response_buffer; +} + +enum modes { MODE_INVALID, MODE_CHUNKED, MODE_ADDCRAP, MODE_NORMAL }; +const struct { + const enum modes mode; + const char * text; +} modes_array[] = { + {MODE_CHUNKED, "chunked"}, + {MODE_ADDCRAP, "addcrap"}, + {MODE_NORMAL, "normal"}, + {MODE_INVALID, NULL} +}; + +/** + * write the response with random behaviour ! + */ +void send_response(int c, const char * buffer, int len) +{ + int n; + while(len > 0) { + n = (rand() % 99) + 1; + if(n > len) + n = len; + n = write(c, buffer, n); + if(n < 0) { + if(errno != EINTR) { + perror("write"); + return; + } + /* if errno == EINTR, try again */ + } else { + len -= n; + buffer += n; + } + usleep(10000); /* 10ms */ + } +} + +/** + * handle the HTTP connection + */ +void handle_http_connection(int c) +{ + char request_buffer[2048]; + int request_len = 0; + int headers_found = 0; + int n, i; + char request_method[16]; + char request_uri[256]; + char http_version[16]; + char * p; + char * response_buffer; + int response_len; + enum modes mode; + int content_length = 16*1024; + + /* read the request */ + while(request_len < (int)sizeof(request_buffer) && !headers_found) { + n = read(c, + request_buffer + request_len, + sizeof(request_buffer) - request_len); + if(n < 0) { + perror("read"); + return; + } else if(n==0) { + /* remote host closed the connection */ + break; + } else { + request_len += n; + for(i = 0; i < request_len - 3; i++) { + if(0 == memcmp(request_buffer + i, "\r\n\r\n", 4)) { + /* found the end of headers */ + headers_found = 1; + break; + } + } + } + } + if(!headers_found) { + /* error */ + return; + } + printf("headers :\n%.*s", request_len, request_buffer); + /* the request have been received, now parse the request line */ + p = request_buffer; + for(i = 0; i < (int)sizeof(request_method) - 1; i++) { + if(*p == ' ' || *p == '\r') + break; + request_method[i] = *p; + ++p; + } + request_method[i] = '\0'; + while(*p == ' ') + p++; + for(i = 0; i < (int)sizeof(request_uri) - 1; i++) { + if(*p == ' ' || *p == '\r') + break; + request_uri[i] = *p; + ++p; + } + request_uri[i] = '\0'; + while(*p == ' ') + p++; + for(i = 0; i < (int)sizeof(http_version) - 1; i++) { + if(*p == ' ' || *p == '\r') + break; + http_version[i] = *p; + ++p; + } + http_version[i] = '\0'; + printf("Method = %s, URI = %s, %s\n", + request_method, request_uri, http_version); + /* check if the request method is allowed */ + if(0 != strcmp(request_method, "GET")) { + const char response405[] = "HTTP/1.1 405 Method Not Allowed\r\n" + "Allow: GET\r\n\r\n"; + const char * pc; + /* 405 Method Not Allowed */ + /* The response MUST include an Allow header containing a list + * of valid methods for the requested resource. */ + n = sizeof(response405) - 1; + pc = response405; + while(n > 0) { + i = write(c, pc, n); + if(i<0) { + if(errno != EINTR) { + perror("write"); + return; + } + } else { + n -= i; + pc += i; + } + } + return; + } + + mode = MODE_INVALID; + /* use the request URI to know what to do */ + for(i = 0; modes_array[i].mode != MODE_INVALID; i++) { + if(strstr(request_uri, modes_array[i].text)) { + mode = modes_array[i].mode; /* found */ + break; + } + } + + switch(mode) { + case MODE_CHUNKED: + response_buffer = build_chunked_response(content_length, &response_len); + break; + case MODE_ADDCRAP: + response_len = content_length+256; + response_buffer = malloc(response_len); + n = snprintf(response_buffer, response_len, + "HTTP/1.1 200 OK\r\n" + "Server: minihttptestserver\r\n" + "Content-Type: text/plain\r\n" + "Content-Length: %d\r\n" + "\r\n", content_length); + response_len = content_length+n+CRAP_LENGTH; + response_buffer = realloc(response_buffer, response_len); + build_content(response_buffer + n, content_length); + build_crap(response_buffer + n + content_length, CRAP_LENGTH); + break; + default: + response_len = content_length+256; + response_buffer = malloc(response_len); + n = snprintf(response_buffer, response_len, + "HTTP/1.1 200 OK\r\n" + "Server: minihttptestserver\r\n" + "Content-Type: text/plain\r\n" + "\r\n"); + response_len = content_length+n; + response_buffer = realloc(response_buffer, response_len); + build_content(response_buffer + n, response_len - n); + } + + if(response_buffer) { + send_response(c, response_buffer, response_len); + free(response_buffer); + } else { + /* Error 500 */ + } +} + +/** + */ +int main(int argc, char * * argv) { + int ipv6 = 0; + int s, c, i; + unsigned short port = 0; + struct sockaddr_storage server_addr; + socklen_t server_addrlen; + struct sockaddr_storage client_addr; + socklen_t client_addrlen; + pid_t pid; + int child = 0; + int status; + const char * expected_file_name = NULL; + + for(i = 1; i < argc; i++) { + if(argv[i][0] == '-') { + switch(argv[i][1]) { + case '6': + ipv6 = 1; + break; + case 'e': + /* write expected file ! */ + expected_file_name = argv[++i]; + break; + case 'p': + /* port */ + if(++i < argc) { + port = (unsigned short)atoi(argv[i]); + } + break; + default: + fprintf(stderr, "unknown command line switch '%s'\n", argv[i]); + } + } else { + fprintf(stderr, "unkown command line argument '%s'\n", argv[i]); + } + } + + srand(time(NULL)); + signal(SIGCHLD, handle_signal_chld); +#if 0 + signal(SIGINT, handle_signal_int); +#endif + + s = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0); + if(s < 0) { + perror("socket"); + return 1; + } + memset(&server_addr, 0, sizeof(struct sockaddr_storage)); + memset(&client_addr, 0, sizeof(struct sockaddr_storage)); + if(ipv6) { + struct sockaddr_in6 * addr = (struct sockaddr_in6 *)&server_addr; + addr->sin6_family = AF_INET6; + addr->sin6_port = htons(port); + addr->sin6_addr = in6addr_loopback; + } else { + struct sockaddr_in * addr = (struct sockaddr_in *)&server_addr; + addr->sin_family = AF_INET; + addr->sin_port = htons(port); + addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK); + } + if(bind(s, (struct sockaddr *)&server_addr, + ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) < 0) { + perror("bind"); + return 1; + } + if(listen(s, 5) < 0) { + perror("listen"); + } + if(port == 0) { + server_addrlen = sizeof(struct sockaddr_storage); + if(getsockname(s, (struct sockaddr *)&server_addr, &server_addrlen) < 0) { + perror("getsockname"); + return 1; + } + if(ipv6) { + struct sockaddr_in6 * addr = (struct sockaddr_in6 *)&server_addr; + port = ntohs(addr->sin6_port); + } else { + struct sockaddr_in * addr = (struct sockaddr_in *)&server_addr; + port = ntohs(addr->sin_port); + } + printf("Listening on port %hu\n", port); + fflush(stdout); + } + + /* write expected file */ + if(expected_file_name) { + FILE * f; + f = fopen(expected_file_name, "wb"); + if(f) { + char * buffer; + buffer = malloc(16*1024); + build_content(buffer, 16*1024); + i = fwrite(buffer, 1, 16*1024, f); + if(i != 16*1024) { + fprintf(stderr, "error writing to file %s : %dbytes written (out of %d)\n", expected_file_name, i, 16*1024); + } + free(buffer); + fclose(f); + } else { + fprintf(stderr, "error opening file %s for writing\n", expected_file_name); + } + } + + /* fork() loop */ + while(!child && !quit) { + while(child_to_wait_for > 0) { + pid = wait(&status); + if(pid < 0) { + perror("wait"); + } else { + printf("child(%d) terminated with status %d\n", pid, status); + } + --child_to_wait_for; + } + /* TODO : add a select() call in order to handle the case + * when a signal is caught */ + client_addrlen = sizeof(struct sockaddr_storage); + c = accept(s, (struct sockaddr *)&client_addr, + &client_addrlen); + if(c < 0) { + perror("accept"); + return 1; + } + printf("accept...\n"); + pid = fork(); + if(pid < 0) { + perror("fork"); + return 1; + } else if(pid == 0) { + /* child */ + child = 1; + close(s); + s = -1; + handle_http_connection(c); + } + close(c); + } + if(s >= 0) { + close(s); + s = -1; + } + if(!child) { + while(child_to_wait_for > 0) { + pid = wait(&status); + if(pid < 0) { + perror("wait"); + } else { + printf("child(%d) terminated with status %d\n", pid, status); + } + --child_to_wait_for; + } + printf("Bye...\n"); + } + return 0; +} + diff --git a/contrib/miniupnpc/minisoap.c b/contrib/miniupnpc/minisoap.c new file mode 100644 index 00000000..e45a481a --- /dev/null +++ b/contrib/miniupnpc/minisoap.c @@ -0,0 +1,121 @@ +/* $Id: minisoap.c,v 1.22 2012/01/21 13:30:31 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2005-2012 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * + * Minimal SOAP implementation for UPnP protocol. + */ +#include +#include +#ifdef _WIN32 +#include +#include +#define snprintf _snprintf +#else +#include +#include +#include +#endif +#include "minisoap.h" +#include "miniupnpcstrings.h" + +/* only for malloc */ +#include + +#ifdef _WIN32 +#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); +#else +#define PRINT_SOCKET_ERROR(x) perror(x) +#endif + +/* httpWrite sends the headers and the body to the socket + * and returns the number of bytes sent */ +static int +httpWrite(int fd, const char * body, int bodysize, + const char * headers, int headerssize) +{ + int n = 0; + /*n = write(fd, headers, headerssize);*/ + /*if(bodysize>0) + n += write(fd, body, bodysize);*/ + /* Note : my old linksys router only took into account + * soap request that are sent into only one packet */ + char * p; + /* TODO: AVOID MALLOC */ + p = malloc(headerssize+bodysize); + if(!p) + return 0; + memcpy(p, headers, headerssize); + memcpy(p+headerssize, body, bodysize); + /*n = write(fd, p, headerssize+bodysize);*/ + n = send(fd, p, headerssize+bodysize, 0); + if(n<0) { + PRINT_SOCKET_ERROR("send"); + } + /* disable send on the socket */ + /* draytek routers dont seems to like that... */ +#if 0 +#ifdef _WIN32 + if(shutdown(fd, SD_SEND)<0) { +#else + if(shutdown(fd, SHUT_WR)<0) { /*SD_SEND*/ +#endif + PRINT_SOCKET_ERROR("shutdown"); + } +#endif + free(p); + return n; +} + +/* self explanatory */ +int soapPostSubmit(int fd, + const char * url, + const char * host, + unsigned short port, + const char * action, + const char * body, + const char * httpversion) +{ + int bodysize; + char headerbuf[512]; + int headerssize; + char portstr[8]; + bodysize = (int)strlen(body); + /* We are not using keep-alive HTTP connections. + * HTTP/1.1 needs the header Connection: close to do that. + * This is the default with HTTP/1.0 + * Using HTTP/1.1 means we need to support chunked transfer-encoding : + * When using HTTP/1.1, the router "BiPAC 7404VNOX" always use chunked + * transfer encoding. */ + /* Connection: Close is normally there only in HTTP/1.1 but who knows */ + portstr[0] = '\0'; + if(port != 80) + snprintf(portstr, sizeof(portstr), ":%hu", port); + headerssize = snprintf(headerbuf, sizeof(headerbuf), + "POST %s HTTP/%s\r\n" + "Host: %s%s\r\n" + "User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" + "Content-Length: %d\r\n" + "Content-Type: text/xml\r\n" + "SOAPAction: \"%s\"\r\n" + "Connection: Close\r\n" + "Cache-Control: no-cache\r\n" /* ??? */ + "Pragma: no-cache\r\n" + "\r\n", + url, httpversion, host, portstr, bodysize, action); +#ifdef DEBUG + /*printf("SOAP request : headersize=%d bodysize=%d\n", + headerssize, bodysize); + */ + printf("SOAP request : POST %s HTTP/%s - Host: %s%s\n", + url, httpversion, host, portstr); + printf("SOAPAction: \"%s\" - Content-Length: %d\n", action, bodysize); + printf("Headers :\n%s", headerbuf); + printf("Body :\n%s\n", body); +#endif + return httpWrite(fd, body, bodysize, headerbuf, headerssize); +} + + diff --git a/contrib/miniupnpc/minisoap.h b/contrib/miniupnpc/minisoap.h new file mode 100644 index 00000000..14c859d1 --- /dev/null +++ b/contrib/miniupnpc/minisoap.h @@ -0,0 +1,15 @@ +/* $Id: minisoap.h,v 1.5 2012/09/27 15:42:10 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2005 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. */ +#ifndef MINISOAP_H_INCLUDED +#define MINISOAP_H_INCLUDED + +/*int httpWrite(int, const char *, int, const char *);*/ +int soapPostSubmit(int, const char *, const char *, unsigned short, + const char *, const char *, const char *); + +#endif + diff --git a/contrib/miniupnpc/minissdpc.c b/contrib/miniupnpc/minissdpc.c new file mode 100644 index 00000000..c4913fb8 --- /dev/null +++ b/contrib/miniupnpc/minissdpc.c @@ -0,0 +1,133 @@ +/* $Id: minissdpc.c,v 1.16 2012/03/05 19:42:46 nanard Exp $ */ +/* Project : miniupnp + * Web : http://miniupnp.free.fr/ + * Author : Thomas BERNARD + * copyright (c) 2005-2012 Thomas Bernard + * This software is subjet to the conditions detailed in the + * provided LICENCE file. */ +/*#include */ +#include +#include +#include +#include +#include +#if defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) +#ifdef _WIN32 +#include +#include +#include +#include +#include +#endif +#if defined(__amigaos__) || defined(__amigaos4__) +#include +#endif +#if defined(__amigaos__) +#define uint16_t unsigned short +#endif +/* Hack */ +#define UNIX_PATH_LEN 108 +struct sockaddr_un { + uint16_t sun_family; + char sun_path[UNIX_PATH_LEN]; +}; +#else +#include +#include +#endif + +#include "minissdpc.h" +#include "miniupnpc.h" + +#include "codelength.h" + +struct UPNPDev * +getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath) +{ + struct UPNPDev * tmp; + struct UPNPDev * devlist = NULL; + unsigned char buffer[2048]; + ssize_t n; + unsigned char * p; + unsigned char * url; + unsigned int i; + unsigned int urlsize, stsize, usnsize, l; + int s; + struct sockaddr_un addr; + + s = socket(AF_UNIX, SOCK_STREAM, 0); + if(s < 0) + { + /*syslog(LOG_ERR, "socket(unix): %m");*/ + perror("socket(unix)"); + return NULL; + } + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, socketpath, sizeof(addr.sun_path)); + /* TODO : check if we need to handle the EINTR */ + if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) + { + /*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/ + close(s); + return NULL; + } + stsize = strlen(devtype); + buffer[0] = 1; /* request type 1 : request devices/services by type */ + p = buffer + 1; + l = stsize; CODELENGTH(l, p); + if(p + stsize > buffer + sizeof(buffer)) + { + /* devtype is too long ! */ + close(s); + return NULL; + } + memcpy(p, devtype, stsize); + p += stsize; + if(write(s, buffer, p - buffer) < 0) + { + /*syslog(LOG_ERR, "write(): %m");*/ + perror("minissdpc.c: write()"); + close(s); + return NULL; + } + n = read(s, buffer, sizeof(buffer)); + if(n<=0) + { + perror("minissdpc.c: read()"); + close(s); + return NULL; + } + p = buffer + 1; + for(i = 0; i < buffer[0]; i++) + { + if(p+2>=buffer+sizeof(buffer)) + break; + DECODELENGTH(urlsize, p); + if(p+urlsize+2>=buffer+sizeof(buffer)) + break; + url = p; + p += urlsize; + DECODELENGTH(stsize, p); + if(p+stsize+2>=buffer+sizeof(buffer)) + break; + tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize); + tmp->pNext = devlist; + tmp->descURL = tmp->buffer; + tmp->st = tmp->buffer + 1 + urlsize; + memcpy(tmp->buffer, url, urlsize); + tmp->buffer[urlsize] = '\0'; + memcpy(tmp->buffer + urlsize + 1, p, stsize); + p += stsize; + tmp->buffer[urlsize+1+stsize] = '\0'; + devlist = tmp; + /* added for compatibility with recent versions of MiniSSDPd + * >= 2007/12/19 */ + DECODELENGTH(usnsize, p); + p += usnsize; + if(p>buffer + sizeof(buffer)) + break; + } + close(s); + return devlist; +} + diff --git a/contrib/miniupnpc/minissdpc.h b/contrib/miniupnpc/minissdpc.h new file mode 100644 index 00000000..915b0026 --- /dev/null +++ b/contrib/miniupnpc/minissdpc.h @@ -0,0 +1,15 @@ +/* $Id: minissdpc.h,v 1.2 2012/09/27 15:42:10 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * Author: Thomas Bernard + * Copyright (c) 2005-2007 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef MINISSDPC_H_INCLUDED +#define MINISSDPC_H_INCLUDED + +struct UPNPDev * +getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath); + +#endif + diff --git a/contrib/miniupnpc/miniupnpc.c b/contrib/miniupnpc/miniupnpc.c new file mode 100644 index 00000000..f661c2e6 --- /dev/null +++ b/contrib/miniupnpc/miniupnpc.c @@ -0,0 +1,1046 @@ +/* $Id: miniupnpc.c,v 1.117 2014/01/31 14:19:13 nanard Exp $ */ +/* Project : miniupnp + * Web : http://miniupnp.free.fr/ + * Author : Thomas BERNARD + * copyright (c) 2005-2014 Thomas Bernard + * This software is subjet to the conditions detailed in the + * provided LICENSE file. */ +#define __EXTENSIONS__ 1 +#if !defined(MACOSX) && !defined(__sun) +#if !defined(_XOPEN_SOURCE) && !defined(__OpenBSD__) && !defined(__NetBSD__) +#ifndef __cplusplus +#define _XOPEN_SOURCE 600 +#endif +#endif +#ifndef __BSD_VISIBLE +#define __BSD_VISIBLE 1 +#endif +#endif + +#if !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(MACOSX) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__sun) +#define HAS_IP_MREQN +#endif + +#include +#include +#include +#ifdef _WIN32 +/* Win32 Specific includes and defines */ +#include +#include +#include +#include +#define snprintf _snprintf +#define strdup _strdup +#ifndef strncasecmp +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#define strncasecmp _memicmp +#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ +#define strncasecmp memicmp +#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ +#endif /* #ifndef strncasecmp */ +#define MAXHOSTNAMELEN 64 +#else /* #ifdef _WIN32 */ +/* Standard POSIX includes */ +#include +#if defined(__amigaos__) && !defined(__amigaos4__) +/* Amiga OS 3 specific stuff */ +#define socklen_t int +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#if !defined(__amigaos__) && !defined(__amigaos4__) +#include +#endif +#include +#include +#define closesocket close +#endif /* #else _WIN32 */ +#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT +#include +#endif +#if defined(__amigaos__) || defined(__amigaos4__) +/* Amiga OS specific stuff */ +#define TIMEVAL struct timeval +#endif + + +#if defined(HAS_IP_MREQN) && defined(NEED_STRUCT_IP_MREQN) +/* Several versions of glibc don't define this structure, define it here and compile with CFLAGS NEED_STRUCT_IP_MREQN */ +struct ip_mreqn +{ + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_address; /* local IP address of interface */ + int imr_ifindex; /* Interface index */ +}; +#endif + +#include "miniupnpc.h" +#include "minissdpc.h" +#include "miniwget.h" +#include "minisoap.h" +#include "minixml.h" +#include "upnpcommands.h" +#include "connecthostport.h" +#include "receivedata.h" + +#ifdef _WIN32 +#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); +#else +#define PRINT_SOCKET_ERROR(x) perror(x) +#endif + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif + +#define SOAPPREFIX "s" +#define SERVICEPREFIX "u" +#define SERVICEPREFIX2 'u' + +/* root description parsing */ +LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data) +{ + struct xmlparser parser; + /* xmlparser object */ + parser.xmlstart = buffer; + parser.xmlsize = bufsize; + parser.data = data; + parser.starteltfunc = IGDstartelt; + parser.endeltfunc = IGDendelt; + parser.datafunc = IGDdata; + parser.attfunc = 0; + parsexml(&parser); +#ifdef DEBUG + printIGD(data); +#endif +} + +/* simpleUPnPcommand2 : + * not so simple ! + * return values : + * pointer - OK + * NULL - error */ +char * simpleUPnPcommand2(int s, const char * url, const char * service, + const char * action, struct UPNParg * args, + int * bufsize, const char * httpversion) +{ + char hostname[MAXHOSTNAMELEN+1]; + unsigned short port = 0; + char * path; + char soapact[128]; + char soapbody[2048]; + char * buf; + int n; + + *bufsize = 0; + snprintf(soapact, sizeof(soapact), "%s#%s", service, action); + if(args==NULL) + { + /*soapbodylen = */snprintf(soapbody, sizeof(soapbody), + "\r\n" + "<" SOAPPREFIX ":Envelope " + "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " + SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "<" SOAPPREFIX ":Body>" + "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">" + "" + "" + "\r\n", action, service, action); + } + else + { + char * p; + const char * pe, * pv; + int soapbodylen; + soapbodylen = snprintf(soapbody, sizeof(soapbody), + "\r\n" + "<" SOAPPREFIX ":Envelope " + "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " + SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "<" SOAPPREFIX ":Body>" + "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">", + action, service); + p = soapbody + soapbodylen; + while(args->elt) + { + /* check that we are never overflowing the string... */ + if(soapbody + sizeof(soapbody) <= p + 100) + { + /* we keep a margin of at least 100 bytes */ + return NULL; + } + *(p++) = '<'; + pe = args->elt; + while(*pe) + *(p++) = *(pe++); + *(p++) = '>'; + if((pv = args->val)) + { + while(*pv) + *(p++) = *(pv++); + } + *(p++) = '<'; + *(p++) = '/'; + pe = args->elt; + while(*pe) + *(p++) = *(pe++); + *(p++) = '>'; + args++; + } + *(p++) = '<'; + *(p++) = '/'; + *(p++) = SERVICEPREFIX2; + *(p++) = ':'; + pe = action; + while(*pe) + *(p++) = *(pe++); + strncpy(p, ">\r\n", + soapbody + sizeof(soapbody) - p); + } + if(!parseURL(url, hostname, &port, &path, NULL)) return NULL; + if(s < 0) { + s = connecthostport(hostname, port, 0); + if(s < 0) { + /* failed to connect */ + return NULL; + } + } + + n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, httpversion); + if(n<=0) { +#ifdef DEBUG + printf("Error sending SOAP request\n"); +#endif + closesocket(s); + return NULL; + } + + buf = getHTTPResponse(s, bufsize); +#ifdef DEBUG + if(*bufsize > 0 && buf) + { + printf("SOAP Response :\n%.*s\n", *bufsize, buf); + } +#endif + closesocket(s); + return buf; +} + +/* simpleUPnPcommand : + * not so simple ! + * return values : + * pointer - OK + * NULL - error */ +char * simpleUPnPcommand(int s, const char * url, const char * service, + const char * action, struct UPNParg * args, + int * bufsize) +{ + char * buf; + +#if 1 + buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1"); +#else + buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.0"); + if (!buf || *bufsize == 0) + { +#if DEBUG + printf("Error or no result from SOAP request; retrying with HTTP/1.1\n"); +#endif + buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1"); + } +#endif + return buf; +} + +/* parseMSEARCHReply() + * the last 4 arguments are filled during the parsing : + * - location/locationsize : "location:" field of the SSDP reply packet + * - st/stsize : "st:" field of the SSDP reply packet. + * The strings are NOT null terminated */ +static void +parseMSEARCHReply(const char * reply, int size, + const char * * location, int * locationsize, + const char * * st, int * stsize) +{ + int a, b, i; + i = 0; + a = i; /* start of the line */ + b = 0; /* end of the "header" (position of the colon) */ + while(isin6_family = AF_INET6; + if(sameport) + p->sin6_port = htons(PORT); + p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */ + } else { + struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r; + p->sin_family = AF_INET; + if(sameport) + p->sin_port = htons(PORT); + p->sin_addr.s_addr = INADDR_ANY; + } +#ifdef _WIN32 +/* This code could help us to use the right Network interface for + * SSDP multicast traffic */ +/* Get IP associated with the index given in the ip_forward struct + * in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */ + if(!ipv6 + && (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) { + DWORD dwRetVal = 0; + PMIB_IPADDRTABLE pIPAddrTable; + DWORD dwSize = 0; +#ifdef DEBUG + IN_ADDR IPAddr; +#endif + int i; +#ifdef DEBUG + printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop); +#endif + pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE)); + if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) { + free(pIPAddrTable); + pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize); + } + if(pIPAddrTable) { + dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 ); +#ifdef DEBUG + printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries); +#endif + for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) { +#ifdef DEBUG + printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex); + IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr; + printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); + IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask; + printf("\tSubnet Mask[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); + IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr; + printf("\tBroadCast[%d]: \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr); + printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize); + printf("\tType and State[%d]:", i); + printf("\n"); +#endif + if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) { + /* Set the address of this interface to be used */ + struct in_addr mc_if; + memset(&mc_if, 0, sizeof(mc_if)); + mc_if.s_addr = pIPAddrTable->table[i].dwAddr; + if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) { + PRINT_SOCKET_ERROR("setsockopt"); + } + ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr; +#ifndef DEBUG + break; +#endif + } + } + free(pIPAddrTable); + pIPAddrTable = NULL; + } + } +#endif + +#ifdef _WIN32 + if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0) +#else + if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0) +#endif + { + if(error) + *error = UPNPDISCOVER_SOCKET_ERROR; + PRINT_SOCKET_ERROR("setsockopt"); + return NULL; + } + + if(multicastif) + { + if(ipv6) { +#if !defined(_WIN32) + /* according to MSDN, if_nametoindex() is supported since + * MS Windows Vista and MS Windows Server 2008. + * http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */ + unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */ + if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(&ifindex)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt"); + } +#else +#ifdef DEBUG + printf("Setting of multicast interface not supported in IPv6 under Windows.\n"); +#endif +#endif + } else { + struct in_addr mc_if; + mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */ + if(mc_if.s_addr != INADDR_NONE) + { + ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr; + if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt"); + } + } else { +#ifdef HAS_IP_MREQN + /* was not an ip address, try with an interface name */ + struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */ + memset(&reqn, 0, sizeof(struct ip_mreqn)); + reqn.imr_ifindex = if_nametoindex(multicastif); + if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt"); + } +#else +#ifdef DEBUG + printf("Setting of multicast interface not supported with interface name.\n"); +#endif +#endif + } + } + } + + /* Before sending the packed, we first "bind" in order to be able + * to receive the response */ + if (bind(sudp, (const struct sockaddr *)&sockudp_r, + ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0) + { + if(error) + *error = UPNPDISCOVER_SOCKET_ERROR; + PRINT_SOCKET_ERROR("bind"); + closesocket(sudp); + return NULL; + } + + if(error) + *error = UPNPDISCOVER_SUCCESS; + /* Calculating maximum response time in seconds */ + mx = ((unsigned int)delay) / 1000u; + if(mx == 0) { + mx = 1; + delay = 1000; + } + /* receiving SSDP response packet */ + for(n = 0; deviceList[deviceIndex]; deviceIndex++) + { + if(n == 0) + { + /* sending the SSDP M-SEARCH packet */ + n = snprintf(bufr, sizeof(bufr), + MSearchMsgFmt, + ipv6 ? + (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]") + : UPNP_MCAST_ADDR, + deviceList[deviceIndex], mx); +#ifdef DEBUG + printf("Sending %s", bufr); +#endif +#ifdef NO_GETADDRINFO + /* the following code is not using getaddrinfo */ + /* emission */ + memset(&sockudp_w, 0, sizeof(struct sockaddr_storage)); + if(ipv6) { + struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w; + p->sin6_family = AF_INET6; + p->sin6_port = htons(PORT); + inet_pton(AF_INET6, + linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR, + &(p->sin6_addr)); + } else { + struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w; + p->sin_family = AF_INET; + p->sin_port = htons(PORT); + p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR); + } + n = sendto(sudp, bufr, n, 0, + &sockudp_w, + ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); + if (n < 0) { + if(error) + *error = UPNPDISCOVER_SOCKET_ERROR; + PRINT_SOCKET_ERROR("sendto"); + break; + } +#else /* #ifdef NO_GETADDRINFO */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; /* AF_INET6 or AF_INET */ + hints.ai_socktype = SOCK_DGRAM; + /*hints.ai_flags = */ + if ((rv = getaddrinfo(ipv6 + ? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR) + : UPNP_MCAST_ADDR, + XSTR(PORT), &hints, &servinfo)) != 0) { + if(error) + *error = UPNPDISCOVER_SOCKET_ERROR; +#ifdef _WIN32 + fprintf(stderr, "getaddrinfo() failed: %d\n", rv); +#else + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); +#endif + break; + } + for(p = servinfo; p; p = p->ai_next) { + n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen); + if (n < 0) { +#ifdef DEBUG + char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; + if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf, + sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) { + fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf); + } +#endif + PRINT_SOCKET_ERROR("sendto"); + continue; + } + } + freeaddrinfo(servinfo); + if(n < 0) { + if(error) + *error = UPNPDISCOVER_SOCKET_ERROR; + break; + } +#endif /* #ifdef NO_GETADDRINFO */ + } + /* Waiting for SSDP REPLY packet to M-SEARCH */ + n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id); + if (n < 0) { + /* error */ + if(error) + *error = UPNPDISCOVER_SOCKET_ERROR; + break; + } else if (n == 0) { + /* no data or Time Out */ + if (devlist) { + /* no more device type to look for... */ + if(error) + *error = UPNPDISCOVER_SUCCESS; + break; + } + if(ipv6) { + if(linklocal) { + linklocal = 0; + --deviceIndex; + } else { + linklocal = 1; + } + } + } else { + const char * descURL=NULL; + int urlsize=0; + const char * st=NULL; + int stsize=0; + /*printf("%d byte(s) :\n%s\n", n, bufr);*/ /* affichage du message */ + parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize); + if(st&&descURL) + { +#ifdef DEBUG + printf("M-SEARCH Reply:\nST: %.*s\nLocation: %.*s\n", + stsize, st, urlsize, descURL); +#endif + for(tmp=devlist; tmp; tmp = tmp->pNext) { + if(memcmp(tmp->descURL, descURL, urlsize) == 0 && + tmp->descURL[urlsize] == '\0' && + memcmp(tmp->st, st, stsize) == 0 && + tmp->st[stsize] == '\0') + break; + } + /* at the exit of the loop above, tmp is null if + * no duplicate device was found */ + if(tmp) + continue; + tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize); + if(!tmp) { + /* memory allocation error */ + if(error) + *error = UPNPDISCOVER_MEMORY_ERROR; + break; + } + tmp->pNext = devlist; + tmp->descURL = tmp->buffer; + tmp->st = tmp->buffer + 1 + urlsize; + memcpy(tmp->buffer, descURL, urlsize); + tmp->buffer[urlsize] = '\0'; + memcpy(tmp->buffer + urlsize + 1, st, stsize); + tmp->buffer[urlsize+1+stsize] = '\0'; + tmp->scope_id = scope_id; + devlist = tmp; + } + } + } + closesocket(sudp); + return devlist; +} + +/* freeUPNPDevlist() should be used to + * free the chained list returned by upnpDiscover() */ +LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist) +{ + struct UPNPDev * next; + while(devlist) + { + next = devlist->pNext; + free(devlist); + devlist = next; + } +} + +static void +url_cpy_or_cat(char * dst, const char * src, int n) +{ + if( (src[0] == 'h') + &&(src[1] == 't') + &&(src[2] == 't') + &&(src[3] == 'p') + &&(src[4] == ':') + &&(src[5] == '/') + &&(src[6] == '/')) + { + strncpy(dst, src, n); + } + else + { + int l = strlen(dst); + if(src[0] != '/') + dst[l++] = '/'; + if(l<=n) + strncpy(dst + l, src, n - l); + } +} + +/* Prepare the Urls for usage... + */ +LIBSPEC void +GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data, + const char * descURL, unsigned int scope_id) +{ + char * p; + int n1, n2, n3, n4; +#ifdef IF_NAMESIZE + char ifname[IF_NAMESIZE]; +#else + char scope_str[8]; +#endif + + n1 = strlen(data->urlbase); + if(n1==0) + n1 = strlen(descURL); + if(scope_id != 0) { +#ifdef IF_NAMESIZE + if(if_indextoname(scope_id, ifname)) { + n1 += 3 + strlen(ifname); /* 3 == strlen(%25) */ + } +#else + /* under windows, scope is numerical */ + snprintf(scope_str, sizeof(scope_str), "%u", scope_id); +#endif + } + n1 += 2; /* 1 byte more for Null terminator, 1 byte for '/' if needed */ + n2 = n1; n3 = n1; n4 = n1; + n1 += strlen(data->first.scpdurl); + n2 += strlen(data->first.controlurl); + n3 += strlen(data->CIF.controlurl); + n4 += strlen(data->IPv6FC.controlurl); + + /* allocate memory to store URLs */ + urls->ipcondescURL = (char *)malloc(n1); + urls->controlURL = (char *)malloc(n2); + urls->controlURL_CIF = (char *)malloc(n3); + urls->controlURL_6FC = (char *)malloc(n4); + + /* strdup descURL */ + urls->rootdescURL = strdup(descURL); + + /* get description of WANIPConnection */ + if(data->urlbase[0] != '\0') + strncpy(urls->ipcondescURL, data->urlbase, n1); + else + strncpy(urls->ipcondescURL, descURL, n1); + p = strchr(urls->ipcondescURL+7, '/'); + if(p) p[0] = '\0'; + if(scope_id != 0) { + if(0 == memcmp(urls->ipcondescURL, "http://[fe80:", 13)) { + /* this is a linklocal IPv6 address */ + p = strchr(urls->ipcondescURL, ']'); + if(p) { + /* insert %25 into URL */ +#ifdef IF_NAMESIZE + memmove(p + 3 + strlen(ifname), p, strlen(p) + 1); + memcpy(p, "%25", 3); + memcpy(p + 3, ifname, strlen(ifname)); +#else + memmove(p + 3 + strlen(scope_str), p, strlen(p) + 1); + memcpy(p, "%25", 3); + memcpy(p + 3, scope_str, strlen(scope_str)); +#endif + } + } + } + strncpy(urls->controlURL, urls->ipcondescURL, n2); + strncpy(urls->controlURL_CIF, urls->ipcondescURL, n3); + strncpy(urls->controlURL_6FC, urls->ipcondescURL, n4); + + url_cpy_or_cat(urls->ipcondescURL, data->first.scpdurl, n1); + + url_cpy_or_cat(urls->controlURL, data->first.controlurl, n2); + + url_cpy_or_cat(urls->controlURL_CIF, data->CIF.controlurl, n3); + + url_cpy_or_cat(urls->controlURL_6FC, data->IPv6FC.controlurl, n4); + +#ifdef DEBUG + printf("urls->ipcondescURL='%s' %u n1=%d\n", urls->ipcondescURL, + (unsigned)strlen(urls->ipcondescURL), n1); + printf("urls->controlURL='%s' %u n2=%d\n", urls->controlURL, + (unsigned)strlen(urls->controlURL), n2); + printf("urls->controlURL_CIF='%s' %u n3=%d\n", urls->controlURL_CIF, + (unsigned)strlen(urls->controlURL_CIF), n3); + printf("urls->controlURL_6FC='%s' %u n4=%d\n", urls->controlURL_6FC, + (unsigned)strlen(urls->controlURL_6FC), n4); +#endif +} + +LIBSPEC void +FreeUPNPUrls(struct UPNPUrls * urls) +{ + if(!urls) + return; + free(urls->controlURL); + urls->controlURL = 0; + free(urls->ipcondescURL); + urls->ipcondescURL = 0; + free(urls->controlURL_CIF); + urls->controlURL_CIF = 0; + free(urls->controlURL_6FC); + urls->controlURL_6FC = 0; + free(urls->rootdescURL); + urls->rootdescURL = 0; +} + +int +UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data) +{ + char status[64]; + unsigned int uptime; + status[0] = '\0'; + UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype, + status, &uptime, NULL); + if(0 == strcmp("Connected", status)) + { + return 1; + } + else + return 0; +} + + +/* UPNP_GetValidIGD() : + * return values : + * -1 = Internal error + * 0 = NO IGD found + * 1 = A valid connected IGD has been found + * 2 = A valid IGD has been found but it reported as + * not connected + * 3 = an UPnP device has been found but was not recognized as an IGD + * + * In any positive non zero return case, the urls and data structures + * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to + * free allocated memory. + */ +LIBSPEC int +UPNP_GetValidIGD(struct UPNPDev * devlist, + struct UPNPUrls * urls, + struct IGDdatas * data, + char * lanaddr, int lanaddrlen) +{ + struct xml_desc { + char * xml; + int size; + int is_igd; + } * desc = NULL; + struct UPNPDev * dev; + int ndev = 0; + int i; + int state = -1; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */ + int n_igd = 0; + char extIpAddr[16]; + if(!devlist) + { +#ifdef DEBUG + printf("Empty devlist\n"); +#endif + return 0; + } + /* counting total number of devices in the list */ + for(dev = devlist; dev; dev = dev->pNext) + ndev++; + if(ndev > 0) + { + desc = calloc(ndev, sizeof(struct xml_desc)); + if(!desc) + return -1; /* memory allocation error */ + } + /* Step 1 : downloading descriptions and testing type */ + for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) + { + /* we should choose an internet gateway device. + * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */ + desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size), + lanaddr, lanaddrlen, + dev->scope_id); +#ifdef DEBUG + if(!desc[i].xml) + { + printf("error getting XML description %s\n", dev->descURL); + } +#endif + if(desc[i].xml) + { + memset(data, 0, sizeof(struct IGDdatas)); + memset(urls, 0, sizeof(struct UPNPUrls)); + parserootdesc(desc[i].xml, desc[i].size, data); + if(0==strcmp(data->CIF.servicetype, + "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")) + { + desc[i].is_igd = 1; + n_igd++; + } + } + } + /* iterate the list to find a device depending on state */ + for(state = 1; state <= 3; state++) + { + for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) + { + if(desc[i].xml) + { + memset(data, 0, sizeof(struct IGDdatas)); + memset(urls, 0, sizeof(struct UPNPUrls)); + parserootdesc(desc[i].xml, desc[i].size, data); + if(desc[i].is_igd || state >= 3 ) + { + GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); + + /* in state 2 and 3 we dont test if device is connected ! */ + if(state >= 2) + goto free_and_return; +#ifdef DEBUG + printf("UPNPIGD_IsConnected(%s) = %d\n", + urls->controlURL, + UPNPIGD_IsConnected(urls, data)); +#endif + /* checks that status is connected AND there is a external IP address assigned */ + if(UPNPIGD_IsConnected(urls, data) + && (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) + goto free_and_return; + FreeUPNPUrls(urls); + if(data->second.servicetype[0] != '\0') { +#ifdef DEBUG + printf("We tried %s, now we try %s !\n", + data->first.servicetype, data->second.servicetype); +#endif + /* swaping WANPPPConnection and WANIPConnection ! */ + memcpy(&data->tmp, &data->first, sizeof(struct IGDdatas_service)); + memcpy(&data->first, &data->second, sizeof(struct IGDdatas_service)); + memcpy(&data->second, &data->tmp, sizeof(struct IGDdatas_service)); + GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); +#ifdef DEBUG + printf("UPNPIGD_IsConnected(%s) = %d\n", + urls->controlURL, + UPNPIGD_IsConnected(urls, data)); +#endif + if(UPNPIGD_IsConnected(urls, data) + && (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) + goto free_and_return; + FreeUPNPUrls(urls); + } + } + memset(data, 0, sizeof(struct IGDdatas)); + } + } + } + state = 0; +free_and_return: + if(desc) { + for(i = 0; i < ndev; i++) { + if(desc[i].xml) { + free(desc[i].xml); + } + } + free(desc); + } + return state; +} + +/* UPNP_GetIGDFromUrl() + * Used when skipping the discovery process. + * return value : + * 0 - Not ok + * 1 - OK */ +int +UPNP_GetIGDFromUrl(const char * rootdescurl, + struct UPNPUrls * urls, + struct IGDdatas * data, + char * lanaddr, int lanaddrlen) +{ + char * descXML; + int descXMLsize = 0; + descXML = miniwget_getaddr(rootdescurl, &descXMLsize, + lanaddr, lanaddrlen, 0); + if(descXML) { + memset(data, 0, sizeof(struct IGDdatas)); + memset(urls, 0, sizeof(struct UPNPUrls)); + parserootdesc(descXML, descXMLsize, data); + free(descXML); + descXML = NULL; + GetUPNPUrls(urls, data, rootdescurl, 0); + return 1; + } else { + return 0; + } +} + diff --git a/contrib/miniupnpc/miniupnpc.def b/contrib/miniupnpc/miniupnpc.def new file mode 100644 index 00000000..33433560 --- /dev/null +++ b/contrib/miniupnpc/miniupnpc.def @@ -0,0 +1,43 @@ +LIBRARY +; miniupnpc library + miniupnpc + +EXPORTS +; miniupnpc + upnpDiscover + freeUPNPDevlist + parserootdesc + UPNP_GetValidIGD + UPNP_GetIGDFromUrl + GetUPNPUrls + FreeUPNPUrls +; miniwget + miniwget + miniwget_getaddr +; upnpcommands + UPNP_GetTotalBytesSent + UPNP_GetTotalBytesReceived + UPNP_GetTotalPacketsSent + UPNP_GetTotalPacketsReceived + UPNP_GetStatusInfo + UPNP_GetConnectionTypeInfo + UPNP_GetExternalIPAddress + UPNP_GetLinkLayerMaxBitRates + UPNP_AddPortMapping + UPNP_DeletePortMapping + UPNP_GetPortMappingNumberOfEntries + UPNP_GetSpecificPortMappingEntry + UPNP_GetGenericPortMappingEntry + UPNP_GetListOfPortMappings + UPNP_AddPinhole + UPNP_CheckPinholeWorking + UPNP_UpdatePinhole + UPNP_GetPinholePackets + UPNP_DeletePinhole + UPNP_GetFirewallStatus + UPNP_GetOutboundPinholeTimeout +; upnperrors + strupnperror +; portlistingparse + ParsePortListing + FreePortListing diff --git a/contrib/miniupnpc/miniupnpc.h b/contrib/miniupnpc/miniupnpc.h new file mode 100644 index 00000000..3af109cf --- /dev/null +++ b/contrib/miniupnpc/miniupnpc.h @@ -0,0 +1,130 @@ +/* $Id: miniupnpc.h,v 1.35 2014/01/31 13:26:34 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ + * Author: Thomas Bernard + * Copyright (c) 2005-2012 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef MINIUPNPC_H_INCLUDED +#define MINIUPNPC_H_INCLUDED + +#include "declspec.h" +#include "igd_desc_parse.h" + +/* error codes : */ +#define UPNPDISCOVER_SUCCESS (0) +#define UPNPDISCOVER_UNKNOWN_ERROR (-1) +#define UPNPDISCOVER_SOCKET_ERROR (-101) +#define UPNPDISCOVER_MEMORY_ERROR (-102) + +/* versions : */ +#define MINIUPNPC_VERSION "1.9.20140401" +#define MINIUPNPC_API_VERSION 10 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Structures definitions : */ +struct UPNParg { const char * elt; const char * val; }; + +char * +simpleUPnPcommand(int, const char *, const char *, + const char *, struct UPNParg *, + int *); + +struct UPNPDev { + struct UPNPDev * pNext; + char * descURL; + char * st; + unsigned int scope_id; + char buffer[2]; +}; + +/* upnpDiscover() + * discover UPnP devices on the network. + * The discovered devices are returned as a chained list. + * It is up to the caller to free the list with freeUPNPDevlist(). + * delay (in millisecond) is the maximum time for waiting any device + * response. + * If available, device list will be obtained from MiniSSDPd. + * Default path for minissdpd socket will be used if minissdpdsock argument + * is NULL. + * If multicastif is not NULL, it will be used instead of the default + * multicast interface for sending SSDP discover packets. + * If sameport is not null, SSDP packets will be sent from the source port + * 1900 (same as destination port) otherwise system assign a source port. */ +LIBSPEC struct UPNPDev * +upnpDiscover(int delay, const char * multicastif, + const char * minissdpdsock, int sameport, + int ipv6, + int * error); +/* freeUPNPDevlist() + * free list returned by upnpDiscover() */ +LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist); + +/* parserootdesc() : + * parse root XML description of a UPnP device and fill the IGDdatas + * structure. */ +LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *); + +/* structure used to get fast access to urls + * controlURL: controlURL of the WANIPConnection + * ipcondescURL: url of the description of the WANIPConnection + * controlURL_CIF: controlURL of the WANCommonInterfaceConfig + * controlURL_6FC: controlURL of the WANIPv6FirewallControl + */ +struct UPNPUrls { + char * controlURL; + char * ipcondescURL; + char * controlURL_CIF; + char * controlURL_6FC; + char * rootdescURL; +}; + +/* UPNP_GetValidIGD() : + * return values : + * 0 = NO IGD found + * 1 = A valid connected IGD has been found + * 2 = A valid IGD has been found but it reported as + * not connected + * 3 = an UPnP device has been found but was not recognized as an IGD + * + * In any non zero return case, the urls and data structures + * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to + * free allocated memory. + */ +LIBSPEC int +UPNP_GetValidIGD(struct UPNPDev * devlist, + struct UPNPUrls * urls, + struct IGDdatas * data, + char * lanaddr, int lanaddrlen); + +/* UPNP_GetIGDFromUrl() + * Used when skipping the discovery process. + * return value : + * 0 - Not ok + * 1 - OK */ +LIBSPEC int +UPNP_GetIGDFromUrl(const char * rootdescurl, + struct UPNPUrls * urls, + struct IGDdatas * data, + char * lanaddr, int lanaddrlen); + +LIBSPEC void +GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, + const char *, unsigned int); + +LIBSPEC void +FreeUPNPUrls(struct UPNPUrls *); + +/* return 0 or 1 */ +LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/contrib/miniupnpc/miniupnpcmodule.c b/contrib/miniupnpc/miniupnpcmodule.c new file mode 100644 index 00000000..4654c987 --- /dev/null +++ b/contrib/miniupnpc/miniupnpcmodule.c @@ -0,0 +1,545 @@ +/* $Id: miniupnpcmodule.c,v 1.22 2014/01/31 13:18:25 nanard Exp $*/ +/* Project : miniupnp + * Author : Thomas BERNARD + * website : http://miniupnp.tuxfamily.org/ + * copyright (c) 2007-2014 Thomas Bernard + * This software is subjet to the conditions detailed in the + * provided LICENCE file. */ +#include +#define STATICLIB +#include "structmember.h" +#include "miniupnpc.h" +#include "upnpcommands.h" +#include "upnperrors.h" + +/* for compatibility with Python < 2.4 */ +#ifndef Py_RETURN_NONE +#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None +#endif + +#ifndef Py_RETURN_TRUE +#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True +#endif + +#ifndef Py_RETURN_FALSE +#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False +#endif + +/* for compatibility with Python < 3.0 */ +#ifndef PyVarObject_HEAD_INIT +#define PyVarObject_HEAD_INIT(type, size) \ + PyObject_HEAD_INIT(type) size, +#endif + +#ifndef Py_TYPE +#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) +#endif + +typedef struct { + PyObject_HEAD + /* Type-specific fields go here. */ + struct UPNPDev * devlist; + struct UPNPUrls urls; + struct IGDdatas data; + unsigned int discoverdelay; /* value passed to upnpDiscover() */ + char lanaddr[40]; /* our ip address on the LAN */ + char * multicastif; + char * minissdpdsocket; +} UPnPObject; + +static PyMemberDef UPnP_members[] = { + {"lanaddr", T_STRING_INPLACE, offsetof(UPnPObject, lanaddr), + READONLY, "ip address on the LAN" + }, + {"discoverdelay", T_UINT, offsetof(UPnPObject, discoverdelay), + 0/*READWRITE*/, "value in ms used to wait for SSDP responses" + }, + /* T_STRING is allways readonly :( */ + {"multicastif", T_STRING, offsetof(UPnPObject, multicastif), + 0, "IP of the network interface to be used for multicast operations" + }, + {"minissdpdsocket", T_STRING, offsetof(UPnPObject, multicastif), + 0, "path of the MiniSSDPd unix socket" + }, + {NULL} +}; + +static void +UPnPObject_dealloc(UPnPObject *self) +{ + freeUPNPDevlist(self->devlist); + FreeUPNPUrls(&self->urls); + Py_TYPE(self)->tp_free((PyObject*)self); +} + +static PyObject * +UPnP_discover(UPnPObject *self) +{ + struct UPNPDev * dev; + int i; + PyObject *res = NULL; + if(self->devlist) + { + freeUPNPDevlist(self->devlist); + self->devlist = 0; + } + Py_BEGIN_ALLOW_THREADS + self->devlist = upnpDiscover((int)self->discoverdelay/*timeout in ms*/, + 0/* multicast if*/, + 0/*minissdpd socket*/, + 0/*sameport flag*/, + 0/*ip v6*/, + 0/*error */); + Py_END_ALLOW_THREADS + /* Py_RETURN_NONE ??? */ + for(dev = self->devlist, i = 0; dev; dev = dev->pNext) + i++; + res = Py_BuildValue("i", i); + return res; +} + +static PyObject * +UPnP_selectigd(UPnPObject *self) +{ + int r; +Py_BEGIN_ALLOW_THREADS + r = UPNP_GetValidIGD(self->devlist, &self->urls, &self->data, + self->lanaddr, sizeof(self->lanaddr)); +Py_END_ALLOW_THREADS + if(r) + { + return Py_BuildValue("s", self->urls.controlURL); + } + else + { + /* TODO: have our own exception type ! */ + PyErr_SetString(PyExc_Exception, "No UPnP device discovered"); + return NULL; + } +} + +static PyObject * +UPnP_totalbytesent(UPnPObject *self) +{ + UNSIGNED_INTEGER i; +Py_BEGIN_ALLOW_THREADS + i = UPNP_GetTotalBytesSent(self->urls.controlURL_CIF, + self->data.CIF.servicetype); +Py_END_ALLOW_THREADS + return Py_BuildValue("I", i); +} + +static PyObject * +UPnP_totalbytereceived(UPnPObject *self) +{ + UNSIGNED_INTEGER i; +Py_BEGIN_ALLOW_THREADS + i = UPNP_GetTotalBytesReceived(self->urls.controlURL_CIF, + self->data.CIF.servicetype); +Py_END_ALLOW_THREADS + return Py_BuildValue("I", i); +} + +static PyObject * +UPnP_totalpacketsent(UPnPObject *self) +{ + UNSIGNED_INTEGER i; +Py_BEGIN_ALLOW_THREADS + i = UPNP_GetTotalPacketsSent(self->urls.controlURL_CIF, + self->data.CIF.servicetype); +Py_END_ALLOW_THREADS + return Py_BuildValue("I", i); +} + +static PyObject * +UPnP_totalpacketreceived(UPnPObject *self) +{ + UNSIGNED_INTEGER i; +Py_BEGIN_ALLOW_THREADS + i = UPNP_GetTotalPacketsReceived(self->urls.controlURL_CIF, + self->data.CIF.servicetype); +Py_END_ALLOW_THREADS + return Py_BuildValue("I", i); +} + +static PyObject * +UPnP_statusinfo(UPnPObject *self) +{ + char status[64]; + char lastconnerror[64]; + unsigned int uptime = 0; + int r; + status[0] = '\0'; + lastconnerror[0] = '\0'; +Py_BEGIN_ALLOW_THREADS + r = UPNP_GetStatusInfo(self->urls.controlURL, self->data.first.servicetype, + status, &uptime, lastconnerror); +Py_END_ALLOW_THREADS + if(r==UPNPCOMMAND_SUCCESS) { + return Py_BuildValue("(s,I,s)", status, uptime, lastconnerror); + } else { + /* TODO: have our own exception type ! */ + PyErr_SetString(PyExc_Exception, strupnperror(r)); + return NULL; + } +} + +static PyObject * +UPnP_connectiontype(UPnPObject *self) +{ + char connectionType[64]; + int r; + connectionType[0] = '\0'; +Py_BEGIN_ALLOW_THREADS + r = UPNP_GetConnectionTypeInfo(self->urls.controlURL, + self->data.first.servicetype, + connectionType); +Py_END_ALLOW_THREADS + if(r==UPNPCOMMAND_SUCCESS) { + return Py_BuildValue("s", connectionType); + } else { + /* TODO: have our own exception type ! */ + PyErr_SetString(PyExc_Exception, strupnperror(r)); + return NULL; + } +} + +static PyObject * +UPnP_externalipaddress(UPnPObject *self) +{ + char externalIPAddress[40]; + int r; + externalIPAddress[0] = '\0'; +Py_BEGIN_ALLOW_THREADS + r = UPNP_GetExternalIPAddress(self->urls.controlURL, + self->data.first.servicetype, + externalIPAddress); +Py_END_ALLOW_THREADS + if(r==UPNPCOMMAND_SUCCESS) { + return Py_BuildValue("s", externalIPAddress); + } else { + /* TODO: have our own exception type ! */ + PyErr_SetString(PyExc_Exception, strupnperror(r)); + return NULL; + } +} + +/* AddPortMapping(externalPort, protocol, internalHost, internalPort, desc, + * remoteHost) + * protocol is 'UDP' or 'TCP' */ +static PyObject * +UPnP_addportmapping(UPnPObject *self, PyObject *args) +{ + char extPort[6]; + unsigned short ePort; + char inPort[6]; + unsigned short iPort; + const char * proto; + const char * host; + const char * desc; + const char * remoteHost; + const char * leaseDuration = "0"; + int r; + if (!PyArg_ParseTuple(args, "HssHss", &ePort, &proto, + &host, &iPort, &desc, &remoteHost)) + return NULL; +Py_BEGIN_ALLOW_THREADS + sprintf(extPort, "%hu", ePort); + sprintf(inPort, "%hu", iPort); + r = UPNP_AddPortMapping(self->urls.controlURL, self->data.first.servicetype, + extPort, inPort, host, desc, proto, + remoteHost, leaseDuration); +Py_END_ALLOW_THREADS + if(r==UPNPCOMMAND_SUCCESS) + { + Py_RETURN_TRUE; + } + else + { + // TODO: RAISE an Exception. See upnpcommands.h for errors codes. + // upnperrors.c + //Py_RETURN_FALSE; + /* TODO: have our own exception type ! */ + PyErr_SetString(PyExc_Exception, strupnperror(r)); + return NULL; + } +} + +/* DeletePortMapping(extPort, proto, removeHost='') + * proto = 'UDP', 'TCP' */ +static PyObject * +UPnP_deleteportmapping(UPnPObject *self, PyObject *args) +{ + char extPort[6]; + unsigned short ePort; + const char * proto; + const char * remoteHost = ""; + int r; + if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost)) + return NULL; +Py_BEGIN_ALLOW_THREADS + sprintf(extPort, "%hu", ePort); + r = UPNP_DeletePortMapping(self->urls.controlURL, self->data.first.servicetype, + extPort, proto, remoteHost); +Py_END_ALLOW_THREADS + if(r==UPNPCOMMAND_SUCCESS) { + Py_RETURN_TRUE; + } else { + /* TODO: have our own exception type ! */ + PyErr_SetString(PyExc_Exception, strupnperror(r)); + return NULL; + } +} + +static PyObject * +UPnP_getportmappingnumberofentries(UPnPObject *self) +{ + unsigned int n = 0; + int r; +Py_BEGIN_ALLOW_THREADS + r = UPNP_GetPortMappingNumberOfEntries(self->urls.controlURL, + self->data.first.servicetype, + &n); +Py_END_ALLOW_THREADS + if(r==UPNPCOMMAND_SUCCESS) { + return Py_BuildValue("I", n); + } else { + /* TODO: have our own exception type ! */ + PyErr_SetString(PyExc_Exception, strupnperror(r)); + return NULL; + } +} + +/* GetSpecificPortMapping(ePort, proto, remoteHost='') + * proto = 'UDP' or 'TCP' */ +static PyObject * +UPnP_getspecificportmapping(UPnPObject *self, PyObject *args) +{ + char extPort[6]; + unsigned short ePort; + const char * proto; + const char * remoteHost = ""; + char intClient[40]; + char intPort[6]; + unsigned short iPort; + char desc[80]; + char enabled[4]; + char leaseDuration[16]; + if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost)) + return NULL; + extPort[0] = '\0'; intClient[0] = '\0'; intPort[0] = '\0'; + desc[0] = '\0'; enabled[0] = '\0'; leaseDuration[0] = '\0'; +Py_BEGIN_ALLOW_THREADS + sprintf(extPort, "%hu", ePort); + UPNP_GetSpecificPortMappingEntry(self->urls.controlURL, + self->data.first.servicetype, + extPort, proto, remoteHost, + intClient, intPort, + desc, enabled, leaseDuration); +Py_END_ALLOW_THREADS + if(intClient[0]) + { + iPort = (unsigned short)atoi(intPort); + return Py_BuildValue("(s,H,s,O,i)", + intClient, iPort, desc, + PyBool_FromLong(atoi(enabled)), + atoi(leaseDuration)); + } + else + { + Py_RETURN_NONE; + } +} + +/* GetGenericPortMapping(index) */ +static PyObject * +UPnP_getgenericportmapping(UPnPObject *self, PyObject *args) +{ + int i, r; + char index[8]; + char intClient[40]; + char intPort[6]; + unsigned short iPort; + char extPort[6]; + unsigned short ePort; + char protocol[4]; + char desc[80]; + char enabled[6]; + char rHost[64]; + char duration[16]; /* lease duration */ + unsigned int dur; + if(!PyArg_ParseTuple(args, "i", &i)) + return NULL; +Py_BEGIN_ALLOW_THREADS + snprintf(index, sizeof(index), "%d", i); + rHost[0] = '\0'; enabled[0] = '\0'; + duration[0] = '\0'; desc[0] = '\0'; + extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0'; + r = UPNP_GetGenericPortMappingEntry(self->urls.controlURL, + self->data.first.servicetype, + index, + extPort, intClient, intPort, + protocol, desc, enabled, rHost, + duration); +Py_END_ALLOW_THREADS + if(r==UPNPCOMMAND_SUCCESS) + { + ePort = (unsigned short)atoi(extPort); + iPort = (unsigned short)atoi(intPort); + dur = (unsigned int)strtoul(duration, 0, 0); + return Py_BuildValue("(H,s,(s,H),s,s,s,I)", + ePort, protocol, intClient, iPort, + desc, enabled, rHost, dur); + } + else + { + Py_RETURN_NONE; + } +} + +/* miniupnpc.UPnP object Method Table */ +static PyMethodDef UPnP_methods[] = { + {"discover", (PyCFunction)UPnP_discover, METH_NOARGS, + "discover UPnP IGD devices on the network" + }, + {"selectigd", (PyCFunction)UPnP_selectigd, METH_NOARGS, + "select a valid UPnP IGD among discovered devices" + }, + {"totalbytesent", (PyCFunction)UPnP_totalbytesent, METH_NOARGS, + "return the total number of bytes sent by UPnP IGD" + }, + {"totalbytereceived", (PyCFunction)UPnP_totalbytereceived, METH_NOARGS, + "return the total number of bytes received by UPnP IGD" + }, + {"totalpacketsent", (PyCFunction)UPnP_totalpacketsent, METH_NOARGS, + "return the total number of packets sent by UPnP IGD" + }, + {"totalpacketreceived", (PyCFunction)UPnP_totalpacketreceived, METH_NOARGS, + "return the total number of packets received by UPnP IGD" + }, + {"statusinfo", (PyCFunction)UPnP_statusinfo, METH_NOARGS, + "return status and uptime" + }, + {"connectiontype", (PyCFunction)UPnP_connectiontype, METH_NOARGS, + "return IGD WAN connection type" + }, + {"externalipaddress", (PyCFunction)UPnP_externalipaddress, METH_NOARGS, + "return external IP address" + }, + {"addportmapping", (PyCFunction)UPnP_addportmapping, METH_VARARGS, + "add a port mapping" + }, + {"deleteportmapping", (PyCFunction)UPnP_deleteportmapping, METH_VARARGS, + "delete a port mapping" + }, + {"getportmappingnumberofentries", (PyCFunction)UPnP_getportmappingnumberofentries, METH_NOARGS, + "-- non standard --" + }, + {"getspecificportmapping", (PyCFunction)UPnP_getspecificportmapping, METH_VARARGS, + "get details about a specific port mapping entry" + }, + {"getgenericportmapping", (PyCFunction)UPnP_getgenericportmapping, METH_VARARGS, + "get all details about the port mapping at index" + }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject UPnPType = { + PyVarObject_HEAD_INIT(NULL, + 0) /*ob_size*/ + "miniupnpc.UPnP", /*tp_name*/ + sizeof(UPnPObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)UPnPObject_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "UPnP objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + UPnP_methods, /* tp_methods */ + UPnP_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0,/*(initproc)UPnP_init,*/ /* tp_init */ + 0, /* tp_alloc */ +#ifndef _WIN32 + PyType_GenericNew,/*UPnP_new,*/ /* tp_new */ +#else + 0, +#endif +}; + +/* module methods */ +static PyMethodDef miniupnpc_methods[] = { + {NULL} /* Sentinel */ +}; + +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "miniupnpc", /* m_name */ + "miniupnpc module.", /* m_doc */ + -1, /* m_size */ + miniupnpc_methods, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; +#endif + +#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ +#define PyMODINIT_FUNC void +#endif + +PyMODINIT_FUNC +#if PY_MAJOR_VERSION >= 3 +PyInit_miniupnpc(void) +#else +initminiupnpc(void) +#endif +{ + PyObject* m; + +#ifdef _WIN32 + UPnPType.tp_new = PyType_GenericNew; +#endif + if (PyType_Ready(&UPnPType) < 0) + return; + +#if PY_MAJOR_VERSION >= 3 + m = PyModule_Create(&moduledef); +#else + m = Py_InitModule3("miniupnpc", miniupnpc_methods, + "miniupnpc module."); +#endif + + Py_INCREF(&UPnPType); + PyModule_AddObject(m, "UPnP", (PyObject *)&UPnPType); + +#if PY_MAJOR_VERSION >= 3 + return m; +#endif +} + diff --git a/contrib/miniupnpc/miniupnpcstrings.h.cmake b/contrib/miniupnpc/miniupnpcstrings.h.cmake new file mode 100644 index 00000000..236b2dca --- /dev/null +++ b/contrib/miniupnpc/miniupnpcstrings.h.cmake @@ -0,0 +1,7 @@ +#ifndef MINIUPNPCSTRINGS_H_INCLUDED +#define MINIUPNPCSTRINGS_H_INCLUDED + +#define OS_STRING "${CMAKE_SYSTEM_NAME}" +#define MINIUPNPC_VERSION_STRING "${MINIUPNPC_VERSION}" + +#endif diff --git a/contrib/miniupnpc/miniupnpcstrings.h.in b/contrib/miniupnpc/miniupnpcstrings.h.in new file mode 100644 index 00000000..c32e3a13 --- /dev/null +++ b/contrib/miniupnpc/miniupnpcstrings.h.in @@ -0,0 +1,15 @@ +/* $Id: miniupnpcstrings.h.in,v 1.5 2012/10/16 16:48:26 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * Author: Thomas Bernard + * Copyright (c) 2005-2011 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef MINIUPNPCSTRINGS_H_INCLUDED +#define MINIUPNPCSTRINGS_H_INCLUDED + +#define OS_STRING "OS/version" +#define MINIUPNPC_VERSION_STRING "version" + +#endif + diff --git a/contrib/miniupnpc/miniupnpctypes.h b/contrib/miniupnpc/miniupnpctypes.h new file mode 100644 index 00000000..591c32fb --- /dev/null +++ b/contrib/miniupnpc/miniupnpctypes.h @@ -0,0 +1,19 @@ +/* $Id: miniupnpctypes.h,v 1.2 2012/09/27 15:42:10 nanard Exp $ */ +/* Miniupnp project : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org + * Author : Thomas Bernard + * Copyright (c) 2011 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided within this distribution */ +#ifndef MINIUPNPCTYPES_H_INCLUDED +#define MINIUPNPCTYPES_H_INCLUDED + +#if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) +#define UNSIGNED_INTEGER unsigned long long +#define STRTOUI strtoull +#else +#define UNSIGNED_INTEGER unsigned int +#define STRTOUI strtoul +#endif + +#endif + diff --git a/contrib/miniupnpc/miniwget.c b/contrib/miniupnpc/miniwget.c new file mode 100644 index 00000000..813db932 --- /dev/null +++ b/contrib/miniupnpc/miniwget.c @@ -0,0 +1,575 @@ +/* $Id: miniwget.c,v 1.61 2014/02/05 17:27:48 nanard Exp $ */ +/* Project : miniupnp + * Website : http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2005-2014 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. */ + +#include +#include +#include +#include +#ifdef _WIN32 +#include +#include +#include +#define MAXHOSTNAMELEN 64 +#define MIN(x,y) (((x)<(y))?(x):(y)) +#define snprintf _snprintf +#define socklen_t int +#ifndef strncasecmp +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#define strncasecmp _memicmp +#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ +#define strncasecmp memicmp +#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ +#endif /* #ifndef strncasecmp */ +#else /* #ifdef _WIN32 */ +#include +#include +#if defined(__amigaos__) && !defined(__amigaos4__) +#define socklen_t int +#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */ +#include +#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */ +#include +#include +#include +#include +#include +#define closesocket close +#endif /* #else _WIN32 */ +#if defined(__sun) || defined(sun) +#define MIN(x,y) (((x)<(y))?(x):(y)) +#endif + +#include "miniupnpcstrings.h" +#include "miniwget.h" +#include "connecthostport.h" +#include "receivedata.h" + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif + +/* + * Read a HTTP response from a socket. + * Process Content-Length and Transfer-encoding headers. + * return a pointer to the content buffer, which length is saved + * to the length parameter. + */ +void * +getHTTPResponse(int s, int * size) +{ + char buf[2048]; + int n; + int endofheaders = 0; + int chunked = 0; + int content_length = -1; + unsigned int chunksize = 0; + unsigned int bytestocopy = 0; + /* buffers : */ + char * header_buf; + unsigned int header_buf_len = 2048; + unsigned int header_buf_used = 0; + char * content_buf; + unsigned int content_buf_len = 2048; + unsigned int content_buf_used = 0; + char chunksize_buf[32]; + unsigned int chunksize_buf_index; + + header_buf = malloc(header_buf_len); + content_buf = malloc(content_buf_len); + chunksize_buf[0] = '\0'; + chunksize_buf_index = 0; + + while((n = receivedata(s, buf, 2048, 5000, NULL)) > 0) + { + if(endofheaders == 0) + { + int i; + int linestart=0; + int colon=0; + int valuestart=0; + if(header_buf_used + n > header_buf_len) { + header_buf = realloc(header_buf, header_buf_used + n); + header_buf_len = header_buf_used + n; + } + memcpy(header_buf + header_buf_used, buf, n); + header_buf_used += n; + /* search for CR LF CR LF (end of headers) + * recognize also LF LF */ + i = 0; + while(i < ((int)header_buf_used-1) && (endofheaders == 0)) { + if(header_buf[i] == '\r') { + i++; + if(header_buf[i] == '\n') { + i++; + if(i < (int)header_buf_used && header_buf[i] == '\r') { + i++; + if(i < (int)header_buf_used && header_buf[i] == '\n') { + endofheaders = i+1; + } + } + } + } else if(header_buf[i] == '\n') { + i++; + if(header_buf[i] == '\n') { + endofheaders = i+1; + } + } + i++; + } + if(endofheaders == 0) + continue; + /* parse header lines */ + for(i = 0; i < endofheaders - 1; i++) { + if(colon <= linestart && header_buf[i]==':') + { + colon = i; + while(i < (endofheaders-1) + && (header_buf[i+1] == ' ' || header_buf[i+1] == '\t')) + i++; + valuestart = i + 1; + } + /* detecting end of line */ + else if(header_buf[i]=='\r' || header_buf[i]=='\n') + { + if(colon > linestart && valuestart > colon) + { +#ifdef DEBUG + printf("header='%.*s', value='%.*s'\n", + colon-linestart, header_buf+linestart, + i-valuestart, header_buf+valuestart); +#endif + if(0==strncasecmp(header_buf+linestart, "content-length", colon-linestart)) + { + content_length = atoi(header_buf+valuestart); +#ifdef DEBUG + printf("Content-Length: %d\n", content_length); +#endif + } + else if(0==strncasecmp(header_buf+linestart, "transfer-encoding", colon-linestart) + && 0==strncasecmp(header_buf+valuestart, "chunked", 7)) + { +#ifdef DEBUG + printf("chunked transfer-encoding!\n"); +#endif + chunked = 1; + } + } + while((i < (int)header_buf_used) && (header_buf[i]=='\r' || header_buf[i] == '\n')) + i++; + linestart = i; + colon = linestart; + valuestart = 0; + } + } + /* copy the remaining of the received data back to buf */ + n = header_buf_used - endofheaders; + memcpy(buf, header_buf + endofheaders, n); + /* if(headers) */ + } + if(endofheaders) + { + /* content */ + if(chunked) + { + int i = 0; + while(i < n) + { + if(chunksize == 0) + { + /* reading chunk size */ + if(chunksize_buf_index == 0) { + /* skipping any leading CR LF */ + if(i= '0' + && chunksize_buf[j] <= '9') + chunksize = (chunksize << 4) + (chunksize_buf[j] - '0'); + else + chunksize = (chunksize << 4) + ((chunksize_buf[j] | 32) - 'a' + 10); + } + chunksize_buf[0] = '\0'; + chunksize_buf_index = 0; + i++; + } else { + /* not finished to get chunksize */ + continue; + } +#ifdef DEBUG + printf("chunksize = %u (%x)\n", chunksize, chunksize); +#endif + if(chunksize == 0) + { +#ifdef DEBUG + printf("end of HTTP content - %d %d\n", i, n); + /*printf("'%.*s'\n", n-i, buf+i);*/ +#endif + goto end_of_stream; + } + } + bytestocopy = ((int)chunksize < (n - i))?chunksize:(unsigned int)(n - i); + if((content_buf_used + bytestocopy) > content_buf_len) + { + if(content_length >= (int)(content_buf_used + bytestocopy)) { + content_buf_len = content_length; + } else { + content_buf_len = content_buf_used + bytestocopy; + } + content_buf = (char *)realloc((void *)content_buf, + content_buf_len); + } + memcpy(content_buf + content_buf_used, buf + i, bytestocopy); + content_buf_used += bytestocopy; + i += bytestocopy; + chunksize -= bytestocopy; + } + } + else + { + /* not chunked */ + if(content_length > 0 + && (int)(content_buf_used + n) > content_length) { + /* skipping additional bytes */ + n = content_length - content_buf_used; + } + if(content_buf_used + n > content_buf_len) + { + if(content_length >= (int)(content_buf_used + n)) { + content_buf_len = content_length; + } else { + content_buf_len = content_buf_used + n; + } + content_buf = (char *)realloc((void *)content_buf, + content_buf_len); + } + memcpy(content_buf + content_buf_used, buf, n); + content_buf_used += n; + } + } + /* use the Content-Length header value if available */ + if(content_length > 0 && (int)content_buf_used >= content_length) + { +#ifdef DEBUG + printf("End of HTTP content\n"); +#endif + break; + } + } +end_of_stream: + free(header_buf); header_buf = NULL; + *size = content_buf_used; + if(content_buf_used == 0) + { + free(content_buf); + content_buf = NULL; + } + return content_buf; +} + +/* miniwget3() : + * do all the work. + * Return NULL if something failed. */ +static void * +miniwget3(const char * host, + unsigned short port, const char * path, + int * size, char * addr_str, int addr_str_len, + const char * httpversion, unsigned int scope_id) +{ + char buf[2048]; + int s; + int n; + int len; + int sent; + void * content; + + *size = 0; + s = connecthostport(host, port, scope_id); + if(s < 0) + return NULL; + + /* get address for caller ! */ + if(addr_str) + { + struct sockaddr_storage saddr; + socklen_t saddrlen; + + saddrlen = sizeof(saddr); + if(getsockname(s, (struct sockaddr *)&saddr, &saddrlen) < 0) + { + perror("getsockname"); + } + else + { +#if defined(__amigaos__) && !defined(__amigaos4__) + /* using INT WINAPI WSAAddressToStringA(LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFOA, LPSTR, LPDWORD); + * But his function make a string with the port : nn.nn.nn.nn:port */ +/* if(WSAAddressToStringA((SOCKADDR *)&saddr, sizeof(saddr), + NULL, addr_str, (DWORD *)&addr_str_len)) + { + printf("WSAAddressToStringA() failed : %d\n", WSAGetLastError()); + }*/ + /* the following code is only compatible with ip v4 addresses */ + strncpy(addr_str, inet_ntoa(((struct sockaddr_in *)&saddr)->sin_addr), addr_str_len); +#else +#if 0 + if(saddr.sa_family == AF_INET6) { + inet_ntop(AF_INET6, + &(((struct sockaddr_in6 *)&saddr)->sin6_addr), + addr_str, addr_str_len); + } else { + inet_ntop(AF_INET, + &(((struct sockaddr_in *)&saddr)->sin_addr), + addr_str, addr_str_len); + } +#endif + /* getnameinfo return ip v6 address with the scope identifier + * such as : 2a01:e35:8b2b:7330::%4281128194 */ + n = getnameinfo((const struct sockaddr *)&saddr, saddrlen, + addr_str, addr_str_len, + NULL, 0, + NI_NUMERICHOST | NI_NUMERICSERV); + if(n != 0) { +#ifdef _WIN32 + fprintf(stderr, "getnameinfo() failed : %d\n", n); +#else + fprintf(stderr, "getnameinfo() failed : %s\n", gai_strerror(n)); +#endif + } +#endif + } +#ifdef DEBUG + printf("address miniwget : %s\n", addr_str); +#endif + } + + len = snprintf(buf, sizeof(buf), + "GET %s HTTP/%s\r\n" + "Host: %s:%d\r\n" + "Connection: Close\r\n" + "User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" + + "\r\n", + path, httpversion, host, port); + sent = 0; + /* sending the HTTP request */ + while(sent < len) + { + n = send(s, buf+sent, len-sent, 0); + if(n < 0) + { + perror("send"); + closesocket(s); + return NULL; + } + else + { + sent += n; + } + } + content = getHTTPResponse(s, size); + closesocket(s); + return content; +} + +/* miniwget2() : + * Call miniwget3(); retry with HTTP/1.1 if 1.0 fails. */ +static void * +miniwget2(const char * host, + unsigned short port, const char * path, + int * size, char * addr_str, int addr_str_len, + unsigned int scope_id) +{ + char * respbuffer; + +#if 1 + respbuffer = miniwget3(host, port, path, size, + addr_str, addr_str_len, "1.1", scope_id); +#else + respbuffer = miniwget3(host, port, path, size, + addr_str, addr_str_len, "1.0", scope_id); + if (*size == 0) + { +#ifdef DEBUG + printf("Retrying with HTTP/1.1\n"); +#endif + free(respbuffer); + respbuffer = miniwget3(host, port, path, size, + addr_str, addr_str_len, "1.1", scope_id); + } +#endif + return respbuffer; +} + + + + +/* parseURL() + * arguments : + * url : source string not modified + * hostname : hostname destination string (size of MAXHOSTNAMELEN+1) + * port : port (destination) + * path : pointer to the path part of the URL + * + * Return values : + * 0 - Failure + * 1 - Success */ +int +parseURL(const char * url, + char * hostname, unsigned short * port, + char * * path, unsigned int * scope_id) +{ + char * p1, *p2, *p3; + if(!url) + return 0; + p1 = strstr(url, "://"); + if(!p1) + return 0; + p1 += 3; + if( (url[0]!='h') || (url[1]!='t') + ||(url[2]!='t') || (url[3]!='p')) + return 0; + memset(hostname, 0, MAXHOSTNAMELEN + 1); + if(*p1 == '[') + { + /* IP v6 : http://[2a00:1450:8002::6a]/path/abc */ + char * scope; + scope = strchr(p1, '%'); + p2 = strchr(p1, ']'); + if(p2 && scope && scope < p2 && scope_id) { + /* parse scope */ +#ifdef IF_NAMESIZE + char tmp[IF_NAMESIZE]; + int l; + scope++; + /* "%25" is just '%' in URL encoding */ + if(scope[0] == '2' && scope[1] == '5') + scope += 2; /* skip "25" */ + l = p2 - scope; + if(l >= IF_NAMESIZE) + l = IF_NAMESIZE - 1; + memcpy(tmp, scope, l); + tmp[l] = '\0'; + *scope_id = if_nametoindex(tmp); + if(*scope_id == 0) { + *scope_id = (unsigned int)strtoul(tmp, NULL, 10); + } +#else + /* under windows, scope is numerical */ + char tmp[8]; + int l; + scope++; + /* "%25" is just '%' in URL encoding */ + if(scope[0] == '2' && scope[1] == '5') + scope += 2; /* skip "25" */ + l = p2 - scope; + if(l >= sizeof(tmp)) + l = sizeof(tmp) - 1; + memcpy(tmp, scope, l); + tmp[l] = '\0'; + *scope_id = (unsigned int)strtoul(tmp, NULL, 10); +#endif + } + p3 = strchr(p1, '/'); + if(p2 && p3) + { + p2++; + strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1))); + if(*p2 == ':') + { + *port = 0; + p2++; + while( (*p2 >= '0') && (*p2 <= '9')) + { + *port *= 10; + *port += (unsigned short)(*p2 - '0'); + p2++; + } + } + else + { + *port = 80; + } + *path = p3; + return 1; + } + } + p2 = strchr(p1, ':'); + p3 = strchr(p1, '/'); + if(!p3) + return 0; + if(!p2 || (p2>p3)) + { + strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p3-p1))); + *port = 80; + } + else + { + strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1))); + *port = 0; + p2++; + while( (*p2 >= '0') && (*p2 <= '9')) + { + *port *= 10; + *port += (unsigned short)(*p2 - '0'); + p2++; + } + } + *path = p3; + return 1; +} + +void * +miniwget(const char * url, int * size, unsigned int scope_id) +{ + unsigned short port; + char * path; + /* protocol://host:port/chemin */ + char hostname[MAXHOSTNAMELEN+1]; + *size = 0; + if(!parseURL(url, hostname, &port, &path, &scope_id)) + return NULL; +#ifdef DEBUG + printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n", + hostname, port, path, scope_id); +#endif + return miniwget2(hostname, port, path, size, 0, 0, scope_id); +} + +void * +miniwget_getaddr(const char * url, int * size, + char * addr, int addrlen, unsigned int scope_id) +{ + unsigned short port; + char * path; + /* protocol://host:port/path */ + char hostname[MAXHOSTNAMELEN+1]; + *size = 0; + if(addr) + addr[0] = '\0'; + if(!parseURL(url, hostname, &port, &path, &scope_id)) + return NULL; +#ifdef DEBUG + printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n", + hostname, port, path, scope_id); +#endif + return miniwget2(hostname, port, path, size, addr, addrlen, scope_id); +} + diff --git a/contrib/miniupnpc/miniwget.h b/contrib/miniupnpc/miniwget.h new file mode 100644 index 00000000..31bcea32 --- /dev/null +++ b/contrib/miniupnpc/miniwget.h @@ -0,0 +1,30 @@ +/* $Id: miniwget.h,v 1.8 2012/09/27 15:42:10 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2005-2012 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * */ +#ifndef MINIWGET_H_INCLUDED +#define MINIWGET_H_INCLUDED + +#include "declspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +LIBSPEC void * getHTTPResponse(int s, int * size); + +LIBSPEC void * miniwget(const char *, int *, unsigned int); + +LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int, unsigned int); + +int parseURL(const char *, char *, unsigned short *, char * *, unsigned int *); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/contrib/miniupnpc/minixml.c b/contrib/miniupnpc/minixml.c new file mode 100644 index 00000000..3e201ec2 --- /dev/null +++ b/contrib/miniupnpc/minixml.c @@ -0,0 +1,229 @@ +/* $Id: minixml.c,v 1.11 2014/02/03 15:54:12 nanard Exp $ */ +/* minixml.c : the minimum size a xml parser can be ! */ +/* Project : miniupnp + * webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * Author : Thomas Bernard + +Copyright (c) 2005-2014, Thomas BERNARD +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * 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. + * The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ +#include +#include "minixml.h" + +/* parseatt : used to parse the argument list + * return 0 (false) in case of success and -1 (true) if the end + * of the xmlbuffer is reached. */ +static int parseatt(struct xmlparser * p) +{ + const char * attname; + int attnamelen; + const char * attvalue; + int attvaluelen; + while(p->xml < p->xmlend) + { + if(*p->xml=='/' || *p->xml=='>') + return 0; + if( !IS_WHITE_SPACE(*p->xml) ) + { + char sep; + attname = p->xml; + attnamelen = 0; + while(*p->xml!='=' && !IS_WHITE_SPACE(*p->xml) ) + { + attnamelen++; p->xml++; + if(p->xml >= p->xmlend) + return -1; + } + while(*(p->xml++) != '=') + { + if(p->xml >= p->xmlend) + return -1; + } + while(IS_WHITE_SPACE(*p->xml)) + { + p->xml++; + if(p->xml >= p->xmlend) + return -1; + } + sep = *p->xml; + if(sep=='\'' || sep=='\"') + { + p->xml++; + if(p->xml >= p->xmlend) + return -1; + attvalue = p->xml; + attvaluelen = 0; + while(*p->xml != sep) + { + attvaluelen++; p->xml++; + if(p->xml >= p->xmlend) + return -1; + } + } + else + { + attvalue = p->xml; + attvaluelen = 0; + while( !IS_WHITE_SPACE(*p->xml) + && *p->xml != '>' && *p->xml != '/') + { + attvaluelen++; p->xml++; + if(p->xml >= p->xmlend) + return -1; + } + } + /*printf("%.*s='%.*s'\n", + attnamelen, attname, attvaluelen, attvalue);*/ + if(p->attfunc) + p->attfunc(p->data, attname, attnamelen, attvalue, attvaluelen); + } + p->xml++; + } + return -1; +} + +/* parseelt parse the xml stream and + * call the callback functions when needed... */ +static void parseelt(struct xmlparser * p) +{ + int i; + const char * elementname; + while(p->xml < (p->xmlend - 1)) + { + if((p->xml + 4) <= p->xmlend && (0 == memcmp(p->xml, "", 3) != 0); + p->xml += 3; + } + else if((p->xml)[0]=='<' && (p->xml)[1]!='?') + { + i = 0; elementname = ++p->xml; + while( !IS_WHITE_SPACE(*p->xml) + && (*p->xml!='>') && (*p->xml!='/') + ) + { + i++; p->xml++; + if (p->xml >= p->xmlend) + return; + /* to ignore namespace : */ + if(*p->xml==':') + { + i = 0; + elementname = ++p->xml; + } + } + if(i>0) + { + if(p->starteltfunc) + p->starteltfunc(p->data, elementname, i); + if(parseatt(p)) + return; + if(*p->xml!='/') + { + const char * data; + i = 0; data = ++p->xml; + if (p->xml >= p->xmlend) + return; + while( IS_WHITE_SPACE(*p->xml) ) + { + i++; p->xml++; + if (p->xml >= p->xmlend) + return; + } + if(memcmp(p->xml, "xml += 9; + data = p->xml; + i = 0; + while(memcmp(p->xml, "]]>", 3) != 0) + { + i++; p->xml++; + if ((p->xml + 3) >= p->xmlend) + return; + } + if(i>0 && p->datafunc) + p->datafunc(p->data, data, i); + while(*p->xml!='<') + { + p->xml++; + if (p->xml >= p->xmlend) + return; + } + } + else + { + while(*p->xml!='<') + { + i++; p->xml++; + if ((p->xml + 1) >= p->xmlend) + return; + } + if(i>0 && p->datafunc && *(p->xml + 1) == '/') + p->datafunc(p->data, data, i); + } + } + } + else if(*p->xml == '/') + { + i = 0; elementname = ++p->xml; + if (p->xml >= p->xmlend) + return; + while((*p->xml != '>')) + { + i++; p->xml++; + if (p->xml >= p->xmlend) + return; + } + if(p->endeltfunc) + p->endeltfunc(p->data, elementname, i); + p->xml++; + } + } + else + { + p->xml++; + } + } +} + +/* the parser must be initialized before calling this function */ +void parsexml(struct xmlparser * parser) +{ + parser->xml = parser->xmlstart; + parser->xmlend = parser->xmlstart + parser->xmlsize; + parseelt(parser); +} + + diff --git a/contrib/miniupnpc/minixml.h b/contrib/miniupnpc/minixml.h new file mode 100644 index 00000000..9f43aa48 --- /dev/null +++ b/contrib/miniupnpc/minixml.h @@ -0,0 +1,37 @@ +/* $Id: minixml.h,v 1.7 2012/09/27 15:42:10 nanard Exp $ */ +/* minimal xml parser + * + * Project : miniupnp + * Website : http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2005 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * */ +#ifndef MINIXML_H_INCLUDED +#define MINIXML_H_INCLUDED +#define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n')) + +/* if a callback function pointer is set to NULL, + * the function is not called */ +struct xmlparser { + const char *xmlstart; + const char *xmlend; + const char *xml; /* pointer to current character */ + int xmlsize; + void * data; + void (*starteltfunc) (void *, const char *, int); + void (*endeltfunc) (void *, const char *, int); + void (*datafunc) (void *, const char *, int); + void (*attfunc) (void *, const char *, int, const char *, int); +}; + +/* parsexml() + * the xmlparser structure must be initialized before the call + * the following structure members have to be initialized : + * xmlstart, xmlsize, data, *func + * xml is for internal usage, xmlend is computed automatically */ +void parsexml(struct xmlparser *); + +#endif + diff --git a/contrib/miniupnpc/minixmlvalid.c b/contrib/miniupnpc/minixmlvalid.c new file mode 100644 index 00000000..0a112bf8 --- /dev/null +++ b/contrib/miniupnpc/minixmlvalid.c @@ -0,0 +1,158 @@ +/* $Id: minixmlvalid.c,v 1.6 2012/05/01 16:24:07 nanard Exp $ */ +/* MiniUPnP Project + * http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/ + * minixmlvalid.c : + * validation program for the minixml parser + * + * (c) 2006-2011 Thomas Bernard */ + +#include +#include +#include +#include "minixml.h" + +/* xml event structure */ +struct event { + enum { ELTSTART, ELTEND, ATT, CHARDATA } type; + const char * data; + int len; +}; + +struct eventlist { + int n; + struct event * events; +}; + +/* compare 2 xml event lists + * return 0 if the two lists are equals */ +int evtlistcmp(struct eventlist * a, struct eventlist * b) +{ + int i; + struct event * ae, * be; + if(a->n != b->n) + { + printf("event number not matching : %d != %d\n", a->n, b->n); + /*return 1;*/ + } + for(i=0; in; i++) + { + ae = a->events + i; + be = b->events + i; + if( (ae->type != be->type) + ||(ae->len != be->len) + ||memcmp(ae->data, be->data, ae->len)) + { + printf("Found a difference : %d '%.*s' != %d '%.*s'\n", + ae->type, ae->len, ae->data, + be->type, be->len, be->data); + return 1; + } + } + return 0; +} + +/* Test data */ +static const char xmldata[] = +"\n" +" " +"character data" +" \n \t" +"" +"\nstuff !\n ]]> \n\n" +" \tchardata1 chardata2 " +""; + +static const struct event evtref[] = +{ + {ELTSTART, "xmlroot", 7}, + {ELTSTART, "elt1", 4}, + /* attributes */ + {CHARDATA, "character data", 14}, + {ELTEND, "elt1", 4}, + {ELTSTART, "elt1b", 5}, + {ELTSTART, "elt1", 4}, + {CHARDATA, " stuff !\n ", 16}, + {ELTEND, "elt1", 4}, + {ELTSTART, "elt2a", 5}, + {ELTSTART, "elt2b", 5}, + {CHARDATA, "chardata1", 9}, + {ELTEND, "elt2b", 5}, + {ELTSTART, "elt2b", 5}, + {CHARDATA, " chardata2 ", 11}, + {ELTEND, "elt2b", 5}, + {ELTEND, "elt2a", 5}, + {ELTEND, "xmlroot", 7} +}; + +void startelt(void * data, const char * p, int l) +{ + struct eventlist * evtlist = data; + struct event * evt; + evt = evtlist->events + evtlist->n; + /*printf("startelt : %.*s\n", l, p);*/ + evt->type = ELTSTART; + evt->data = p; + evt->len = l; + evtlist->n++; +} + +void endelt(void * data, const char * p, int l) +{ + struct eventlist * evtlist = data; + struct event * evt; + evt = evtlist->events + evtlist->n; + /*printf("endelt : %.*s\n", l, p);*/ + evt->type = ELTEND; + evt->data = p; + evt->len = l; + evtlist->n++; +} + +void chardata(void * data, const char * p, int l) +{ + struct eventlist * evtlist = data; + struct event * evt; + evt = evtlist->events + evtlist->n; + /*printf("chardata : '%.*s'\n", l, p);*/ + evt->type = CHARDATA; + evt->data = p; + evt->len = l; + evtlist->n++; +} + +int testxmlparser(const char * xml, int size) +{ + int r; + struct eventlist evtlist; + struct eventlist evtlistref; + struct xmlparser parser; + evtlist.n = 0; + evtlist.events = malloc(sizeof(struct event)*100); + memset(&parser, 0, sizeof(parser)); + parser.xmlstart = xml; + parser.xmlsize = size; + parser.data = &evtlist; + parser.starteltfunc = startelt; + parser.endeltfunc = endelt; + parser.datafunc = chardata; + parsexml(&parser); + printf("%d events\n", evtlist.n); + /* compare */ + evtlistref.n = sizeof(evtref)/sizeof(struct event); + evtlistref.events = (struct event *)evtref; + r = evtlistcmp(&evtlistref, &evtlist); + free(evtlist.events); + return r; +} + +int main(int argc, char * * argv) +{ + int r; + (void)argc; (void)argv; + + r = testxmlparser(xmldata, sizeof(xmldata)-1); + if(r) + printf("minixml validation test failed\n"); + return r; +} + diff --git a/contrib/miniupnpc/msvc/miniupnpc.sln b/contrib/miniupnpc/msvc/miniupnpc.sln new file mode 100644 index 00000000..b3da1919 --- /dev/null +++ b/contrib/miniupnpc/msvc/miniupnpc.sln @@ -0,0 +1,29 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual C++ Express 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniupnpc", "miniupnpc.vcproj", "{D28CE435-CB33-4BAE-8A52-C6EF915956F5}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "upnpc-static", "upnpc-static.vcproj", "{469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}" + ProjectSection(ProjectDependencies) = postProject + {D28CE435-CB33-4BAE-8A52-C6EF915956F5} = {D28CE435-CB33-4BAE-8A52-C6EF915956F5} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Debug|Win32.ActiveCfg = Debug|Win32 + {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Debug|Win32.Build.0 = Debug|Win32 + {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Release|Win32.ActiveCfg = Release|Win32 + {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Release|Win32.Build.0 = Release|Win32 + {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Debug|Win32.ActiveCfg = Debug|Win32 + {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Debug|Win32.Build.0 = Debug|Win32 + {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Release|Win32.ActiveCfg = Release|Win32 + {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/contrib/miniupnpc/msvc/miniupnpc.vcproj b/contrib/miniupnpc/msvc/miniupnpc.vcproj new file mode 100644 index 00000000..12a55aaf --- /dev/null +++ b/contrib/miniupnpc/msvc/miniupnpc.vcproj @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/contrib/miniupnpc/msvc/upnpc-static.vcproj b/contrib/miniupnpc/msvc/upnpc-static.vcproj new file mode 100644 index 00000000..29461387 --- /dev/null +++ b/contrib/miniupnpc/msvc/upnpc-static.vcproj @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/contrib/miniupnpc/portlistingparse.c b/contrib/miniupnpc/portlistingparse.c new file mode 100644 index 00000000..19e3054e --- /dev/null +++ b/contrib/miniupnpc/portlistingparse.c @@ -0,0 +1,159 @@ +/* $Id: portlistingparse.c,v 1.6 2012/05/29 10:26:51 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2011 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ +#include +#include +#include "portlistingparse.h" +#include "minixml.h" + +/* list of the elements */ +static const struct { + const portMappingElt code; + const char * const str; +} elements[] = { + { PortMappingEntry, "PortMappingEntry"}, + { NewRemoteHost, "NewRemoteHost"}, + { NewExternalPort, "NewExternalPort"}, + { NewProtocol, "NewProtocol"}, + { NewInternalPort, "NewInternalPort"}, + { NewInternalClient, "NewInternalClient"}, + { NewEnabled, "NewEnabled"}, + { NewDescription, "NewDescription"}, + { NewLeaseTime, "NewLeaseTime"}, + { PortMappingEltNone, NULL} +}; + +/* Helper function */ +static UNSIGNED_INTEGER +atoui(const char * p, int l) +{ + UNSIGNED_INTEGER r = 0; + while(l > 0 && *p) + { + if(*p >= '0' && *p <= '9') + r = r*10 + (*p - '0'); + else + break; + p++; + l--; + } + return r; +} + +/* Start element handler */ +static void +startelt(void * d, const char * name, int l) +{ + int i; + struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; + pdata->curelt = PortMappingEltNone; + for(i = 0; elements[i].str; i++) + { + if(memcmp(name, elements[i].str, l) == 0) + { + pdata->curelt = elements[i].code; + break; + } + } + if(pdata->curelt == PortMappingEntry) + { + struct PortMapping * pm; + pm = calloc(1, sizeof(struct PortMapping)); + LIST_INSERT_HEAD( &(pdata->head), pm, entries); + } +} + +/* End element handler */ +static void +endelt(void * d, const char * name, int l) +{ + struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; + (void)name; + (void)l; + pdata->curelt = PortMappingEltNone; +} + +/* Data handler */ +static void +data(void * d, const char * data, int l) +{ + struct PortMapping * pm; + struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; + pm = pdata->head.lh_first; + if(!pm) + return; + if(l > 63) + l = 63; + switch(pdata->curelt) + { + case NewRemoteHost: + memcpy(pm->remoteHost, data, l); + pm->remoteHost[l] = '\0'; + break; + case NewExternalPort: + pm->externalPort = (unsigned short)atoui(data, l); + break; + case NewProtocol: + if(l > 3) + l = 3; + memcpy(pm->protocol, data, l); + pm->protocol[l] = '\0'; + break; + case NewInternalPort: + pm->internalPort = (unsigned short)atoui(data, l); + break; + case NewInternalClient: + memcpy(pm->internalClient, data, l); + pm->internalClient[l] = '\0'; + break; + case NewEnabled: + pm->enabled = (unsigned char)atoui(data, l); + break; + case NewDescription: + memcpy(pm->description, data, l); + pm->description[l] = '\0'; + break; + case NewLeaseTime: + pm->leaseTime = atoui(data, l); + break; + default: + break; + } +} + + +/* Parse the PortMappingList XML document for IGD version 2 + */ +void +ParsePortListing(const char * buffer, int bufsize, + struct PortMappingParserData * pdata) +{ + struct xmlparser parser; + + memset(pdata, 0, sizeof(struct PortMappingParserData)); + LIST_INIT(&(pdata->head)); + /* init xmlparser */ + parser.xmlstart = buffer; + parser.xmlsize = bufsize; + parser.data = pdata; + parser.starteltfunc = startelt; + parser.endeltfunc = endelt; + parser.datafunc = data; + parser.attfunc = 0; + parsexml(&parser); +} + +void +FreePortListing(struct PortMappingParserData * pdata) +{ + struct PortMapping * pm; + while((pm = pdata->head.lh_first) != NULL) + { + LIST_REMOVE(pm, entries); + free(pm); + } +} + diff --git a/contrib/miniupnpc/portlistingparse.h b/contrib/miniupnpc/portlistingparse.h new file mode 100644 index 00000000..bafa2a47 --- /dev/null +++ b/contrib/miniupnpc/portlistingparse.h @@ -0,0 +1,71 @@ +/* $Id: portlistingparse.h,v 1.7 2012/09/27 15:42:10 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2011-2012 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ +#ifndef PORTLISTINGPARSE_H_INCLUDED +#define PORTLISTINGPARSE_H_INCLUDED + +#include "declspec.h" +/* for the definition of UNSIGNED_INTEGER */ +#include "miniupnpctypes.h" + +#if defined(NO_SYS_QUEUE_H) || defined(_WIN32) || defined(__HAIKU__) +#include "bsdqueue.h" +#else +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* sample of PortMappingEntry : + + 202.233.2.1 + 2345 + TCP + 2345 + 192.168.1.137 + 1 + dooom + 345 + + */ +typedef enum { PortMappingEltNone, + PortMappingEntry, NewRemoteHost, + NewExternalPort, NewProtocol, + NewInternalPort, NewInternalClient, + NewEnabled, NewDescription, + NewLeaseTime } portMappingElt; + +struct PortMapping { + LIST_ENTRY(PortMapping) entries; + UNSIGNED_INTEGER leaseTime; + unsigned short externalPort; + unsigned short internalPort; + char remoteHost[64]; + char internalClient[64]; + char description[64]; + char protocol[4]; + unsigned char enabled; +}; + +struct PortMappingParserData { + LIST_HEAD(portmappinglisthead, PortMapping) head; + portMappingElt curelt; +}; + +LIBSPEC void +ParsePortListing(const char * buffer, int bufsize, + struct PortMappingParserData * pdata); + +LIBSPEC void +FreePortListing(struct PortMappingParserData * pdata); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/miniupnpc/pymoduletest.py b/contrib/miniupnpc/pymoduletest.py new file mode 100644 index 00000000..d35a3b09 --- /dev/null +++ b/contrib/miniupnpc/pymoduletest.py @@ -0,0 +1,52 @@ +#! /usr/bin/python +# MiniUPnP project +# Author : Thomas Bernard +# This Sample code is public domain. +# website : http://miniupnp.tuxfamily.org/ + +# import the python miniupnpc module +import miniupnpc +import sys + +# create the object +u = miniupnpc.UPnP() +print 'inital(default) values :' +print ' discoverdelay', u.discoverdelay +print ' lanaddr', u.lanaddr +print ' multicastif', u.multicastif +print ' minissdpdsocket', u.minissdpdsocket +u.discoverdelay = 200; +#u.minissdpdsocket = '../minissdpd/minissdpd.sock' +# discovery process, it usualy takes several seconds (2 seconds or more) +print 'Discovering... delay=%ums' % u.discoverdelay +print u.discover(), 'device(s) detected' +# select an igd +try: + u.selectigd() +except Exception, e: + print 'Exception :', e + sys.exit(1) +# display information about the IGD and the internet connection +print 'local ip address :', u.lanaddr +print 'external ip address :', u.externalipaddress() +print u.statusinfo(), u.connectiontype() + +#print u.addportmapping(64000, 'TCP', +# '192.168.1.166', 63000, 'port mapping test', '') +#print u.deleteportmapping(64000, 'TCP') + +port = 0 +proto = 'UDP' +# list the redirections : +i = 0 +while True: + p = u.getgenericportmapping(i) + if p==None: + break + print i, p + (port, proto, (ihost,iport), desc, c, d, e) = p + #print port, desc + i = i + 1 + +print u.getspecificportmapping(port, proto) + diff --git a/contrib/miniupnpc/receivedata.c b/contrib/miniupnpc/receivedata.c new file mode 100644 index 00000000..ffbfbead --- /dev/null +++ b/contrib/miniupnpc/receivedata.c @@ -0,0 +1,109 @@ +/* $Id: receivedata.c,v 1.5 2013/10/07 09:48:36 nanard Exp $ */ +/* Project : miniupnp + * Website : http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2011-2012 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. */ + +#include +#ifdef _WIN32 +#include +#include +#else +#include +#if defined(__amigaos__) && !defined(__amigaos4__) +#define socklen_t int +#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */ +#include +#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */ +#include +#include +#if !defined(__amigaos__) && !defined(__amigaos4__) +#include +#endif +#include +#define MINIUPNPC_IGNORE_EINTR +#endif + +#ifdef _WIN32 +#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); +#else +#define PRINT_SOCKET_ERROR(x) perror(x) +#endif + +#include "receivedata.h" + +int +receivedata(int socket, + char * data, int length, + int timeout, unsigned int * scope_id) +{ +#if MINIUPNPC_GET_SRC_ADDR +#ifdef DEBUG + /* to shut up valgrind about uninit value */ + struct sockaddr_storage src_addr = {0}; +#else + struct sockaddr_storage src_addr; +#endif + socklen_t src_addr_len = sizeof(src_addr); +#endif + int n; +#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) + /* using poll */ + struct pollfd fds[1]; /* for the poll */ +#ifdef MINIUPNPC_IGNORE_EINTR + do { +#endif + fds[0].fd = socket; + fds[0].events = POLLIN; + n = poll(fds, 1, timeout); +#ifdef MINIUPNPC_IGNORE_EINTR + } while(n < 0 && errno == EINTR); +#endif + if(n < 0) { + PRINT_SOCKET_ERROR("poll"); + return -1; + } else if(n == 0) { + /* timeout */ + return 0; + } +#else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ + /* using select under _WIN32 and amigaos */ + fd_set socketSet; + TIMEVAL timeval; + FD_ZERO(&socketSet); + FD_SET(socket, &socketSet); + timeval.tv_sec = timeout / 1000; + timeval.tv_usec = (timeout % 1000) * 1000; + n = select(FD_SETSIZE, &socketSet, NULL, NULL, &timeval); + if(n < 0) { + PRINT_SOCKET_ERROR("select"); + return -1; + } else if(n == 0) { + return 0; + } +#endif +#if MINIUPNPC_GET_SRC_ADDR + n = recvfrom(socket, data, length, 0, + (struct sockaddr *)&src_addr, &src_addr_len); +#else + n = recv(socket, data, length, 0); +#endif + if(n<0) { + PRINT_SOCKET_ERROR("recv"); + } +#if MINIUPNPC_GET_SRC_ADDR + if (src_addr.ss_family == AF_INET6) { + const struct sockaddr_in6 * src_addr6 = (struct sockaddr_in6 *)&src_addr; +#ifdef DEBUG + printf("scope_id=%u\n", src_addr6->sin6_scope_id); +#endif + if(scope_id) + *scope_id = src_addr6->sin6_scope_id; + } +#endif + return n; +} + + diff --git a/contrib/miniupnpc/receivedata.h b/contrib/miniupnpc/receivedata.h new file mode 100644 index 00000000..0520a11d --- /dev/null +++ b/contrib/miniupnpc/receivedata.h @@ -0,0 +1,19 @@ +/* $Id: receivedata.h,v 1.4 2012/09/27 15:42:10 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * Author: Thomas Bernard + * Copyright (c) 2011-2012 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef RECEIVEDATA_H_INCLUDED +#define RECEIVEDATA_H_INCLUDED + +/* Reads data from the specified socket. + * Returns the number of bytes read if successful, zero if no bytes were + * read or if we timed out. Returns negative if there was an error. */ +int receivedata(int socket, + char * data, int length, + int timeout, unsigned int * scope_id); + +#endif + diff --git a/contrib/miniupnpc/setup.py b/contrib/miniupnpc/setup.py new file mode 100644 index 00000000..63a275cb --- /dev/null +++ b/contrib/miniupnpc/setup.py @@ -0,0 +1,18 @@ +#! /usr/bin/python +# $Id: setup.py,v 1.9 2012/05/23 08:50:10 nanard Exp $ +# the MiniUPnP Project (c) 2007-2012 Thomas Bernard +# http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/ +# +# python script to build the miniupnpc module under unix +# +# replace libminiupnpc.a by libminiupnpc.so for shared library usage +from distutils.core import setup, Extension +from distutils import sysconfig +sysconfig.get_config_vars()["OPT"] = '' +sysconfig.get_config_vars()["CFLAGS"] = '' +setup(name="miniupnpc", version="1.7", + ext_modules=[ + Extension(name="miniupnpc", sources=["miniupnpcmodule.c"], + extra_objects=["libminiupnpc.a"]) + ]) + diff --git a/contrib/miniupnpc/setupmingw32.py b/contrib/miniupnpc/setupmingw32.py new file mode 100644 index 00000000..cb23d1d3 --- /dev/null +++ b/contrib/miniupnpc/setupmingw32.py @@ -0,0 +1,18 @@ +#! /usr/bin/python +# $Id: setupmingw32.py,v 1.8 2012/05/23 08:50:10 nanard Exp $ +# the MiniUPnP Project (c) 2007-2012 Thomas Bernard +# http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/ +# +# python script to build the miniupnpc module under windows (using mingw32) +# +from distutils.core import setup, Extension +from distutils import sysconfig +sysconfig.get_config_vars()["OPT"] = '' +sysconfig.get_config_vars()["CFLAGS"] = '' +setup(name="miniupnpc", version="1.7", + ext_modules=[ + Extension(name="miniupnpc", sources=["miniupnpcmodule.c"], + libraries=["ws2_32", "iphlpapi"], + extra_objects=["libminiupnpc.a"]) + ]) + diff --git a/contrib/miniupnpc/testigddescparse.c b/contrib/miniupnpc/testigddescparse.c new file mode 100644 index 00000000..1c0028a0 --- /dev/null +++ b/contrib/miniupnpc/testigddescparse.c @@ -0,0 +1,64 @@ +/* $Id: testigddescparse.c,v 1.4 2012/06/28 18:52:12 nanard Exp $ */ +/* Project : miniupnp + * http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2008-2012 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * */ +#include +#include +#include +#include "igd_desc_parse.h" +#include "minixml.h" +#include "miniupnpc.h" + +int test_igd_desc_parse(char * buffer, int len) +{ + struct IGDdatas igd; + struct xmlparser parser; + struct UPNPUrls urls; + memset(&igd, 0, sizeof(struct IGDdatas)); + memset(&parser, 0, sizeof(struct xmlparser)); + parser.xmlstart = buffer; + parser.xmlsize = len; + parser.data = &igd; + parser.starteltfunc = IGDstartelt; + parser.endeltfunc = IGDendelt; + parser.datafunc = IGDdata; + parsexml(&parser); + printIGD(&igd); + GetUPNPUrls(&urls, &igd, "http://fake/desc/url/file.xml", 0); + printf("ipcondescURL='%s'\n", urls.ipcondescURL); + printf("controlURL='%s'\n", urls.controlURL); + printf("controlURL_CIF='%s'\n", urls.controlURL_CIF); + FreeUPNPUrls(&urls); + return 0; +} + +int main(int argc, char * * argv) +{ + FILE * f; + char * buffer; + int len; + int r = 0; + if(argc<2) { + fprintf(stderr, "Usage: %s file.xml\n", argv[0]); + return 1; + } + f = fopen(argv[1], "r"); + if(!f) { + fprintf(stderr, "Cannot open %s for reading.\n", argv[1]); + return 1; + } + fseek(f, 0, SEEK_END); + len = ftell(f); + fseek(f, 0, SEEK_SET); + buffer = malloc(len); + fread(buffer, 1, len, f); + fclose(f); + r = test_igd_desc_parse(buffer, len); + free(buffer); + return r; +} + diff --git a/contrib/miniupnpc/testminiwget.c b/contrib/miniupnpc/testminiwget.c new file mode 100644 index 00000000..8ae90320 --- /dev/null +++ b/contrib/miniupnpc/testminiwget.c @@ -0,0 +1,53 @@ +/* $Id: testminiwget.c,v 1.4 2012/06/23 22:35:59 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2005-2012 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * */ +#include +#include +#include "miniwget.h" + +/** + * This program uses the miniwget / miniwget_getaddr function + * from miniwget.c in order to retreive a web ressource using + * a GET HTTP method, and store it in a file. + */ +int main(int argc, char * * argv) +{ + void * data; + int size, writtensize; + FILE *f; + char addr[64]; + + if(argc < 3) { + fprintf(stderr, "Usage:\t%s url file\n", argv[0]); + fprintf(stderr, "Example:\t%s http://www.google.com/ out.html\n", argv[0]); + return 1; + } + data = miniwget_getaddr(argv[1], &size, addr, sizeof(addr), 0); + if(!data) { + fprintf(stderr, "Error fetching %s\n", argv[1]); + return 1; + } + printf("local address : %s\n", addr); + printf("got %d bytes\n", size); + f = fopen(argv[2], "wb"); + if(!f) { + fprintf(stderr, "Cannot open file %s for writing\n", argv[2]); + free(data); + return 1; + } + writtensize = fwrite(data, 1, size, f); + if(writtensize != size) { + fprintf(stderr, "Could only write %d bytes out of %d to %s\n", + writtensize, size, argv[2]); + } else { + printf("%d bytes written to %s\n", writtensize, argv[2]); + } + fclose(f); + free(data); + return 0; +} + diff --git a/contrib/miniupnpc/testminiwget.sh b/contrib/miniupnpc/testminiwget.sh new file mode 100644 index 00000000..80e153b1 --- /dev/null +++ b/contrib/miniupnpc/testminiwget.sh @@ -0,0 +1,96 @@ +#!/bin/sh +# $Id: testminiwget.sh,v 1.10 2013/11/13 15:08:08 nanard Exp $ +# project miniupnp : http://miniupnp.free.fr/ +# (c) 2011-2012 Thomas Bernard +# +# test program for miniwget.c +# is usually invoked by "make check" +# +# This test program : +# 1 - launches a local HTTP server (minihttptestserver) +# 2 - uses testminiwget to retreive data from this server +# 3 - compares served and received data +# 4 - kills the local HTTP server and exits +# +# The script was tested and works with ksh, bash +# it should now also run with dash + +TMPD=`mktemp -d miniwgetXXXXXXXXXX` +HTTPSERVEROUT="${TMPD}/httpserverout" +EXPECTEDFILE="${TMPD}/expectedfile" +DOWNLOADEDFILE="${TMPD}/downloadedfile" +PORT= +RET=0 + +case "$HAVE_IPV6" in + n|no|0) + ADDR=localhost + SERVERARGS="" + ;; + *) + ADDR="[::1]" + SERVERARGS="-6" + ;; + +esac + +#make minihttptestserver +#make testminiwget + +# launching the test HTTP server +./minihttptestserver $SERVERARGS -e $EXPECTEDFILE > $HTTPSERVEROUT & +SERVERPID=$! +while [ -z "$PORT" ]; do + sleep 1 + PORT=`cat $HTTPSERVEROUT | sed 's/Listening on port \([0-9]*\)/\1/' ` +done +echo "Test HTTP server is listening on $PORT" + +URL1="http://$ADDR:$PORT/index.html" +URL2="http://$ADDR:$PORT/chunked" +URL3="http://$ADDR:$PORT/addcrap" + +echo "standard test ..." +./testminiwget $URL1 "${DOWNLOADEDFILE}.1" +if cmp $EXPECTEDFILE "${DOWNLOADEDFILE}.1" ; then + echo "ok" +else + echo "standard test FAILED" + RET=1 +fi + +echo "chunked transfert encoding test ..." +./testminiwget $URL2 "${DOWNLOADEDFILE}.2" +if cmp $EXPECTEDFILE "${DOWNLOADEDFILE}.2" ; then + echo "ok" +else + echo "chunked transfert encoding test FAILED" + RET=1 +fi + +echo "response too long test ..." +./testminiwget $URL3 "${DOWNLOADEDFILE}.3" +if cmp $EXPECTEDFILE "${DOWNLOADEDFILE}.3" ; then + echo "ok" +else + echo "response too long test FAILED" + RET=1 +fi + +# kill the test HTTP server +kill $SERVERPID +wait $SERVERPID + +# remove temporary files (for success cases) +if [ $RET -eq 0 ]; then + rm -f "${DOWNLOADEDFILE}.1" + rm -f "${DOWNLOADEDFILE}.2" + rm -f "${DOWNLOADEDFILE}.3" + rm -f $EXPECTEDFILE $HTTPSERVEROUT + rmdir ${TMPD} +else + echo "at least one of the test FAILED" + echo "directory ${TMPD} is left intact" +fi +exit $RET + diff --git a/contrib/miniupnpc/testminixml.c b/contrib/miniupnpc/testminixml.c new file mode 100644 index 00000000..d0fe794a --- /dev/null +++ b/contrib/miniupnpc/testminixml.c @@ -0,0 +1,87 @@ +/* $Id: testminixml.c,v 1.9 2013/05/14 19:50:49 nanard Exp $ + * MiniUPnP project + * Website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * Author : Thomas Bernard. + * Copyright (c) 2005-2013 Thomas Bernard + * + * testminixml.c + * test program for the "minixml" functions. + */ +#include +#include +#include +#include "minixml.h" +#include "igd_desc_parse.h" + +/* ---------------------------------------------------------------------- */ +void printeltname1(void * d, const char * name, int l) +{ + int i; + (void)d; + printf("element "); + for(i=0;i +123 +TCP + + + diff --git a/contrib/miniupnpc/testreplyparse/GetExternalIPAddress.namevalue b/contrib/miniupnpc/testreplyparse/GetExternalIPAddress.namevalue new file mode 100644 index 00000000..5aa75f88 --- /dev/null +++ b/contrib/miniupnpc/testreplyparse/GetExternalIPAddress.namevalue @@ -0,0 +1,2 @@ +NewExternalIPAddress=1.2.3.4 + diff --git a/contrib/miniupnpc/testreplyparse/GetExternalIPAddress.xml b/contrib/miniupnpc/testreplyparse/GetExternalIPAddress.xml new file mode 100644 index 00000000..db7ec1f9 --- /dev/null +++ b/contrib/miniupnpc/testreplyparse/GetExternalIPAddress.xml @@ -0,0 +1,2 @@ +1.2.3.4 + diff --git a/contrib/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.namevalue b/contrib/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.namevalue new file mode 100644 index 00000000..26b169c3 --- /dev/null +++ b/contrib/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.namevalue @@ -0,0 +1,3 @@ +NewProtocol=UDP +NewExternalPort=12345 +NewRemoteHost= diff --git a/contrib/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.xml b/contrib/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.xml new file mode 100644 index 00000000..bbb540ea --- /dev/null +++ b/contrib/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.xml @@ -0,0 +1,3 @@ + +12345UDP + diff --git a/contrib/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.namevalue b/contrib/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.namevalue new file mode 100644 index 00000000..2189789b --- /dev/null +++ b/contrib/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.namevalue @@ -0,0 +1,5 @@ +NewInternalPort=12345 +NewInternalClient=192.168.10.110 +NewEnabled=1 +NewPortMappingDescription=libminiupnpc +NewLeaseDuration=0 diff --git a/contrib/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.xml b/contrib/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.xml new file mode 100644 index 00000000..77e8d9c7 --- /dev/null +++ b/contrib/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.xml @@ -0,0 +1,2 @@ +12345192.168.10.1101libminiupnpc0 + diff --git a/contrib/miniupnpc/testreplyparse/SetDefaultConnectionService.namevalue b/contrib/miniupnpc/testreplyparse/SetDefaultConnectionService.namevalue new file mode 100644 index 00000000..f78c7e2a --- /dev/null +++ b/contrib/miniupnpc/testreplyparse/SetDefaultConnectionService.namevalue @@ -0,0 +1 @@ +NewDefaultConnectionService=uuid:c6c05a33-f704-48df-9910-e099b3471d81:WANConnectionDevice:1,INVALID_SERVICE_ID diff --git a/contrib/miniupnpc/testreplyparse/SetDefaultConnectionService.xml b/contrib/miniupnpc/testreplyparse/SetDefaultConnectionService.xml new file mode 100644 index 00000000..ac04c07a --- /dev/null +++ b/contrib/miniupnpc/testreplyparse/SetDefaultConnectionService.xml @@ -0,0 +1 @@ +uuid:c6c05a33-f704-48df-9910-e099b3471d81:WANConnectionDevice:1,INVALID_SERVICE_ID diff --git a/contrib/miniupnpc/testreplyparse/readme.txt b/contrib/miniupnpc/testreplyparse/readme.txt new file mode 100644 index 00000000..3eb1f015 --- /dev/null +++ b/contrib/miniupnpc/testreplyparse/readme.txt @@ -0,0 +1,7 @@ +This directory contains files used for validation of upnpreplyparse.c code. + +Each .xml file to parse should give the results which are in the .namevalue +file. + +A .namevalue file contain name=value lines. + diff --git a/contrib/miniupnpc/testupnpigd.py b/contrib/miniupnpc/testupnpigd.py new file mode 100644 index 00000000..6d167a4c --- /dev/null +++ b/contrib/miniupnpc/testupnpigd.py @@ -0,0 +1,84 @@ +#! /usr/bin/python +# $Id: testupnpigd.py,v 1.4 2008/10/11 10:27:20 nanard Exp $ +# MiniUPnP project +# Author : Thomas Bernard +# This Sample code is public domain. +# website : http://miniupnp.tuxfamily.org/ + +# import the python miniupnpc module +import miniupnpc +import socket +import BaseHTTPServer + +# function definition +def list_redirections(): + i = 0 + while True: + p = u.getgenericportmapping(i) + if p==None: + break + print i, p + i = i + 1 + +#define the handler class for HTTP connections +class handler_class(BaseHTTPServer.BaseHTTPRequestHandler): + def do_GET(self): + self.send_response(200) + self.end_headers() + self.wfile.write("OK MON GARS") + +# create the object +u = miniupnpc.UPnP() +#print 'inital(default) values :' +#print ' discoverdelay', u.discoverdelay +#print ' lanaddr', u.lanaddr +#print ' multicastif', u.multicastif +#print ' minissdpdsocket', u.minissdpdsocket +u.discoverdelay = 200; + +try: + print 'Discovering... delay=%ums' % u.discoverdelay + ndevices = u.discover() + print ndevices, 'device(s) detected' + + # select an igd + u.selectigd() + # display information about the IGD and the internet connection + print 'local ip address :', u.lanaddr + externalipaddress = u.externalipaddress() + print 'external ip address :', externalipaddress + print u.statusinfo(), u.connectiontype() + + #instanciate a HTTPd object. The port is assigned by the system. + httpd = BaseHTTPServer.HTTPServer((u.lanaddr, 0), handler_class) + eport = httpd.server_port + + # find a free port for the redirection + r = u.getspecificportmapping(eport, 'TCP') + while r != None and eport < 65536: + eport = eport + 1 + r = u.getspecificportmapping(eport, 'TCP') + + print 'trying to redirect %s port %u TCP => %s port %u TCP' % (externalipaddress, eport, u.lanaddr, httpd.server_port) + + b = u.addportmapping(eport, 'TCP', u.lanaddr, httpd.server_port, + 'UPnP IGD Tester port %u' % eport, '') + if b: + print 'Success. Now waiting for some HTTP request on http://%s:%u' % (externalipaddress ,eport) + try: + httpd.handle_request() + httpd.server_close() + except KeyboardInterrupt, details: + print "CTRL-C exception!", details + b = u.deleteportmapping(eport, 'TCP') + if b: + print 'Successfully deleted port mapping' + else: + print 'Failed to remove port mapping' + else: + print 'Failed' + + httpd.server_close() + +except Exception, e: + print 'Exception :', e diff --git a/contrib/miniupnpc/testupnpreplyparse.c b/contrib/miniupnpc/testupnpreplyparse.c new file mode 100644 index 00000000..7ba7131e --- /dev/null +++ b/contrib/miniupnpc/testupnpreplyparse.c @@ -0,0 +1,96 @@ +/* $Id: testupnpreplyparse.c,v 1.4 2014/01/27 11:45:19 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2006-2014 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ +#include +#include +#include +#include "upnpreplyparse.h" + +int +test_parsing(const char * buf, int len, FILE * f) +{ + char line[1024]; + struct NameValueParserData pdata; + int ok = 1; + ParseNameValue(buf, len, &pdata); + /* check result */ + if(f != NULL) + { + while(fgets(line, sizeof(line), f)) + { + char * value; + char * equal; + char * parsedvalue; + int l; + l = strlen(line); + while((l > 0) && ((line[l-1] == '\r') || (line[l-1] == '\n'))) + line[--l] = '\0'; + /* skip empty lines */ + if(l == 0) + continue; + equal = strchr(line, '='); + if(equal == NULL) + { + fprintf(stderr, "Warning, line does not contain '=' : %s\n", line); + continue; + } + *equal = '\0'; + value = equal + 1; + parsedvalue = GetValueFromNameValueList(&pdata, line); + if((parsedvalue == NULL) || (strcmp(parsedvalue, value) != 0)) + { + fprintf(stderr, "Element <%s> : expecting value '%s', got '%s'\n", + line, value, parsedvalue ? parsedvalue : ""); + ok = 0; + } + } + } + ClearNameValueList(&pdata); + return ok; +} + +int main(int argc, char * * argv) +{ + FILE * f; + char buffer[4096]; + int l; + int ok; + + if(argc<2) + { + fprintf(stderr, "Usage: %s file.xml [file.namevalues]\n", argv[0]); + return 1; + } + f = fopen(argv[1], "r"); + if(!f) + { + fprintf(stderr, "Error : can not open file %s\n", argv[1]); + return 2; + } + l = fread(buffer, 1, sizeof(buffer)-1, f); + fclose(f); + f = NULL; + buffer[l] = '\0'; + if(argc > 2) + { + f = fopen(argv[2], "r"); + if(!f) + { + fprintf(stderr, "Error : can not open file %s\n", argv[2]); + return 2; + } + } +#ifdef DEBUG + DisplayNameValueList(buffer, l); +#endif + ok = test_parsing(buffer, l, f); + if(f) + { + fclose(f); + } + return ok ? 0 : 3; +} + diff --git a/contrib/miniupnpc/testupnpreplyparse.sh b/contrib/miniupnpc/testupnpreplyparse.sh new file mode 100644 index 00000000..992930b7 --- /dev/null +++ b/contrib/miniupnpc/testupnpreplyparse.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +for f in testreplyparse/*.xml ; do + bf="`dirname $f`/`basename $f .xml`" + if ./testupnpreplyparse $f $bf.namevalue ; then + echo "$f : passed" + else + echo "$f : FAILED" + exit 1 + fi +done + +exit 0 + diff --git a/contrib/miniupnpc/updateminiupnpcstrings.sh b/contrib/miniupnpc/updateminiupnpcstrings.sh new file mode 100644 index 00000000..dde4354a --- /dev/null +++ b/contrib/miniupnpc/updateminiupnpcstrings.sh @@ -0,0 +1,53 @@ +#! /bin/sh +# $Id: updateminiupnpcstrings.sh,v 1.7 2011/01/04 11:41:53 nanard Exp $ +# project miniupnp : http://miniupnp.free.fr/ +# (c) 2009 Thomas Bernard + +FILE=miniupnpcstrings.h +TMPFILE=miniupnpcstrings.h.tmp +TEMPLATE_FILE=${FILE}.in + +# detecting the OS name and version +OS_NAME=`uname -s` +OS_VERSION=`uname -r` +if [ -f /etc/debian_version ]; then + OS_NAME=Debian + OS_VERSION=`cat /etc/debian_version` +fi +# use lsb_release (Linux Standard Base) when available +LSB_RELEASE=`which lsb_release` +if [ 0 -eq $? -a -x "${LSB_RELEASE}" ]; then + OS_NAME=`${LSB_RELEASE} -i -s` + OS_VERSION=`${LSB_RELEASE} -r -s` + case $OS_NAME in + Debian) + #OS_VERSION=`${LSB_RELEASE} -c -s` + ;; + Ubuntu) + #OS_VERSION=`${LSB_RELEASE} -c -s` + ;; + esac +fi + +# on AmigaOS 3, uname -r returns "unknown", so we use uname -v +if [ "$OS_NAME" = "AmigaOS" ]; then + if [ "$OS_VERSION" = "unknown" ]; then + OS_VERSION=`uname -v` + fi +fi + +echo "Detected OS [$OS_NAME] version [$OS_VERSION]" +MINIUPNPC_VERSION=`cat VERSION` +echo "MiniUPnPc version [${MINIUPNPC_VERSION}]" + +EXPR="s|OS_STRING \".*\"|OS_STRING \"${OS_NAME}/${OS_VERSION}\"|" +#echo $EXPR +test -f ${FILE}.in +echo "setting OS_STRING macro value to ${OS_NAME}/${OS_VERSION} in $FILE." +sed -e "$EXPR" < $TEMPLATE_FILE > $TMPFILE + +EXPR="s|MINIUPNPC_VERSION_STRING \".*\"|MINIUPNPC_VERSION_STRING \"${MINIUPNPC_VERSION}\"|" +echo "setting MINIUPNPC_VERSION_STRING macro value to ${MINIUPNPC_VERSION} in $FILE." +sed -e "$EXPR" < $TMPFILE > $FILE +rm $TMPFILE + diff --git a/contrib/miniupnpc/upnpc.c b/contrib/miniupnpc/upnpc.c new file mode 100644 index 00000000..70c9a547 --- /dev/null +++ b/contrib/miniupnpc/upnpc.c @@ -0,0 +1,720 @@ +/* $Id: upnpc.c,v 1.102 2014/02/05 17:27:14 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2005-2014 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. */ + +#include +#include +#include +#include +#ifdef _WIN32 +#include +#define snprintf _snprintf +#else +/* for IPPROTO_TCP / IPPROTO_UDP */ +#include +#endif +#include "miniwget.h" +#include "miniupnpc.h" +#include "upnpcommands.h" +#include "upnperrors.h" + +/* protofix() checks if protocol is "UDP" or "TCP" + * returns NULL if not */ +const char * protofix(const char * proto) +{ + static const char proto_tcp[4] = { 'T', 'C', 'P', 0}; + static const char proto_udp[4] = { 'U', 'D', 'P', 0}; + int i, b; + for(i=0, b=1; i<4; i++) + b = b && ( (proto[i] == proto_tcp[i]) + || (proto[i] == (proto_tcp[i] | 32)) ); + if(b) + return proto_tcp; + for(i=0, b=1; i<4; i++) + b = b && ( (proto[i] == proto_udp[i]) + || (proto[i] == (proto_udp[i] | 32)) ); + if(b) + return proto_udp; + return 0; +} + +static void DisplayInfos(struct UPNPUrls * urls, + struct IGDdatas * data) +{ + char externalIPAddress[40]; + char connectionType[64]; + char status[64]; + char lastconnerr[64]; + unsigned int uptime; + unsigned int brUp, brDown; + time_t timenow, timestarted; + int r; + if(UPNP_GetConnectionTypeInfo(urls->controlURL, + data->first.servicetype, + connectionType) != UPNPCOMMAND_SUCCESS) + printf("GetConnectionTypeInfo failed.\n"); + else + printf("Connection Type : %s\n", connectionType); + if(UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype, + status, &uptime, lastconnerr) != UPNPCOMMAND_SUCCESS) + printf("GetStatusInfo failed.\n"); + else + printf("Status : %s, uptime=%us, LastConnectionError : %s\n", + status, uptime, lastconnerr); + timenow = time(NULL); + timestarted = timenow - uptime; + printf(" Time started : %s", ctime(×tarted)); + if(UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->CIF.servicetype, + &brDown, &brUp) != UPNPCOMMAND_SUCCESS) { + printf("GetLinkLayerMaxBitRates failed.\n"); + } else { + printf("MaxBitRateDown : %u bps", brDown); + if(brDown >= 1000000) { + printf(" (%u.%u Mbps)", brDown / 1000000, (brDown / 100000) % 10); + } else if(brDown >= 1000) { + printf(" (%u Kbps)", brDown / 1000); + } + printf(" MaxBitRateUp %u bps", brUp); + if(brUp >= 1000000) { + printf(" (%u.%u Mbps)", brUp / 1000000, (brUp / 100000) % 10); + } else if(brUp >= 1000) { + printf(" (%u Kbps)", brUp / 1000); + } + printf("\n"); + } + r = UPNP_GetExternalIPAddress(urls->controlURL, + data->first.servicetype, + externalIPAddress); + if(r != UPNPCOMMAND_SUCCESS) { + printf("GetExternalIPAddress failed. (errorcode=%d)\n", r); + } else { + printf("ExternalIPAddress = %s\n", externalIPAddress); + } +} + +static void GetConnectionStatus(struct UPNPUrls * urls, + struct IGDdatas * data) +{ + unsigned int bytessent, bytesreceived, packetsreceived, packetssent; + DisplayInfos(urls, data); + bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype); + bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype); + packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype); + packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype); + printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived); + printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived); +} + +static void ListRedirections(struct UPNPUrls * urls, + struct IGDdatas * data) +{ + int r; + int i = 0; + char index[6]; + char intClient[40]; + char intPort[6]; + char extPort[6]; + char protocol[4]; + char desc[80]; + char enabled[6]; + char rHost[64]; + char duration[16]; + /*unsigned int num=0; + UPNP_GetPortMappingNumberOfEntries(urls->controlURL, data->servicetype, &num); + printf("PortMappingNumberOfEntries : %u\n", num);*/ + printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n"); + do { + snprintf(index, 6, "%d", i); + rHost[0] = '\0'; enabled[0] = '\0'; + duration[0] = '\0'; desc[0] = '\0'; + extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0'; + r = UPNP_GetGenericPortMappingEntry(urls->controlURL, + data->first.servicetype, + index, + extPort, intClient, intPort, + protocol, desc, enabled, + rHost, duration); + if(r==0) + /* + printf("%02d - %s %s->%s:%s\tenabled=%s leaseDuration=%s\n" + " desc='%s' rHost='%s'\n", + i, protocol, extPort, intClient, intPort, + enabled, duration, + desc, rHost); + */ + printf("%2d %s %5s->%s:%-5s '%s' '%s' %s\n", + i, protocol, extPort, intClient, intPort, + desc, rHost, duration); + else + printf("GetGenericPortMappingEntry() returned %d (%s)\n", + r, strupnperror(r)); + i++; + } while(r==0); +} + +static void NewListRedirections(struct UPNPUrls * urls, + struct IGDdatas * data) +{ + int r; + int i = 0; + struct PortMappingParserData pdata; + struct PortMapping * pm; + + memset(&pdata, 0, sizeof(struct PortMappingParserData)); + r = UPNP_GetListOfPortMappings(urls->controlURL, + data->first.servicetype, + "0", + "65535", + "TCP", + "1000", + &pdata); + if(r == UPNPCOMMAND_SUCCESS) + { + printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n"); + for(pm = pdata.head.lh_first; pm != NULL; pm = pm->entries.le_next) + { + printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n", + i, pm->protocol, pm->externalPort, pm->internalClient, + pm->internalPort, + pm->description, pm->remoteHost, + (unsigned)pm->leaseTime); + i++; + } + FreePortListing(&pdata); + } + else + { + printf("GetListOfPortMappings() returned %d (%s)\n", + r, strupnperror(r)); + } + r = UPNP_GetListOfPortMappings(urls->controlURL, + data->first.servicetype, + "0", + "65535", + "UDP", + "1000", + &pdata); + if(r == UPNPCOMMAND_SUCCESS) + { + for(pm = pdata.head.lh_first; pm != NULL; pm = pm->entries.le_next) + { + printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n", + i, pm->protocol, pm->externalPort, pm->internalClient, + pm->internalPort, + pm->description, pm->remoteHost, + (unsigned)pm->leaseTime); + i++; + } + FreePortListing(&pdata); + } + else + { + printf("GetListOfPortMappings() returned %d (%s)\n", + r, strupnperror(r)); + } +} + +/* Test function + * 1 - get connection type + * 2 - get extenal ip address + * 3 - Add port mapping + * 4 - get this port mapping from the IGD */ +static void SetRedirectAndTest(struct UPNPUrls * urls, + struct IGDdatas * data, + const char * iaddr, + const char * iport, + const char * eport, + const char * proto, + const char * leaseDuration, + const char * description) +{ + char externalIPAddress[40]; + char intClient[40]; + char intPort[6]; + char duration[16]; + int r; + + if(!iaddr || !iport || !eport || !proto) + { + fprintf(stderr, "Wrong arguments\n"); + return; + } + proto = protofix(proto); + if(!proto) + { + fprintf(stderr, "invalid protocol\n"); + return; + } + + UPNP_GetExternalIPAddress(urls->controlURL, + data->first.servicetype, + externalIPAddress); + if(externalIPAddress[0]) + printf("ExternalIPAddress = %s\n", externalIPAddress); + else + printf("GetExternalIPAddress failed.\n"); + + r = UPNP_AddPortMapping(urls->controlURL, data->first.servicetype, + eport, iport, iaddr, description, + proto, 0, leaseDuration); + if(r!=UPNPCOMMAND_SUCCESS) + printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", + eport, iport, iaddr, r, strupnperror(r)); + + r = UPNP_GetSpecificPortMappingEntry(urls->controlURL, + data->first.servicetype, + eport, proto, NULL/*remoteHost*/, + intClient, intPort, NULL/*desc*/, + NULL/*enabled*/, duration); + if(r!=UPNPCOMMAND_SUCCESS) + printf("GetSpecificPortMappingEntry() failed with code %d (%s)\n", + r, strupnperror(r)); + + if(intClient[0]) { + printf("InternalIP:Port = %s:%s\n", intClient, intPort); + printf("external %s:%s %s is redirected to internal %s:%s (duration=%s)\n", + externalIPAddress, eport, proto, intClient, intPort, duration); + } +} + +static void +RemoveRedirect(struct UPNPUrls * urls, + struct IGDdatas * data, + const char * eport, + const char * proto) +{ + int r; + if(!proto || !eport) + { + fprintf(stderr, "invalid arguments\n"); + return; + } + proto = protofix(proto); + if(!proto) + { + fprintf(stderr, "protocol invalid\n"); + return; + } + r = UPNP_DeletePortMapping(urls->controlURL, data->first.servicetype, eport, proto, 0); + printf("UPNP_DeletePortMapping() returned : %d\n", r); +} + +/* IGD:2, functions for service WANIPv6FirewallControl:1 */ +static void GetFirewallStatus(struct UPNPUrls * urls, struct IGDdatas * data) +{ + unsigned int bytessent, bytesreceived, packetsreceived, packetssent; + int firewallEnabled = 0, inboundPinholeAllowed = 0; + + UPNP_GetFirewallStatus(urls->controlURL_6FC, data->IPv6FC.servicetype, &firewallEnabled, &inboundPinholeAllowed); + printf("FirewallEnabled: %d & Inbound Pinhole Allowed: %d\n", firewallEnabled, inboundPinholeAllowed); + printf("GetFirewallStatus:\n Firewall Enabled: %s\n Inbound Pinhole Allowed: %s\n", (firewallEnabled)? "Yes":"No", (inboundPinholeAllowed)? "Yes":"No"); + + bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype); + bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype); + packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype); + packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype); + printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived); + printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived); +} + +/* Test function + * 1 - Add pinhole + * 2 - Check if pinhole is working from the IGD side */ +static void SetPinholeAndTest(struct UPNPUrls * urls, struct IGDdatas * data, + const char * remoteaddr, const char * eport, + const char * intaddr, const char * iport, + const char * proto, const char * lease_time) +{ + char uniqueID[8]; + /*int isWorking = 0;*/ + int r; + char proto_tmp[8]; + + if(!intaddr || !remoteaddr || !iport || !eport || !proto || !lease_time) + { + fprintf(stderr, "Wrong arguments\n"); + return; + } + if(atoi(proto) == 0) + { + const char * protocol; + protocol = protofix(proto); + if(protocol && (strcmp("TCP", protocol) == 0)) + { + snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_TCP); + proto = proto_tmp; + } + else if(protocol && (strcmp("UDP", protocol) == 0)) + { + snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_UDP); + proto = proto_tmp; + } + else + { + fprintf(stderr, "invalid protocol\n"); + return; + } + } + r = UPNP_AddPinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, lease_time, uniqueID); + if(r!=UPNPCOMMAND_SUCCESS) + printf("AddPinhole([%s]:%s -> [%s]:%s) failed with code %d (%s)\n", + remoteaddr, eport, intaddr, iport, r, strupnperror(r)); + else + { + printf("AddPinhole: ([%s]:%s -> [%s]:%s) / Pinhole ID = %s\n", + remoteaddr, eport, intaddr, iport, uniqueID); + /*r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->servicetype_6FC, uniqueID, &isWorking); + if(r!=UPNPCOMMAND_SUCCESS) + printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r)); + printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");*/ + } +} + +/* Test function + * 1 - Check if pinhole is working from the IGD side + * 2 - Update pinhole */ +static void GetPinholeAndUpdate(struct UPNPUrls * urls, struct IGDdatas * data, + const char * uniqueID, const char * lease_time) +{ + int isWorking = 0; + int r; + + if(!uniqueID || !lease_time) + { + fprintf(stderr, "Wrong arguments\n"); + return; + } + r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking); + printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No"); + if(r!=UPNPCOMMAND_SUCCESS) + printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r)); + if(isWorking || r==709) + { + r = UPNP_UpdatePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, lease_time); + printf("UpdatePinhole: Pinhole ID = %s with Lease Time: %s\n", uniqueID, lease_time); + if(r!=UPNPCOMMAND_SUCCESS) + printf("UpdatePinhole: ID (%s) failed with code %d (%s)\n", uniqueID, r, strupnperror(r)); + } +} + +/* Test function + * Get pinhole timeout + */ +static void GetPinholeOutboundTimeout(struct UPNPUrls * urls, struct IGDdatas * data, + const char * remoteaddr, const char * eport, + const char * intaddr, const char * iport, + const char * proto) +{ + int timeout = 0; + int r; + + if(!intaddr || !remoteaddr || !iport || !eport || !proto) + { + fprintf(stderr, "Wrong arguments\n"); + return; + } + + r = UPNP_GetOutboundPinholeTimeout(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, &timeout); + if(r!=UPNPCOMMAND_SUCCESS) + printf("GetOutboundPinholeTimeout([%s]:%s -> [%s]:%s) failed with code %d (%s)\n", + intaddr, iport, remoteaddr, eport, r, strupnperror(r)); + else + printf("GetOutboundPinholeTimeout: ([%s]:%s -> [%s]:%s) / Timeout = %d\n", intaddr, iport, remoteaddr, eport, timeout); +} + +static void +GetPinholePackets(struct UPNPUrls * urls, + struct IGDdatas * data, const char * uniqueID) +{ + int r, pinholePackets = 0; + if(!uniqueID) + { + fprintf(stderr, "invalid arguments\n"); + return; + } + r = UPNP_GetPinholePackets(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &pinholePackets); + if(r!=UPNPCOMMAND_SUCCESS) + printf("GetPinholePackets() failed with code %d (%s)\n", r, strupnperror(r)); + else + printf("GetPinholePackets: Pinhole ID = %s / PinholePackets = %d\n", uniqueID, pinholePackets); +} + +static void +CheckPinhole(struct UPNPUrls * urls, + struct IGDdatas * data, const char * uniqueID) +{ + int r, isWorking = 0; + if(!uniqueID) + { + fprintf(stderr, "invalid arguments\n"); + return; + } + r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking); + if(r!=UPNPCOMMAND_SUCCESS) + printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r)); + else + printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No"); +} + +static void +RemovePinhole(struct UPNPUrls * urls, + struct IGDdatas * data, const char * uniqueID) +{ + int r; + if(!uniqueID) + { + fprintf(stderr, "invalid arguments\n"); + return; + } + r = UPNP_DeletePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID); + printf("UPNP_DeletePinhole() returned : %d\n", r); +} + + +/* sample upnp client program */ +int main(int argc, char ** argv) +{ + char command = 0; + char ** commandargv = 0; + int commandargc = 0; + struct UPNPDev * devlist = 0; + char lanaddr[64]; /* my ip address on the LAN */ + int i; + const char * rootdescurl = 0; + const char * multicastif = 0; + const char * minissdpdpath = 0; + int retcode = 0; + int error = 0; + int ipv6 = 0; + const char * description = 0; + +#ifdef _WIN32 + WSADATA wsaData; + int nResult = WSAStartup(MAKEWORD(2,2), &wsaData); + if(nResult != NO_ERROR) + { + fprintf(stderr, "WSAStartup() failed.\n"); + return -1; + } +#endif + printf("upnpc : miniupnpc library test client. (c) 2005-2014 Thomas Bernard\n"); + printf("Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/\n" + "for more information.\n"); + /* command line processing */ + for(i=1; ipNext) + { + printf(" desc: %s\n st: %s\n\n", + device->descURL, device->st); + } + } + else + { + printf("upnpDiscover() error code=%d\n", error); + } + i = 1; + if( (rootdescurl && UPNP_GetIGDFromUrl(rootdescurl, &urls, &data, lanaddr, sizeof(lanaddr))) + || (i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)))) + { + switch(i) { + case 1: + printf("Found valid IGD : %s\n", urls.controlURL); + break; + case 2: + printf("Found a (not connected?) IGD : %s\n", urls.controlURL); + printf("Trying to continue anyway\n"); + break; + case 3: + printf("UPnP device found. Is it an IGD ? : %s\n", urls.controlURL); + printf("Trying to continue anyway\n"); + break; + default: + printf("Found device (igd ?) : %s\n", urls.controlURL); + printf("Trying to continue anyway\n"); + } + printf("Local LAN ip address : %s\n", lanaddr); + #if 0 + printf("getting \"%s\"\n", urls.ipcondescURL); + descXML = miniwget(urls.ipcondescURL, &descXMLsize); + if(descXML) + { + /*fwrite(descXML, 1, descXMLsize, stdout);*/ + free(descXML); descXML = NULL; + } + #endif + + switch(command) + { + case 'l': + DisplayInfos(&urls, &data); + ListRedirections(&urls, &data); + break; + case 'L': + NewListRedirections(&urls, &data); + break; + case 'a': + SetRedirectAndTest(&urls, &data, + commandargv[0], commandargv[1], + commandargv[2], commandargv[3], + (commandargc > 4)?commandargv[4]:"0", + description); + break; + case 'd': + for(i=0; i +#include +#include +#include "upnpcommands.h" +#include "miniupnpc.h" +#include "portlistingparse.h" + +static UNSIGNED_INTEGER +my_atoui(const char * s) +{ + return s ? ((UNSIGNED_INTEGER)STRTOUI(s, NULL, 0)) : 0; +} + +/* + * */ +LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalBytesSent(const char * controlURL, + const char * servicetype) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + unsigned int r = 0; + char * p; + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetTotalBytesSent", 0, &bufsize))) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + /*DisplayNameValueList(buffer, bufsize);*/ + free(buffer); buffer = NULL; + p = GetValueFromNameValueList(&pdata, "NewTotalBytesSent"); + r = my_atoui(p); + ClearNameValueList(&pdata); + return r; +} + +/* + * */ +LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalBytesReceived(const char * controlURL, + const char * servicetype) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + unsigned int r = 0; + char * p; + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetTotalBytesReceived", 0, &bufsize))) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + /*DisplayNameValueList(buffer, bufsize);*/ + free(buffer); buffer = NULL; + p = GetValueFromNameValueList(&pdata, "NewTotalBytesReceived"); + r = my_atoui(p); + ClearNameValueList(&pdata); + return r; +} + +/* + * */ +LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalPacketsSent(const char * controlURL, + const char * servicetype) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + unsigned int r = 0; + char * p; + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetTotalPacketsSent", 0, &bufsize))) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + /*DisplayNameValueList(buffer, bufsize);*/ + free(buffer); buffer = NULL; + p = GetValueFromNameValueList(&pdata, "NewTotalPacketsSent"); + r = my_atoui(p); + ClearNameValueList(&pdata); + return r; +} + +/* + * */ +LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalPacketsReceived(const char * controlURL, + const char * servicetype) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + unsigned int r = 0; + char * p; + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetTotalPacketsReceived", 0, &bufsize))) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + /*DisplayNameValueList(buffer, bufsize);*/ + free(buffer); buffer = NULL; + p = GetValueFromNameValueList(&pdata, "NewTotalPacketsReceived"); + r = my_atoui(p); + ClearNameValueList(&pdata); + return r; +} + +/* UPNP_GetStatusInfo() call the corresponding UPNP method + * returns the current status and uptime */ +LIBSPEC int +UPNP_GetStatusInfo(const char * controlURL, + const char * servicetype, + char * status, + unsigned int * uptime, + char * lastconnerror) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + char * p; + char * up; + char * err; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + + if(!status && !uptime) + return UPNPCOMMAND_INVALID_ARGS; + + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetStatusInfo", 0, &bufsize))) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + /*DisplayNameValueList(buffer, bufsize);*/ + free(buffer); buffer = NULL; + up = GetValueFromNameValueList(&pdata, "NewUptime"); + p = GetValueFromNameValueList(&pdata, "NewConnectionStatus"); + err = GetValueFromNameValueList(&pdata, "NewLastConnectionError"); + if(p && up) + ret = UPNPCOMMAND_SUCCESS; + + if(status) { + if(p){ + strncpy(status, p, 64 ); + status[63] = '\0'; + }else + status[0]= '\0'; + } + + if(uptime) { + if(up) + sscanf(up,"%u",uptime); + else + uptime = 0; + } + + if(lastconnerror) { + if(err) { + strncpy(lastconnerror, err, 64 ); + lastconnerror[63] = '\0'; + } else + lastconnerror[0] = '\0'; + } + + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + ClearNameValueList(&pdata); + return ret; +} + +/* UPNP_GetConnectionTypeInfo() call the corresponding UPNP method + * returns the connection type */ +LIBSPEC int +UPNP_GetConnectionTypeInfo(const char * controlURL, + const char * servicetype, + char * connectionType) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + char * p; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + + if(!connectionType) + return UPNPCOMMAND_INVALID_ARGS; + + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetConnectionTypeInfo", 0, &bufsize))) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + p = GetValueFromNameValueList(&pdata, "NewConnectionType"); + /*p = GetValueFromNameValueList(&pdata, "NewPossibleConnectionTypes");*/ + /* PossibleConnectionTypes will have several values.... */ + if(p) { + strncpy(connectionType, p, 64 ); + connectionType[63] = '\0'; + ret = UPNPCOMMAND_SUCCESS; + } else + connectionType[0] = '\0'; + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + ClearNameValueList(&pdata); + return ret; +} + +/* UPNP_GetLinkLayerMaxBitRate() call the corresponding UPNP method. + * Returns 2 values: Downloadlink bandwidth and Uplink bandwidth. + * One of the values can be null + * Note : GetLinkLayerMaxBitRates belongs to WANPPPConnection:1 only + * We can use the GetCommonLinkProperties from WANCommonInterfaceConfig:1 */ +LIBSPEC int +UPNP_GetLinkLayerMaxBitRates(const char * controlURL, + const char * servicetype, + unsigned int * bitrateDown, + unsigned int * bitrateUp) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + char * down; + char * up; + char * p; + + if(!bitrateDown && !bitrateUp) + return UPNPCOMMAND_INVALID_ARGS; + + /* shouldn't we use GetCommonLinkProperties ? */ + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetCommonLinkProperties", 0, &bufsize))) { + /*"GetLinkLayerMaxBitRates", 0, &bufsize);*/ + return UPNPCOMMAND_HTTP_ERROR; + } + /*DisplayNameValueList(buffer, bufsize);*/ + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + /*down = GetValueFromNameValueList(&pdata, "NewDownstreamMaxBitRate");*/ + /*up = GetValueFromNameValueList(&pdata, "NewUpstreamMaxBitRate");*/ + down = GetValueFromNameValueList(&pdata, "NewLayer1DownstreamMaxBitRate"); + up = GetValueFromNameValueList(&pdata, "NewLayer1UpstreamMaxBitRate"); + /*GetValueFromNameValueList(&pdata, "NewWANAccessType");*/ + /*GetValueFromNameValueList(&pdata, "NewPhysicalLinkStatus");*/ + if(down && up) + ret = UPNPCOMMAND_SUCCESS; + + if(bitrateDown) { + if(down) + sscanf(down,"%u",bitrateDown); + else + *bitrateDown = 0; + } + + if(bitrateUp) { + if(up) + sscanf(up,"%u",bitrateUp); + else + *bitrateUp = 0; + } + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + ClearNameValueList(&pdata); + return ret; +} + + +/* UPNP_GetExternalIPAddress() call the corresponding UPNP method. + * if the third arg is not null the value is copied to it. + * at least 16 bytes must be available + * + * Return values : + * 0 : SUCCESS + * NON ZERO : ERROR Either an UPnP error code or an unknown error. + * + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. + */ +LIBSPEC int +UPNP_GetExternalIPAddress(const char * controlURL, + const char * servicetype, + char * extIpAdd) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + char * p; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + + if(!extIpAdd || !controlURL || !servicetype) + return UPNPCOMMAND_INVALID_ARGS; + + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetExternalIPAddress", 0, &bufsize))) { + return UPNPCOMMAND_HTTP_ERROR; + } + /*DisplayNameValueList(buffer, bufsize);*/ + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + /*printf("external ip = %s\n", GetValueFromNameValueList(&pdata, "NewExternalIPAddress") );*/ + p = GetValueFromNameValueList(&pdata, "NewExternalIPAddress"); + if(p) { + strncpy(extIpAdd, p, 16 ); + extIpAdd[15] = '\0'; + ret = UPNPCOMMAND_SUCCESS; + } else + extIpAdd[0] = '\0'; + + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + + ClearNameValueList(&pdata); + return ret; +} + +LIBSPEC int +UPNP_AddPortMapping(const char * controlURL, const char * servicetype, + const char * extPort, + const char * inPort, + const char * inClient, + const char * desc, + const char * proto, + const char * remoteHost, + const char * leaseDuration) +{ + struct UPNParg * AddPortMappingArgs; + char * buffer; + int bufsize; + struct NameValueParserData pdata; + const char * resVal; + int ret; + + if(!inPort || !inClient || !proto || !extPort) + return UPNPCOMMAND_INVALID_ARGS; + + AddPortMappingArgs = calloc(9, sizeof(struct UPNParg)); + AddPortMappingArgs[0].elt = "NewRemoteHost"; + AddPortMappingArgs[0].val = remoteHost; + AddPortMappingArgs[1].elt = "NewExternalPort"; + AddPortMappingArgs[1].val = extPort; + AddPortMappingArgs[2].elt = "NewProtocol"; + AddPortMappingArgs[2].val = proto; + AddPortMappingArgs[3].elt = "NewInternalPort"; + AddPortMappingArgs[3].val = inPort; + AddPortMappingArgs[4].elt = "NewInternalClient"; + AddPortMappingArgs[4].val = inClient; + AddPortMappingArgs[5].elt = "NewEnabled"; + AddPortMappingArgs[5].val = "1"; + AddPortMappingArgs[6].elt = "NewPortMappingDescription"; + AddPortMappingArgs[6].val = desc?desc:"libminiupnpc"; + AddPortMappingArgs[7].elt = "NewLeaseDuration"; + AddPortMappingArgs[7].val = leaseDuration?leaseDuration:"0"; + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "AddPortMapping", AddPortMappingArgs, + &bufsize))) { + free(AddPortMappingArgs); + return UPNPCOMMAND_HTTP_ERROR; + } + /*DisplayNameValueList(buffer, bufsize);*/ + /*buffer[bufsize] = '\0';*/ + /*puts(buffer);*/ + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + resVal = GetValueFromNameValueList(&pdata, "errorCode"); + if(resVal) { + /*printf("AddPortMapping errorCode = '%s'\n", resVal); */ + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(resVal, "%d", &ret); + } else { + ret = UPNPCOMMAND_SUCCESS; + } + ClearNameValueList(&pdata); + free(AddPortMappingArgs); + return ret; +} + +LIBSPEC int +UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, + const char * extPort, const char * proto, + const char * remoteHost) +{ + /*struct NameValueParserData pdata;*/ + struct UPNParg * DeletePortMappingArgs; + char * buffer; + int bufsize; + struct NameValueParserData pdata; + const char * resVal; + int ret; + + if(!extPort || !proto) + return UPNPCOMMAND_INVALID_ARGS; + + DeletePortMappingArgs = calloc(4, sizeof(struct UPNParg)); + DeletePortMappingArgs[0].elt = "NewRemoteHost"; + DeletePortMappingArgs[0].val = remoteHost; + DeletePortMappingArgs[1].elt = "NewExternalPort"; + DeletePortMappingArgs[1].val = extPort; + DeletePortMappingArgs[2].elt = "NewProtocol"; + DeletePortMappingArgs[2].val = proto; + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "DeletePortMapping", + DeletePortMappingArgs, &bufsize))) { + free(DeletePortMappingArgs); + return UPNPCOMMAND_HTTP_ERROR; + } + /*DisplayNameValueList(buffer, bufsize);*/ + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + resVal = GetValueFromNameValueList(&pdata, "errorCode"); + if(resVal) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(resVal, "%d", &ret); + } else { + ret = UPNPCOMMAND_SUCCESS; + } + ClearNameValueList(&pdata); + free(DeletePortMappingArgs); + return ret; +} + +LIBSPEC int +UPNP_GetGenericPortMappingEntry(const char * controlURL, + const char * servicetype, + const char * index, + char * extPort, + char * intClient, + char * intPort, + char * protocol, + char * desc, + char * enabled, + char * rHost, + char * duration) +{ + struct NameValueParserData pdata; + struct UPNParg * GetPortMappingArgs; + char * buffer; + int bufsize; + char * p; + int r = UPNPCOMMAND_UNKNOWN_ERROR; + if(!index) + return UPNPCOMMAND_INVALID_ARGS; + intClient[0] = '\0'; + intPort[0] = '\0'; + GetPortMappingArgs = calloc(2, sizeof(struct UPNParg)); + GetPortMappingArgs[0].elt = "NewPortMappingIndex"; + GetPortMappingArgs[0].val = index; + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetGenericPortMappingEntry", + GetPortMappingArgs, &bufsize))) { + free(GetPortMappingArgs); + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + + p = GetValueFromNameValueList(&pdata, "NewRemoteHost"); + if(p && rHost) + { + strncpy(rHost, p, 64); + rHost[63] = '\0'; + } + p = GetValueFromNameValueList(&pdata, "NewExternalPort"); + if(p && extPort) + { + strncpy(extPort, p, 6); + extPort[5] = '\0'; + r = UPNPCOMMAND_SUCCESS; + } + p = GetValueFromNameValueList(&pdata, "NewProtocol"); + if(p && protocol) + { + strncpy(protocol, p, 4); + protocol[3] = '\0'; + } + p = GetValueFromNameValueList(&pdata, "NewInternalClient"); + if(p && intClient) + { + strncpy(intClient, p, 16); + intClient[15] = '\0'; + r = 0; + } + p = GetValueFromNameValueList(&pdata, "NewInternalPort"); + if(p && intPort) + { + strncpy(intPort, p, 6); + intPort[5] = '\0'; + } + p = GetValueFromNameValueList(&pdata, "NewEnabled"); + if(p && enabled) + { + strncpy(enabled, p, 4); + enabled[3] = '\0'; + } + p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription"); + if(p && desc) + { + strncpy(desc, p, 80); + desc[79] = '\0'; + } + p = GetValueFromNameValueList(&pdata, "NewLeaseDuration"); + if(p && duration) + { + strncpy(duration, p, 16); + duration[15] = '\0'; + } + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) { + r = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &r); + } + ClearNameValueList(&pdata); + free(GetPortMappingArgs); + return r; +} + +LIBSPEC int +UPNP_GetPortMappingNumberOfEntries(const char * controlURL, + const char * servicetype, + unsigned int * numEntries) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + char* p; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetPortMappingNumberOfEntries", 0, + &bufsize))) { + return UPNPCOMMAND_HTTP_ERROR; + } +#ifdef DEBUG + DisplayNameValueList(buffer, bufsize); +#endif + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + + p = GetValueFromNameValueList(&pdata, "NewPortMappingNumberOfEntries"); + if(numEntries && p) { + *numEntries = 0; + sscanf(p, "%u", numEntries); + ret = UPNPCOMMAND_SUCCESS; + } + + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + + ClearNameValueList(&pdata); + return ret; +} + +/* UPNP_GetSpecificPortMappingEntry retrieves an existing port mapping + * the result is returned in the intClient and intPort strings + * please provide 16 and 6 bytes of data */ +LIBSPEC int +UPNP_GetSpecificPortMappingEntry(const char * controlURL, + const char * servicetype, + const char * extPort, + const char * proto, + const char * remoteHost, + char * intClient, + char * intPort, + char * desc, + char * enabled, + char * leaseDuration) +{ + struct NameValueParserData pdata; + struct UPNParg * GetPortMappingArgs; + char * buffer; + int bufsize; + char * p; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + + if(!intPort || !intClient || !extPort || !proto) + return UPNPCOMMAND_INVALID_ARGS; + + GetPortMappingArgs = calloc(4, sizeof(struct UPNParg)); + GetPortMappingArgs[0].elt = "NewRemoteHost"; + GetPortMappingArgs[0].val = remoteHost; + GetPortMappingArgs[1].elt = "NewExternalPort"; + GetPortMappingArgs[1].val = extPort; + GetPortMappingArgs[2].elt = "NewProtocol"; + GetPortMappingArgs[2].val = proto; + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetSpecificPortMappingEntry", + GetPortMappingArgs, &bufsize))) { + free(GetPortMappingArgs); + return UPNPCOMMAND_HTTP_ERROR; + } + /*DisplayNameValueList(buffer, bufsize);*/ + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + + p = GetValueFromNameValueList(&pdata, "NewInternalClient"); + if(p) { + strncpy(intClient, p, 16); + intClient[15] = '\0'; + ret = UPNPCOMMAND_SUCCESS; + } else + intClient[0] = '\0'; + + p = GetValueFromNameValueList(&pdata, "NewInternalPort"); + if(p) { + strncpy(intPort, p, 6); + intPort[5] = '\0'; + } else + intPort[0] = '\0'; + + p = GetValueFromNameValueList(&pdata, "NewEnabled"); + if(p && enabled) { + strncpy(enabled, p, 4); + enabled[3] = '\0'; + } + + p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription"); + if(p && desc) { + strncpy(desc, p, 80); + desc[79] = '\0'; + } + + p = GetValueFromNameValueList(&pdata, "NewLeaseDuration"); + if(p && leaseDuration) + { + strncpy(leaseDuration, p, 16); + leaseDuration[15] = '\0'; + } + + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + + ClearNameValueList(&pdata); + free(GetPortMappingArgs); + return ret; +} + +/* UPNP_GetListOfPortMappings() + * + * Possible UPNP Error codes : + * 606 Action not Authorized + * 730 PortMappingNotFound - no port mapping is found in the specified range. + * 733 InconsistantParameters - NewStartPort and NewEndPort values are not + * consistent. + */ +LIBSPEC int +UPNP_GetListOfPortMappings(const char * controlURL, + const char * servicetype, + const char * startPort, + const char * endPort, + const char * protocol, + const char * numberOfPorts, + struct PortMappingParserData * data) +{ + struct NameValueParserData pdata; + struct UPNParg * GetListOfPortMappingsArgs; + const char * p; + char * buffer; + int bufsize; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + + if(!startPort || !endPort || !protocol) + return UPNPCOMMAND_INVALID_ARGS; + + GetListOfPortMappingsArgs = calloc(6, sizeof(struct UPNParg)); + GetListOfPortMappingsArgs[0].elt = "NewStartPort"; + GetListOfPortMappingsArgs[0].val = startPort; + GetListOfPortMappingsArgs[1].elt = "NewEndPort"; + GetListOfPortMappingsArgs[1].val = endPort; + GetListOfPortMappingsArgs[2].elt = "NewProtocol"; + GetListOfPortMappingsArgs[2].val = protocol; + GetListOfPortMappingsArgs[3].elt = "NewManage"; + GetListOfPortMappingsArgs[3].val = "1"; + GetListOfPortMappingsArgs[4].elt = "NewNumberOfPorts"; + GetListOfPortMappingsArgs[4].val = numberOfPorts?numberOfPorts:"1000"; + + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetListOfPortMappings", + GetListOfPortMappingsArgs, &bufsize))) { + free(GetListOfPortMappingsArgs); + return UPNPCOMMAND_HTTP_ERROR; + } + free(GetListOfPortMappingsArgs); + + /*DisplayNameValueList(buffer, bufsize);*/ + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + + /*p = GetValueFromNameValueList(&pdata, "NewPortListing");*/ + /*if(p) { + printf("NewPortListing : %s\n", p); + }*/ + /*printf("NewPortListing(%d chars) : %s\n", + pdata.portListingLength, pdata.portListing);*/ + if(pdata.portListing) + { + /*struct PortMapping * pm; + int i = 0;*/ + ParsePortListing(pdata.portListing, pdata.portListingLength, + data); + ret = UPNPCOMMAND_SUCCESS; + /* + for(pm = data->head.lh_first; pm != NULL; pm = pm->entries.le_next) + { + printf("%2d %s %5hu->%s:%-5hu '%s' '%s'\n", + i, pm->protocol, pm->externalPort, pm->internalClient, + pm->internalPort, + pm->description, pm->remoteHost); + i++; + } + */ + /*FreePortListing(&data);*/ + } + + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + ClearNameValueList(&pdata); + + /*printf("%.*s", bufsize, buffer);*/ + + return ret; +} + +/* IGD:2, functions for service WANIPv6FirewallControl:1 */ +LIBSPEC int +UPNP_GetFirewallStatus(const char * controlURL, + const char * servicetype, + int * firewallEnabled, + int * inboundPinholeAllowed) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + char * fe, *ipa, *p; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + + if(!firewallEnabled || !inboundPinholeAllowed) + return UPNPCOMMAND_INVALID_ARGS; + + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetFirewallStatus", 0, &bufsize); + if(!buffer) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + fe = GetValueFromNameValueList(&pdata, "FirewallEnabled"); + ipa = GetValueFromNameValueList(&pdata, "InboundPinholeAllowed"); + if(ipa && fe) + ret = UPNPCOMMAND_SUCCESS; + if(fe) + *firewallEnabled = my_atoui(fe); + /*else + *firewallEnabled = 0;*/ + if(ipa) + *inboundPinholeAllowed = my_atoui(ipa); + /*else + *inboundPinholeAllowed = 0;*/ + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) + { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + ClearNameValueList(&pdata); + return ret; +} + +LIBSPEC int +UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype, + const char * remoteHost, + const char * remotePort, + const char * intClient, + const char * intPort, + const char * proto, + int * opTimeout) +{ + struct UPNParg * GetOutboundPinholeTimeoutArgs; + char * buffer; + int bufsize; + struct NameValueParserData pdata; + const char * resVal; + char * p; + int ret; + + if(!intPort || !intClient || !proto || !remotePort || !remoteHost) + return UPNPCOMMAND_INVALID_ARGS; + + GetOutboundPinholeTimeoutArgs = calloc(6, sizeof(struct UPNParg)); + GetOutboundPinholeTimeoutArgs[0].elt = "RemoteHost"; + GetOutboundPinholeTimeoutArgs[0].val = remoteHost; + GetOutboundPinholeTimeoutArgs[1].elt = "RemotePort"; + GetOutboundPinholeTimeoutArgs[1].val = remotePort; + GetOutboundPinholeTimeoutArgs[2].elt = "Protocol"; + GetOutboundPinholeTimeoutArgs[2].val = proto; + GetOutboundPinholeTimeoutArgs[3].elt = "InternalPort"; + GetOutboundPinholeTimeoutArgs[3].val = intPort; + GetOutboundPinholeTimeoutArgs[4].elt = "InternalClient"; + GetOutboundPinholeTimeoutArgs[4].val = intClient; + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetOutboundPinholeTimeout", GetOutboundPinholeTimeoutArgs, &bufsize); + if(!buffer) + return UPNPCOMMAND_HTTP_ERROR; + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + resVal = GetValueFromNameValueList(&pdata, "errorCode"); + if(resVal) + { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(resVal, "%d", &ret); + } + else + { + ret = UPNPCOMMAND_SUCCESS; + p = GetValueFromNameValueList(&pdata, "OutboundPinholeTimeout"); + if(p) + *opTimeout = my_atoui(p); + } + ClearNameValueList(&pdata); + free(GetOutboundPinholeTimeoutArgs); + return ret; +} + +LIBSPEC int +UPNP_AddPinhole(const char * controlURL, const char * servicetype, + const char * remoteHost, + const char * remotePort, + const char * intClient, + const char * intPort, + const char * proto, + const char * leaseTime, + char * uniqueID) +{ + struct UPNParg * AddPinholeArgs; + char * buffer; + int bufsize; + struct NameValueParserData pdata; + const char * resVal; + char * p; + int ret; + + if(!intPort || !intClient || !proto || !remoteHost || !remotePort || !leaseTime) + return UPNPCOMMAND_INVALID_ARGS; + + AddPinholeArgs = calloc(7, sizeof(struct UPNParg)); + /* RemoteHost can be wilcarded */ + if(strncmp(remoteHost, "empty", 5)==0) + { + AddPinholeArgs[0].elt = "RemoteHost"; + AddPinholeArgs[0].val = ""; + } + else + { + AddPinholeArgs[0].elt = "RemoteHost"; + AddPinholeArgs[0].val = remoteHost; + } + AddPinholeArgs[1].elt = "RemotePort"; + AddPinholeArgs[1].val = remotePort; + AddPinholeArgs[2].elt = "Protocol"; + AddPinholeArgs[2].val = proto; + AddPinholeArgs[3].elt = "InternalPort"; + AddPinholeArgs[3].val = intPort; + if(strncmp(intClient, "empty", 5)==0) + { + AddPinholeArgs[4].elt = "InternalClient"; + AddPinholeArgs[4].val = ""; + } + else + { + AddPinholeArgs[4].elt = "InternalClient"; + AddPinholeArgs[4].val = intClient; + } + AddPinholeArgs[5].elt = "LeaseTime"; + AddPinholeArgs[5].val = leaseTime; + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "AddPinhole", AddPinholeArgs, &bufsize); + if(!buffer) + return UPNPCOMMAND_HTTP_ERROR; + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + p = GetValueFromNameValueList(&pdata, "UniqueID"); + if(p) + { + strncpy(uniqueID, p, 8); + uniqueID[7] = '\0'; + } + resVal = GetValueFromNameValueList(&pdata, "errorCode"); + if(resVal) + { + /*printf("AddPortMapping errorCode = '%s'\n", resVal);*/ + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(resVal, "%d", &ret); + } + else + { + ret = UPNPCOMMAND_SUCCESS; + } + ClearNameValueList(&pdata); + free(AddPinholeArgs); + return ret; +} + +LIBSPEC int +UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, + const char * uniqueID, + const char * leaseTime) +{ + struct UPNParg * UpdatePinholeArgs; + char * buffer; + int bufsize; + struct NameValueParserData pdata; + const char * resVal; + int ret; + + if(!uniqueID || !leaseTime) + return UPNPCOMMAND_INVALID_ARGS; + + UpdatePinholeArgs = calloc(3, sizeof(struct UPNParg)); + UpdatePinholeArgs[0].elt = "UniqueID"; + UpdatePinholeArgs[0].val = uniqueID; + UpdatePinholeArgs[1].elt = "NewLeaseTime"; + UpdatePinholeArgs[1].val = leaseTime; + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "UpdatePinhole", UpdatePinholeArgs, &bufsize); + if(!buffer) + return UPNPCOMMAND_HTTP_ERROR; + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + resVal = GetValueFromNameValueList(&pdata, "errorCode"); + if(resVal) + { + /*printf("AddPortMapping errorCode = '%s'\n", resVal); */ + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(resVal, "%d", &ret); + } + else + { + ret = UPNPCOMMAND_SUCCESS; + } + ClearNameValueList(&pdata); + free(UpdatePinholeArgs); + return ret; +} + +LIBSPEC int +UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID) +{ + /*struct NameValueParserData pdata;*/ + struct UPNParg * DeletePinholeArgs; + char * buffer; + int bufsize; + struct NameValueParserData pdata; + const char * resVal; + int ret; + + if(!uniqueID) + return UPNPCOMMAND_INVALID_ARGS; + + DeletePinholeArgs = calloc(2, sizeof(struct UPNParg)); + DeletePinholeArgs[0].elt = "UniqueID"; + DeletePinholeArgs[0].val = uniqueID; + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "DeletePinhole", DeletePinholeArgs, &bufsize); + if(!buffer) + return UPNPCOMMAND_HTTP_ERROR; + /*DisplayNameValueList(buffer, bufsize);*/ + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + resVal = GetValueFromNameValueList(&pdata, "errorCode"); + if(resVal) + { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(resVal, "%d", &ret); + } + else + { + ret = UPNPCOMMAND_SUCCESS; + } + ClearNameValueList(&pdata); + free(DeletePinholeArgs); + return ret; +} + +LIBSPEC int +UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, + const char * uniqueID, int * isWorking) +{ + struct NameValueParserData pdata; + struct UPNParg * CheckPinholeWorkingArgs; + char * buffer; + int bufsize; + char * p; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + + if(!uniqueID) + return UPNPCOMMAND_INVALID_ARGS; + + CheckPinholeWorkingArgs = calloc(4, sizeof(struct UPNParg)); + CheckPinholeWorkingArgs[0].elt = "UniqueID"; + CheckPinholeWorkingArgs[0].val = uniqueID; + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "CheckPinholeWorking", CheckPinholeWorkingArgs, &bufsize); + if(!buffer) + return UPNPCOMMAND_HTTP_ERROR; + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + + p = GetValueFromNameValueList(&pdata, "IsWorking"); + if(p) + { + *isWorking=my_atoui(p); + ret = UPNPCOMMAND_SUCCESS; + } + else + *isWorking = 0; + + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) + { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + + ClearNameValueList(&pdata); + free(CheckPinholeWorkingArgs); + return ret; +} + +LIBSPEC int +UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, + const char * uniqueID, int * packets) +{ + struct NameValueParserData pdata; + struct UPNParg * GetPinholePacketsArgs; + char * buffer; + int bufsize; + char * p; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + + if(!uniqueID) + return UPNPCOMMAND_INVALID_ARGS; + + GetPinholePacketsArgs = calloc(4, sizeof(struct UPNParg)); + GetPinholePacketsArgs[0].elt = "UniqueID"; + GetPinholePacketsArgs[0].val = uniqueID; + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetPinholePackets", GetPinholePacketsArgs, &bufsize); + if(!buffer) + return UPNPCOMMAND_HTTP_ERROR; + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + + p = GetValueFromNameValueList(&pdata, "PinholePackets"); + if(p) + { + *packets=my_atoui(p); + ret = UPNPCOMMAND_SUCCESS; + } + + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) + { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + + ClearNameValueList(&pdata); + free(GetPinholePacketsArgs); + return ret; +} + + diff --git a/contrib/miniupnpc/upnpcommands.h b/contrib/miniupnpc/upnpcommands.h new file mode 100644 index 00000000..93d9f3dd --- /dev/null +++ b/contrib/miniupnpc/upnpcommands.h @@ -0,0 +1,293 @@ +/* $Id: upnpcommands.h,v 1.27 2014/02/17 15:38:26 nanard Exp $ */ +/* Miniupnp project : http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2005-2014 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided within this distribution */ +#ifndef UPNPCOMMANDS_H_INCLUDED +#define UPNPCOMMANDS_H_INCLUDED + +#include "upnpreplyparse.h" +#include "portlistingparse.h" +#include "declspec.h" +#include "miniupnpctypes.h" + +/* MiniUPnPc return codes : */ +#define UPNPCOMMAND_SUCCESS (0) +#define UPNPCOMMAND_UNKNOWN_ERROR (-1) +#define UPNPCOMMAND_INVALID_ARGS (-2) +#define UPNPCOMMAND_HTTP_ERROR (-3) + +#ifdef __cplusplus +extern "C" { +#endif + +LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalBytesSent(const char * controlURL, + const char * servicetype); + +LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalBytesReceived(const char * controlURL, + const char * servicetype); + +LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalPacketsSent(const char * controlURL, + const char * servicetype); + +LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalPacketsReceived(const char * controlURL, + const char * servicetype); + +/* UPNP_GetStatusInfo() + * status and lastconnerror are 64 byte buffers + * Return values : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error code */ +LIBSPEC int +UPNP_GetStatusInfo(const char * controlURL, + const char * servicetype, + char * status, + unsigned int * uptime, + char * lastconnerror); + +/* UPNP_GetConnectionTypeInfo() + * argument connectionType is a 64 character buffer + * Return Values : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error code */ +LIBSPEC int +UPNP_GetConnectionTypeInfo(const char * controlURL, + const char * servicetype, + char * connectionType); + +/* UPNP_GetExternalIPAddress() call the corresponding UPNP method. + * if the third arg is not null the value is copied to it. + * at least 16 bytes must be available + * + * Return values : + * 0 : SUCCESS + * NON ZERO : ERROR Either an UPnP error code or an unknown error. + * + * possible UPnP Errors : + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. */ +LIBSPEC int +UPNP_GetExternalIPAddress(const char * controlURL, + const char * servicetype, + char * extIpAdd); + +/* UPNP_GetLinkLayerMaxBitRates() + * call WANCommonInterfaceConfig:1#GetCommonLinkProperties + * + * return values : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error Code. */ +LIBSPEC int +UPNP_GetLinkLayerMaxBitRates(const char* controlURL, + const char* servicetype, + unsigned int * bitrateDown, + unsigned int * bitrateUp); + +/* UPNP_AddPortMapping() + * if desc is NULL, it will be defaulted to "libminiupnpc" + * remoteHost is usually NULL because IGD don't support it. + * + * Return values : + * 0 : SUCCESS + * NON ZERO : ERROR. Either an UPnP error code or an unknown error. + * + * List of possible UPnP errors for AddPortMapping : + * errorCode errorDescription (short) - Description (long) + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization and + * the sender was not authorized. + * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be + * wild-carded + * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded + * 718 ConflictInMappingEntry - The port mapping entry specified conflicts + * with a mapping assigned previously to another client + * 724 SamePortValuesRequired - Internal and External port values + * must be the same + * 725 OnlyPermanentLeasesSupported - The NAT implementation only supports + * permanent lease times on port mappings + * 726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard + * and cannot be a specific IP address or DNS name + * 727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and + * cannot be a specific port value + * 728 NoPortMapsAvailable - There are not enough free ports available to + * complete port mapping. + * 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed + * due to conflict with other mechanisms. + * 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded + */ +LIBSPEC int +UPNP_AddPortMapping(const char * controlURL, const char * servicetype, + const char * extPort, + const char * inPort, + const char * inClient, + const char * desc, + const char * proto, + const char * remoteHost, + const char * leaseDuration); + +/* UPNP_DeletePortMapping() + * Use same argument values as what was used for AddPortMapping(). + * remoteHost is usually NULL because IGD don't support it. + * Return Values : + * 0 : SUCCESS + * NON ZERO : error. Either an UPnP error code or an undefined error. + * + * List of possible UPnP errors for DeletePortMapping : + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. + * 714 NoSuchEntryInArray - The specified value does not exist in the array */ +LIBSPEC int +UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, + const char * extPort, const char * proto, + const char * remoteHost); + +/* UPNP_GetPortMappingNumberOfEntries() + * not supported by all routers */ +LIBSPEC int +UPNP_GetPortMappingNumberOfEntries(const char* controlURL, + const char* servicetype, + unsigned int * num); + +/* UPNP_GetSpecificPortMappingEntry() + * retrieves an existing port mapping + * params : + * in extPort + * in proto + * in remoteHost + * out intClient (16 bytes) + * out intPort (6 bytes) + * out desc (80 bytes) + * out enabled (4 bytes) + * out leaseDuration (16 bytes) + * + * return value : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error Code. + * + * List of possible UPnP errors for _GetSpecificPortMappingEntry : + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. + * 714 NoSuchEntryInArray - The specified value does not exist in the array. + */ +LIBSPEC int +UPNP_GetSpecificPortMappingEntry(const char * controlURL, + const char * servicetype, + const char * extPort, + const char * proto, + const char * remoteHost, + char * intClient, + char * intPort, + char * desc, + char * enabled, + char * leaseDuration); + +/* UPNP_GetGenericPortMappingEntry() + * params : + * in index + * out extPort (6 bytes) + * out intClient (16 bytes) + * out intPort (6 bytes) + * out protocol (4 bytes) + * out desc (80 bytes) + * out enabled (4 bytes) + * out rHost (64 bytes) + * out duration (16 bytes) + * + * return value : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error Code. + * + * Possible UPNP Error codes : + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. + * 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds + */ +LIBSPEC int +UPNP_GetGenericPortMappingEntry(const char * controlURL, + const char * servicetype, + const char * index, + char * extPort, + char * intClient, + char * intPort, + char * protocol, + char * desc, + char * enabled, + char * rHost, + char * duration); + +/* UPNP_GetListOfPortMappings() Available in IGD v2 + * + * + * Possible UPNP Error codes : + * 606 Action not Authorized + * 730 PortMappingNotFound - no port mapping is found in the specified range. + * 733 InconsistantParameters - NewStartPort and NewEndPort values are not + * consistent. + */ +LIBSPEC int +UPNP_GetListOfPortMappings(const char * controlURL, + const char * servicetype, + const char * startPort, + const char * endPort, + const char * protocol, + const char * numberOfPorts, + struct PortMappingParserData * data); + +/* IGD:2, functions for service WANIPv6FirewallControl:1 */ +LIBSPEC int +UPNP_GetFirewallStatus(const char * controlURL, + const char * servicetype, + int * firewallEnabled, + int * inboundPinholeAllowed); + +LIBSPEC int +UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype, + const char * remoteHost, + const char * remotePort, + const char * intClient, + const char * intPort, + const char * proto, + int * opTimeout); + +LIBSPEC int +UPNP_AddPinhole(const char * controlURL, const char * servicetype, + const char * remoteHost, + const char * remotePort, + const char * intClient, + const char * intPort, + const char * proto, + const char * leaseTime, + char * uniqueID); + +LIBSPEC int +UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, + const char * uniqueID, + const char * leaseTime); + +LIBSPEC int +UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID); + +LIBSPEC int +UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, + const char * uniqueID, int * isWorking); + +LIBSPEC int +UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, + const char * uniqueID, int * packets); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/contrib/miniupnpc/upnperrors.c b/contrib/miniupnpc/upnperrors.c new file mode 100644 index 00000000..644098f0 --- /dev/null +++ b/contrib/miniupnpc/upnperrors.c @@ -0,0 +1,104 @@ +/* $Id: upnperrors.c,v 1.6 2012/03/15 01:02:03 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas BERNARD + * copyright (c) 2007 Thomas Bernard + * All Right reserved. + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * This software is subjet to the conditions detailed in the + * provided LICENCE file. */ +#include +#include "upnperrors.h" +#include "upnpcommands.h" +#include "miniupnpc.h" + +const char * strupnperror(int err) +{ + const char * s = NULL; + switch(err) { + case UPNPCOMMAND_SUCCESS: + s = "Success"; + break; + case UPNPCOMMAND_UNKNOWN_ERROR: + s = "Miniupnpc Unknown Error"; + break; + case UPNPCOMMAND_INVALID_ARGS: + s = "Miniupnpc Invalid Arguments"; + break; + case UPNPDISCOVER_SOCKET_ERROR: + s = "Miniupnpc Socket error"; + break; + case UPNPDISCOVER_MEMORY_ERROR: + s = "Miniupnpc Memory allocation error"; + break; + case 401: + s = "Invalid Action"; + break; + case 402: + s = "Invalid Args"; + break; + case 501: + s = "Action Failed"; + break; + case 606: + s = "Action not authorized"; + break; + case 701: + s = "PinholeSpaceExhausted"; + break; + case 702: + s = "FirewallDisabled"; + break; + case 703: + s = "InboundPinholeNotAllowed"; + break; + case 704: + s = "NoSuchEntry"; + break; + case 705: + s = "ProtocolNotSupported"; + break; + case 706: + s = "InternalPortWildcardingNotAllowed"; + break; + case 707: + s = "ProtocolWildcardingNotAllowed"; + break; + case 708: + s = "WildcardNotPermittedInSrcIP"; + break; + case 709: + s = "NoPacketSent"; + break; + case 713: + s = "SpecifiedArrayIndexInvalid"; + break; + case 714: + s = "NoSuchEntryInArray"; + break; + case 715: + s = "WildCardNotPermittedInSrcIP"; + break; + case 716: + s = "WildCardNotPermittedInExtPort"; + break; + case 718: + s = "ConflictInMappingEntry"; + break; + case 724: + s = "SamePortValuesRequired"; + break; + case 725: + s = "OnlyPermanentLeasesSupported"; + break; + case 726: + s = "RemoteHostOnlySupportsWildcard"; + break; + case 727: + s = "ExternalPortOnlySupportsWildcard"; + break; + default: + s = "UnknownError"; + break; + } + return s; +} diff --git a/contrib/miniupnpc/upnperrors.h b/contrib/miniupnpc/upnperrors.h new file mode 100644 index 00000000..077d6938 --- /dev/null +++ b/contrib/miniupnpc/upnperrors.h @@ -0,0 +1,26 @@ +/* $Id: upnperrors.h,v 1.4 2012/09/27 15:42:11 nanard Exp $ */ +/* (c) 2007 Thomas Bernard + * All rights reserved. + * MiniUPnP Project. + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * This software is subjet to the conditions detailed in the + * provided LICENCE file. */ +#ifndef UPNPERRORS_H_INCLUDED +#define UPNPERRORS_H_INCLUDED + +#include "declspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* strupnperror() + * Return a string description of the UPnP error code + * or NULL for undefinded errors */ +LIBSPEC const char * strupnperror(int err); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/miniupnpc/upnpreplyparse.c b/contrib/miniupnpc/upnpreplyparse.c new file mode 100644 index 00000000..dafa2631 --- /dev/null +++ b/contrib/miniupnpc/upnpreplyparse.c @@ -0,0 +1,183 @@ +/* $Id: upnpreplyparse.c,v 1.15 2013/06/06 21:36:40 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2006-2013 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ + +#include +#include +#include + +#include "upnpreplyparse.h" +#include "minixml.h" + +static void +NameValueParserStartElt(void * d, const char * name, int l) +{ + struct NameValueParserData * data = (struct NameValueParserData *)d; + data->topelt = 1; + if(l>63) + l = 63; + memcpy(data->curelt, name, l); + data->curelt[l] = '\0'; + data->cdata = NULL; + data->cdatalen = 0; +} + +static void +NameValueParserEndElt(void * d, const char * name, int l) +{ + struct NameValueParserData * data = (struct NameValueParserData *)d; + struct NameValue * nv; + (void)name; + (void)l; + if(!data->topelt) + return; + if(strcmp(data->curelt, "NewPortListing") != 0) + { + int l; + /* standard case. Limited to n chars strings */ + l = data->cdatalen; + nv = malloc(sizeof(struct NameValue)); + if(l>=(int)sizeof(nv->value)) + l = sizeof(nv->value) - 1; + strncpy(nv->name, data->curelt, 64); + nv->name[63] = '\0'; + if(data->cdata != NULL) + { + memcpy(nv->value, data->cdata, l); + nv->value[l] = '\0'; + } + else + { + nv->value[0] = '\0'; + } + LIST_INSERT_HEAD( &(data->head), nv, entries); + } + data->cdata = NULL; + data->cdatalen = 0; + data->topelt = 0; +} + +static void +NameValueParserGetData(void * d, const char * datas, int l) +{ + struct NameValueParserData * data = (struct NameValueParserData *)d; + if(strcmp(data->curelt, "NewPortListing") == 0) + { + /* specific case for NewPortListing which is a XML Document */ + data->portListing = malloc(l + 1); + if(!data->portListing) + { + /* malloc error */ + return; + } + memcpy(data->portListing, datas, l); + data->portListing[l] = '\0'; + data->portListingLength = l; + } + else + { + /* standard case. */ + data->cdata = datas; + data->cdatalen = l; + } +} + +void +ParseNameValue(const char * buffer, int bufsize, + struct NameValueParserData * data) +{ + struct xmlparser parser; + LIST_INIT(&(data->head)); + data->portListing = NULL; + data->portListingLength = 0; + /* init xmlparser object */ + parser.xmlstart = buffer; + parser.xmlsize = bufsize; + parser.data = data; + parser.starteltfunc = NameValueParserStartElt; + parser.endeltfunc = NameValueParserEndElt; + parser.datafunc = NameValueParserGetData; + parser.attfunc = 0; + parsexml(&parser); +} + +void +ClearNameValueList(struct NameValueParserData * pdata) +{ + struct NameValue * nv; + if(pdata->portListing) + { + free(pdata->portListing); + pdata->portListing = NULL; + pdata->portListingLength = 0; + } + while((nv = pdata->head.lh_first) != NULL) + { + LIST_REMOVE(nv, entries); + free(nv); + } +} + +char * +GetValueFromNameValueList(struct NameValueParserData * pdata, + const char * Name) +{ + struct NameValue * nv; + char * p = NULL; + for(nv = pdata->head.lh_first; + (nv != NULL) && (p == NULL); + nv = nv->entries.le_next) + { + if(strcmp(nv->name, Name) == 0) + p = nv->value; + } + return p; +} + +#if 0 +/* useless now that minixml ignores namespaces by itself */ +char * +GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata, + const char * Name) +{ + struct NameValue * nv; + char * p = NULL; + char * pname; + for(nv = pdata->head.lh_first; + (nv != NULL) && (p == NULL); + nv = nv->entries.le_next) + { + pname = strrchr(nv->name, ':'); + if(pname) + pname++; + else + pname = nv->name; + if(strcmp(pname, Name)==0) + p = nv->value; + } + return p; +} +#endif + +/* debug all-in-one function + * do parsing then display to stdout */ +#ifdef DEBUG +void +DisplayNameValueList(char * buffer, int bufsize) +{ + struct NameValueParserData pdata; + struct NameValue * nv; + ParseNameValue(buffer, bufsize, &pdata); + for(nv = pdata.head.lh_first; + nv != NULL; + nv = nv->entries.le_next) + { + printf("%s = %s\n", nv->name, nv->value); + } + ClearNameValueList(&pdata); +} +#endif + diff --git a/contrib/miniupnpc/upnpreplyparse.h b/contrib/miniupnpc/upnpreplyparse.h new file mode 100644 index 00000000..d4e37576 --- /dev/null +++ b/contrib/miniupnpc/upnpreplyparse.h @@ -0,0 +1,69 @@ +/* $Id: upnpreplyparse.h,v 1.17 2013/06/06 21:36:40 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2006-2013 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ + +#ifndef UPNPREPLYPARSE_H_INCLUDED +#define UPNPREPLYPARSE_H_INCLUDED + +#if defined(NO_SYS_QUEUE_H) || defined(_WIN32) || defined(__HAIKU__) +#include "bsdqueue.h" +#else +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct NameValue { + LIST_ENTRY(NameValue) entries; + char name[64]; + char value[128]; +}; + +struct NameValueParserData { + LIST_HEAD(listhead, NameValue) head; + char curelt[64]; + char * portListing; + int portListingLength; + int topelt; + const char * cdata; + int cdatalen; +}; + +/* ParseNameValue() */ +void +ParseNameValue(const char * buffer, int bufsize, + struct NameValueParserData * data); + +/* ClearNameValueList() */ +void +ClearNameValueList(struct NameValueParserData * pdata); + +/* GetValueFromNameValueList() */ +char * +GetValueFromNameValueList(struct NameValueParserData * pdata, + const char * Name); + +#if 0 +/* GetValueFromNameValueListIgnoreNS() */ +char * +GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata, + const char * Name); +#endif + +/* DisplayNameValueList() */ +#ifdef DEBUG +void +DisplayNameValueList(char * buffer, int bufsize); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/contrib/miniupnpc/wingenminiupnpcstrings.c b/contrib/miniupnpc/wingenminiupnpcstrings.c new file mode 100644 index 00000000..ed289f4a --- /dev/null +++ b/contrib/miniupnpc/wingenminiupnpcstrings.c @@ -0,0 +1,82 @@ +/* $Id: wingenminiupnpcstrings.c,v 1.3 2012/03/05 19:42:48 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * Author: Thomas Bernard + * Copyright (c) 2005-2009 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENSE file provided within this distribution */ +#include +#include + +/* This program display the Windows version and is used to + * generate the miniupnpcstrings.h + * wingenminiupnpcstrings miniupnpcstrings.h.in miniupnpcstrings.h + */ +int main(int argc, char * * argv) { + char buffer[256]; + OSVERSIONINFO osvi; + FILE * fin; + FILE * fout; + int n; + char miniupnpcVersion[32]; + /* dwMajorVersion : + The major version number of the operating system. For more information, see Remarks. + dwMinorVersion : + The minor version number of the operating system. For more information, see Remarks. + dwBuildNumber : + The build number of the operating system. + dwPlatformId + The operating system platform. This member can be the following value. + szCSDVersion + A null-terminated string, such as "Service Pack 3", that indicates the + latest Service Pack installed on the system. If no Service Pack has + been installed, the string is empty. + */ + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + + GetVersionEx(&osvi); + + printf("Windows %lu.%lu Build %lu %s\n", + osvi.dwMajorVersion, osvi.dwMinorVersion, + osvi.dwBuildNumber, (const char *)&(osvi.szCSDVersion)); + + fin = fopen("VERSION", "r"); + fgets(miniupnpcVersion, sizeof(miniupnpcVersion), fin); + fclose(fin); + for(n = 0; n < sizeof(miniupnpcVersion); n++) { + if(miniupnpcVersion[n] < ' ') + miniupnpcVersion[n] = '\0'; + } + printf("MiniUPnPc version %s\n", miniupnpcVersion); + + if(argc >= 3) { + fin = fopen(argv[1], "r"); + if(!fin) { + fprintf(stderr, "Cannot open %s for reading.\n", argv[1]); + return 1; + } + fout = fopen(argv[2], "w"); + if(!fout) { + fprintf(stderr, "Cannot open %s for writing.\n", argv[2]); + return 1; + } + n = 0; + while(fgets(buffer, sizeof(buffer), fin)) { + if(0 == memcmp(buffer, "#define OS_STRING \"OS/version\"", 30)) { + sprintf(buffer, "#define OS_STRING \"MSWindows/%ld.%ld.%ld\"\n", + osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber); + } else if(0 == memcmp(buffer, "#define MINIUPNPC_VERSION_STRING \"version\"", 42)) { + sprintf(buffer, "#define MINIUPNPC_VERSION_STRING \"%s\"\n", + miniupnpcVersion); + } + /*fputs(buffer, stdout);*/ + fputs(buffer, fout); + n++; + } + fclose(fin); + fclose(fout); + printf("%d lines written to %s.\n", n, argv[2]); + } + return 0; +} diff --git a/contrib/zlib/CMakeLists.txt b/contrib/zlib/CMakeLists.txt new file mode 100644 index 00000000..0fe939df --- /dev/null +++ b/contrib/zlib/CMakeLists.txt @@ -0,0 +1,249 @@ +cmake_minimum_required(VERSION 2.4.4) +set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON) + +project(zlib C) + +set(VERSION "1.2.11") + +option(ASM686 "Enable building i686 assembly implementation") +option(AMD64 "Enable building amd64 assembly implementation") + +set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables") +set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries") +set(INSTALL_INC_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "Installation directory for headers") +set(INSTALL_MAN_DIR "${CMAKE_INSTALL_PREFIX}/share/man" CACHE PATH "Installation directory for manual pages") +set(INSTALL_PKGCONFIG_DIR "${CMAKE_INSTALL_PREFIX}/share/pkgconfig" CACHE PATH "Installation directory for pkgconfig (.pc) files") + +include(CheckTypeSize) +include(CheckFunctionExists) +include(CheckIncludeFile) +include(CheckCSourceCompiles) +enable_testing() + +check_include_file(sys/types.h HAVE_SYS_TYPES_H) +check_include_file(stdint.h HAVE_STDINT_H) +check_include_file(stddef.h HAVE_STDDEF_H) + +# +# Check to see if we have large file support +# +set(CMAKE_REQUIRED_DEFINITIONS -D_LARGEFILE64_SOURCE=1) +# We add these other definitions here because CheckTypeSize.cmake +# in CMake 2.4.x does not automatically do so and we want +# compatibility with CMake 2.4.x. +if(HAVE_SYS_TYPES_H) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_SYS_TYPES_H) +endif() +if(HAVE_STDINT_H) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDINT_H) +endif() +if(HAVE_STDDEF_H) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDDEF_H) +endif() +check_type_size(off64_t OFF64_T) +if(HAVE_OFF64_T) + add_definitions(-D_LARGEFILE64_SOURCE=1) +endif() +set(CMAKE_REQUIRED_DEFINITIONS) # clear variable + +# +# Check for fseeko +# +check_function_exists(fseeko HAVE_FSEEKO) +if(NOT HAVE_FSEEKO) + add_definitions(-DNO_FSEEKO) +endif() + +# +# Check for unistd.h +# +check_include_file(unistd.h Z_HAVE_UNISTD_H) + +if(MSVC) + set(CMAKE_DEBUG_POSTFIX "d") + add_definitions(-D_CRT_SECURE_NO_DEPRECATE) + add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE) + include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +endif() + +if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) + # If we're doing an out of source build and the user has a zconf.h + # in their source tree... + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h) + message(STATUS "Renaming") + message(STATUS " ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h") + message(STATUS "to 'zconf.h.included' because this file is included with zlib") + message(STATUS "but CMake generates it automatically in the build directory.") + file(RENAME ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h.included) + endif() +endif() + +set(ZLIB_PC ${CMAKE_CURRENT_BINARY_DIR}/zlib.pc) +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/zlib.pc.cmakein + ${ZLIB_PC} @ONLY) +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h.cmakein + ${CMAKE_CURRENT_BINARY_DIR}/zconf.h @ONLY) +include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}) + + +#============================================================================ +# zlib +#============================================================================ + +set(ZLIB_PUBLIC_HDRS + ${CMAKE_CURRENT_BINARY_DIR}/zconf.h + zlib.h +) +set(ZLIB_PRIVATE_HDRS + crc32.h + deflate.h + gzguts.h + inffast.h + inffixed.h + inflate.h + inftrees.h + trees.h + zutil.h +) +set(ZLIB_SRCS + adler32.c + compress.c + crc32.c + deflate.c + gzclose.c + gzlib.c + gzread.c + gzwrite.c + inflate.c + infback.c + inftrees.c + inffast.c + trees.c + uncompr.c + zutil.c +) + +if(NOT MINGW) + set(ZLIB_DLL_SRCS + win32/zlib1.rc # If present will override custom build rule below. + ) +endif() + +if(CMAKE_COMPILER_IS_GNUCC) + if(ASM686) + set(ZLIB_ASMS contrib/asm686/match.S) + elseif (AMD64) + set(ZLIB_ASMS contrib/amd64/amd64-match.S) + endif () + + if(ZLIB_ASMS) + add_definitions(-DASMV) + set_source_files_properties(${ZLIB_ASMS} PROPERTIES LANGUAGE C COMPILE_FLAGS -DNO_UNDERLINE) + endif() +endif() + +if(MSVC) + if(ASM686) + ENABLE_LANGUAGE(ASM_MASM) + set(ZLIB_ASMS + contrib/masmx86/inffas32.asm + contrib/masmx86/match686.asm + ) + elseif (AMD64) + ENABLE_LANGUAGE(ASM_MASM) + set(ZLIB_ASMS + contrib/masmx64/gvmat64.asm + contrib/masmx64/inffasx64.asm + ) + endif() + + if(ZLIB_ASMS) + add_definitions(-DASMV -DASMINF) + endif() +endif() + +# parse the full version number from zlib.h and include in ZLIB_FULL_VERSION +file(READ ${CMAKE_CURRENT_SOURCE_DIR}/zlib.h _zlib_h_contents) +string(REGEX REPLACE ".*#define[ \t]+ZLIB_VERSION[ \t]+\"([-0-9A-Za-z.]+)\".*" + "\\1" ZLIB_FULL_VERSION ${_zlib_h_contents}) + +if(MINGW) + # This gets us DLL resource information when compiling on MinGW. + if(NOT CMAKE_RC_COMPILER) + set(CMAKE_RC_COMPILER windres.exe) + endif() + + add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj + COMMAND ${CMAKE_RC_COMPILER} + -D GCC_WINDRES + -I ${CMAKE_CURRENT_SOURCE_DIR} + -I ${CMAKE_CURRENT_BINARY_DIR} + -o ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj + -i ${CMAKE_CURRENT_SOURCE_DIR}/win32/zlib1.rc) + set(ZLIB_DLL_SRCS ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj) +endif(MINGW) + +add_library(zlib SHARED ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) +add_library(zlibstatic STATIC ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) +set_target_properties(zlib PROPERTIES DEFINE_SYMBOL ZLIB_DLL) +set_target_properties(zlib PROPERTIES SOVERSION 1) + +if(NOT CYGWIN) + # This property causes shared libraries on Linux to have the full version + # encoded into their final filename. We disable this on Cygwin because + # it causes cygz-${ZLIB_FULL_VERSION}.dll to be created when cygz.dll + # seems to be the default. + # + # This has no effect with MSVC, on that platform the version info for + # the DLL comes from the resource file win32/zlib1.rc + set_target_properties(zlib PROPERTIES VERSION ${ZLIB_FULL_VERSION}) +endif() + +if(UNIX) + # On unix-like platforms the library is almost always called libz + set_target_properties(zlib zlibstatic PROPERTIES OUTPUT_NAME z) + if(NOT APPLE) + set_target_properties(zlib PROPERTIES LINK_FLAGS "-Wl,--version-script,\"${CMAKE_CURRENT_SOURCE_DIR}/zlib.map\"") + endif() +elseif(BUILD_SHARED_LIBS AND WIN32) + # Creates zlib1.dll when building shared library version + set_target_properties(zlib PROPERTIES SUFFIX "1.dll") +endif() + +if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL ) + install(TARGETS zlib zlibstatic + RUNTIME DESTINATION "${INSTALL_BIN_DIR}" + ARCHIVE DESTINATION "${INSTALL_LIB_DIR}" + LIBRARY DESTINATION "${INSTALL_LIB_DIR}" ) +endif() +if(NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL ) + install(FILES ${ZLIB_PUBLIC_HDRS} DESTINATION "${INSTALL_INC_DIR}") +endif() +if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL ) + install(FILES zlib.3 DESTINATION "${INSTALL_MAN_DIR}/man3") +endif() +if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL ) + install(FILES ${ZLIB_PC} DESTINATION "${INSTALL_PKGCONFIG_DIR}") +endif() + +#============================================================================ +# Example binaries +#============================================================================ + +add_executable(example test/example.c) +target_link_libraries(example zlib) +add_test(example example) + +add_executable(minigzip test/minigzip.c) +target_link_libraries(minigzip zlib) + +if(HAVE_OFF64_T) + add_executable(example64 test/example.c) + target_link_libraries(example64 zlib) + set_target_properties(example64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") + add_test(example64 example64) + + add_executable(minigzip64 test/minigzip.c) + target_link_libraries(minigzip64 zlib) + set_target_properties(minigzip64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") +endif() diff --git a/contrib/zlib/ChangeLog b/contrib/zlib/ChangeLog new file mode 100644 index 00000000..30199a65 --- /dev/null +++ b/contrib/zlib/ChangeLog @@ -0,0 +1,1515 @@ + + ChangeLog file for zlib + +Changes in 1.2.11 (15 Jan 2017) +- Fix deflate stored bug when pulling last block from window +- Permit immediate deflateParams changes before any deflate input + +Changes in 1.2.10 (2 Jan 2017) +- Avoid warnings on snprintf() return value +- Fix bug in deflate_stored() for zero-length input +- Fix bug in gzwrite.c that produced corrupt gzip files +- Remove files to be installed before copying them in Makefile.in +- Add warnings when compiling with assembler code + +Changes in 1.2.9 (31 Dec 2016) +- Fix contrib/minizip to permit unzipping with desktop API [Zouzou] +- Improve contrib/blast to return unused bytes +- Assure that gzoffset() is correct when appending +- Improve compress() and uncompress() to support large lengths +- Fix bug in test/example.c where error code not saved +- Remedy Coverity warning [Randers-Pehrson] +- Improve speed of gzprintf() in transparent mode +- Fix inflateInit2() bug when windowBits is 16 or 32 +- Change DEBUG macro to ZLIB_DEBUG +- Avoid uninitialized access by gzclose_w() +- Allow building zlib outside of the source directory +- Fix bug that accepted invalid zlib header when windowBits is zero +- Fix gzseek() problem on MinGW due to buggy _lseeki64 there +- Loop on write() calls in gzwrite.c in case of non-blocking I/O +- Add --warn (-w) option to ./configure for more compiler warnings +- Reject a window size of 256 bytes if not using the zlib wrapper +- Fix bug when level 0 used with Z_HUFFMAN or Z_RLE +- Add --debug (-d) option to ./configure to define ZLIB_DEBUG +- Fix bugs in creating a very large gzip header +- Add uncompress2() function, which returns the input size used +- Assure that deflateParams() will not switch functions mid-block +- Dramatically speed up deflation for level 0 (storing) +- Add gzfread(), duplicating the interface of fread() +- Add gzfwrite(), duplicating the interface of fwrite() +- Add deflateGetDictionary() function +- Use snprintf() for later versions of Microsoft C +- Fix *Init macros to use z_ prefix when requested +- Replace as400 with os400 for OS/400 support [Monnerat] +- Add crc32_z() and adler32_z() functions with size_t lengths +- Update Visual Studio project files [AraHaan] + +Changes in 1.2.8 (28 Apr 2013) +- Update contrib/minizip/iowin32.c for Windows RT [Vollant] +- Do not force Z_CONST for C++ +- Clean up contrib/vstudio [Roß] +- Correct spelling error in zlib.h +- Fix mixed line endings in contrib/vstudio + +Changes in 1.2.7.3 (13 Apr 2013) +- Fix version numbers and DLL names in contrib/vstudio/*/zlib.rc + +Changes in 1.2.7.2 (13 Apr 2013) +- Change check for a four-byte type back to hexadecimal +- Fix typo in win32/Makefile.msc +- Add casts in gzwrite.c for pointer differences + +Changes in 1.2.7.1 (24 Mar 2013) +- Replace use of unsafe string functions with snprintf if available +- Avoid including stddef.h on Windows for Z_SOLO compile [Niessink] +- Fix gzgetc undefine when Z_PREFIX set [Turk] +- Eliminate use of mktemp in Makefile (not always available) +- Fix bug in 'F' mode for gzopen() +- Add inflateGetDictionary() function +- Correct comment in deflate.h +- Use _snprintf for snprintf in Microsoft C +- On Darwin, only use /usr/bin/libtool if libtool is not Apple +- Delete "--version" file if created by "ar --version" [Richard G.] +- Fix configure check for veracity of compiler error return codes +- Fix CMake compilation of static lib for MSVC2010 x64 +- Remove unused variable in infback9.c +- Fix argument checks in gzlog_compress() and gzlog_write() +- Clean up the usage of z_const and respect const usage within zlib +- Clean up examples/gzlog.[ch] comparisons of different types +- Avoid shift equal to bits in type (caused endless loop) +- Fix uninitialized value bug in gzputc() introduced by const patches +- Fix memory allocation error in examples/zran.c [Nor] +- Fix bug where gzopen(), gzclose() would write an empty file +- Fix bug in gzclose() when gzwrite() runs out of memory +- Check for input buffer malloc failure in examples/gzappend.c +- Add note to contrib/blast to use binary mode in stdio +- Fix comparisons of differently signed integers in contrib/blast +- Check for invalid code length codes in contrib/puff +- Fix serious but very rare decompression bug in inftrees.c +- Update inflateBack() comments, since inflate() can be faster +- Use underscored I/O function names for WINAPI_FAMILY +- Add _tr_flush_bits to the external symbols prefixed by --zprefix +- Add contrib/vstudio/vc10 pre-build step for static only +- Quote --version-script argument in CMakeLists.txt +- Don't specify --version-script on Apple platforms in CMakeLists.txt +- Fix casting error in contrib/testzlib/testzlib.c +- Fix types in contrib/minizip to match result of get_crc_table() +- Simplify contrib/vstudio/vc10 with 'd' suffix +- Add TOP support to win32/Makefile.msc +- Suport i686 and amd64 assembler builds in CMakeLists.txt +- Fix typos in the use of _LARGEFILE64_SOURCE in zconf.h +- Add vc11 and vc12 build files to contrib/vstudio +- Add gzvprintf() as an undocumented function in zlib +- Fix configure for Sun shell +- Remove runtime check in configure for four-byte integer type +- Add casts and consts to ease user conversion to C++ +- Add man pages for minizip and miniunzip +- In Makefile uninstall, don't rm if preceding cd fails +- Do not return Z_BUF_ERROR if deflateParam() has nothing to write + +Changes in 1.2.7 (2 May 2012) +- Replace use of memmove() with a simple copy for portability +- Test for existence of strerror +- Restore gzgetc_ for backward compatibility with 1.2.6 +- Fix build with non-GNU make on Solaris +- Require gcc 4.0 or later on Mac OS X to use the hidden attribute +- Include unistd.h for Watcom C +- Use __WATCOMC__ instead of __WATCOM__ +- Do not use the visibility attribute if NO_VIZ defined +- Improve the detection of no hidden visibility attribute +- Avoid using __int64 for gcc or solo compilation +- Cast to char * in gzprintf to avoid warnings [Zinser] +- Fix make_vms.com for VAX [Zinser] +- Don't use library or built-in byte swaps +- Simplify test and use of gcc hidden attribute +- Fix bug in gzclose_w() when gzwrite() fails to allocate memory +- Add "x" (O_EXCL) and "e" (O_CLOEXEC) modes support to gzopen() +- Fix bug in test/minigzip.c for configure --solo +- Fix contrib/vstudio project link errors [Mohanathas] +- Add ability to choose the builder in make_vms.com [Schweda] +- Add DESTDIR support to mingw32 win32/Makefile.gcc +- Fix comments in win32/Makefile.gcc for proper usage +- Allow overriding the default install locations for cmake +- Generate and install the pkg-config file with cmake +- Build both a static and a shared version of zlib with cmake +- Include version symbols for cmake builds +- If using cmake with MSVC, add the source directory to the includes +- Remove unneeded EXTRA_CFLAGS from win32/Makefile.gcc [Truta] +- Move obsolete emx makefile to old [Truta] +- Allow the use of -Wundef when compiling or using zlib +- Avoid the use of the -u option with mktemp +- Improve inflate() documentation on the use of Z_FINISH +- Recognize clang as gcc +- Add gzopen_w() in Windows for wide character path names +- Rename zconf.h in CMakeLists.txt to move it out of the way +- Add source directory in CMakeLists.txt for building examples +- Look in build directory for zlib.pc in CMakeLists.txt +- Remove gzflags from zlibvc.def in vc9 and vc10 +- Fix contrib/minizip compilation in the MinGW environment +- Update ./configure for Solaris, support --64 [Mooney] +- Remove -R. from Solaris shared build (possible security issue) +- Avoid race condition for parallel make (-j) running example +- Fix type mismatch between get_crc_table() and crc_table +- Fix parsing of version with "-" in CMakeLists.txt [Snider, Ziegler] +- Fix the path to zlib.map in CMakeLists.txt +- Force the native libtool in Mac OS X to avoid GNU libtool [Beebe] +- Add instructions to win32/Makefile.gcc for shared install [Torri] + +Changes in 1.2.6.1 (12 Feb 2012) +- Avoid the use of the Objective-C reserved name "id" +- Include io.h in gzguts.h for Microsoft compilers +- Fix problem with ./configure --prefix and gzgetc macro +- Include gz_header definition when compiling zlib solo +- Put gzflags() functionality back in zutil.c +- Avoid library header include in crc32.c for Z_SOLO +- Use name in GCC_CLASSIC as C compiler for coverage testing, if set +- Minor cleanup in contrib/minizip/zip.c [Vollant] +- Update make_vms.com [Zinser] +- Remove unnecessary gzgetc_ function +- Use optimized byte swap operations for Microsoft and GNU [Snyder] +- Fix minor typo in zlib.h comments [Rzesniowiecki] + +Changes in 1.2.6 (29 Jan 2012) +- Update the Pascal interface in contrib/pascal +- Fix function numbers for gzgetc_ in zlibvc.def files +- Fix configure.ac for contrib/minizip [Schiffer] +- Fix large-entry detection in minizip on 64-bit systems [Schiffer] +- Have ./configure use the compiler return code for error indication +- Fix CMakeLists.txt for cross compilation [McClure] +- Fix contrib/minizip/zip.c for 64-bit architectures [Dalsnes] +- Fix compilation of contrib/minizip on FreeBSD [Marquez] +- Correct suggested usages in win32/Makefile.msc [Shachar, Horvath] +- Include io.h for Turbo C / Borland C on all platforms [Truta] +- Make version explicit in contrib/minizip/configure.ac [Bosmans] +- Avoid warning for no encryption in contrib/minizip/zip.c [Vollant] +- Minor cleanup up contrib/minizip/unzip.c [Vollant] +- Fix bug when compiling minizip with C++ [Vollant] +- Protect for long name and extra fields in contrib/minizip [Vollant] +- Avoid some warnings in contrib/minizip [Vollant] +- Add -I../.. -L../.. to CFLAGS for minizip and miniunzip +- Add missing libs to minizip linker command +- Add support for VPATH builds in contrib/minizip +- Add an --enable-demos option to contrib/minizip/configure +- Add the generation of configure.log by ./configure +- Exit when required parameters not provided to win32/Makefile.gcc +- Have gzputc return the character written instead of the argument +- Use the -m option on ldconfig for BSD systems [Tobias] +- Correct in zlib.map when deflateResetKeep was added + +Changes in 1.2.5.3 (15 Jan 2012) +- Restore gzgetc function for binary compatibility +- Do not use _lseeki64 under Borland C++ [Truta] +- Update win32/Makefile.msc to build test/*.c [Truta] +- Remove old/visualc6 given CMakefile and other alternatives +- Update AS400 build files and documentation [Monnerat] +- Update win32/Makefile.gcc to build test/*.c [Truta] +- Permit stronger flushes after Z_BLOCK flushes +- Avoid extraneous empty blocks when doing empty flushes +- Permit Z_NULL arguments to deflatePending +- Allow deflatePrime() to insert bits in the middle of a stream +- Remove second empty static block for Z_PARTIAL_FLUSH +- Write out all of the available bits when using Z_BLOCK +- Insert the first two strings in the hash table after a flush + +Changes in 1.2.5.2 (17 Dec 2011) +- fix ld error: unable to find version dependency 'ZLIB_1.2.5' +- use relative symlinks for shared libs +- Avoid searching past window for Z_RLE strategy +- Assure that high-water mark initialization is always applied in deflate +- Add assertions to fill_window() in deflate.c to match comments +- Update python link in README +- Correct spelling error in gzread.c +- Fix bug in gzgets() for a concatenated empty gzip stream +- Correct error in comment for gz_make() +- Change gzread() and related to ignore junk after gzip streams +- Allow gzread() and related to continue after gzclearerr() +- Allow gzrewind() and gzseek() after a premature end-of-file +- Simplify gzseek() now that raw after gzip is ignored +- Change gzgetc() to a macro for speed (~40% speedup in testing) +- Fix gzclose() to return the actual error last encountered +- Always add large file support for windows +- Include zconf.h for windows large file support +- Include zconf.h.cmakein for windows large file support +- Update zconf.h.cmakein on make distclean +- Merge vestigial vsnprintf determination from zutil.h to gzguts.h +- Clarify how gzopen() appends in zlib.h comments +- Correct documentation of gzdirect() since junk at end now ignored +- Add a transparent write mode to gzopen() when 'T' is in the mode +- Update python link in zlib man page +- Get inffixed.h and MAKEFIXED result to match +- Add a ./config --solo option to make zlib subset with no library use +- Add undocumented inflateResetKeep() function for CAB file decoding +- Add --cover option to ./configure for gcc coverage testing +- Add #define ZLIB_CONST option to use const in the z_stream interface +- Add comment to gzdopen() in zlib.h to use dup() when using fileno() +- Note behavior of uncompress() to provide as much data as it can +- Add files in contrib/minizip to aid in building libminizip +- Split off AR options in Makefile.in and configure +- Change ON macro to Z_ARG to avoid application conflicts +- Facilitate compilation with Borland C++ for pragmas and vsnprintf +- Include io.h for Turbo C / Borland C++ +- Move example.c and minigzip.c to test/ +- Simplify incomplete code table filling in inflate_table() +- Remove code from inflate.c and infback.c that is impossible to execute +- Test the inflate code with full coverage +- Allow deflateSetDictionary, inflateSetDictionary at any time (in raw) +- Add deflateResetKeep and fix inflateResetKeep to retain dictionary +- Fix gzwrite.c to accommodate reduced memory zlib compilation +- Have inflate() with Z_FINISH avoid the allocation of a window +- Do not set strm->adler when doing raw inflate +- Fix gzeof() to behave just like feof() when read is not past end of file +- Fix bug in gzread.c when end-of-file is reached +- Avoid use of Z_BUF_ERROR in gz* functions except for premature EOF +- Document gzread() capability to read concurrently written files +- Remove hard-coding of resource compiler in CMakeLists.txt [Blammo] + +Changes in 1.2.5.1 (10 Sep 2011) +- Update FAQ entry on shared builds (#13) +- Avoid symbolic argument to chmod in Makefile.in +- Fix bug and add consts in contrib/puff [Oberhumer] +- Update contrib/puff/zeros.raw test file to have all block types +- Add full coverage test for puff in contrib/puff/Makefile +- Fix static-only-build install in Makefile.in +- Fix bug in unzGetCurrentFileInfo() in contrib/minizip [Kuno] +- Add libz.a dependency to shared in Makefile.in for parallel builds +- Spell out "number" (instead of "nb") in zlib.h for total_in, total_out +- Replace $(...) with `...` in configure for non-bash sh [Bowler] +- Add darwin* to Darwin* and solaris* to SunOS\ 5* in configure [Groffen] +- Add solaris* to Linux* in configure to allow gcc use [Groffen] +- Add *bsd* to Linux* case in configure [Bar-Lev] +- Add inffast.obj to dependencies in win32/Makefile.msc +- Correct spelling error in deflate.h [Kohler] +- Change libzdll.a again to libz.dll.a (!) in win32/Makefile.gcc +- Add test to configure for GNU C looking for gcc in output of $cc -v +- Add zlib.pc generation to win32/Makefile.gcc [Weigelt] +- Fix bug in zlib.h for _FILE_OFFSET_BITS set and _LARGEFILE64_SOURCE not +- Add comment in zlib.h that adler32_combine with len2 < 0 makes no sense +- Make NO_DIVIDE option in adler32.c much faster (thanks to John Reiser) +- Make stronger test in zconf.h to include unistd.h for LFS +- Apply Darwin patches for 64-bit file offsets to contrib/minizip [Slack] +- Fix zlib.h LFS support when Z_PREFIX used +- Add updated as400 support (removed from old) [Monnerat] +- Avoid deflate sensitivity to volatile input data +- Avoid division in adler32_combine for NO_DIVIDE +- Clarify the use of Z_FINISH with deflateBound() amount of space +- Set binary for output file in puff.c +- Use u4 type for crc_table to avoid conversion warnings +- Apply casts in zlib.h to avoid conversion warnings +- Add OF to prototypes for adler32_combine_ and crc32_combine_ [Miller] +- Improve inflateSync() documentation to note indeterminancy +- Add deflatePending() function to return the amount of pending output +- Correct the spelling of "specification" in FAQ [Randers-Pehrson] +- Add a check in configure for stdarg.h, use for gzprintf() +- Check that pointers fit in ints when gzprint() compiled old style +- Add dummy name before $(SHAREDLIBV) in Makefile [Bar-Lev, Bowler] +- Delete line in configure that adds -L. libz.a to LDFLAGS [Weigelt] +- Add debug records in assmebler code [Londer] +- Update RFC references to use http://tools.ietf.org/html/... [Li] +- Add --archs option, use of libtool to configure for Mac OS X [Borstel] + +Changes in 1.2.5 (19 Apr 2010) +- Disable visibility attribute in win32/Makefile.gcc [Bar-Lev] +- Default to libdir as sharedlibdir in configure [Nieder] +- Update copyright dates on modified source files +- Update trees.c to be able to generate modified trees.h +- Exit configure for MinGW, suggesting win32/Makefile.gcc +- Check for NULL path in gz_open [Homurlu] + +Changes in 1.2.4.5 (18 Apr 2010) +- Set sharedlibdir in configure [Torok] +- Set LDFLAGS in Makefile.in [Bar-Lev] +- Avoid mkdir objs race condition in Makefile.in [Bowler] +- Add ZLIB_INTERNAL in front of internal inter-module functions and arrays +- Define ZLIB_INTERNAL to hide internal functions and arrays for GNU C +- Don't use hidden attribute when it is a warning generator (e.g. Solaris) + +Changes in 1.2.4.4 (18 Apr 2010) +- Fix CROSS_PREFIX executable testing, CHOST extract, mingw* [Torok] +- Undefine _LARGEFILE64_SOURCE in zconf.h if it is zero, but not if empty +- Try to use bash or ksh regardless of functionality of /bin/sh +- Fix configure incompatibility with NetBSD sh +- Remove attempt to run under bash or ksh since have better NetBSD fix +- Fix win32/Makefile.gcc for MinGW [Bar-Lev] +- Add diagnostic messages when using CROSS_PREFIX in configure +- Added --sharedlibdir option to configure [Weigelt] +- Use hidden visibility attribute when available [Frysinger] + +Changes in 1.2.4.3 (10 Apr 2010) +- Only use CROSS_PREFIX in configure for ar and ranlib if they exist +- Use CROSS_PREFIX for nm [Bar-Lev] +- Assume _LARGEFILE64_SOURCE defined is equivalent to true +- Avoid use of undefined symbols in #if with && and || +- Make *64 prototypes in gzguts.h consistent with functions +- Add -shared load option for MinGW in configure [Bowler] +- Move z_off64_t to public interface, use instead of off64_t +- Remove ! from shell test in configure (not portable to Solaris) +- Change +0 macro tests to -0 for possibly increased portability + +Changes in 1.2.4.2 (9 Apr 2010) +- Add consistent carriage returns to readme.txt's in masmx86 and masmx64 +- Really provide prototypes for *64 functions when building without LFS +- Only define unlink() in minigzip.c if unistd.h not included +- Update README to point to contrib/vstudio project files +- Move projects/vc6 to old/ and remove projects/ +- Include stdlib.h in minigzip.c for setmode() definition under WinCE +- Clean up assembler builds in win32/Makefile.msc [Rowe] +- Include sys/types.h for Microsoft for off_t definition +- Fix memory leak on error in gz_open() +- Symbolize nm as $NM in configure [Weigelt] +- Use TEST_LDSHARED instead of LDSHARED to link test programs [Weigelt] +- Add +0 to _FILE_OFFSET_BITS and _LFS64_LARGEFILE in case not defined +- Fix bug in gzeof() to take into account unused input data +- Avoid initialization of structures with variables in puff.c +- Updated win32/README-WIN32.txt [Rowe] + +Changes in 1.2.4.1 (28 Mar 2010) +- Remove the use of [a-z] constructs for sed in configure [gentoo 310225] +- Remove $(SHAREDLIB) from LIBS in Makefile.in [Creech] +- Restore "for debugging" comment on sprintf() in gzlib.c +- Remove fdopen for MVS from gzguts.h +- Put new README-WIN32.txt in win32 [Rowe] +- Add check for shell to configure and invoke another shell if needed +- Fix big fat stinking bug in gzseek() on uncompressed files +- Remove vestigial F_OPEN64 define in zutil.h +- Set and check the value of _LARGEFILE_SOURCE and _LARGEFILE64_SOURCE +- Avoid errors on non-LFS systems when applications define LFS macros +- Set EXE to ".exe" in configure for MINGW [Kahle] +- Match crc32() in crc32.c exactly to the prototype in zlib.h [Sherrill] +- Add prefix for cross-compilation in win32/makefile.gcc [Bar-Lev] +- Add DLL install in win32/makefile.gcc [Bar-Lev] +- Allow Linux* or linux* from uname in configure [Bar-Lev] +- Allow ldconfig to be redefined in configure and Makefile.in [Bar-Lev] +- Add cross-compilation prefixes to configure [Bar-Lev] +- Match type exactly in gz_load() invocation in gzread.c +- Match type exactly of zcalloc() in zutil.c to zlib.h alloc_func +- Provide prototypes for *64 functions when building zlib without LFS +- Don't use -lc when linking shared library on MinGW +- Remove errno.h check in configure and vestigial errno code in zutil.h + +Changes in 1.2.4 (14 Mar 2010) +- Fix VER3 extraction in configure for no fourth subversion +- Update zlib.3, add docs to Makefile.in to make .pdf out of it +- Add zlib.3.pdf to distribution +- Don't set error code in gzerror() if passed pointer is NULL +- Apply destination directory fixes to CMakeLists.txt [Lowman] +- Move #cmakedefine's to a new zconf.in.cmakein +- Restore zconf.h for builds that don't use configure or cmake +- Add distclean to dummy Makefile for convenience +- Update and improve INDEX, README, and FAQ +- Update CMakeLists.txt for the return of zconf.h [Lowman] +- Update contrib/vstudio/vc9 and vc10 [Vollant] +- Change libz.dll.a back to libzdll.a in win32/Makefile.gcc +- Apply license and readme changes to contrib/asm686 [Raiter] +- Check file name lengths and add -c option in minigzip.c [Li] +- Update contrib/amd64 and contrib/masmx86/ [Vollant] +- Avoid use of "eof" parameter in trees.c to not shadow library variable +- Update make_vms.com for removal of zlibdefs.h [Zinser] +- Update assembler code and vstudio projects in contrib [Vollant] +- Remove outdated assembler code contrib/masm686 and contrib/asm586 +- Remove old vc7 and vc8 from contrib/vstudio +- Update win32/Makefile.msc, add ZLIB_VER_SUBREVISION [Rowe] +- Fix memory leaks in gzclose_r() and gzclose_w(), file leak in gz_open() +- Add contrib/gcc_gvmat64 for longest_match and inflate_fast [Vollant] +- Remove *64 functions from win32/zlib.def (they're not 64-bit yet) +- Fix bug in void-returning vsprintf() case in gzwrite.c +- Fix name change from inflate.h in contrib/inflate86/inffas86.c +- Check if temporary file exists before removing in make_vms.com [Zinser] +- Fix make install and uninstall for --static option +- Fix usage of _MSC_VER in gzguts.h and zutil.h [Truta] +- Update readme.txt in contrib/masmx64 and masmx86 to assemble + +Changes in 1.2.3.9 (21 Feb 2010) +- Expunge gzio.c +- Move as400 build information to old +- Fix updates in contrib/minizip and contrib/vstudio +- Add const to vsnprintf test in configure to avoid warnings [Weigelt] +- Delete zconf.h (made by configure) [Weigelt] +- Change zconf.in.h to zconf.h.in per convention [Weigelt] +- Check for NULL buf in gzgets() +- Return empty string for gzgets() with len == 1 (like fgets()) +- Fix description of gzgets() in zlib.h for end-of-file, NULL return +- Update minizip to 1.1 [Vollant] +- Avoid MSVC loss of data warnings in gzread.c, gzwrite.c +- Note in zlib.h that gzerror() should be used to distinguish from EOF +- Remove use of snprintf() from gzlib.c +- Fix bug in gzseek() +- Update contrib/vstudio, adding vc9 and vc10 [Kuno, Vollant] +- Fix zconf.h generation in CMakeLists.txt [Lowman] +- Improve comments in zconf.h where modified by configure + +Changes in 1.2.3.8 (13 Feb 2010) +- Clean up text files (tabs, trailing whitespace, etc.) [Oberhumer] +- Use z_off64_t in gz_zero() and gz_skip() to match state->skip +- Avoid comparison problem when sizeof(int) == sizeof(z_off64_t) +- Revert to Makefile.in from 1.2.3.6 (live with the clutter) +- Fix missing error return in gzflush(), add zlib.h note +- Add *64 functions to zlib.map [Levin] +- Fix signed/unsigned comparison in gz_comp() +- Use SFLAGS when testing shared linking in configure +- Add --64 option to ./configure to use -m64 with gcc +- Fix ./configure --help to correctly name options +- Have make fail if a test fails [Levin] +- Avoid buffer overrun in contrib/masmx64/gvmat64.asm [Simpson] +- Remove assembler object files from contrib + +Changes in 1.2.3.7 (24 Jan 2010) +- Always gzopen() with O_LARGEFILE if available +- Fix gzdirect() to work immediately after gzopen() or gzdopen() +- Make gzdirect() more precise when the state changes while reading +- Improve zlib.h documentation in many places +- Catch memory allocation failure in gz_open() +- Complete close operation if seek forward in gzclose_w() fails +- Return Z_ERRNO from gzclose_r() if close() fails +- Return Z_STREAM_ERROR instead of EOF for gzclose() being passed NULL +- Return zero for gzwrite() errors to match zlib.h description +- Return -1 on gzputs() error to match zlib.h description +- Add zconf.in.h to allow recovery from configure modification [Weigelt] +- Fix static library permissions in Makefile.in [Weigelt] +- Avoid warnings in configure tests that hide functionality [Weigelt] +- Add *BSD and DragonFly to Linux case in configure [gentoo 123571] +- Change libzdll.a to libz.dll.a in win32/Makefile.gcc [gentoo 288212] +- Avoid access of uninitialized data for first inflateReset2 call [Gomes] +- Keep object files in subdirectories to reduce the clutter somewhat +- Remove default Makefile and zlibdefs.h, add dummy Makefile +- Add new external functions to Z_PREFIX, remove duplicates, z_z_ -> z_ +- Remove zlibdefs.h completely -- modify zconf.h instead + +Changes in 1.2.3.6 (17 Jan 2010) +- Avoid void * arithmetic in gzread.c and gzwrite.c +- Make compilers happier with const char * for gz_error message +- Avoid unused parameter warning in inflate.c +- Avoid signed-unsigned comparison warning in inflate.c +- Indent #pragma's for traditional C +- Fix usage of strwinerror() in glib.c, change to gz_strwinerror() +- Correct email address in configure for system options +- Update make_vms.com and add make_vms.com to contrib/minizip [Zinser] +- Update zlib.map [Brown] +- Fix Makefile.in for Solaris 10 make of example64 and minizip64 [Torok] +- Apply various fixes to CMakeLists.txt [Lowman] +- Add checks on len in gzread() and gzwrite() +- Add error message for no more room for gzungetc() +- Remove zlib version check in gzwrite() +- Defer compression of gzprintf() result until need to +- Use snprintf() in gzdopen() if available +- Remove USE_MMAP configuration determination (only used by minigzip) +- Remove examples/pigz.c (available separately) +- Update examples/gun.c to 1.6 + +Changes in 1.2.3.5 (8 Jan 2010) +- Add space after #if in zutil.h for some compilers +- Fix relatively harmless bug in deflate_fast() [Exarevsky] +- Fix same problem in deflate_slow() +- Add $(SHAREDLIBV) to LIBS in Makefile.in [Brown] +- Add deflate_rle() for faster Z_RLE strategy run-length encoding +- Add deflate_huff() for faster Z_HUFFMAN_ONLY encoding +- Change name of "write" variable in inffast.c to avoid library collisions +- Fix premature EOF from gzread() in gzio.c [Brown] +- Use zlib header window size if windowBits is 0 in inflateInit2() +- Remove compressBound() call in deflate.c to avoid linking compress.o +- Replace use of errno in gz* with functions, support WinCE [Alves] +- Provide alternative to perror() in minigzip.c for WinCE [Alves] +- Don't use _vsnprintf on later versions of MSVC [Lowman] +- Add CMake build script and input file [Lowman] +- Update contrib/minizip to 1.1 [Svensson, Vollant] +- Moved nintendods directory from contrib to . +- Replace gzio.c with a new set of routines with the same functionality +- Add gzbuffer(), gzoffset(), gzclose_r(), gzclose_w() as part of above +- Update contrib/minizip to 1.1b +- Change gzeof() to return 0 on error instead of -1 to agree with zlib.h + +Changes in 1.2.3.4 (21 Dec 2009) +- Use old school .SUFFIXES in Makefile.in for FreeBSD compatibility +- Update comments in configure and Makefile.in for default --shared +- Fix test -z's in configure [Marquess] +- Build examplesh and minigzipsh when not testing +- Change NULL's to Z_NULL's in deflate.c and in comments in zlib.h +- Import LDFLAGS from the environment in configure +- Fix configure to populate SFLAGS with discovered CFLAGS options +- Adapt make_vms.com to the new Makefile.in [Zinser] +- Add zlib2ansi script for C++ compilation [Marquess] +- Add _FILE_OFFSET_BITS=64 test to make test (when applicable) +- Add AMD64 assembler code for longest match to contrib [Teterin] +- Include options from $SFLAGS when doing $LDSHARED +- Simplify 64-bit file support by introducing z_off64_t type +- Make shared object files in objs directory to work around old Sun cc +- Use only three-part version number for Darwin shared compiles +- Add rc option to ar in Makefile.in for when ./configure not run +- Add -WI,-rpath,. to LDFLAGS for OSF 1 V4* +- Set LD_LIBRARYN32_PATH for SGI IRIX shared compile +- Protect against _FILE_OFFSET_BITS being defined when compiling zlib +- Rename Makefile.in targets allstatic to static and allshared to shared +- Fix static and shared Makefile.in targets to be independent +- Correct error return bug in gz_open() by setting state [Brown] +- Put spaces before ;;'s in configure for better sh compatibility +- Add pigz.c (parallel implementation of gzip) to examples/ +- Correct constant in crc32.c to UL [Leventhal] +- Reject negative lengths in crc32_combine() +- Add inflateReset2() function to work like inflateEnd()/inflateInit2() +- Include sys/types.h for _LARGEFILE64_SOURCE [Brown] +- Correct typo in doc/algorithm.txt [Janik] +- Fix bug in adler32_combine() [Zhu] +- Catch missing-end-of-block-code error in all inflates and in puff + Assures that random input to inflate eventually results in an error +- Added enough.c (calculation of ENOUGH for inftrees.h) to examples/ +- Update ENOUGH and its usage to reflect discovered bounds +- Fix gzerror() error report on empty input file [Brown] +- Add ush casts in trees.c to avoid pedantic runtime errors +- Fix typo in zlib.h uncompress() description [Reiss] +- Correct inflate() comments with regard to automatic header detection +- Remove deprecation comment on Z_PARTIAL_FLUSH (it stays) +- Put new version of gzlog (2.0) in examples with interruption recovery +- Add puff compile option to permit invalid distance-too-far streams +- Add puff TEST command options, ability to read piped input +- Prototype the *64 functions in zlib.h when _FILE_OFFSET_BITS == 64, but + _LARGEFILE64_SOURCE not defined +- Fix Z_FULL_FLUSH to truly erase the past by resetting s->strstart +- Fix deflateSetDictionary() to use all 32K for output consistency +- Remove extraneous #define MIN_LOOKAHEAD in deflate.c (in deflate.h) +- Clear bytes after deflate lookahead to avoid use of uninitialized data +- Change a limit in inftrees.c to be more transparent to Coverity Prevent +- Update win32/zlib.def with exported symbols from zlib.h +- Correct spelling errors in zlib.h [Willem, Sobrado] +- Allow Z_BLOCK for deflate() to force a new block +- Allow negative bits in inflatePrime() to delete existing bit buffer +- Add Z_TREES flush option to inflate() to return at end of trees +- Add inflateMark() to return current state information for random access +- Add Makefile for NintendoDS to contrib [Costa] +- Add -w in configure compile tests to avoid spurious warnings [Beucler] +- Fix typos in zlib.h comments for deflateSetDictionary() +- Fix EOF detection in transparent gzread() [Maier] + +Changes in 1.2.3.3 (2 October 2006) +- Make --shared the default for configure, add a --static option +- Add compile option to permit invalid distance-too-far streams +- Add inflateUndermine() function which is required to enable above +- Remove use of "this" variable name for C++ compatibility [Marquess] +- Add testing of shared library in make test, if shared library built +- Use ftello() and fseeko() if available instead of ftell() and fseek() +- Provide two versions of all functions that use the z_off_t type for + binary compatibility -- a normal version and a 64-bit offset version, + per the Large File Support Extension when _LARGEFILE64_SOURCE is + defined; use the 64-bit versions by default when _FILE_OFFSET_BITS + is defined to be 64 +- Add a --uname= option to configure to perhaps help with cross-compiling + +Changes in 1.2.3.2 (3 September 2006) +- Turn off silly Borland warnings [Hay] +- Use off64_t and define _LARGEFILE64_SOURCE when present +- Fix missing dependency on inffixed.h in Makefile.in +- Rig configure --shared to build both shared and static [Teredesai, Truta] +- Remove zconf.in.h and instead create a new zlibdefs.h file +- Fix contrib/minizip/unzip.c non-encrypted after encrypted [Vollant] +- Add treebuild.xml (see http://treebuild.metux.de/) [Weigelt] + +Changes in 1.2.3.1 (16 August 2006) +- Add watcom directory with OpenWatcom make files [Daniel] +- Remove #undef of FAR in zconf.in.h for MVS [Fedtke] +- Update make_vms.com [Zinser] +- Use -fPIC for shared build in configure [Teredesai, Nicholson] +- Use only major version number for libz.so on IRIX and OSF1 [Reinholdtsen] +- Use fdopen() (not _fdopen()) for Interix in zutil.h [Bäck] +- Add some FAQ entries about the contrib directory +- Update the MVS question in the FAQ +- Avoid extraneous reads after EOF in gzio.c [Brown] +- Correct spelling of "successfully" in gzio.c [Randers-Pehrson] +- Add comments to zlib.h about gzerror() usage [Brown] +- Set extra flags in gzip header in gzopen() like deflate() does +- Make configure options more compatible with double-dash conventions + [Weigelt] +- Clean up compilation under Solaris SunStudio cc [Rowe, Reinholdtsen] +- Fix uninstall target in Makefile.in [Truta] +- Add pkgconfig support [Weigelt] +- Use $(DESTDIR) macro in Makefile.in [Reinholdtsen, Weigelt] +- Replace set_data_type() with a more accurate detect_data_type() in + trees.c, according to the txtvsbin.txt document [Truta] +- Swap the order of #include and #include "zlib.h" in + gzio.c, example.c and minigzip.c [Truta] +- Shut up annoying VS2005 warnings about standard C deprecation [Rowe, + Truta] (where?) +- Fix target "clean" from win32/Makefile.bor [Truta] +- Create .pdb and .manifest files in win32/makefile.msc [Ziegler, Rowe] +- Update zlib www home address in win32/DLL_FAQ.txt [Truta] +- Update contrib/masmx86/inffas32.asm for VS2005 [Vollant, Van Wassenhove] +- Enable browse info in the "Debug" and "ASM Debug" configurations in + the Visual C++ 6 project, and set (non-ASM) "Debug" as default [Truta] +- Add pkgconfig support [Weigelt] +- Add ZLIB_VER_MAJOR, ZLIB_VER_MINOR and ZLIB_VER_REVISION in zlib.h, + for use in win32/zlib1.rc [Polushin, Rowe, Truta] +- Add a document that explains the new text detection scheme to + doc/txtvsbin.txt [Truta] +- Add rfc1950.txt, rfc1951.txt and rfc1952.txt to doc/ [Truta] +- Move algorithm.txt into doc/ [Truta] +- Synchronize FAQ with website +- Fix compressBound(), was low for some pathological cases [Fearnley] +- Take into account wrapper variations in deflateBound() +- Set examples/zpipe.c input and output to binary mode for Windows +- Update examples/zlib_how.html with new zpipe.c (also web site) +- Fix some warnings in examples/gzlog.c and examples/zran.c (it seems + that gcc became pickier in 4.0) +- Add zlib.map for Linux: "All symbols from zlib-1.1.4 remain + un-versioned, the patch adds versioning only for symbols introduced in + zlib-1.2.0 or later. It also declares as local those symbols which are + not designed to be exported." [Levin] +- Update Z_PREFIX list in zconf.in.h, add --zprefix option to configure +- Do not initialize global static by default in trees.c, add a response + NO_INIT_GLOBAL_POINTERS to initialize them if needed [Marquess] +- Don't use strerror() in gzio.c under WinCE [Yakimov] +- Don't use errno.h in zutil.h under WinCE [Yakimov] +- Move arguments for AR to its usage to allow replacing ar [Marot] +- Add HAVE_VISIBILITY_PRAGMA in zconf.in.h for Mozilla [Randers-Pehrson] +- Improve inflateInit() and inflateInit2() documentation +- Fix structure size comment in inflate.h +- Change configure help option from --h* to --help [Santos] + +Changes in 1.2.3 (18 July 2005) +- Apply security vulnerability fixes to contrib/infback9 as well +- Clean up some text files (carriage returns, trailing space) +- Update testzlib, vstudio, masmx64, and masmx86 in contrib [Vollant] + +Changes in 1.2.2.4 (11 July 2005) +- Add inflatePrime() function for starting inflation at bit boundary +- Avoid some Visual C warnings in deflate.c +- Avoid more silly Visual C warnings in inflate.c and inftrees.c for 64-bit + compile +- Fix some spelling errors in comments [Betts] +- Correct inflateInit2() error return documentation in zlib.h +- Add zran.c example of compressed data random access to examples + directory, shows use of inflatePrime() +- Fix cast for assignments to strm->state in inflate.c and infback.c +- Fix zlibCompileFlags() in zutil.c to use 1L for long shifts [Oberhumer] +- Move declarations of gf2 functions to right place in crc32.c [Oberhumer] +- Add cast in trees.c t avoid a warning [Oberhumer] +- Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer] +- Update make_vms.com [Zinser] +- Initialize state->write in inflateReset() since copied in inflate_fast() +- Be more strict on incomplete code sets in inflate_table() and increase + ENOUGH and MAXD -- this repairs a possible security vulnerability for + invalid inflate input. Thanks to Tavis Ormandy and Markus Oberhumer for + discovering the vulnerability and providing test cases. +- Add ia64 support to configure for HP-UX [Smith] +- Add error return to gzread() for format or i/o error [Levin] +- Use malloc.h for OS/2 [Necasek] + +Changes in 1.2.2.3 (27 May 2005) +- Replace 1U constants in inflate.c and inftrees.c for 64-bit compile +- Typecast fread() return values in gzio.c [Vollant] +- Remove trailing space in minigzip.c outmode (VC++ can't deal with it) +- Fix crc check bug in gzread() after gzungetc() [Heiner] +- Add the deflateTune() function to adjust internal compression parameters +- Add a fast gzip decompressor, gun.c, to examples (use of inflateBack) +- Remove an incorrect assertion in examples/zpipe.c +- Add C++ wrapper in infback9.h [Donais] +- Fix bug in inflateCopy() when decoding fixed codes +- Note in zlib.h how much deflateSetDictionary() actually uses +- Remove USE_DICT_HEAD in deflate.c (would mess up inflate if used) +- Add _WIN32_WCE to define WIN32 in zconf.in.h [Spencer] +- Don't include stderr.h or errno.h for _WIN32_WCE in zutil.h [Spencer] +- Add gzdirect() function to indicate transparent reads +- Update contrib/minizip [Vollant] +- Fix compilation of deflate.c when both ASMV and FASTEST [Oberhumer] +- Add casts in crc32.c to avoid warnings [Oberhumer] +- Add contrib/masmx64 [Vollant] +- Update contrib/asm586, asm686, masmx86, testzlib, vstudio [Vollant] + +Changes in 1.2.2.2 (30 December 2004) +- Replace structure assignments in deflate.c and inflate.c with zmemcpy to + avoid implicit memcpy calls (portability for no-library compilation) +- Increase sprintf() buffer size in gzdopen() to allow for large numbers +- Add INFLATE_STRICT to check distances against zlib header +- Improve WinCE errno handling and comments [Chang] +- Remove comment about no gzip header processing in FAQ +- Add Z_FIXED strategy option to deflateInit2() to force fixed trees +- Add updated make_vms.com [Coghlan], update README +- Create a new "examples" directory, move gzappend.c there, add zpipe.c, + fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html. +- Add FAQ entry and comments in deflate.c on uninitialized memory access +- Add Solaris 9 make options in configure [Gilbert] +- Allow strerror() usage in gzio.c for STDC +- Fix DecompressBuf in contrib/delphi/ZLib.pas [ManChesTer] +- Update contrib/masmx86/inffas32.asm and gvmat32.asm [Vollant] +- Use z_off_t for adler32_combine() and crc32_combine() lengths +- Make adler32() much faster for small len +- Use OS_CODE in deflate() default gzip header + +Changes in 1.2.2.1 (31 October 2004) +- Allow inflateSetDictionary() call for raw inflate +- Fix inflate header crc check bug for file names and comments +- Add deflateSetHeader() and gz_header structure for custom gzip headers +- Add inflateGetheader() to retrieve gzip headers +- Add crc32_combine() and adler32_combine() functions +- Add alloc_func, free_func, in_func, out_func to Z_PREFIX list +- Use zstreamp consistently in zlib.h (inflate_back functions) +- Remove GUNZIP condition from definition of inflate_mode in inflate.h + and in contrib/inflate86/inffast.S [Truta, Anderson] +- Add support for AMD64 in contrib/inflate86/inffas86.c [Anderson] +- Update projects/README.projects and projects/visualc6 [Truta] +- Update win32/DLL_FAQ.txt [Truta] +- Avoid warning under NO_GZCOMPRESS in gzio.c; fix typo [Truta] +- Deprecate Z_ASCII; use Z_TEXT instead [Truta] +- Use a new algorithm for setting strm->data_type in trees.c [Truta] +- Do not define an exit() prototype in zutil.c unless DEBUG defined +- Remove prototype of exit() from zutil.c, example.c, minigzip.c [Truta] +- Add comment in zlib.h for Z_NO_FLUSH parameter to deflate() +- Fix Darwin build version identification [Peterson] + +Changes in 1.2.2 (3 October 2004) +- Update zlib.h comments on gzip in-memory processing +- Set adler to 1 in inflateReset() to support Java test suite [Walles] +- Add contrib/dotzlib [Ravn] +- Update win32/DLL_FAQ.txt [Truta] +- Update contrib/minizip [Vollant] +- Move contrib/visual-basic.txt to old/ [Truta] +- Fix assembler builds in projects/visualc6/ [Truta] + +Changes in 1.2.1.2 (9 September 2004) +- Update INDEX file +- Fix trees.c to update strm->data_type (no one ever noticed!) +- Fix bug in error case in inflate.c, infback.c, and infback9.c [Brown] +- Add "volatile" to crc table flag declaration (for DYNAMIC_CRC_TABLE) +- Add limited multitasking protection to DYNAMIC_CRC_TABLE +- Add NO_vsnprintf for VMS in zutil.h [Mozilla] +- Don't declare strerror() under VMS [Mozilla] +- Add comment to DYNAMIC_CRC_TABLE to use get_crc_table() to initialize +- Update contrib/ada [Anisimkov] +- Update contrib/minizip [Vollant] +- Fix configure to not hardcode directories for Darwin [Peterson] +- Fix gzio.c to not return error on empty files [Brown] +- Fix indentation; update version in contrib/delphi/ZLib.pas and + contrib/pascal/zlibpas.pas [Truta] +- Update mkasm.bat in contrib/masmx86 [Truta] +- Update contrib/untgz [Truta] +- Add projects/README.projects [Truta] +- Add project for MS Visual C++ 6.0 in projects/visualc6 [Cadieux, Truta] +- Update win32/DLL_FAQ.txt [Truta] +- Update list of Z_PREFIX symbols in zconf.h [Randers-Pehrson, Truta] +- Remove an unnecessary assignment to curr in inftrees.c [Truta] +- Add OS/2 to exe builds in configure [Poltorak] +- Remove err dummy parameter in zlib.h [Kientzle] + +Changes in 1.2.1.1 (9 January 2004) +- Update email address in README +- Several FAQ updates +- Fix a big fat bug in inftrees.c that prevented decoding valid + dynamic blocks with only literals and no distance codes -- + Thanks to "Hot Emu" for the bug report and sample file +- Add a note to puff.c on no distance codes case. + +Changes in 1.2.1 (17 November 2003) +- Remove a tab in contrib/gzappend/gzappend.c +- Update some interfaces in contrib for new zlib functions +- Update zlib version number in some contrib entries +- Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta] +- Support shared libraries on Hurd and KFreeBSD [Brown] +- Fix error in NO_DIVIDE option of adler32.c + +Changes in 1.2.0.8 (4 November 2003) +- Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas +- Add experimental NO_DIVIDE #define in adler32.c + - Possibly faster on some processors (let me know if it is) +- Correct Z_BLOCK to not return on first inflate call if no wrap +- Fix strm->data_type on inflate() return to correctly indicate EOB +- Add deflatePrime() function for appending in the middle of a byte +- Add contrib/gzappend for an example of appending to a stream +- Update win32/DLL_FAQ.txt [Truta] +- Delete Turbo C comment in README [Truta] +- Improve some indentation in zconf.h [Truta] +- Fix infinite loop on bad input in configure script [Church] +- Fix gzeof() for concatenated gzip files [Johnson] +- Add example to contrib/visual-basic.txt [Michael B.] +- Add -p to mkdir's in Makefile.in [vda] +- Fix configure to properly detect presence or lack of printf functions +- Add AS400 support [Monnerat] +- Add a little Cygwin support [Wilson] + +Changes in 1.2.0.7 (21 September 2003) +- Correct some debug formats in contrib/infback9 +- Cast a type in a debug statement in trees.c +- Change search and replace delimiter in configure from % to # [Beebe] +- Update contrib/untgz to 0.2 with various fixes [Truta] +- Add build support for Amiga [Nikl] +- Remove some directories in old that have been updated to 1.2 +- Add dylib building for Mac OS X in configure and Makefile.in +- Remove old distribution stuff from Makefile +- Update README to point to DLL_FAQ.txt, and add comment on Mac OS X +- Update links in README + +Changes in 1.2.0.6 (13 September 2003) +- Minor FAQ updates +- Update contrib/minizip to 1.00 [Vollant] +- Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta] +- Update POSTINC comment for 68060 [Nikl] +- Add contrib/infback9 with deflate64 decoding (unsupported) +- For MVS define NO_vsnprintf and undefine FAR [van Burik] +- Add pragma for fdopen on MVS [van Burik] + +Changes in 1.2.0.5 (8 September 2003) +- Add OF to inflateBackEnd() declaration in zlib.h +- Remember start when using gzdopen in the middle of a file +- Use internal off_t counters in gz* functions to properly handle seeks +- Perform more rigorous check for distance-too-far in inffast.c +- Add Z_BLOCK flush option to return from inflate at block boundary +- Set strm->data_type on return from inflate + - Indicate bits unused, if at block boundary, and if in last block +- Replace size_t with ptrdiff_t in crc32.c, and check for correct size +- Add condition so old NO_DEFLATE define still works for compatibility +- FAQ update regarding the Windows DLL [Truta] +- INDEX update: add qnx entry, remove aix entry [Truta] +- Install zlib.3 into mandir [Wilson] +- Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta] +- Adapt the zlib interface to the new DLL convention guidelines [Truta] +- Introduce ZLIB_WINAPI macro to allow the export of functions using + the WINAPI calling convention, for Visual Basic [Vollant, Truta] +- Update msdos and win32 scripts and makefiles [Truta] +- Export symbols by name, not by ordinal, in win32/zlib.def [Truta] +- Add contrib/ada [Anisimkov] +- Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta] +- Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant] +- Add contrib/masm686 [Truta] +- Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm + [Truta, Vollant] +- Update contrib/delphi; rename to contrib/pascal; add example [Truta] +- Remove contrib/delphi2; add a new contrib/delphi [Truta] +- Avoid inclusion of the nonstandard in contrib/iostream, + and fix some method prototypes [Truta] +- Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip + [Truta] +- Avoid the use of backslash (\) in contrib/minizip [Vollant] +- Fix file time handling in contrib/untgz; update makefiles [Truta] +- Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines + [Vollant] +- Remove contrib/vstudio/vc15_16 [Vollant] +- Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta] +- Update README.contrib [Truta] +- Invert the assignment order of match_head and s->prev[...] in + INSERT_STRING [Truta] +- Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings + [Truta] +- Compare function pointers with 0, not with NULL or Z_NULL [Truta] +- Fix prototype of syncsearch in inflate.c [Truta] +- Introduce ASMINF macro to be enabled when using an ASM implementation + of inflate_fast [Truta] +- Change NO_DEFLATE to NO_GZCOMPRESS [Truta] +- Modify test_gzio in example.c to take a single file name as a + parameter [Truta] +- Exit the example.c program if gzopen fails [Truta] +- Add type casts around strlen in example.c [Truta] +- Remove casting to sizeof in minigzip.c; give a proper type + to the variable compared with SUFFIX_LEN [Truta] +- Update definitions of STDC and STDC99 in zconf.h [Truta] +- Synchronize zconf.h with the new Windows DLL interface [Truta] +- Use SYS16BIT instead of __32BIT__ to distinguish between + 16- and 32-bit platforms [Truta] +- Use far memory allocators in small 16-bit memory models for + Turbo C [Truta] +- Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in + zlibCompileFlags [Truta] +- Cygwin has vsnprintf [Wilson] +- In Windows16, OS_CODE is 0, as in MSDOS [Truta] +- In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson] + +Changes in 1.2.0.4 (10 August 2003) +- Minor FAQ updates +- Be more strict when checking inflateInit2's windowBits parameter +- Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well +- Add gzip wrapper option to deflateInit2 using windowBits +- Add updated QNX rule in configure and qnx directory [Bonnefoy] +- Make inflate distance-too-far checks more rigorous +- Clean up FAR usage in inflate +- Add casting to sizeof() in gzio.c and minigzip.c + +Changes in 1.2.0.3 (19 July 2003) +- Fix silly error in gzungetc() implementation [Vollant] +- Update contrib/minizip and contrib/vstudio [Vollant] +- Fix printf format in example.c +- Correct cdecl support in zconf.in.h [Anisimkov] +- Minor FAQ updates + +Changes in 1.2.0.2 (13 July 2003) +- Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons +- Attempt to avoid warnings in crc32.c for pointer-int conversion +- Add AIX to configure, remove aix directory [Bakker] +- Add some casts to minigzip.c +- Improve checking after insecure sprintf() or vsprintf() calls +- Remove #elif's from crc32.c +- Change leave label to inf_leave in inflate.c and infback.c to avoid + library conflicts +- Remove inflate gzip decoding by default--only enable gzip decoding by + special request for stricter backward compatibility +- Add zlibCompileFlags() function to return compilation information +- More typecasting in deflate.c to avoid warnings +- Remove leading underscore from _Capital #defines [Truta] +- Fix configure to link shared library when testing +- Add some Windows CE target adjustments [Mai] +- Remove #define ZLIB_DLL in zconf.h [Vollant] +- Add zlib.3 [Rodgers] +- Update RFC URL in deflate.c and algorithm.txt [Mai] +- Add zlib_dll_FAQ.txt to contrib [Truta] +- Add UL to some constants [Truta] +- Update minizip and vstudio [Vollant] +- Remove vestigial NEED_DUMMY_RETURN from zconf.in.h +- Expand use of NO_DUMMY_DECL to avoid all dummy structures +- Added iostream3 to contrib [Schwardt] +- Replace rewind() with fseek() for WinCE [Truta] +- Improve setting of zlib format compression level flags + - Report 0 for huffman and rle strategies and for level == 0 or 1 + - Report 2 only for level == 6 +- Only deal with 64K limit when necessary at compile time [Truta] +- Allow TOO_FAR check to be turned off at compile time [Truta] +- Add gzclearerr() function [Souza] +- Add gzungetc() function + +Changes in 1.2.0.1 (17 March 2003) +- Add Z_RLE strategy for run-length encoding [Truta] + - When Z_RLE requested, restrict matches to distance one + - Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE +- Correct FASTEST compilation to allow level == 0 +- Clean up what gets compiled for FASTEST +- Incorporate changes to zconf.in.h [Vollant] + - Refine detection of Turbo C need for dummy returns + - Refine ZLIB_DLL compilation + - Include additional header file on VMS for off_t typedef +- Try to use _vsnprintf where it supplants vsprintf [Vollant] +- Add some casts in inffast.c +- Enchance comments in zlib.h on what happens if gzprintf() tries to + write more than 4095 bytes before compression +- Remove unused state from inflateBackEnd() +- Remove exit(0) from minigzip.c, example.c +- Get rid of all those darn tabs +- Add "check" target to Makefile.in that does the same thing as "test" +- Add "mostlyclean" and "maintainer-clean" targets to Makefile.in +- Update contrib/inflate86 [Anderson] +- Update contrib/testzlib, contrib/vstudio, contrib/minizip [Vollant] +- Add msdos and win32 directories with makefiles [Truta] +- More additions and improvements to the FAQ + +Changes in 1.2.0 (9 March 2003) +- New and improved inflate code + - About 20% faster + - Does not allocate 32K window unless and until needed + - Automatically detects and decompresses gzip streams + - Raw inflate no longer needs an extra dummy byte at end + - Added inflateBack functions using a callback interface--even faster + than inflate, useful for file utilities (gzip, zip) + - Added inflateCopy() function to record state for random access on + externally generated deflate streams (e.g. in gzip files) + - More readable code (I hope) +- New and improved crc32() + - About 50% faster, thanks to suggestions from Rodney Brown +- Add deflateBound() and compressBound() functions +- Fix memory leak in deflateInit2() +- Permit setting dictionary for raw deflate (for parallel deflate) +- Fix const declaration for gzwrite() +- Check for some malloc() failures in gzio.c +- Fix bug in gzopen() on single-byte file 0x1f +- Fix bug in gzread() on concatenated file with 0x1f at end of buffer + and next buffer doesn't start with 0x8b +- Fix uncompress() to return Z_DATA_ERROR on truncated input +- Free memory at end of example.c +- Remove MAX #define in trees.c (conflicted with some libraries) +- Fix static const's in deflate.c, gzio.c, and zutil.[ch] +- Declare malloc() and free() in gzio.c if STDC not defined +- Use malloc() instead of calloc() in zutil.c if int big enough +- Define STDC for AIX +- Add aix/ with approach for compiling shared library on AIX +- Add HP-UX support for shared libraries in configure +- Add OpenUNIX support for shared libraries in configure +- Use $cc instead of gcc to build shared library +- Make prefix directory if needed when installing +- Correct Macintosh avoidance of typedef Byte in zconf.h +- Correct Turbo C memory allocation when under Linux +- Use libz.a instead of -lz in Makefile (assure use of compiled library) +- Update configure to check for snprintf or vsnprintf functions and their + return value, warn during make if using an insecure function +- Fix configure problem with compile-time knowledge of HAVE_UNISTD_H that + is lost when library is used--resolution is to build new zconf.h +- Documentation improvements (in zlib.h): + - Document raw deflate and inflate + - Update RFCs URL + - Point out that zlib and gzip formats are different + - Note that Z_BUF_ERROR is not fatal + - Document string limit for gzprintf() and possible buffer overflow + - Note requirement on avail_out when flushing + - Note permitted values of flush parameter of inflate() +- Add some FAQs (and even answers) to the FAQ +- Add contrib/inflate86/ for x86 faster inflate +- Add contrib/blast/ for PKWare Data Compression Library decompression +- Add contrib/puff/ simple inflate for deflate format description + +Changes in 1.1.4 (11 March 2002) +- ZFREE was repeated on same allocation on some error conditions. + This creates a security problem described in + http://www.zlib.org/advisory-2002-03-11.txt +- Returned incorrect error (Z_MEM_ERROR) on some invalid data +- Avoid accesses before window for invalid distances with inflate window + less than 32K. +- force windowBits > 8 to avoid a bug in the encoder for a window size + of 256 bytes. (A complete fix will be available in 1.1.5). + +Changes in 1.1.3 (9 July 1998) +- fix "an inflate input buffer bug that shows up on rare but persistent + occasions" (Mark) +- fix gzread and gztell for concatenated .gz files (Didier Le Botlan) +- fix gzseek(..., SEEK_SET) in write mode +- fix crc check after a gzeek (Frank Faubert) +- fix miniunzip when the last entry in a zip file is itself a zip file + (J Lillge) +- add contrib/asm586 and contrib/asm686 (Brian Raiter) + See http://www.muppetlabs.com/~breadbox/software/assembly.html +- add support for Delphi 3 in contrib/delphi (Bob Dellaca) +- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti) +- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren) +- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks) +- added a FAQ file + +- Support gzdopen on Mac with Metrowerks (Jason Linhart) +- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart) +- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young) +- avoid some warnings with Borland C (Tom Tanner) +- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant) +- emulate utime() for WIN32 in contrib/untgz (Gilles Vollant) +- allow several arguments to configure (Tim Mooney, Frodo Looijaard) +- use libdir and includedir in Makefile.in (Tim Mooney) +- support shared libraries on OSF1 V4 (Tim Mooney) +- remove so_locations in "make clean" (Tim Mooney) +- fix maketree.c compilation error (Glenn, Mark) +- Python interface to zlib now in Python 1.5 (Jeremy Hylton) +- new Makefile.riscos (Rich Walker) +- initialize static descriptors in trees.c for embedded targets (Nick Smith) +- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith) +- add the OS/2 files in Makefile.in too (Andrew Zabolotny) +- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane) +- fix maketree.c to allow clean compilation of inffixed.h (Mark) +- fix parameter check in deflateCopy (Gunther Nikl) +- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler) +- Many portability patches by Christian Spieler: + . zutil.c, zutil.h: added "const" for zmem* + . Make_vms.com: fixed some typos + . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists + . msdos/Makefile.msc: remove "default rtl link library" info from obj files + . msdos/Makefile.*: use model-dependent name for the built zlib library + . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc: + new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT) +- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane) +- replace __far with _far for better portability (Christian Spieler, Tom Lane) +- fix test for errno.h in configure (Tim Newsham) + +Changes in 1.1.2 (19 March 98) +- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant) + See http://www.winimage.com/zLibDll/unzip.html +- preinitialize the inflate tables for fixed codes, to make the code + completely thread safe (Mark) +- some simplifications and slight speed-up to the inflate code (Mark) +- fix gzeof on non-compressed files (Allan Schrum) +- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs) +- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn) +- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny) +- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori) +- do not wrap extern "C" around system includes (Tom Lane) +- mention zlib binding for TCL in README (Andreas Kupries) +- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert) +- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson) +- allow "configure --prefix $HOME" (Tim Mooney) +- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson) +- move Makefile.sas to amiga/Makefile.sas + +Changes in 1.1.1 (27 Feb 98) +- fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson) +- remove block truncation heuristic which had very marginal effect for zlib + (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the + compression ratio on some files. This also allows inlining _tr_tally for + matches in deflate_slow. +- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier) + +Changes in 1.1.0 (24 Feb 98) +- do not return STREAM_END prematurely in inflate (John Bowler) +- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler) +- compile with -DFASTEST to get compression code optimized for speed only +- in minigzip, try mmap'ing the input file first (Miguel Albrecht) +- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain + on Sun but significant on HP) + +- add a pointer to experimental unzip library in README (Gilles Vollant) +- initialize variable gcc in configure (Chris Herborth) + +Changes in 1.0.9 (17 Feb 1998) +- added gzputs and gzgets functions +- do not clear eof flag in gzseek (Mark Diekhans) +- fix gzseek for files in transparent mode (Mark Diekhans) +- do not assume that vsprintf returns the number of bytes written (Jens Krinke) +- replace EXPORT with ZEXPORT to avoid conflict with other programs +- added compress2 in zconf.h, zlib.def, zlib.dnt +- new asm code from Gilles Vollant in contrib/asm386 +- simplify the inflate code (Mark): + . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new() + . ZALLOC the length list in inflate_trees_fixed() instead of using stack + . ZALLOC the value area for huft_build() instead of using stack + . Simplify Z_FINISH check in inflate() + +- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8 +- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi) +- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with + the declaration of FAR (Gilles VOllant) +- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann) +- read_buf buf parameter of type Bytef* instead of charf* +- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout) +- do not redeclare unlink in minigzip.c for WIN32 (John Bowler) +- fix check for presence of directories in "make install" (Ian Willis) + +Changes in 1.0.8 (27 Jan 1998) +- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant) +- fix gzgetc and gzputc for big endian systems (Markus Oberhumer) +- added compress2() to allow setting the compression level +- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong) +- use constant arrays for the static trees in trees.c instead of computing + them at run time (thanks to Ken Raeburn for this suggestion). To create + trees.h, compile with GEN_TREES_H and run "make test". +- check return code of example in "make test" and display result +- pass minigzip command line options to file_compress +- simplifying code of inflateSync to avoid gcc 2.8 bug + +- support CC="gcc -Wall" in configure -s (QingLong) +- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn) +- fix test for shared library support to avoid compiler warnings +- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant) +- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit) +- do not use fdopen for Metrowerks on Mac (Brad Pettit)) +- add checks for gzputc and gzputc in example.c +- avoid warnings in gzio.c and deflate.c (Andreas Kleinert) +- use const for the CRC table (Ken Raeburn) +- fixed "make uninstall" for shared libraries +- use Tracev instead of Trace in infblock.c +- in example.c use correct compressed length for test_sync +- suppress +vnocompatwarnings in configure for HPUX (not always supported) + +Changes in 1.0.7 (20 Jan 1998) +- fix gzseek which was broken in write mode +- return error for gzseek to negative absolute position +- fix configure for Linux (Chun-Chung Chen) +- increase stack space for MSC (Tim Wegner) +- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant) +- define EXPORTVA for gzprintf (Gilles Vollant) +- added man page zlib.3 (Rick Rodgers) +- for contrib/untgz, fix makedir() and improve Makefile + +- check gzseek in write mode in example.c +- allocate extra buffer for seeks only if gzseek is actually called +- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant) +- add inflateSyncPoint in zconf.h +- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def + +Changes in 1.0.6 (19 Jan 1998) +- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and + gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code) +- Fix a deflate bug occurring only with compression level 0 (thanks to + Andy Buckler for finding this one). +- In minigzip, pass transparently also the first byte for .Z files. +- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress() +- check Z_FINISH in inflate (thanks to Marc Schluper) +- Implement deflateCopy (thanks to Adam Costello) +- make static libraries by default in configure, add --shared option. +- move MSDOS or Windows specific files to directory msdos +- suppress the notion of partial flush to simplify the interface + (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4) +- suppress history buffer provided by application to simplify the interface + (this feature was not implemented anyway in 1.0.4) +- next_in and avail_in must be initialized before calling inflateInit or + inflateInit2 +- add EXPORT in all exported functions (for Windows DLL) +- added Makefile.nt (thanks to Stephen Williams) +- added the unsupported "contrib" directory: + contrib/asm386/ by Gilles Vollant + 386 asm code replacing longest_match(). + contrib/iostream/ by Kevin Ruland + A C++ I/O streams interface to the zlib gz* functions + contrib/iostream2/ by Tyge Løvset + Another C++ I/O streams interface + contrib/untgz/ by "Pedro A. Aranda Guti\irrez" + A very simple tar.gz file extractor using zlib + contrib/visual-basic.txt by Carlos Rios + How to use compress(), uncompress() and the gz* functions from VB. +- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression + level) in minigzip (thanks to Tom Lane) + +- use const for rommable constants in deflate +- added test for gzseek and gztell in example.c +- add undocumented function inflateSyncPoint() (hack for Paul Mackerras) +- add undocumented function zError to convert error code to string + (for Tim Smithers) +- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code. +- Use default memcpy for Symantec MSDOS compiler. +- Add EXPORT keyword for check_func (needed for Windows DLL) +- add current directory to LD_LIBRARY_PATH for "make test" +- create also a link for libz.so.1 +- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura) +- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX) +- added -soname for Linux in configure (Chun-Chung Chen, +- assign numbers to the exported functions in zlib.def (for Windows DLL) +- add advice in zlib.h for best usage of deflateSetDictionary +- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn) +- allow compilation with ANSI keywords only enabled for TurboC in large model +- avoid "versionString"[0] (Borland bug) +- add NEED_DUMMY_RETURN for Borland +- use variable z_verbose for tracing in debug mode (L. Peter Deutsch). +- allow compilation with CC +- defined STDC for OS/2 (David Charlap) +- limit external names to 8 chars for MVS (Thomas Lund) +- in minigzip.c, use static buffers only for 16-bit systems +- fix suffix check for "minigzip -d foo.gz" +- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee) +- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau) +- added makelcc.bat for lcc-win32 (Tom St Denis) +- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe) +- Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion. +- check for unistd.h in configure (for off_t) +- remove useless check parameter in inflate_blocks_free +- avoid useless assignment of s->check to itself in inflate_blocks_new +- do not flush twice in gzclose (thanks to Ken Raeburn) +- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h +- use NO_ERRNO_H instead of enumeration of operating systems with errno.h +- work around buggy fclose on pipes for HP/UX +- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson) +- fix configure if CC is already equal to gcc + +Changes in 1.0.5 (3 Jan 98) +- Fix inflate to terminate gracefully when fed corrupted or invalid data +- Use const for rommable constants in inflate +- Eliminate memory leaks on error conditions in inflate +- Removed some vestigial code in inflate +- Update web address in README + +Changes in 1.0.4 (24 Jul 96) +- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF + bit, so the decompressor could decompress all the correct data but went + on to attempt decompressing extra garbage data. This affected minigzip too. +- zlibVersion and gzerror return const char* (needed for DLL) +- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno) +- use z_error only for DEBUG (avoid problem with DLLs) + +Changes in 1.0.3 (2 Jul 96) +- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS + small and medium models; this makes the library incompatible with previous + versions for these models. (No effect in large model or on other systems.) +- return OK instead of BUF_ERROR if previous deflate call returned with + avail_out as zero but there is nothing to do +- added memcmp for non STDC compilers +- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly) +- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO) +- better check for 16-bit mode MSC (avoids problem with Symantec) + +Changes in 1.0.2 (23 May 96) +- added Windows DLL support +- added a function zlibVersion (for the DLL support) +- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model) +- Bytef is define's instead of typedef'd only for Borland C +- avoid reading uninitialized memory in example.c +- mention in README that the zlib format is now RFC1950 +- updated Makefile.dj2 +- added algorithm.doc + +Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion] +- fix array overlay in deflate.c which sometimes caused bad compressed data +- fix inflate bug with empty stored block +- fix MSDOS medium model which was broken in 0.99 +- fix deflateParams() which could generate bad compressed data. +- Bytef is define'd instead of typedef'ed (work around Borland bug) +- added an INDEX file +- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32), + Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas) +- speed up adler32 for modern machines without auto-increment +- added -ansi for IRIX in configure +- static_init_done in trees.c is an int +- define unlink as delete for VMS +- fix configure for QNX +- add configure branch for SCO and HPUX +- avoid many warnings (unused variables, dead assignments, etc...) +- no fdopen for BeOS +- fix the Watcom fix for 32 bit mode (define FAR as empty) +- removed redefinition of Byte for MKWERKS +- work around an MWKERKS bug (incorrect merge of all .h files) + +Changes in 0.99 (27 Jan 96) +- allow preset dictionary shared between compressor and decompressor +- allow compression level 0 (no compression) +- add deflateParams in zlib.h: allow dynamic change of compression level + and compression strategy. +- test large buffers and deflateParams in example.c +- add optional "configure" to build zlib as a shared library +- suppress Makefile.qnx, use configure instead +- fixed deflate for 64-bit systems (detected on Cray) +- fixed inflate_blocks for 64-bit systems (detected on Alpha) +- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2) +- always return Z_BUF_ERROR when deflate() has nothing to do +- deflateInit and inflateInit are now macros to allow version checking +- prefix all global functions and types with z_ with -DZ_PREFIX +- make falloc completely reentrant (inftrees.c) +- fixed very unlikely race condition in ct_static_init +- free in reverse order of allocation to help memory manager +- use zlib-1.0/* instead of zlib/* inside the tar.gz +- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith + -Wconversion -Wstrict-prototypes -Wmissing-prototypes" +- allow gzread on concatenated .gz files +- deflateEnd now returns Z_DATA_ERROR if it was premature +- deflate is finally (?) fully deterministic (no matches beyond end of input) +- Document Z_SYNC_FLUSH +- add uninstall in Makefile +- Check for __cpluplus in zlib.h +- Better test in ct_align for partial flush +- avoid harmless warnings for Borland C++ +- initialize hash_head in deflate.c +- avoid warning on fdopen (gzio.c) for HP cc -Aa +- include stdlib.h for STDC compilers +- include errno.h for Cray +- ignore error if ranlib doesn't exist +- call ranlib twice for NeXTSTEP +- use exec_prefix instead of prefix for libz.a +- renamed ct_* as _tr_* to avoid conflict with applications +- clear z->msg in inflateInit2 before any error return +- initialize opaque in example.c, gzio.c, deflate.c and inflate.c +- fixed typo in zconf.h (_GNUC__ => __GNUC__) +- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode) +- fix typo in Make_vms.com (f$trnlnm -> f$getsyi) +- in fcalloc, normalize pointer if size > 65520 bytes +- don't use special fcalloc for 32 bit Borland C++ +- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc... +- use Z_BINARY instead of BINARY +- document that gzclose after gzdopen will close the file +- allow "a" as mode in gzopen. +- fix error checking in gzread +- allow skipping .gz extra-field on pipes +- added reference to Perl interface in README +- put the crc table in FAR data (I dislike more and more the medium model :) +- added get_crc_table +- added a dimension to all arrays (Borland C can't count). +- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast +- guard against multiple inclusion of *.h (for precompiled header on Mac) +- Watcom C pretends to be Microsoft C small model even in 32 bit mode. +- don't use unsized arrays to avoid silly warnings by Visual C++: + warning C4746: 'inflate_mask' : unsized array treated as '__far' + (what's wrong with far data in far model?). +- define enum out of inflate_blocks_state to allow compilation with C++ + +Changes in 0.95 (16 Aug 95) +- fix MSDOS small and medium model (now easier to adapt to any compiler) +- inlined send_bits +- fix the final (:-) bug for deflate with flush (output was correct but + not completely flushed in rare occasions). +- default window size is same for compression and decompression + (it's now sufficient to set MAX_WBITS in zconf.h). +- voidp -> voidpf and voidnp -> voidp (for consistency with other + typedefs and because voidnp was not near in large model). + +Changes in 0.94 (13 Aug 95) +- support MSDOS medium model +- fix deflate with flush (could sometimes generate bad output) +- fix deflateReset (zlib header was incorrectly suppressed) +- added support for VMS +- allow a compression level in gzopen() +- gzflush now calls fflush +- For deflate with flush, flush even if no more input is provided. +- rename libgz.a as libz.a +- avoid complex expression in infcodes.c triggering Turbo C bug +- work around a problem with gcc on Alpha (in INSERT_STRING) +- don't use inline functions (problem with some gcc versions) +- allow renaming of Byte, uInt, etc... with #define. +- avoid warning about (unused) pointer before start of array in deflate.c +- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c +- avoid reserved word 'new' in trees.c + +Changes in 0.93 (25 June 95) +- temporarily disable inline functions +- make deflate deterministic +- give enough lookahead for PARTIAL_FLUSH +- Set binary mode for stdin/stdout in minigzip.c for OS/2 +- don't even use signed char in inflate (not portable enough) +- fix inflate memory leak for segmented architectures + +Changes in 0.92 (3 May 95) +- don't assume that char is signed (problem on SGI) +- Clear bit buffer when starting a stored block +- no memcpy on Pyramid +- suppressed inftest.c +- optimized fill_window, put longest_match inline for gcc +- optimized inflate on stored blocks. +- untabify all sources to simplify patches + +Changes in 0.91 (2 May 95) +- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h +- Document the memory requirements in zconf.h +- added "make install" +- fix sync search logic in inflateSync +- deflate(Z_FULL_FLUSH) now works even if output buffer too short +- after inflateSync, don't scare people with just "lo world" +- added support for DJGPP + +Changes in 0.9 (1 May 95) +- don't assume that zalloc clears the allocated memory (the TurboC bug + was Mark's bug after all :) +- let again gzread copy uncompressed data unchanged (was working in 0.71) +- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented +- added a test of inflateSync in example.c +- moved MAX_WBITS to zconf.h because users might want to change that. +- document explicitly that zalloc(64K) on MSDOS must return a normalized + pointer (zero offset) +- added Makefiles for Microsoft C, Turbo C, Borland C++ +- faster crc32() + +Changes in 0.8 (29 April 95) +- added fast inflate (inffast.c) +- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this + is incompatible with previous versions of zlib which returned Z_OK. +- work around a TurboC compiler bug (bad code for b << 0, see infutil.h) + (actually that was not a compiler bug, see 0.81 above) +- gzread no longer reads one extra byte in certain cases +- In gzio destroy(), don't reference a freed structure +- avoid many warnings for MSDOS +- avoid the ERROR symbol which is used by MS Windows + +Changes in 0.71 (14 April 95) +- Fixed more MSDOS compilation problems :( There is still a bug with + TurboC large model. + +Changes in 0.7 (14 April 95) +- Added full inflate support. +- Simplified the crc32() interface. The pre- and post-conditioning + (one's complement) is now done inside crc32(). WARNING: this is + incompatible with previous versions; see zlib.h for the new usage. + +Changes in 0.61 (12 April 95) +- workaround for a bug in TurboC. example and minigzip now work on MSDOS. + +Changes in 0.6 (11 April 95) +- added minigzip.c +- added gzdopen to reopen a file descriptor as gzFile +- added transparent reading of non-gziped files in gzread. +- fixed bug in gzread (don't read crc as data) +- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose). +- don't allocate big arrays in the stack (for MSDOS) +- fix some MSDOS compilation problems + +Changes in 0.5: +- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but + not yet Z_FULL_FLUSH. +- support decompression but only in a single step (forced Z_FINISH) +- added opaque object for zalloc and zfree. +- added deflateReset and inflateReset +- added a variable zlib_version for consistency checking. +- renamed the 'filter' parameter of deflateInit2 as 'strategy'. + Added Z_FILTERED and Z_HUFFMAN_ONLY constants. + +Changes in 0.4: +- avoid "zip" everywhere, use zlib instead of ziplib. +- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush + if compression method == 8. +- added adler32 and crc32 +- renamed deflateOptions as deflateInit2, call one or the other but not both +- added the method parameter for deflateInit2. +- added inflateInit2 +- simplied considerably deflateInit and inflateInit by not supporting + user-provided history buffer. This is supported only in deflateInit2 + and inflateInit2. + +Changes in 0.3: +- prefix all macro names with Z_ +- use Z_FINISH instead of deflateEnd to finish compression. +- added Z_HUFFMAN_ONLY +- added gzerror() diff --git a/contrib/zlib/FAQ b/contrib/zlib/FAQ new file mode 100644 index 00000000..99b7cf92 --- /dev/null +++ b/contrib/zlib/FAQ @@ -0,0 +1,368 @@ + + Frequently Asked Questions about zlib + + +If your question is not there, please check the zlib home page +http://zlib.net/ which may have more recent information. +The lastest zlib FAQ is at http://zlib.net/zlib_faq.html + + + 1. Is zlib Y2K-compliant? + + Yes. zlib doesn't handle dates. + + 2. Where can I get a Windows DLL version? + + The zlib sources can be compiled without change to produce a DLL. See the + file win32/DLL_FAQ.txt in the zlib distribution. Pointers to the + precompiled DLL are found in the zlib web site at http://zlib.net/ . + + 3. Where can I get a Visual Basic interface to zlib? + + See + * http://marknelson.us/1997/01/01/zlib-engine/ + * win32/DLL_FAQ.txt in the zlib distribution + + 4. compress() returns Z_BUF_ERROR. + + Make sure that before the call of compress(), the length of the compressed + buffer is equal to the available size of the compressed buffer and not + zero. For Visual Basic, check that this parameter is passed by reference + ("as any"), not by value ("as long"). + + 5. deflate() or inflate() returns Z_BUF_ERROR. + + Before making the call, make sure that avail_in and avail_out are not zero. + When setting the parameter flush equal to Z_FINISH, also make sure that + avail_out is big enough to allow processing all pending input. Note that a + Z_BUF_ERROR is not fatal--another call to deflate() or inflate() can be + made with more input or output space. A Z_BUF_ERROR may in fact be + unavoidable depending on how the functions are used, since it is not + possible to tell whether or not there is more output pending when + strm.avail_out returns with zero. See http://zlib.net/zlib_how.html for a + heavily annotated example. + + 6. Where's the zlib documentation (man pages, etc.)? + + It's in zlib.h . Examples of zlib usage are in the files test/example.c + and test/minigzip.c, with more in examples/ . + + 7. Why don't you use GNU autoconf or libtool or ...? + + Because we would like to keep zlib as a very small and simple package. + zlib is rather portable and doesn't need much configuration. + + 8. I found a bug in zlib. + + Most of the time, such problems are due to an incorrect usage of zlib. + Please try to reproduce the problem with a small program and send the + corresponding source to us at zlib@gzip.org . Do not send multi-megabyte + data files without prior agreement. + + 9. Why do I get "undefined reference to gzputc"? + + If "make test" produces something like + + example.o(.text+0x154): undefined reference to `gzputc' + + check that you don't have old files libz.* in /usr/lib, /usr/local/lib or + /usr/X11R6/lib. Remove any old versions, then do "make install". + +10. I need a Delphi interface to zlib. + + See the contrib/delphi directory in the zlib distribution. + +11. Can zlib handle .zip archives? + + Not by itself, no. See the directory contrib/minizip in the zlib + distribution. + +12. Can zlib handle .Z files? + + No, sorry. You have to spawn an uncompress or gunzip subprocess, or adapt + the code of uncompress on your own. + +13. How can I make a Unix shared library? + + By default a shared (and a static) library is built for Unix. So: + + make distclean + ./configure + make + +14. How do I install a shared zlib library on Unix? + + After the above, then: + + make install + + However, many flavors of Unix come with a shared zlib already installed. + Before going to the trouble of compiling a shared version of zlib and + trying to install it, you may want to check if it's already there! If you + can #include , it's there. The -lz option will probably link to + it. You can check the version at the top of zlib.h or with the + ZLIB_VERSION symbol defined in zlib.h . + +15. I have a question about OttoPDF. + + We are not the authors of OttoPDF. The real author is on the OttoPDF web + site: Joel Hainley, jhainley@myndkryme.com. + +16. Can zlib decode Flate data in an Adobe PDF file? + + Yes. See http://www.pdflib.com/ . To modify PDF forms, see + http://sourceforge.net/projects/acroformtool/ . + +17. Why am I getting this "register_frame_info not found" error on Solaris? + + After installing zlib 1.1.4 on Solaris 2.6, running applications using zlib + generates an error such as: + + ld.so.1: rpm: fatal: relocation error: file /usr/local/lib/libz.so: + symbol __register_frame_info: referenced symbol not found + + The symbol __register_frame_info is not part of zlib, it is generated by + the C compiler (cc or gcc). You must recompile applications using zlib + which have this problem. This problem is specific to Solaris. See + http://www.sunfreeware.com for Solaris versions of zlib and applications + using zlib. + +18. Why does gzip give an error on a file I make with compress/deflate? + + The compress and deflate functions produce data in the zlib format, which + is different and incompatible with the gzip format. The gz* functions in + zlib on the other hand use the gzip format. Both the zlib and gzip formats + use the same compressed data format internally, but have different headers + and trailers around the compressed data. + +19. Ok, so why are there two different formats? + + The gzip format was designed to retain the directory information about a + single file, such as the name and last modification date. The zlib format + on the other hand was designed for in-memory and communication channel + applications, and has a much more compact header and trailer and uses a + faster integrity check than gzip. + +20. Well that's nice, but how do I make a gzip file in memory? + + You can request that deflate write the gzip format instead of the zlib + format using deflateInit2(). You can also request that inflate decode the + gzip format using inflateInit2(). Read zlib.h for more details. + +21. Is zlib thread-safe? + + Yes. However any library routines that zlib uses and any application- + provided memory allocation routines must also be thread-safe. zlib's gz* + functions use stdio library routines, and most of zlib's functions use the + library memory allocation routines by default. zlib's *Init* functions + allow for the application to provide custom memory allocation routines. + + Of course, you should only operate on any given zlib or gzip stream from a + single thread at a time. + +22. Can I use zlib in my commercial application? + + Yes. Please read the license in zlib.h. + +23. Is zlib under the GNU license? + + No. Please read the license in zlib.h. + +24. The license says that altered source versions must be "plainly marked". So + what exactly do I need to do to meet that requirement? + + You need to change the ZLIB_VERSION and ZLIB_VERNUM #defines in zlib.h. In + particular, the final version number needs to be changed to "f", and an + identification string should be appended to ZLIB_VERSION. Version numbers + x.x.x.f are reserved for modifications to zlib by others than the zlib + maintainers. For example, if the version of the base zlib you are altering + is "1.2.3.4", then in zlib.h you should change ZLIB_VERNUM to 0x123f, and + ZLIB_VERSION to something like "1.2.3.f-zachary-mods-v3". You can also + update the version strings in deflate.c and inftrees.c. + + For altered source distributions, you should also note the origin and + nature of the changes in zlib.h, as well as in ChangeLog and README, along + with the dates of the alterations. The origin should include at least your + name (or your company's name), and an email address to contact for help or + issues with the library. + + Note that distributing a compiled zlib library along with zlib.h and + zconf.h is also a source distribution, and so you should change + ZLIB_VERSION and ZLIB_VERNUM and note the origin and nature of the changes + in zlib.h as you would for a full source distribution. + +25. Will zlib work on a big-endian or little-endian architecture, and can I + exchange compressed data between them? + + Yes and yes. + +26. Will zlib work on a 64-bit machine? + + Yes. It has been tested on 64-bit machines, and has no dependence on any + data types being limited to 32-bits in length. If you have any + difficulties, please provide a complete problem report to zlib@gzip.org + +27. Will zlib decompress data from the PKWare Data Compression Library? + + No. The PKWare DCL uses a completely different compressed data format than + does PKZIP and zlib. However, you can look in zlib's contrib/blast + directory for a possible solution to your problem. + +28. Can I access data randomly in a compressed stream? + + No, not without some preparation. If when compressing you periodically use + Z_FULL_FLUSH, carefully write all the pending data at those points, and + keep an index of those locations, then you can start decompression at those + points. You have to be careful to not use Z_FULL_FLUSH too often, since it + can significantly degrade compression. Alternatively, you can scan a + deflate stream once to generate an index, and then use that index for + random access. See examples/zran.c . + +29. Does zlib work on MVS, OS/390, CICS, etc.? + + It has in the past, but we have not heard of any recent evidence. There + were working ports of zlib 1.1.4 to MVS, but those links no longer work. + If you know of recent, successful applications of zlib on these operating + systems, please let us know. Thanks. + +30. Is there some simpler, easier to read version of inflate I can look at to + understand the deflate format? + + First off, you should read RFC 1951. Second, yes. Look in zlib's + contrib/puff directory. + +31. Does zlib infringe on any patents? + + As far as we know, no. In fact, that was originally the whole point behind + zlib. Look here for some more information: + + http://www.gzip.org/#faq11 + +32. Can zlib work with greater than 4 GB of data? + + Yes. inflate() and deflate() will process any amount of data correctly. + Each call of inflate() or deflate() is limited to input and output chunks + of the maximum value that can be stored in the compiler's "unsigned int" + type, but there is no limit to the number of chunks. Note however that the + strm.total_in and strm_total_out counters may be limited to 4 GB. These + counters are provided as a convenience and are not used internally by + inflate() or deflate(). The application can easily set up its own counters + updated after each call of inflate() or deflate() to count beyond 4 GB. + compress() and uncompress() may be limited to 4 GB, since they operate in a + single call. gzseek() and gztell() may be limited to 4 GB depending on how + zlib is compiled. See the zlibCompileFlags() function in zlib.h. + + The word "may" appears several times above since there is a 4 GB limit only + if the compiler's "long" type is 32 bits. If the compiler's "long" type is + 64 bits, then the limit is 16 exabytes. + +33. Does zlib have any security vulnerabilities? + + The only one that we are aware of is potentially in gzprintf(). If zlib is + compiled to use sprintf() or vsprintf(), then there is no protection + against a buffer overflow of an 8K string space (or other value as set by + gzbuffer()), other than the caller of gzprintf() assuring that the output + will not exceed 8K. On the other hand, if zlib is compiled to use + snprintf() or vsnprintf(), which should normally be the case, then there is + no vulnerability. The ./configure script will display warnings if an + insecure variation of sprintf() will be used by gzprintf(). Also the + zlibCompileFlags() function will return information on what variant of + sprintf() is used by gzprintf(). + + If you don't have snprintf() or vsnprintf() and would like one, you can + find a portable implementation here: + + http://www.ijs.si/software/snprintf/ + + Note that you should be using the most recent version of zlib. Versions + 1.1.3 and before were subject to a double-free vulnerability, and versions + 1.2.1 and 1.2.2 were subject to an access exception when decompressing + invalid compressed data. + +34. Is there a Java version of zlib? + + Probably what you want is to use zlib in Java. zlib is already included + as part of the Java SDK in the java.util.zip package. If you really want + a version of zlib written in the Java language, look on the zlib home + page for links: http://zlib.net/ . + +35. I get this or that compiler or source-code scanner warning when I crank it + up to maximally-pedantic. Can't you guys write proper code? + + Many years ago, we gave up attempting to avoid warnings on every compiler + in the universe. It just got to be a waste of time, and some compilers + were downright silly as well as contradicted each other. So now, we simply + make sure that the code always works. + +36. Valgrind (or some similar memory access checker) says that deflate is + performing a conditional jump that depends on an uninitialized value. + Isn't that a bug? + + No. That is intentional for performance reasons, and the output of deflate + is not affected. This only started showing up recently since zlib 1.2.x + uses malloc() by default for allocations, whereas earlier versions used + calloc(), which zeros out the allocated memory. Even though the code was + correct, versions 1.2.4 and later was changed to not stimulate these + checkers. + +37. Will zlib read the (insert any ancient or arcane format here) compressed + data format? + + Probably not. Look in the comp.compression FAQ for pointers to various + formats and associated software. + +38. How can I encrypt/decrypt zip files with zlib? + + zlib doesn't support encryption. The original PKZIP encryption is very + weak and can be broken with freely available programs. To get strong + encryption, use GnuPG, http://www.gnupg.org/ , which already includes zlib + compression. For PKZIP compatible "encryption", look at + http://www.info-zip.org/ + +39. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings? + + "gzip" is the gzip format, and "deflate" is the zlib format. They should + probably have called the second one "zlib" instead to avoid confusion with + the raw deflate compressed data format. While the HTTP 1.1 RFC 2616 + correctly points to the zlib specification in RFC 1950 for the "deflate" + transfer encoding, there have been reports of servers and browsers that + incorrectly produce or expect raw deflate data per the deflate + specification in RFC 1951, most notably Microsoft. So even though the + "deflate" transfer encoding using the zlib format would be the more + efficient approach (and in fact exactly what the zlib format was designed + for), using the "gzip" transfer encoding is probably more reliable due to + an unfortunate choice of name on the part of the HTTP 1.1 authors. + + Bottom line: use the gzip format for HTTP 1.1 encoding. + +40. Does zlib support the new "Deflate64" format introduced by PKWare? + + No. PKWare has apparently decided to keep that format proprietary, since + they have not documented it as they have previous compression formats. In + any case, the compression improvements are so modest compared to other more + modern approaches, that it's not worth the effort to implement. + +41. I'm having a problem with the zip functions in zlib, can you help? + + There are no zip functions in zlib. You are probably using minizip by + Giles Vollant, which is found in the contrib directory of zlib. It is not + part of zlib. In fact none of the stuff in contrib is part of zlib. The + files in there are not supported by the zlib authors. You need to contact + the authors of the respective contribution for help. + +42. The match.asm code in contrib is under the GNU General Public License. + Since it's part of zlib, doesn't that mean that all of zlib falls under the + GNU GPL? + + No. The files in contrib are not part of zlib. They were contributed by + other authors and are provided as a convenience to the user within the zlib + distribution. Each item in contrib has its own license. + +43. Is zlib subject to export controls? What is its ECCN? + + zlib is not subject to export controls, and so is classified as EAR99. + +44. Can you please sign these lengthy legal documents and fax them back to us + so that we can use your software in our product? + + No. Go away. Shoo. diff --git a/contrib/zlib/INDEX b/contrib/zlib/INDEX new file mode 100644 index 00000000..2ba06412 --- /dev/null +++ b/contrib/zlib/INDEX @@ -0,0 +1,68 @@ +CMakeLists.txt cmake build file +ChangeLog history of changes +FAQ Frequently Asked Questions about zlib +INDEX this file +Makefile dummy Makefile that tells you to ./configure +Makefile.in template for Unix Makefile +README guess what +configure configure script for Unix +make_vms.com makefile for VMS +test/example.c zlib usages examples for build testing +test/minigzip.c minimal gzip-like functionality for build testing +test/infcover.c inf*.c code coverage for build coverage testing +treebuild.xml XML description of source file dependencies +zconf.h.cmakein zconf.h template for cmake +zconf.h.in zconf.h template for configure +zlib.3 Man page for zlib +zlib.3.pdf Man page in PDF format +zlib.map Linux symbol information +zlib.pc.in Template for pkg-config descriptor +zlib.pc.cmakein zlib.pc template for cmake +zlib2ansi perl script to convert source files for C++ compilation + +amiga/ makefiles for Amiga SAS C +as400/ makefiles for AS/400 +doc/ documentation for formats and algorithms +msdos/ makefiles for MSDOS +nintendods/ makefile for Nintendo DS +old/ makefiles for various architectures and zlib documentation + files that have not yet been updated for zlib 1.2.x +qnx/ makefiles for QNX +watcom/ makefiles for OpenWatcom +win32/ makefiles for Windows + + zlib public header files (required for library use): +zconf.h +zlib.h + + private source files used to build the zlib library: +adler32.c +compress.c +crc32.c +crc32.h +deflate.c +deflate.h +gzclose.c +gzguts.h +gzlib.c +gzread.c +gzwrite.c +infback.c +inffast.c +inffast.h +inffixed.h +inflate.c +inflate.h +inftrees.c +inftrees.h +trees.c +trees.h +uncompr.c +zutil.c +zutil.h + + source files for sample programs +See examples/README.examples + + unsupported contributions by third parties +See contrib/README.contrib diff --git a/contrib/zlib/Makefile b/contrib/zlib/Makefile new file mode 100644 index 00000000..6bba86c7 --- /dev/null +++ b/contrib/zlib/Makefile @@ -0,0 +1,5 @@ +all: + -@echo "Please use ./configure first. Thank you." + +distclean: + make -f Makefile.in distclean diff --git a/contrib/zlib/Makefile.in b/contrib/zlib/Makefile.in new file mode 100644 index 00000000..5a77949f --- /dev/null +++ b/contrib/zlib/Makefile.in @@ -0,0 +1,410 @@ +# Makefile for zlib +# Copyright (C) 1995-2017 Jean-loup Gailly, Mark Adler +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile and test, type: +# ./configure; make test +# Normally configure builds both a static and a shared library. +# If you want to build just a static library, use: ./configure --static + +# To use the asm code, type: +# cp contrib/asm?86/match.S ./match.S +# make LOC=-DASMV OBJA=match.o + +# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type: +# make install +# To install in $HOME instead of /usr/local, use: +# make install prefix=$HOME + +CC=cc + +CFLAGS=-O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-g -DZLIB_DEBUG +#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ +# -Wstrict-prototypes -Wmissing-prototypes + +SFLAGS=-O +LDFLAGS= +TEST_LDFLAGS=-L. libz.a +LDSHARED=$(CC) +CPP=$(CC) -E + +STATICLIB=libz.a +SHAREDLIB=libz.so +SHAREDLIBV=libz.so.1.2.11 +SHAREDLIBM=libz.so.1 +LIBS=$(STATICLIB) $(SHAREDLIBV) + +AR=ar +ARFLAGS=rc +RANLIB=ranlib +LDCONFIG=ldconfig +LDSHAREDLIBC=-lc +TAR=tar +SHELL=/bin/sh +EXE= + +prefix = /usr/local +exec_prefix = ${prefix} +libdir = ${exec_prefix}/lib +sharedlibdir = ${libdir} +includedir = ${prefix}/include +mandir = ${prefix}/share/man +man3dir = ${mandir}/man3 +pkgconfigdir = ${libdir}/pkgconfig +SRCDIR= +ZINC= +ZINCOUT=-I. + +OBJZ = adler32.o crc32.o deflate.o infback.o inffast.o inflate.o inftrees.o trees.o zutil.o +OBJG = compress.o uncompr.o gzclose.o gzlib.o gzread.o gzwrite.o +OBJC = $(OBJZ) $(OBJG) + +PIC_OBJZ = adler32.lo crc32.lo deflate.lo infback.lo inffast.lo inflate.lo inftrees.lo trees.lo zutil.lo +PIC_OBJG = compress.lo uncompr.lo gzclose.lo gzlib.lo gzread.lo gzwrite.lo +PIC_OBJC = $(PIC_OBJZ) $(PIC_OBJG) + +# to use the asm code: make OBJA=match.o, PIC_OBJA=match.lo +OBJA = +PIC_OBJA = + +OBJS = $(OBJC) $(OBJA) + +PIC_OBJS = $(PIC_OBJC) $(PIC_OBJA) + +all: static shared + +static: example$(EXE) minigzip$(EXE) + +shared: examplesh$(EXE) minigzipsh$(EXE) + +all64: example64$(EXE) minigzip64$(EXE) + +check: test + +test: all teststatic testshared + +teststatic: static + @TMPST=tmpst_$$; \ + if echo hello world | ./minigzip | ./minigzip -d && ./example $$TMPST ; then \ + echo ' *** zlib test OK ***'; \ + else \ + echo ' *** zlib test FAILED ***'; false; \ + fi; \ + rm -f $$TMPST + +testshared: shared + @LD_LIBRARY_PATH=`pwd`:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \ + LD_LIBRARYN32_PATH=`pwd`:$(LD_LIBRARYN32_PATH) ; export LD_LIBRARYN32_PATH; \ + DYLD_LIBRARY_PATH=`pwd`:$(DYLD_LIBRARY_PATH) ; export DYLD_LIBRARY_PATH; \ + SHLIB_PATH=`pwd`:$(SHLIB_PATH) ; export SHLIB_PATH; \ + TMPSH=tmpsh_$$; \ + if echo hello world | ./minigzipsh | ./minigzipsh -d && ./examplesh $$TMPSH; then \ + echo ' *** zlib shared test OK ***'; \ + else \ + echo ' *** zlib shared test FAILED ***'; false; \ + fi; \ + rm -f $$TMPSH + +test64: all64 + @TMP64=tmp64_$$; \ + if echo hello world | ./minigzip64 | ./minigzip64 -d && ./example64 $$TMP64; then \ + echo ' *** zlib 64-bit test OK ***'; \ + else \ + echo ' *** zlib 64-bit test FAILED ***'; false; \ + fi; \ + rm -f $$TMP64 + +infcover.o: $(SRCDIR)test/infcover.c $(SRCDIR)zlib.h zconf.h + $(CC) $(CFLAGS) $(ZINCOUT) -c -o $@ $(SRCDIR)test/infcover.c + +infcover: infcover.o libz.a + $(CC) $(CFLAGS) -o $@ infcover.o libz.a + +cover: infcover + rm -f *.gcda + ./infcover + gcov inf*.c + +libz.a: $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + -@ ($(RANLIB) $@ || true) >/dev/null 2>&1 + +match.o: match.S + $(CPP) match.S > _match.s + $(CC) -c _match.s + mv _match.o match.o + rm -f _match.s + +match.lo: match.S + $(CPP) match.S > _match.s + $(CC) -c -fPIC _match.s + mv _match.o match.lo + rm -f _match.s + +example.o: $(SRCDIR)test/example.c $(SRCDIR)zlib.h zconf.h + $(CC) $(CFLAGS) $(ZINCOUT) -c -o $@ $(SRCDIR)test/example.c + +minigzip.o: $(SRCDIR)test/minigzip.c $(SRCDIR)zlib.h zconf.h + $(CC) $(CFLAGS) $(ZINCOUT) -c -o $@ $(SRCDIR)test/minigzip.c + +example64.o: $(SRCDIR)test/example.c $(SRCDIR)zlib.h zconf.h + $(CC) $(CFLAGS) $(ZINCOUT) -D_FILE_OFFSET_BITS=64 -c -o $@ $(SRCDIR)test/example.c + +minigzip64.o: $(SRCDIR)test/minigzip.c $(SRCDIR)zlib.h zconf.h + $(CC) $(CFLAGS) $(ZINCOUT) -D_FILE_OFFSET_BITS=64 -c -o $@ $(SRCDIR)test/minigzip.c + + +adler32.o: $(SRCDIR)adler32.c + $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)adler32.c + +crc32.o: $(SRCDIR)crc32.c + $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)crc32.c + +deflate.o: $(SRCDIR)deflate.c + $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)deflate.c + +infback.o: $(SRCDIR)infback.c + $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)infback.c + +inffast.o: $(SRCDIR)inffast.c + $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)inffast.c + +inflate.o: $(SRCDIR)inflate.c + $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)inflate.c + +inftrees.o: $(SRCDIR)inftrees.c + $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)inftrees.c + +trees.o: $(SRCDIR)trees.c + $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)trees.c + +zutil.o: $(SRCDIR)zutil.c + $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)zutil.c + +compress.o: $(SRCDIR)compress.c + $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)compress.c + +uncompr.o: $(SRCDIR)uncompr.c + $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)uncompr.c + +gzclose.o: $(SRCDIR)gzclose.c + $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)gzclose.c + +gzlib.o: $(SRCDIR)gzlib.c + $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)gzlib.c + +gzread.o: $(SRCDIR)gzread.c + $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)gzread.c + +gzwrite.o: $(SRCDIR)gzwrite.c + $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)gzwrite.c + + +adler32.lo: $(SRCDIR)adler32.c + -@mkdir objs 2>/dev/null || test -d objs + $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/adler32.o $(SRCDIR)adler32.c + -@mv objs/adler32.o $@ + +crc32.lo: $(SRCDIR)crc32.c + -@mkdir objs 2>/dev/null || test -d objs + $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/crc32.o $(SRCDIR)crc32.c + -@mv objs/crc32.o $@ + +deflate.lo: $(SRCDIR)deflate.c + -@mkdir objs 2>/dev/null || test -d objs + $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/deflate.o $(SRCDIR)deflate.c + -@mv objs/deflate.o $@ + +infback.lo: $(SRCDIR)infback.c + -@mkdir objs 2>/dev/null || test -d objs + $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/infback.o $(SRCDIR)infback.c + -@mv objs/infback.o $@ + +inffast.lo: $(SRCDIR)inffast.c + -@mkdir objs 2>/dev/null || test -d objs + $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/inffast.o $(SRCDIR)inffast.c + -@mv objs/inffast.o $@ + +inflate.lo: $(SRCDIR)inflate.c + -@mkdir objs 2>/dev/null || test -d objs + $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/inflate.o $(SRCDIR)inflate.c + -@mv objs/inflate.o $@ + +inftrees.lo: $(SRCDIR)inftrees.c + -@mkdir objs 2>/dev/null || test -d objs + $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/inftrees.o $(SRCDIR)inftrees.c + -@mv objs/inftrees.o $@ + +trees.lo: $(SRCDIR)trees.c + -@mkdir objs 2>/dev/null || test -d objs + $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/trees.o $(SRCDIR)trees.c + -@mv objs/trees.o $@ + +zutil.lo: $(SRCDIR)zutil.c + -@mkdir objs 2>/dev/null || test -d objs + $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/zutil.o $(SRCDIR)zutil.c + -@mv objs/zutil.o $@ + +compress.lo: $(SRCDIR)compress.c + -@mkdir objs 2>/dev/null || test -d objs + $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/compress.o $(SRCDIR)compress.c + -@mv objs/compress.o $@ + +uncompr.lo: $(SRCDIR)uncompr.c + -@mkdir objs 2>/dev/null || test -d objs + $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/uncompr.o $(SRCDIR)uncompr.c + -@mv objs/uncompr.o $@ + +gzclose.lo: $(SRCDIR)gzclose.c + -@mkdir objs 2>/dev/null || test -d objs + $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/gzclose.o $(SRCDIR)gzclose.c + -@mv objs/gzclose.o $@ + +gzlib.lo: $(SRCDIR)gzlib.c + -@mkdir objs 2>/dev/null || test -d objs + $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/gzlib.o $(SRCDIR)gzlib.c + -@mv objs/gzlib.o $@ + +gzread.lo: $(SRCDIR)gzread.c + -@mkdir objs 2>/dev/null || test -d objs + $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/gzread.o $(SRCDIR)gzread.c + -@mv objs/gzread.o $@ + +gzwrite.lo: $(SRCDIR)gzwrite.c + -@mkdir objs 2>/dev/null || test -d objs + $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/gzwrite.o $(SRCDIR)gzwrite.c + -@mv objs/gzwrite.o $@ + + +placebo $(SHAREDLIBV): $(PIC_OBJS) libz.a + $(LDSHARED) $(SFLAGS) -o $@ $(PIC_OBJS) $(LDSHAREDLIBC) $(LDFLAGS) + rm -f $(SHAREDLIB) $(SHAREDLIBM) + ln -s $@ $(SHAREDLIB) + ln -s $@ $(SHAREDLIBM) + -@rmdir objs + +example$(EXE): example.o $(STATICLIB) + $(CC) $(CFLAGS) -o $@ example.o $(TEST_LDFLAGS) + +minigzip$(EXE): minigzip.o $(STATICLIB) + $(CC) $(CFLAGS) -o $@ minigzip.o $(TEST_LDFLAGS) + +examplesh$(EXE): example.o $(SHAREDLIBV) + $(CC) $(CFLAGS) -o $@ example.o -L. $(SHAREDLIBV) + +minigzipsh$(EXE): minigzip.o $(SHAREDLIBV) + $(CC) $(CFLAGS) -o $@ minigzip.o -L. $(SHAREDLIBV) + +example64$(EXE): example64.o $(STATICLIB) + $(CC) $(CFLAGS) -o $@ example64.o $(TEST_LDFLAGS) + +minigzip64$(EXE): minigzip64.o $(STATICLIB) + $(CC) $(CFLAGS) -o $@ minigzip64.o $(TEST_LDFLAGS) + +install-libs: $(LIBS) + -@if [ ! -d $(DESTDIR)$(exec_prefix) ]; then mkdir -p $(DESTDIR)$(exec_prefix); fi + -@if [ ! -d $(DESTDIR)$(libdir) ]; then mkdir -p $(DESTDIR)$(libdir); fi + -@if [ ! -d $(DESTDIR)$(sharedlibdir) ]; then mkdir -p $(DESTDIR)$(sharedlibdir); fi + -@if [ ! -d $(DESTDIR)$(man3dir) ]; then mkdir -p $(DESTDIR)$(man3dir); fi + -@if [ ! -d $(DESTDIR)$(pkgconfigdir) ]; then mkdir -p $(DESTDIR)$(pkgconfigdir); fi + rm -f $(DESTDIR)$(libdir)/$(STATICLIB) + cp $(STATICLIB) $(DESTDIR)$(libdir) + chmod 644 $(DESTDIR)$(libdir)/$(STATICLIB) + -@($(RANLIB) $(DESTDIR)$(libdir)/libz.a || true) >/dev/null 2>&1 + -@if test -n "$(SHAREDLIBV)"; then \ + rm -f $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBV); \ + cp $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir); \ + echo "cp $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir)"; \ + chmod 755 $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBV); \ + echo "chmod 755 $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBV)"; \ + rm -f $(DESTDIR)$(sharedlibdir)/$(SHAREDLIB) $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBM); \ + ln -s $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir)/$(SHAREDLIB); \ + ln -s $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBM); \ + ($(LDCONFIG) || true) >/dev/null 2>&1; \ + fi + rm -f $(DESTDIR)$(man3dir)/zlib.3 + cp $(SRCDIR)zlib.3 $(DESTDIR)$(man3dir) + chmod 644 $(DESTDIR)$(man3dir)/zlib.3 + rm -f $(DESTDIR)$(pkgconfigdir)/zlib.pc + cp zlib.pc $(DESTDIR)$(pkgconfigdir) + chmod 644 $(DESTDIR)$(pkgconfigdir)/zlib.pc +# The ranlib in install is needed on NeXTSTEP which checks file times +# ldconfig is for Linux + +install: install-libs + -@if [ ! -d $(DESTDIR)$(includedir) ]; then mkdir -p $(DESTDIR)$(includedir); fi + rm -f $(DESTDIR)$(includedir)/zlib.h $(DESTDIR)$(includedir)/zconf.h + cp $(SRCDIR)zlib.h zconf.h $(DESTDIR)$(includedir) + chmod 644 $(DESTDIR)$(includedir)/zlib.h $(DESTDIR)$(includedir)/zconf.h + +uninstall: + cd $(DESTDIR)$(includedir) && rm -f zlib.h zconf.h + cd $(DESTDIR)$(libdir) && rm -f libz.a; \ + if test -n "$(SHAREDLIBV)" -a -f $(SHAREDLIBV); then \ + rm -f $(SHAREDLIBV) $(SHAREDLIB) $(SHAREDLIBM); \ + fi + cd $(DESTDIR)$(man3dir) && rm -f zlib.3 + cd $(DESTDIR)$(pkgconfigdir) && rm -f zlib.pc + +docs: zlib.3.pdf + +zlib.3.pdf: $(SRCDIR)zlib.3 + groff -mandoc -f H -T ps $(SRCDIR)zlib.3 | ps2pdf - $@ + +zconf.h.cmakein: $(SRCDIR)zconf.h.in + -@ TEMPFILE=zconfh_$$; \ + echo "/#define ZCONF_H/ a\\\\\n#cmakedefine Z_PREFIX\\\\\n#cmakedefine Z_HAVE_UNISTD_H\n" >> $$TEMPFILE &&\ + sed -f $$TEMPFILE $(SRCDIR)zconf.h.in > $@ &&\ + touch -r $(SRCDIR)zconf.h.in $@ &&\ + rm $$TEMPFILE + +zconf: $(SRCDIR)zconf.h.in + cp -p $(SRCDIR)zconf.h.in zconf.h + +mostlyclean: clean +clean: + rm -f *.o *.lo *~ \ + example$(EXE) minigzip$(EXE) examplesh$(EXE) minigzipsh$(EXE) \ + example64$(EXE) minigzip64$(EXE) \ + infcover \ + libz.* foo.gz so_locations \ + _match.s maketree contrib/infback9/*.o + rm -rf objs + rm -f *.gcda *.gcno *.gcov + rm -f contrib/infback9/*.gcda contrib/infback9/*.gcno contrib/infback9/*.gcov + +maintainer-clean: distclean +distclean: clean zconf zconf.h.cmakein docs + rm -f Makefile zlib.pc configure.log + -@rm -f .DS_Store + @if [ -f Makefile.in ]; then \ + printf 'all:\n\t-@echo "Please use ./configure first. Thank you."\n' > Makefile ; \ + printf '\ndistclean:\n\tmake -f Makefile.in distclean\n' >> Makefile ; \ + touch -r $(SRCDIR)Makefile.in Makefile ; fi + @if [ ! -f zconf.h.in ]; then rm -f zconf.h zconf.h.cmakein ; fi + @if [ ! -f zlib.3 ]; then rm -f zlib.3.pdf ; fi + +tags: + etags $(SRCDIR)*.[ch] + +adler32.o zutil.o: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h +gzclose.o gzlib.o gzread.o gzwrite.o: $(SRCDIR)zlib.h zconf.h $(SRCDIR)gzguts.h +compress.o example.o minigzip.o uncompr.o: $(SRCDIR)zlib.h zconf.h +crc32.o: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)crc32.h +deflate.o: $(SRCDIR)deflate.h $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h +infback.o inflate.o: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)inftrees.h $(SRCDIR)inflate.h $(SRCDIR)inffast.h $(SRCDIR)inffixed.h +inffast.o: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)inftrees.h $(SRCDIR)inflate.h $(SRCDIR)inffast.h +inftrees.o: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)inftrees.h +trees.o: $(SRCDIR)deflate.h $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)trees.h + +adler32.lo zutil.lo: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h +gzclose.lo gzlib.lo gzread.lo gzwrite.lo: $(SRCDIR)zlib.h zconf.h $(SRCDIR)gzguts.h +compress.lo example.lo minigzip.lo uncompr.lo: $(SRCDIR)zlib.h zconf.h +crc32.lo: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)crc32.h +deflate.lo: $(SRCDIR)deflate.h $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h +infback.lo inflate.lo: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)inftrees.h $(SRCDIR)inflate.h $(SRCDIR)inffast.h $(SRCDIR)inffixed.h +inffast.lo: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)inftrees.h $(SRCDIR)inflate.h $(SRCDIR)inffast.h +inftrees.lo: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)inftrees.h +trees.lo: $(SRCDIR)deflate.h $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)trees.h diff --git a/contrib/zlib/README b/contrib/zlib/README new file mode 100644 index 00000000..51106de4 --- /dev/null +++ b/contrib/zlib/README @@ -0,0 +1,115 @@ +ZLIB DATA COMPRESSION LIBRARY + +zlib 1.2.11 is a general purpose data compression library. All the code is +thread safe. The data format used by the zlib library is described by RFCs +(Request for Comments) 1950 to 1952 in the files +http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and +rfc1952 (gzip format). + +All functions of the compression library are documented in the file zlib.h +(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example +of the library is given in the file test/example.c which also tests that +the library is working correctly. Another example is given in the file +test/minigzip.c. The compression library itself is composed of all source +files in the root directory. + +To compile all files and run the test program, follow the instructions given at +the top of Makefile.in. In short "./configure; make test", and if that goes +well, "make install" should work for most flavors of Unix. For Windows, use +one of the special makefiles in win32/ or contrib/vstudio/ . For VMS, use +make_vms.com. + +Questions about zlib should be sent to , or to Gilles Vollant + for the Windows DLL version. The zlib home page is +http://zlib.net/ . Before reporting a problem, please check this site to +verify that you have the latest version of zlib; otherwise get the latest +version and check whether the problem still exists or not. + +PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help. + +Mark Nelson wrote an article about zlib for the Jan. 1997 +issue of Dr. Dobb's Journal; a copy of the article is available at +http://marknelson.us/1997/01/01/zlib-engine/ . + +The changes made in version 1.2.11 are documented in the file ChangeLog. + +Unsupported third party contributions are provided in directory contrib/ . + +zlib is available in Java using the java.util.zip package, documented at +http://java.sun.com/developer/technicalArticles/Programming/compression/ . + +A Perl interface to zlib written by Paul Marquess is available +at CPAN (Comprehensive Perl Archive Network) sites, including +http://search.cpan.org/~pmqs/IO-Compress-Zlib/ . + +A Python interface to zlib written by A.M. Kuchling is +available in Python 1.5 and later versions, see +http://docs.python.org/library/zlib.html . + +zlib is built into tcl: http://wiki.tcl.tk/4610 . + +An experimental package to read and write files in .zip format, written on top +of zlib by Gilles Vollant , is available in the +contrib/minizip directory of zlib. + + +Notes for some targets: + +- For Windows DLL versions, please see win32/DLL_FAQ.txt + +- For 64-bit Irix, deflate.c must be compiled without any optimization. With + -O, one libpng test fails. The test works in 32 bit mode (with the -n32 + compiler flag). The compiler bug has been reported to SGI. + +- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works + when compiled with cc. + +- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is + necessary to get gzprintf working correctly. This is done by configure. + +- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with + other compilers. Use "make test" to check your compiler. + +- gzdopen is not supported on RISCOS or BEOS. + +- For PalmOs, see http://palmzlib.sourceforge.net/ + + +Acknowledgments: + + The deflate format used by zlib was defined by Phil Katz. The deflate and + zlib specifications were written by L. Peter Deutsch. Thanks to all the + people who reported problems and suggested various improvements in zlib; they + are too numerous to cite here. + +Copyright notice: + + (C) 1995-2017 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* receiving +lengthy legal documents to sign. The sources are provided for free but without +warranty of any kind. The library has been entirely written by Jean-loup +Gailly and Mark Adler; it does not include third-party code. + +If you redistribute modified sources, we would appreciate that you include in +the file ChangeLog history information documenting your changes. Please read +the FAQ for more information on the distribution of modified source versions. diff --git a/contrib/zlib/adler32.c b/contrib/zlib/adler32.c new file mode 100644 index 00000000..d0be4380 --- /dev/null +++ b/contrib/zlib/adler32.c @@ -0,0 +1,186 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2011, 2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); + +#define BASE 65521U /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware -- + try it both ways to see which is faster */ +#ifdef NO_DIVIDE +/* note that this assumes BASE is 65521, where 65536 % 65521 == 15 + (thank you to John Reiser for pointing this out) */ +# define CHOP(a) \ + do { \ + unsigned long tmp = a >> 16; \ + a &= 0xffffUL; \ + a += (tmp << 4) - tmp; \ + } while (0) +# define MOD28(a) \ + do { \ + CHOP(a); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD(a) \ + do { \ + CHOP(a); \ + MOD28(a); \ + } while (0) +# define MOD63(a) \ + do { /* this assumes a is not negative */ \ + z_off64_t tmp = a >> 32; \ + a &= 0xffffffffL; \ + a += (tmp << 8) - (tmp << 5) + tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD28(a) a %= BASE +# define MOD63(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32_z(adler, buf, len) + uLong adler; + const Bytef *buf; + z_size_t len; +{ + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD28(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + return adler32_z(adler, buf, len); +} + +/* ========================================================================= */ +local uLong adler32_combine_(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off64_t len2; +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* for negative len, return invalid adler32 as a clue for debugging */ + if (len2 < 0) + return 0xffffffffUL; + + /* the derivation of this formula is left as an exercise for the reader */ + MOD63(len2); /* assumes len2 >= 0 */ + rem = (unsigned)len2; + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 >= BASE) sum1 -= BASE; + if (sum1 >= BASE) sum1 -= BASE; + if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1); + if (sum2 >= BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + return adler32_combine_(adler1, adler2, len2); +} + +uLong ZEXPORT adler32_combine64(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off64_t len2; +{ + return adler32_combine_(adler1, adler2, len2); +} diff --git a/contrib/zlib/amiga/Makefile.pup b/contrib/zlib/amiga/Makefile.pup new file mode 100644 index 00000000..8940c120 --- /dev/null +++ b/contrib/zlib/amiga/Makefile.pup @@ -0,0 +1,69 @@ +# Amiga powerUP (TM) Makefile +# makefile for libpng and SAS C V6.58/7.00 PPC compiler +# Copyright (C) 1998 by Andreas R. Kleinert + +LIBNAME = libzip.a + +CC = scppc +CFLAGS = NOSTKCHK NOSINT OPTIMIZE OPTGO OPTPEEP OPTINLOCAL OPTINL \ + OPTLOOP OPTRDEP=8 OPTDEP=8 OPTCOMP=8 NOVER +AR = ppc-amigaos-ar cr +RANLIB = ppc-amigaos-ranlib +LD = ppc-amigaos-ld -r +LDFLAGS = -o +LDLIBS = LIB:scppc.a LIB:end.o +RM = delete quiet + +OBJS = adler32.o compress.o crc32.o gzclose.o gzlib.o gzread.o gzwrite.o \ + uncompr.o deflate.o trees.o zutil.o inflate.o infback.o inftrees.o inffast.o + +TEST_OBJS = example.o minigzip.o + +all: example minigzip + +check: test +test: all + example + echo hello world | minigzip | minigzip -d + +$(LIBNAME): $(OBJS) + $(AR) $@ $(OBJS) + -$(RANLIB) $@ + +example: example.o $(LIBNAME) + $(LD) $(LDFLAGS) $@ LIB:c_ppc.o $@.o $(LIBNAME) $(LDLIBS) + +minigzip: minigzip.o $(LIBNAME) + $(LD) $(LDFLAGS) $@ LIB:c_ppc.o $@.o $(LIBNAME) $(LDLIBS) + +mostlyclean: clean +clean: + $(RM) *.o example minigzip $(LIBNAME) foo.gz + +zip: + zip -ul9 zlib README ChangeLog Makefile Make????.??? Makefile.?? \ + descrip.mms *.[ch] + +tgz: + cd ..; tar cfz zlib/zlib.tgz zlib/README zlib/ChangeLog zlib/Makefile \ + zlib/Make????.??? zlib/Makefile.?? zlib/descrip.mms zlib/*.[ch] + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +adler32.o: zlib.h zconf.h +compress.o: zlib.h zconf.h +crc32.o: crc32.h zlib.h zconf.h +deflate.o: deflate.h zutil.h zlib.h zconf.h +example.o: zlib.h zconf.h +gzclose.o: zlib.h zconf.h gzguts.h +gzlib.o: zlib.h zconf.h gzguts.h +gzread.o: zlib.h zconf.h gzguts.h +gzwrite.o: zlib.h zconf.h gzguts.h +inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inftrees.o: zutil.h zlib.h zconf.h inftrees.h +minigzip.o: zlib.h zconf.h +trees.o: deflate.h zutil.h zlib.h zconf.h trees.h +uncompr.o: zlib.h zconf.h +zutil.o: zutil.h zlib.h zconf.h diff --git a/contrib/zlib/amiga/Makefile.sas b/contrib/zlib/amiga/Makefile.sas new file mode 100644 index 00000000..749e2915 --- /dev/null +++ b/contrib/zlib/amiga/Makefile.sas @@ -0,0 +1,68 @@ +# SMakefile for zlib +# Modified from the standard UNIX Makefile Copyright Jean-loup Gailly +# Osma Ahvenlampi +# Amiga, SAS/C 6.56 & Smake + +CC=sc +CFLAGS=OPT +#CFLAGS=OPT CPU=68030 +#CFLAGS=DEBUG=LINE +LDFLAGS=LIB z.lib + +SCOPTIONS=OPTSCHED OPTINLINE OPTALIAS OPTTIME OPTINLOCAL STRMERGE \ + NOICONS PARMS=BOTH NOSTACKCHECK UTILLIB NOVERSION ERRORREXX \ + DEF=POSTINC + +OBJS = adler32.o compress.o crc32.o gzclose.o gzlib.o gzread.o gzwrite.o \ + uncompr.o deflate.o trees.o zutil.o inflate.o infback.o inftrees.o inffast.o + +TEST_OBJS = example.o minigzip.o + +all: SCOPTIONS example minigzip + +check: test +test: all + example + echo hello world | minigzip | minigzip -d + +install: z.lib + copy clone zlib.h zconf.h INCLUDE: + copy clone z.lib LIB: + +z.lib: $(OBJS) + oml z.lib r $(OBJS) + +example: example.o z.lib + $(CC) $(CFLAGS) LINK TO $@ example.o $(LDFLAGS) + +minigzip: minigzip.o z.lib + $(CC) $(CFLAGS) LINK TO $@ minigzip.o $(LDFLAGS) + +mostlyclean: clean +clean: + -delete force quiet example minigzip *.o z.lib foo.gz *.lnk SCOPTIONS + +SCOPTIONS: Makefile.sas + copy to $@ (uLong)max ? max : (uInt)left; + left -= stream.avail_out; + } + if (stream.avail_in == 0) { + stream.avail_in = sourceLen > (uLong)max ? max : (uInt)sourceLen; + sourceLen -= stream.avail_in; + } + err = deflate(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH); + } while (err == Z_OK); + + *destLen = stream.total_out; + deflateEnd(&stream); + return err == Z_STREAM_END ? Z_OK : err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + + (sourceLen >> 25) + 13; +} diff --git a/contrib/zlib/configure b/contrib/zlib/configure new file mode 100644 index 00000000..e974d1fd --- /dev/null +++ b/contrib/zlib/configure @@ -0,0 +1,921 @@ +#!/bin/sh +# configure script for zlib. +# +# Normally configure builds both a static and a shared library. +# If you want to build just a static library, use: ./configure --static +# +# To impose specific compiler or flags or install directory, use for example: +# prefix=$HOME CC=cc CFLAGS="-O4" ./configure +# or for csh/tcsh users: +# (setenv prefix $HOME; setenv CC cc; setenv CFLAGS "-O4"; ./configure) + +# Incorrect settings of CC or CFLAGS may prevent creating a shared library. +# If you have problems, try without defining CC and CFLAGS before reporting +# an error. + +# start off configure.log +echo -------------------- >> configure.log +echo $0 $* >> configure.log +date >> configure.log + +# get source directory +SRCDIR=`dirname $0` +if test $SRCDIR = "."; then + ZINC="" + ZINCOUT="-I." + SRCDIR="" +else + ZINC='-include zconf.h' + ZINCOUT='-I. -I$(SRCDIR)' + SRCDIR="$SRCDIR/" +fi + +# set command prefix for cross-compilation +if [ -n "${CHOST}" ]; then + uname="`echo "${CHOST}" | sed -e 's/^[^-]*-\([^-]*\)$/\1/' -e 's/^[^-]*-[^-]*-\([^-]*\)$/\1/' -e 's/^[^-]*-[^-]*-\([^-]*\)-.*$/\1/'`" + CROSS_PREFIX="${CHOST}-" +fi + +# destination name for static library +STATICLIB=libz.a + +# extract zlib version numbers from zlib.h +VER=`sed -n -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < ${SRCDIR}zlib.h` +VER3=`sed -n -e '/VERSION "/s/.*"\([0-9]*\\.[0-9]*\\.[0-9]*\).*/\1/p' < ${SRCDIR}zlib.h` +VER2=`sed -n -e '/VERSION "/s/.*"\([0-9]*\\.[0-9]*\)\\..*/\1/p' < ${SRCDIR}zlib.h` +VER1=`sed -n -e '/VERSION "/s/.*"\([0-9]*\)\\..*/\1/p' < ${SRCDIR}zlib.h` + +# establish commands for library building +if "${CROSS_PREFIX}ar" --version >/dev/null 2>/dev/null || test $? -lt 126; then + AR=${AR-"${CROSS_PREFIX}ar"} + test -n "${CROSS_PREFIX}" && echo Using ${AR} | tee -a configure.log +else + AR=${AR-"ar"} + test -n "${CROSS_PREFIX}" && echo Using ${AR} | tee -a configure.log +fi +ARFLAGS=${ARFLAGS-"rc"} +if "${CROSS_PREFIX}ranlib" --version >/dev/null 2>/dev/null || test $? -lt 126; then + RANLIB=${RANLIB-"${CROSS_PREFIX}ranlib"} + test -n "${CROSS_PREFIX}" && echo Using ${RANLIB} | tee -a configure.log +else + RANLIB=${RANLIB-"ranlib"} +fi +if "${CROSS_PREFIX}nm" --version >/dev/null 2>/dev/null || test $? -lt 126; then + NM=${NM-"${CROSS_PREFIX}nm"} + test -n "${CROSS_PREFIX}" && echo Using ${NM} | tee -a configure.log +else + NM=${NM-"nm"} +fi + +# set defaults before processing command line options +LDCONFIG=${LDCONFIG-"ldconfig"} +LDSHAREDLIBC="${LDSHAREDLIBC--lc}" +ARCHS= +prefix=${prefix-/usr/local} +exec_prefix=${exec_prefix-'${prefix}'} +libdir=${libdir-'${exec_prefix}/lib'} +sharedlibdir=${sharedlibdir-'${libdir}'} +includedir=${includedir-'${prefix}/include'} +mandir=${mandir-'${prefix}/share/man'} +shared_ext='.so' +shared=1 +solo=0 +cover=0 +zprefix=0 +zconst=0 +build64=0 +gcc=0 +warn=0 +debug=0 +old_cc="$CC" +old_cflags="$CFLAGS" +OBJC='$(OBJZ) $(OBJG)' +PIC_OBJC='$(PIC_OBJZ) $(PIC_OBJG)' + +# leave this script, optionally in a bad way +leave() +{ + if test "$*" != "0"; then + echo "** $0 aborting." | tee -a configure.log + fi + rm -f $test.[co] $test $test$shared_ext $test.gcno ./--version + echo -------------------- >> configure.log + echo >> configure.log + echo >> configure.log + exit $1 +} + +# process command line options +while test $# -ge 1 +do +case "$1" in + -h* | --help) + echo 'usage:' | tee -a configure.log + echo ' configure [--const] [--zprefix] [--prefix=PREFIX] [--eprefix=EXPREFIX]' | tee -a configure.log + echo ' [--static] [--64] [--libdir=LIBDIR] [--sharedlibdir=LIBDIR]' | tee -a configure.log + echo ' [--includedir=INCLUDEDIR] [--archs="-arch i386 -arch x86_64"]' | tee -a configure.log + exit 0 ;; + -p*=* | --prefix=*) prefix=`echo $1 | sed 's/.*=//'`; shift ;; + -e*=* | --eprefix=*) exec_prefix=`echo $1 | sed 's/.*=//'`; shift ;; + -l*=* | --libdir=*) libdir=`echo $1 | sed 's/.*=//'`; shift ;; + --sharedlibdir=*) sharedlibdir=`echo $1 | sed 's/.*=//'`; shift ;; + -i*=* | --includedir=*) includedir=`echo $1 | sed 's/.*=//'`;shift ;; + -u*=* | --uname=*) uname=`echo $1 | sed 's/.*=//'`;shift ;; + -p* | --prefix) prefix="$2"; shift; shift ;; + -e* | --eprefix) exec_prefix="$2"; shift; shift ;; + -l* | --libdir) libdir="$2"; shift; shift ;; + -i* | --includedir) includedir="$2"; shift; shift ;; + -s* | --shared | --enable-shared) shared=1; shift ;; + -t | --static) shared=0; shift ;; + --solo) solo=1; shift ;; + --cover) cover=1; shift ;; + -z* | --zprefix) zprefix=1; shift ;; + -6* | --64) build64=1; shift ;; + -a*=* | --archs=*) ARCHS=`echo $1 | sed 's/.*=//'`; shift ;; + --sysconfdir=*) echo "ignored option: --sysconfdir" | tee -a configure.log; shift ;; + --localstatedir=*) echo "ignored option: --localstatedir" | tee -a configure.log; shift ;; + -c* | --const) zconst=1; shift ;; + -w* | --warn) warn=1; shift ;; + -d* | --debug) debug=1; shift ;; + *) + echo "unknown option: $1" | tee -a configure.log + echo "$0 --help for help" | tee -a configure.log + leave 1;; + esac +done + +# temporary file name +test=ztest$$ + +# put arguments in log, also put test file in log if used in arguments +show() +{ + case "$*" in + *$test.c*) + echo === $test.c === >> configure.log + cat $test.c >> configure.log + echo === >> configure.log;; + esac + echo $* >> configure.log +} + +# check for gcc vs. cc and set compile and link flags based on the system identified by uname +cat > $test.c <&1` in + *gcc*) gcc=1 ;; + *clang*) gcc=1 ;; +esac + +show $cc -c $test.c +if test "$gcc" -eq 1 && ($cc -c $test.c) >> configure.log 2>&1; then + echo ... using gcc >> configure.log + CC="$cc" + CFLAGS="${CFLAGS--O3}" + SFLAGS="${CFLAGS--O3} -fPIC" + if test "$ARCHS"; then + CFLAGS="${CFLAGS} ${ARCHS}" + LDFLAGS="${LDFLAGS} ${ARCHS}" + fi + if test $build64 -eq 1; then + CFLAGS="${CFLAGS} -m64" + SFLAGS="${SFLAGS} -m64" + fi + if test "$warn" -eq 1; then + if test "$zconst" -eq 1; then + CFLAGS="${CFLAGS} -Wall -Wextra -Wcast-qual -pedantic -DZLIB_CONST" + else + CFLAGS="${CFLAGS} -Wall -Wextra -pedantic" + fi + fi + if test $debug -eq 1; then + CFLAGS="${CFLAGS} -DZLIB_DEBUG" + SFLAGS="${SFLAGS} -DZLIB_DEBUG" + fi + if test -z "$uname"; then + uname=`(uname -s || echo unknown) 2>/dev/null` + fi + case "$uname" in + Linux* | linux* | GNU | GNU/* | solaris*) + LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1,--version-script,${SRCDIR}zlib.map"} ;; + *BSD | *bsd* | DragonFly) + LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1,--version-script,${SRCDIR}zlib.map"} + LDCONFIG="ldconfig -m" ;; + CYGWIN* | Cygwin* | cygwin* | OS/2*) + EXE='.exe' ;; + MINGW* | mingw*) +# temporary bypass + rm -f $test.[co] $test $test$shared_ext + echo "Please use win32/Makefile.gcc instead." | tee -a configure.log + leave 1 + LDSHARED=${LDSHARED-"$cc -shared"} + LDSHAREDLIBC="" + EXE='.exe' ;; + QNX*) # This is for QNX6. I suppose that the QNX rule below is for QNX2,QNX4 + # (alain.bonnefoy@icbt.com) + LDSHARED=${LDSHARED-"$cc -shared -Wl,-hlibz.so.1"} ;; + HP-UX*) + LDSHARED=${LDSHARED-"$cc -shared $SFLAGS"} + case `(uname -m || echo unknown) 2>/dev/null` in + ia64) + shared_ext='.so' + SHAREDLIB='libz.so' ;; + *) + shared_ext='.sl' + SHAREDLIB='libz.sl' ;; + esac ;; + Darwin* | darwin*) + shared_ext='.dylib' + SHAREDLIB=libz$shared_ext + SHAREDLIBV=libz.$VER$shared_ext + SHAREDLIBM=libz.$VER1$shared_ext + LDSHARED=${LDSHARED-"$cc -dynamiclib -install_name $libdir/$SHAREDLIBM -compatibility_version $VER1 -current_version $VER3"} + if libtool -V 2>&1 | grep Apple > /dev/null; then + AR="libtool" + else + AR="/usr/bin/libtool" + fi + ARFLAGS="-o" ;; + *) LDSHARED=${LDSHARED-"$cc -shared"} ;; + esac +else + # find system name and corresponding cc options + CC=${CC-cc} + gcc=0 + echo ... using $CC >> configure.log + if test -z "$uname"; then + uname=`(uname -sr || echo unknown) 2>/dev/null` + fi + case "$uname" in + HP-UX*) SFLAGS=${CFLAGS-"-O +z"} + CFLAGS=${CFLAGS-"-O"} +# LDSHARED=${LDSHARED-"ld -b +vnocompatwarnings"} + LDSHARED=${LDSHARED-"ld -b"} + case `(uname -m || echo unknown) 2>/dev/null` in + ia64) + shared_ext='.so' + SHAREDLIB='libz.so' ;; + *) + shared_ext='.sl' + SHAREDLIB='libz.sl' ;; + esac ;; + IRIX*) SFLAGS=${CFLAGS-"-ansi -O2 -rpath ."} + CFLAGS=${CFLAGS-"-ansi -O2"} + LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so.1"} ;; + OSF1\ V4*) SFLAGS=${CFLAGS-"-O -std1"} + CFLAGS=${CFLAGS-"-O -std1"} + LDFLAGS="${LDFLAGS} -Wl,-rpath,." + LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so -Wl,-msym -Wl,-rpath,$(libdir) -Wl,-set_version,${VER}:1.0"} ;; + OSF1*) SFLAGS=${CFLAGS-"-O -std1"} + CFLAGS=${CFLAGS-"-O -std1"} + LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so.1"} ;; + QNX*) SFLAGS=${CFLAGS-"-4 -O"} + CFLAGS=${CFLAGS-"-4 -O"} + LDSHARED=${LDSHARED-"cc"} + RANLIB=${RANLIB-"true"} + AR="cc" + ARFLAGS="-A" ;; + SCO_SV\ 3.2*) SFLAGS=${CFLAGS-"-O3 -dy -KPIC "} + CFLAGS=${CFLAGS-"-O3"} + LDSHARED=${LDSHARED-"cc -dy -KPIC -G"} ;; + SunOS\ 5* | solaris*) + LDSHARED=${LDSHARED-"cc -G -h libz$shared_ext.$VER1"} + SFLAGS=${CFLAGS-"-fast -KPIC"} + CFLAGS=${CFLAGS-"-fast"} + if test $build64 -eq 1; then + # old versions of SunPRO/Workshop/Studio don't support -m64, + # but newer ones do. Check for it. + flag64=`$CC -flags | egrep -- '^-m64'` + if test x"$flag64" != x"" ; then + CFLAGS="${CFLAGS} -m64" + SFLAGS="${SFLAGS} -m64" + else + case `(uname -m || echo unknown) 2>/dev/null` in + i86*) + SFLAGS="$SFLAGS -xarch=amd64" + CFLAGS="$CFLAGS -xarch=amd64" ;; + *) + SFLAGS="$SFLAGS -xarch=v9" + CFLAGS="$CFLAGS -xarch=v9" ;; + esac + fi + fi + if test -n "$ZINC"; then + ZINC='-I- -I. -I$(SRCDIR)' + fi + ;; + SunOS\ 4*) SFLAGS=${CFLAGS-"-O2 -PIC"} + CFLAGS=${CFLAGS-"-O2"} + LDSHARED=${LDSHARED-"ld"} ;; + SunStudio\ 9*) SFLAGS=${CFLAGS-"-fast -xcode=pic32 -xtarget=ultra3 -xarch=v9b"} + CFLAGS=${CFLAGS-"-fast -xtarget=ultra3 -xarch=v9b"} + LDSHARED=${LDSHARED-"cc -xarch=v9b"} ;; + UNIX_System_V\ 4.2.0) + SFLAGS=${CFLAGS-"-KPIC -O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -G"} ;; + UNIX_SV\ 4.2MP) + SFLAGS=${CFLAGS-"-Kconform_pic -O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -G"} ;; + OpenUNIX\ 5) + SFLAGS=${CFLAGS-"-KPIC -O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -G"} ;; + AIX*) # Courtesy of dbakker@arrayasolutions.com + SFLAGS=${CFLAGS-"-O -qmaxmem=8192"} + CFLAGS=${CFLAGS-"-O -qmaxmem=8192"} + LDSHARED=${LDSHARED-"xlc -G"} ;; + # send working options for other systems to zlib@gzip.org + *) SFLAGS=${CFLAGS-"-O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -shared"} ;; + esac +fi + +# destination names for shared library if not defined above +SHAREDLIB=${SHAREDLIB-"libz$shared_ext"} +SHAREDLIBV=${SHAREDLIBV-"libz$shared_ext.$VER"} +SHAREDLIBM=${SHAREDLIBM-"libz$shared_ext.$VER1"} + +echo >> configure.log + +# define functions for testing compiler and library characteristics and logging the results + +cat > $test.c </dev/null; then + try() + { + show $* + test "`( $* ) 2>&1 | tee -a configure.log`" = "" + } + echo - using any output from compiler to indicate an error >> configure.log +else + try() + { + show $* + ( $* ) >> configure.log 2>&1 + ret=$? + if test $ret -ne 0; then + echo "(exit code "$ret")" >> configure.log + fi + return $ret + } +fi + +tryboth() +{ + show $* + got=`( $* ) 2>&1` + ret=$? + printf %s "$got" >> configure.log + if test $ret -ne 0; then + return $ret + fi + test "$got" = "" +} + +cat > $test.c << EOF +int foo() { return 0; } +EOF +echo "Checking for obsessive-compulsive compiler options..." >> configure.log +if try $CC -c $CFLAGS $test.c; then + : +else + echo "Compiler error reporting is too harsh for $0 (perhaps remove -Werror)." | tee -a configure.log + leave 1 +fi + +echo >> configure.log + +# see if shared library build supported +cat > $test.c <> configure.log + show "$NM $test.o | grep _hello" + if test "`$NM $test.o | grep _hello | tee -a configure.log`" = ""; then + CPP="$CPP -DNO_UNDERLINE" + echo Checking for underline in external names... No. | tee -a configure.log + else + echo Checking for underline in external names... Yes. | tee -a configure.log + fi ;; +esac + +echo >> configure.log + +# check for size_t +cat > $test.c < +#include +size_t dummy = 0; +EOF +if try $CC -c $CFLAGS $test.c; then + echo "Checking for size_t... Yes." | tee -a configure.log + need_sizet=0 +else + echo "Checking for size_t... No." | tee -a configure.log + need_sizet=1 +fi + +echo >> configure.log + +# find the size_t integer type, if needed +if test $need_sizet -eq 1; then + cat > $test.c < $test.c < +int main(void) { + if (sizeof(void *) <= sizeof(int)) puts("int"); + else if (sizeof(void *) <= sizeof(long)) puts("long"); + else puts("z_longlong"); + return 0; +} +EOF + else + echo "Checking for long long... No." | tee -a configure.log + cat > $test.c < +int main(void) { + if (sizeof(void *) <= sizeof(int)) puts("int"); + else puts("long"); + return 0; +} +EOF + fi + if try $CC $CFLAGS -o $test $test.c; then + sizet=`./$test` + echo "Checking for a pointer-size integer type..." $sizet"." | tee -a configure.log + else + echo "Failed to find a pointer-size integer type." | tee -a configure.log + leave 1 + fi +fi + +if test $need_sizet -eq 1; then + CFLAGS="${CFLAGS} -DNO_SIZE_T=${sizet}" + SFLAGS="${SFLAGS} -DNO_SIZE_T=${sizet}" +fi + +echo >> configure.log + +# check for large file support, and if none, check for fseeko() +cat > $test.c < +off64_t dummy = 0; +EOF +if try $CC -c $CFLAGS -D_LARGEFILE64_SOURCE=1 $test.c; then + CFLAGS="${CFLAGS} -D_LARGEFILE64_SOURCE=1" + SFLAGS="${SFLAGS} -D_LARGEFILE64_SOURCE=1" + ALL="${ALL} all64" + TEST="${TEST} test64" + echo "Checking for off64_t... Yes." | tee -a configure.log + echo "Checking for fseeko... Yes." | tee -a configure.log +else + echo "Checking for off64_t... No." | tee -a configure.log + echo >> configure.log + cat > $test.c < +int main(void) { + fseeko(NULL, 0, 0); + return 0; +} +EOF + if try $CC $CFLAGS -o $test $test.c; then + echo "Checking for fseeko... Yes." | tee -a configure.log + else + CFLAGS="${CFLAGS} -DNO_FSEEKO" + SFLAGS="${SFLAGS} -DNO_FSEEKO" + echo "Checking for fseeko... No." | tee -a configure.log + fi +fi + +echo >> configure.log + +# check for strerror() for use by gz* functions +cat > $test.c < +#include +int main() { return strlen(strerror(errno)); } +EOF +if try $CC $CFLAGS -o $test $test.c; then + echo "Checking for strerror... Yes." | tee -a configure.log +else + CFLAGS="${CFLAGS} -DNO_STRERROR" + SFLAGS="${SFLAGS} -DNO_STRERROR" + echo "Checking for strerror... No." | tee -a configure.log +fi + +# copy clean zconf.h for subsequent edits +cp -p ${SRCDIR}zconf.h.in zconf.h + +echo >> configure.log + +# check for unistd.h and save result in zconf.h +cat > $test.c < +int main() { return 0; } +EOF +if try $CC -c $CFLAGS $test.c; then + sed < zconf.h "/^#ifdef HAVE_UNISTD_H.* may be/s/def HAVE_UNISTD_H\(.*\) may be/ 1\1 was/" > zconf.temp.h + mv zconf.temp.h zconf.h + echo "Checking for unistd.h... Yes." | tee -a configure.log +else + echo "Checking for unistd.h... No." | tee -a configure.log +fi + +echo >> configure.log + +# check for stdarg.h and save result in zconf.h +cat > $test.c < +int main() { return 0; } +EOF +if try $CC -c $CFLAGS $test.c; then + sed < zconf.h "/^#ifdef HAVE_STDARG_H.* may be/s/def HAVE_STDARG_H\(.*\) may be/ 1\1 was/" > zconf.temp.h + mv zconf.temp.h zconf.h + echo "Checking for stdarg.h... Yes." | tee -a configure.log +else + echo "Checking for stdarg.h... No." | tee -a configure.log +fi + +# if the z_ prefix was requested, save that in zconf.h +if test $zprefix -eq 1; then + sed < zconf.h "/#ifdef Z_PREFIX.* may be/s/def Z_PREFIX\(.*\) may be/ 1\1 was/" > zconf.temp.h + mv zconf.temp.h zconf.h + echo >> configure.log + echo "Using z_ prefix on all symbols." | tee -a configure.log +fi + +# if --solo compilation was requested, save that in zconf.h and remove gz stuff from object lists +if test $solo -eq 1; then + sed '/#define ZCONF_H/a\ +#define Z_SOLO + +' < zconf.h > zconf.temp.h + mv zconf.temp.h zconf.h +OBJC='$(OBJZ)' +PIC_OBJC='$(PIC_OBJZ)' +fi + +# if code coverage testing was requested, use older gcc if defined, e.g. "gcc-4.2" on Mac OS X +if test $cover -eq 1; then + CFLAGS="${CFLAGS} -fprofile-arcs -ftest-coverage" + if test -n "$GCC_CLASSIC"; then + CC=$GCC_CLASSIC + fi +fi + +echo >> configure.log + +# conduct a series of tests to resolve eight possible cases of using "vs" or "s" printf functions +# (using stdarg or not), with or without "n" (proving size of buffer), and with or without a +# return value. The most secure result is vsnprintf() with a return value. snprintf() with a +# return value is secure as well, but then gzprintf() will be limited to 20 arguments. +cat > $test.c < +#include +#include "zconf.h" +int main() +{ +#ifndef STDC + choke me +#endif + return 0; +} +EOF +if try $CC -c $CFLAGS $test.c; then + echo "Checking whether to use vs[n]printf() or s[n]printf()... using vs[n]printf()." | tee -a configure.log + + echo >> configure.log + cat > $test.c < +#include +int mytest(const char *fmt, ...) +{ + char buf[20]; + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + return 0; +} +int main() +{ + return (mytest("Hello%d\n", 1)); +} +EOF + if try $CC $CFLAGS -o $test $test.c; then + echo "Checking for vsnprintf() in stdio.h... Yes." | tee -a configure.log + + echo >> configure.log + cat >$test.c < +#include +int mytest(const char *fmt, ...) +{ + int n; + char buf[20]; + va_list ap; + va_start(ap, fmt); + n = vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + return n; +} +int main() +{ + return (mytest("Hello%d\n", 1)); +} +EOF + + if try $CC -c $CFLAGS $test.c; then + echo "Checking for return value of vsnprintf()... Yes." | tee -a configure.log + else + CFLAGS="$CFLAGS -DHAS_vsnprintf_void" + SFLAGS="$SFLAGS -DHAS_vsnprintf_void" + echo "Checking for return value of vsnprintf()... No." | tee -a configure.log + echo " WARNING: apparently vsnprintf() does not return a value. zlib" | tee -a configure.log + echo " can build but will be open to possible string-format security" | tee -a configure.log + echo " vulnerabilities." | tee -a configure.log + fi + else + CFLAGS="$CFLAGS -DNO_vsnprintf" + SFLAGS="$SFLAGS -DNO_vsnprintf" + echo "Checking for vsnprintf() in stdio.h... No." | tee -a configure.log + echo " WARNING: vsnprintf() not found, falling back to vsprintf(). zlib" | tee -a configure.log + echo " can build but will be open to possible buffer-overflow security" | tee -a configure.log + echo " vulnerabilities." | tee -a configure.log + + echo >> configure.log + cat >$test.c < +#include +int mytest(const char *fmt, ...) +{ + int n; + char buf[20]; + va_list ap; + va_start(ap, fmt); + n = vsprintf(buf, fmt, ap); + va_end(ap); + return n; +} +int main() +{ + return (mytest("Hello%d\n", 1)); +} +EOF + + if try $CC -c $CFLAGS $test.c; then + echo "Checking for return value of vsprintf()... Yes." | tee -a configure.log + else + CFLAGS="$CFLAGS -DHAS_vsprintf_void" + SFLAGS="$SFLAGS -DHAS_vsprintf_void" + echo "Checking for return value of vsprintf()... No." | tee -a configure.log + echo " WARNING: apparently vsprintf() does not return a value. zlib" | tee -a configure.log + echo " can build but will be open to possible string-format security" | tee -a configure.log + echo " vulnerabilities." | tee -a configure.log + fi + fi +else + echo "Checking whether to use vs[n]printf() or s[n]printf()... using s[n]printf()." | tee -a configure.log + + echo >> configure.log + cat >$test.c < +int mytest() +{ + char buf[20]; + snprintf(buf, sizeof(buf), "%s", "foo"); + return 0; +} +int main() +{ + return (mytest()); +} +EOF + + if try $CC $CFLAGS -o $test $test.c; then + echo "Checking for snprintf() in stdio.h... Yes." | tee -a configure.log + + echo >> configure.log + cat >$test.c < +int mytest() +{ + char buf[20]; + return snprintf(buf, sizeof(buf), "%s", "foo"); +} +int main() +{ + return (mytest()); +} +EOF + + if try $CC -c $CFLAGS $test.c; then + echo "Checking for return value of snprintf()... Yes." | tee -a configure.log + else + CFLAGS="$CFLAGS -DHAS_snprintf_void" + SFLAGS="$SFLAGS -DHAS_snprintf_void" + echo "Checking for return value of snprintf()... No." | tee -a configure.log + echo " WARNING: apparently snprintf() does not return a value. zlib" | tee -a configure.log + echo " can build but will be open to possible string-format security" | tee -a configure.log + echo " vulnerabilities." | tee -a configure.log + fi + else + CFLAGS="$CFLAGS -DNO_snprintf" + SFLAGS="$SFLAGS -DNO_snprintf" + echo "Checking for snprintf() in stdio.h... No." | tee -a configure.log + echo " WARNING: snprintf() not found, falling back to sprintf(). zlib" | tee -a configure.log + echo " can build but will be open to possible buffer-overflow security" | tee -a configure.log + echo " vulnerabilities." | tee -a configure.log + + echo >> configure.log + cat >$test.c < +int mytest() +{ + char buf[20]; + return sprintf(buf, "%s", "foo"); +} +int main() +{ + return (mytest()); +} +EOF + + if try $CC -c $CFLAGS $test.c; then + echo "Checking for return value of sprintf()... Yes." | tee -a configure.log + else + CFLAGS="$CFLAGS -DHAS_sprintf_void" + SFLAGS="$SFLAGS -DHAS_sprintf_void" + echo "Checking for return value of sprintf()... No." | tee -a configure.log + echo " WARNING: apparently sprintf() does not return a value. zlib" | tee -a configure.log + echo " can build but will be open to possible string-format security" | tee -a configure.log + echo " vulnerabilities." | tee -a configure.log + fi + fi +fi + +# see if we can hide zlib internal symbols that are linked between separate source files +if test "$gcc" -eq 1; then + echo >> configure.log + cat > $test.c <> configure.log +echo ALL = $ALL >> configure.log +echo AR = $AR >> configure.log +echo ARFLAGS = $ARFLAGS >> configure.log +echo CC = $CC >> configure.log +echo CFLAGS = $CFLAGS >> configure.log +echo CPP = $CPP >> configure.log +echo EXE = $EXE >> configure.log +echo LDCONFIG = $LDCONFIG >> configure.log +echo LDFLAGS = $LDFLAGS >> configure.log +echo LDSHARED = $LDSHARED >> configure.log +echo LDSHAREDLIBC = $LDSHAREDLIBC >> configure.log +echo OBJC = $OBJC >> configure.log +echo PIC_OBJC = $PIC_OBJC >> configure.log +echo RANLIB = $RANLIB >> configure.log +echo SFLAGS = $SFLAGS >> configure.log +echo SHAREDLIB = $SHAREDLIB >> configure.log +echo SHAREDLIBM = $SHAREDLIBM >> configure.log +echo SHAREDLIBV = $SHAREDLIBV >> configure.log +echo STATICLIB = $STATICLIB >> configure.log +echo TEST = $TEST >> configure.log +echo VER = $VER >> configure.log +echo Z_U4 = $Z_U4 >> configure.log +echo SRCDIR = $SRCDIR >> configure.log +echo exec_prefix = $exec_prefix >> configure.log +echo includedir = $includedir >> configure.log +echo libdir = $libdir >> configure.log +echo mandir = $mandir >> configure.log +echo prefix = $prefix >> configure.log +echo sharedlibdir = $sharedlibdir >> configure.log +echo uname = $uname >> configure.log + +# udpate Makefile with the configure results +sed < ${SRCDIR}Makefile.in " +/^CC *=/s#=.*#=$CC# +/^CFLAGS *=/s#=.*#=$CFLAGS# +/^SFLAGS *=/s#=.*#=$SFLAGS# +/^LDFLAGS *=/s#=.*#=$LDFLAGS# +/^LDSHARED *=/s#=.*#=$LDSHARED# +/^CPP *=/s#=.*#=$CPP# +/^STATICLIB *=/s#=.*#=$STATICLIB# +/^SHAREDLIB *=/s#=.*#=$SHAREDLIB# +/^SHAREDLIBV *=/s#=.*#=$SHAREDLIBV# +/^SHAREDLIBM *=/s#=.*#=$SHAREDLIBM# +/^AR *=/s#=.*#=$AR# +/^ARFLAGS *=/s#=.*#=$ARFLAGS# +/^RANLIB *=/s#=.*#=$RANLIB# +/^LDCONFIG *=/s#=.*#=$LDCONFIG# +/^LDSHAREDLIBC *=/s#=.*#=$LDSHAREDLIBC# +/^EXE *=/s#=.*#=$EXE# +/^SRCDIR *=/s#=.*#=$SRCDIR# +/^ZINC *=/s#=.*#=$ZINC# +/^ZINCOUT *=/s#=.*#=$ZINCOUT# +/^prefix *=/s#=.*#=$prefix# +/^exec_prefix *=/s#=.*#=$exec_prefix# +/^libdir *=/s#=.*#=$libdir# +/^sharedlibdir *=/s#=.*#=$sharedlibdir# +/^includedir *=/s#=.*#=$includedir# +/^mandir *=/s#=.*#=$mandir# +/^OBJC *=/s#=.*#= $OBJC# +/^PIC_OBJC *=/s#=.*#= $PIC_OBJC# +/^all: */s#:.*#: $ALL# +/^test: */s#:.*#: $TEST# +" > Makefile + +# create zlib.pc with the configure results +sed < ${SRCDIR}zlib.pc.in " +/^CC *=/s#=.*#=$CC# +/^CFLAGS *=/s#=.*#=$CFLAGS# +/^CPP *=/s#=.*#=$CPP# +/^LDSHARED *=/s#=.*#=$LDSHARED# +/^STATICLIB *=/s#=.*#=$STATICLIB# +/^SHAREDLIB *=/s#=.*#=$SHAREDLIB# +/^SHAREDLIBV *=/s#=.*#=$SHAREDLIBV# +/^SHAREDLIBM *=/s#=.*#=$SHAREDLIBM# +/^AR *=/s#=.*#=$AR# +/^ARFLAGS *=/s#=.*#=$ARFLAGS# +/^RANLIB *=/s#=.*#=$RANLIB# +/^EXE *=/s#=.*#=$EXE# +/^prefix *=/s#=.*#=$prefix# +/^exec_prefix *=/s#=.*#=$exec_prefix# +/^libdir *=/s#=.*#=$libdir# +/^sharedlibdir *=/s#=.*#=$sharedlibdir# +/^includedir *=/s#=.*#=$includedir# +/^mandir *=/s#=.*#=$mandir# +/^LDFLAGS *=/s#=.*#=$LDFLAGS# +" | sed -e " +s/\@VERSION\@/$VER/g; +" > zlib.pc + +# done +leave 0 diff --git a/contrib/zlib/contrib/README.contrib b/contrib/zlib/contrib/README.contrib new file mode 100644 index 00000000..a411d5c3 --- /dev/null +++ b/contrib/zlib/contrib/README.contrib @@ -0,0 +1,78 @@ +All files under this contrib directory are UNSUPPORTED. There were +provided by users of zlib and were not tested by the authors of zlib. +Use at your own risk. Please contact the authors of the contributions +for help about these, not the zlib authors. Thanks. + + +ada/ by Dmitriy Anisimkov + Support for Ada + See http://zlib-ada.sourceforge.net/ + +amd64/ by Mikhail Teterin + asm code for AMD64 + See patch at http://www.freebsd.org/cgi/query-pr.cgi?pr=bin/96393 + +asm686/ by Brian Raiter + asm code for Pentium and PPro/PII, using the AT&T (GNU as) syntax + See http://www.muppetlabs.com/~breadbox/software/assembly.html + +blast/ by Mark Adler + Decompressor for output of PKWare Data Compression Library (DCL) + +delphi/ by Cosmin Truta + Support for Delphi and C++ Builder + +dotzlib/ by Henrik Ravn + Support for Microsoft .Net and Visual C++ .Net + +gcc_gvmat64/by Gilles Vollant + GCC Version of x86 64-bit (AMD64 and Intel EM64t) code for x64 + assembler to replace longest_match() and inflate_fast() + +infback9/ by Mark Adler + Unsupported diffs to infback to decode the deflate64 format + +inflate86/ by Chris Anderson + Tuned x86 gcc asm code to replace inflate_fast() + +iostream/ by Kevin Ruland + A C++ I/O streams interface to the zlib gz* functions + +iostream2/ by Tyge Løvset + Another C++ I/O streams interface + +iostream3/ by Ludwig Schwardt + and Kevin Ruland + Yet another C++ I/O streams interface + +masmx64/ by Gilles Vollant + x86 64-bit (AMD64 and Intel EM64t) code for x64 assembler to + replace longest_match() and inflate_fast(), also masm x86 + 64-bits translation of Chris Anderson inflate_fast() + +masmx86/ by Gilles Vollant + x86 asm code to replace longest_match() and inflate_fast(), + for Visual C++ and MASM (32 bits). + Based on Brian Raiter (asm686) and Chris Anderson (inflate86) + +minizip/ by Gilles Vollant + Mini zip and unzip based on zlib + Includes Zip64 support by Mathias Svensson + See http://www.winimage.com/zLibDll/minizip.html + +pascal/ by Bob Dellaca et al. + Support for Pascal + +puff/ by Mark Adler + Small, low memory usage inflate. Also serves to provide an + unambiguous description of the deflate format. + +testzlib/ by Gilles Vollant + Example of the use of zlib + +untgz/ by Pedro A. Aranda Gutierrez + A very simple tar.gz file extractor using zlib + +vstudio/ by Gilles Vollant + Building a minizip-enhanced zlib with Microsoft Visual Studio + Includes vc11 from kreuzerkrieg and vc12 from davispuh diff --git a/contrib/zlib/contrib/ada/buffer_demo.adb b/contrib/zlib/contrib/ada/buffer_demo.adb new file mode 100644 index 00000000..46b86381 --- /dev/null +++ b/contrib/zlib/contrib/ada/buffer_demo.adb @@ -0,0 +1,106 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2004 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- +-- +-- $Id: buffer_demo.adb,v 1.3 2004/09/06 06:55:35 vagul Exp $ + +-- This demo program provided by Dr Steve Sangwine +-- +-- Demonstration of a problem with Zlib-Ada (already fixed) when a buffer +-- of exactly the correct size is used for decompressed data, and the last +-- few bytes passed in to Zlib are checksum bytes. + +-- This program compresses a string of text, and then decompresses the +-- compressed text into a buffer of the same size as the original text. + +with Ada.Streams; use Ada.Streams; +with Ada.Text_IO; + +with ZLib; use ZLib; + +procedure Buffer_Demo is + EOL : Character renames ASCII.LF; + Text : constant String + := "Four score and seven years ago our fathers brought forth," & EOL & + "upon this continent, a new nation, conceived in liberty," & EOL & + "and dedicated to the proposition that `all men are created equal'."; + + Source : Stream_Element_Array (1 .. Text'Length); + for Source'Address use Text'Address; + +begin + Ada.Text_IO.Put (Text); + Ada.Text_IO.New_Line; + Ada.Text_IO.Put_Line + ("Uncompressed size : " & Positive'Image (Text'Length) & " bytes"); + + declare + Compressed_Data : Stream_Element_Array (1 .. Text'Length); + L : Stream_Element_Offset; + begin + Compress : declare + Compressor : Filter_Type; + I : Stream_Element_Offset; + begin + Deflate_Init (Compressor); + + -- Compress the whole of T at once. + + Translate (Compressor, Source, I, Compressed_Data, L, Finish); + pragma Assert (I = Source'Last); + + Close (Compressor); + + Ada.Text_IO.Put_Line + ("Compressed size : " + & Stream_Element_Offset'Image (L) & " bytes"); + end Compress; + + -- Now we decompress the data, passing short blocks of data to Zlib + -- (because this demonstrates the problem - the last block passed will + -- contain checksum information and there will be no output, only a + -- check inside Zlib that the checksum is correct). + + Decompress : declare + Decompressor : Filter_Type; + + Uncompressed_Data : Stream_Element_Array (1 .. Text'Length); + + Block_Size : constant := 4; + -- This makes sure that the last block contains + -- only Adler checksum data. + + P : Stream_Element_Offset := Compressed_Data'First - 1; + O : Stream_Element_Offset; + begin + Inflate_Init (Decompressor); + + loop + Translate + (Decompressor, + Compressed_Data + (P + 1 .. Stream_Element_Offset'Min (P + Block_Size, L)), + P, + Uncompressed_Data + (Total_Out (Decompressor) + 1 .. Uncompressed_Data'Last), + O, + No_Flush); + + Ada.Text_IO.Put_Line + ("Total in : " & Count'Image (Total_In (Decompressor)) & + ", out : " & Count'Image (Total_Out (Decompressor))); + + exit when P = L; + end loop; + + Ada.Text_IO.New_Line; + Ada.Text_IO.Put_Line + ("Decompressed text matches original text : " + & Boolean'Image (Uncompressed_Data = Source)); + end Decompress; + end; +end Buffer_Demo; diff --git a/contrib/zlib/contrib/ada/mtest.adb b/contrib/zlib/contrib/ada/mtest.adb new file mode 100644 index 00000000..c4dfd080 --- /dev/null +++ b/contrib/zlib/contrib/ada/mtest.adb @@ -0,0 +1,156 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- +-- Continuous test for ZLib multithreading. If the test would fail +-- we should provide thread safe allocation routines for the Z_Stream. +-- +-- $Id: mtest.adb,v 1.4 2004/07/23 07:49:54 vagul Exp $ + +with ZLib; +with Ada.Streams; +with Ada.Numerics.Discrete_Random; +with Ada.Text_IO; +with Ada.Exceptions; +with Ada.Task_Identification; + +procedure MTest is + use Ada.Streams; + use ZLib; + + Stop : Boolean := False; + + pragma Atomic (Stop); + + subtype Visible_Symbols is Stream_Element range 16#20# .. 16#7E#; + + package Random_Elements is + new Ada.Numerics.Discrete_Random (Visible_Symbols); + + task type Test_Task; + + task body Test_Task is + Buffer : Stream_Element_Array (1 .. 100_000); + Gen : Random_Elements.Generator; + + Buffer_First : Stream_Element_Offset; + Compare_First : Stream_Element_Offset; + + Deflate : Filter_Type; + Inflate : Filter_Type; + + procedure Further (Item : in Stream_Element_Array); + + procedure Read_Buffer + (Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset); + + ------------- + -- Further -- + ------------- + + procedure Further (Item : in Stream_Element_Array) is + + procedure Compare (Item : in Stream_Element_Array); + + ------------- + -- Compare -- + ------------- + + procedure Compare (Item : in Stream_Element_Array) is + Next_First : Stream_Element_Offset := Compare_First + Item'Length; + begin + if Buffer (Compare_First .. Next_First - 1) /= Item then + raise Program_Error; + end if; + + Compare_First := Next_First; + end Compare; + + procedure Compare_Write is new ZLib.Write (Write => Compare); + begin + Compare_Write (Inflate, Item, No_Flush); + end Further; + + ----------------- + -- Read_Buffer -- + ----------------- + + procedure Read_Buffer + (Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset) + is + Buff_Diff : Stream_Element_Offset := Buffer'Last - Buffer_First; + Next_First : Stream_Element_Offset; + begin + if Item'Length <= Buff_Diff then + Last := Item'Last; + + Next_First := Buffer_First + Item'Length; + + Item := Buffer (Buffer_First .. Next_First - 1); + + Buffer_First := Next_First; + else + Last := Item'First + Buff_Diff; + Item (Item'First .. Last) := Buffer (Buffer_First .. Buffer'Last); + Buffer_First := Buffer'Last + 1; + end if; + end Read_Buffer; + + procedure Translate is new Generic_Translate + (Data_In => Read_Buffer, + Data_Out => Further); + + begin + Random_Elements.Reset (Gen); + + Buffer := (others => 20); + + Main : loop + for J in Buffer'Range loop + Buffer (J) := Random_Elements.Random (Gen); + + Deflate_Init (Deflate); + Inflate_Init (Inflate); + + Buffer_First := Buffer'First; + Compare_First := Buffer'First; + + Translate (Deflate); + + if Compare_First /= Buffer'Last + 1 then + raise Program_Error; + end if; + + Ada.Text_IO.Put_Line + (Ada.Task_Identification.Image + (Ada.Task_Identification.Current_Task) + & Stream_Element_Offset'Image (J) + & ZLib.Count'Image (Total_Out (Deflate))); + + Close (Deflate); + Close (Inflate); + + exit Main when Stop; + end loop; + end loop Main; + exception + when E : others => + Ada.Text_IO.Put_Line (Ada.Exceptions.Exception_Information (E)); + Stop := True; + end Test_Task; + + Test : array (1 .. 4) of Test_Task; + + pragma Unreferenced (Test); + + Dummy : Character; + +begin + Ada.Text_IO.Get_Immediate (Dummy); + Stop := True; +end MTest; diff --git a/contrib/zlib/contrib/ada/read.adb b/contrib/zlib/contrib/ada/read.adb new file mode 100644 index 00000000..1f2efbfe --- /dev/null +++ b/contrib/zlib/contrib/ada/read.adb @@ -0,0 +1,156 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: read.adb,v 1.8 2004/05/31 10:53:40 vagul Exp $ + +-- Test/demo program for the generic read interface. + +with Ada.Numerics.Discrete_Random; +with Ada.Streams; +with Ada.Text_IO; + +with ZLib; + +procedure Read is + + use Ada.Streams; + + ------------------------------------ + -- Test configuration parameters -- + ------------------------------------ + + File_Size : Stream_Element_Offset := 100_000; + + Continuous : constant Boolean := False; + -- If this constant is True, the test would be repeated again and again, + -- with increment File_Size for every iteration. + + Header : constant ZLib.Header_Type := ZLib.Default; + -- Do not use Header other than Default in ZLib versions 1.1.4 and older. + + Init_Random : constant := 8; + -- We are using the same random sequence, in case of we catch bug, + -- so we would be able to reproduce it. + + -- End -- + + Pack_Size : Stream_Element_Offset; + Offset : Stream_Element_Offset; + + Filter : ZLib.Filter_Type; + + subtype Visible_Symbols + is Stream_Element range 16#20# .. 16#7E#; + + package Random_Elements is new + Ada.Numerics.Discrete_Random (Visible_Symbols); + + Gen : Random_Elements.Generator; + Period : constant Stream_Element_Offset := 200; + -- Period constant variable for random generator not to be very random. + -- Bigger period, harder random. + + Read_Buffer : Stream_Element_Array (1 .. 2048); + Read_First : Stream_Element_Offset; + Read_Last : Stream_Element_Offset; + + procedure Reset; + + procedure Read + (Item : out Stream_Element_Array; + Last : out Stream_Element_Offset); + -- this procedure is for generic instantiation of + -- ZLib.Read + -- reading data from the File_In. + + procedure Read is new ZLib.Read + (Read, + Read_Buffer, + Rest_First => Read_First, + Rest_Last => Read_Last); + + ---------- + -- Read -- + ---------- + + procedure Read + (Item : out Stream_Element_Array; + Last : out Stream_Element_Offset) is + begin + Last := Stream_Element_Offset'Min + (Item'Last, + Item'First + File_Size - Offset); + + for J in Item'First .. Last loop + if J < Item'First + Period then + Item (J) := Random_Elements.Random (Gen); + else + Item (J) := Item (J - Period); + end if; + + Offset := Offset + 1; + end loop; + end Read; + + ----------- + -- Reset -- + ----------- + + procedure Reset is + begin + Random_Elements.Reset (Gen, Init_Random); + Pack_Size := 0; + Offset := 1; + Read_First := Read_Buffer'Last + 1; + Read_Last := Read_Buffer'Last; + end Reset; + +begin + Ada.Text_IO.Put_Line ("ZLib " & ZLib.Version); + + loop + for Level in ZLib.Compression_Level'Range loop + + Ada.Text_IO.Put ("Level =" + & ZLib.Compression_Level'Image (Level)); + + -- Deflate using generic instantiation. + + ZLib.Deflate_Init + (Filter, + Level, + Header => Header); + + Reset; + + Ada.Text_IO.Put + (Stream_Element_Offset'Image (File_Size) & " ->"); + + loop + declare + Buffer : Stream_Element_Array (1 .. 1024); + Last : Stream_Element_Offset; + begin + Read (Filter, Buffer, Last); + + Pack_Size := Pack_Size + Last - Buffer'First + 1; + + exit when Last < Buffer'Last; + end; + end loop; + + Ada.Text_IO.Put_Line (Stream_Element_Offset'Image (Pack_Size)); + + ZLib.Close (Filter); + end loop; + + exit when not Continuous; + + File_Size := File_Size + 1; + end loop; +end Read; diff --git a/contrib/zlib/contrib/ada/readme.txt b/contrib/zlib/contrib/ada/readme.txt new file mode 100644 index 00000000..ce4d2cad --- /dev/null +++ b/contrib/zlib/contrib/ada/readme.txt @@ -0,0 +1,65 @@ + ZLib for Ada thick binding (ZLib.Ada) + Release 1.3 + +ZLib.Ada is a thick binding interface to the popular ZLib data +compression library, available at http://www.gzip.org/zlib/. +It provides Ada-style access to the ZLib C library. + + + Here are the main changes since ZLib.Ada 1.2: + +- Attension: ZLib.Read generic routine have a initialization requirement + for Read_Last parameter now. It is a bit incompartible with previous version, + but extends functionality, we could use new parameters Allow_Read_Some and + Flush now. + +- Added Is_Open routines to ZLib and ZLib.Streams packages. + +- Add pragma Assert to check Stream_Element is 8 bit. + +- Fix extraction to buffer with exact known decompressed size. Error reported by + Steve Sangwine. + +- Fix definition of ULong (changed to unsigned_long), fix regression on 64 bits + computers. Patch provided by Pascal Obry. + +- Add Status_Error exception definition. + +- Add pragma Assertion that Ada.Streams.Stream_Element size is 8 bit. + + + How to build ZLib.Ada under GNAT + +You should have the ZLib library already build on your computer, before +building ZLib.Ada. Make the directory of ZLib.Ada sources current and +issue the command: + + gnatmake test -largs -L -lz + +Or use the GNAT project file build for GNAT 3.15 or later: + + gnatmake -Pzlib.gpr -L + + + How to build ZLib.Ada under Aonix ObjectAda for Win32 7.2.2 + +1. Make a project with all *.ads and *.adb files from the distribution. +2. Build the libz.a library from the ZLib C sources. +3. Rename libz.a to z.lib. +4. Add the library z.lib to the project. +5. Add the libc.lib library from the ObjectAda distribution to the project. +6. Build the executable using test.adb as a main procedure. + + + How to use ZLib.Ada + +The source files test.adb and read.adb are small demo programs that show +the main functionality of ZLib.Ada. + +The routines from the package specifications are commented. + + +Homepage: http://zlib-ada.sourceforge.net/ +Author: Dmitriy Anisimkov + +Contributors: Pascal Obry , Steve Sangwine diff --git a/contrib/zlib/contrib/ada/test.adb b/contrib/zlib/contrib/ada/test.adb new file mode 100644 index 00000000..90773acf --- /dev/null +++ b/contrib/zlib/contrib/ada/test.adb @@ -0,0 +1,463 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: test.adb,v 1.17 2003/08/12 12:13:30 vagul Exp $ + +-- The program has a few aims. +-- 1. Test ZLib.Ada95 thick binding functionality. +-- 2. Show the example of use main functionality of the ZLib.Ada95 binding. +-- 3. Build this program automatically compile all ZLib.Ada95 packages under +-- GNAT Ada95 compiler. + +with ZLib.Streams; +with Ada.Streams.Stream_IO; +with Ada.Numerics.Discrete_Random; + +with Ada.Text_IO; + +with Ada.Calendar; + +procedure Test is + + use Ada.Streams; + use Stream_IO; + + ------------------------------------ + -- Test configuration parameters -- + ------------------------------------ + + File_Size : Count := 100_000; + Continuous : constant Boolean := False; + + Header : constant ZLib.Header_Type := ZLib.Default; + -- ZLib.None; + -- ZLib.Auto; + -- ZLib.GZip; + -- Do not use Header other then Default in ZLib versions 1.1.4 + -- and older. + + Strategy : constant ZLib.Strategy_Type := ZLib.Default_Strategy; + Init_Random : constant := 10; + + -- End -- + + In_File_Name : constant String := "testzlib.in"; + -- Name of the input file + + Z_File_Name : constant String := "testzlib.zlb"; + -- Name of the compressed file. + + Out_File_Name : constant String := "testzlib.out"; + -- Name of the decompressed file. + + File_In : File_Type; + File_Out : File_Type; + File_Back : File_Type; + File_Z : ZLib.Streams.Stream_Type; + + Filter : ZLib.Filter_Type; + + Time_Stamp : Ada.Calendar.Time; + + procedure Generate_File; + -- Generate file of spetsified size with some random data. + -- The random data is repeatable, for the good compression. + + procedure Compare_Streams + (Left, Right : in out Root_Stream_Type'Class); + -- The procedure compearing data in 2 streams. + -- It is for compare data before and after compression/decompression. + + procedure Compare_Files (Left, Right : String); + -- Compare files. Based on the Compare_Streams. + + procedure Copy_Streams + (Source, Target : in out Root_Stream_Type'Class; + Buffer_Size : in Stream_Element_Offset := 1024); + -- Copying data from one stream to another. It is for test stream + -- interface of the library. + + procedure Data_In + (Item : out Stream_Element_Array; + Last : out Stream_Element_Offset); + -- this procedure is for generic instantiation of + -- ZLib.Generic_Translate. + -- reading data from the File_In. + + procedure Data_Out (Item : in Stream_Element_Array); + -- this procedure is for generic instantiation of + -- ZLib.Generic_Translate. + -- writing data to the File_Out. + + procedure Stamp; + -- Store the timestamp to the local variable. + + procedure Print_Statistic (Msg : String; Data_Size : ZLib.Count); + -- Print the time statistic with the message. + + procedure Translate is new ZLib.Generic_Translate + (Data_In => Data_In, + Data_Out => Data_Out); + -- This procedure is moving data from File_In to File_Out + -- with compression or decompression, depend on initialization of + -- Filter parameter. + + ------------------- + -- Compare_Files -- + ------------------- + + procedure Compare_Files (Left, Right : String) is + Left_File, Right_File : File_Type; + begin + Open (Left_File, In_File, Left); + Open (Right_File, In_File, Right); + Compare_Streams (Stream (Left_File).all, Stream (Right_File).all); + Close (Left_File); + Close (Right_File); + end Compare_Files; + + --------------------- + -- Compare_Streams -- + --------------------- + + procedure Compare_Streams + (Left, Right : in out Ada.Streams.Root_Stream_Type'Class) + is + Left_Buffer, Right_Buffer : Stream_Element_Array (0 .. 16#FFF#); + Left_Last, Right_Last : Stream_Element_Offset; + begin + loop + Read (Left, Left_Buffer, Left_Last); + Read (Right, Right_Buffer, Right_Last); + + if Left_Last /= Right_Last then + Ada.Text_IO.Put_Line ("Compare error :" + & Stream_Element_Offset'Image (Left_Last) + & " /= " + & Stream_Element_Offset'Image (Right_Last)); + + raise Constraint_Error; + + elsif Left_Buffer (0 .. Left_Last) + /= Right_Buffer (0 .. Right_Last) + then + Ada.Text_IO.Put_Line ("ERROR: IN and OUT files is not equal."); + raise Constraint_Error; + + end if; + + exit when Left_Last < Left_Buffer'Last; + end loop; + end Compare_Streams; + + ------------------ + -- Copy_Streams -- + ------------------ + + procedure Copy_Streams + (Source, Target : in out Ada.Streams.Root_Stream_Type'Class; + Buffer_Size : in Stream_Element_Offset := 1024) + is + Buffer : Stream_Element_Array (1 .. Buffer_Size); + Last : Stream_Element_Offset; + begin + loop + Read (Source, Buffer, Last); + Write (Target, Buffer (1 .. Last)); + + exit when Last < Buffer'Last; + end loop; + end Copy_Streams; + + ------------- + -- Data_In -- + ------------- + + procedure Data_In + (Item : out Stream_Element_Array; + Last : out Stream_Element_Offset) is + begin + Read (File_In, Item, Last); + end Data_In; + + -------------- + -- Data_Out -- + -------------- + + procedure Data_Out (Item : in Stream_Element_Array) is + begin + Write (File_Out, Item); + end Data_Out; + + ------------------- + -- Generate_File -- + ------------------- + + procedure Generate_File is + subtype Visible_Symbols is Stream_Element range 16#20# .. 16#7E#; + + package Random_Elements is + new Ada.Numerics.Discrete_Random (Visible_Symbols); + + Gen : Random_Elements.Generator; + Buffer : Stream_Element_Array := (1 .. 77 => 16#20#) & 10; + + Buffer_Count : constant Count := File_Size / Buffer'Length; + -- Number of same buffers in the packet. + + Density : constant Count := 30; -- from 0 to Buffer'Length - 2; + + procedure Fill_Buffer (J, D : in Count); + -- Change the part of the buffer. + + ----------------- + -- Fill_Buffer -- + ----------------- + + procedure Fill_Buffer (J, D : in Count) is + begin + for K in 0 .. D loop + Buffer + (Stream_Element_Offset ((J + K) mod (Buffer'Length - 1) + 1)) + := Random_Elements.Random (Gen); + + end loop; + end Fill_Buffer; + + begin + Random_Elements.Reset (Gen, Init_Random); + + Create (File_In, Out_File, In_File_Name); + + Fill_Buffer (1, Buffer'Length - 2); + + for J in 1 .. Buffer_Count loop + Write (File_In, Buffer); + + Fill_Buffer (J, Density); + end loop; + + -- fill remain size. + + Write + (File_In, + Buffer + (1 .. Stream_Element_Offset + (File_Size - Buffer'Length * Buffer_Count))); + + Flush (File_In); + Close (File_In); + end Generate_File; + + --------------------- + -- Print_Statistic -- + --------------------- + + procedure Print_Statistic (Msg : String; Data_Size : ZLib.Count) is + use Ada.Calendar; + use Ada.Text_IO; + + package Count_IO is new Integer_IO (ZLib.Count); + + Curr_Dur : Duration := Clock - Time_Stamp; + begin + Put (Msg); + + Set_Col (20); + Ada.Text_IO.Put ("size ="); + + Count_IO.Put + (Data_Size, + Width => Stream_IO.Count'Image (File_Size)'Length); + + Put_Line (" duration =" & Duration'Image (Curr_Dur)); + end Print_Statistic; + + ----------- + -- Stamp -- + ----------- + + procedure Stamp is + begin + Time_Stamp := Ada.Calendar.Clock; + end Stamp; + +begin + Ada.Text_IO.Put_Line ("ZLib " & ZLib.Version); + + loop + Generate_File; + + for Level in ZLib.Compression_Level'Range loop + + Ada.Text_IO.Put_Line ("Level =" + & ZLib.Compression_Level'Image (Level)); + + -- Test generic interface. + Open (File_In, In_File, In_File_Name); + Create (File_Out, Out_File, Z_File_Name); + + Stamp; + + -- Deflate using generic instantiation. + + ZLib.Deflate_Init + (Filter => Filter, + Level => Level, + Strategy => Strategy, + Header => Header); + + Translate (Filter); + Print_Statistic ("Generic compress", ZLib.Total_Out (Filter)); + ZLib.Close (Filter); + + Close (File_In); + Close (File_Out); + + Open (File_In, In_File, Z_File_Name); + Create (File_Out, Out_File, Out_File_Name); + + Stamp; + + -- Inflate using generic instantiation. + + ZLib.Inflate_Init (Filter, Header => Header); + + Translate (Filter); + Print_Statistic ("Generic decompress", ZLib.Total_Out (Filter)); + + ZLib.Close (Filter); + + Close (File_In); + Close (File_Out); + + Compare_Files (In_File_Name, Out_File_Name); + + -- Test stream interface. + + -- Compress to the back stream. + + Open (File_In, In_File, In_File_Name); + Create (File_Back, Out_File, Z_File_Name); + + Stamp; + + ZLib.Streams.Create + (Stream => File_Z, + Mode => ZLib.Streams.Out_Stream, + Back => ZLib.Streams.Stream_Access + (Stream (File_Back)), + Back_Compressed => True, + Level => Level, + Strategy => Strategy, + Header => Header); + + Copy_Streams + (Source => Stream (File_In).all, + Target => File_Z); + + -- Flushing internal buffers to the back stream. + + ZLib.Streams.Flush (File_Z, ZLib.Finish); + + Print_Statistic ("Write compress", + ZLib.Streams.Write_Total_Out (File_Z)); + + ZLib.Streams.Close (File_Z); + + Close (File_In); + Close (File_Back); + + -- Compare reading from original file and from + -- decompression stream. + + Open (File_In, In_File, In_File_Name); + Open (File_Back, In_File, Z_File_Name); + + ZLib.Streams.Create + (Stream => File_Z, + Mode => ZLib.Streams.In_Stream, + Back => ZLib.Streams.Stream_Access + (Stream (File_Back)), + Back_Compressed => True, + Header => Header); + + Stamp; + Compare_Streams (Stream (File_In).all, File_Z); + + Print_Statistic ("Read decompress", + ZLib.Streams.Read_Total_Out (File_Z)); + + ZLib.Streams.Close (File_Z); + Close (File_In); + Close (File_Back); + + -- Compress by reading from compression stream. + + Open (File_Back, In_File, In_File_Name); + Create (File_Out, Out_File, Z_File_Name); + + ZLib.Streams.Create + (Stream => File_Z, + Mode => ZLib.Streams.In_Stream, + Back => ZLib.Streams.Stream_Access + (Stream (File_Back)), + Back_Compressed => False, + Level => Level, + Strategy => Strategy, + Header => Header); + + Stamp; + Copy_Streams + (Source => File_Z, + Target => Stream (File_Out).all); + + Print_Statistic ("Read compress", + ZLib.Streams.Read_Total_Out (File_Z)); + + ZLib.Streams.Close (File_Z); + + Close (File_Out); + Close (File_Back); + + -- Decompress to decompression stream. + + Open (File_In, In_File, Z_File_Name); + Create (File_Back, Out_File, Out_File_Name); + + ZLib.Streams.Create + (Stream => File_Z, + Mode => ZLib.Streams.Out_Stream, + Back => ZLib.Streams.Stream_Access + (Stream (File_Back)), + Back_Compressed => False, + Header => Header); + + Stamp; + + Copy_Streams + (Source => Stream (File_In).all, + Target => File_Z); + + Print_Statistic ("Write decompress", + ZLib.Streams.Write_Total_Out (File_Z)); + + ZLib.Streams.Close (File_Z); + Close (File_In); + Close (File_Back); + + Compare_Files (In_File_Name, Out_File_Name); + end loop; + + Ada.Text_IO.Put_Line (Count'Image (File_Size) & " Ok."); + + exit when not Continuous; + + File_Size := File_Size + 1; + end loop; +end Test; diff --git a/contrib/zlib/contrib/ada/zlib-streams.adb b/contrib/zlib/contrib/ada/zlib-streams.adb new file mode 100644 index 00000000..b6497bae --- /dev/null +++ b/contrib/zlib/contrib/ada/zlib-streams.adb @@ -0,0 +1,225 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: zlib-streams.adb,v 1.10 2004/05/31 10:53:40 vagul Exp $ + +with Ada.Unchecked_Deallocation; + +package body ZLib.Streams is + + ----------- + -- Close -- + ----------- + + procedure Close (Stream : in out Stream_Type) is + procedure Free is new Ada.Unchecked_Deallocation + (Stream_Element_Array, Buffer_Access); + begin + if Stream.Mode = Out_Stream or Stream.Mode = Duplex then + -- We should flush the data written by the writer. + + Flush (Stream, Finish); + + Close (Stream.Writer); + end if; + + if Stream.Mode = In_Stream or Stream.Mode = Duplex then + Close (Stream.Reader); + Free (Stream.Buffer); + end if; + end Close; + + ------------ + -- Create -- + ------------ + + procedure Create + (Stream : out Stream_Type; + Mode : in Stream_Mode; + Back : in Stream_Access; + Back_Compressed : in Boolean; + Level : in Compression_Level := Default_Compression; + Strategy : in Strategy_Type := Default_Strategy; + Header : in Header_Type := Default; + Read_Buffer_Size : in Ada.Streams.Stream_Element_Offset + := Default_Buffer_Size; + Write_Buffer_Size : in Ada.Streams.Stream_Element_Offset + := Default_Buffer_Size) + is + + subtype Buffer_Subtype is Stream_Element_Array (1 .. Read_Buffer_Size); + + procedure Init_Filter + (Filter : in out Filter_Type; + Compress : in Boolean); + + ----------------- + -- Init_Filter -- + ----------------- + + procedure Init_Filter + (Filter : in out Filter_Type; + Compress : in Boolean) is + begin + if Compress then + Deflate_Init + (Filter, Level, Strategy, Header => Header); + else + Inflate_Init (Filter, Header => Header); + end if; + end Init_Filter; + + begin + Stream.Back := Back; + Stream.Mode := Mode; + + if Mode = Out_Stream or Mode = Duplex then + Init_Filter (Stream.Writer, Back_Compressed); + Stream.Buffer_Size := Write_Buffer_Size; + else + Stream.Buffer_Size := 0; + end if; + + if Mode = In_Stream or Mode = Duplex then + Init_Filter (Stream.Reader, not Back_Compressed); + + Stream.Buffer := new Buffer_Subtype; + Stream.Rest_First := Stream.Buffer'Last + 1; + Stream.Rest_Last := Stream.Buffer'Last; + end if; + end Create; + + ----------- + -- Flush -- + ----------- + + procedure Flush + (Stream : in out Stream_Type; + Mode : in Flush_Mode := Sync_Flush) + is + Buffer : Stream_Element_Array (1 .. Stream.Buffer_Size); + Last : Stream_Element_Offset; + begin + loop + Flush (Stream.Writer, Buffer, Last, Mode); + + Ada.Streams.Write (Stream.Back.all, Buffer (1 .. Last)); + + exit when Last < Buffer'Last; + end loop; + end Flush; + + ------------- + -- Is_Open -- + ------------- + + function Is_Open (Stream : Stream_Type) return Boolean is + begin + return Is_Open (Stream.Reader) or else Is_Open (Stream.Writer); + end Is_Open; + + ---------- + -- Read -- + ---------- + + procedure Read + (Stream : in out Stream_Type; + Item : out Stream_Element_Array; + Last : out Stream_Element_Offset) + is + + procedure Read + (Item : out Stream_Element_Array; + Last : out Stream_Element_Offset); + + ---------- + -- Read -- + ---------- + + procedure Read + (Item : out Stream_Element_Array; + Last : out Stream_Element_Offset) is + begin + Ada.Streams.Read (Stream.Back.all, Item, Last); + end Read; + + procedure Read is new ZLib.Read + (Read => Read, + Buffer => Stream.Buffer.all, + Rest_First => Stream.Rest_First, + Rest_Last => Stream.Rest_Last); + + begin + Read (Stream.Reader, Item, Last); + end Read; + + ------------------- + -- Read_Total_In -- + ------------------- + + function Read_Total_In (Stream : in Stream_Type) return Count is + begin + return Total_In (Stream.Reader); + end Read_Total_In; + + -------------------- + -- Read_Total_Out -- + -------------------- + + function Read_Total_Out (Stream : in Stream_Type) return Count is + begin + return Total_Out (Stream.Reader); + end Read_Total_Out; + + ----------- + -- Write -- + ----------- + + procedure Write + (Stream : in out Stream_Type; + Item : in Stream_Element_Array) + is + + procedure Write (Item : in Stream_Element_Array); + + ----------- + -- Write -- + ----------- + + procedure Write (Item : in Stream_Element_Array) is + begin + Ada.Streams.Write (Stream.Back.all, Item); + end Write; + + procedure Write is new ZLib.Write + (Write => Write, + Buffer_Size => Stream.Buffer_Size); + + begin + Write (Stream.Writer, Item, No_Flush); + end Write; + + -------------------- + -- Write_Total_In -- + -------------------- + + function Write_Total_In (Stream : in Stream_Type) return Count is + begin + return Total_In (Stream.Writer); + end Write_Total_In; + + --------------------- + -- Write_Total_Out -- + --------------------- + + function Write_Total_Out (Stream : in Stream_Type) return Count is + begin + return Total_Out (Stream.Writer); + end Write_Total_Out; + +end ZLib.Streams; diff --git a/contrib/zlib/contrib/ada/zlib-streams.ads b/contrib/zlib/contrib/ada/zlib-streams.ads new file mode 100644 index 00000000..8e26cd45 --- /dev/null +++ b/contrib/zlib/contrib/ada/zlib-streams.ads @@ -0,0 +1,114 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: zlib-streams.ads,v 1.12 2004/05/31 10:53:40 vagul Exp $ + +package ZLib.Streams is + + type Stream_Mode is (In_Stream, Out_Stream, Duplex); + + type Stream_Access is access all Ada.Streams.Root_Stream_Type'Class; + + type Stream_Type is + new Ada.Streams.Root_Stream_Type with private; + + procedure Read + (Stream : in out Stream_Type; + Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset); + + procedure Write + (Stream : in out Stream_Type; + Item : in Ada.Streams.Stream_Element_Array); + + procedure Flush + (Stream : in out Stream_Type; + Mode : in Flush_Mode := Sync_Flush); + -- Flush the written data to the back stream, + -- all data placed to the compressor is flushing to the Back stream. + -- Should not be used until necessary, because it is decreasing + -- compression. + + function Read_Total_In (Stream : in Stream_Type) return Count; + pragma Inline (Read_Total_In); + -- Return total number of bytes read from back stream so far. + + function Read_Total_Out (Stream : in Stream_Type) return Count; + pragma Inline (Read_Total_Out); + -- Return total number of bytes read so far. + + function Write_Total_In (Stream : in Stream_Type) return Count; + pragma Inline (Write_Total_In); + -- Return total number of bytes written so far. + + function Write_Total_Out (Stream : in Stream_Type) return Count; + pragma Inline (Write_Total_Out); + -- Return total number of bytes written to the back stream. + + procedure Create + (Stream : out Stream_Type; + Mode : in Stream_Mode; + Back : in Stream_Access; + Back_Compressed : in Boolean; + Level : in Compression_Level := Default_Compression; + Strategy : in Strategy_Type := Default_Strategy; + Header : in Header_Type := Default; + Read_Buffer_Size : in Ada.Streams.Stream_Element_Offset + := Default_Buffer_Size; + Write_Buffer_Size : in Ada.Streams.Stream_Element_Offset + := Default_Buffer_Size); + -- Create the Comression/Decompression stream. + -- If mode is In_Stream then Write operation is disabled. + -- If mode is Out_Stream then Read operation is disabled. + + -- If Back_Compressed is true then + -- Data written to the Stream is compressing to the Back stream + -- and data read from the Stream is decompressed data from the Back stream. + + -- If Back_Compressed is false then + -- Data written to the Stream is decompressing to the Back stream + -- and data read from the Stream is compressed data from the Back stream. + + -- !!! When the Need_Header is False ZLib-Ada is using undocumented + -- ZLib 1.1.4 functionality to do not create/wait for ZLib headers. + + function Is_Open (Stream : Stream_Type) return Boolean; + + procedure Close (Stream : in out Stream_Type); + +private + + use Ada.Streams; + + type Buffer_Access is access all Stream_Element_Array; + + type Stream_Type + is new Root_Stream_Type with + record + Mode : Stream_Mode; + + Buffer : Buffer_Access; + Rest_First : Stream_Element_Offset; + Rest_Last : Stream_Element_Offset; + -- Buffer for Read operation. + -- We need to have this buffer in the record + -- because not all read data from back stream + -- could be processed during the read operation. + + Buffer_Size : Stream_Element_Offset; + -- Buffer size for write operation. + -- We do not need to have this buffer + -- in the record because all data could be + -- processed in the write operation. + + Back : Stream_Access; + Reader : Filter_Type; + Writer : Filter_Type; + end record; + +end ZLib.Streams; diff --git a/contrib/zlib/contrib/ada/zlib-thin.adb b/contrib/zlib/contrib/ada/zlib-thin.adb new file mode 100644 index 00000000..0ca4a712 --- /dev/null +++ b/contrib/zlib/contrib/ada/zlib-thin.adb @@ -0,0 +1,141 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: zlib-thin.adb,v 1.8 2003/12/14 18:27:31 vagul Exp $ + +package body ZLib.Thin is + + ZLIB_VERSION : constant Chars_Ptr := zlibVersion; + + Z_Stream_Size : constant Int := Z_Stream'Size / System.Storage_Unit; + + -------------- + -- Avail_In -- + -------------- + + function Avail_In (Strm : in Z_Stream) return UInt is + begin + return Strm.Avail_In; + end Avail_In; + + --------------- + -- Avail_Out -- + --------------- + + function Avail_Out (Strm : in Z_Stream) return UInt is + begin + return Strm.Avail_Out; + end Avail_Out; + + ------------------ + -- Deflate_Init -- + ------------------ + + function Deflate_Init + (strm : Z_Streamp; + level : Int; + method : Int; + windowBits : Int; + memLevel : Int; + strategy : Int) + return Int is + begin + return deflateInit2 + (strm, + level, + method, + windowBits, + memLevel, + strategy, + ZLIB_VERSION, + Z_Stream_Size); + end Deflate_Init; + + ------------------ + -- Inflate_Init -- + ------------------ + + function Inflate_Init (strm : Z_Streamp; windowBits : Int) return Int is + begin + return inflateInit2 (strm, windowBits, ZLIB_VERSION, Z_Stream_Size); + end Inflate_Init; + + ------------------------ + -- Last_Error_Message -- + ------------------------ + + function Last_Error_Message (Strm : in Z_Stream) return String is + use Interfaces.C.Strings; + begin + if Strm.msg = Null_Ptr then + return ""; + else + return Value (Strm.msg); + end if; + end Last_Error_Message; + + ------------ + -- Set_In -- + ------------ + + procedure Set_In + (Strm : in out Z_Stream; + Buffer : in Voidp; + Size : in UInt) is + begin + Strm.Next_In := Buffer; + Strm.Avail_In := Size; + end Set_In; + + ------------------ + -- Set_Mem_Func -- + ------------------ + + procedure Set_Mem_Func + (Strm : in out Z_Stream; + Opaque : in Voidp; + Alloc : in alloc_func; + Free : in free_func) is + begin + Strm.opaque := Opaque; + Strm.zalloc := Alloc; + Strm.zfree := Free; + end Set_Mem_Func; + + ------------- + -- Set_Out -- + ------------- + + procedure Set_Out + (Strm : in out Z_Stream; + Buffer : in Voidp; + Size : in UInt) is + begin + Strm.Next_Out := Buffer; + Strm.Avail_Out := Size; + end Set_Out; + + -------------- + -- Total_In -- + -------------- + + function Total_In (Strm : in Z_Stream) return ULong is + begin + return Strm.Total_In; + end Total_In; + + --------------- + -- Total_Out -- + --------------- + + function Total_Out (Strm : in Z_Stream) return ULong is + begin + return Strm.Total_Out; + end Total_Out; + +end ZLib.Thin; diff --git a/contrib/zlib/contrib/ada/zlib-thin.ads b/contrib/zlib/contrib/ada/zlib-thin.ads new file mode 100644 index 00000000..810173cf --- /dev/null +++ b/contrib/zlib/contrib/ada/zlib-thin.ads @@ -0,0 +1,450 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: zlib-thin.ads,v 1.11 2004/07/23 06:33:11 vagul Exp $ + +with Interfaces.C.Strings; + +with System; + +private package ZLib.Thin is + + -- From zconf.h + + MAX_MEM_LEVEL : constant := 9; -- zconf.h:105 + -- zconf.h:105 + MAX_WBITS : constant := 15; -- zconf.h:115 + -- 32K LZ77 window + -- zconf.h:115 + SEEK_SET : constant := 8#0000#; -- zconf.h:244 + -- Seek from beginning of file. + -- zconf.h:244 + SEEK_CUR : constant := 1; -- zconf.h:245 + -- Seek from current position. + -- zconf.h:245 + SEEK_END : constant := 2; -- zconf.h:246 + -- Set file pointer to EOF plus "offset" + -- zconf.h:246 + + type Byte is new Interfaces.C.unsigned_char; -- 8 bits + -- zconf.h:214 + type UInt is new Interfaces.C.unsigned; -- 16 bits or more + -- zconf.h:216 + type Int is new Interfaces.C.int; + + type ULong is new Interfaces.C.unsigned_long; -- 32 bits or more + -- zconf.h:217 + subtype Chars_Ptr is Interfaces.C.Strings.chars_ptr; + + type ULong_Access is access ULong; + type Int_Access is access Int; + + subtype Voidp is System.Address; -- zconf.h:232 + + subtype Byte_Access is Voidp; + + Nul : constant Voidp := System.Null_Address; + -- end from zconf + + Z_NO_FLUSH : constant := 8#0000#; -- zlib.h:125 + -- zlib.h:125 + Z_PARTIAL_FLUSH : constant := 1; -- zlib.h:126 + -- will be removed, use + -- Z_SYNC_FLUSH instead + -- zlib.h:126 + Z_SYNC_FLUSH : constant := 2; -- zlib.h:127 + -- zlib.h:127 + Z_FULL_FLUSH : constant := 3; -- zlib.h:128 + -- zlib.h:128 + Z_FINISH : constant := 4; -- zlib.h:129 + -- zlib.h:129 + Z_OK : constant := 8#0000#; -- zlib.h:132 + -- zlib.h:132 + Z_STREAM_END : constant := 1; -- zlib.h:133 + -- zlib.h:133 + Z_NEED_DICT : constant := 2; -- zlib.h:134 + -- zlib.h:134 + Z_ERRNO : constant := -1; -- zlib.h:135 + -- zlib.h:135 + Z_STREAM_ERROR : constant := -2; -- zlib.h:136 + -- zlib.h:136 + Z_DATA_ERROR : constant := -3; -- zlib.h:137 + -- zlib.h:137 + Z_MEM_ERROR : constant := -4; -- zlib.h:138 + -- zlib.h:138 + Z_BUF_ERROR : constant := -5; -- zlib.h:139 + -- zlib.h:139 + Z_VERSION_ERROR : constant := -6; -- zlib.h:140 + -- zlib.h:140 + Z_NO_COMPRESSION : constant := 8#0000#; -- zlib.h:145 + -- zlib.h:145 + Z_BEST_SPEED : constant := 1; -- zlib.h:146 + -- zlib.h:146 + Z_BEST_COMPRESSION : constant := 9; -- zlib.h:147 + -- zlib.h:147 + Z_DEFAULT_COMPRESSION : constant := -1; -- zlib.h:148 + -- zlib.h:148 + Z_FILTERED : constant := 1; -- zlib.h:151 + -- zlib.h:151 + Z_HUFFMAN_ONLY : constant := 2; -- zlib.h:152 + -- zlib.h:152 + Z_DEFAULT_STRATEGY : constant := 8#0000#; -- zlib.h:153 + -- zlib.h:153 + Z_BINARY : constant := 8#0000#; -- zlib.h:156 + -- zlib.h:156 + Z_ASCII : constant := 1; -- zlib.h:157 + -- zlib.h:157 + Z_UNKNOWN : constant := 2; -- zlib.h:158 + -- zlib.h:158 + Z_DEFLATED : constant := 8; -- zlib.h:161 + -- zlib.h:161 + Z_NULL : constant := 8#0000#; -- zlib.h:164 + -- for initializing zalloc, zfree, opaque + -- zlib.h:164 + type gzFile is new Voidp; -- zlib.h:646 + + type Z_Stream is private; + + type Z_Streamp is access all Z_Stream; -- zlib.h:89 + + type alloc_func is access function + (Opaque : Voidp; + Items : UInt; + Size : UInt) + return Voidp; -- zlib.h:63 + + type free_func is access procedure (opaque : Voidp; address : Voidp); + + function zlibVersion return Chars_Ptr; + + function Deflate (strm : Z_Streamp; flush : Int) return Int; + + function DeflateEnd (strm : Z_Streamp) return Int; + + function Inflate (strm : Z_Streamp; flush : Int) return Int; + + function InflateEnd (strm : Z_Streamp) return Int; + + function deflateSetDictionary + (strm : Z_Streamp; + dictionary : Byte_Access; + dictLength : UInt) + return Int; + + function deflateCopy (dest : Z_Streamp; source : Z_Streamp) return Int; + -- zlib.h:478 + + function deflateReset (strm : Z_Streamp) return Int; -- zlib.h:495 + + function deflateParams + (strm : Z_Streamp; + level : Int; + strategy : Int) + return Int; -- zlib.h:506 + + function inflateSetDictionary + (strm : Z_Streamp; + dictionary : Byte_Access; + dictLength : UInt) + return Int; -- zlib.h:548 + + function inflateSync (strm : Z_Streamp) return Int; -- zlib.h:565 + + function inflateReset (strm : Z_Streamp) return Int; -- zlib.h:580 + + function compress + (dest : Byte_Access; + destLen : ULong_Access; + source : Byte_Access; + sourceLen : ULong) + return Int; -- zlib.h:601 + + function compress2 + (dest : Byte_Access; + destLen : ULong_Access; + source : Byte_Access; + sourceLen : ULong; + level : Int) + return Int; -- zlib.h:615 + + function uncompress + (dest : Byte_Access; + destLen : ULong_Access; + source : Byte_Access; + sourceLen : ULong) + return Int; + + function gzopen (path : Chars_Ptr; mode : Chars_Ptr) return gzFile; + + function gzdopen (fd : Int; mode : Chars_Ptr) return gzFile; + + function gzsetparams + (file : gzFile; + level : Int; + strategy : Int) + return Int; + + function gzread + (file : gzFile; + buf : Voidp; + len : UInt) + return Int; + + function gzwrite + (file : in gzFile; + buf : in Voidp; + len : in UInt) + return Int; + + function gzprintf (file : in gzFile; format : in Chars_Ptr) return Int; + + function gzputs (file : in gzFile; s : in Chars_Ptr) return Int; + + function gzgets + (file : gzFile; + buf : Chars_Ptr; + len : Int) + return Chars_Ptr; + + function gzputc (file : gzFile; char : Int) return Int; + + function gzgetc (file : gzFile) return Int; + + function gzflush (file : gzFile; flush : Int) return Int; + + function gzseek + (file : gzFile; + offset : Int; + whence : Int) + return Int; + + function gzrewind (file : gzFile) return Int; + + function gztell (file : gzFile) return Int; + + function gzeof (file : gzFile) return Int; + + function gzclose (file : gzFile) return Int; + + function gzerror (file : gzFile; errnum : Int_Access) return Chars_Ptr; + + function adler32 + (adler : ULong; + buf : Byte_Access; + len : UInt) + return ULong; + + function crc32 + (crc : ULong; + buf : Byte_Access; + len : UInt) + return ULong; + + function deflateInit + (strm : Z_Streamp; + level : Int; + version : Chars_Ptr; + stream_size : Int) + return Int; + + function deflateInit2 + (strm : Z_Streamp; + level : Int; + method : Int; + windowBits : Int; + memLevel : Int; + strategy : Int; + version : Chars_Ptr; + stream_size : Int) + return Int; + + function Deflate_Init + (strm : Z_Streamp; + level : Int; + method : Int; + windowBits : Int; + memLevel : Int; + strategy : Int) + return Int; + pragma Inline (Deflate_Init); + + function inflateInit + (strm : Z_Streamp; + version : Chars_Ptr; + stream_size : Int) + return Int; + + function inflateInit2 + (strm : in Z_Streamp; + windowBits : in Int; + version : in Chars_Ptr; + stream_size : in Int) + return Int; + + function inflateBackInit + (strm : in Z_Streamp; + windowBits : in Int; + window : in Byte_Access; + version : in Chars_Ptr; + stream_size : in Int) + return Int; + -- Size of window have to be 2**windowBits. + + function Inflate_Init (strm : Z_Streamp; windowBits : Int) return Int; + pragma Inline (Inflate_Init); + + function zError (err : Int) return Chars_Ptr; + + function inflateSyncPoint (z : Z_Streamp) return Int; + + function get_crc_table return ULong_Access; + + -- Interface to the available fields of the z_stream structure. + -- The application must update next_in and avail_in when avail_in has + -- dropped to zero. It must update next_out and avail_out when avail_out + -- has dropped to zero. The application must initialize zalloc, zfree and + -- opaque before calling the init function. + + procedure Set_In + (Strm : in out Z_Stream; + Buffer : in Voidp; + Size : in UInt); + pragma Inline (Set_In); + + procedure Set_Out + (Strm : in out Z_Stream; + Buffer : in Voidp; + Size : in UInt); + pragma Inline (Set_Out); + + procedure Set_Mem_Func + (Strm : in out Z_Stream; + Opaque : in Voidp; + Alloc : in alloc_func; + Free : in free_func); + pragma Inline (Set_Mem_Func); + + function Last_Error_Message (Strm : in Z_Stream) return String; + pragma Inline (Last_Error_Message); + + function Avail_Out (Strm : in Z_Stream) return UInt; + pragma Inline (Avail_Out); + + function Avail_In (Strm : in Z_Stream) return UInt; + pragma Inline (Avail_In); + + function Total_In (Strm : in Z_Stream) return ULong; + pragma Inline (Total_In); + + function Total_Out (Strm : in Z_Stream) return ULong; + pragma Inline (Total_Out); + + function inflateCopy + (dest : in Z_Streamp; + Source : in Z_Streamp) + return Int; + + function compressBound (Source_Len : in ULong) return ULong; + + function deflateBound + (Strm : in Z_Streamp; + Source_Len : in ULong) + return ULong; + + function gzungetc (C : in Int; File : in gzFile) return Int; + + function zlibCompileFlags return ULong; + +private + + type Z_Stream is record -- zlib.h:68 + Next_In : Voidp := Nul; -- next input byte + Avail_In : UInt := 0; -- number of bytes available at next_in + Total_In : ULong := 0; -- total nb of input bytes read so far + Next_Out : Voidp := Nul; -- next output byte should be put there + Avail_Out : UInt := 0; -- remaining free space at next_out + Total_Out : ULong := 0; -- total nb of bytes output so far + msg : Chars_Ptr; -- last error message, NULL if no error + state : Voidp; -- not visible by applications + zalloc : alloc_func := null; -- used to allocate the internal state + zfree : free_func := null; -- used to free the internal state + opaque : Voidp; -- private data object passed to + -- zalloc and zfree + data_type : Int; -- best guess about the data type: + -- ascii or binary + adler : ULong; -- adler32 value of the uncompressed + -- data + reserved : ULong; -- reserved for future use + end record; + + pragma Convention (C, Z_Stream); + + pragma Import (C, zlibVersion, "zlibVersion"); + pragma Import (C, Deflate, "deflate"); + pragma Import (C, DeflateEnd, "deflateEnd"); + pragma Import (C, Inflate, "inflate"); + pragma Import (C, InflateEnd, "inflateEnd"); + pragma Import (C, deflateSetDictionary, "deflateSetDictionary"); + pragma Import (C, deflateCopy, "deflateCopy"); + pragma Import (C, deflateReset, "deflateReset"); + pragma Import (C, deflateParams, "deflateParams"); + pragma Import (C, inflateSetDictionary, "inflateSetDictionary"); + pragma Import (C, inflateSync, "inflateSync"); + pragma Import (C, inflateReset, "inflateReset"); + pragma Import (C, compress, "compress"); + pragma Import (C, compress2, "compress2"); + pragma Import (C, uncompress, "uncompress"); + pragma Import (C, gzopen, "gzopen"); + pragma Import (C, gzdopen, "gzdopen"); + pragma Import (C, gzsetparams, "gzsetparams"); + pragma Import (C, gzread, "gzread"); + pragma Import (C, gzwrite, "gzwrite"); + pragma Import (C, gzprintf, "gzprintf"); + pragma Import (C, gzputs, "gzputs"); + pragma Import (C, gzgets, "gzgets"); + pragma Import (C, gzputc, "gzputc"); + pragma Import (C, gzgetc, "gzgetc"); + pragma Import (C, gzflush, "gzflush"); + pragma Import (C, gzseek, "gzseek"); + pragma Import (C, gzrewind, "gzrewind"); + pragma Import (C, gztell, "gztell"); + pragma Import (C, gzeof, "gzeof"); + pragma Import (C, gzclose, "gzclose"); + pragma Import (C, gzerror, "gzerror"); + pragma Import (C, adler32, "adler32"); + pragma Import (C, crc32, "crc32"); + pragma Import (C, deflateInit, "deflateInit_"); + pragma Import (C, inflateInit, "inflateInit_"); + pragma Import (C, deflateInit2, "deflateInit2_"); + pragma Import (C, inflateInit2, "inflateInit2_"); + pragma Import (C, zError, "zError"); + pragma Import (C, inflateSyncPoint, "inflateSyncPoint"); + pragma Import (C, get_crc_table, "get_crc_table"); + + -- since zlib 1.2.0: + + pragma Import (C, inflateCopy, "inflateCopy"); + pragma Import (C, compressBound, "compressBound"); + pragma Import (C, deflateBound, "deflateBound"); + pragma Import (C, gzungetc, "gzungetc"); + pragma Import (C, zlibCompileFlags, "zlibCompileFlags"); + + pragma Import (C, inflateBackInit, "inflateBackInit_"); + + -- I stopped binding the inflateBack routines, because realize that + -- it does not support zlib and gzip headers for now, and have no + -- symmetric deflateBack routines. + -- ZLib-Ada is symmetric regarding deflate/inflate data transformation + -- and has a similar generic callback interface for the + -- deflate/inflate transformation based on the regular Deflate/Inflate + -- routines. + + -- pragma Import (C, inflateBack, "inflateBack"); + -- pragma Import (C, inflateBackEnd, "inflateBackEnd"); + +end ZLib.Thin; diff --git a/contrib/zlib/contrib/ada/zlib.adb b/contrib/zlib/contrib/ada/zlib.adb new file mode 100644 index 00000000..8b6fd686 --- /dev/null +++ b/contrib/zlib/contrib/ada/zlib.adb @@ -0,0 +1,701 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2004 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: zlib.adb,v 1.31 2004/09/06 06:53:19 vagul Exp $ + +with Ada.Exceptions; +with Ada.Unchecked_Conversion; +with Ada.Unchecked_Deallocation; + +with Interfaces.C.Strings; + +with ZLib.Thin; + +package body ZLib is + + use type Thin.Int; + + type Z_Stream is new Thin.Z_Stream; + + type Return_Code_Enum is + (OK, + STREAM_END, + NEED_DICT, + ERRNO, + STREAM_ERROR, + DATA_ERROR, + MEM_ERROR, + BUF_ERROR, + VERSION_ERROR); + + type Flate_Step_Function is access + function (Strm : in Thin.Z_Streamp; Flush : in Thin.Int) return Thin.Int; + pragma Convention (C, Flate_Step_Function); + + type Flate_End_Function is access + function (Ctrm : in Thin.Z_Streamp) return Thin.Int; + pragma Convention (C, Flate_End_Function); + + type Flate_Type is record + Step : Flate_Step_Function; + Done : Flate_End_Function; + end record; + + subtype Footer_Array is Stream_Element_Array (1 .. 8); + + Simple_GZip_Header : constant Stream_Element_Array (1 .. 10) + := (16#1f#, 16#8b#, -- Magic header + 16#08#, -- Z_DEFLATED + 16#00#, -- Flags + 16#00#, 16#00#, 16#00#, 16#00#, -- Time + 16#00#, -- XFlags + 16#03# -- OS code + ); + -- The simplest gzip header is not for informational, but just for + -- gzip format compatibility. + -- Note that some code below is using assumption + -- Simple_GZip_Header'Last > Footer_Array'Last, so do not make + -- Simple_GZip_Header'Last <= Footer_Array'Last. + + Return_Code : constant array (Thin.Int range <>) of Return_Code_Enum + := (0 => OK, + 1 => STREAM_END, + 2 => NEED_DICT, + -1 => ERRNO, + -2 => STREAM_ERROR, + -3 => DATA_ERROR, + -4 => MEM_ERROR, + -5 => BUF_ERROR, + -6 => VERSION_ERROR); + + Flate : constant array (Boolean) of Flate_Type + := (True => (Step => Thin.Deflate'Access, + Done => Thin.DeflateEnd'Access), + False => (Step => Thin.Inflate'Access, + Done => Thin.InflateEnd'Access)); + + Flush_Finish : constant array (Boolean) of Flush_Mode + := (True => Finish, False => No_Flush); + + procedure Raise_Error (Stream : in Z_Stream); + pragma Inline (Raise_Error); + + procedure Raise_Error (Message : in String); + pragma Inline (Raise_Error); + + procedure Check_Error (Stream : in Z_Stream; Code : in Thin.Int); + + procedure Free is new Ada.Unchecked_Deallocation + (Z_Stream, Z_Stream_Access); + + function To_Thin_Access is new Ada.Unchecked_Conversion + (Z_Stream_Access, Thin.Z_Streamp); + + procedure Translate_GZip + (Filter : in out Filter_Type; + In_Data : in Ada.Streams.Stream_Element_Array; + In_Last : out Ada.Streams.Stream_Element_Offset; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode); + -- Separate translate routine for make gzip header. + + procedure Translate_Auto + (Filter : in out Filter_Type; + In_Data : in Ada.Streams.Stream_Element_Array; + In_Last : out Ada.Streams.Stream_Element_Offset; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode); + -- translate routine without additional headers. + + ----------------- + -- Check_Error -- + ----------------- + + procedure Check_Error (Stream : in Z_Stream; Code : in Thin.Int) is + use type Thin.Int; + begin + if Code /= Thin.Z_OK then + Raise_Error + (Return_Code_Enum'Image (Return_Code (Code)) + & ": " & Last_Error_Message (Stream)); + end if; + end Check_Error; + + ----------- + -- Close -- + ----------- + + procedure Close + (Filter : in out Filter_Type; + Ignore_Error : in Boolean := False) + is + Code : Thin.Int; + begin + if not Ignore_Error and then not Is_Open (Filter) then + raise Status_Error; + end if; + + Code := Flate (Filter.Compression).Done (To_Thin_Access (Filter.Strm)); + + if Ignore_Error or else Code = Thin.Z_OK then + Free (Filter.Strm); + else + declare + Error_Message : constant String + := Last_Error_Message (Filter.Strm.all); + begin + Free (Filter.Strm); + Ada.Exceptions.Raise_Exception + (ZLib_Error'Identity, + Return_Code_Enum'Image (Return_Code (Code)) + & ": " & Error_Message); + end; + end if; + end Close; + + ----------- + -- CRC32 -- + ----------- + + function CRC32 + (CRC : in Unsigned_32; + Data : in Ada.Streams.Stream_Element_Array) + return Unsigned_32 + is + use Thin; + begin + return Unsigned_32 (crc32 (ULong (CRC), + Data'Address, + Data'Length)); + end CRC32; + + procedure CRC32 + (CRC : in out Unsigned_32; + Data : in Ada.Streams.Stream_Element_Array) is + begin + CRC := CRC32 (CRC, Data); + end CRC32; + + ------------------ + -- Deflate_Init -- + ------------------ + + procedure Deflate_Init + (Filter : in out Filter_Type; + Level : in Compression_Level := Default_Compression; + Strategy : in Strategy_Type := Default_Strategy; + Method : in Compression_Method := Deflated; + Window_Bits : in Window_Bits_Type := Default_Window_Bits; + Memory_Level : in Memory_Level_Type := Default_Memory_Level; + Header : in Header_Type := Default) + is + use type Thin.Int; + Win_Bits : Thin.Int := Thin.Int (Window_Bits); + begin + if Is_Open (Filter) then + raise Status_Error; + end if; + + -- We allow ZLib to make header only in case of default header type. + -- Otherwise we would either do header by ourselfs, or do not do + -- header at all. + + if Header = None or else Header = GZip then + Win_Bits := -Win_Bits; + end if; + + -- For the GZip CRC calculation and make headers. + + if Header = GZip then + Filter.CRC := 0; + Filter.Offset := Simple_GZip_Header'First; + else + Filter.Offset := Simple_GZip_Header'Last + 1; + end if; + + Filter.Strm := new Z_Stream; + Filter.Compression := True; + Filter.Stream_End := False; + Filter.Header := Header; + + if Thin.Deflate_Init + (To_Thin_Access (Filter.Strm), + Level => Thin.Int (Level), + method => Thin.Int (Method), + windowBits => Win_Bits, + memLevel => Thin.Int (Memory_Level), + strategy => Thin.Int (Strategy)) /= Thin.Z_OK + then + Raise_Error (Filter.Strm.all); + end if; + end Deflate_Init; + + ----------- + -- Flush -- + ----------- + + procedure Flush + (Filter : in out Filter_Type; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode) + is + No_Data : Stream_Element_Array := (1 .. 0 => 0); + Last : Stream_Element_Offset; + begin + Translate (Filter, No_Data, Last, Out_Data, Out_Last, Flush); + end Flush; + + ----------------------- + -- Generic_Translate -- + ----------------------- + + procedure Generic_Translate + (Filter : in out ZLib.Filter_Type; + In_Buffer_Size : in Integer := Default_Buffer_Size; + Out_Buffer_Size : in Integer := Default_Buffer_Size) + is + In_Buffer : Stream_Element_Array + (1 .. Stream_Element_Offset (In_Buffer_Size)); + Out_Buffer : Stream_Element_Array + (1 .. Stream_Element_Offset (Out_Buffer_Size)); + Last : Stream_Element_Offset; + In_Last : Stream_Element_Offset; + In_First : Stream_Element_Offset; + Out_Last : Stream_Element_Offset; + begin + Main : loop + Data_In (In_Buffer, Last); + + In_First := In_Buffer'First; + + loop + Translate + (Filter => Filter, + In_Data => In_Buffer (In_First .. Last), + In_Last => In_Last, + Out_Data => Out_Buffer, + Out_Last => Out_Last, + Flush => Flush_Finish (Last < In_Buffer'First)); + + if Out_Buffer'First <= Out_Last then + Data_Out (Out_Buffer (Out_Buffer'First .. Out_Last)); + end if; + + exit Main when Stream_End (Filter); + + -- The end of in buffer. + + exit when In_Last = Last; + + In_First := In_Last + 1; + end loop; + end loop Main; + + end Generic_Translate; + + ------------------ + -- Inflate_Init -- + ------------------ + + procedure Inflate_Init + (Filter : in out Filter_Type; + Window_Bits : in Window_Bits_Type := Default_Window_Bits; + Header : in Header_Type := Default) + is + use type Thin.Int; + Win_Bits : Thin.Int := Thin.Int (Window_Bits); + + procedure Check_Version; + -- Check the latest header types compatibility. + + procedure Check_Version is + begin + if Version <= "1.1.4" then + Raise_Error + ("Inflate header type " & Header_Type'Image (Header) + & " incompatible with ZLib version " & Version); + end if; + end Check_Version; + + begin + if Is_Open (Filter) then + raise Status_Error; + end if; + + case Header is + when None => + Check_Version; + + -- Inflate data without headers determined + -- by negative Win_Bits. + + Win_Bits := -Win_Bits; + when GZip => + Check_Version; + + -- Inflate gzip data defined by flag 16. + + Win_Bits := Win_Bits + 16; + when Auto => + Check_Version; + + -- Inflate with automatic detection + -- of gzip or native header defined by flag 32. + + Win_Bits := Win_Bits + 32; + when Default => null; + end case; + + Filter.Strm := new Z_Stream; + Filter.Compression := False; + Filter.Stream_End := False; + Filter.Header := Header; + + if Thin.Inflate_Init + (To_Thin_Access (Filter.Strm), Win_Bits) /= Thin.Z_OK + then + Raise_Error (Filter.Strm.all); + end if; + end Inflate_Init; + + ------------- + -- Is_Open -- + ------------- + + function Is_Open (Filter : in Filter_Type) return Boolean is + begin + return Filter.Strm /= null; + end Is_Open; + + ----------------- + -- Raise_Error -- + ----------------- + + procedure Raise_Error (Message : in String) is + begin + Ada.Exceptions.Raise_Exception (ZLib_Error'Identity, Message); + end Raise_Error; + + procedure Raise_Error (Stream : in Z_Stream) is + begin + Raise_Error (Last_Error_Message (Stream)); + end Raise_Error; + + ---------- + -- Read -- + ---------- + + procedure Read + (Filter : in out Filter_Type; + Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode := No_Flush) + is + In_Last : Stream_Element_Offset; + Item_First : Ada.Streams.Stream_Element_Offset := Item'First; + V_Flush : Flush_Mode := Flush; + + begin + pragma Assert (Rest_First in Buffer'First .. Buffer'Last + 1); + pragma Assert (Rest_Last in Buffer'First - 1 .. Buffer'Last); + + loop + if Rest_Last = Buffer'First - 1 then + V_Flush := Finish; + + elsif Rest_First > Rest_Last then + Read (Buffer, Rest_Last); + Rest_First := Buffer'First; + + if Rest_Last < Buffer'First then + V_Flush := Finish; + end if; + end if; + + Translate + (Filter => Filter, + In_Data => Buffer (Rest_First .. Rest_Last), + In_Last => In_Last, + Out_Data => Item (Item_First .. Item'Last), + Out_Last => Last, + Flush => V_Flush); + + Rest_First := In_Last + 1; + + exit when Stream_End (Filter) + or else Last = Item'Last + or else (Last >= Item'First and then Allow_Read_Some); + + Item_First := Last + 1; + end loop; + end Read; + + ---------------- + -- Stream_End -- + ---------------- + + function Stream_End (Filter : in Filter_Type) return Boolean is + begin + if Filter.Header = GZip and Filter.Compression then + return Filter.Stream_End + and then Filter.Offset = Footer_Array'Last + 1; + else + return Filter.Stream_End; + end if; + end Stream_End; + + -------------- + -- Total_In -- + -------------- + + function Total_In (Filter : in Filter_Type) return Count is + begin + return Count (Thin.Total_In (To_Thin_Access (Filter.Strm).all)); + end Total_In; + + --------------- + -- Total_Out -- + --------------- + + function Total_Out (Filter : in Filter_Type) return Count is + begin + return Count (Thin.Total_Out (To_Thin_Access (Filter.Strm).all)); + end Total_Out; + + --------------- + -- Translate -- + --------------- + + procedure Translate + (Filter : in out Filter_Type; + In_Data : in Ada.Streams.Stream_Element_Array; + In_Last : out Ada.Streams.Stream_Element_Offset; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode) is + begin + if Filter.Header = GZip and then Filter.Compression then + Translate_GZip + (Filter => Filter, + In_Data => In_Data, + In_Last => In_Last, + Out_Data => Out_Data, + Out_Last => Out_Last, + Flush => Flush); + else + Translate_Auto + (Filter => Filter, + In_Data => In_Data, + In_Last => In_Last, + Out_Data => Out_Data, + Out_Last => Out_Last, + Flush => Flush); + end if; + end Translate; + + -------------------- + -- Translate_Auto -- + -------------------- + + procedure Translate_Auto + (Filter : in out Filter_Type; + In_Data : in Ada.Streams.Stream_Element_Array; + In_Last : out Ada.Streams.Stream_Element_Offset; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode) + is + use type Thin.Int; + Code : Thin.Int; + + begin + if not Is_Open (Filter) then + raise Status_Error; + end if; + + if Out_Data'Length = 0 and then In_Data'Length = 0 then + raise Constraint_Error; + end if; + + Set_Out (Filter.Strm.all, Out_Data'Address, Out_Data'Length); + Set_In (Filter.Strm.all, In_Data'Address, In_Data'Length); + + Code := Flate (Filter.Compression).Step + (To_Thin_Access (Filter.Strm), + Thin.Int (Flush)); + + if Code = Thin.Z_STREAM_END then + Filter.Stream_End := True; + else + Check_Error (Filter.Strm.all, Code); + end if; + + In_Last := In_Data'Last + - Stream_Element_Offset (Avail_In (Filter.Strm.all)); + Out_Last := Out_Data'Last + - Stream_Element_Offset (Avail_Out (Filter.Strm.all)); + end Translate_Auto; + + -------------------- + -- Translate_GZip -- + -------------------- + + procedure Translate_GZip + (Filter : in out Filter_Type; + In_Data : in Ada.Streams.Stream_Element_Array; + In_Last : out Ada.Streams.Stream_Element_Offset; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode) + is + Out_First : Stream_Element_Offset; + + procedure Add_Data (Data : in Stream_Element_Array); + -- Add data to stream from the Filter.Offset till necessary, + -- used for add gzip headr/footer. + + procedure Put_32 + (Item : in out Stream_Element_Array; + Data : in Unsigned_32); + pragma Inline (Put_32); + + -------------- + -- Add_Data -- + -------------- + + procedure Add_Data (Data : in Stream_Element_Array) is + Data_First : Stream_Element_Offset renames Filter.Offset; + Data_Last : Stream_Element_Offset; + Data_Len : Stream_Element_Offset; -- -1 + Out_Len : Stream_Element_Offset; -- -1 + begin + Out_First := Out_Last + 1; + + if Data_First > Data'Last then + return; + end if; + + Data_Len := Data'Last - Data_First; + Out_Len := Out_Data'Last - Out_First; + + if Data_Len <= Out_Len then + Out_Last := Out_First + Data_Len; + Data_Last := Data'Last; + else + Out_Last := Out_Data'Last; + Data_Last := Data_First + Out_Len; + end if; + + Out_Data (Out_First .. Out_Last) := Data (Data_First .. Data_Last); + + Data_First := Data_Last + 1; + Out_First := Out_Last + 1; + end Add_Data; + + ------------ + -- Put_32 -- + ------------ + + procedure Put_32 + (Item : in out Stream_Element_Array; + Data : in Unsigned_32) + is + D : Unsigned_32 := Data; + begin + for J in Item'First .. Item'First + 3 loop + Item (J) := Stream_Element (D and 16#FF#); + D := Shift_Right (D, 8); + end loop; + end Put_32; + + begin + Out_Last := Out_Data'First - 1; + + if not Filter.Stream_End then + Add_Data (Simple_GZip_Header); + + Translate_Auto + (Filter => Filter, + In_Data => In_Data, + In_Last => In_Last, + Out_Data => Out_Data (Out_First .. Out_Data'Last), + Out_Last => Out_Last, + Flush => Flush); + + CRC32 (Filter.CRC, In_Data (In_Data'First .. In_Last)); + end if; + + if Filter.Stream_End and then Out_Last <= Out_Data'Last then + -- This detection method would work only when + -- Simple_GZip_Header'Last > Footer_Array'Last + + if Filter.Offset = Simple_GZip_Header'Last + 1 then + Filter.Offset := Footer_Array'First; + end if; + + declare + Footer : Footer_Array; + begin + Put_32 (Footer, Filter.CRC); + Put_32 (Footer (Footer'First + 4 .. Footer'Last), + Unsigned_32 (Total_In (Filter))); + Add_Data (Footer); + end; + end if; + end Translate_GZip; + + ------------- + -- Version -- + ------------- + + function Version return String is + begin + return Interfaces.C.Strings.Value (Thin.zlibVersion); + end Version; + + ----------- + -- Write -- + ----------- + + procedure Write + (Filter : in out Filter_Type; + Item : in Ada.Streams.Stream_Element_Array; + Flush : in Flush_Mode := No_Flush) + is + Buffer : Stream_Element_Array (1 .. Buffer_Size); + In_Last : Stream_Element_Offset; + Out_Last : Stream_Element_Offset; + In_First : Stream_Element_Offset := Item'First; + begin + if Item'Length = 0 and Flush = No_Flush then + return; + end if; + + loop + Translate + (Filter => Filter, + In_Data => Item (In_First .. Item'Last), + In_Last => In_Last, + Out_Data => Buffer, + Out_Last => Out_Last, + Flush => Flush); + + if Out_Last >= Buffer'First then + Write (Buffer (1 .. Out_Last)); + end if; + + exit when In_Last = Item'Last or Stream_End (Filter); + + In_First := In_Last + 1; + end loop; + end Write; + +end ZLib; diff --git a/contrib/zlib/contrib/ada/zlib.ads b/contrib/zlib/contrib/ada/zlib.ads new file mode 100644 index 00000000..79ffc409 --- /dev/null +++ b/contrib/zlib/contrib/ada/zlib.ads @@ -0,0 +1,328 @@ +------------------------------------------------------------------------------ +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2004 Dmitriy Anisimkov -- +-- -- +-- This library is free software; you can redistribute it and/or modify -- +-- it under the terms of the GNU General Public License as published by -- +-- the Free Software Foundation; either version 2 of the License, or (at -- +-- your option) any later version. -- +-- -- +-- This library is distributed in the hope that it will be useful, but -- +-- WITHOUT ANY WARRANTY; without even the implied warranty of -- +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- +-- General Public License for more details. -- +-- -- +-- You should have received a copy of the GNU General Public License -- +-- along with this library; if not, write to the Free Software Foundation, -- +-- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -- +-- -- +-- As a special exception, if other files instantiate generics from this -- +-- unit, or you link this unit with other files to produce an executable, -- +-- this unit does not by itself cause the resulting executable to be -- +-- covered by the GNU General Public License. This exception does not -- +-- however invalidate any other reasons why the executable file might be -- +-- covered by the GNU Public License. -- +------------------------------------------------------------------------------ + +-- $Id: zlib.ads,v 1.26 2004/09/06 06:53:19 vagul Exp $ + +with Ada.Streams; + +with Interfaces; + +package ZLib is + + ZLib_Error : exception; + Status_Error : exception; + + type Compression_Level is new Integer range -1 .. 9; + + type Flush_Mode is private; + + type Compression_Method is private; + + type Window_Bits_Type is new Integer range 8 .. 15; + + type Memory_Level_Type is new Integer range 1 .. 9; + + type Unsigned_32 is new Interfaces.Unsigned_32; + + type Strategy_Type is private; + + type Header_Type is (None, Auto, Default, GZip); + -- Header type usage have a some limitation for inflate. + -- See comment for Inflate_Init. + + subtype Count is Ada.Streams.Stream_Element_Count; + + Default_Memory_Level : constant Memory_Level_Type := 8; + Default_Window_Bits : constant Window_Bits_Type := 15; + + ---------------------------------- + -- Compression method constants -- + ---------------------------------- + + Deflated : constant Compression_Method; + -- Only one method allowed in this ZLib version + + --------------------------------- + -- Compression level constants -- + --------------------------------- + + No_Compression : constant Compression_Level := 0; + Best_Speed : constant Compression_Level := 1; + Best_Compression : constant Compression_Level := 9; + Default_Compression : constant Compression_Level := -1; + + -------------------------- + -- Flush mode constants -- + -------------------------- + + No_Flush : constant Flush_Mode; + -- Regular way for compression, no flush + + Partial_Flush : constant Flush_Mode; + -- Will be removed, use Z_SYNC_FLUSH instead + + Sync_Flush : constant Flush_Mode; + -- All pending output is flushed to the output buffer and the output + -- is aligned on a byte boundary, so that the decompressor can get all + -- input data available so far. (In particular avail_in is zero after the + -- call if enough output space has been provided before the call.) + -- Flushing may degrade compression for some compression algorithms and so + -- it should be used only when necessary. + + Block_Flush : constant Flush_Mode; + -- Z_BLOCK requests that inflate() stop + -- if and when it get to the next deflate block boundary. When decoding the + -- zlib or gzip format, this will cause inflate() to return immediately + -- after the header and before the first block. When doing a raw inflate, + -- inflate() will go ahead and process the first block, and will return + -- when it gets to the end of that block, or when it runs out of data. + + Full_Flush : constant Flush_Mode; + -- All output is flushed as with SYNC_FLUSH, and the compression state + -- is reset so that decompression can restart from this point if previous + -- compressed data has been damaged or if random access is desired. Using + -- Full_Flush too often can seriously degrade the compression. + + Finish : constant Flush_Mode; + -- Just for tell the compressor that input data is complete. + + ------------------------------------ + -- Compression strategy constants -- + ------------------------------------ + + -- RLE stategy could be used only in version 1.2.0 and later. + + Filtered : constant Strategy_Type; + Huffman_Only : constant Strategy_Type; + RLE : constant Strategy_Type; + Default_Strategy : constant Strategy_Type; + + Default_Buffer_Size : constant := 4096; + + type Filter_Type is tagged limited private; + -- The filter is for compression and for decompression. + -- The usage of the type is depend of its initialization. + + function Version return String; + pragma Inline (Version); + -- Return string representation of the ZLib version. + + procedure Deflate_Init + (Filter : in out Filter_Type; + Level : in Compression_Level := Default_Compression; + Strategy : in Strategy_Type := Default_Strategy; + Method : in Compression_Method := Deflated; + Window_Bits : in Window_Bits_Type := Default_Window_Bits; + Memory_Level : in Memory_Level_Type := Default_Memory_Level; + Header : in Header_Type := Default); + -- Compressor initialization. + -- When Header parameter is Auto or Default, then default zlib header + -- would be provided for compressed data. + -- When Header is GZip, then gzip header would be set instead of + -- default header. + -- When Header is None, no header would be set for compressed data. + + procedure Inflate_Init + (Filter : in out Filter_Type; + Window_Bits : in Window_Bits_Type := Default_Window_Bits; + Header : in Header_Type := Default); + -- Decompressor initialization. + -- Default header type mean that ZLib default header is expecting in the + -- input compressed stream. + -- Header type None mean that no header is expecting in the input stream. + -- GZip header type mean that GZip header is expecting in the + -- input compressed stream. + -- Auto header type mean that header type (GZip or Native) would be + -- detected automatically in the input stream. + -- Note that header types parameter values None, GZip and Auto are + -- supported for inflate routine only in ZLib versions 1.2.0.2 and later. + -- Deflate_Init is supporting all header types. + + function Is_Open (Filter : in Filter_Type) return Boolean; + pragma Inline (Is_Open); + -- Is the filter opened for compression or decompression. + + procedure Close + (Filter : in out Filter_Type; + Ignore_Error : in Boolean := False); + -- Closing the compression or decompressor. + -- If stream is closing before the complete and Ignore_Error is False, + -- The exception would be raised. + + generic + with procedure Data_In + (Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset); + with procedure Data_Out + (Item : in Ada.Streams.Stream_Element_Array); + procedure Generic_Translate + (Filter : in out Filter_Type; + In_Buffer_Size : in Integer := Default_Buffer_Size; + Out_Buffer_Size : in Integer := Default_Buffer_Size); + -- Compress/decompress data fetch from Data_In routine and pass the result + -- to the Data_Out routine. User should provide Data_In and Data_Out + -- for compression/decompression data flow. + -- Compression or decompression depend on Filter initialization. + + function Total_In (Filter : in Filter_Type) return Count; + pragma Inline (Total_In); + -- Returns total number of input bytes read so far + + function Total_Out (Filter : in Filter_Type) return Count; + pragma Inline (Total_Out); + -- Returns total number of bytes output so far + + function CRC32 + (CRC : in Unsigned_32; + Data : in Ada.Streams.Stream_Element_Array) + return Unsigned_32; + pragma Inline (CRC32); + -- Compute CRC32, it could be necessary for make gzip format + + procedure CRC32 + (CRC : in out Unsigned_32; + Data : in Ada.Streams.Stream_Element_Array); + pragma Inline (CRC32); + -- Compute CRC32, it could be necessary for make gzip format + + ------------------------------------------------- + -- Below is more complex low level routines. -- + ------------------------------------------------- + + procedure Translate + (Filter : in out Filter_Type; + In_Data : in Ada.Streams.Stream_Element_Array; + In_Last : out Ada.Streams.Stream_Element_Offset; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode); + -- Compress/decompress the In_Data buffer and place the result into + -- Out_Data. In_Last is the index of last element from In_Data accepted by + -- the Filter. Out_Last is the last element of the received data from + -- Filter. To tell the filter that incoming data are complete put the + -- Flush parameter to Finish. + + function Stream_End (Filter : in Filter_Type) return Boolean; + pragma Inline (Stream_End); + -- Return the true when the stream is complete. + + procedure Flush + (Filter : in out Filter_Type; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode); + pragma Inline (Flush); + -- Flushing the data from the compressor. + + generic + with procedure Write + (Item : in Ada.Streams.Stream_Element_Array); + -- User should provide this routine for accept + -- compressed/decompressed data. + + Buffer_Size : in Ada.Streams.Stream_Element_Offset + := Default_Buffer_Size; + -- Buffer size for Write user routine. + + procedure Write + (Filter : in out Filter_Type; + Item : in Ada.Streams.Stream_Element_Array; + Flush : in Flush_Mode := No_Flush); + -- Compress/Decompress data from Item to the generic parameter procedure + -- Write. Output buffer size could be set in Buffer_Size generic parameter. + + generic + with procedure Read + (Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset); + -- User should provide data for compression/decompression + -- thru this routine. + + Buffer : in out Ada.Streams.Stream_Element_Array; + -- Buffer for keep remaining data from the previous + -- back read. + + Rest_First, Rest_Last : in out Ada.Streams.Stream_Element_Offset; + -- Rest_First have to be initialized to Buffer'Last + 1 + -- Rest_Last have to be initialized to Buffer'Last + -- before usage. + + Allow_Read_Some : in Boolean := False; + -- Is it allowed to return Last < Item'Last before end of data. + + procedure Read + (Filter : in out Filter_Type; + Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode := No_Flush); + -- Compress/Decompress data from generic parameter procedure Read to the + -- Item. User should provide Buffer and initialized Rest_First, Rest_Last + -- indicators. If Allow_Read_Some is True, Read routines could return + -- Last < Item'Last only at end of stream. + +private + + use Ada.Streams; + + pragma Assert (Ada.Streams.Stream_Element'Size = 8); + pragma Assert (Ada.Streams.Stream_Element'Modulus = 2**8); + + type Flush_Mode is new Integer range 0 .. 5; + + type Compression_Method is new Integer range 8 .. 8; + + type Strategy_Type is new Integer range 0 .. 3; + + No_Flush : constant Flush_Mode := 0; + Partial_Flush : constant Flush_Mode := 1; + Sync_Flush : constant Flush_Mode := 2; + Full_Flush : constant Flush_Mode := 3; + Finish : constant Flush_Mode := 4; + Block_Flush : constant Flush_Mode := 5; + + Filtered : constant Strategy_Type := 1; + Huffman_Only : constant Strategy_Type := 2; + RLE : constant Strategy_Type := 3; + Default_Strategy : constant Strategy_Type := 0; + + Deflated : constant Compression_Method := 8; + + type Z_Stream; + + type Z_Stream_Access is access all Z_Stream; + + type Filter_Type is tagged limited record + Strm : Z_Stream_Access; + Compression : Boolean; + Stream_End : Boolean; + Header : Header_Type; + CRC : Unsigned_32; + Offset : Stream_Element_Offset; + -- Offset for gzip header/footer output. + end record; + +end ZLib; diff --git a/contrib/zlib/contrib/ada/zlib.gpr b/contrib/zlib/contrib/ada/zlib.gpr new file mode 100644 index 00000000..296b22aa --- /dev/null +++ b/contrib/zlib/contrib/ada/zlib.gpr @@ -0,0 +1,20 @@ +project Zlib is + + for Languages use ("Ada"); + for Source_Dirs use ("."); + for Object_Dir use "."; + for Main use ("test.adb", "mtest.adb", "read.adb", "buffer_demo"); + + package Compiler is + for Default_Switches ("ada") use ("-gnatwcfilopru", "-gnatVcdfimorst", "-gnatyabcefhiklmnoprst"); + end Compiler; + + package Linker is + for Default_Switches ("ada") use ("-lz"); + end Linker; + + package Builder is + for Default_Switches ("ada") use ("-s", "-gnatQ"); + end Builder; + +end Zlib; diff --git a/contrib/zlib/contrib/amd64/amd64-match.S b/contrib/zlib/contrib/amd64/amd64-match.S new file mode 100644 index 00000000..81d4a1c9 --- /dev/null +++ b/contrib/zlib/contrib/amd64/amd64-match.S @@ -0,0 +1,452 @@ +/* + * match.S -- optimized version of longest_match() + * based on the similar work by Gilles Vollant, and Brian Raiter, written 1998 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the BSD License. Use by owners of Che Guevarra + * parafernalia is prohibited, where possible, and highly discouraged + * elsewhere. + */ + +#ifndef NO_UNDERLINE +# define match_init _match_init +# define longest_match _longest_match +#endif + +#define scanend ebx +#define scanendw bx +#define chainlenwmask edx /* high word: current chain len low word: s->wmask */ +#define curmatch rsi +#define curmatchd esi +#define windowbestlen r8 +#define scanalign r9 +#define scanalignd r9d +#define window r10 +#define bestlen r11 +#define bestlend r11d +#define scanstart r12d +#define scanstartw r12w +#define scan r13 +#define nicematch r14d +#define limit r15 +#define limitd r15d +#define prev rcx + +/* + * The 258 is a "magic number, not a parameter -- changing it + * breaks the hell loose + */ +#define MAX_MATCH (258) +#define MIN_MATCH (3) +#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1) +#define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7) + +/* stack frame offsets */ +#define LocalVarsSize (112) +#define _chainlenwmask ( 8-LocalVarsSize)(%rsp) +#define _windowbestlen (16-LocalVarsSize)(%rsp) +#define save_r14 (24-LocalVarsSize)(%rsp) +#define save_rsi (32-LocalVarsSize)(%rsp) +#define save_rbx (40-LocalVarsSize)(%rsp) +#define save_r12 (56-LocalVarsSize)(%rsp) +#define save_r13 (64-LocalVarsSize)(%rsp) +#define save_r15 (80-LocalVarsSize)(%rsp) + + +.globl match_init, longest_match + +/* + * On AMD64 the first argument of a function (in our case -- the pointer to + * deflate_state structure) is passed in %rdi, hence our offsets below are + * all off of that. + */ + +/* you can check the structure offset by running + +#include +#include +#include "deflate.h" + +void print_depl() +{ +deflate_state ds; +deflate_state *s=&ds; +printf("size pointer=%u\n",(int)sizeof(void*)); + +printf("#define dsWSize (%3u)(%%rdi)\n",(int)(((char*)&(s->w_size))-((char*)s))); +printf("#define dsWMask (%3u)(%%rdi)\n",(int)(((char*)&(s->w_mask))-((char*)s))); +printf("#define dsWindow (%3u)(%%rdi)\n",(int)(((char*)&(s->window))-((char*)s))); +printf("#define dsPrev (%3u)(%%rdi)\n",(int)(((char*)&(s->prev))-((char*)s))); +printf("#define dsMatchLen (%3u)(%%rdi)\n",(int)(((char*)&(s->match_length))-((char*)s))); +printf("#define dsPrevMatch (%3u)(%%rdi)\n",(int)(((char*)&(s->prev_match))-((char*)s))); +printf("#define dsStrStart (%3u)(%%rdi)\n",(int)(((char*)&(s->strstart))-((char*)s))); +printf("#define dsMatchStart (%3u)(%%rdi)\n",(int)(((char*)&(s->match_start))-((char*)s))); +printf("#define dsLookahead (%3u)(%%rdi)\n",(int)(((char*)&(s->lookahead))-((char*)s))); +printf("#define dsPrevLen (%3u)(%%rdi)\n",(int)(((char*)&(s->prev_length))-((char*)s))); +printf("#define dsMaxChainLen (%3u)(%%rdi)\n",(int)(((char*)&(s->max_chain_length))-((char*)s))); +printf("#define dsGoodMatch (%3u)(%%rdi)\n",(int)(((char*)&(s->good_match))-((char*)s))); +printf("#define dsNiceMatch (%3u)(%%rdi)\n",(int)(((char*)&(s->nice_match))-((char*)s))); +} + +*/ + + +/* + to compile for XCode 3.2 on MacOSX x86_64 + - run "gcc -g -c -DXCODE_MAC_X64_STRUCTURE amd64-match.S" + */ + + +#ifndef CURRENT_LINX_XCODE_MAC_X64_STRUCTURE +#define dsWSize ( 68)(%rdi) +#define dsWMask ( 76)(%rdi) +#define dsWindow ( 80)(%rdi) +#define dsPrev ( 96)(%rdi) +#define dsMatchLen (144)(%rdi) +#define dsPrevMatch (148)(%rdi) +#define dsStrStart (156)(%rdi) +#define dsMatchStart (160)(%rdi) +#define dsLookahead (164)(%rdi) +#define dsPrevLen (168)(%rdi) +#define dsMaxChainLen (172)(%rdi) +#define dsGoodMatch (188)(%rdi) +#define dsNiceMatch (192)(%rdi) + +#else + +#ifndef STRUCT_OFFSET +# define STRUCT_OFFSET (0) +#endif + + +#define dsWSize ( 56 + STRUCT_OFFSET)(%rdi) +#define dsWMask ( 64 + STRUCT_OFFSET)(%rdi) +#define dsWindow ( 72 + STRUCT_OFFSET)(%rdi) +#define dsPrev ( 88 + STRUCT_OFFSET)(%rdi) +#define dsMatchLen (136 + STRUCT_OFFSET)(%rdi) +#define dsPrevMatch (140 + STRUCT_OFFSET)(%rdi) +#define dsStrStart (148 + STRUCT_OFFSET)(%rdi) +#define dsMatchStart (152 + STRUCT_OFFSET)(%rdi) +#define dsLookahead (156 + STRUCT_OFFSET)(%rdi) +#define dsPrevLen (160 + STRUCT_OFFSET)(%rdi) +#define dsMaxChainLen (164 + STRUCT_OFFSET)(%rdi) +#define dsGoodMatch (180 + STRUCT_OFFSET)(%rdi) +#define dsNiceMatch (184 + STRUCT_OFFSET)(%rdi) + +#endif + + + + +.text + +/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */ + +longest_match: +/* + * Retrieve the function arguments. %curmatch will hold cur_match + * throughout the entire function (passed via rsi on amd64). + * rdi will hold the pointer to the deflate_state (first arg on amd64) + */ + mov %rsi, save_rsi + mov %rbx, save_rbx + mov %r12, save_r12 + mov %r13, save_r13 + mov %r14, save_r14 + mov %r15, save_r15 + +/* uInt wmask = s->w_mask; */ +/* unsigned chain_length = s->max_chain_length; */ +/* if (s->prev_length >= s->good_match) { */ +/* chain_length >>= 2; */ +/* } */ + + movl dsPrevLen, %eax + movl dsGoodMatch, %ebx + cmpl %ebx, %eax + movl dsWMask, %eax + movl dsMaxChainLen, %chainlenwmask + jl LastMatchGood + shrl $2, %chainlenwmask +LastMatchGood: + +/* chainlen is decremented once beforehand so that the function can */ +/* use the sign flag instead of the zero flag for the exit test. */ +/* It is then shifted into the high word, to make room for the wmask */ +/* value, which it will always accompany. */ + + decl %chainlenwmask + shll $16, %chainlenwmask + orl %eax, %chainlenwmask + +/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */ + + movl dsNiceMatch, %eax + movl dsLookahead, %ebx + cmpl %eax, %ebx + jl LookaheadLess + movl %eax, %ebx +LookaheadLess: movl %ebx, %nicematch + +/* register Bytef *scan = s->window + s->strstart; */ + + mov dsWindow, %window + movl dsStrStart, %limitd + lea (%limit, %window), %scan + +/* Determine how many bytes the scan ptr is off from being */ +/* dword-aligned. */ + + mov %scan, %scanalign + negl %scanalignd + andl $3, %scanalignd + +/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */ +/* s->strstart - (IPos)MAX_DIST(s) : NIL; */ + + movl dsWSize, %eax + subl $MIN_LOOKAHEAD, %eax + xorl %ecx, %ecx + subl %eax, %limitd + cmovng %ecx, %limitd + +/* int best_len = s->prev_length; */ + + movl dsPrevLen, %bestlend + +/* Store the sum of s->window + best_len in %windowbestlen locally, and in memory. */ + + lea (%window, %bestlen), %windowbestlen + mov %windowbestlen, _windowbestlen + +/* register ush scan_start = *(ushf*)scan; */ +/* register ush scan_end = *(ushf*)(scan+best_len-1); */ +/* Posf *prev = s->prev; */ + + movzwl (%scan), %scanstart + movzwl -1(%scan, %bestlen), %scanend + mov dsPrev, %prev + +/* Jump into the main loop. */ + + movl %chainlenwmask, _chainlenwmask + jmp LoopEntry + +.balign 16 + +/* do { + * match = s->window + cur_match; + * if (*(ushf*)(match+best_len-1) != scan_end || + * *(ushf*)match != scan_start) continue; + * [...] + * } while ((cur_match = prev[cur_match & wmask]) > limit + * && --chain_length != 0); + * + * Here is the inner loop of the function. The function will spend the + * majority of its time in this loop, and majority of that time will + * be spent in the first ten instructions. + */ +LookupLoop: + andl %chainlenwmask, %curmatchd + movzwl (%prev, %curmatch, 2), %curmatchd + cmpl %limitd, %curmatchd + jbe LeaveNow + subl $0x00010000, %chainlenwmask + js LeaveNow +LoopEntry: cmpw -1(%windowbestlen, %curmatch), %scanendw + jne LookupLoop + cmpw %scanstartw, (%window, %curmatch) + jne LookupLoop + +/* Store the current value of chainlen. */ + movl %chainlenwmask, _chainlenwmask + +/* %scan is the string under scrutiny, and %prev to the string we */ +/* are hoping to match it up with. In actuality, %esi and %edi are */ +/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is */ +/* initialized to -(MAX_MATCH_8 - scanalign). */ + + mov $(-MAX_MATCH_8), %rdx + lea (%curmatch, %window), %windowbestlen + lea MAX_MATCH_8(%windowbestlen, %scanalign), %windowbestlen + lea MAX_MATCH_8(%scan, %scanalign), %prev + +/* the prefetching below makes very little difference... */ + prefetcht1 (%windowbestlen, %rdx) + prefetcht1 (%prev, %rdx) + +/* + * Test the strings for equality, 8 bytes at a time. At the end, + * adjust %rdx so that it is offset to the exact byte that mismatched. + * + * It should be confessed that this loop usually does not represent + * much of the total running time. Replacing it with a more + * straightforward "rep cmpsb" would not drastically degrade + * performance -- unrolling it, for example, makes no difference. + */ + +#undef USE_SSE /* works, but is 6-7% slower, than non-SSE... */ + +LoopCmps: +#ifdef USE_SSE + /* Preload the SSE registers */ + movdqu (%windowbestlen, %rdx), %xmm1 + movdqu (%prev, %rdx), %xmm2 + pcmpeqb %xmm2, %xmm1 + movdqu 16(%windowbestlen, %rdx), %xmm3 + movdqu 16(%prev, %rdx), %xmm4 + pcmpeqb %xmm4, %xmm3 + movdqu 32(%windowbestlen, %rdx), %xmm5 + movdqu 32(%prev, %rdx), %xmm6 + pcmpeqb %xmm6, %xmm5 + movdqu 48(%windowbestlen, %rdx), %xmm7 + movdqu 48(%prev, %rdx), %xmm8 + pcmpeqb %xmm8, %xmm7 + + /* Check the comparisions' results */ + pmovmskb %xmm1, %rax + notw %ax + bsfw %ax, %ax + jnz LeaveLoopCmps + + /* this is the only iteration of the loop with a possibility of having + incremented rdx by 0x108 (each loop iteration add 16*4 = 0x40 + and (0x40*4)+8=0x108 */ + add $8, %rdx + jz LenMaximum + add $8, %rdx + + + pmovmskb %xmm3, %rax + notw %ax + bsfw %ax, %ax + jnz LeaveLoopCmps + + + add $16, %rdx + + + pmovmskb %xmm5, %rax + notw %ax + bsfw %ax, %ax + jnz LeaveLoopCmps + + add $16, %rdx + + + pmovmskb %xmm7, %rax + notw %ax + bsfw %ax, %ax + jnz LeaveLoopCmps + + add $16, %rdx + + jmp LoopCmps +LeaveLoopCmps: add %rax, %rdx +#else + mov (%windowbestlen, %rdx), %rax + xor (%prev, %rdx), %rax + jnz LeaveLoopCmps + + mov 8(%windowbestlen, %rdx), %rax + xor 8(%prev, %rdx), %rax + jnz LeaveLoopCmps8 + + mov 16(%windowbestlen, %rdx), %rax + xor 16(%prev, %rdx), %rax + jnz LeaveLoopCmps16 + + add $24, %rdx + jnz LoopCmps + jmp LenMaximum +# if 0 +/* + * This three-liner is tantalizingly simple, but bsf is a slow instruction, + * and the complicated alternative down below is quite a bit faster. Sad... + */ + +LeaveLoopCmps: bsf %rax, %rax /* find the first non-zero bit */ + shrl $3, %eax /* divide by 8 to get the byte */ + add %rax, %rdx +# else +LeaveLoopCmps16: + add $8, %rdx +LeaveLoopCmps8: + add $8, %rdx +LeaveLoopCmps: testl $0xFFFFFFFF, %eax /* Check the first 4 bytes */ + jnz Check16 + add $4, %rdx + shr $32, %rax +Check16: testw $0xFFFF, %ax + jnz LenLower + add $2, %rdx + shrl $16, %eax +LenLower: subb $1, %al + adc $0, %rdx +# endif +#endif + +/* Calculate the length of the match. If it is longer than MAX_MATCH, */ +/* then automatically accept it as the best possible match and leave. */ + + lea (%prev, %rdx), %rax + sub %scan, %rax + cmpl $MAX_MATCH, %eax + jge LenMaximum + +/* If the length of the match is not longer than the best match we */ +/* have so far, then forget it and return to the lookup loop. */ + + cmpl %bestlend, %eax + jg LongerMatch + mov _windowbestlen, %windowbestlen + mov dsPrev, %prev + movl _chainlenwmask, %edx + jmp LookupLoop + +/* s->match_start = cur_match; */ +/* best_len = len; */ +/* if (len >= nice_match) break; */ +/* scan_end = *(ushf*)(scan+best_len-1); */ + +LongerMatch: + movl %eax, %bestlend + movl %curmatchd, dsMatchStart + cmpl %nicematch, %eax + jge LeaveNow + + lea (%window, %bestlen), %windowbestlen + mov %windowbestlen, _windowbestlen + + movzwl -1(%scan, %rax), %scanend + mov dsPrev, %prev + movl _chainlenwmask, %chainlenwmask + jmp LookupLoop + +/* Accept the current string, with the maximum possible length. */ + +LenMaximum: + movl $MAX_MATCH, %bestlend + movl %curmatchd, dsMatchStart + +/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */ +/* return s->lookahead; */ + +LeaveNow: + movl dsLookahead, %eax + cmpl %eax, %bestlend + cmovngl %bestlend, %eax +LookaheadRet: + +/* Restore the registers and return from whence we came. */ + + mov save_rsi, %rsi + mov save_rbx, %rbx + mov save_r12, %r12 + mov save_r13, %r13 + mov save_r14, %r14 + mov save_r15, %r15 + + ret + +match_init: ret diff --git a/contrib/zlib/contrib/asm686/README.686 b/contrib/zlib/contrib/asm686/README.686 new file mode 100644 index 00000000..a0bf3bea --- /dev/null +++ b/contrib/zlib/contrib/asm686/README.686 @@ -0,0 +1,51 @@ +This is a patched version of zlib, modified to use +Pentium-Pro-optimized assembly code in the deflation algorithm. The +files changed/added by this patch are: + +README.686 +match.S + +The speedup that this patch provides varies, depending on whether the +compiler used to build the original version of zlib falls afoul of the +PPro's speed traps. My own tests show a speedup of around 10-20% at +the default compression level, and 20-30% using -9, against a version +compiled using gcc 2.7.2.3. Your mileage may vary. + +Note that this code has been tailored for the PPro/PII in particular, +and will not perform particuarly well on a Pentium. + +If you are using an assembler other than GNU as, you will have to +translate match.S to use your assembler's syntax. (Have fun.) + +Brian Raiter +breadbox@muppetlabs.com +April, 1998 + + +Added for zlib 1.1.3: + +The patches come from +http://www.muppetlabs.com/~breadbox/software/assembly.html + +To compile zlib with this asm file, copy match.S to the zlib directory +then do: + +CFLAGS="-O3 -DASMV" ./configure +make OBJA=match.o + + +Update: + +I've been ignoring these assembly routines for years, believing that +gcc's generated code had caught up with it sometime around gcc 2.95 +and the major rearchitecting of the Pentium 4. However, I recently +learned that, despite what I believed, this code still has some life +in it. On the Pentium 4 and AMD64 chips, it continues to run about 8% +faster than the code produced by gcc 4.1. + +In acknowledgement of its continuing usefulness, I've altered the +license to match that of the rest of zlib. Share and Enjoy! + +Brian Raiter +breadbox@muppetlabs.com +April, 2007 diff --git a/contrib/zlib/contrib/asm686/match.S b/contrib/zlib/contrib/asm686/match.S new file mode 100644 index 00000000..fa421092 --- /dev/null +++ b/contrib/zlib/contrib/asm686/match.S @@ -0,0 +1,357 @@ +/* match.S -- x86 assembly version of the zlib longest_match() function. + * Optimized for the Intel 686 chips (PPro and later). + * + * Copyright (C) 1998, 2007 Brian Raiter + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the author be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef NO_UNDERLINE +#define match_init _match_init +#define longest_match _longest_match +#endif + +#define MAX_MATCH (258) +#define MIN_MATCH (3) +#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1) +#define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7) + +/* stack frame offsets */ + +#define chainlenwmask 0 /* high word: current chain len */ + /* low word: s->wmask */ +#define window 4 /* local copy of s->window */ +#define windowbestlen 8 /* s->window + bestlen */ +#define scanstart 16 /* first two bytes of string */ +#define scanend 12 /* last two bytes of string */ +#define scanalign 20 /* dword-misalignment of string */ +#define nicematch 24 /* a good enough match size */ +#define bestlen 28 /* size of best match so far */ +#define scan 32 /* ptr to string wanting match */ + +#define LocalVarsSize (36) +/* saved ebx 36 */ +/* saved edi 40 */ +/* saved esi 44 */ +/* saved ebp 48 */ +/* return address 52 */ +#define deflatestate 56 /* the function arguments */ +#define curmatch 60 + +/* All the +zlib1222add offsets are due to the addition of fields + * in zlib in the deflate_state structure since the asm code was first written + * (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)"). + * (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0"). + * if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8"). + */ + +#define zlib1222add (8) + +#define dsWSize (36+zlib1222add) +#define dsWMask (44+zlib1222add) +#define dsWindow (48+zlib1222add) +#define dsPrev (56+zlib1222add) +#define dsMatchLen (88+zlib1222add) +#define dsPrevMatch (92+zlib1222add) +#define dsStrStart (100+zlib1222add) +#define dsMatchStart (104+zlib1222add) +#define dsLookahead (108+zlib1222add) +#define dsPrevLen (112+zlib1222add) +#define dsMaxChainLen (116+zlib1222add) +#define dsGoodMatch (132+zlib1222add) +#define dsNiceMatch (136+zlib1222add) + + +.file "match.S" + +.globl match_init, longest_match + +.text + +/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */ +.cfi_sections .debug_frame + +longest_match: + +.cfi_startproc +/* Save registers that the compiler may be using, and adjust %esp to */ +/* make room for our stack frame. */ + + pushl %ebp + .cfi_def_cfa_offset 8 + .cfi_offset ebp, -8 + pushl %edi + .cfi_def_cfa_offset 12 + pushl %esi + .cfi_def_cfa_offset 16 + pushl %ebx + .cfi_def_cfa_offset 20 + subl $LocalVarsSize, %esp + .cfi_def_cfa_offset LocalVarsSize+20 + +/* Retrieve the function arguments. %ecx will hold cur_match */ +/* throughout the entire function. %edx will hold the pointer to the */ +/* deflate_state structure during the function's setup (before */ +/* entering the main loop). */ + + movl deflatestate(%esp), %edx + movl curmatch(%esp), %ecx + +/* uInt wmask = s->w_mask; */ +/* unsigned chain_length = s->max_chain_length; */ +/* if (s->prev_length >= s->good_match) { */ +/* chain_length >>= 2; */ +/* } */ + + movl dsPrevLen(%edx), %eax + movl dsGoodMatch(%edx), %ebx + cmpl %ebx, %eax + movl dsWMask(%edx), %eax + movl dsMaxChainLen(%edx), %ebx + jl LastMatchGood + shrl $2, %ebx +LastMatchGood: + +/* chainlen is decremented once beforehand so that the function can */ +/* use the sign flag instead of the zero flag for the exit test. */ +/* It is then shifted into the high word, to make room for the wmask */ +/* value, which it will always accompany. */ + + decl %ebx + shll $16, %ebx + orl %eax, %ebx + movl %ebx, chainlenwmask(%esp) + +/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */ + + movl dsNiceMatch(%edx), %eax + movl dsLookahead(%edx), %ebx + cmpl %eax, %ebx + jl LookaheadLess + movl %eax, %ebx +LookaheadLess: movl %ebx, nicematch(%esp) + +/* register Bytef *scan = s->window + s->strstart; */ + + movl dsWindow(%edx), %esi + movl %esi, window(%esp) + movl dsStrStart(%edx), %ebp + lea (%esi,%ebp), %edi + movl %edi, scan(%esp) + +/* Determine how many bytes the scan ptr is off from being */ +/* dword-aligned. */ + + movl %edi, %eax + negl %eax + andl $3, %eax + movl %eax, scanalign(%esp) + +/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */ +/* s->strstart - (IPos)MAX_DIST(s) : NIL; */ + + movl dsWSize(%edx), %eax + subl $MIN_LOOKAHEAD, %eax + subl %eax, %ebp + jg LimitPositive + xorl %ebp, %ebp +LimitPositive: + +/* int best_len = s->prev_length; */ + + movl dsPrevLen(%edx), %eax + movl %eax, bestlen(%esp) + +/* Store the sum of s->window + best_len in %esi locally, and in %esi. */ + + addl %eax, %esi + movl %esi, windowbestlen(%esp) + +/* register ush scan_start = *(ushf*)scan; */ +/* register ush scan_end = *(ushf*)(scan+best_len-1); */ +/* Posf *prev = s->prev; */ + + movzwl (%edi), %ebx + movl %ebx, scanstart(%esp) + movzwl -1(%edi,%eax), %ebx + movl %ebx, scanend(%esp) + movl dsPrev(%edx), %edi + +/* Jump into the main loop. */ + + movl chainlenwmask(%esp), %edx + jmp LoopEntry + +.balign 16 + +/* do { + * match = s->window + cur_match; + * if (*(ushf*)(match+best_len-1) != scan_end || + * *(ushf*)match != scan_start) continue; + * [...] + * } while ((cur_match = prev[cur_match & wmask]) > limit + * && --chain_length != 0); + * + * Here is the inner loop of the function. The function will spend the + * majority of its time in this loop, and majority of that time will + * be spent in the first ten instructions. + * + * Within this loop: + * %ebx = scanend + * %ecx = curmatch + * %edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) + * %esi = windowbestlen - i.e., (window + bestlen) + * %edi = prev + * %ebp = limit + */ +LookupLoop: + andl %edx, %ecx + movzwl (%edi,%ecx,2), %ecx + cmpl %ebp, %ecx + jbe LeaveNow + subl $0x00010000, %edx + js LeaveNow +LoopEntry: movzwl -1(%esi,%ecx), %eax + cmpl %ebx, %eax + jnz LookupLoop + movl window(%esp), %eax + movzwl (%eax,%ecx), %eax + cmpl scanstart(%esp), %eax + jnz LookupLoop + +/* Store the current value of chainlen. */ + + movl %edx, chainlenwmask(%esp) + +/* Point %edi to the string under scrutiny, and %esi to the string we */ +/* are hoping to match it up with. In actuality, %esi and %edi are */ +/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is */ +/* initialized to -(MAX_MATCH_8 - scanalign). */ + + movl window(%esp), %esi + movl scan(%esp), %edi + addl %ecx, %esi + movl scanalign(%esp), %eax + movl $(-MAX_MATCH_8), %edx + lea MAX_MATCH_8(%edi,%eax), %edi + lea MAX_MATCH_8(%esi,%eax), %esi + +/* Test the strings for equality, 8 bytes at a time. At the end, + * adjust %edx so that it is offset to the exact byte that mismatched. + * + * We already know at this point that the first three bytes of the + * strings match each other, and they can be safely passed over before + * starting the compare loop. So what this code does is skip over 0-3 + * bytes, as much as necessary in order to dword-align the %edi + * pointer. (%esi will still be misaligned three times out of four.) + * + * It should be confessed that this loop usually does not represent + * much of the total running time. Replacing it with a more + * straightforward "rep cmpsb" would not drastically degrade + * performance. + */ +LoopCmps: + movl (%esi,%edx), %eax + xorl (%edi,%edx), %eax + jnz LeaveLoopCmps + movl 4(%esi,%edx), %eax + xorl 4(%edi,%edx), %eax + jnz LeaveLoopCmps4 + addl $8, %edx + jnz LoopCmps + jmp LenMaximum +LeaveLoopCmps4: addl $4, %edx +LeaveLoopCmps: testl $0x0000FFFF, %eax + jnz LenLower + addl $2, %edx + shrl $16, %eax +LenLower: subb $1, %al + adcl $0, %edx + +/* Calculate the length of the match. If it is longer than MAX_MATCH, */ +/* then automatically accept it as the best possible match and leave. */ + + lea (%edi,%edx), %eax + movl scan(%esp), %edi + subl %edi, %eax + cmpl $MAX_MATCH, %eax + jge LenMaximum + +/* If the length of the match is not longer than the best match we */ +/* have so far, then forget it and return to the lookup loop. */ + + movl deflatestate(%esp), %edx + movl bestlen(%esp), %ebx + cmpl %ebx, %eax + jg LongerMatch + movl windowbestlen(%esp), %esi + movl dsPrev(%edx), %edi + movl scanend(%esp), %ebx + movl chainlenwmask(%esp), %edx + jmp LookupLoop + +/* s->match_start = cur_match; */ +/* best_len = len; */ +/* if (len >= nice_match) break; */ +/* scan_end = *(ushf*)(scan+best_len-1); */ + +LongerMatch: movl nicematch(%esp), %ebx + movl %eax, bestlen(%esp) + movl %ecx, dsMatchStart(%edx) + cmpl %ebx, %eax + jge LeaveNow + movl window(%esp), %esi + addl %eax, %esi + movl %esi, windowbestlen(%esp) + movzwl -1(%edi,%eax), %ebx + movl dsPrev(%edx), %edi + movl %ebx, scanend(%esp) + movl chainlenwmask(%esp), %edx + jmp LookupLoop + +/* Accept the current string, with the maximum possible length. */ + +LenMaximum: movl deflatestate(%esp), %edx + movl $MAX_MATCH, bestlen(%esp) + movl %ecx, dsMatchStart(%edx) + +/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */ +/* return s->lookahead; */ + +LeaveNow: + movl deflatestate(%esp), %edx + movl bestlen(%esp), %ebx + movl dsLookahead(%edx), %eax + cmpl %eax, %ebx + jg LookaheadRet + movl %ebx, %eax +LookaheadRet: + +/* Restore the stack and return from whence we came. */ + + addl $LocalVarsSize, %esp + .cfi_def_cfa_offset 20 + popl %ebx + .cfi_def_cfa_offset 16 + popl %esi + .cfi_def_cfa_offset 12 + popl %edi + .cfi_def_cfa_offset 8 + popl %ebp + .cfi_def_cfa_offset 4 +.cfi_endproc +match_init: ret diff --git a/contrib/zlib/contrib/blast/Makefile b/contrib/zlib/contrib/blast/Makefile new file mode 100644 index 00000000..9be80baf --- /dev/null +++ b/contrib/zlib/contrib/blast/Makefile @@ -0,0 +1,8 @@ +blast: blast.c blast.h + cc -DTEST -o blast blast.c + +test: blast + blast < test.pk | cmp - test.txt + +clean: + rm -f blast blast.o diff --git a/contrib/zlib/contrib/blast/README b/contrib/zlib/contrib/blast/README new file mode 100644 index 00000000..e3a60b3f --- /dev/null +++ b/contrib/zlib/contrib/blast/README @@ -0,0 +1,4 @@ +Read blast.h for purpose and usage. + +Mark Adler +madler@alumni.caltech.edu diff --git a/contrib/zlib/contrib/blast/blast.c b/contrib/zlib/contrib/blast/blast.c new file mode 100644 index 00000000..e6e65907 --- /dev/null +++ b/contrib/zlib/contrib/blast/blast.c @@ -0,0 +1,466 @@ +/* blast.c + * Copyright (C) 2003, 2012, 2013 Mark Adler + * For conditions of distribution and use, see copyright notice in blast.h + * version 1.3, 24 Aug 2013 + * + * blast.c decompresses data compressed by the PKWare Compression Library. + * This function provides functionality similar to the explode() function of + * the PKWare library, hence the name "blast". + * + * This decompressor is based on the excellent format description provided by + * Ben Rudiak-Gould in comp.compression on August 13, 2001. Interestingly, the + * example Ben provided in the post is incorrect. The distance 110001 should + * instead be 111000. When corrected, the example byte stream becomes: + * + * 00 04 82 24 25 8f 80 7f + * + * which decompresses to "AIAIAIAIAIAIA" (without the quotes). + */ + +/* + * Change history: + * + * 1.0 12 Feb 2003 - First version + * 1.1 16 Feb 2003 - Fixed distance check for > 4 GB uncompressed data + * 1.2 24 Oct 2012 - Add note about using binary mode in stdio + * - Fix comparisons of differently signed integers + * 1.3 24 Aug 2013 - Return unused input from blast() + * - Fix test code to correctly report unused input + * - Enable the provision of initial input to blast() + */ + +#include /* for NULL */ +#include /* for setjmp(), longjmp(), and jmp_buf */ +#include "blast.h" /* prototype for blast() */ + +#define local static /* for local function definitions */ +#define MAXBITS 13 /* maximum code length */ +#define MAXWIN 4096 /* maximum window size */ + +/* input and output state */ +struct state { + /* input state */ + blast_in infun; /* input function provided by user */ + void *inhow; /* opaque information passed to infun() */ + unsigned char *in; /* next input location */ + unsigned left; /* available input at in */ + int bitbuf; /* bit buffer */ + int bitcnt; /* number of bits in bit buffer */ + + /* input limit error return state for bits() and decode() */ + jmp_buf env; + + /* output state */ + blast_out outfun; /* output function provided by user */ + void *outhow; /* opaque information passed to outfun() */ + unsigned next; /* index of next write location in out[] */ + int first; /* true to check distances (for first 4K) */ + unsigned char out[MAXWIN]; /* output buffer and sliding window */ +}; + +/* + * Return need bits from the input stream. This always leaves less than + * eight bits in the buffer. bits() works properly for need == 0. + * + * Format notes: + * + * - Bits are stored in bytes from the least significant bit to the most + * significant bit. Therefore bits are dropped from the bottom of the bit + * buffer, using shift right, and new bytes are appended to the top of the + * bit buffer, using shift left. + */ +local int bits(struct state *s, int need) +{ + int val; /* bit accumulator */ + + /* load at least need bits into val */ + val = s->bitbuf; + while (s->bitcnt < need) { + if (s->left == 0) { + s->left = s->infun(s->inhow, &(s->in)); + if (s->left == 0) longjmp(s->env, 1); /* out of input */ + } + val |= (int)(*(s->in)++) << s->bitcnt; /* load eight bits */ + s->left--; + s->bitcnt += 8; + } + + /* drop need bits and update buffer, always zero to seven bits left */ + s->bitbuf = val >> need; + s->bitcnt -= need; + + /* return need bits, zeroing the bits above that */ + return val & ((1 << need) - 1); +} + +/* + * Huffman code decoding tables. count[1..MAXBITS] is the number of symbols of + * each length, which for a canonical code are stepped through in order. + * symbol[] are the symbol values in canonical order, where the number of + * entries is the sum of the counts in count[]. The decoding process can be + * seen in the function decode() below. + */ +struct huffman { + short *count; /* number of symbols of each length */ + short *symbol; /* canonically ordered symbols */ +}; + +/* + * Decode a code from the stream s using huffman table h. Return the symbol or + * a negative value if there is an error. If all of the lengths are zero, i.e. + * an empty code, or if the code is incomplete and an invalid code is received, + * then -9 is returned after reading MAXBITS bits. + * + * Format notes: + * + * - The codes as stored in the compressed data are bit-reversed relative to + * a simple integer ordering of codes of the same lengths. Hence below the + * bits are pulled from the compressed data one at a time and used to + * build the code value reversed from what is in the stream in order to + * permit simple integer comparisons for decoding. + * + * - The first code for the shortest length is all ones. Subsequent codes of + * the same length are simply integer decrements of the previous code. When + * moving up a length, a one bit is appended to the code. For a complete + * code, the last code of the longest length will be all zeros. To support + * this ordering, the bits pulled during decoding are inverted to apply the + * more "natural" ordering starting with all zeros and incrementing. + */ +local int decode(struct state *s, struct huffman *h) +{ + int len; /* current number of bits in code */ + int code; /* len bits being decoded */ + int first; /* first code of length len */ + int count; /* number of codes of length len */ + int index; /* index of first code of length len in symbol table */ + int bitbuf; /* bits from stream */ + int left; /* bits left in next or left to process */ + short *next; /* next number of codes */ + + bitbuf = s->bitbuf; + left = s->bitcnt; + code = first = index = 0; + len = 1; + next = h->count + 1; + while (1) { + while (left--) { + code |= (bitbuf & 1) ^ 1; /* invert code */ + bitbuf >>= 1; + count = *next++; + if (code < first + count) { /* if length len, return symbol */ + s->bitbuf = bitbuf; + s->bitcnt = (s->bitcnt - len) & 7; + return h->symbol[index + (code - first)]; + } + index += count; /* else update for next length */ + first += count; + first <<= 1; + code <<= 1; + len++; + } + left = (MAXBITS+1) - len; + if (left == 0) break; + if (s->left == 0) { + s->left = s->infun(s->inhow, &(s->in)); + if (s->left == 0) longjmp(s->env, 1); /* out of input */ + } + bitbuf = *(s->in)++; + s->left--; + if (left > 8) left = 8; + } + return -9; /* ran out of codes */ +} + +/* + * Given a list of repeated code lengths rep[0..n-1], where each byte is a + * count (high four bits + 1) and a code length (low four bits), generate the + * list of code lengths. This compaction reduces the size of the object code. + * Then given the list of code lengths length[0..n-1] representing a canonical + * Huffman code for n symbols, construct the tables required to decode those + * codes. Those tables are the number of codes of each length, and the symbols + * sorted by length, retaining their original order within each length. The + * return value is zero for a complete code set, negative for an over- + * subscribed code set, and positive for an incomplete code set. The tables + * can be used if the return value is zero or positive, but they cannot be used + * if the return value is negative. If the return value is zero, it is not + * possible for decode() using that table to return an error--any stream of + * enough bits will resolve to a symbol. If the return value is positive, then + * it is possible for decode() using that table to return an error for received + * codes past the end of the incomplete lengths. + */ +local int construct(struct huffman *h, const unsigned char *rep, int n) +{ + int symbol; /* current symbol when stepping through length[] */ + int len; /* current length when stepping through h->count[] */ + int left; /* number of possible codes left of current length */ + short offs[MAXBITS+1]; /* offsets in symbol table for each length */ + short length[256]; /* code lengths */ + + /* convert compact repeat counts into symbol bit length list */ + symbol = 0; + do { + len = *rep++; + left = (len >> 4) + 1; + len &= 15; + do { + length[symbol++] = len; + } while (--left); + } while (--n); + n = symbol; + + /* count number of codes of each length */ + for (len = 0; len <= MAXBITS; len++) + h->count[len] = 0; + for (symbol = 0; symbol < n; symbol++) + (h->count[length[symbol]])++; /* assumes lengths are within bounds */ + if (h->count[0] == n) /* no codes! */ + return 0; /* complete, but decode() will fail */ + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; /* one possible code of zero length */ + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; /* one more bit, double codes left */ + left -= h->count[len]; /* deduct count from possible codes */ + if (left < 0) return left; /* over-subscribed--return negative */ + } /* left > 0 means incomplete */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + h->count[len]; + + /* + * put symbols in table sorted by length, by symbol order within each + * length + */ + for (symbol = 0; symbol < n; symbol++) + if (length[symbol] != 0) + h->symbol[offs[length[symbol]]++] = symbol; + + /* return zero for complete set, positive for incomplete set */ + return left; +} + +/* + * Decode PKWare Compression Library stream. + * + * Format notes: + * + * - First byte is 0 if literals are uncoded or 1 if they are coded. Second + * byte is 4, 5, or 6 for the number of extra bits in the distance code. + * This is the base-2 logarithm of the dictionary size minus six. + * + * - Compressed data is a combination of literals and length/distance pairs + * terminated by an end code. Literals are either Huffman coded or + * uncoded bytes. A length/distance pair is a coded length followed by a + * coded distance to represent a string that occurs earlier in the + * uncompressed data that occurs again at the current location. + * + * - A bit preceding a literal or length/distance pair indicates which comes + * next, 0 for literals, 1 for length/distance. + * + * - If literals are uncoded, then the next eight bits are the literal, in the + * normal bit order in the stream, i.e. no bit-reversal is needed. Similarly, + * no bit reversal is needed for either the length extra bits or the distance + * extra bits. + * + * - Literal bytes are simply written to the output. A length/distance pair is + * an instruction to copy previously uncompressed bytes to the output. The + * copy is from distance bytes back in the output stream, copying for length + * bytes. + * + * - Distances pointing before the beginning of the output data are not + * permitted. + * + * - Overlapped copies, where the length is greater than the distance, are + * allowed and common. For example, a distance of one and a length of 518 + * simply copies the last byte 518 times. A distance of four and a length of + * twelve copies the last four bytes three times. A simple forward copy + * ignoring whether the length is greater than the distance or not implements + * this correctly. + */ +local int decomp(struct state *s) +{ + int lit; /* true if literals are coded */ + int dict; /* log2(dictionary size) - 6 */ + int symbol; /* decoded symbol, extra bits for distance */ + int len; /* length for copy */ + unsigned dist; /* distance for copy */ + int copy; /* copy counter */ + unsigned char *from, *to; /* copy pointers */ + static int virgin = 1; /* build tables once */ + static short litcnt[MAXBITS+1], litsym[256]; /* litcode memory */ + static short lencnt[MAXBITS+1], lensym[16]; /* lencode memory */ + static short distcnt[MAXBITS+1], distsym[64]; /* distcode memory */ + static struct huffman litcode = {litcnt, litsym}; /* length code */ + static struct huffman lencode = {lencnt, lensym}; /* length code */ + static struct huffman distcode = {distcnt, distsym};/* distance code */ + /* bit lengths of literal codes */ + static const unsigned char litlen[] = { + 11, 124, 8, 7, 28, 7, 188, 13, 76, 4, 10, 8, 12, 10, 12, 10, 8, 23, 8, + 9, 7, 6, 7, 8, 7, 6, 55, 8, 23, 24, 12, 11, 7, 9, 11, 12, 6, 7, 22, 5, + 7, 24, 6, 11, 9, 6, 7, 22, 7, 11, 38, 7, 9, 8, 25, 11, 8, 11, 9, 12, + 8, 12, 5, 38, 5, 38, 5, 11, 7, 5, 6, 21, 6, 10, 53, 8, 7, 24, 10, 27, + 44, 253, 253, 253, 252, 252, 252, 13, 12, 45, 12, 45, 12, 61, 12, 45, + 44, 173}; + /* bit lengths of length codes 0..15 */ + static const unsigned char lenlen[] = {2, 35, 36, 53, 38, 23}; + /* bit lengths of distance codes 0..63 */ + static const unsigned char distlen[] = {2, 20, 53, 230, 247, 151, 248}; + static const short base[16] = { /* base for length codes */ + 3, 2, 4, 5, 6, 7, 8, 9, 10, 12, 16, 24, 40, 72, 136, 264}; + static const char extra[16] = { /* extra bits for length codes */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8}; + + /* set up decoding tables (once--might not be thread-safe) */ + if (virgin) { + construct(&litcode, litlen, sizeof(litlen)); + construct(&lencode, lenlen, sizeof(lenlen)); + construct(&distcode, distlen, sizeof(distlen)); + virgin = 0; + } + + /* read header */ + lit = bits(s, 8); + if (lit > 1) return -1; + dict = bits(s, 8); + if (dict < 4 || dict > 6) return -2; + + /* decode literals and length/distance pairs */ + do { + if (bits(s, 1)) { + /* get length */ + symbol = decode(s, &lencode); + len = base[symbol] + bits(s, extra[symbol]); + if (len == 519) break; /* end code */ + + /* get distance */ + symbol = len == 2 ? 2 : dict; + dist = decode(s, &distcode) << symbol; + dist += bits(s, symbol); + dist++; + if (s->first && dist > s->next) + return -3; /* distance too far back */ + + /* copy length bytes from distance bytes back */ + do { + to = s->out + s->next; + from = to - dist; + copy = MAXWIN; + if (s->next < dist) { + from += copy; + copy = dist; + } + copy -= s->next; + if (copy > len) copy = len; + len -= copy; + s->next += copy; + do { + *to++ = *from++; + } while (--copy); + if (s->next == MAXWIN) { + if (s->outfun(s->outhow, s->out, s->next)) return 1; + s->next = 0; + s->first = 0; + } + } while (len != 0); + } + else { + /* get literal and write it */ + symbol = lit ? decode(s, &litcode) : bits(s, 8); + s->out[s->next++] = symbol; + if (s->next == MAXWIN) { + if (s->outfun(s->outhow, s->out, s->next)) return 1; + s->next = 0; + s->first = 0; + } + } + } while (1); + return 0; +} + +/* See comments in blast.h */ +int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow, + unsigned *left, unsigned char **in) +{ + struct state s; /* input/output state */ + int err; /* return value */ + + /* initialize input state */ + s.infun = infun; + s.inhow = inhow; + if (left != NULL && *left) { + s.left = *left; + s.in = *in; + } + else + s.left = 0; + s.bitbuf = 0; + s.bitcnt = 0; + + /* initialize output state */ + s.outfun = outfun; + s.outhow = outhow; + s.next = 0; + s.first = 1; + + /* return if bits() or decode() tries to read past available input */ + if (setjmp(s.env) != 0) /* if came back here via longjmp(), */ + err = 2; /* then skip decomp(), return error */ + else + err = decomp(&s); /* decompress */ + + /* return unused input */ + if (left != NULL) + *left = s.left; + if (in != NULL) + *in = s.left ? s.in : NULL; + + /* write any leftover output and update the error code if needed */ + if (err != 1 && s.next && s.outfun(s.outhow, s.out, s.next) && err == 0) + err = 1; + return err; +} + +#ifdef TEST +/* Example of how to use blast() */ +#include +#include + +#define CHUNK 16384 + +local unsigned inf(void *how, unsigned char **buf) +{ + static unsigned char hold[CHUNK]; + + *buf = hold; + return fread(hold, 1, CHUNK, (FILE *)how); +} + +local int outf(void *how, unsigned char *buf, unsigned len) +{ + return fwrite(buf, 1, len, (FILE *)how) != len; +} + +/* Decompress a PKWare Compression Library stream from stdin to stdout */ +int main(void) +{ + int ret; + unsigned left; + + /* decompress to stdout */ + left = 0; + ret = blast(inf, stdin, outf, stdout, &left, NULL); + if (ret != 0) + fprintf(stderr, "blast error: %d\n", ret); + + /* count any leftover bytes */ + while (getchar() != EOF) + left++; + if (left) + fprintf(stderr, "blast warning: %u unused bytes of input\n", left); + + /* return blast() error code */ + return ret; +} +#endif diff --git a/contrib/zlib/contrib/blast/blast.h b/contrib/zlib/contrib/blast/blast.h new file mode 100644 index 00000000..6cf65eda --- /dev/null +++ b/contrib/zlib/contrib/blast/blast.h @@ -0,0 +1,83 @@ +/* blast.h -- interface for blast.c + Copyright (C) 2003, 2012, 2013 Mark Adler + version 1.3, 24 Aug 2013 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler madler@alumni.caltech.edu + */ + + +/* + * blast() decompresses the PKWare Data Compression Library (DCL) compressed + * format. It provides the same functionality as the explode() function in + * that library. (Note: PKWare overused the "implode" verb, and the format + * used by their library implode() function is completely different and + * incompatible with the implode compression method supported by PKZIP.) + * + * The binary mode for stdio functions should be used to assure that the + * compressed data is not corrupted when read or written. For example: + * fopen(..., "rb") and fopen(..., "wb"). + */ + + +typedef unsigned (*blast_in)(void *how, unsigned char **buf); +typedef int (*blast_out)(void *how, unsigned char *buf, unsigned len); +/* Definitions for input/output functions passed to blast(). See below for + * what the provided functions need to do. + */ + + +int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow, + unsigned *left, unsigned char **in); +/* Decompress input to output using the provided infun() and outfun() calls. + * On success, the return value of blast() is zero. If there is an error in + * the source data, i.e. it is not in the proper format, then a negative value + * is returned. If there is not enough input available or there is not enough + * output space, then a positive error is returned. + * + * The input function is invoked: len = infun(how, &buf), where buf is set by + * infun() to point to the input buffer, and infun() returns the number of + * available bytes there. If infun() returns zero, then blast() returns with + * an input error. (blast() only asks for input if it needs it.) inhow is for + * use by the application to pass an input descriptor to infun(), if desired. + * + * If left and in are not NULL and *left is not zero when blast() is called, + * then the *left bytes are *in are consumed for input before infun() is used. + * + * The output function is invoked: err = outfun(how, buf, len), where the bytes + * to be written are buf[0..len-1]. If err is not zero, then blast() returns + * with an output error. outfun() is always called with len <= 4096. outhow + * is for use by the application to pass an output descriptor to outfun(), if + * desired. + * + * If there is any unused input, *left is set to the number of bytes that were + * read and *in points to them. Otherwise *left is set to zero and *in is set + * to NULL. If left or in are NULL, then they are not set. + * + * The return codes are: + * + * 2: ran out of input before completing decompression + * 1: output error before completing decompression + * 0: successful decompression + * -1: literal flag not zero or one + * -2: dictionary size not in 4..6 + * -3: distance is too far back + * + * At the bottom of blast.c is an example program that uses blast() that can be + * compiled to produce a command-line decompression filter by defining TEST. + */ diff --git a/contrib/zlib/contrib/blast/test.pk b/contrib/zlib/contrib/blast/test.pk new file mode 100644 index 00000000..be10b2bb Binary files /dev/null and b/contrib/zlib/contrib/blast/test.pk differ diff --git a/contrib/zlib/contrib/blast/test.txt b/contrib/zlib/contrib/blast/test.txt new file mode 100644 index 00000000..bfdf1c5d --- /dev/null +++ b/contrib/zlib/contrib/blast/test.txt @@ -0,0 +1 @@ +AIAIAIAIAIAIA \ No newline at end of file diff --git a/contrib/zlib/contrib/delphi/ZLib.pas b/contrib/zlib/contrib/delphi/ZLib.pas new file mode 100644 index 00000000..060e1991 --- /dev/null +++ b/contrib/zlib/contrib/delphi/ZLib.pas @@ -0,0 +1,557 @@ +{*******************************************************} +{ } +{ Borland Delphi Supplemental Components } +{ ZLIB Data Compression Interface Unit } +{ } +{ Copyright (c) 1997,99 Borland Corporation } +{ } +{*******************************************************} + +{ Updated for zlib 1.2.x by Cosmin Truta } + +unit ZLib; + +interface + +uses SysUtils, Classes; + +type + TAlloc = function (AppData: Pointer; Items, Size: Integer): Pointer; cdecl; + TFree = procedure (AppData, Block: Pointer); cdecl; + + // Internal structure. Ignore. + TZStreamRec = packed record + next_in: PChar; // next input byte + avail_in: Integer; // number of bytes available at next_in + total_in: Longint; // total nb of input bytes read so far + + next_out: PChar; // next output byte should be put here + avail_out: Integer; // remaining free space at next_out + total_out: Longint; // total nb of bytes output so far + + msg: PChar; // last error message, NULL if no error + internal: Pointer; // not visible by applications + + zalloc: TAlloc; // used to allocate the internal state + zfree: TFree; // used to free the internal state + AppData: Pointer; // private data object passed to zalloc and zfree + + data_type: Integer; // best guess about the data type: ascii or binary + adler: Longint; // adler32 value of the uncompressed data + reserved: Longint; // reserved for future use + end; + + // Abstract ancestor class + TCustomZlibStream = class(TStream) + private + FStrm: TStream; + FStrmPos: Integer; + FOnProgress: TNotifyEvent; + FZRec: TZStreamRec; + FBuffer: array [Word] of Char; + protected + procedure Progress(Sender: TObject); dynamic; + property OnProgress: TNotifyEvent read FOnProgress write FOnProgress; + constructor Create(Strm: TStream); + end; + +{ TCompressionStream compresses data on the fly as data is written to it, and + stores the compressed data to another stream. + + TCompressionStream is write-only and strictly sequential. Reading from the + stream will raise an exception. Using Seek to move the stream pointer + will raise an exception. + + Output data is cached internally, written to the output stream only when + the internal output buffer is full. All pending output data is flushed + when the stream is destroyed. + + The Position property returns the number of uncompressed bytes of + data that have been written to the stream so far. + + CompressionRate returns the on-the-fly percentage by which the original + data has been compressed: (1 - (CompressedBytes / UncompressedBytes)) * 100 + If raw data size = 100 and compressed data size = 25, the CompressionRate + is 75% + + The OnProgress event is called each time the output buffer is filled and + written to the output stream. This is useful for updating a progress + indicator when you are writing a large chunk of data to the compression + stream in a single call.} + + + TCompressionLevel = (clNone, clFastest, clDefault, clMax); + + TCompressionStream = class(TCustomZlibStream) + private + function GetCompressionRate: Single; + public + constructor Create(CompressionLevel: TCompressionLevel; Dest: TStream); + destructor Destroy; override; + function Read(var Buffer; Count: Longint): Longint; override; + function Write(const Buffer; Count: Longint): Longint; override; + function Seek(Offset: Longint; Origin: Word): Longint; override; + property CompressionRate: Single read GetCompressionRate; + property OnProgress; + end; + +{ TDecompressionStream decompresses data on the fly as data is read from it. + + Compressed data comes from a separate source stream. TDecompressionStream + is read-only and unidirectional; you can seek forward in the stream, but not + backwards. The special case of setting the stream position to zero is + allowed. Seeking forward decompresses data until the requested position in + the uncompressed data has been reached. Seeking backwards, seeking relative + to the end of the stream, requesting the size of the stream, and writing to + the stream will raise an exception. + + The Position property returns the number of bytes of uncompressed data that + have been read from the stream so far. + + The OnProgress event is called each time the internal input buffer of + compressed data is exhausted and the next block is read from the input stream. + This is useful for updating a progress indicator when you are reading a + large chunk of data from the decompression stream in a single call.} + + TDecompressionStream = class(TCustomZlibStream) + public + constructor Create(Source: TStream); + destructor Destroy; override; + function Read(var Buffer; Count: Longint): Longint; override; + function Write(const Buffer; Count: Longint): Longint; override; + function Seek(Offset: Longint; Origin: Word): Longint; override; + property OnProgress; + end; + + + +{ CompressBuf compresses data, buffer to buffer, in one call. + In: InBuf = ptr to compressed data + InBytes = number of bytes in InBuf + Out: OutBuf = ptr to newly allocated buffer containing decompressed data + OutBytes = number of bytes in OutBuf } +procedure CompressBuf(const InBuf: Pointer; InBytes: Integer; + out OutBuf: Pointer; out OutBytes: Integer); + + +{ DecompressBuf decompresses data, buffer to buffer, in one call. + In: InBuf = ptr to compressed data + InBytes = number of bytes in InBuf + OutEstimate = zero, or est. size of the decompressed data + Out: OutBuf = ptr to newly allocated buffer containing decompressed data + OutBytes = number of bytes in OutBuf } +procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer; + OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer); + +{ DecompressToUserBuf decompresses data, buffer to buffer, in one call. + In: InBuf = ptr to compressed data + InBytes = number of bytes in InBuf + Out: OutBuf = ptr to user-allocated buffer to contain decompressed data + BufSize = number of bytes in OutBuf } +procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer; + const OutBuf: Pointer; BufSize: Integer); + +const + zlib_version = '1.2.11'; + +type + EZlibError = class(Exception); + ECompressionError = class(EZlibError); + EDecompressionError = class(EZlibError); + +implementation + +uses ZLibConst; + +const + Z_NO_FLUSH = 0; + Z_PARTIAL_FLUSH = 1; + Z_SYNC_FLUSH = 2; + Z_FULL_FLUSH = 3; + Z_FINISH = 4; + + Z_OK = 0; + Z_STREAM_END = 1; + Z_NEED_DICT = 2; + Z_ERRNO = (-1); + Z_STREAM_ERROR = (-2); + Z_DATA_ERROR = (-3); + Z_MEM_ERROR = (-4); + Z_BUF_ERROR = (-5); + Z_VERSION_ERROR = (-6); + + Z_NO_COMPRESSION = 0; + Z_BEST_SPEED = 1; + Z_BEST_COMPRESSION = 9; + Z_DEFAULT_COMPRESSION = (-1); + + Z_FILTERED = 1; + Z_HUFFMAN_ONLY = 2; + Z_RLE = 3; + Z_DEFAULT_STRATEGY = 0; + + Z_BINARY = 0; + Z_ASCII = 1; + Z_UNKNOWN = 2; + + Z_DEFLATED = 8; + + +{$L adler32.obj} +{$L compress.obj} +{$L crc32.obj} +{$L deflate.obj} +{$L infback.obj} +{$L inffast.obj} +{$L inflate.obj} +{$L inftrees.obj} +{$L trees.obj} +{$L uncompr.obj} +{$L zutil.obj} + +procedure adler32; external; +procedure compressBound; external; +procedure crc32; external; +procedure deflateInit2_; external; +procedure deflateParams; external; + +function _malloc(Size: Integer): Pointer; cdecl; +begin + Result := AllocMem(Size); +end; + +procedure _free(Block: Pointer); cdecl; +begin + FreeMem(Block); +end; + +procedure _memset(P: Pointer; B: Byte; count: Integer); cdecl; +begin + FillChar(P^, count, B); +end; + +procedure _memcpy(dest, source: Pointer; count: Integer); cdecl; +begin + Move(source^, dest^, count); +end; + + + +// deflate compresses data +function deflateInit_(var strm: TZStreamRec; level: Integer; version: PChar; + recsize: Integer): Integer; external; +function deflate(var strm: TZStreamRec; flush: Integer): Integer; external; +function deflateEnd(var strm: TZStreamRec): Integer; external; + +// inflate decompresses data +function inflateInit_(var strm: TZStreamRec; version: PChar; + recsize: Integer): Integer; external; +function inflate(var strm: TZStreamRec; flush: Integer): Integer; external; +function inflateEnd(var strm: TZStreamRec): Integer; external; +function inflateReset(var strm: TZStreamRec): Integer; external; + + +function zlibAllocMem(AppData: Pointer; Items, Size: Integer): Pointer; cdecl; +begin +// GetMem(Result, Items*Size); + Result := AllocMem(Items * Size); +end; + +procedure zlibFreeMem(AppData, Block: Pointer); cdecl; +begin + FreeMem(Block); +end; + +{function zlibCheck(code: Integer): Integer; +begin + Result := code; + if code < 0 then + raise EZlibError.Create('error'); //!! +end;} + +function CCheck(code: Integer): Integer; +begin + Result := code; + if code < 0 then + raise ECompressionError.Create('error'); //!! +end; + +function DCheck(code: Integer): Integer; +begin + Result := code; + if code < 0 then + raise EDecompressionError.Create('error'); //!! +end; + +procedure CompressBuf(const InBuf: Pointer; InBytes: Integer; + out OutBuf: Pointer; out OutBytes: Integer); +var + strm: TZStreamRec; + P: Pointer; +begin + FillChar(strm, sizeof(strm), 0); + strm.zalloc := zlibAllocMem; + strm.zfree := zlibFreeMem; + OutBytes := ((InBytes + (InBytes div 10) + 12) + 255) and not 255; + GetMem(OutBuf, OutBytes); + try + strm.next_in := InBuf; + strm.avail_in := InBytes; + strm.next_out := OutBuf; + strm.avail_out := OutBytes; + CCheck(deflateInit_(strm, Z_BEST_COMPRESSION, zlib_version, sizeof(strm))); + try + while CCheck(deflate(strm, Z_FINISH)) <> Z_STREAM_END do + begin + P := OutBuf; + Inc(OutBytes, 256); + ReallocMem(OutBuf, OutBytes); + strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P))); + strm.avail_out := 256; + end; + finally + CCheck(deflateEnd(strm)); + end; + ReallocMem(OutBuf, strm.total_out); + OutBytes := strm.total_out; + except + FreeMem(OutBuf); + raise + end; +end; + + +procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer; + OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer); +var + strm: TZStreamRec; + P: Pointer; + BufInc: Integer; +begin + FillChar(strm, sizeof(strm), 0); + strm.zalloc := zlibAllocMem; + strm.zfree := zlibFreeMem; + BufInc := (InBytes + 255) and not 255; + if OutEstimate = 0 then + OutBytes := BufInc + else + OutBytes := OutEstimate; + GetMem(OutBuf, OutBytes); + try + strm.next_in := InBuf; + strm.avail_in := InBytes; + strm.next_out := OutBuf; + strm.avail_out := OutBytes; + DCheck(inflateInit_(strm, zlib_version, sizeof(strm))); + try + while DCheck(inflate(strm, Z_NO_FLUSH)) <> Z_STREAM_END do + begin + P := OutBuf; + Inc(OutBytes, BufInc); + ReallocMem(OutBuf, OutBytes); + strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P))); + strm.avail_out := BufInc; + end; + finally + DCheck(inflateEnd(strm)); + end; + ReallocMem(OutBuf, strm.total_out); + OutBytes := strm.total_out; + except + FreeMem(OutBuf); + raise + end; +end; + +procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer; + const OutBuf: Pointer; BufSize: Integer); +var + strm: TZStreamRec; +begin + FillChar(strm, sizeof(strm), 0); + strm.zalloc := zlibAllocMem; + strm.zfree := zlibFreeMem; + strm.next_in := InBuf; + strm.avail_in := InBytes; + strm.next_out := OutBuf; + strm.avail_out := BufSize; + DCheck(inflateInit_(strm, zlib_version, sizeof(strm))); + try + if DCheck(inflate(strm, Z_FINISH)) <> Z_STREAM_END then + raise EZlibError.CreateRes(@sTargetBufferTooSmall); + finally + DCheck(inflateEnd(strm)); + end; +end; + +// TCustomZlibStream + +constructor TCustomZLibStream.Create(Strm: TStream); +begin + inherited Create; + FStrm := Strm; + FStrmPos := Strm.Position; + FZRec.zalloc := zlibAllocMem; + FZRec.zfree := zlibFreeMem; +end; + +procedure TCustomZLibStream.Progress(Sender: TObject); +begin + if Assigned(FOnProgress) then FOnProgress(Sender); +end; + + +// TCompressionStream + +constructor TCompressionStream.Create(CompressionLevel: TCompressionLevel; + Dest: TStream); +const + Levels: array [TCompressionLevel] of ShortInt = + (Z_NO_COMPRESSION, Z_BEST_SPEED, Z_DEFAULT_COMPRESSION, Z_BEST_COMPRESSION); +begin + inherited Create(Dest); + FZRec.next_out := FBuffer; + FZRec.avail_out := sizeof(FBuffer); + CCheck(deflateInit_(FZRec, Levels[CompressionLevel], zlib_version, sizeof(FZRec))); +end; + +destructor TCompressionStream.Destroy; +begin + FZRec.next_in := nil; + FZRec.avail_in := 0; + try + if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; + while (CCheck(deflate(FZRec, Z_FINISH)) <> Z_STREAM_END) + and (FZRec.avail_out = 0) do + begin + FStrm.WriteBuffer(FBuffer, sizeof(FBuffer)); + FZRec.next_out := FBuffer; + FZRec.avail_out := sizeof(FBuffer); + end; + if FZRec.avail_out < sizeof(FBuffer) then + FStrm.WriteBuffer(FBuffer, sizeof(FBuffer) - FZRec.avail_out); + finally + deflateEnd(FZRec); + end; + inherited Destroy; +end; + +function TCompressionStream.Read(var Buffer; Count: Longint): Longint; +begin + raise ECompressionError.CreateRes(@sInvalidStreamOp); +end; + +function TCompressionStream.Write(const Buffer; Count: Longint): Longint; +begin + FZRec.next_in := @Buffer; + FZRec.avail_in := Count; + if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; + while (FZRec.avail_in > 0) do + begin + CCheck(deflate(FZRec, 0)); + if FZRec.avail_out = 0 then + begin + FStrm.WriteBuffer(FBuffer, sizeof(FBuffer)); + FZRec.next_out := FBuffer; + FZRec.avail_out := sizeof(FBuffer); + FStrmPos := FStrm.Position; + Progress(Self); + end; + end; + Result := Count; +end; + +function TCompressionStream.Seek(Offset: Longint; Origin: Word): Longint; +begin + if (Offset = 0) and (Origin = soFromCurrent) then + Result := FZRec.total_in + else + raise ECompressionError.CreateRes(@sInvalidStreamOp); +end; + +function TCompressionStream.GetCompressionRate: Single; +begin + if FZRec.total_in = 0 then + Result := 0 + else + Result := (1.0 - (FZRec.total_out / FZRec.total_in)) * 100.0; +end; + + +// TDecompressionStream + +constructor TDecompressionStream.Create(Source: TStream); +begin + inherited Create(Source); + FZRec.next_in := FBuffer; + FZRec.avail_in := 0; + DCheck(inflateInit_(FZRec, zlib_version, sizeof(FZRec))); +end; + +destructor TDecompressionStream.Destroy; +begin + FStrm.Seek(-FZRec.avail_in, 1); + inflateEnd(FZRec); + inherited Destroy; +end; + +function TDecompressionStream.Read(var Buffer; Count: Longint): Longint; +begin + FZRec.next_out := @Buffer; + FZRec.avail_out := Count; + if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; + while (FZRec.avail_out > 0) do + begin + if FZRec.avail_in = 0 then + begin + FZRec.avail_in := FStrm.Read(FBuffer, sizeof(FBuffer)); + if FZRec.avail_in = 0 then + begin + Result := Count - FZRec.avail_out; + Exit; + end; + FZRec.next_in := FBuffer; + FStrmPos := FStrm.Position; + Progress(Self); + end; + CCheck(inflate(FZRec, 0)); + end; + Result := Count; +end; + +function TDecompressionStream.Write(const Buffer; Count: Longint): Longint; +begin + raise EDecompressionError.CreateRes(@sInvalidStreamOp); +end; + +function TDecompressionStream.Seek(Offset: Longint; Origin: Word): Longint; +var + I: Integer; + Buf: array [0..4095] of Char; +begin + if (Offset = 0) and (Origin = soFromBeginning) then + begin + DCheck(inflateReset(FZRec)); + FZRec.next_in := FBuffer; + FZRec.avail_in := 0; + FStrm.Position := 0; + FStrmPos := 0; + end + else if ( (Offset >= 0) and (Origin = soFromCurrent)) or + ( ((Offset - FZRec.total_out) > 0) and (Origin = soFromBeginning)) then + begin + if Origin = soFromBeginning then Dec(Offset, FZRec.total_out); + if Offset > 0 then + begin + for I := 1 to Offset div sizeof(Buf) do + ReadBuffer(Buf, sizeof(Buf)); + ReadBuffer(Buf, Offset mod sizeof(Buf)); + end; + end + else + raise EDecompressionError.CreateRes(@sInvalidStreamOp); + Result := FZRec.total_out; +end; + + +end. diff --git a/contrib/zlib/contrib/delphi/ZLibConst.pas b/contrib/zlib/contrib/delphi/ZLibConst.pas new file mode 100644 index 00000000..cdfe1367 --- /dev/null +++ b/contrib/zlib/contrib/delphi/ZLibConst.pas @@ -0,0 +1,11 @@ +unit ZLibConst; + +interface + +resourcestring + sTargetBufferTooSmall = 'ZLib error: target buffer may be too small'; + sInvalidStreamOp = 'Invalid stream operation'; + +implementation + +end. diff --git a/contrib/zlib/contrib/delphi/readme.txt b/contrib/zlib/contrib/delphi/readme.txt new file mode 100644 index 00000000..2dc9a8bb --- /dev/null +++ b/contrib/zlib/contrib/delphi/readme.txt @@ -0,0 +1,76 @@ + +Overview +======== + +This directory contains an update to the ZLib interface unit, +distributed by Borland as a Delphi supplemental component. + +The original ZLib unit is Copyright (c) 1997,99 Borland Corp., +and is based on zlib version 1.0.4. There are a series of bugs +and security problems associated with that old zlib version, and +we recommend the users to update their ZLib unit. + + +Summary of modifications +======================== + +- Improved makefile, adapted to zlib version 1.2.1. + +- Some field types from TZStreamRec are changed from Integer to + Longint, for consistency with the zlib.h header, and for 64-bit + readiness. + +- The zlib_version constant is updated. + +- The new Z_RLE strategy has its corresponding symbolic constant. + +- The allocation and deallocation functions and function types + (TAlloc, TFree, zlibAllocMem and zlibFreeMem) are now cdecl, + and _malloc and _free are added as C RTL stubs. As a result, + the original C sources of zlib can be compiled out of the box, + and linked to the ZLib unit. + + +Suggestions for improvements +============================ + +Currently, the ZLib unit provides only a limited wrapper around +the zlib library, and much of the original zlib functionality is +missing. Handling compressed file formats like ZIP/GZIP or PNG +cannot be implemented without having this functionality. +Applications that handle these formats are either using their own, +duplicated code, or not using the ZLib unit at all. + +Here are a few suggestions: + +- Checksum class wrappers around adler32() and crc32(), similar + to the Java classes that implement the java.util.zip.Checksum + interface. + +- The ability to read and write raw deflate streams, without the + zlib stream header and trailer. Raw deflate streams are used + in the ZIP file format. + +- The ability to read and write gzip streams, used in the GZIP + file format, and normally produced by the gzip program. + +- The ability to select a different compression strategy, useful + to PNG and MNG image compression, and to multimedia compression + in general. Besides the compression level + + TCompressionLevel = (clNone, clFastest, clDefault, clMax); + + which, in fact, could have used the 'z' prefix and avoided + TColor-like symbols + + TCompressionLevel = (zcNone, zcFastest, zcDefault, zcMax); + + there could be a compression strategy + + TCompressionStrategy = (zsDefault, zsFiltered, zsHuffmanOnly, zsRle); + +- ZIP and GZIP stream handling via TStreams. + + +-- +Cosmin Truta diff --git a/contrib/zlib/contrib/delphi/zlibd32.mak b/contrib/zlib/contrib/delphi/zlibd32.mak new file mode 100644 index 00000000..9bb00b7c --- /dev/null +++ b/contrib/zlib/contrib/delphi/zlibd32.mak @@ -0,0 +1,99 @@ +# Makefile for zlib +# For use with Delphi and C++ Builder under Win32 +# Updated for zlib 1.2.x by Cosmin Truta + +# ------------ Borland C++ ------------ + +# This project uses the Delphi (fastcall/register) calling convention: +LOC = -DZEXPORT=__fastcall -DZEXPORTVA=__cdecl + +CC = bcc32 +LD = bcc32 +AR = tlib +# do not use "-pr" in CFLAGS +CFLAGS = -a -d -k- -O2 $(LOC) +LDFLAGS = + + +# variables +ZLIB_LIB = zlib.lib + +OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzclose.obj gzlib.obj gzread.obj +OBJ2 = gzwrite.obj infback.obj inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj +OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzclose.obj+gzlib.obj+gzread.obj +OBJP2 = +gzwrite.obj+infback.obj+inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj + + +# targets +all: $(ZLIB_LIB) example.exe minigzip.exe + +.c.obj: + $(CC) -c $(CFLAGS) $*.c + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzclose.obj: gzclose.c zlib.h zconf.h gzguts.h + +gzlib.obj: gzlib.c zlib.h zconf.h gzguts.h + +gzread.obj: gzread.c zlib.h zconf.h gzguts.h + +gzwrite.obj: gzwrite.c zlib.h zconf.h gzguts.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: test/example.c zlib.h zconf.h + +minigzip.obj: test/minigzip.c zlib.h zconf.h + + +# For the sake of the old Borland make, +# the command line is cut to fit in the MS-DOS 128 byte limit: +$(ZLIB_LIB): $(OBJ1) $(OBJ2) + -del $(ZLIB_LIB) + $(AR) $(ZLIB_LIB) $(OBJP1) + $(AR) $(ZLIB_LIB) $(OBJP2) + + +# testing +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +example.exe: example.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB) + +minigzip.exe: minigzip.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB) + + +# cleanup +clean: + -del *.obj + -del *.exe + -del *.lib + -del *.tds + -del zlib.bak + -del foo.gz + diff --git a/contrib/zlib/contrib/dotzlib/DotZLib.build b/contrib/zlib/contrib/dotzlib/DotZLib.build new file mode 100644 index 00000000..e69630ce --- /dev/null +++ b/contrib/zlib/contrib/dotzlib/DotZLib.build @@ -0,0 +1,33 @@ + + + A .Net wrapper library around ZLib1.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/dotzlib/DotZLib.chm b/contrib/zlib/contrib/dotzlib/DotZLib.chm new file mode 100644 index 00000000..f214a444 Binary files /dev/null and b/contrib/zlib/contrib/dotzlib/DotZLib.chm differ diff --git a/contrib/zlib/contrib/dotzlib/DotZLib.sln b/contrib/zlib/contrib/dotzlib/DotZLib.sln new file mode 100644 index 00000000..5d533d6b --- /dev/null +++ b/contrib/zlib/contrib/dotzlib/DotZLib.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotZLib", "DotZLib\DotZLib.csproj", "{BB1EE0B1-1808-46CB-B786-949D91117FC5}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {BB1EE0B1-1808-46CB-B786-949D91117FC5}.Debug.ActiveCfg = Debug|.NET + {BB1EE0B1-1808-46CB-B786-949D91117FC5}.Debug.Build.0 = Debug|.NET + {BB1EE0B1-1808-46CB-B786-949D91117FC5}.Release.ActiveCfg = Release|.NET + {BB1EE0B1-1808-46CB-B786-949D91117FC5}.Release.Build.0 = Release|.NET + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/contrib/zlib/contrib/dotzlib/DotZLib/AssemblyInfo.cs b/contrib/zlib/contrib/dotzlib/DotZLib/AssemblyInfo.cs new file mode 100644 index 00000000..724c5347 --- /dev/null +++ b/contrib/zlib/contrib/dotzlib/DotZLib/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("DotZLib")] +[assembly: AssemblyDescription(".Net bindings for ZLib compression dll 1.2.x")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Henrik Ravn")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("(c) 2004 by Henrik Ravn")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/contrib/zlib/contrib/dotzlib/DotZLib/ChecksumImpl.cs b/contrib/zlib/contrib/dotzlib/DotZLib/ChecksumImpl.cs new file mode 100644 index 00000000..b110dae6 --- /dev/null +++ b/contrib/zlib/contrib/dotzlib/DotZLib/ChecksumImpl.cs @@ -0,0 +1,202 @@ +// +// Copyright Henrik Ravn 2004 +// +// Use, modification and distribution are subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.Runtime.InteropServices; +using System.Text; + + +namespace DotZLib +{ + #region ChecksumGeneratorBase + /// + /// Implements the common functionality needed for all s + /// + /// + public abstract class ChecksumGeneratorBase : ChecksumGenerator + { + /// + /// The value of the current checksum + /// + protected uint _current; + + /// + /// Initializes a new instance of the checksum generator base - the current checksum is + /// set to zero + /// + public ChecksumGeneratorBase() + { + _current = 0; + } + + /// + /// Initializes a new instance of the checksum generator basewith a specified value + /// + /// The value to set the current checksum to + public ChecksumGeneratorBase(uint initialValue) + { + _current = initialValue; + } + + /// + /// Resets the current checksum to zero + /// + public void Reset() { _current = 0; } + + /// + /// Gets the current checksum value + /// + public uint Value { get { return _current; } } + + /// + /// Updates the current checksum with part of an array of bytes + /// + /// The data to update the checksum with + /// Where in data to start updating + /// The number of bytes from data to use + /// The sum of offset and count is larger than the length of data + /// data is a null reference + /// Offset or count is negative. + /// All the other Update methods are implmeneted in terms of this one. + /// This is therefore the only method a derived class has to implement + public abstract void Update(byte[] data, int offset, int count); + + /// + /// Updates the current checksum with an array of bytes. + /// + /// The data to update the checksum with + public void Update(byte[] data) + { + Update(data, 0, data.Length); + } + + /// + /// Updates the current checksum with the data from a string + /// + /// The string to update the checksum with + /// The characters in the string are converted by the UTF-8 encoding + public void Update(string data) + { + Update(Encoding.UTF8.GetBytes(data)); + } + + /// + /// Updates the current checksum with the data from a string, using a specific encoding + /// + /// The string to update the checksum with + /// The encoding to use + public void Update(string data, Encoding encoding) + { + Update(encoding.GetBytes(data)); + } + + } + #endregion + + #region CRC32 + /// + /// Implements a CRC32 checksum generator + /// + public sealed class CRC32Checksum : ChecksumGeneratorBase + { + #region DLL imports + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern uint crc32(uint crc, int data, uint length); + + #endregion + + /// + /// Initializes a new instance of the CRC32 checksum generator + /// + public CRC32Checksum() : base() {} + + /// + /// Initializes a new instance of the CRC32 checksum generator with a specified value + /// + /// The value to set the current checksum to + public CRC32Checksum(uint initialValue) : base(initialValue) {} + + /// + /// Updates the current checksum with part of an array of bytes + /// + /// The data to update the checksum with + /// Where in data to start updating + /// The number of bytes from data to use + /// The sum of offset and count is larger than the length of data + /// data is a null reference + /// Offset or count is negative. + public override void Update(byte[] data, int offset, int count) + { + if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException(); + if ((offset+count) > data.Length) throw new ArgumentException(); + GCHandle hData = GCHandle.Alloc(data, GCHandleType.Pinned); + try + { + _current = crc32(_current, hData.AddrOfPinnedObject().ToInt32()+offset, (uint)count); + } + finally + { + hData.Free(); + } + } + + } + #endregion + + #region Adler + /// + /// Implements a checksum generator that computes the Adler checksum on data + /// + public sealed class AdlerChecksum : ChecksumGeneratorBase + { + #region DLL imports + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern uint adler32(uint adler, int data, uint length); + + #endregion + + /// + /// Initializes a new instance of the Adler checksum generator + /// + public AdlerChecksum() : base() {} + + /// + /// Initializes a new instance of the Adler checksum generator with a specified value + /// + /// The value to set the current checksum to + public AdlerChecksum(uint initialValue) : base(initialValue) {} + + /// + /// Updates the current checksum with part of an array of bytes + /// + /// The data to update the checksum with + /// Where in data to start updating + /// The number of bytes from data to use + /// The sum of offset and count is larger than the length of data + /// data is a null reference + /// Offset or count is negative. + public override void Update(byte[] data, int offset, int count) + { + if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException(); + if ((offset+count) > data.Length) throw new ArgumentException(); + GCHandle hData = GCHandle.Alloc(data, GCHandleType.Pinned); + try + { + _current = adler32(_current, hData.AddrOfPinnedObject().ToInt32()+offset, (uint)count); + } + finally + { + hData.Free(); + } + } + + } + #endregion + +} \ No newline at end of file diff --git a/contrib/zlib/contrib/dotzlib/DotZLib/CircularBuffer.cs b/contrib/zlib/contrib/dotzlib/DotZLib/CircularBuffer.cs new file mode 100644 index 00000000..9c8d6019 --- /dev/null +++ b/contrib/zlib/contrib/dotzlib/DotZLib/CircularBuffer.cs @@ -0,0 +1,83 @@ +// +// Copyright Henrik Ravn 2004 +// +// Use, modification and distribution are subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.Diagnostics; + +namespace DotZLib +{ + + /// + /// This class implements a circular buffer + /// + internal class CircularBuffer + { + #region Private data + private int _capacity; + private int _head; + private int _tail; + private int _size; + private byte[] _buffer; + #endregion + + public CircularBuffer(int capacity) + { + Debug.Assert( capacity > 0 ); + _buffer = new byte[capacity]; + _capacity = capacity; + _head = 0; + _tail = 0; + _size = 0; + } + + public int Size { get { return _size; } } + + public int Put(byte[] source, int offset, int count) + { + Debug.Assert( count > 0 ); + int trueCount = Math.Min(count, _capacity - Size); + for (int i = 0; i < trueCount; ++i) + _buffer[(_tail+i) % _capacity] = source[offset+i]; + _tail += trueCount; + _tail %= _capacity; + _size += trueCount; + return trueCount; + } + + public bool Put(byte b) + { + if (Size == _capacity) // no room + return false; + _buffer[_tail++] = b; + _tail %= _capacity; + ++_size; + return true; + } + + public int Get(byte[] destination, int offset, int count) + { + int trueCount = Math.Min(count,Size); + for (int i = 0; i < trueCount; ++i) + destination[offset + i] = _buffer[(_head+i) % _capacity]; + _head += trueCount; + _head %= _capacity; + _size -= trueCount; + return trueCount; + } + + public int Get() + { + if (Size == 0) + return -1; + + int result = (int)_buffer[_head++ % _capacity]; + --_size; + return result; + } + + } +} diff --git a/contrib/zlib/contrib/dotzlib/DotZLib/CodecBase.cs b/contrib/zlib/contrib/dotzlib/DotZLib/CodecBase.cs new file mode 100644 index 00000000..b0eb78a0 --- /dev/null +++ b/contrib/zlib/contrib/dotzlib/DotZLib/CodecBase.cs @@ -0,0 +1,198 @@ +// +// Copyright Henrik Ravn 2004 +// +// Use, modification and distribution are subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.Runtime.InteropServices; + +namespace DotZLib +{ + /// + /// Implements the common functionality needed for all s + /// + public abstract class CodecBase : Codec, IDisposable + { + + #region Data members + + /// + /// Instance of the internal zlib buffer structure that is + /// passed to all functions in the zlib dll + /// + internal ZStream _ztream = new ZStream(); + + /// + /// True if the object instance has been disposed, false otherwise + /// + protected bool _isDisposed = false; + + /// + /// The size of the internal buffers + /// + protected const int kBufferSize = 16384; + + private byte[] _outBuffer = new byte[kBufferSize]; + private byte[] _inBuffer = new byte[kBufferSize]; + + private GCHandle _hInput; + private GCHandle _hOutput; + + private uint _checksum = 0; + + #endregion + + /// + /// Initializes a new instance of the CodeBase class. + /// + public CodecBase() + { + try + { + _hInput = GCHandle.Alloc(_inBuffer, GCHandleType.Pinned); + _hOutput = GCHandle.Alloc(_outBuffer, GCHandleType.Pinned); + } + catch (Exception) + { + CleanUp(false); + throw; + } + } + + + #region Codec Members + + /// + /// Occurs when more processed data are available. + /// + public event DataAvailableHandler DataAvailable; + + /// + /// Fires the event + /// + protected void OnDataAvailable() + { + if (_ztream.total_out > 0) + { + if (DataAvailable != null) + DataAvailable( _outBuffer, 0, (int)_ztream.total_out); + resetOutput(); + } + } + + /// + /// Adds more data to the codec to be processed. + /// + /// Byte array containing the data to be added to the codec + /// Adding data may, or may not, raise the DataAvailable event + public void Add(byte[] data) + { + Add(data,0,data.Length); + } + + /// + /// Adds more data to the codec to be processed. + /// + /// Byte array containing the data to be added to the codec + /// The index of the first byte to add from data + /// The number of bytes to add + /// Adding data may, or may not, raise the DataAvailable event + /// This must be implemented by a derived class + public abstract void Add(byte[] data, int offset, int count); + + /// + /// Finishes up any pending data that needs to be processed and handled. + /// + /// This must be implemented by a derived class + public abstract void Finish(); + + /// + /// Gets the checksum of the data that has been added so far + /// + public uint Checksum { get { return _checksum; } } + + #endregion + + #region Destructor & IDisposable stuff + + /// + /// Destroys this instance + /// + ~CodecBase() + { + CleanUp(false); + } + + /// + /// Releases any unmanaged resources and calls the method of the derived class + /// + public void Dispose() + { + CleanUp(true); + } + + /// + /// Performs any codec specific cleanup + /// + /// This must be implemented by a derived class + protected abstract void CleanUp(); + + // performs the release of the handles and calls the dereived CleanUp() + private void CleanUp(bool isDisposing) + { + if (!_isDisposed) + { + CleanUp(); + if (_hInput.IsAllocated) + _hInput.Free(); + if (_hOutput.IsAllocated) + _hOutput.Free(); + + _isDisposed = true; + } + } + + + #endregion + + #region Helper methods + + /// + /// Copies a number of bytes to the internal codec buffer - ready for proccesing + /// + /// The byte array that contains the data to copy + /// The index of the first byte to copy + /// The number of bytes to copy from data + protected void copyInput(byte[] data, int startIndex, int count) + { + Array.Copy(data, startIndex, _inBuffer,0, count); + _ztream.next_in = _hInput.AddrOfPinnedObject(); + _ztream.total_in = 0; + _ztream.avail_in = (uint)count; + + } + + /// + /// Resets the internal output buffers to a known state - ready for processing + /// + protected void resetOutput() + { + _ztream.total_out = 0; + _ztream.avail_out = kBufferSize; + _ztream.next_out = _hOutput.AddrOfPinnedObject(); + } + + /// + /// Updates the running checksum property + /// + /// The new checksum value + protected void setChecksum(uint newSum) + { + _checksum = newSum; + } + #endregion + + } +} diff --git a/contrib/zlib/contrib/dotzlib/DotZLib/Deflater.cs b/contrib/zlib/contrib/dotzlib/DotZLib/Deflater.cs new file mode 100644 index 00000000..9039f41f --- /dev/null +++ b/contrib/zlib/contrib/dotzlib/DotZLib/Deflater.cs @@ -0,0 +1,106 @@ +// +// Copyright Henrik Ravn 2004 +// +// Use, modification and distribution are subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace DotZLib +{ + + /// + /// Implements a data compressor, using the deflate algorithm in the ZLib dll + /// + public sealed class Deflater : CodecBase + { + #region Dll imports + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)] + private static extern int deflateInit_(ref ZStream sz, int level, string vs, int size); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int deflate(ref ZStream sz, int flush); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int deflateReset(ref ZStream sz); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int deflateEnd(ref ZStream sz); + #endregion + + /// + /// Constructs an new instance of the Deflater + /// + /// The compression level to use for this Deflater + public Deflater(CompressLevel level) : base() + { + int retval = deflateInit_(ref _ztream, (int)level, Info.Version, Marshal.SizeOf(_ztream)); + if (retval != 0) + throw new ZLibException(retval, "Could not initialize deflater"); + + resetOutput(); + } + + /// + /// Adds more data to the codec to be processed. + /// + /// Byte array containing the data to be added to the codec + /// The index of the first byte to add from data + /// The number of bytes to add + /// Adding data may, or may not, raise the DataAvailable event + public override void Add(byte[] data, int offset, int count) + { + if (data == null) throw new ArgumentNullException(); + if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException(); + if ((offset+count) > data.Length) throw new ArgumentException(); + + int total = count; + int inputIndex = offset; + int err = 0; + + while (err >= 0 && inputIndex < total) + { + copyInput(data, inputIndex, Math.Min(total - inputIndex, kBufferSize)); + while (err >= 0 && _ztream.avail_in > 0) + { + err = deflate(ref _ztream, (int)FlushTypes.None); + if (err == 0) + while (_ztream.avail_out == 0) + { + OnDataAvailable(); + err = deflate(ref _ztream, (int)FlushTypes.None); + } + inputIndex += (int)_ztream.total_in; + } + } + setChecksum( _ztream.adler ); + } + + + /// + /// Finishes up any pending data that needs to be processed and handled. + /// + public override void Finish() + { + int err; + do + { + err = deflate(ref _ztream, (int)FlushTypes.Finish); + OnDataAvailable(); + } + while (err == 0); + setChecksum( _ztream.adler ); + deflateReset(ref _ztream); + resetOutput(); + } + + /// + /// Closes the internal zlib deflate stream + /// + protected override void CleanUp() { deflateEnd(ref _ztream); } + + } +} diff --git a/contrib/zlib/contrib/dotzlib/DotZLib/DotZLib.cs b/contrib/zlib/contrib/dotzlib/DotZLib/DotZLib.cs new file mode 100644 index 00000000..90c7c3b3 --- /dev/null +++ b/contrib/zlib/contrib/dotzlib/DotZLib/DotZLib.cs @@ -0,0 +1,288 @@ +// +// Copyright Henrik Ravn 2004 +// +// Use, modification and distribution are subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; + + +namespace DotZLib +{ + + #region Internal types + + /// + /// Defines constants for the various flush types used with zlib + /// + internal enum FlushTypes + { + None, Partial, Sync, Full, Finish, Block + } + + #region ZStream structure + // internal mapping of the zlib zstream structure for marshalling + [StructLayoutAttribute(LayoutKind.Sequential, Pack=4, Size=0, CharSet=CharSet.Ansi)] + internal struct ZStream + { + public IntPtr next_in; + public uint avail_in; + public uint total_in; + + public IntPtr next_out; + public uint avail_out; + public uint total_out; + + [MarshalAs(UnmanagedType.LPStr)] + string msg; + uint state; + + uint zalloc; + uint zfree; + uint opaque; + + int data_type; + public uint adler; + uint reserved; + } + + #endregion + + #endregion + + #region Public enums + /// + /// Defines constants for the available compression levels in zlib + /// + public enum CompressLevel : int + { + /// + /// The default compression level with a reasonable compromise between compression and speed + /// + Default = -1, + /// + /// No compression at all. The data are passed straight through. + /// + None = 0, + /// + /// The maximum compression rate available. + /// + Best = 9, + /// + /// The fastest available compression level. + /// + Fastest = 1 + } + #endregion + + #region Exception classes + /// + /// The exception that is thrown when an error occurs on the zlib dll + /// + public class ZLibException : ApplicationException + { + /// + /// Initializes a new instance of the class with a specified + /// error message and error code + /// + /// The zlib error code that caused the exception + /// A message that (hopefully) describes the error + public ZLibException(int errorCode, string msg) : base(String.Format("ZLib error {0} {1}", errorCode, msg)) + { + } + + /// + /// Initializes a new instance of the class with a specified + /// error code + /// + /// The zlib error code that caused the exception + public ZLibException(int errorCode) : base(String.Format("ZLib error {0}", errorCode)) + { + } + } + #endregion + + #region Interfaces + + /// + /// Declares methods and properties that enables a running checksum to be calculated + /// + public interface ChecksumGenerator + { + /// + /// Gets the current value of the checksum + /// + uint Value { get; } + + /// + /// Clears the current checksum to 0 + /// + void Reset(); + + /// + /// Updates the current checksum with an array of bytes + /// + /// The data to update the checksum with + void Update(byte[] data); + + /// + /// Updates the current checksum with part of an array of bytes + /// + /// The data to update the checksum with + /// Where in data to start updating + /// The number of bytes from data to use + /// The sum of offset and count is larger than the length of data + /// data is a null reference + /// Offset or count is negative. + void Update(byte[] data, int offset, int count); + + /// + /// Updates the current checksum with the data from a string + /// + /// The string to update the checksum with + /// The characters in the string are converted by the UTF-8 encoding + void Update(string data); + + /// + /// Updates the current checksum with the data from a string, using a specific encoding + /// + /// The string to update the checksum with + /// The encoding to use + void Update(string data, Encoding encoding); + } + + + /// + /// Represents the method that will be called from a codec when new data + /// are available. + /// + /// The byte array containing the processed data + /// The index of the first processed byte in data + /// The number of processed bytes available + /// On return from this method, the data may be overwritten, so grab it while you can. + /// You cannot assume that startIndex will be zero. + /// + public delegate void DataAvailableHandler(byte[] data, int startIndex, int count); + + /// + /// Declares methods and events for implementing compressors/decompressors + /// + public interface Codec + { + /// + /// Occurs when more processed data are available. + /// + event DataAvailableHandler DataAvailable; + + /// + /// Adds more data to the codec to be processed. + /// + /// Byte array containing the data to be added to the codec + /// Adding data may, or may not, raise the DataAvailable event + void Add(byte[] data); + + /// + /// Adds more data to the codec to be processed. + /// + /// Byte array containing the data to be added to the codec + /// The index of the first byte to add from data + /// The number of bytes to add + /// Adding data may, or may not, raise the DataAvailable event + void Add(byte[] data, int offset, int count); + + /// + /// Finishes up any pending data that needs to be processed and handled. + /// + void Finish(); + + /// + /// Gets the checksum of the data that has been added so far + /// + uint Checksum { get; } + + + } + + #endregion + + #region Classes + /// + /// Encapsulates general information about the ZLib library + /// + public class Info + { + #region DLL imports + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern uint zlibCompileFlags(); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern string zlibVersion(); + #endregion + + #region Private stuff + private uint _flags; + + // helper function that unpacks a bitsize mask + private static int bitSize(uint bits) + { + switch (bits) + { + case 0: return 16; + case 1: return 32; + case 2: return 64; + } + return -1; + } + #endregion + + /// + /// Constructs an instance of the Info class. + /// + public Info() + { + _flags = zlibCompileFlags(); + } + + /// + /// True if the library is compiled with debug info + /// + public bool HasDebugInfo { get { return 0 != (_flags & 0x100); } } + + /// + /// True if the library is compiled with assembly optimizations + /// + public bool UsesAssemblyCode { get { return 0 != (_flags & 0x200); } } + + /// + /// Gets the size of the unsigned int that was compiled into Zlib + /// + public int SizeOfUInt { get { return bitSize(_flags & 3); } } + + /// + /// Gets the size of the unsigned long that was compiled into Zlib + /// + public int SizeOfULong { get { return bitSize((_flags >> 2) & 3); } } + + /// + /// Gets the size of the pointers that were compiled into Zlib + /// + public int SizeOfPointer { get { return bitSize((_flags >> 4) & 3); } } + + /// + /// Gets the size of the z_off_t type that was compiled into Zlib + /// + public int SizeOfOffset { get { return bitSize((_flags >> 6) & 3); } } + + /// + /// Gets the version of ZLib as a string, e.g. "1.2.1" + /// + public static string Version { get { return zlibVersion(); } } + } + + #endregion + +} diff --git a/contrib/zlib/contrib/dotzlib/DotZLib/DotZLib.csproj b/contrib/zlib/contrib/dotzlib/DotZLib/DotZLib.csproj new file mode 100644 index 00000000..dea7fb16 --- /dev/null +++ b/contrib/zlib/contrib/dotzlib/DotZLib/DotZLib.csproj @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/contrib/zlib/contrib/dotzlib/DotZLib/GZipStream.cs b/contrib/zlib/contrib/dotzlib/DotZLib/GZipStream.cs new file mode 100644 index 00000000..f0eada1d --- /dev/null +++ b/contrib/zlib/contrib/dotzlib/DotZLib/GZipStream.cs @@ -0,0 +1,301 @@ +// +// Copyright Henrik Ravn 2004 +// +// Use, modification and distribution are subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.IO; +using System.Runtime.InteropServices; + +namespace DotZLib +{ + /// + /// Implements a compressed , in GZip (.gz) format. + /// + public class GZipStream : Stream, IDisposable + { + #region Dll Imports + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)] + private static extern IntPtr gzopen(string name, string mode); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int gzclose(IntPtr gzFile); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int gzwrite(IntPtr gzFile, int data, int length); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int gzread(IntPtr gzFile, int data, int length); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int gzgetc(IntPtr gzFile); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int gzputc(IntPtr gzFile, int c); + + #endregion + + #region Private data + private IntPtr _gzFile; + private bool _isDisposed = false; + private bool _isWriting; + #endregion + + #region Constructors + /// + /// Creates a new file as a writeable GZipStream + /// + /// The name of the compressed file to create + /// The compression level to use when adding data + /// If an error occurred in the internal zlib function + public GZipStream(string fileName, CompressLevel level) + { + _isWriting = true; + _gzFile = gzopen(fileName, String.Format("wb{0}", (int)level)); + if (_gzFile == IntPtr.Zero) + throw new ZLibException(-1, "Could not open " + fileName); + } + + /// + /// Opens an existing file as a readable GZipStream + /// + /// The name of the file to open + /// If an error occurred in the internal zlib function + public GZipStream(string fileName) + { + _isWriting = false; + _gzFile = gzopen(fileName, "rb"); + if (_gzFile == IntPtr.Zero) + throw new ZLibException(-1, "Could not open " + fileName); + + } + #endregion + + #region Access properties + /// + /// Returns true of this stream can be read from, false otherwise + /// + public override bool CanRead + { + get + { + return !_isWriting; + } + } + + + /// + /// Returns false. + /// + public override bool CanSeek + { + get + { + return false; + } + } + + /// + /// Returns true if this tsream is writeable, false otherwise + /// + public override bool CanWrite + { + get + { + return _isWriting; + } + } + #endregion + + #region Destructor & IDispose stuff + + /// + /// Destroys this instance + /// + ~GZipStream() + { + cleanUp(false); + } + + /// + /// Closes the external file handle + /// + public void Dispose() + { + cleanUp(true); + } + + // Does the actual closing of the file handle. + private void cleanUp(bool isDisposing) + { + if (!_isDisposed) + { + gzclose(_gzFile); + _isDisposed = true; + } + } + #endregion + + #region Basic reading and writing + /// + /// Attempts to read a number of bytes from the stream. + /// + /// The destination data buffer + /// The index of the first destination byte in buffer + /// The number of bytes requested + /// The number of bytes read + /// If buffer is null + /// If count or offset are negative + /// If offset + count is > buffer.Length + /// If this stream is not readable. + /// If this stream has been disposed. + public override int Read(byte[] buffer, int offset, int count) + { + if (!CanRead) throw new NotSupportedException(); + if (buffer == null) throw new ArgumentNullException(); + if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException(); + if ((offset+count) > buffer.Length) throw new ArgumentException(); + if (_isDisposed) throw new ObjectDisposedException("GZipStream"); + + GCHandle h = GCHandle.Alloc(buffer, GCHandleType.Pinned); + int result; + try + { + result = gzread(_gzFile, h.AddrOfPinnedObject().ToInt32() + offset, count); + if (result < 0) + throw new IOException(); + } + finally + { + h.Free(); + } + return result; + } + + /// + /// Attempts to read a single byte from the stream. + /// + /// The byte that was read, or -1 in case of error or End-Of-File + public override int ReadByte() + { + if (!CanRead) throw new NotSupportedException(); + if (_isDisposed) throw new ObjectDisposedException("GZipStream"); + return gzgetc(_gzFile); + } + + /// + /// Writes a number of bytes to the stream + /// + /// + /// + /// + /// If buffer is null + /// If count or offset are negative + /// If offset + count is > buffer.Length + /// If this stream is not writeable. + /// If this stream has been disposed. + public override void Write(byte[] buffer, int offset, int count) + { + if (!CanWrite) throw new NotSupportedException(); + if (buffer == null) throw new ArgumentNullException(); + if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException(); + if ((offset+count) > buffer.Length) throw new ArgumentException(); + if (_isDisposed) throw new ObjectDisposedException("GZipStream"); + + GCHandle h = GCHandle.Alloc(buffer, GCHandleType.Pinned); + try + { + int result = gzwrite(_gzFile, h.AddrOfPinnedObject().ToInt32() + offset, count); + if (result < 0) + throw new IOException(); + } + finally + { + h.Free(); + } + } + + /// + /// Writes a single byte to the stream + /// + /// The byte to add to the stream. + /// If this stream is not writeable. + /// If this stream has been disposed. + public override void WriteByte(byte value) + { + if (!CanWrite) throw new NotSupportedException(); + if (_isDisposed) throw new ObjectDisposedException("GZipStream"); + + int result = gzputc(_gzFile, (int)value); + if (result < 0) + throw new IOException(); + } + #endregion + + #region Position & length stuff + /// + /// Not supported. + /// + /// + /// Always thrown + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + /// + /// Not suppported. + /// + /// + /// + /// + /// Always thrown + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + /// + /// Flushes the GZipStream. + /// + /// In this implementation, this method does nothing. This is because excessive + /// flushing may degrade the achievable compression rates. + public override void Flush() + { + // left empty on purpose + } + + /// + /// Gets/sets the current position in the GZipStream. Not suppported. + /// + /// In this implementation this property is not supported + /// Always thrown + public override long Position + { + get + { + throw new NotSupportedException(); + } + set + { + throw new NotSupportedException(); + } + } + + /// + /// Gets the size of the stream. Not suppported. + /// + /// In this implementation this property is not supported + /// Always thrown + public override long Length + { + get + { + throw new NotSupportedException(); + } + } + #endregion + } +} diff --git a/contrib/zlib/contrib/dotzlib/DotZLib/Inflater.cs b/contrib/zlib/contrib/dotzlib/DotZLib/Inflater.cs new file mode 100644 index 00000000..d295f268 --- /dev/null +++ b/contrib/zlib/contrib/dotzlib/DotZLib/Inflater.cs @@ -0,0 +1,105 @@ +// +// Copyright Henrik Ravn 2004 +// +// Use, modification and distribution are subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace DotZLib +{ + + /// + /// Implements a data decompressor, using the inflate algorithm in the ZLib dll + /// + public class Inflater : CodecBase + { + #region Dll imports + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)] + private static extern int inflateInit_(ref ZStream sz, string vs, int size); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int inflate(ref ZStream sz, int flush); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int inflateReset(ref ZStream sz); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int inflateEnd(ref ZStream sz); + #endregion + + /// + /// Constructs an new instance of the Inflater + /// + public Inflater() : base() + { + int retval = inflateInit_(ref _ztream, Info.Version, Marshal.SizeOf(_ztream)); + if (retval != 0) + throw new ZLibException(retval, "Could not initialize inflater"); + + resetOutput(); + } + + + /// + /// Adds more data to the codec to be processed. + /// + /// Byte array containing the data to be added to the codec + /// The index of the first byte to add from data + /// The number of bytes to add + /// Adding data may, or may not, raise the DataAvailable event + public override void Add(byte[] data, int offset, int count) + { + if (data == null) throw new ArgumentNullException(); + if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException(); + if ((offset+count) > data.Length) throw new ArgumentException(); + + int total = count; + int inputIndex = offset; + int err = 0; + + while (err >= 0 && inputIndex < total) + { + copyInput(data, inputIndex, Math.Min(total - inputIndex, kBufferSize)); + err = inflate(ref _ztream, (int)FlushTypes.None); + if (err == 0) + while (_ztream.avail_out == 0) + { + OnDataAvailable(); + err = inflate(ref _ztream, (int)FlushTypes.None); + } + + inputIndex += (int)_ztream.total_in; + } + setChecksum( _ztream.adler ); + } + + + /// + /// Finishes up any pending data that needs to be processed and handled. + /// + public override void Finish() + { + int err; + do + { + err = inflate(ref _ztream, (int)FlushTypes.Finish); + OnDataAvailable(); + } + while (err == 0); + setChecksum( _ztream.adler ); + inflateReset(ref _ztream); + resetOutput(); + } + + /// + /// Closes the internal zlib inflate stream + /// + protected override void CleanUp() { inflateEnd(ref _ztream); } + + + } +} diff --git a/contrib/zlib/contrib/dotzlib/DotZLib/UnitTests.cs b/contrib/zlib/contrib/dotzlib/DotZLib/UnitTests.cs new file mode 100644 index 00000000..6d8aebb7 --- /dev/null +++ b/contrib/zlib/contrib/dotzlib/DotZLib/UnitTests.cs @@ -0,0 +1,274 @@ +// +// © Copyright Henrik Ravn 2004 +// +// Use, modification and distribution are subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.Collections; +using System.IO; + +// uncomment the define below to include unit tests +//#define nunit +#if nunit +using NUnit.Framework; + +// Unit tests for the DotZLib class library +// ---------------------------------------- +// +// Use this with NUnit 2 from http://www.nunit.org +// + +namespace DotZLibTests +{ + using DotZLib; + + // helper methods + internal class Utils + { + public static bool byteArrEqual( byte[] lhs, byte[] rhs ) + { + if (lhs.Length != rhs.Length) + return false; + for (int i = lhs.Length-1; i >= 0; --i) + if (lhs[i] != rhs[i]) + return false; + return true; + } + + } + + + [TestFixture] + public class CircBufferTests + { + #region Circular buffer tests + [Test] + public void SinglePutGet() + { + CircularBuffer buf = new CircularBuffer(10); + Assert.AreEqual( 0, buf.Size ); + Assert.AreEqual( -1, buf.Get() ); + + Assert.IsTrue(buf.Put( 1 )); + Assert.AreEqual( 1, buf.Size ); + Assert.AreEqual( 1, buf.Get() ); + Assert.AreEqual( 0, buf.Size ); + Assert.AreEqual( -1, buf.Get() ); + } + + [Test] + public void BlockPutGet() + { + CircularBuffer buf = new CircularBuffer(10); + byte[] arr = {1,2,3,4,5,6,7,8,9,10}; + Assert.AreEqual( 10, buf.Put(arr,0,10) ); + Assert.AreEqual( 10, buf.Size ); + Assert.IsFalse( buf.Put(11) ); + Assert.AreEqual( 1, buf.Get() ); + Assert.IsTrue( buf.Put(11) ); + + byte[] arr2 = (byte[])arr.Clone(); + Assert.AreEqual( 9, buf.Get(arr2,1,9) ); + Assert.IsTrue( Utils.byteArrEqual(arr,arr2) ); + } + + #endregion + } + + [TestFixture] + public class ChecksumTests + { + #region CRC32 Tests + [Test] + public void CRC32_Null() + { + CRC32Checksum crc32 = new CRC32Checksum(); + Assert.AreEqual( 0, crc32.Value ); + + crc32 = new CRC32Checksum(1); + Assert.AreEqual( 1, crc32.Value ); + + crc32 = new CRC32Checksum(556); + Assert.AreEqual( 556, crc32.Value ); + } + + [Test] + public void CRC32_Data() + { + CRC32Checksum crc32 = new CRC32Checksum(); + byte[] data = { 1,2,3,4,5,6,7 }; + crc32.Update(data); + Assert.AreEqual( 0x70e46888, crc32.Value ); + + crc32 = new CRC32Checksum(); + crc32.Update("penguin"); + Assert.AreEqual( 0x0e5c1a120, crc32.Value ); + + crc32 = new CRC32Checksum(1); + crc32.Update("penguin"); + Assert.AreEqual(0x43b6aa94, crc32.Value); + + } + #endregion + + #region Adler tests + + [Test] + public void Adler_Null() + { + AdlerChecksum adler = new AdlerChecksum(); + Assert.AreEqual(0, adler.Value); + + adler = new AdlerChecksum(1); + Assert.AreEqual( 1, adler.Value ); + + adler = new AdlerChecksum(556); + Assert.AreEqual( 556, adler.Value ); + } + + [Test] + public void Adler_Data() + { + AdlerChecksum adler = new AdlerChecksum(1); + byte[] data = { 1,2,3,4,5,6,7 }; + adler.Update(data); + Assert.AreEqual( 0x5b001d, adler.Value ); + + adler = new AdlerChecksum(); + adler.Update("penguin"); + Assert.AreEqual(0x0bcf02f6, adler.Value ); + + adler = new AdlerChecksum(1); + adler.Update("penguin"); + Assert.AreEqual(0x0bd602f7, adler.Value); + + } + #endregion + } + + [TestFixture] + public class InfoTests + { + #region Info tests + [Test] + public void Info_Version() + { + Info info = new Info(); + Assert.AreEqual("1.2.11", Info.Version); + Assert.AreEqual(32, info.SizeOfUInt); + Assert.AreEqual(32, info.SizeOfULong); + Assert.AreEqual(32, info.SizeOfPointer); + Assert.AreEqual(32, info.SizeOfOffset); + } + #endregion + } + + [TestFixture] + public class DeflateInflateTests + { + #region Deflate tests + [Test] + public void Deflate_Init() + { + using (Deflater def = new Deflater(CompressLevel.Default)) + { + } + } + + private ArrayList compressedData = new ArrayList(); + private uint adler1; + + private ArrayList uncompressedData = new ArrayList(); + private uint adler2; + + public void CDataAvail(byte[] data, int startIndex, int count) + { + for (int i = 0; i < count; ++i) + compressedData.Add(data[i+startIndex]); + } + + [Test] + public void Deflate_Compress() + { + compressedData.Clear(); + + byte[] testData = new byte[35000]; + for (int i = 0; i < testData.Length; ++i) + testData[i] = 5; + + using (Deflater def = new Deflater((CompressLevel)5)) + { + def.DataAvailable += new DataAvailableHandler(CDataAvail); + def.Add(testData); + def.Finish(); + adler1 = def.Checksum; + } + } + #endregion + + #region Inflate tests + [Test] + public void Inflate_Init() + { + using (Inflater inf = new Inflater()) + { + } + } + + private void DDataAvail(byte[] data, int startIndex, int count) + { + for (int i = 0; i < count; ++i) + uncompressedData.Add(data[i+startIndex]); + } + + [Test] + public void Inflate_Expand() + { + uncompressedData.Clear(); + + using (Inflater inf = new Inflater()) + { + inf.DataAvailable += new DataAvailableHandler(DDataAvail); + inf.Add((byte[])compressedData.ToArray(typeof(byte))); + inf.Finish(); + adler2 = inf.Checksum; + } + Assert.AreEqual( adler1, adler2 ); + } + #endregion + } + + [TestFixture] + public class GZipStreamTests + { + #region GZipStream test + [Test] + public void GZipStream_WriteRead() + { + using (GZipStream gzOut = new GZipStream("gzstream.gz", CompressLevel.Best)) + { + BinaryWriter writer = new BinaryWriter(gzOut); + writer.Write("hi there"); + writer.Write(Math.PI); + writer.Write(42); + } + + using (GZipStream gzIn = new GZipStream("gzstream.gz")) + { + BinaryReader reader = new BinaryReader(gzIn); + string s = reader.ReadString(); + Assert.AreEqual("hi there",s); + double d = reader.ReadDouble(); + Assert.AreEqual(Math.PI, d); + int i = reader.ReadInt32(); + Assert.AreEqual(42,i); + } + + } + #endregion + } +} + +#endif diff --git a/contrib/zlib/contrib/dotzlib/LICENSE_1_0.txt b/contrib/zlib/contrib/dotzlib/LICENSE_1_0.txt new file mode 100644 index 00000000..127a5bc3 --- /dev/null +++ b/contrib/zlib/contrib/dotzlib/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/contrib/zlib/contrib/dotzlib/readme.txt b/contrib/zlib/contrib/dotzlib/readme.txt new file mode 100644 index 00000000..4d8c2dd9 --- /dev/null +++ b/contrib/zlib/contrib/dotzlib/readme.txt @@ -0,0 +1,58 @@ +This directory contains a .Net wrapper class library for the ZLib1.dll + +The wrapper includes support for inflating/deflating memory buffers, +.Net streaming wrappers for the gz streams part of zlib, and wrappers +for the checksum parts of zlib. See DotZLib/UnitTests.cs for examples. + +Directory structure: +-------------------- + +LICENSE_1_0.txt - License file. +readme.txt - This file. +DotZLib.chm - Class library documentation +DotZLib.build - NAnt build file +DotZLib.sln - Microsoft Visual Studio 2003 solution file + +DotZLib\*.cs - Source files for the class library + +Unit tests: +----------- +The file DotZLib/UnitTests.cs contains unit tests for use with NUnit 2.1 or higher. +To include unit tests in the build, define nunit before building. + + +Build instructions: +------------------- + +1. Using Visual Studio.Net 2003: + Open DotZLib.sln in VS.Net and build from there. Output file (DotZLib.dll) + will be found ./DotZLib/bin/release or ./DotZLib/bin/debug, depending on + you are building the release or debug version of the library. Check + DotZLib/UnitTests.cs for instructions on how to include unit tests in the + build. + +2. Using NAnt: + Open a command prompt with access to the build environment and run nant + in the same directory as the DotZLib.build file. + You can define 2 properties on the nant command-line to control the build: + debug={true|false} to toggle between release/debug builds (default=true). + nunit={true|false} to include or esclude unit tests (default=true). + Also the target clean will remove binaries. + Output file (DotZLib.dll) will be found in either ./DotZLib/bin/release + or ./DotZLib/bin/debug, depending on whether you are building the release + or debug version of the library. + + Examples: + nant -D:debug=false -D:nunit=false + will build a release mode version of the library without unit tests. + nant + will build a debug version of the library with unit tests + nant clean + will remove all previously built files. + + +--------------------------------- +Copyright (c) Henrik Ravn 2004 + +Use, modification and distribution are subject to the Boost Software License, Version 1.0. +(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/contrib/zlib/contrib/gcc_gvmat64/gvmat64.S b/contrib/zlib/contrib/gcc_gvmat64/gvmat64.S new file mode 100644 index 00000000..23309fa2 --- /dev/null +++ b/contrib/zlib/contrib/gcc_gvmat64/gvmat64.S @@ -0,0 +1,574 @@ +/* +;uInt longest_match_x64( +; deflate_state *s, +; IPos cur_match); // current match + +; gvmat64.S -- Asm portion of the optimized longest_match for 32 bits x86_64 +; (AMD64 on Athlon 64, Opteron, Phenom +; and Intel EM64T on Pentium 4 with EM64T, Pentium D, Core 2 Duo, Core I5/I7) +; this file is translation from gvmat64.asm to GCC 4.x (for Linux, Mac XCode) +; Copyright (C) 1995-2010 Jean-loup Gailly, Brian Raiter and Gilles Vollant. +; +; File written by Gilles Vollant, by converting to assembly the longest_match +; from Jean-loup Gailly in deflate.c of zLib and infoZip zip. +; and by taking inspiration on asm686 with masm, optimised assembly code +; from Brian Raiter, written 1998 +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Permission is granted to anyone to use this software for any purpose, +; including commercial applications, and to alter it and redistribute it +; freely, subject to the following restrictions: +; +; 1. The origin of this software must not be misrepresented; you must not +; claim that you wrote the original software. If you use this software +; in a product, an acknowledgment in the product documentation would be +; appreciated but is not required. +; 2. Altered source versions must be plainly marked as such, and must not be +; misrepresented as being the original software +; 3. This notice may not be removed or altered from any source distribution. +; +; http://www.zlib.net +; http://www.winimage.com/zLibDll +; http://www.muppetlabs.com/~breadbox/software/assembly.html +; +; to compile this file for zLib, I use option: +; gcc -c -arch x86_64 gvmat64.S + + +;uInt longest_match(s, cur_match) +; deflate_state *s; +; IPos cur_match; // current match / +; +; with XCode for Mac, I had strange error with some jump on intel syntax +; this is why BEFORE_JMP and AFTER_JMP are used + */ + + +#define BEFORE_JMP .att_syntax +#define AFTER_JMP .intel_syntax noprefix + +#ifndef NO_UNDERLINE +# define match_init _match_init +# define longest_match _longest_match +#endif + +.intel_syntax noprefix + +.globl match_init, longest_match +.text +longest_match: + + + +#define LocalVarsSize 96 +/* +; register used : rax,rbx,rcx,rdx,rsi,rdi,r8,r9,r10,r11,r12 +; free register : r14,r15 +; register can be saved : rsp +*/ + +#define chainlenwmask (rsp + 8 - LocalVarsSize) +#define nicematch (rsp + 16 - LocalVarsSize) + +#define save_rdi (rsp + 24 - LocalVarsSize) +#define save_rsi (rsp + 32 - LocalVarsSize) +#define save_rbx (rsp + 40 - LocalVarsSize) +#define save_rbp (rsp + 48 - LocalVarsSize) +#define save_r12 (rsp + 56 - LocalVarsSize) +#define save_r13 (rsp + 64 - LocalVarsSize) +#define save_r14 (rsp + 72 - LocalVarsSize) +#define save_r15 (rsp + 80 - LocalVarsSize) + + +/* +; all the +4 offsets are due to the addition of pending_buf_size (in zlib +; in the deflate_state structure since the asm code was first written +; (if you compile with zlib 1.0.4 or older, remove the +4). +; Note : these value are good with a 8 bytes boundary pack structure +*/ + +#define MAX_MATCH 258 +#define MIN_MATCH 3 +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) + +/* +;;; Offsets for fields in the deflate_state structure. These numbers +;;; are calculated from the definition of deflate_state, with the +;;; assumption that the compiler will dword-align the fields. (Thus, +;;; changing the definition of deflate_state could easily cause this +;;; program to crash horribly, without so much as a warning at +;;; compile time. Sigh.) + +; all the +zlib1222add offsets are due to the addition of fields +; in zlib in the deflate_state structure since the asm code was first written +; (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)"). +; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0"). +; if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8"). +*/ + + + +/* you can check the structure offset by running + +#include +#include +#include "deflate.h" + +void print_depl() +{ +deflate_state ds; +deflate_state *s=&ds; +printf("size pointer=%u\n",(int)sizeof(void*)); + +printf("#define dsWSize %u\n",(int)(((char*)&(s->w_size))-((char*)s))); +printf("#define dsWMask %u\n",(int)(((char*)&(s->w_mask))-((char*)s))); +printf("#define dsWindow %u\n",(int)(((char*)&(s->window))-((char*)s))); +printf("#define dsPrev %u\n",(int)(((char*)&(s->prev))-((char*)s))); +printf("#define dsMatchLen %u\n",(int)(((char*)&(s->match_length))-((char*)s))); +printf("#define dsPrevMatch %u\n",(int)(((char*)&(s->prev_match))-((char*)s))); +printf("#define dsStrStart %u\n",(int)(((char*)&(s->strstart))-((char*)s))); +printf("#define dsMatchStart %u\n",(int)(((char*)&(s->match_start))-((char*)s))); +printf("#define dsLookahead %u\n",(int)(((char*)&(s->lookahead))-((char*)s))); +printf("#define dsPrevLen %u\n",(int)(((char*)&(s->prev_length))-((char*)s))); +printf("#define dsMaxChainLen %u\n",(int)(((char*)&(s->max_chain_length))-((char*)s))); +printf("#define dsGoodMatch %u\n",(int)(((char*)&(s->good_match))-((char*)s))); +printf("#define dsNiceMatch %u\n",(int)(((char*)&(s->nice_match))-((char*)s))); +} +*/ + +#define dsWSize 68 +#define dsWMask 76 +#define dsWindow 80 +#define dsPrev 96 +#define dsMatchLen 144 +#define dsPrevMatch 148 +#define dsStrStart 156 +#define dsMatchStart 160 +#define dsLookahead 164 +#define dsPrevLen 168 +#define dsMaxChainLen 172 +#define dsGoodMatch 188 +#define dsNiceMatch 192 + +#define window_size [ rcx + dsWSize] +#define WMask [ rcx + dsWMask] +#define window_ad [ rcx + dsWindow] +#define prev_ad [ rcx + dsPrev] +#define strstart [ rcx + dsStrStart] +#define match_start [ rcx + dsMatchStart] +#define Lookahead [ rcx + dsLookahead] //; 0ffffffffh on infozip +#define prev_length [ rcx + dsPrevLen] +#define max_chain_length [ rcx + dsMaxChainLen] +#define good_match [ rcx + dsGoodMatch] +#define nice_match [ rcx + dsNiceMatch] + +/* +; windows: +; parameter 1 in rcx(deflate state s), param 2 in rdx (cur match) + +; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and +; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp +; +; All registers must be preserved across the call, except for +; rax, rcx, rdx, r8, r9, r10, and r11, which are scratch. + +; +; gcc on macosx-linux: +; see http://www.x86-64.org/documentation/abi-0.99.pdf +; param 1 in rdi, param 2 in rsi +; rbx, rsp, rbp, r12 to r15 must be preserved + +;;; Save registers that the compiler may be using, and adjust esp to +;;; make room for our stack frame. + + +;;; Retrieve the function arguments. r8d will hold cur_match +;;; throughout the entire function. edx will hold the pointer to the +;;; deflate_state structure during the function's setup (before +;;; entering the main loop. + +; ms: parameter 1 in rcx (deflate_state* s), param 2 in edx -> r8 (cur match) +; mac: param 1 in rdi, param 2 rsi +; this clear high 32 bits of r8, which can be garbage in both r8 and rdx +*/ + mov [save_rbx],rbx + mov [save_rbp],rbp + + + mov rcx,rdi + + mov r8d,esi + + + mov [save_r12],r12 + mov [save_r13],r13 + mov [save_r14],r14 + mov [save_r15],r15 + + +//;;; uInt wmask = s->w_mask; +//;;; unsigned chain_length = s->max_chain_length; +//;;; if (s->prev_length >= s->good_match) { +//;;; chain_length >>= 2; +//;;; } + + + mov edi, prev_length + mov esi, good_match + mov eax, WMask + mov ebx, max_chain_length + cmp edi, esi + jl LastMatchGood + shr ebx, 2 +LastMatchGood: + +//;;; chainlen is decremented once beforehand so that the function can +//;;; use the sign flag instead of the zero flag for the exit test. +//;;; It is then shifted into the high word, to make room for the wmask +//;;; value, which it will always accompany. + + dec ebx + shl ebx, 16 + or ebx, eax + +//;;; on zlib only +//;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + + + mov eax, nice_match + mov [chainlenwmask], ebx + mov r10d, Lookahead + cmp r10d, eax + cmovnl r10d, eax + mov [nicematch],r10d + + + +//;;; register Bytef *scan = s->window + s->strstart; + mov r10, window_ad + mov ebp, strstart + lea r13, [r10 + rbp] + +//;;; Determine how many bytes the scan ptr is off from being +//;;; dword-aligned. + + mov r9,r13 + neg r13 + and r13,3 + +//;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ? +//;;; s->strstart - (IPos)MAX_DIST(s) : NIL; + + + mov eax, window_size + sub eax, MIN_LOOKAHEAD + + + xor edi,edi + sub ebp, eax + + mov r11d, prev_length + + cmovng ebp,edi + +//;;; int best_len = s->prev_length; + + +//;;; Store the sum of s->window + best_len in esi locally, and in esi. + + lea rsi,[r10+r11] + +//;;; register ush scan_start = *(ushf*)scan; +//;;; register ush scan_end = *(ushf*)(scan+best_len-1); +//;;; Posf *prev = s->prev; + + movzx r12d,word ptr [r9] + movzx ebx, word ptr [r9 + r11 - 1] + + mov rdi, prev_ad + +//;;; Jump into the main loop. + + mov edx, [chainlenwmask] + + cmp bx,word ptr [rsi + r8 - 1] + jz LookupLoopIsZero + + + +LookupLoop1: + and r8d, edx + + movzx r8d, word ptr [rdi + r8*2] + cmp r8d, ebp + jbe LeaveNow + + + + sub edx, 0x00010000 + BEFORE_JMP + js LeaveNow + AFTER_JMP + +LoopEntry1: + cmp bx,word ptr [rsi + r8 - 1] + BEFORE_JMP + jz LookupLoopIsZero + AFTER_JMP + +LookupLoop2: + and r8d, edx + + movzx r8d, word ptr [rdi + r8*2] + cmp r8d, ebp + BEFORE_JMP + jbe LeaveNow + AFTER_JMP + sub edx, 0x00010000 + BEFORE_JMP + js LeaveNow + AFTER_JMP + +LoopEntry2: + cmp bx,word ptr [rsi + r8 - 1] + BEFORE_JMP + jz LookupLoopIsZero + AFTER_JMP + +LookupLoop4: + and r8d, edx + + movzx r8d, word ptr [rdi + r8*2] + cmp r8d, ebp + BEFORE_JMP + jbe LeaveNow + AFTER_JMP + sub edx, 0x00010000 + BEFORE_JMP + js LeaveNow + AFTER_JMP + +LoopEntry4: + + cmp bx,word ptr [rsi + r8 - 1] + BEFORE_JMP + jnz LookupLoop1 + jmp LookupLoopIsZero + AFTER_JMP +/* +;;; do { +;;; match = s->window + cur_match; +;;; if (*(ushf*)(match+best_len-1) != scan_end || +;;; *(ushf*)match != scan_start) continue; +;;; [...] +;;; } while ((cur_match = prev[cur_match & wmask]) > limit +;;; && --chain_length != 0); +;;; +;;; Here is the inner loop of the function. The function will spend the +;;; majority of its time in this loop, and majority of that time will +;;; be spent in the first ten instructions. +;;; +;;; Within this loop: +;;; ebx = scanend +;;; r8d = curmatch +;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) +;;; esi = windowbestlen - i.e., (window + bestlen) +;;; edi = prev +;;; ebp = limit +*/ +.balign 16 +LookupLoop: + and r8d, edx + + movzx r8d, word ptr [rdi + r8*2] + cmp r8d, ebp + BEFORE_JMP + jbe LeaveNow + AFTER_JMP + sub edx, 0x00010000 + BEFORE_JMP + js LeaveNow + AFTER_JMP + +LoopEntry: + + cmp bx,word ptr [rsi + r8 - 1] + BEFORE_JMP + jnz LookupLoop1 + AFTER_JMP +LookupLoopIsZero: + cmp r12w, word ptr [r10 + r8] + BEFORE_JMP + jnz LookupLoop1 + AFTER_JMP + + +//;;; Store the current value of chainlen. + mov [chainlenwmask], edx +/* +;;; Point edi to the string under scrutiny, and esi to the string we +;;; are hoping to match it up with. In actuality, esi and edi are +;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is +;;; initialized to -(MAX_MATCH_8 - scanalign). +*/ + lea rsi,[r8+r10] + mov rdx, 0xfffffffffffffef8 //; -(MAX_MATCH_8) + lea rsi, [rsi + r13 + 0x0108] //;MAX_MATCH_8] + lea rdi, [r9 + r13 + 0x0108] //;MAX_MATCH_8] + + prefetcht1 [rsi+rdx] + prefetcht1 [rdi+rdx] + +/* +;;; Test the strings for equality, 8 bytes at a time. At the end, +;;; adjust rdx so that it is offset to the exact byte that mismatched. +;;; +;;; We already know at this point that the first three bytes of the +;;; strings match each other, and they can be safely passed over before +;;; starting the compare loop. So what this code does is skip over 0-3 +;;; bytes, as much as necessary in order to dword-align the edi +;;; pointer. (rsi will still be misaligned three times out of four.) +;;; +;;; It should be confessed that this loop usually does not represent +;;; much of the total running time. Replacing it with a more +;;; straightforward "rep cmpsb" would not drastically degrade +;;; performance. +*/ + +LoopCmps: + mov rax, [rsi + rdx] + xor rax, [rdi + rdx] + jnz LeaveLoopCmps + + mov rax, [rsi + rdx + 8] + xor rax, [rdi + rdx + 8] + jnz LeaveLoopCmps8 + + + mov rax, [rsi + rdx + 8+8] + xor rax, [rdi + rdx + 8+8] + jnz LeaveLoopCmps16 + + add rdx,8+8+8 + + BEFORE_JMP + jnz LoopCmps + jmp LenMaximum + AFTER_JMP + +LeaveLoopCmps16: add rdx,8 +LeaveLoopCmps8: add rdx,8 +LeaveLoopCmps: + + test eax, 0x0000FFFF + jnz LenLower + + test eax,0xffffffff + + jnz LenLower32 + + add rdx,4 + shr rax,32 + or ax,ax + BEFORE_JMP + jnz LenLower + AFTER_JMP + +LenLower32: + shr eax,16 + add rdx,2 + +LenLower: + sub al, 1 + adc rdx, 0 +//;;; Calculate the length of the match. If it is longer than MAX_MATCH, +//;;; then automatically accept it as the best possible match and leave. + + lea rax, [rdi + rdx] + sub rax, r9 + cmp eax, MAX_MATCH + BEFORE_JMP + jge LenMaximum + AFTER_JMP +/* +;;; If the length of the match is not longer than the best match we +;;; have so far, then forget it and return to the lookup loop. +;/////////////////////////////////// +*/ + cmp eax, r11d + jg LongerMatch + + lea rsi,[r10+r11] + + mov rdi, prev_ad + mov edx, [chainlenwmask] + BEFORE_JMP + jmp LookupLoop + AFTER_JMP +/* +;;; s->match_start = cur_match; +;;; best_len = len; +;;; if (len >= nice_match) break; +;;; scan_end = *(ushf*)(scan+best_len-1); +*/ +LongerMatch: + mov r11d, eax + mov match_start, r8d + cmp eax, [nicematch] + BEFORE_JMP + jge LeaveNow + AFTER_JMP + + lea rsi,[r10+rax] + + movzx ebx, word ptr [r9 + rax - 1] + mov rdi, prev_ad + mov edx, [chainlenwmask] + BEFORE_JMP + jmp LookupLoop + AFTER_JMP + +//;;; Accept the current string, with the maximum possible length. + +LenMaximum: + mov r11d,MAX_MATCH + mov match_start, r8d + +//;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len; +//;;; return s->lookahead; + +LeaveNow: + mov eax, Lookahead + cmp r11d, eax + cmovng eax, r11d + + + +//;;; Restore the stack and return from whence we came. + + +// mov rsi,[save_rsi] +// mov rdi,[save_rdi] + mov rbx,[save_rbx] + mov rbp,[save_rbp] + mov r12,[save_r12] + mov r13,[save_r13] + mov r14,[save_r14] + mov r15,[save_r15] + + + ret 0 +//; please don't remove this string ! +//; Your can freely use gvmat64 in any free or commercial app +//; but it is far better don't remove the string in the binary! + // db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998, converted to amd 64 by Gilles Vollant 2005",0dh,0ah,0 + + +match_init: + ret 0 + + diff --git a/contrib/zlib/contrib/infback9/README b/contrib/zlib/contrib/infback9/README new file mode 100644 index 00000000..e75ed132 --- /dev/null +++ b/contrib/zlib/contrib/infback9/README @@ -0,0 +1 @@ +See infback9.h for what this is and how to use it. diff --git a/contrib/zlib/contrib/infback9/infback9.c b/contrib/zlib/contrib/infback9/infback9.c new file mode 100644 index 00000000..05fb3e33 --- /dev/null +++ b/contrib/zlib/contrib/infback9/infback9.c @@ -0,0 +1,615 @@ +/* infback9.c -- inflate deflate64 data using a call-back interface + * Copyright (C) 1995-2008 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "infback9.h" +#include "inftree9.h" +#include "inflate9.h" + +#define WSIZE 65536UL + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + window is a user-supplied window and output buffer that is 64K bytes. + */ +int ZEXPORT inflateBack9Init_(strm, window, version, stream_size) +z_stream FAR *strm; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (voidpf)state; + state->window = window; + return Z_OK; +} + +/* + Build and output length and distance decoding tables for fixed code + decoding. + */ +#ifdef MAKEFIXED +#include + +void makefixed9(void) +{ + unsigned sym, bits, low, size; + code *next, *lenfix, *distfix; + struct inflate_state state; + code fixed[544]; + + /* literal/length table */ + sym = 0; + while (sym < 144) state.lens[sym++] = 8; + while (sym < 256) state.lens[sym++] = 9; + while (sym < 280) state.lens[sym++] = 7; + while (sym < 288) state.lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table9(LENS, state.lens, 288, &(next), &(bits), state.work); + + /* distance table */ + sym = 0; + while (sym < 32) state.lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table9(DISTS, state.lens, 32, &(next), &(bits), state.work); + + /* write tables */ + puts(" /* inffix9.h -- table for decoding deflate64 fixed codes"); + puts(" * Generated automatically by makefixed9()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", lenfix[low].op, lenfix[low].bits, + lenfix[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 5) == 0) printf("\n "); + printf("{%u,%u,%d}", distfix[low].op, distfix[low].bits, + distfix[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* Macros for inflateBack(): */ + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n <= 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = window; \ + left = WSIZE; \ + wrap = 1; \ + if (out(out_desc, put, (unsigned)left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack9(strm, in, in_desc, out, out_desc) +z_stream FAR *strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + z_const unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have; /* available input */ + unsigned long left; /* available output */ + inflate_mode mode; /* current inflate mode */ + int lastblock; /* true if processing last block */ + int wrap; /* true if the window has wrapped */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned extra; /* extra bits needed */ + unsigned long length; /* literal or length of data to copy */ + unsigned long offset; /* distance back to copy string from */ + unsigned long copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; +#include "inffix9.h" + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + mode = TYPE; + lastblock = 0; + wrap = 0; + window = state->window; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = window; + left = WSIZE; + lencode = Z_NULL; + distcode = Z_NULL; + + /* Inflate until end of block marked as last */ + for (;;) + switch (mode) { + case TYPE: + /* determine and dispatch block type */ + if (lastblock) { + BYTEBITS(); + mode = DONE; + break; + } + NEEDBITS(3); + lastblock = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + lastblock ? " (last)" : "")); + mode = STORED; + break; + case 1: /* fixed block */ + lencode = lenfix; + lenbits = 9; + distcode = distfix; + distbits = 5; + Tracev((stderr, "inflate: fixed codes block%s\n", + lastblock ? " (last)" : "")); + mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + lastblock ? " (last)" : "")); + mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + mode = BAD; + break; + } + length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %lu\n", + length)); + INITBITS(); + + /* copy stored block from input to output */ + while (length != 0) { + copy = length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); + if (state->nlen > 286) { + strm->msg = (char *)"too many length symbols"; + mode = BAD; + break; + } + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + lencode = (code const FAR *)(state->next); + lenbits = 7; + ret = inflate_table9(CODES, state->lens, 19, &(state->next), + &(lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = lencode[BITS(lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + NEEDBITS(here.bits); + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftree9.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + lencode = (code const FAR *)(state->next); + lenbits = 9; + ret = inflate_table9(LENS, state->lens, state->nlen, + &(state->next), &(lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + mode = BAD; + break; + } + distcode = (code const FAR *)(state->next); + distbits = 6; + ret = inflate_table9(DISTS, state->lens + state->nlen, + state->ndist, &(state->next), &(distbits), + state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + mode = LEN; + + case LEN: + /* get a literal, length, or end-of-block code */ + for (;;) { + here = lencode[BITS(lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + length = (unsigned)here.val; + + /* process literal */ + if (here.op == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + ROOM(); + *put++ = (unsigned char)(length); + left--; + mode = LEN; + break; + } + + /* process end of block */ + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + mode = TYPE; + break; + } + + /* invalid code */ + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + extra = (unsigned)(here.op) & 31; + if (extra != 0) { + NEEDBITS(extra); + length += BITS(extra); + DROPBITS(extra); + } + Tracevv((stderr, "inflate: length %lu\n", length)); + + /* get distance code */ + for (;;) { + here = distcode[BITS(distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + mode = BAD; + break; + } + offset = (unsigned)here.val; + + /* get distance extra bits, if any */ + extra = (unsigned)(here.op) & 15; + if (extra != 0) { + NEEDBITS(extra); + offset += BITS(extra); + DROPBITS(extra); + } + if (offset > WSIZE - (wrap ? 0: left)) { + strm->msg = (char *)"invalid distance too far back"; + mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %lu\n", offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = WSIZE - offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - offset; + copy = left; + } + if (copy > length) copy = length; + length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < WSIZE) { + if (out(out_desc, window, (unsigned)(WSIZE - left))) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBack9End(strm) +z_stream FAR *strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/contrib/zlib/contrib/infback9/infback9.h b/contrib/zlib/contrib/infback9/infback9.h new file mode 100644 index 00000000..1073c0a3 --- /dev/null +++ b/contrib/zlib/contrib/infback9/infback9.h @@ -0,0 +1,37 @@ +/* infback9.h -- header for using inflateBack9 functions + * Copyright (C) 2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * This header file and associated patches provide a decoder for PKWare's + * undocumented deflate64 compression method (method 9). Use with infback9.c, + * inftree9.h, inftree9.c, and inffix9.h. These patches are not supported. + * This should be compiled with zlib, since it uses zutil.h and zutil.o. + * This code has not yet been tested on 16-bit architectures. See the + * comments in zlib.h for inflateBack() usage. These functions are used + * identically, except that there is no windowBits parameter, and a 64K + * window must be provided. Also if int's are 16 bits, then a zero for + * the third parameter of the "out" function actually means 65536UL. + * zlib.h must be included before this header file. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +ZEXTERN int ZEXPORT inflateBack9 OF((z_stream FAR *strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +ZEXTERN int ZEXPORT inflateBack9End OF((z_stream FAR *strm)); +ZEXTERN int ZEXPORT inflateBack9Init_ OF((z_stream FAR *strm, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define inflateBack9Init(strm, window) \ + inflateBack9Init_((strm), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + +#ifdef __cplusplus +} +#endif diff --git a/contrib/zlib/contrib/infback9/inffix9.h b/contrib/zlib/contrib/infback9/inffix9.h new file mode 100644 index 00000000..ee5671d2 --- /dev/null +++ b/contrib/zlib/contrib/infback9/inffix9.h @@ -0,0 +1,107 @@ + /* inffix9.h -- table for decoding deflate64 fixed codes + * Generated automatically by makefixed9(). + */ + + /* WARNING: this file should *not* be used by applications. + It is part of the implementation of this library and is + subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{132,8,115},{130,7,31},{0,8,112}, + {0,8,48},{0,9,192},{128,7,10},{0,8,96},{0,8,32},{0,9,160}, + {0,8,0},{0,8,128},{0,8,64},{0,9,224},{128,7,6},{0,8,88}, + {0,8,24},{0,9,144},{131,7,59},{0,8,120},{0,8,56},{0,9,208}, + {129,7,17},{0,8,104},{0,8,40},{0,9,176},{0,8,8},{0,8,136}, + {0,8,72},{0,9,240},{128,7,4},{0,8,84},{0,8,20},{133,8,227}, + {131,7,43},{0,8,116},{0,8,52},{0,9,200},{129,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232}, + {128,7,8},{0,8,92},{0,8,28},{0,9,152},{132,7,83},{0,8,124}, + {0,8,60},{0,9,216},{130,7,23},{0,8,108},{0,8,44},{0,9,184}, + {0,8,12},{0,8,140},{0,8,76},{0,9,248},{128,7,3},{0,8,82}, + {0,8,18},{133,8,163},{131,7,35},{0,8,114},{0,8,50},{0,9,196}, + {129,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},{0,8,130}, + {0,8,66},{0,9,228},{128,7,7},{0,8,90},{0,8,26},{0,9,148}, + {132,7,67},{0,8,122},{0,8,58},{0,9,212},{130,7,19},{0,8,106}, + {0,8,42},{0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244}, + {128,7,5},{0,8,86},{0,8,22},{65,8,0},{131,7,51},{0,8,118}, + {0,8,54},{0,9,204},{129,7,15},{0,8,102},{0,8,38},{0,9,172}, + {0,8,6},{0,8,134},{0,8,70},{0,9,236},{128,7,9},{0,8,94}, + {0,8,30},{0,9,156},{132,7,99},{0,8,126},{0,8,62},{0,9,220}, + {130,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{133,8,131}, + {130,7,31},{0,8,113},{0,8,49},{0,9,194},{128,7,10},{0,8,97}, + {0,8,33},{0,9,162},{0,8,1},{0,8,129},{0,8,65},{0,9,226}, + {128,7,6},{0,8,89},{0,8,25},{0,9,146},{131,7,59},{0,8,121}, + {0,8,57},{0,9,210},{129,7,17},{0,8,105},{0,8,41},{0,9,178}, + {0,8,9},{0,8,137},{0,8,73},{0,9,242},{128,7,4},{0,8,85}, + {0,8,21},{144,8,3},{131,7,43},{0,8,117},{0,8,53},{0,9,202}, + {129,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133}, + {0,8,69},{0,9,234},{128,7,8},{0,8,93},{0,8,29},{0,9,154}, + {132,7,83},{0,8,125},{0,8,61},{0,9,218},{130,7,23},{0,8,109}, + {0,8,45},{0,9,186},{0,8,13},{0,8,141},{0,8,77},{0,9,250}, + {128,7,3},{0,8,83},{0,8,19},{133,8,195},{131,7,35},{0,8,115}, + {0,8,51},{0,9,198},{129,7,11},{0,8,99},{0,8,35},{0,9,166}, + {0,8,3},{0,8,131},{0,8,67},{0,9,230},{128,7,7},{0,8,91}, + {0,8,27},{0,9,150},{132,7,67},{0,8,123},{0,8,59},{0,9,214}, + {130,7,19},{0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139}, + {0,8,75},{0,9,246},{128,7,5},{0,8,87},{0,8,23},{77,8,0}, + {131,7,51},{0,8,119},{0,8,55},{0,9,206},{129,7,15},{0,8,103}, + {0,8,39},{0,9,174},{0,8,7},{0,8,135},{0,8,71},{0,9,238}, + {128,7,9},{0,8,95},{0,8,31},{0,9,158},{132,7,99},{0,8,127}, + {0,8,63},{0,9,222},{130,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80}, + {0,8,16},{132,8,115},{130,7,31},{0,8,112},{0,8,48},{0,9,193}, + {128,7,10},{0,8,96},{0,8,32},{0,9,161},{0,8,0},{0,8,128}, + {0,8,64},{0,9,225},{128,7,6},{0,8,88},{0,8,24},{0,9,145}, + {131,7,59},{0,8,120},{0,8,56},{0,9,209},{129,7,17},{0,8,104}, + {0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},{0,9,241}, + {128,7,4},{0,8,84},{0,8,20},{133,8,227},{131,7,43},{0,8,116}, + {0,8,52},{0,9,201},{129,7,13},{0,8,100},{0,8,36},{0,9,169}, + {0,8,4},{0,8,132},{0,8,68},{0,9,233},{128,7,8},{0,8,92}, + {0,8,28},{0,9,153},{132,7,83},{0,8,124},{0,8,60},{0,9,217}, + {130,7,23},{0,8,108},{0,8,44},{0,9,185},{0,8,12},{0,8,140}, + {0,8,76},{0,9,249},{128,7,3},{0,8,82},{0,8,18},{133,8,163}, + {131,7,35},{0,8,114},{0,8,50},{0,9,197},{129,7,11},{0,8,98}, + {0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {128,7,7},{0,8,90},{0,8,26},{0,9,149},{132,7,67},{0,8,122}, + {0,8,58},{0,9,213},{130,7,19},{0,8,106},{0,8,42},{0,9,181}, + {0,8,10},{0,8,138},{0,8,74},{0,9,245},{128,7,5},{0,8,86}, + {0,8,22},{65,8,0},{131,7,51},{0,8,118},{0,8,54},{0,9,205}, + {129,7,15},{0,8,102},{0,8,38},{0,9,173},{0,8,6},{0,8,134}, + {0,8,70},{0,9,237},{128,7,9},{0,8,94},{0,8,30},{0,9,157}, + {132,7,99},{0,8,126},{0,8,62},{0,9,221},{130,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253}, + {96,7,0},{0,8,81},{0,8,17},{133,8,131},{130,7,31},{0,8,113}, + {0,8,49},{0,9,195},{128,7,10},{0,8,97},{0,8,33},{0,9,163}, + {0,8,1},{0,8,129},{0,8,65},{0,9,227},{128,7,6},{0,8,89}, + {0,8,25},{0,9,147},{131,7,59},{0,8,121},{0,8,57},{0,9,211}, + {129,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},{0,8,137}, + {0,8,73},{0,9,243},{128,7,4},{0,8,85},{0,8,21},{144,8,3}, + {131,7,43},{0,8,117},{0,8,53},{0,9,203},{129,7,13},{0,8,101}, + {0,8,37},{0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235}, + {128,7,8},{0,8,93},{0,8,29},{0,9,155},{132,7,83},{0,8,125}, + {0,8,61},{0,9,219},{130,7,23},{0,8,109},{0,8,45},{0,9,187}, + {0,8,13},{0,8,141},{0,8,77},{0,9,251},{128,7,3},{0,8,83}, + {0,8,19},{133,8,195},{131,7,35},{0,8,115},{0,8,51},{0,9,199}, + {129,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{128,7,7},{0,8,91},{0,8,27},{0,9,151}, + {132,7,67},{0,8,123},{0,8,59},{0,9,215},{130,7,19},{0,8,107}, + {0,8,43},{0,9,183},{0,8,11},{0,8,139},{0,8,75},{0,9,247}, + {128,7,5},{0,8,87},{0,8,23},{77,8,0},{131,7,51},{0,8,119}, + {0,8,55},{0,9,207},{129,7,15},{0,8,103},{0,8,39},{0,9,175}, + {0,8,7},{0,8,135},{0,8,71},{0,9,239},{128,7,9},{0,8,95}, + {0,8,31},{0,9,159},{132,7,99},{0,8,127},{0,8,63},{0,9,223}, + {130,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143}, + {0,8,79},{0,9,255} + }; + + static const code distfix[32] = { + {128,5,1},{135,5,257},{131,5,17},{139,5,4097},{129,5,5}, + {137,5,1025},{133,5,65},{141,5,16385},{128,5,3},{136,5,513}, + {132,5,33},{140,5,8193},{130,5,9},{138,5,2049},{134,5,129}, + {142,5,32769},{128,5,2},{135,5,385},{131,5,25},{139,5,6145}, + {129,5,7},{137,5,1537},{133,5,97},{141,5,24577},{128,5,4}, + {136,5,769},{132,5,49},{140,5,12289},{130,5,13},{138,5,3073}, + {134,5,193},{142,5,49153} + }; diff --git a/contrib/zlib/contrib/infback9/inflate9.h b/contrib/zlib/contrib/infback9/inflate9.h new file mode 100644 index 00000000..ee9a7939 --- /dev/null +++ b/contrib/zlib/contrib/infback9/inflate9.h @@ -0,0 +1,47 @@ +/* inflate9.h -- internal inflate state definition + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Possible inflate modes between inflate() calls */ +typedef enum { + TYPE, /* i: waiting for type bits, including last-flag bit */ + STORED, /* i: waiting for stored size (length and complement) */ + TABLE, /* i: waiting for dynamic block table lengths */ + LEN, /* i: waiting for length/lit code */ + DONE, /* finished check, done -- remain here until reset */ + BAD /* got a data error -- remain here until reset */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD mode -- not shown for clarity) + + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or DONE + STORED -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LEN or TYPE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + /* sliding window */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/contrib/zlib/contrib/infback9/inftree9.c b/contrib/zlib/contrib/infback9/inftree9.c new file mode 100644 index 00000000..5f4a7679 --- /dev/null +++ b/contrib/zlib/contrib/infback9/inftree9.c @@ -0,0 +1,324 @@ +/* inftree9.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2017 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftree9.h" + +#define MAXBITS 15 + +const char inflate9_copyright[] = + " inflate9 1.2.11 Copyright 1995-2017 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int inflate_table9(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, + 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, + 131, 163, 195, 227, 3, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 128, 128, 128, 128, 128, 128, 128, 128, 129, 129, 129, 129, + 130, 130, 130, 130, 131, 131, 131, 131, 132, 132, 132, 132, + 133, 133, 133, 133, 144, 77, 202}; + static const unsigned short dbase[32] = { /* Distance codes 0..31 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, + 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, + 4097, 6145, 8193, 12289, 16385, 24577, 32769, 49153}; + static const unsigned short dext[32] = { /* Distance codes 0..31 extra */ + 128, 128, 128, 128, 129, 129, 130, 130, 131, 131, 132, 132, + 133, 133, 134, 134, 135, 135, 136, 136, 137, 137, 138, 138, + 139, 139, 140, 140, 141, 141, 142, 142}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) return -1; /* no codes! */ + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for LENS and DIST tables against + the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in + the initial root table size constants. See the comments in inftree9.h + for more information. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if ((type == LENS && used >= ENOUGH_LENS) || + (type == DISTS && used >= ENOUGH_DISTS)) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += 1U << curr; + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if ((type == LENS && used >= ENOUGH_LENS) || + (type == DISTS && used >= ENOUGH_DISTS)) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + curr = root; + this.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/contrib/zlib/contrib/infback9/inftree9.h b/contrib/zlib/contrib/infback9/inftree9.h new file mode 100644 index 00000000..5ab21f0c --- /dev/null +++ b/contrib/zlib/contrib/infback9/inftree9.h @@ -0,0 +1,61 @@ +/* inftree9.h -- header to use inftree9.c + * Copyright (C) 1995-2008 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 100eeeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of the dynamic table. The maximum number of code structures is + 1446, which is the sum of 852 for literal/length codes and 594 for distance + codes. These values were found by exhaustive searches using the program + examples/enough.c found in the zlib distribtution. The arguments to that + program are the number of symbols, the initial root table size, and the + maximum bit length of a code. "enough 286 9 15" for literal/length codes + returns returns 852, and "enough 32 6 15" for distance codes returns 594. + The initial root table size (9 or 6) is found in the fifth argument of the + inflate_table() calls in infback9.c. If the root table size is changed, + then these maximum sizes would be need to be recalculated and updated. */ +#define ENOUGH_LENS 852 +#define ENOUGH_DISTS 594 +#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) + +/* Type of code to build for inflate_table9() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table9 OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/contrib/zlib/contrib/inflate86/inffas86.c b/contrib/zlib/contrib/inflate86/inffas86.c new file mode 100644 index 00000000..7292f67b --- /dev/null +++ b/contrib/zlib/contrib/inflate86/inffas86.c @@ -0,0 +1,1157 @@ +/* inffas86.c is a hand tuned assembler version of + * + * inffast.c -- fast decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Copyright (C) 2003 Chris Anderson + * Please use the copyright conditions above. + * + * Dec-29-2003 -- I added AMD64 inflate asm support. This version is also + * slightly quicker on x86 systems because, instead of using rep movsb to copy + * data, it uses rep movsw, which moves data in 2-byte chunks instead of single + * bytes. I've tested the AMD64 code on a Fedora Core 1 + the x86_64 updates + * from http://fedora.linux.duke.edu/fc1_x86_64 + * which is running on an Athlon 64 3000+ / Gigabyte GA-K8VT800M system with + * 1GB ram. The 64-bit version is about 4% faster than the 32-bit version, + * when decompressing mozilla-source-1.3.tar.gz. + * + * Mar-13-2003 -- Most of this is derived from inffast.S which is derived from + * the gcc -S output of zlib-1.2.0/inffast.c. Zlib-1.2.0 is in beta release at + * the moment. I have successfully compiled and tested this code with gcc2.96, + * gcc3.2, icc5.0, msvc6.0. It is very close to the speed of inffast.S + * compiled with gcc -DNO_MMX, but inffast.S is still faster on the P3 with MMX + * enabled. I will attempt to merge the MMX code into this version. Newer + * versions of this and inffast.S can be found at + * http://www.eetbeetee.com/zlib/ and http://www.charm.net/~christop/zlib/ + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* Mark Adler's comments from inffast.c: */ + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + struct inffast_ar { +/* 64 32 x86 x86_64 */ +/* ar offset register */ +/* 0 0 */ void *esp; /* esp save */ +/* 8 4 */ void *ebp; /* ebp save */ +/* 16 8 */ unsigned char FAR *in; /* esi rsi local strm->next_in */ +/* 24 12 */ unsigned char FAR *last; /* r9 while in < last */ +/* 32 16 */ unsigned char FAR *out; /* edi rdi local strm->next_out */ +/* 40 20 */ unsigned char FAR *beg; /* inflate()'s init next_out */ +/* 48 24 */ unsigned char FAR *end; /* r10 while out < end */ +/* 56 28 */ unsigned char FAR *window;/* size of window, wsize!=0 */ +/* 64 32 */ code const FAR *lcode; /* ebp rbp local strm->lencode */ +/* 72 36 */ code const FAR *dcode; /* r11 local strm->distcode */ +/* 80 40 */ unsigned long hold; /* edx rdx local strm->hold */ +/* 88 44 */ unsigned bits; /* ebx rbx local strm->bits */ +/* 92 48 */ unsigned wsize; /* window size */ +/* 96 52 */ unsigned write; /* window write index */ +/*100 56 */ unsigned lmask; /* r12 mask for lcode */ +/*104 60 */ unsigned dmask; /* r13 mask for dcode */ +/*108 64 */ unsigned len; /* r14 match length */ +/*112 68 */ unsigned dist; /* r15 match distance */ +/*116 72 */ unsigned status; /* set when state chng*/ + } ar; + +#if defined( __GNUC__ ) && defined( __amd64__ ) && ! defined( __i386 ) +#define PAD_AVAIL_IN 6 +#define PAD_AVAIL_OUT 258 +#else +#define PAD_AVAIL_IN 5 +#define PAD_AVAIL_OUT 257 +#endif + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + ar.in = strm->next_in; + ar.last = ar.in + (strm->avail_in - PAD_AVAIL_IN); + ar.out = strm->next_out; + ar.beg = ar.out - (start - strm->avail_out); + ar.end = ar.out + (strm->avail_out - PAD_AVAIL_OUT); + ar.wsize = state->wsize; + ar.write = state->wnext; + ar.window = state->window; + ar.hold = state->hold; + ar.bits = state->bits; + ar.lcode = state->lencode; + ar.dcode = state->distcode; + ar.lmask = (1U << state->lenbits) - 1; + ar.dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + + /* align in on 1/2 hold size boundary */ + while (((unsigned long)(void *)ar.in & (sizeof(ar.hold) / 2 - 1)) != 0) { + ar.hold += (unsigned long)*ar.in++ << ar.bits; + ar.bits += 8; + } + +#if defined( __GNUC__ ) && defined( __amd64__ ) && ! defined( __i386 ) + __asm__ __volatile__ ( +" leaq %0, %%rax\n" +" movq %%rbp, 8(%%rax)\n" /* save regs rbp and rsp */ +" movq %%rsp, (%%rax)\n" +" movq %%rax, %%rsp\n" /* make rsp point to &ar */ +" movq 16(%%rsp), %%rsi\n" /* rsi = in */ +" movq 32(%%rsp), %%rdi\n" /* rdi = out */ +" movq 24(%%rsp), %%r9\n" /* r9 = last */ +" movq 48(%%rsp), %%r10\n" /* r10 = end */ +" movq 64(%%rsp), %%rbp\n" /* rbp = lcode */ +" movq 72(%%rsp), %%r11\n" /* r11 = dcode */ +" movq 80(%%rsp), %%rdx\n" /* rdx = hold */ +" movl 88(%%rsp), %%ebx\n" /* ebx = bits */ +" movl 100(%%rsp), %%r12d\n" /* r12d = lmask */ +" movl 104(%%rsp), %%r13d\n" /* r13d = dmask */ + /* r14d = len */ + /* r15d = dist */ +" cld\n" +" cmpq %%rdi, %%r10\n" +" je .L_one_time\n" /* if only one decode left */ +" cmpq %%rsi, %%r9\n" +" je .L_one_time\n" +" jmp .L_do_loop\n" + +".L_one_time:\n" +" movq %%r12, %%r8\n" /* r8 = lmask */ +" cmpb $32, %%bl\n" +" ja .L_get_length_code_one_time\n" + +" lodsl\n" /* eax = *(uint *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $32, %%bl\n" /* bits += 32 */ +" shlq %%cl, %%rax\n" +" orq %%rax, %%rdx\n" /* hold |= *((uint *)in)++ << bits */ +" jmp .L_get_length_code_one_time\n" + +".align 32,0x90\n" +".L_while_test:\n" +" cmpq %%rdi, %%r10\n" +" jbe .L_break_loop\n" +" cmpq %%rsi, %%r9\n" +" jbe .L_break_loop\n" + +".L_do_loop:\n" +" movq %%r12, %%r8\n" /* r8 = lmask */ +" cmpb $32, %%bl\n" +" ja .L_get_length_code\n" /* if (32 < bits) */ + +" lodsl\n" /* eax = *(uint *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $32, %%bl\n" /* bits += 32 */ +" shlq %%cl, %%rax\n" +" orq %%rax, %%rdx\n" /* hold |= *((uint *)in)++ << bits */ + +".L_get_length_code:\n" +" andq %%rdx, %%r8\n" /* r8 &= hold */ +" movl (%%rbp,%%r8,4), %%eax\n" /* eax = lcode[hold & lmask] */ + +" movb %%ah, %%cl\n" /* cl = this.bits */ +" subb %%ah, %%bl\n" /* bits -= this.bits */ +" shrq %%cl, %%rdx\n" /* hold >>= this.bits */ + +" testb %%al, %%al\n" +" jnz .L_test_for_length_base\n" /* if (op != 0) 45.7% */ + +" movq %%r12, %%r8\n" /* r8 = lmask */ +" shrl $16, %%eax\n" /* output this.val char */ +" stosb\n" + +".L_get_length_code_one_time:\n" +" andq %%rdx, %%r8\n" /* r8 &= hold */ +" movl (%%rbp,%%r8,4), %%eax\n" /* eax = lcode[hold & lmask] */ + +".L_dolen:\n" +" movb %%ah, %%cl\n" /* cl = this.bits */ +" subb %%ah, %%bl\n" /* bits -= this.bits */ +" shrq %%cl, %%rdx\n" /* hold >>= this.bits */ + +" testb %%al, %%al\n" +" jnz .L_test_for_length_base\n" /* if (op != 0) 45.7% */ + +" shrl $16, %%eax\n" /* output this.val char */ +" stosb\n" +" jmp .L_while_test\n" + +".align 32,0x90\n" +".L_test_for_length_base:\n" +" movl %%eax, %%r14d\n" /* len = this */ +" shrl $16, %%r14d\n" /* len = this.val */ +" movb %%al, %%cl\n" + +" testb $16, %%al\n" +" jz .L_test_for_second_level_length\n" /* if ((op & 16) == 0) 8% */ +" andb $15, %%cl\n" /* op &= 15 */ +" jz .L_decode_distance\n" /* if (!op) */ + +".L_add_bits_to_len:\n" +" subb %%cl, %%bl\n" +" xorl %%eax, %%eax\n" +" incl %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" +" andl %%edx, %%eax\n" /* eax &= hold */ +" shrq %%cl, %%rdx\n" +" addl %%eax, %%r14d\n" /* len += hold & mask[op] */ + +".L_decode_distance:\n" +" movq %%r13, %%r8\n" /* r8 = dmask */ +" cmpb $32, %%bl\n" +" ja .L_get_distance_code\n" /* if (32 < bits) */ + +" lodsl\n" /* eax = *(uint *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $32, %%bl\n" /* bits += 32 */ +" shlq %%cl, %%rax\n" +" orq %%rax, %%rdx\n" /* hold |= *((uint *)in)++ << bits */ + +".L_get_distance_code:\n" +" andq %%rdx, %%r8\n" /* r8 &= hold */ +" movl (%%r11,%%r8,4), %%eax\n" /* eax = dcode[hold & dmask] */ + +".L_dodist:\n" +" movl %%eax, %%r15d\n" /* dist = this */ +" shrl $16, %%r15d\n" /* dist = this.val */ +" movb %%ah, %%cl\n" +" subb %%ah, %%bl\n" /* bits -= this.bits */ +" shrq %%cl, %%rdx\n" /* hold >>= this.bits */ +" movb %%al, %%cl\n" /* cl = this.op */ + +" testb $16, %%al\n" /* if ((op & 16) == 0) */ +" jz .L_test_for_second_level_dist\n" +" andb $15, %%cl\n" /* op &= 15 */ +" jz .L_check_dist_one\n" + +".L_add_bits_to_dist:\n" +" subb %%cl, %%bl\n" +" xorl %%eax, %%eax\n" +" incl %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" /* (1 << op) - 1 */ +" andl %%edx, %%eax\n" /* eax &= hold */ +" shrq %%cl, %%rdx\n" +" addl %%eax, %%r15d\n" /* dist += hold & ((1 << op) - 1) */ + +".L_check_window:\n" +" movq %%rsi, %%r8\n" /* save in so from can use it's reg */ +" movq %%rdi, %%rax\n" +" subq 40(%%rsp), %%rax\n" /* nbytes = out - beg */ + +" cmpl %%r15d, %%eax\n" +" jb .L_clip_window\n" /* if (dist > nbytes) 4.2% */ + +" movl %%r14d, %%ecx\n" /* ecx = len */ +" movq %%rdi, %%rsi\n" +" subq %%r15, %%rsi\n" /* from = out - dist */ + +" sarl %%ecx\n" +" jnc .L_copy_two\n" /* if len % 2 == 0 */ + +" rep movsw\n" +" movb (%%rsi), %%al\n" +" movb %%al, (%%rdi)\n" +" incq %%rdi\n" + +" movq %%r8, %%rsi\n" /* move in back to %rsi, toss from */ +" jmp .L_while_test\n" + +".L_copy_two:\n" +" rep movsw\n" +" movq %%r8, %%rsi\n" /* move in back to %rsi, toss from */ +" jmp .L_while_test\n" + +".align 32,0x90\n" +".L_check_dist_one:\n" +" cmpl $1, %%r15d\n" /* if dist 1, is a memset */ +" jne .L_check_window\n" +" cmpq %%rdi, 40(%%rsp)\n" /* if out == beg, outside window */ +" je .L_check_window\n" + +" movl %%r14d, %%ecx\n" /* ecx = len */ +" movb -1(%%rdi), %%al\n" +" movb %%al, %%ah\n" + +" sarl %%ecx\n" +" jnc .L_set_two\n" +" movb %%al, (%%rdi)\n" +" incq %%rdi\n" + +".L_set_two:\n" +" rep stosw\n" +" jmp .L_while_test\n" + +".align 32,0x90\n" +".L_test_for_second_level_length:\n" +" testb $64, %%al\n" +" jnz .L_test_for_end_of_block\n" /* if ((op & 64) != 0) */ + +" xorl %%eax, %%eax\n" +" incl %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" +" andl %%edx, %%eax\n" /* eax &= hold */ +" addl %%r14d, %%eax\n" /* eax += len */ +" movl (%%rbp,%%rax,4), %%eax\n" /* eax = lcode[val+(hold&mask[op])]*/ +" jmp .L_dolen\n" + +".align 32,0x90\n" +".L_test_for_second_level_dist:\n" +" testb $64, %%al\n" +" jnz .L_invalid_distance_code\n" /* if ((op & 64) != 0) */ + +" xorl %%eax, %%eax\n" +" incl %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" +" andl %%edx, %%eax\n" /* eax &= hold */ +" addl %%r15d, %%eax\n" /* eax += dist */ +" movl (%%r11,%%rax,4), %%eax\n" /* eax = dcode[val+(hold&mask[op])]*/ +" jmp .L_dodist\n" + +".align 32,0x90\n" +".L_clip_window:\n" +" movl %%eax, %%ecx\n" /* ecx = nbytes */ +" movl 92(%%rsp), %%eax\n" /* eax = wsize, prepare for dist cmp */ +" negl %%ecx\n" /* nbytes = -nbytes */ + +" cmpl %%r15d, %%eax\n" +" jb .L_invalid_distance_too_far\n" /* if (dist > wsize) */ + +" addl %%r15d, %%ecx\n" /* nbytes = dist - nbytes */ +" cmpl $0, 96(%%rsp)\n" +" jne .L_wrap_around_window\n" /* if (write != 0) */ + +" movq 56(%%rsp), %%rsi\n" /* from = window */ +" subl %%ecx, %%eax\n" /* eax -= nbytes */ +" addq %%rax, %%rsi\n" /* from += wsize - nbytes */ + +" movl %%r14d, %%eax\n" /* eax = len */ +" cmpl %%ecx, %%r14d\n" +" jbe .L_do_copy\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* eax -= nbytes */ +" rep movsb\n" +" movq %%rdi, %%rsi\n" +" subq %%r15, %%rsi\n" /* from = &out[ -dist ] */ +" jmp .L_do_copy\n" + +".align 32,0x90\n" +".L_wrap_around_window:\n" +" movl 96(%%rsp), %%eax\n" /* eax = write */ +" cmpl %%eax, %%ecx\n" +" jbe .L_contiguous_in_window\n" /* if (write >= nbytes) */ + +" movl 92(%%rsp), %%esi\n" /* from = wsize */ +" addq 56(%%rsp), %%rsi\n" /* from += window */ +" addq %%rax, %%rsi\n" /* from += write */ +" subq %%rcx, %%rsi\n" /* from -= nbytes */ +" subl %%eax, %%ecx\n" /* nbytes -= write */ + +" movl %%r14d, %%eax\n" /* eax = len */ +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movq 56(%%rsp), %%rsi\n" /* from = window */ +" movl 96(%%rsp), %%ecx\n" /* nbytes = write */ +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movq %%rdi, %%rsi\n" +" subq %%r15, %%rsi\n" /* from = out - dist */ +" jmp .L_do_copy\n" + +".align 32,0x90\n" +".L_contiguous_in_window:\n" +" movq 56(%%rsp), %%rsi\n" /* rsi = window */ +" addq %%rax, %%rsi\n" +" subq %%rcx, %%rsi\n" /* from += write - nbytes */ + +" movl %%r14d, %%eax\n" /* eax = len */ +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movq %%rdi, %%rsi\n" +" subq %%r15, %%rsi\n" /* from = out - dist */ +" jmp .L_do_copy\n" /* if (nbytes >= len) */ + +".align 32,0x90\n" +".L_do_copy:\n" +" movl %%eax, %%ecx\n" /* ecx = len */ +" rep movsb\n" + +" movq %%r8, %%rsi\n" /* move in back to %esi, toss from */ +" jmp .L_while_test\n" + +".L_test_for_end_of_block:\n" +" testb $32, %%al\n" +" jz .L_invalid_literal_length_code\n" +" movl $1, 116(%%rsp)\n" +" jmp .L_break_loop_with_status\n" + +".L_invalid_literal_length_code:\n" +" movl $2, 116(%%rsp)\n" +" jmp .L_break_loop_with_status\n" + +".L_invalid_distance_code:\n" +" movl $3, 116(%%rsp)\n" +" jmp .L_break_loop_with_status\n" + +".L_invalid_distance_too_far:\n" +" movl $4, 116(%%rsp)\n" +" jmp .L_break_loop_with_status\n" + +".L_break_loop:\n" +" movl $0, 116(%%rsp)\n" + +".L_break_loop_with_status:\n" +/* put in, out, bits, and hold back into ar and pop esp */ +" movq %%rsi, 16(%%rsp)\n" /* in */ +" movq %%rdi, 32(%%rsp)\n" /* out */ +" movl %%ebx, 88(%%rsp)\n" /* bits */ +" movq %%rdx, 80(%%rsp)\n" /* hold */ +" movq (%%rsp), %%rax\n" /* restore rbp and rsp */ +" movq 8(%%rsp), %%rbp\n" +" movq %%rax, %%rsp\n" + : + : "m" (ar) + : "memory", "%rax", "%rbx", "%rcx", "%rdx", "%rsi", "%rdi", + "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" + ); +#elif ( defined( __GNUC__ ) || defined( __ICC ) ) && defined( __i386 ) + __asm__ __volatile__ ( +" leal %0, %%eax\n" +" movl %%esp, (%%eax)\n" /* save esp, ebp */ +" movl %%ebp, 4(%%eax)\n" +" movl %%eax, %%esp\n" +" movl 8(%%esp), %%esi\n" /* esi = in */ +" movl 16(%%esp), %%edi\n" /* edi = out */ +" movl 40(%%esp), %%edx\n" /* edx = hold */ +" movl 44(%%esp), %%ebx\n" /* ebx = bits */ +" movl 32(%%esp), %%ebp\n" /* ebp = lcode */ + +" cld\n" +" jmp .L_do_loop\n" + +".align 32,0x90\n" +".L_while_test:\n" +" cmpl %%edi, 24(%%esp)\n" /* out < end */ +" jbe .L_break_loop\n" +" cmpl %%esi, 12(%%esp)\n" /* in < last */ +" jbe .L_break_loop\n" + +".L_do_loop:\n" +" cmpb $15, %%bl\n" +" ja .L_get_length_code\n" /* if (15 < bits) */ + +" xorl %%eax, %%eax\n" +" lodsw\n" /* al = *(ushort *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $16, %%bl\n" /* bits += 16 */ +" shll %%cl, %%eax\n" +" orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */ + +".L_get_length_code:\n" +" movl 56(%%esp), %%eax\n" /* eax = lmask */ +" andl %%edx, %%eax\n" /* eax &= hold */ +" movl (%%ebp,%%eax,4), %%eax\n" /* eax = lcode[hold & lmask] */ + +".L_dolen:\n" +" movb %%ah, %%cl\n" /* cl = this.bits */ +" subb %%ah, %%bl\n" /* bits -= this.bits */ +" shrl %%cl, %%edx\n" /* hold >>= this.bits */ + +" testb %%al, %%al\n" +" jnz .L_test_for_length_base\n" /* if (op != 0) 45.7% */ + +" shrl $16, %%eax\n" /* output this.val char */ +" stosb\n" +" jmp .L_while_test\n" + +".align 32,0x90\n" +".L_test_for_length_base:\n" +" movl %%eax, %%ecx\n" /* len = this */ +" shrl $16, %%ecx\n" /* len = this.val */ +" movl %%ecx, 64(%%esp)\n" /* save len */ +" movb %%al, %%cl\n" + +" testb $16, %%al\n" +" jz .L_test_for_second_level_length\n" /* if ((op & 16) == 0) 8% */ +" andb $15, %%cl\n" /* op &= 15 */ +" jz .L_decode_distance\n" /* if (!op) */ +" cmpb %%cl, %%bl\n" +" jae .L_add_bits_to_len\n" /* if (op <= bits) */ + +" movb %%cl, %%ch\n" /* stash op in ch, freeing cl */ +" xorl %%eax, %%eax\n" +" lodsw\n" /* al = *(ushort *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $16, %%bl\n" /* bits += 16 */ +" shll %%cl, %%eax\n" +" orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */ +" movb %%ch, %%cl\n" /* move op back to ecx */ + +".L_add_bits_to_len:\n" +" subb %%cl, %%bl\n" +" xorl %%eax, %%eax\n" +" incl %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" +" andl %%edx, %%eax\n" /* eax &= hold */ +" shrl %%cl, %%edx\n" +" addl %%eax, 64(%%esp)\n" /* len += hold & mask[op] */ + +".L_decode_distance:\n" +" cmpb $15, %%bl\n" +" ja .L_get_distance_code\n" /* if (15 < bits) */ + +" xorl %%eax, %%eax\n" +" lodsw\n" /* al = *(ushort *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $16, %%bl\n" /* bits += 16 */ +" shll %%cl, %%eax\n" +" orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */ + +".L_get_distance_code:\n" +" movl 60(%%esp), %%eax\n" /* eax = dmask */ +" movl 36(%%esp), %%ecx\n" /* ecx = dcode */ +" andl %%edx, %%eax\n" /* eax &= hold */ +" movl (%%ecx,%%eax,4), %%eax\n"/* eax = dcode[hold & dmask] */ + +".L_dodist:\n" +" movl %%eax, %%ebp\n" /* dist = this */ +" shrl $16, %%ebp\n" /* dist = this.val */ +" movb %%ah, %%cl\n" +" subb %%ah, %%bl\n" /* bits -= this.bits */ +" shrl %%cl, %%edx\n" /* hold >>= this.bits */ +" movb %%al, %%cl\n" /* cl = this.op */ + +" testb $16, %%al\n" /* if ((op & 16) == 0) */ +" jz .L_test_for_second_level_dist\n" +" andb $15, %%cl\n" /* op &= 15 */ +" jz .L_check_dist_one\n" +" cmpb %%cl, %%bl\n" +" jae .L_add_bits_to_dist\n" /* if (op <= bits) 97.6% */ + +" movb %%cl, %%ch\n" /* stash op in ch, freeing cl */ +" xorl %%eax, %%eax\n" +" lodsw\n" /* al = *(ushort *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $16, %%bl\n" /* bits += 16 */ +" shll %%cl, %%eax\n" +" orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */ +" movb %%ch, %%cl\n" /* move op back to ecx */ + +".L_add_bits_to_dist:\n" +" subb %%cl, %%bl\n" +" xorl %%eax, %%eax\n" +" incl %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" /* (1 << op) - 1 */ +" andl %%edx, %%eax\n" /* eax &= hold */ +" shrl %%cl, %%edx\n" +" addl %%eax, %%ebp\n" /* dist += hold & ((1 << op) - 1) */ + +".L_check_window:\n" +" movl %%esi, 8(%%esp)\n" /* save in so from can use it's reg */ +" movl %%edi, %%eax\n" +" subl 20(%%esp), %%eax\n" /* nbytes = out - beg */ + +" cmpl %%ebp, %%eax\n" +" jb .L_clip_window\n" /* if (dist > nbytes) 4.2% */ + +" movl 64(%%esp), %%ecx\n" /* ecx = len */ +" movl %%edi, %%esi\n" +" subl %%ebp, %%esi\n" /* from = out - dist */ + +" sarl %%ecx\n" +" jnc .L_copy_two\n" /* if len % 2 == 0 */ + +" rep movsw\n" +" movb (%%esi), %%al\n" +" movb %%al, (%%edi)\n" +" incl %%edi\n" + +" movl 8(%%esp), %%esi\n" /* move in back to %esi, toss from */ +" movl 32(%%esp), %%ebp\n" /* ebp = lcode */ +" jmp .L_while_test\n" + +".L_copy_two:\n" +" rep movsw\n" +" movl 8(%%esp), %%esi\n" /* move in back to %esi, toss from */ +" movl 32(%%esp), %%ebp\n" /* ebp = lcode */ +" jmp .L_while_test\n" + +".align 32,0x90\n" +".L_check_dist_one:\n" +" cmpl $1, %%ebp\n" /* if dist 1, is a memset */ +" jne .L_check_window\n" +" cmpl %%edi, 20(%%esp)\n" +" je .L_check_window\n" /* out == beg, if outside window */ + +" movl 64(%%esp), %%ecx\n" /* ecx = len */ +" movb -1(%%edi), %%al\n" +" movb %%al, %%ah\n" + +" sarl %%ecx\n" +" jnc .L_set_two\n" +" movb %%al, (%%edi)\n" +" incl %%edi\n" + +".L_set_two:\n" +" rep stosw\n" +" movl 32(%%esp), %%ebp\n" /* ebp = lcode */ +" jmp .L_while_test\n" + +".align 32,0x90\n" +".L_test_for_second_level_length:\n" +" testb $64, %%al\n" +" jnz .L_test_for_end_of_block\n" /* if ((op & 64) != 0) */ + +" xorl %%eax, %%eax\n" +" incl %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" +" andl %%edx, %%eax\n" /* eax &= hold */ +" addl 64(%%esp), %%eax\n" /* eax += len */ +" movl (%%ebp,%%eax,4), %%eax\n" /* eax = lcode[val+(hold&mask[op])]*/ +" jmp .L_dolen\n" + +".align 32,0x90\n" +".L_test_for_second_level_dist:\n" +" testb $64, %%al\n" +" jnz .L_invalid_distance_code\n" /* if ((op & 64) != 0) */ + +" xorl %%eax, %%eax\n" +" incl %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" +" andl %%edx, %%eax\n" /* eax &= hold */ +" addl %%ebp, %%eax\n" /* eax += dist */ +" movl 36(%%esp), %%ecx\n" /* ecx = dcode */ +" movl (%%ecx,%%eax,4), %%eax\n" /* eax = dcode[val+(hold&mask[op])]*/ +" jmp .L_dodist\n" + +".align 32,0x90\n" +".L_clip_window:\n" +" movl %%eax, %%ecx\n" +" movl 48(%%esp), %%eax\n" /* eax = wsize */ +" negl %%ecx\n" /* nbytes = -nbytes */ +" movl 28(%%esp), %%esi\n" /* from = window */ + +" cmpl %%ebp, %%eax\n" +" jb .L_invalid_distance_too_far\n" /* if (dist > wsize) */ + +" addl %%ebp, %%ecx\n" /* nbytes = dist - nbytes */ +" cmpl $0, 52(%%esp)\n" +" jne .L_wrap_around_window\n" /* if (write != 0) */ + +" subl %%ecx, %%eax\n" +" addl %%eax, %%esi\n" /* from += wsize - nbytes */ + +" movl 64(%%esp), %%eax\n" /* eax = len */ +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movl %%edi, %%esi\n" +" subl %%ebp, %%esi\n" /* from = out - dist */ +" jmp .L_do_copy\n" + +".align 32,0x90\n" +".L_wrap_around_window:\n" +" movl 52(%%esp), %%eax\n" /* eax = write */ +" cmpl %%eax, %%ecx\n" +" jbe .L_contiguous_in_window\n" /* if (write >= nbytes) */ + +" addl 48(%%esp), %%esi\n" /* from += wsize */ +" addl %%eax, %%esi\n" /* from += write */ +" subl %%ecx, %%esi\n" /* from -= nbytes */ +" subl %%eax, %%ecx\n" /* nbytes -= write */ + +" movl 64(%%esp), %%eax\n" /* eax = len */ +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movl 28(%%esp), %%esi\n" /* from = window */ +" movl 52(%%esp), %%ecx\n" /* nbytes = write */ +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movl %%edi, %%esi\n" +" subl %%ebp, %%esi\n" /* from = out - dist */ +" jmp .L_do_copy\n" + +".align 32,0x90\n" +".L_contiguous_in_window:\n" +" addl %%eax, %%esi\n" +" subl %%ecx, %%esi\n" /* from += write - nbytes */ + +" movl 64(%%esp), %%eax\n" /* eax = len */ +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movl %%edi, %%esi\n" +" subl %%ebp, %%esi\n" /* from = out - dist */ +" jmp .L_do_copy\n" /* if (nbytes >= len) */ + +".align 32,0x90\n" +".L_do_copy:\n" +" movl %%eax, %%ecx\n" +" rep movsb\n" + +" movl 8(%%esp), %%esi\n" /* move in back to %esi, toss from */ +" movl 32(%%esp), %%ebp\n" /* ebp = lcode */ +" jmp .L_while_test\n" + +".L_test_for_end_of_block:\n" +" testb $32, %%al\n" +" jz .L_invalid_literal_length_code\n" +" movl $1, 72(%%esp)\n" +" jmp .L_break_loop_with_status\n" + +".L_invalid_literal_length_code:\n" +" movl $2, 72(%%esp)\n" +" jmp .L_break_loop_with_status\n" + +".L_invalid_distance_code:\n" +" movl $3, 72(%%esp)\n" +" jmp .L_break_loop_with_status\n" + +".L_invalid_distance_too_far:\n" +" movl 8(%%esp), %%esi\n" +" movl $4, 72(%%esp)\n" +" jmp .L_break_loop_with_status\n" + +".L_break_loop:\n" +" movl $0, 72(%%esp)\n" + +".L_break_loop_with_status:\n" +/* put in, out, bits, and hold back into ar and pop esp */ +" movl %%esi, 8(%%esp)\n" /* save in */ +" movl %%edi, 16(%%esp)\n" /* save out */ +" movl %%ebx, 44(%%esp)\n" /* save bits */ +" movl %%edx, 40(%%esp)\n" /* save hold */ +" movl 4(%%esp), %%ebp\n" /* restore esp, ebp */ +" movl (%%esp), %%esp\n" + : + : "m" (ar) + : "memory", "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi" + ); +#elif defined( _MSC_VER ) && ! defined( _M_AMD64 ) + __asm { + lea eax, ar + mov [eax], esp /* save esp, ebp */ + mov [eax+4], ebp + mov esp, eax + mov esi, [esp+8] /* esi = in */ + mov edi, [esp+16] /* edi = out */ + mov edx, [esp+40] /* edx = hold */ + mov ebx, [esp+44] /* ebx = bits */ + mov ebp, [esp+32] /* ebp = lcode */ + + cld + jmp L_do_loop + +ALIGN 4 +L_while_test: + cmp [esp+24], edi + jbe L_break_loop + cmp [esp+12], esi + jbe L_break_loop + +L_do_loop: + cmp bl, 15 + ja L_get_length_code /* if (15 < bits) */ + + xor eax, eax + lodsw /* al = *(ushort *)in++ */ + mov cl, bl /* cl = bits, needs it for shifting */ + add bl, 16 /* bits += 16 */ + shl eax, cl + or edx, eax /* hold |= *((ushort *)in)++ << bits */ + +L_get_length_code: + mov eax, [esp+56] /* eax = lmask */ + and eax, edx /* eax &= hold */ + mov eax, [ebp+eax*4] /* eax = lcode[hold & lmask] */ + +L_dolen: + mov cl, ah /* cl = this.bits */ + sub bl, ah /* bits -= this.bits */ + shr edx, cl /* hold >>= this.bits */ + + test al, al + jnz L_test_for_length_base /* if (op != 0) 45.7% */ + + shr eax, 16 /* output this.val char */ + stosb + jmp L_while_test + +ALIGN 4 +L_test_for_length_base: + mov ecx, eax /* len = this */ + shr ecx, 16 /* len = this.val */ + mov [esp+64], ecx /* save len */ + mov cl, al + + test al, 16 + jz L_test_for_second_level_length /* if ((op & 16) == 0) 8% */ + and cl, 15 /* op &= 15 */ + jz L_decode_distance /* if (!op) */ + cmp bl, cl + jae L_add_bits_to_len /* if (op <= bits) */ + + mov ch, cl /* stash op in ch, freeing cl */ + xor eax, eax + lodsw /* al = *(ushort *)in++ */ + mov cl, bl /* cl = bits, needs it for shifting */ + add bl, 16 /* bits += 16 */ + shl eax, cl + or edx, eax /* hold |= *((ushort *)in)++ << bits */ + mov cl, ch /* move op back to ecx */ + +L_add_bits_to_len: + sub bl, cl + xor eax, eax + inc eax + shl eax, cl + dec eax + and eax, edx /* eax &= hold */ + shr edx, cl + add [esp+64], eax /* len += hold & mask[op] */ + +L_decode_distance: + cmp bl, 15 + ja L_get_distance_code /* if (15 < bits) */ + + xor eax, eax + lodsw /* al = *(ushort *)in++ */ + mov cl, bl /* cl = bits, needs it for shifting */ + add bl, 16 /* bits += 16 */ + shl eax, cl + or edx, eax /* hold |= *((ushort *)in)++ << bits */ + +L_get_distance_code: + mov eax, [esp+60] /* eax = dmask */ + mov ecx, [esp+36] /* ecx = dcode */ + and eax, edx /* eax &= hold */ + mov eax, [ecx+eax*4]/* eax = dcode[hold & dmask] */ + +L_dodist: + mov ebp, eax /* dist = this */ + shr ebp, 16 /* dist = this.val */ + mov cl, ah + sub bl, ah /* bits -= this.bits */ + shr edx, cl /* hold >>= this.bits */ + mov cl, al /* cl = this.op */ + + test al, 16 /* if ((op & 16) == 0) */ + jz L_test_for_second_level_dist + and cl, 15 /* op &= 15 */ + jz L_check_dist_one + cmp bl, cl + jae L_add_bits_to_dist /* if (op <= bits) 97.6% */ + + mov ch, cl /* stash op in ch, freeing cl */ + xor eax, eax + lodsw /* al = *(ushort *)in++ */ + mov cl, bl /* cl = bits, needs it for shifting */ + add bl, 16 /* bits += 16 */ + shl eax, cl + or edx, eax /* hold |= *((ushort *)in)++ << bits */ + mov cl, ch /* move op back to ecx */ + +L_add_bits_to_dist: + sub bl, cl + xor eax, eax + inc eax + shl eax, cl + dec eax /* (1 << op) - 1 */ + and eax, edx /* eax &= hold */ + shr edx, cl + add ebp, eax /* dist += hold & ((1 << op) - 1) */ + +L_check_window: + mov [esp+8], esi /* save in so from can use it's reg */ + mov eax, edi + sub eax, [esp+20] /* nbytes = out - beg */ + + cmp eax, ebp + jb L_clip_window /* if (dist > nbytes) 4.2% */ + + mov ecx, [esp+64] /* ecx = len */ + mov esi, edi + sub esi, ebp /* from = out - dist */ + + sar ecx, 1 + jnc L_copy_two + + rep movsw + mov al, [esi] + mov [edi], al + inc edi + + mov esi, [esp+8] /* move in back to %esi, toss from */ + mov ebp, [esp+32] /* ebp = lcode */ + jmp L_while_test + +L_copy_two: + rep movsw + mov esi, [esp+8] /* move in back to %esi, toss from */ + mov ebp, [esp+32] /* ebp = lcode */ + jmp L_while_test + +ALIGN 4 +L_check_dist_one: + cmp ebp, 1 /* if dist 1, is a memset */ + jne L_check_window + cmp [esp+20], edi + je L_check_window /* out == beg, if outside window */ + + mov ecx, [esp+64] /* ecx = len */ + mov al, [edi-1] + mov ah, al + + sar ecx, 1 + jnc L_set_two + mov [edi], al /* memset out with from[-1] */ + inc edi + +L_set_two: + rep stosw + mov ebp, [esp+32] /* ebp = lcode */ + jmp L_while_test + +ALIGN 4 +L_test_for_second_level_length: + test al, 64 + jnz L_test_for_end_of_block /* if ((op & 64) != 0) */ + + xor eax, eax + inc eax + shl eax, cl + dec eax + and eax, edx /* eax &= hold */ + add eax, [esp+64] /* eax += len */ + mov eax, [ebp+eax*4] /* eax = lcode[val+(hold&mask[op])]*/ + jmp L_dolen + +ALIGN 4 +L_test_for_second_level_dist: + test al, 64 + jnz L_invalid_distance_code /* if ((op & 64) != 0) */ + + xor eax, eax + inc eax + shl eax, cl + dec eax + and eax, edx /* eax &= hold */ + add eax, ebp /* eax += dist */ + mov ecx, [esp+36] /* ecx = dcode */ + mov eax, [ecx+eax*4] /* eax = dcode[val+(hold&mask[op])]*/ + jmp L_dodist + +ALIGN 4 +L_clip_window: + mov ecx, eax + mov eax, [esp+48] /* eax = wsize */ + neg ecx /* nbytes = -nbytes */ + mov esi, [esp+28] /* from = window */ + + cmp eax, ebp + jb L_invalid_distance_too_far /* if (dist > wsize) */ + + add ecx, ebp /* nbytes = dist - nbytes */ + cmp dword ptr [esp+52], 0 + jne L_wrap_around_window /* if (write != 0) */ + + sub eax, ecx + add esi, eax /* from += wsize - nbytes */ + + mov eax, [esp+64] /* eax = len */ + cmp eax, ecx + jbe L_do_copy /* if (nbytes >= len) */ + + sub eax, ecx /* len -= nbytes */ + rep movsb + mov esi, edi + sub esi, ebp /* from = out - dist */ + jmp L_do_copy + +ALIGN 4 +L_wrap_around_window: + mov eax, [esp+52] /* eax = write */ + cmp ecx, eax + jbe L_contiguous_in_window /* if (write >= nbytes) */ + + add esi, [esp+48] /* from += wsize */ + add esi, eax /* from += write */ + sub esi, ecx /* from -= nbytes */ + sub ecx, eax /* nbytes -= write */ + + mov eax, [esp+64] /* eax = len */ + cmp eax, ecx + jbe L_do_copy /* if (nbytes >= len) */ + + sub eax, ecx /* len -= nbytes */ + rep movsb + mov esi, [esp+28] /* from = window */ + mov ecx, [esp+52] /* nbytes = write */ + cmp eax, ecx + jbe L_do_copy /* if (nbytes >= len) */ + + sub eax, ecx /* len -= nbytes */ + rep movsb + mov esi, edi + sub esi, ebp /* from = out - dist */ + jmp L_do_copy + +ALIGN 4 +L_contiguous_in_window: + add esi, eax + sub esi, ecx /* from += write - nbytes */ + + mov eax, [esp+64] /* eax = len */ + cmp eax, ecx + jbe L_do_copy /* if (nbytes >= len) */ + + sub eax, ecx /* len -= nbytes */ + rep movsb + mov esi, edi + sub esi, ebp /* from = out - dist */ + jmp L_do_copy + +ALIGN 4 +L_do_copy: + mov ecx, eax + rep movsb + + mov esi, [esp+8] /* move in back to %esi, toss from */ + mov ebp, [esp+32] /* ebp = lcode */ + jmp L_while_test + +L_test_for_end_of_block: + test al, 32 + jz L_invalid_literal_length_code + mov dword ptr [esp+72], 1 + jmp L_break_loop_with_status + +L_invalid_literal_length_code: + mov dword ptr [esp+72], 2 + jmp L_break_loop_with_status + +L_invalid_distance_code: + mov dword ptr [esp+72], 3 + jmp L_break_loop_with_status + +L_invalid_distance_too_far: + mov esi, [esp+4] + mov dword ptr [esp+72], 4 + jmp L_break_loop_with_status + +L_break_loop: + mov dword ptr [esp+72], 0 + +L_break_loop_with_status: +/* put in, out, bits, and hold back into ar and pop esp */ + mov [esp+8], esi /* save in */ + mov [esp+16], edi /* save out */ + mov [esp+44], ebx /* save bits */ + mov [esp+40], edx /* save hold */ + mov ebp, [esp+4] /* restore esp, ebp */ + mov esp, [esp] + } +#else +#error "x86 architecture not defined" +#endif + + if (ar.status > 1) { + if (ar.status == 2) + strm->msg = "invalid literal/length code"; + else if (ar.status == 3) + strm->msg = "invalid distance code"; + else + strm->msg = "invalid distance too far back"; + state->mode = BAD; + } + else if ( ar.status == 1 ) { + state->mode = TYPE; + } + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + ar.len = ar.bits >> 3; + ar.in -= ar.len; + ar.bits -= ar.len << 3; + ar.hold &= (1U << ar.bits) - 1; + + /* update state and return */ + strm->next_in = ar.in; + strm->next_out = ar.out; + strm->avail_in = (unsigned)(ar.in < ar.last ? + PAD_AVAIL_IN + (ar.last - ar.in) : + PAD_AVAIL_IN - (ar.in - ar.last)); + strm->avail_out = (unsigned)(ar.out < ar.end ? + PAD_AVAIL_OUT + (ar.end - ar.out) : + PAD_AVAIL_OUT - (ar.out - ar.end)); + state->hold = ar.hold; + state->bits = ar.bits; + return; +} + diff --git a/contrib/zlib/contrib/inflate86/inffast.S b/contrib/zlib/contrib/inflate86/inffast.S new file mode 100644 index 00000000..2245a290 --- /dev/null +++ b/contrib/zlib/contrib/inflate86/inffast.S @@ -0,0 +1,1368 @@ +/* + * inffast.S is a hand tuned assembler version of: + * + * inffast.c -- fast decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Copyright (C) 2003 Chris Anderson + * Please use the copyright conditions above. + * + * This version (Jan-23-2003) of inflate_fast was coded and tested under + * GNU/Linux on a pentium 3, using the gcc-3.2 compiler distribution. On that + * machine, I found that gzip style archives decompressed about 20% faster than + * the gcc-3.2 -O3 -fomit-frame-pointer compiled version. Your results will + * depend on how large of a buffer is used for z_stream.next_in & next_out + * (8K-32K worked best for my 256K cpu cache) and how much overhead there is in + * stream processing I/O and crc32/addler32. In my case, this routine used + * 70% of the cpu time and crc32 used 20%. + * + * I am confident that this version will work in the general case, but I have + * not tested a wide variety of datasets or a wide variety of platforms. + * + * Jan-24-2003 -- Added -DUSE_MMX define for slightly faster inflating. + * It should be a runtime flag instead of compile time flag... + * + * Jan-26-2003 -- Added runtime check for MMX support with cpuid instruction. + * With -DUSE_MMX, only MMX code is compiled. With -DNO_MMX, only non-MMX code + * is compiled. Without either option, runtime detection is enabled. Runtime + * detection should work on all modern cpus and the recomended algorithm (flip + * ID bit on eflags and then use the cpuid instruction) is used in many + * multimedia applications. Tested under win2k with gcc-2.95 and gas-2.12 + * distributed with cygwin3. Compiling with gcc-2.95 -c inffast.S -o + * inffast.obj generates a COFF object which can then be linked with MSVC++ + * compiled code. Tested under FreeBSD 4.7 with gcc-2.95. + * + * Jan-28-2003 -- Tested Athlon XP... MMX mode is slower than no MMX (and + * slower than compiler generated code). Adjusted cpuid check to use the MMX + * code only for Pentiums < P4 until I have more data on the P4. Speed + * improvment is only about 15% on the Athlon when compared with code generated + * with MSVC++. Not sure yet, but I think the P4 will also be slower using the + * MMX mode because many of it's x86 ALU instructions execute in .5 cycles and + * have less latency than MMX ops. Added code to buffer the last 11 bytes of + * the input stream since the MMX code grabs bits in chunks of 32, which + * differs from the inffast.c algorithm. I don't think there would have been + * read overruns where a page boundary was crossed (a segfault), but there + * could have been overruns when next_in ends on unaligned memory (unintialized + * memory read). + * + * Mar-13-2003 -- P4 MMX is slightly slower than P4 NO_MMX. I created a C + * version of the non-MMX code so that it doesn't depend on zstrm and zstate + * structure offsets which are hard coded in this file. This was last tested + * with zlib-1.2.0 which is currently in beta testing, newer versions of this + * and inffas86.c can be found at http://www.eetbeetee.com/zlib/ and + * http://www.charm.net/~christop/zlib/ + */ + + +/* + * if you have underscore linking problems (_inflate_fast undefined), try + * using -DGAS_COFF + */ +#if ! defined( GAS_COFF ) && ! defined( GAS_ELF ) + +#if defined( WIN32 ) || defined( __CYGWIN__ ) +#define GAS_COFF /* windows object format */ +#else +#define GAS_ELF +#endif + +#endif /* ! GAS_COFF && ! GAS_ELF */ + + +#if defined( GAS_COFF ) + +/* coff externals have underscores */ +#define inflate_fast _inflate_fast +#define inflate_fast_use_mmx _inflate_fast_use_mmx + +#endif /* GAS_COFF */ + + +.file "inffast.S" + +.globl inflate_fast + +.text +.align 4,0 +.L_invalid_literal_length_code_msg: +.string "invalid literal/length code" + +.align 4,0 +.L_invalid_distance_code_msg: +.string "invalid distance code" + +.align 4,0 +.L_invalid_distance_too_far_msg: +.string "invalid distance too far back" + +#if ! defined( NO_MMX ) +.align 4,0 +.L_mask: /* mask[N] = ( 1 << N ) - 1 */ +.long 0 +.long 1 +.long 3 +.long 7 +.long 15 +.long 31 +.long 63 +.long 127 +.long 255 +.long 511 +.long 1023 +.long 2047 +.long 4095 +.long 8191 +.long 16383 +.long 32767 +.long 65535 +.long 131071 +.long 262143 +.long 524287 +.long 1048575 +.long 2097151 +.long 4194303 +.long 8388607 +.long 16777215 +.long 33554431 +.long 67108863 +.long 134217727 +.long 268435455 +.long 536870911 +.long 1073741823 +.long 2147483647 +.long 4294967295 +#endif /* NO_MMX */ + +.text + +/* + * struct z_stream offsets, in zlib.h + */ +#define next_in_strm 0 /* strm->next_in */ +#define avail_in_strm 4 /* strm->avail_in */ +#define next_out_strm 12 /* strm->next_out */ +#define avail_out_strm 16 /* strm->avail_out */ +#define msg_strm 24 /* strm->msg */ +#define state_strm 28 /* strm->state */ + +/* + * struct inflate_state offsets, in inflate.h + */ +#define mode_state 0 /* state->mode */ +#define wsize_state 32 /* state->wsize */ +#define write_state 40 /* state->write */ +#define window_state 44 /* state->window */ +#define hold_state 48 /* state->hold */ +#define bits_state 52 /* state->bits */ +#define lencode_state 68 /* state->lencode */ +#define distcode_state 72 /* state->distcode */ +#define lenbits_state 76 /* state->lenbits */ +#define distbits_state 80 /* state->distbits */ + +/* + * inflate_fast's activation record + */ +#define local_var_size 64 /* how much local space for vars */ +#define strm_sp 88 /* first arg: z_stream * (local_var_size + 24) */ +#define start_sp 92 /* second arg: unsigned int (local_var_size + 28) */ + +/* + * offsets for local vars on stack + */ +#define out 60 /* unsigned char* */ +#define window 56 /* unsigned char* */ +#define wsize 52 /* unsigned int */ +#define write 48 /* unsigned int */ +#define in 44 /* unsigned char* */ +#define beg 40 /* unsigned char* */ +#define buf 28 /* char[ 12 ] */ +#define len 24 /* unsigned int */ +#define last 20 /* unsigned char* */ +#define end 16 /* unsigned char* */ +#define dcode 12 /* code* */ +#define lcode 8 /* code* */ +#define dmask 4 /* unsigned int */ +#define lmask 0 /* unsigned int */ + +/* + * typedef enum inflate_mode consts, in inflate.h + */ +#define INFLATE_MODE_TYPE 11 /* state->mode flags enum-ed in inflate.h */ +#define INFLATE_MODE_BAD 26 + + +#if ! defined( USE_MMX ) && ! defined( NO_MMX ) + +#define RUN_TIME_MMX + +#define CHECK_MMX 1 +#define DO_USE_MMX 2 +#define DONT_USE_MMX 3 + +.globl inflate_fast_use_mmx + +.data + +.align 4,0 +inflate_fast_use_mmx: /* integer flag for run time control 1=check,2=mmx,3=no */ +.long CHECK_MMX + +#if defined( GAS_ELF ) +/* elf info */ +.type inflate_fast_use_mmx,@object +.size inflate_fast_use_mmx,4 +#endif + +#endif /* RUN_TIME_MMX */ + +#if defined( GAS_COFF ) +/* coff info: scl 2 = extern, type 32 = function */ +.def inflate_fast; .scl 2; .type 32; .endef +#endif + +.text + +.align 32,0x90 +inflate_fast: + pushl %edi + pushl %esi + pushl %ebp + pushl %ebx + pushf /* save eflags (strm_sp, state_sp assumes this is 32 bits) */ + subl $local_var_size, %esp + cld + +#define strm_r %esi +#define state_r %edi + + movl strm_sp(%esp), strm_r + movl state_strm(strm_r), state_r + + /* in = strm->next_in; + * out = strm->next_out; + * last = in + strm->avail_in - 11; + * beg = out - (start - strm->avail_out); + * end = out + (strm->avail_out - 257); + */ + movl avail_in_strm(strm_r), %edx + movl next_in_strm(strm_r), %eax + + addl %eax, %edx /* avail_in += next_in */ + subl $11, %edx /* avail_in -= 11 */ + + movl %eax, in(%esp) + movl %edx, last(%esp) + + movl start_sp(%esp), %ebp + movl avail_out_strm(strm_r), %ecx + movl next_out_strm(strm_r), %ebx + + subl %ecx, %ebp /* start -= avail_out */ + negl %ebp /* start = -start */ + addl %ebx, %ebp /* start += next_out */ + + subl $257, %ecx /* avail_out -= 257 */ + addl %ebx, %ecx /* avail_out += out */ + + movl %ebx, out(%esp) + movl %ebp, beg(%esp) + movl %ecx, end(%esp) + + /* wsize = state->wsize; + * write = state->write; + * window = state->window; + * hold = state->hold; + * bits = state->bits; + * lcode = state->lencode; + * dcode = state->distcode; + * lmask = ( 1 << state->lenbits ) - 1; + * dmask = ( 1 << state->distbits ) - 1; + */ + + movl lencode_state(state_r), %eax + movl distcode_state(state_r), %ecx + + movl %eax, lcode(%esp) + movl %ecx, dcode(%esp) + + movl $1, %eax + movl lenbits_state(state_r), %ecx + shll %cl, %eax + decl %eax + movl %eax, lmask(%esp) + + movl $1, %eax + movl distbits_state(state_r), %ecx + shll %cl, %eax + decl %eax + movl %eax, dmask(%esp) + + movl wsize_state(state_r), %eax + movl write_state(state_r), %ecx + movl window_state(state_r), %edx + + movl %eax, wsize(%esp) + movl %ecx, write(%esp) + movl %edx, window(%esp) + + movl hold_state(state_r), %ebp + movl bits_state(state_r), %ebx + +#undef strm_r +#undef state_r + +#define in_r %esi +#define from_r %esi +#define out_r %edi + + movl in(%esp), in_r + movl last(%esp), %ecx + cmpl in_r, %ecx + ja .L_align_long /* if in < last */ + + addl $11, %ecx /* ecx = &in[ avail_in ] */ + subl in_r, %ecx /* ecx = avail_in */ + movl $12, %eax + subl %ecx, %eax /* eax = 12 - avail_in */ + leal buf(%esp), %edi + rep movsb /* memcpy( buf, in, avail_in ) */ + movl %eax, %ecx + xorl %eax, %eax + rep stosb /* memset( &buf[ avail_in ], 0, 12 - avail_in ) */ + leal buf(%esp), in_r /* in = buf */ + movl in_r, last(%esp) /* last = in, do just one iteration */ + jmp .L_is_aligned + + /* align in_r on long boundary */ +.L_align_long: + testl $3, in_r + jz .L_is_aligned + xorl %eax, %eax + movb (in_r), %al + incl in_r + movl %ebx, %ecx + addl $8, %ebx + shll %cl, %eax + orl %eax, %ebp + jmp .L_align_long + +.L_is_aligned: + movl out(%esp), out_r + +#if defined( NO_MMX ) + jmp .L_do_loop +#endif + +#if defined( USE_MMX ) + jmp .L_init_mmx +#endif + +/*** Runtime MMX check ***/ + +#if defined( RUN_TIME_MMX ) +.L_check_mmx: + cmpl $DO_USE_MMX, inflate_fast_use_mmx + je .L_init_mmx + ja .L_do_loop /* > 2 */ + + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + pushf + movl (%esp), %eax /* copy eflags to eax */ + xorl $0x200000, (%esp) /* try toggling ID bit of eflags (bit 21) + * to see if cpu supports cpuid... + * ID bit method not supported by NexGen but + * bios may load a cpuid instruction and + * cpuid may be disabled on Cyrix 5-6x86 */ + popf + pushf + popl %edx /* copy new eflags to edx */ + xorl %eax, %edx /* test if ID bit is flipped */ + jz .L_dont_use_mmx /* not flipped if zero */ + xorl %eax, %eax + cpuid + cmpl $0x756e6547, %ebx /* check for GenuineIntel in ebx,ecx,edx */ + jne .L_dont_use_mmx + cmpl $0x6c65746e, %ecx + jne .L_dont_use_mmx + cmpl $0x49656e69, %edx + jne .L_dont_use_mmx + movl $1, %eax + cpuid /* get cpu features */ + shrl $8, %eax + andl $15, %eax + cmpl $6, %eax /* check for Pentium family, is 0xf for P4 */ + jne .L_dont_use_mmx + testl $0x800000, %edx /* test if MMX feature is set (bit 23) */ + jnz .L_use_mmx + jmp .L_dont_use_mmx +.L_use_mmx: + movl $DO_USE_MMX, inflate_fast_use_mmx + jmp .L_check_mmx_pop +.L_dont_use_mmx: + movl $DONT_USE_MMX, inflate_fast_use_mmx +.L_check_mmx_pop: + popl %edx + popl %ecx + popl %ebx + popl %eax + jmp .L_check_mmx +#endif + + +/*** Non-MMX code ***/ + +#if defined ( NO_MMX ) || defined( RUN_TIME_MMX ) + +#define hold_r %ebp +#define bits_r %bl +#define bitslong_r %ebx + +.align 32,0x90 +.L_while_test: + /* while (in < last && out < end) + */ + cmpl out_r, end(%esp) + jbe .L_break_loop /* if (out >= end) */ + + cmpl in_r, last(%esp) + jbe .L_break_loop + +.L_do_loop: + /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out + * + * do { + * if (bits < 15) { + * hold |= *((unsigned short *)in)++ << bits; + * bits += 16 + * } + * this = lcode[hold & lmask] + */ + cmpb $15, bits_r + ja .L_get_length_code /* if (15 < bits) */ + + xorl %eax, %eax + lodsw /* al = *(ushort *)in++ */ + movb bits_r, %cl /* cl = bits, needs it for shifting */ + addb $16, bits_r /* bits += 16 */ + shll %cl, %eax + orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */ + +.L_get_length_code: + movl lmask(%esp), %edx /* edx = lmask */ + movl lcode(%esp), %ecx /* ecx = lcode */ + andl hold_r, %edx /* edx &= hold */ + movl (%ecx,%edx,4), %eax /* eax = lcode[hold & lmask] */ + +.L_dolen: + /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out + * + * dolen: + * bits -= this.bits; + * hold >>= this.bits + */ + movb %ah, %cl /* cl = this.bits */ + subb %ah, bits_r /* bits -= this.bits */ + shrl %cl, hold_r /* hold >>= this.bits */ + + /* check if op is a literal + * if (op == 0) { + * PUP(out) = this.val; + * } + */ + testb %al, %al + jnz .L_test_for_length_base /* if (op != 0) 45.7% */ + + shrl $16, %eax /* output this.val char */ + stosb + jmp .L_while_test + +.L_test_for_length_base: + /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out, %edx = len + * + * else if (op & 16) { + * len = this.val + * op &= 15 + * if (op) { + * if (op > bits) { + * hold |= *((unsigned short *)in)++ << bits; + * bits += 16 + * } + * len += hold & mask[op]; + * bits -= op; + * hold >>= op; + * } + */ +#define len_r %edx + movl %eax, len_r /* len = this */ + shrl $16, len_r /* len = this.val */ + movb %al, %cl + + testb $16, %al + jz .L_test_for_second_level_length /* if ((op & 16) == 0) 8% */ + andb $15, %cl /* op &= 15 */ + jz .L_save_len /* if (!op) */ + cmpb %cl, bits_r + jae .L_add_bits_to_len /* if (op <= bits) */ + + movb %cl, %ch /* stash op in ch, freeing cl */ + xorl %eax, %eax + lodsw /* al = *(ushort *)in++ */ + movb bits_r, %cl /* cl = bits, needs it for shifting */ + addb $16, bits_r /* bits += 16 */ + shll %cl, %eax + orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */ + movb %ch, %cl /* move op back to ecx */ + +.L_add_bits_to_len: + movl $1, %eax + shll %cl, %eax + decl %eax + subb %cl, bits_r + andl hold_r, %eax /* eax &= hold */ + shrl %cl, hold_r + addl %eax, len_r /* len += hold & mask[op] */ + +.L_save_len: + movl len_r, len(%esp) /* save len */ +#undef len_r + +.L_decode_distance: + /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out, %edx = dist + * + * if (bits < 15) { + * hold |= *((unsigned short *)in)++ << bits; + * bits += 16 + * } + * this = dcode[hold & dmask]; + * dodist: + * bits -= this.bits; + * hold >>= this.bits; + * op = this.op; + */ + + cmpb $15, bits_r + ja .L_get_distance_code /* if (15 < bits) */ + + xorl %eax, %eax + lodsw /* al = *(ushort *)in++ */ + movb bits_r, %cl /* cl = bits, needs it for shifting */ + addb $16, bits_r /* bits += 16 */ + shll %cl, %eax + orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */ + +.L_get_distance_code: + movl dmask(%esp), %edx /* edx = dmask */ + movl dcode(%esp), %ecx /* ecx = dcode */ + andl hold_r, %edx /* edx &= hold */ + movl (%ecx,%edx,4), %eax /* eax = dcode[hold & dmask] */ + +#define dist_r %edx +.L_dodist: + movl %eax, dist_r /* dist = this */ + shrl $16, dist_r /* dist = this.val */ + movb %ah, %cl + subb %ah, bits_r /* bits -= this.bits */ + shrl %cl, hold_r /* hold >>= this.bits */ + + /* if (op & 16) { + * dist = this.val + * op &= 15 + * if (op > bits) { + * hold |= *((unsigned short *)in)++ << bits; + * bits += 16 + * } + * dist += hold & mask[op]; + * bits -= op; + * hold >>= op; + */ + movb %al, %cl /* cl = this.op */ + + testb $16, %al /* if ((op & 16) == 0) */ + jz .L_test_for_second_level_dist + andb $15, %cl /* op &= 15 */ + jz .L_check_dist_one + cmpb %cl, bits_r + jae .L_add_bits_to_dist /* if (op <= bits) 97.6% */ + + movb %cl, %ch /* stash op in ch, freeing cl */ + xorl %eax, %eax + lodsw /* al = *(ushort *)in++ */ + movb bits_r, %cl /* cl = bits, needs it for shifting */ + addb $16, bits_r /* bits += 16 */ + shll %cl, %eax + orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */ + movb %ch, %cl /* move op back to ecx */ + +.L_add_bits_to_dist: + movl $1, %eax + shll %cl, %eax + decl %eax /* (1 << op) - 1 */ + subb %cl, bits_r + andl hold_r, %eax /* eax &= hold */ + shrl %cl, hold_r + addl %eax, dist_r /* dist += hold & ((1 << op) - 1) */ + jmp .L_check_window + +.L_check_window: + /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist + * %ecx = nbytes + * + * nbytes = out - beg; + * if (dist <= nbytes) { + * from = out - dist; + * do { + * PUP(out) = PUP(from); + * } while (--len > 0) { + * } + */ + + movl in_r, in(%esp) /* save in so from can use it's reg */ + movl out_r, %eax + subl beg(%esp), %eax /* nbytes = out - beg */ + + cmpl dist_r, %eax + jb .L_clip_window /* if (dist > nbytes) 4.2% */ + + movl len(%esp), %ecx + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + + subl $3, %ecx + movb (from_r), %al + movb %al, (out_r) + movb 1(from_r), %al + movb 2(from_r), %dl + addl $3, from_r + movb %al, 1(out_r) + movb %dl, 2(out_r) + addl $3, out_r + rep movsb + + movl in(%esp), in_r /* move in back to %esi, toss from */ + jmp .L_while_test + +.align 16,0x90 +.L_check_dist_one: + cmpl $1, dist_r + jne .L_check_window + cmpl out_r, beg(%esp) + je .L_check_window + + decl out_r + movl len(%esp), %ecx + movb (out_r), %al + subl $3, %ecx + + movb %al, 1(out_r) + movb %al, 2(out_r) + movb %al, 3(out_r) + addl $4, out_r + rep stosb + + jmp .L_while_test + +.align 16,0x90 +.L_test_for_second_level_length: + /* else if ((op & 64) == 0) { + * this = lcode[this.val + (hold & mask[op])]; + * } + */ + testb $64, %al + jnz .L_test_for_end_of_block /* if ((op & 64) != 0) */ + + movl $1, %eax + shll %cl, %eax + decl %eax + andl hold_r, %eax /* eax &= hold */ + addl %edx, %eax /* eax += this.val */ + movl lcode(%esp), %edx /* edx = lcode */ + movl (%edx,%eax,4), %eax /* eax = lcode[val + (hold&mask[op])] */ + jmp .L_dolen + +.align 16,0x90 +.L_test_for_second_level_dist: + /* else if ((op & 64) == 0) { + * this = dcode[this.val + (hold & mask[op])]; + * } + */ + testb $64, %al + jnz .L_invalid_distance_code /* if ((op & 64) != 0) */ + + movl $1, %eax + shll %cl, %eax + decl %eax + andl hold_r, %eax /* eax &= hold */ + addl %edx, %eax /* eax += this.val */ + movl dcode(%esp), %edx /* edx = dcode */ + movl (%edx,%eax,4), %eax /* eax = dcode[val + (hold&mask[op])] */ + jmp .L_dodist + +.align 16,0x90 +.L_clip_window: + /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist + * %ecx = nbytes + * + * else { + * if (dist > wsize) { + * invalid distance + * } + * from = window; + * nbytes = dist - nbytes; + * if (write == 0) { + * from += wsize - nbytes; + */ +#define nbytes_r %ecx + movl %eax, nbytes_r + movl wsize(%esp), %eax /* prepare for dist compare */ + negl nbytes_r /* nbytes = -nbytes */ + movl window(%esp), from_r /* from = window */ + + cmpl dist_r, %eax + jb .L_invalid_distance_too_far /* if (dist > wsize) */ + + addl dist_r, nbytes_r /* nbytes = dist - nbytes */ + cmpl $0, write(%esp) + jne .L_wrap_around_window /* if (write != 0) */ + + subl nbytes_r, %eax + addl %eax, from_r /* from += wsize - nbytes */ + + /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist + * %ecx = nbytes, %eax = len + * + * if (nbytes < len) { + * len -= nbytes; + * do { + * PUP(out) = PUP(from); + * } while (--nbytes); + * from = out - dist; + * } + * } + */ +#define len_r %eax + movl len(%esp), len_r + cmpl nbytes_r, len_r + jbe .L_do_copy1 /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + jmp .L_do_copy1 + + cmpl nbytes_r, len_r + jbe .L_do_copy1 /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + jmp .L_do_copy1 + +.L_wrap_around_window: + /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist + * %ecx = nbytes, %eax = write, %eax = len + * + * else if (write < nbytes) { + * from += wsize + write - nbytes; + * nbytes -= write; + * if (nbytes < len) { + * len -= nbytes; + * do { + * PUP(out) = PUP(from); + * } while (--nbytes); + * from = window; + * nbytes = write; + * if (nbytes < len) { + * len -= nbytes; + * do { + * PUP(out) = PUP(from); + * } while(--nbytes); + * from = out - dist; + * } + * } + * } + */ +#define write_r %eax + movl write(%esp), write_r + cmpl write_r, nbytes_r + jbe .L_contiguous_in_window /* if (write >= nbytes) */ + + addl wsize(%esp), from_r + addl write_r, from_r + subl nbytes_r, from_r /* from += wsize + write - nbytes */ + subl write_r, nbytes_r /* nbytes -= write */ +#undef write_r + + movl len(%esp), len_r + cmpl nbytes_r, len_r + jbe .L_do_copy1 /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl window(%esp), from_r /* from = window */ + movl write(%esp), nbytes_r /* nbytes = write */ + cmpl nbytes_r, len_r + jbe .L_do_copy1 /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + jmp .L_do_copy1 + +.L_contiguous_in_window: + /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist + * %ecx = nbytes, %eax = write, %eax = len + * + * else { + * from += write - nbytes; + * if (nbytes < len) { + * len -= nbytes; + * do { + * PUP(out) = PUP(from); + * } while (--nbytes); + * from = out - dist; + * } + * } + */ +#define write_r %eax + addl write_r, from_r + subl nbytes_r, from_r /* from += write - nbytes */ +#undef write_r + + movl len(%esp), len_r + cmpl nbytes_r, len_r + jbe .L_do_copy1 /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + +.L_do_copy1: + /* regs: %esi = from, %esi = in, %ebp = hold, %bl = bits, %edi = out + * %eax = len + * + * while (len > 0) { + * PUP(out) = PUP(from); + * len--; + * } + * } + * } while (in < last && out < end); + */ +#undef nbytes_r +#define in_r %esi + movl len_r, %ecx + rep movsb + + movl in(%esp), in_r /* move in back to %esi, toss from */ + jmp .L_while_test + +#undef len_r +#undef dist_r + +#endif /* NO_MMX || RUN_TIME_MMX */ + + +/*** MMX code ***/ + +#if defined( USE_MMX ) || defined( RUN_TIME_MMX ) + +.align 32,0x90 +.L_init_mmx: + emms + +#undef bits_r +#undef bitslong_r +#define bitslong_r %ebp +#define hold_mm %mm0 + movd %ebp, hold_mm + movl %ebx, bitslong_r + +#define used_mm %mm1 +#define dmask2_mm %mm2 +#define lmask2_mm %mm3 +#define lmask_mm %mm4 +#define dmask_mm %mm5 +#define tmp_mm %mm6 + + movd lmask(%esp), lmask_mm + movq lmask_mm, lmask2_mm + movd dmask(%esp), dmask_mm + movq dmask_mm, dmask2_mm + pxor used_mm, used_mm + movl lcode(%esp), %ebx /* ebx = lcode */ + jmp .L_do_loop_mmx + +.align 32,0x90 +.L_while_test_mmx: + /* while (in < last && out < end) + */ + cmpl out_r, end(%esp) + jbe .L_break_loop /* if (out >= end) */ + + cmpl in_r, last(%esp) + jbe .L_break_loop + +.L_do_loop_mmx: + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + + cmpl $32, bitslong_r + ja .L_get_length_code_mmx /* if (32 < bits) */ + + movd bitslong_r, tmp_mm + movd (in_r), %mm7 + addl $4, in_r + psllq tmp_mm, %mm7 + addl $32, bitslong_r + por %mm7, hold_mm /* hold_mm |= *((uint *)in)++ << bits */ + +.L_get_length_code_mmx: + pand hold_mm, lmask_mm + movd lmask_mm, %eax + movq lmask2_mm, lmask_mm + movl (%ebx,%eax,4), %eax /* eax = lcode[hold & lmask] */ + +.L_dolen_mmx: + movzbl %ah, %ecx /* ecx = this.bits */ + movd %ecx, used_mm + subl %ecx, bitslong_r /* bits -= this.bits */ + + testb %al, %al + jnz .L_test_for_length_base_mmx /* if (op != 0) 45.7% */ + + shrl $16, %eax /* output this.val char */ + stosb + jmp .L_while_test_mmx + +.L_test_for_length_base_mmx: +#define len_r %edx + movl %eax, len_r /* len = this */ + shrl $16, len_r /* len = this.val */ + + testb $16, %al + jz .L_test_for_second_level_length_mmx /* if ((op & 16) == 0) 8% */ + andl $15, %eax /* op &= 15 */ + jz .L_decode_distance_mmx /* if (!op) */ + + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + movd %eax, used_mm + movd hold_mm, %ecx + subl %eax, bitslong_r + andl .L_mask(,%eax,4), %ecx + addl %ecx, len_r /* len += hold & mask[op] */ + +.L_decode_distance_mmx: + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + + cmpl $32, bitslong_r + ja .L_get_dist_code_mmx /* if (32 < bits) */ + + movd bitslong_r, tmp_mm + movd (in_r), %mm7 + addl $4, in_r + psllq tmp_mm, %mm7 + addl $32, bitslong_r + por %mm7, hold_mm /* hold_mm |= *((uint *)in)++ << bits */ + +.L_get_dist_code_mmx: + movl dcode(%esp), %ebx /* ebx = dcode */ + pand hold_mm, dmask_mm + movd dmask_mm, %eax + movq dmask2_mm, dmask_mm + movl (%ebx,%eax,4), %eax /* eax = dcode[hold & lmask] */ + +.L_dodist_mmx: +#define dist_r %ebx + movzbl %ah, %ecx /* ecx = this.bits */ + movl %eax, dist_r + shrl $16, dist_r /* dist = this.val */ + subl %ecx, bitslong_r /* bits -= this.bits */ + movd %ecx, used_mm + + testb $16, %al /* if ((op & 16) == 0) */ + jz .L_test_for_second_level_dist_mmx + andl $15, %eax /* op &= 15 */ + jz .L_check_dist_one_mmx + +.L_add_bits_to_dist_mmx: + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + movd %eax, used_mm /* save bit length of current op */ + movd hold_mm, %ecx /* get the next bits on input stream */ + subl %eax, bitslong_r /* bits -= op bits */ + andl .L_mask(,%eax,4), %ecx /* ecx = hold & mask[op] */ + addl %ecx, dist_r /* dist += hold & mask[op] */ + +.L_check_window_mmx: + movl in_r, in(%esp) /* save in so from can use it's reg */ + movl out_r, %eax + subl beg(%esp), %eax /* nbytes = out - beg */ + + cmpl dist_r, %eax + jb .L_clip_window_mmx /* if (dist > nbytes) 4.2% */ + + movl len_r, %ecx + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + + subl $3, %ecx + movb (from_r), %al + movb %al, (out_r) + movb 1(from_r), %al + movb 2(from_r), %dl + addl $3, from_r + movb %al, 1(out_r) + movb %dl, 2(out_r) + addl $3, out_r + rep movsb + + movl in(%esp), in_r /* move in back to %esi, toss from */ + movl lcode(%esp), %ebx /* move lcode back to %ebx, toss dist */ + jmp .L_while_test_mmx + +.align 16,0x90 +.L_check_dist_one_mmx: + cmpl $1, dist_r + jne .L_check_window_mmx + cmpl out_r, beg(%esp) + je .L_check_window_mmx + + decl out_r + movl len_r, %ecx + movb (out_r), %al + subl $3, %ecx + + movb %al, 1(out_r) + movb %al, 2(out_r) + movb %al, 3(out_r) + addl $4, out_r + rep stosb + + movl lcode(%esp), %ebx /* move lcode back to %ebx, toss dist */ + jmp .L_while_test_mmx + +.align 16,0x90 +.L_test_for_second_level_length_mmx: + testb $64, %al + jnz .L_test_for_end_of_block /* if ((op & 64) != 0) */ + + andl $15, %eax + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + movd hold_mm, %ecx + andl .L_mask(,%eax,4), %ecx + addl len_r, %ecx + movl (%ebx,%ecx,4), %eax /* eax = lcode[hold & lmask] */ + jmp .L_dolen_mmx + +.align 16,0x90 +.L_test_for_second_level_dist_mmx: + testb $64, %al + jnz .L_invalid_distance_code /* if ((op & 64) != 0) */ + + andl $15, %eax + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + movd hold_mm, %ecx + andl .L_mask(,%eax,4), %ecx + movl dcode(%esp), %eax /* ecx = dcode */ + addl dist_r, %ecx + movl (%eax,%ecx,4), %eax /* eax = lcode[hold & lmask] */ + jmp .L_dodist_mmx + +.align 16,0x90 +.L_clip_window_mmx: +#define nbytes_r %ecx + movl %eax, nbytes_r + movl wsize(%esp), %eax /* prepare for dist compare */ + negl nbytes_r /* nbytes = -nbytes */ + movl window(%esp), from_r /* from = window */ + + cmpl dist_r, %eax + jb .L_invalid_distance_too_far /* if (dist > wsize) */ + + addl dist_r, nbytes_r /* nbytes = dist - nbytes */ + cmpl $0, write(%esp) + jne .L_wrap_around_window_mmx /* if (write != 0) */ + + subl nbytes_r, %eax + addl %eax, from_r /* from += wsize - nbytes */ + + cmpl nbytes_r, len_r + jbe .L_do_copy1_mmx /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + jmp .L_do_copy1_mmx + + cmpl nbytes_r, len_r + jbe .L_do_copy1_mmx /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + jmp .L_do_copy1_mmx + +.L_wrap_around_window_mmx: +#define write_r %eax + movl write(%esp), write_r + cmpl write_r, nbytes_r + jbe .L_contiguous_in_window_mmx /* if (write >= nbytes) */ + + addl wsize(%esp), from_r + addl write_r, from_r + subl nbytes_r, from_r /* from += wsize + write - nbytes */ + subl write_r, nbytes_r /* nbytes -= write */ +#undef write_r + + cmpl nbytes_r, len_r + jbe .L_do_copy1_mmx /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl window(%esp), from_r /* from = window */ + movl write(%esp), nbytes_r /* nbytes = write */ + cmpl nbytes_r, len_r + jbe .L_do_copy1_mmx /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + jmp .L_do_copy1_mmx + +.L_contiguous_in_window_mmx: +#define write_r %eax + addl write_r, from_r + subl nbytes_r, from_r /* from += write - nbytes */ +#undef write_r + + cmpl nbytes_r, len_r + jbe .L_do_copy1_mmx /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + +.L_do_copy1_mmx: +#undef nbytes_r +#define in_r %esi + movl len_r, %ecx + rep movsb + + movl in(%esp), in_r /* move in back to %esi, toss from */ + movl lcode(%esp), %ebx /* move lcode back to %ebx, toss dist */ + jmp .L_while_test_mmx + +#undef hold_r +#undef bitslong_r + +#endif /* USE_MMX || RUN_TIME_MMX */ + + +/*** USE_MMX, NO_MMX, and RUNTIME_MMX from here on ***/ + +.L_invalid_distance_code: + /* else { + * strm->msg = "invalid distance code"; + * state->mode = BAD; + * } + */ + movl $.L_invalid_distance_code_msg, %ecx + movl $INFLATE_MODE_BAD, %edx + jmp .L_update_stream_state + +.L_test_for_end_of_block: + /* else if (op & 32) { + * state->mode = TYPE; + * break; + * } + */ + testb $32, %al + jz .L_invalid_literal_length_code /* if ((op & 32) == 0) */ + + movl $0, %ecx + movl $INFLATE_MODE_TYPE, %edx + jmp .L_update_stream_state + +.L_invalid_literal_length_code: + /* else { + * strm->msg = "invalid literal/length code"; + * state->mode = BAD; + * } + */ + movl $.L_invalid_literal_length_code_msg, %ecx + movl $INFLATE_MODE_BAD, %edx + jmp .L_update_stream_state + +.L_invalid_distance_too_far: + /* strm->msg = "invalid distance too far back"; + * state->mode = BAD; + */ + movl in(%esp), in_r /* from_r has in's reg, put in back */ + movl $.L_invalid_distance_too_far_msg, %ecx + movl $INFLATE_MODE_BAD, %edx + jmp .L_update_stream_state + +.L_update_stream_state: + /* set strm->msg = %ecx, strm->state->mode = %edx */ + movl strm_sp(%esp), %eax + testl %ecx, %ecx /* if (msg != NULL) */ + jz .L_skip_msg + movl %ecx, msg_strm(%eax) /* strm->msg = msg */ +.L_skip_msg: + movl state_strm(%eax), %eax /* state = strm->state */ + movl %edx, mode_state(%eax) /* state->mode = edx (BAD | TYPE) */ + jmp .L_break_loop + +.align 32,0x90 +.L_break_loop: + +/* + * Regs: + * + * bits = %ebp when mmx, and in %ebx when non-mmx + * hold = %hold_mm when mmx, and in %ebp when non-mmx + * in = %esi + * out = %edi + */ + +#if defined( USE_MMX ) || defined( RUN_TIME_MMX ) + +#if defined( RUN_TIME_MMX ) + + cmpl $DO_USE_MMX, inflate_fast_use_mmx + jne .L_update_next_in + +#endif /* RUN_TIME_MMX */ + + movl %ebp, %ebx + +.L_update_next_in: + +#endif + +#define strm_r %eax +#define state_r %edx + + /* len = bits >> 3; + * in -= len; + * bits -= len << 3; + * hold &= (1U << bits) - 1; + * state->hold = hold; + * state->bits = bits; + * strm->next_in = in; + * strm->next_out = out; + */ + movl strm_sp(%esp), strm_r + movl %ebx, %ecx + movl state_strm(strm_r), state_r + shrl $3, %ecx + subl %ecx, in_r + shll $3, %ecx + subl %ecx, %ebx + movl out_r, next_out_strm(strm_r) + movl %ebx, bits_state(state_r) + movl %ebx, %ecx + + leal buf(%esp), %ebx + cmpl %ebx, last(%esp) + jne .L_buf_not_used /* if buf != last */ + + subl %ebx, in_r /* in -= buf */ + movl next_in_strm(strm_r), %ebx + movl %ebx, last(%esp) /* last = strm->next_in */ + addl %ebx, in_r /* in += strm->next_in */ + movl avail_in_strm(strm_r), %ebx + subl $11, %ebx + addl %ebx, last(%esp) /* last = &strm->next_in[ avail_in - 11 ] */ + +.L_buf_not_used: + movl in_r, next_in_strm(strm_r) + + movl $1, %ebx + shll %cl, %ebx + decl %ebx + +#if defined( USE_MMX ) || defined( RUN_TIME_MMX ) + +#if defined( RUN_TIME_MMX ) + + cmpl $DO_USE_MMX, inflate_fast_use_mmx + jne .L_update_hold + +#endif /* RUN_TIME_MMX */ + + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + movd hold_mm, %ebp + + emms + +.L_update_hold: + +#endif /* USE_MMX || RUN_TIME_MMX */ + + andl %ebx, %ebp + movl %ebp, hold_state(state_r) + +#define last_r %ebx + + /* strm->avail_in = in < last ? 11 + (last - in) : 11 - (in - last) */ + movl last(%esp), last_r + cmpl in_r, last_r + jbe .L_last_is_smaller /* if (in >= last) */ + + subl in_r, last_r /* last -= in */ + addl $11, last_r /* last += 11 */ + movl last_r, avail_in_strm(strm_r) + jmp .L_fixup_out +.L_last_is_smaller: + subl last_r, in_r /* in -= last */ + negl in_r /* in = -in */ + addl $11, in_r /* in += 11 */ + movl in_r, avail_in_strm(strm_r) + +#undef last_r +#define end_r %ebx + +.L_fixup_out: + /* strm->avail_out = out < end ? 257 + (end - out) : 257 - (out - end)*/ + movl end(%esp), end_r + cmpl out_r, end_r + jbe .L_end_is_smaller /* if (out >= end) */ + + subl out_r, end_r /* end -= out */ + addl $257, end_r /* end += 257 */ + movl end_r, avail_out_strm(strm_r) + jmp .L_done +.L_end_is_smaller: + subl end_r, out_r /* out -= end */ + negl out_r /* out = -out */ + addl $257, out_r /* out += 257 */ + movl out_r, avail_out_strm(strm_r) + +#undef end_r +#undef strm_r +#undef state_r + +.L_done: + addl $local_var_size, %esp + popf + popl %ebx + popl %ebp + popl %esi + popl %edi + ret + +#if defined( GAS_ELF ) +/* elf info */ +.type inflate_fast,@function +.size inflate_fast,.-inflate_fast +#endif diff --git a/contrib/zlib/contrib/iostream/test.cpp b/contrib/zlib/contrib/iostream/test.cpp new file mode 100644 index 00000000..7d265b3b --- /dev/null +++ b/contrib/zlib/contrib/iostream/test.cpp @@ -0,0 +1,24 @@ + +#include "zfstream.h" + +int main() { + + // Construct a stream object with this filebuffer. Anything sent + // to this stream will go to standard out. + gzofstream os( 1, ios::out ); + + // This text is getting compressed and sent to stdout. + // To prove this, run 'test | zcat'. + os << "Hello, Mommy" << endl; + + os << setcompressionlevel( Z_NO_COMPRESSION ); + os << "hello, hello, hi, ho!" << endl; + + setcompressionlevel( os, Z_DEFAULT_COMPRESSION ) + << "I'm compressing again" << endl; + + os.close(); + + return 0; + +} diff --git a/contrib/zlib/contrib/iostream/zfstream.cpp b/contrib/zlib/contrib/iostream/zfstream.cpp new file mode 100644 index 00000000..d0cd85fa --- /dev/null +++ b/contrib/zlib/contrib/iostream/zfstream.cpp @@ -0,0 +1,329 @@ + +#include "zfstream.h" + +gzfilebuf::gzfilebuf() : + file(NULL), + mode(0), + own_file_descriptor(0) +{ } + +gzfilebuf::~gzfilebuf() { + + sync(); + if ( own_file_descriptor ) + close(); + +} + +gzfilebuf *gzfilebuf::open( const char *name, + int io_mode ) { + + if ( is_open() ) + return NULL; + + char char_mode[10]; + char *p = char_mode; + + if ( io_mode & ios::in ) { + mode = ios::in; + *p++ = 'r'; + } else if ( io_mode & ios::app ) { + mode = ios::app; + *p++ = 'a'; + } else { + mode = ios::out; + *p++ = 'w'; + } + + if ( io_mode & ios::binary ) { + mode |= ios::binary; + *p++ = 'b'; + } + + // Hard code the compression level + if ( io_mode & (ios::out|ios::app )) { + *p++ = '9'; + } + + // Put the end-of-string indicator + *p = '\0'; + + if ( (file = gzopen(name, char_mode)) == NULL ) + return NULL; + + own_file_descriptor = 1; + + return this; + +} + +gzfilebuf *gzfilebuf::attach( int file_descriptor, + int io_mode ) { + + if ( is_open() ) + return NULL; + + char char_mode[10]; + char *p = char_mode; + + if ( io_mode & ios::in ) { + mode = ios::in; + *p++ = 'r'; + } else if ( io_mode & ios::app ) { + mode = ios::app; + *p++ = 'a'; + } else { + mode = ios::out; + *p++ = 'w'; + } + + if ( io_mode & ios::binary ) { + mode |= ios::binary; + *p++ = 'b'; + } + + // Hard code the compression level + if ( io_mode & (ios::out|ios::app )) { + *p++ = '9'; + } + + // Put the end-of-string indicator + *p = '\0'; + + if ( (file = gzdopen(file_descriptor, char_mode)) == NULL ) + return NULL; + + own_file_descriptor = 0; + + return this; + +} + +gzfilebuf *gzfilebuf::close() { + + if ( is_open() ) { + + sync(); + gzclose( file ); + file = NULL; + + } + + return this; + +} + +int gzfilebuf::setcompressionlevel( int comp_level ) { + + return gzsetparams(file, comp_level, -2); + +} + +int gzfilebuf::setcompressionstrategy( int comp_strategy ) { + + return gzsetparams(file, -2, comp_strategy); + +} + + +streampos gzfilebuf::seekoff( streamoff off, ios::seek_dir dir, int which ) { + + return streampos(EOF); + +} + +int gzfilebuf::underflow() { + + // If the file hasn't been opened for reading, error. + if ( !is_open() || !(mode & ios::in) ) + return EOF; + + // if a buffer doesn't exists, allocate one. + if ( !base() ) { + + if ( (allocate()) == EOF ) + return EOF; + setp(0,0); + + } else { + + if ( in_avail() ) + return (unsigned char) *gptr(); + + if ( out_waiting() ) { + if ( flushbuf() == EOF ) + return EOF; + } + + } + + // Attempt to fill the buffer. + + int result = fillbuf(); + if ( result == EOF ) { + // disable get area + setg(0,0,0); + return EOF; + } + + return (unsigned char) *gptr(); + +} + +int gzfilebuf::overflow( int c ) { + + if ( !is_open() || !(mode & ios::out) ) + return EOF; + + if ( !base() ) { + if ( allocate() == EOF ) + return EOF; + setg(0,0,0); + } else { + if (in_avail()) { + return EOF; + } + if (out_waiting()) { + if (flushbuf() == EOF) + return EOF; + } + } + + int bl = blen(); + setp( base(), base() + bl); + + if ( c != EOF ) { + + *pptr() = c; + pbump(1); + + } + + return 0; + +} + +int gzfilebuf::sync() { + + if ( !is_open() ) + return EOF; + + if ( out_waiting() ) + return flushbuf(); + + return 0; + +} + +int gzfilebuf::flushbuf() { + + int n; + char *q; + + q = pbase(); + n = pptr() - q; + + if ( gzwrite( file, q, n) < n ) + return EOF; + + setp(0,0); + + return 0; + +} + +int gzfilebuf::fillbuf() { + + int required; + char *p; + + p = base(); + + required = blen(); + + int t = gzread( file, p, required ); + + if ( t <= 0) return EOF; + + setg( base(), base(), base()+t); + + return t; + +} + +gzfilestream_common::gzfilestream_common() : + ios( gzfilestream_common::rdbuf() ) +{ } + +gzfilestream_common::~gzfilestream_common() +{ } + +void gzfilestream_common::attach( int fd, int io_mode ) { + + if ( !buffer.attach( fd, io_mode) ) + clear( ios::failbit | ios::badbit ); + else + clear(); + +} + +void gzfilestream_common::open( const char *name, int io_mode ) { + + if ( !buffer.open( name, io_mode ) ) + clear( ios::failbit | ios::badbit ); + else + clear(); + +} + +void gzfilestream_common::close() { + + if ( !buffer.close() ) + clear( ios::failbit | ios::badbit ); + +} + +gzfilebuf *gzfilestream_common::rdbuf() +{ + return &buffer; +} + +gzifstream::gzifstream() : + ios( gzfilestream_common::rdbuf() ) +{ + clear( ios::badbit ); +} + +gzifstream::gzifstream( const char *name, int io_mode ) : + ios( gzfilestream_common::rdbuf() ) +{ + gzfilestream_common::open( name, io_mode ); +} + +gzifstream::gzifstream( int fd, int io_mode ) : + ios( gzfilestream_common::rdbuf() ) +{ + gzfilestream_common::attach( fd, io_mode ); +} + +gzifstream::~gzifstream() { } + +gzofstream::gzofstream() : + ios( gzfilestream_common::rdbuf() ) +{ + clear( ios::badbit ); +} + +gzofstream::gzofstream( const char *name, int io_mode ) : + ios( gzfilestream_common::rdbuf() ) +{ + gzfilestream_common::open( name, io_mode ); +} + +gzofstream::gzofstream( int fd, int io_mode ) : + ios( gzfilestream_common::rdbuf() ) +{ + gzfilestream_common::attach( fd, io_mode ); +} + +gzofstream::~gzofstream() { } diff --git a/contrib/zlib/contrib/iostream/zfstream.h b/contrib/zlib/contrib/iostream/zfstream.h new file mode 100644 index 00000000..ed79098a --- /dev/null +++ b/contrib/zlib/contrib/iostream/zfstream.h @@ -0,0 +1,128 @@ + +#ifndef zfstream_h +#define zfstream_h + +#include +#include "zlib.h" + +class gzfilebuf : public streambuf { + +public: + + gzfilebuf( ); + virtual ~gzfilebuf(); + + gzfilebuf *open( const char *name, int io_mode ); + gzfilebuf *attach( int file_descriptor, int io_mode ); + gzfilebuf *close(); + + int setcompressionlevel( int comp_level ); + int setcompressionstrategy( int comp_strategy ); + + inline int is_open() const { return (file !=NULL); } + + virtual streampos seekoff( streamoff, ios::seek_dir, int ); + + virtual int sync(); + +protected: + + virtual int underflow(); + virtual int overflow( int = EOF ); + +private: + + gzFile file; + short mode; + short own_file_descriptor; + + int flushbuf(); + int fillbuf(); + +}; + +class gzfilestream_common : virtual public ios { + + friend class gzifstream; + friend class gzofstream; + friend gzofstream &setcompressionlevel( gzofstream &, int ); + friend gzofstream &setcompressionstrategy( gzofstream &, int ); + +public: + virtual ~gzfilestream_common(); + + void attach( int fd, int io_mode ); + void open( const char *name, int io_mode ); + void close(); + +protected: + gzfilestream_common(); + +private: + gzfilebuf *rdbuf(); + + gzfilebuf buffer; + +}; + +class gzifstream : public gzfilestream_common, public istream { + +public: + + gzifstream(); + gzifstream( const char *name, int io_mode = ios::in ); + gzifstream( int fd, int io_mode = ios::in ); + + virtual ~gzifstream(); + +}; + +class gzofstream : public gzfilestream_common, public ostream { + +public: + + gzofstream(); + gzofstream( const char *name, int io_mode = ios::out ); + gzofstream( int fd, int io_mode = ios::out ); + + virtual ~gzofstream(); + +}; + +template class gzomanip { + friend gzofstream &operator<<(gzofstream &, const gzomanip &); +public: + gzomanip(gzofstream &(*f)(gzofstream &, T), T v) : func(f), val(v) { } +private: + gzofstream &(*func)(gzofstream &, T); + T val; +}; + +template gzofstream &operator<<(gzofstream &s, const gzomanip &m) +{ + return (*m.func)(s, m.val); +} + +inline gzofstream &setcompressionlevel( gzofstream &s, int l ) +{ + (s.rdbuf())->setcompressionlevel(l); + return s; +} + +inline gzofstream &setcompressionstrategy( gzofstream &s, int l ) +{ + (s.rdbuf())->setcompressionstrategy(l); + return s; +} + +inline gzomanip setcompressionlevel(int l) +{ + return gzomanip(&setcompressionlevel,l); +} + +inline gzomanip setcompressionstrategy(int l) +{ + return gzomanip(&setcompressionstrategy,l); +} + +#endif diff --git a/contrib/zlib/contrib/iostream2/zstream.h b/contrib/zlib/contrib/iostream2/zstream.h new file mode 100644 index 00000000..43d2332b --- /dev/null +++ b/contrib/zlib/contrib/iostream2/zstream.h @@ -0,0 +1,307 @@ +/* + * + * Copyright (c) 1997 + * Christian Michelsen Research AS + * Advanced Computing + * Fantoftvegen 38, 5036 BERGEN, Norway + * http://www.cmr.no + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Christian Michelsen Research AS makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef ZSTREAM__H +#define ZSTREAM__H + +/* + * zstream.h - C++ interface to the 'zlib' general purpose compression library + * $Id: zstream.h 1.1 1997-06-25 12:00:56+02 tyge Exp tyge $ + */ + +#include +#include +#include +#include "zlib.h" + +#if defined(_WIN32) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +class zstringlen { +public: + zstringlen(class izstream&); + zstringlen(class ozstream&, const char*); + size_t value() const { return val.word; } +private: + struct Val { unsigned char byte; size_t word; } val; +}; + +// ----------------------------- izstream ----------------------------- + +class izstream +{ + public: + izstream() : m_fp(0) {} + izstream(FILE* fp) : m_fp(0) { open(fp); } + izstream(const char* name) : m_fp(0) { open(name); } + ~izstream() { close(); } + + /* Opens a gzip (.gz) file for reading. + * open() can be used to read a file which is not in gzip format; + * in this case read() will directly read from the file without + * decompression. errno can be checked to distinguish two error + * cases (if errno is zero, the zlib error is Z_MEM_ERROR). + */ + void open(const char* name) { + if (m_fp) close(); + m_fp = ::gzopen(name, "rb"); + } + + void open(FILE* fp) { + SET_BINARY_MODE(fp); + if (m_fp) close(); + m_fp = ::gzdopen(fileno(fp), "rb"); + } + + /* Flushes all pending input if necessary, closes the compressed file + * and deallocates all the (de)compression state. The return value is + * the zlib error number (see function error() below). + */ + int close() { + int r = ::gzclose(m_fp); + m_fp = 0; return r; + } + + /* Binary read the given number of bytes from the compressed file. + */ + int read(void* buf, size_t len) { + return ::gzread(m_fp, buf, len); + } + + /* Returns the error message for the last error which occurred on the + * given compressed file. errnum is set to zlib error number. If an + * error occurred in the file system and not in the compression library, + * errnum is set to Z_ERRNO and the application may consult errno + * to get the exact error code. + */ + const char* error(int* errnum) { + return ::gzerror(m_fp, errnum); + } + + gzFile fp() { return m_fp; } + + private: + gzFile m_fp; +}; + +/* + * Binary read the given (array of) object(s) from the compressed file. + * If the input file was not in gzip format, read() copies the objects number + * of bytes into the buffer. + * returns the number of uncompressed bytes actually read + * (0 for end of file, -1 for error). + */ +template +inline int read(izstream& zs, T* x, Items items) { + return ::gzread(zs.fp(), x, items*sizeof(T)); +} + +/* + * Binary input with the '>' operator. + */ +template +inline izstream& operator>(izstream& zs, T& x) { + ::gzread(zs.fp(), &x, sizeof(T)); + return zs; +} + + +inline zstringlen::zstringlen(izstream& zs) { + zs > val.byte; + if (val.byte == 255) zs > val.word; + else val.word = val.byte; +} + +/* + * Read length of string + the string with the '>' operator. + */ +inline izstream& operator>(izstream& zs, char* x) { + zstringlen len(zs); + ::gzread(zs.fp(), x, len.value()); + x[len.value()] = '\0'; + return zs; +} + +inline char* read_string(izstream& zs) { + zstringlen len(zs); + char* x = new char[len.value()+1]; + ::gzread(zs.fp(), x, len.value()); + x[len.value()] = '\0'; + return x; +} + +// ----------------------------- ozstream ----------------------------- + +class ozstream +{ + public: + ozstream() : m_fp(0), m_os(0) { + } + ozstream(FILE* fp, int level = Z_DEFAULT_COMPRESSION) + : m_fp(0), m_os(0) { + open(fp, level); + } + ozstream(const char* name, int level = Z_DEFAULT_COMPRESSION) + : m_fp(0), m_os(0) { + open(name, level); + } + ~ozstream() { + close(); + } + + /* Opens a gzip (.gz) file for writing. + * The compression level parameter should be in 0..9 + * errno can be checked to distinguish two error cases + * (if errno is zero, the zlib error is Z_MEM_ERROR). + */ + void open(const char* name, int level = Z_DEFAULT_COMPRESSION) { + char mode[4] = "wb\0"; + if (level != Z_DEFAULT_COMPRESSION) mode[2] = '0'+level; + if (m_fp) close(); + m_fp = ::gzopen(name, mode); + } + + /* open from a FILE pointer. + */ + void open(FILE* fp, int level = Z_DEFAULT_COMPRESSION) { + SET_BINARY_MODE(fp); + char mode[4] = "wb\0"; + if (level != Z_DEFAULT_COMPRESSION) mode[2] = '0'+level; + if (m_fp) close(); + m_fp = ::gzdopen(fileno(fp), mode); + } + + /* Flushes all pending output if necessary, closes the compressed file + * and deallocates all the (de)compression state. The return value is + * the zlib error number (see function error() below). + */ + int close() { + if (m_os) { + ::gzwrite(m_fp, m_os->str(), m_os->pcount()); + delete[] m_os->str(); delete m_os; m_os = 0; + } + int r = ::gzclose(m_fp); m_fp = 0; return r; + } + + /* Binary write the given number of bytes into the compressed file. + */ + int write(const void* buf, size_t len) { + return ::gzwrite(m_fp, (voidp) buf, len); + } + + /* Flushes all pending output into the compressed file. The parameter + * _flush is as in the deflate() function. The return value is the zlib + * error number (see function gzerror below). flush() returns Z_OK if + * the flush_ parameter is Z_FINISH and all output could be flushed. + * flush() should be called only when strictly necessary because it can + * degrade compression. + */ + int flush(int _flush) { + os_flush(); + return ::gzflush(m_fp, _flush); + } + + /* Returns the error message for the last error which occurred on the + * given compressed file. errnum is set to zlib error number. If an + * error occurred in the file system and not in the compression library, + * errnum is set to Z_ERRNO and the application may consult errno + * to get the exact error code. + */ + const char* error(int* errnum) { + return ::gzerror(m_fp, errnum); + } + + gzFile fp() { return m_fp; } + + ostream& os() { + if (m_os == 0) m_os = new ostrstream; + return *m_os; + } + + void os_flush() { + if (m_os && m_os->pcount()>0) { + ostrstream* oss = new ostrstream; + oss->fill(m_os->fill()); + oss->flags(m_os->flags()); + oss->precision(m_os->precision()); + oss->width(m_os->width()); + ::gzwrite(m_fp, m_os->str(), m_os->pcount()); + delete[] m_os->str(); delete m_os; m_os = oss; + } + } + + private: + gzFile m_fp; + ostrstream* m_os; +}; + +/* + * Binary write the given (array of) object(s) into the compressed file. + * returns the number of uncompressed bytes actually written + * (0 in case of error). + */ +template +inline int write(ozstream& zs, const T* x, Items items) { + return ::gzwrite(zs.fp(), (voidp) x, items*sizeof(T)); +} + +/* + * Binary output with the '<' operator. + */ +template +inline ozstream& operator<(ozstream& zs, const T& x) { + ::gzwrite(zs.fp(), (voidp) &x, sizeof(T)); + return zs; +} + +inline zstringlen::zstringlen(ozstream& zs, const char* x) { + val.byte = 255; val.word = ::strlen(x); + if (val.word < 255) zs < (val.byte = val.word); + else zs < val; +} + +/* + * Write length of string + the string with the '<' operator. + */ +inline ozstream& operator<(ozstream& zs, const char* x) { + zstringlen len(zs, x); + ::gzwrite(zs.fp(), (voidp) x, len.value()); + return zs; +} + +#ifdef _MSC_VER +inline ozstream& operator<(ozstream& zs, char* const& x) { + return zs < (const char*) x; +} +#endif + +/* + * Ascii write with the << operator; + */ +template +inline ostream& operator<<(ozstream& zs, const T& x) { + zs.os_flush(); + return zs.os() << x; +} + +#endif diff --git a/contrib/zlib/contrib/iostream2/zstream_test.cpp b/contrib/zlib/contrib/iostream2/zstream_test.cpp new file mode 100644 index 00000000..6273f62d --- /dev/null +++ b/contrib/zlib/contrib/iostream2/zstream_test.cpp @@ -0,0 +1,25 @@ +#include "zstream.h" +#include +#include +#include + +void main() { + char h[256] = "Hello"; + char* g = "Goodbye"; + ozstream out("temp.gz"); + out < "This works well" < h < g; + out.close(); + + izstream in("temp.gz"); // read it back + char *x = read_string(in), *y = new char[256], z[256]; + in > y > z; + in.close(); + cout << x << endl << y << endl << z << endl; + + out.open("temp.gz"); // try ascii output; zcat temp.gz to see the results + out << setw(50) << setfill('#') << setprecision(20) << x << endl << y << endl << z << endl; + out << z << endl << y << endl << x << endl; + out << 1.1234567890123456789 << endl; + + delete[] x; delete[] y; +} diff --git a/contrib/zlib/contrib/iostream3/README b/contrib/zlib/contrib/iostream3/README new file mode 100644 index 00000000..f7b319ab --- /dev/null +++ b/contrib/zlib/contrib/iostream3/README @@ -0,0 +1,35 @@ +These classes provide a C++ stream interface to the zlib library. It allows you +to do things like: + + gzofstream outf("blah.gz"); + outf << "These go into the gzip file " << 123 << endl; + +It does this by deriving a specialized stream buffer for gzipped files, which is +the way Stroustrup would have done it. :-> + +The gzifstream and gzofstream classes were originally written by Kevin Ruland +and made available in the zlib contrib/iostream directory. The older version still +compiles under gcc 2.xx, but not under gcc 3.xx, which sparked the development of +this version. + +The new classes are as standard-compliant as possible, closely following the +approach of the standard library's fstream classes. It compiles under gcc versions +3.2 and 3.3, but not under gcc 2.xx. This is mainly due to changes in the standard +library naming scheme. The new version of gzifstream/gzofstream/gzfilebuf differs +from the previous one in the following respects: +- added showmanyc +- added setbuf, with support for unbuffered output via setbuf(0,0) +- a few bug fixes of stream behavior +- gzipped output file opened with default compression level instead of maximum level +- setcompressionlevel()/strategy() members replaced by single setcompression() + +The code is provided "as is", with the permission to use, copy, modify, distribute +and sell it for any purpose without fee. + +Ludwig Schwardt + + +DSP Lab +Electrical & Electronic Engineering Department +University of Stellenbosch +South Africa diff --git a/contrib/zlib/contrib/iostream3/TODO b/contrib/zlib/contrib/iostream3/TODO new file mode 100644 index 00000000..7032f97b --- /dev/null +++ b/contrib/zlib/contrib/iostream3/TODO @@ -0,0 +1,17 @@ +Possible upgrades to gzfilebuf: + +- The ability to do putback (e.g. putbackfail) + +- The ability to seek (zlib supports this, but could be slow/tricky) + +- Simultaneous read/write access (does it make sense?) + +- Support for ios_base::ate open mode + +- Locale support? + +- Check public interface to see which calls give problems + (due to dependence on library internals) + +- Override operator<<(ostream&, gzfilebuf*) to allow direct copying + of stream buffer to stream ( i.e. os << is.rdbuf(); ) diff --git a/contrib/zlib/contrib/iostream3/test.cc b/contrib/zlib/contrib/iostream3/test.cc new file mode 100644 index 00000000..94235334 --- /dev/null +++ b/contrib/zlib/contrib/iostream3/test.cc @@ -0,0 +1,50 @@ +/* + * Test program for gzifstream and gzofstream + * + * by Ludwig Schwardt + * original version by Kevin Ruland + */ + +#include "zfstream.h" +#include // for cout + +int main() { + + gzofstream outf; + gzifstream inf; + char buf[80]; + + outf.open("test1.txt.gz"); + outf << "The quick brown fox sidestepped the lazy canine\n" + << 1.3 << "\nPlan " << 9 << std::endl; + outf.close(); + std::cout << "Wrote the following message to 'test1.txt.gz' (check with zcat or zless):\n" + << "The quick brown fox sidestepped the lazy canine\n" + << 1.3 << "\nPlan " << 9 << std::endl; + + std::cout << "\nReading 'test1.txt.gz' (buffered) produces:\n"; + inf.open("test1.txt.gz"); + while (inf.getline(buf,80,'\n')) { + std::cout << buf << "\t(" << inf.rdbuf()->in_avail() << " chars left in buffer)\n"; + } + inf.close(); + + outf.rdbuf()->pubsetbuf(0,0); + outf.open("test2.txt.gz"); + outf << setcompression(Z_NO_COMPRESSION) + << "The quick brown fox sidestepped the lazy canine\n" + << 1.3 << "\nPlan " << 9 << std::endl; + outf.close(); + std::cout << "\nWrote the same message to 'test2.txt.gz' in uncompressed form"; + + std::cout << "\nReading 'test2.txt.gz' (unbuffered) produces:\n"; + inf.rdbuf()->pubsetbuf(0,0); + inf.open("test2.txt.gz"); + while (inf.getline(buf,80,'\n')) { + std::cout << buf << "\t(" << inf.rdbuf()->in_avail() << " chars left in buffer)\n"; + } + inf.close(); + + return 0; + +} diff --git a/contrib/zlib/contrib/iostream3/zfstream.cc b/contrib/zlib/contrib/iostream3/zfstream.cc new file mode 100644 index 00000000..94eb9334 --- /dev/null +++ b/contrib/zlib/contrib/iostream3/zfstream.cc @@ -0,0 +1,479 @@ +/* + * A C++ I/O streams interface to the zlib gz* functions + * + * by Ludwig Schwardt + * original version by Kevin Ruland + * + * This version is standard-compliant and compatible with gcc 3.x. + */ + +#include "zfstream.h" +#include // for strcpy, strcat, strlen (mode strings) +#include // for BUFSIZ + +// Internal buffer sizes (default and "unbuffered" versions) +#define BIGBUFSIZE BUFSIZ +#define SMALLBUFSIZE 1 + +/*****************************************************************************/ + +// Default constructor +gzfilebuf::gzfilebuf() +: file(NULL), io_mode(std::ios_base::openmode(0)), own_fd(false), + buffer(NULL), buffer_size(BIGBUFSIZE), own_buffer(true) +{ + // No buffers to start with + this->disable_buffer(); +} + +// Destructor +gzfilebuf::~gzfilebuf() +{ + // Sync output buffer and close only if responsible for file + // (i.e. attached streams should be left open at this stage) + this->sync(); + if (own_fd) + this->close(); + // Make sure internal buffer is deallocated + this->disable_buffer(); +} + +// Set compression level and strategy +int +gzfilebuf::setcompression(int comp_level, + int comp_strategy) +{ + return gzsetparams(file, comp_level, comp_strategy); +} + +// Open gzipped file +gzfilebuf* +gzfilebuf::open(const char *name, + std::ios_base::openmode mode) +{ + // Fail if file already open + if (this->is_open()) + return NULL; + // Don't support simultaneous read/write access (yet) + if ((mode & std::ios_base::in) && (mode & std::ios_base::out)) + return NULL; + + // Build mode string for gzopen and check it [27.8.1.3.2] + char char_mode[6] = "\0\0\0\0\0"; + if (!this->open_mode(mode, char_mode)) + return NULL; + + // Attempt to open file + if ((file = gzopen(name, char_mode)) == NULL) + return NULL; + + // On success, allocate internal buffer and set flags + this->enable_buffer(); + io_mode = mode; + own_fd = true; + return this; +} + +// Attach to gzipped file +gzfilebuf* +gzfilebuf::attach(int fd, + std::ios_base::openmode mode) +{ + // Fail if file already open + if (this->is_open()) + return NULL; + // Don't support simultaneous read/write access (yet) + if ((mode & std::ios_base::in) && (mode & std::ios_base::out)) + return NULL; + + // Build mode string for gzdopen and check it [27.8.1.3.2] + char char_mode[6] = "\0\0\0\0\0"; + if (!this->open_mode(mode, char_mode)) + return NULL; + + // Attempt to attach to file + if ((file = gzdopen(fd, char_mode)) == NULL) + return NULL; + + // On success, allocate internal buffer and set flags + this->enable_buffer(); + io_mode = mode; + own_fd = false; + return this; +} + +// Close gzipped file +gzfilebuf* +gzfilebuf::close() +{ + // Fail immediately if no file is open + if (!this->is_open()) + return NULL; + // Assume success + gzfilebuf* retval = this; + // Attempt to sync and close gzipped file + if (this->sync() == -1) + retval = NULL; + if (gzclose(file) < 0) + retval = NULL; + // File is now gone anyway (postcondition [27.8.1.3.8]) + file = NULL; + own_fd = false; + // Destroy internal buffer if it exists + this->disable_buffer(); + return retval; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +// Convert int open mode to mode string +bool +gzfilebuf::open_mode(std::ios_base::openmode mode, + char* c_mode) const +{ + bool testb = mode & std::ios_base::binary; + bool testi = mode & std::ios_base::in; + bool testo = mode & std::ios_base::out; + bool testt = mode & std::ios_base::trunc; + bool testa = mode & std::ios_base::app; + + // Check for valid flag combinations - see [27.8.1.3.2] (Table 92) + // Original zfstream hardcoded the compression level to maximum here... + // Double the time for less than 1% size improvement seems + // excessive though - keeping it at the default level + // To change back, just append "9" to the next three mode strings + if (!testi && testo && !testt && !testa) + strcpy(c_mode, "w"); + if (!testi && testo && !testt && testa) + strcpy(c_mode, "a"); + if (!testi && testo && testt && !testa) + strcpy(c_mode, "w"); + if (testi && !testo && !testt && !testa) + strcpy(c_mode, "r"); + // No read/write mode yet +// if (testi && testo && !testt && !testa) +// strcpy(c_mode, "r+"); +// if (testi && testo && testt && !testa) +// strcpy(c_mode, "w+"); + + // Mode string should be empty for invalid combination of flags + if (strlen(c_mode) == 0) + return false; + if (testb) + strcat(c_mode, "b"); + return true; +} + +// Determine number of characters in internal get buffer +std::streamsize +gzfilebuf::showmanyc() +{ + // Calls to underflow will fail if file not opened for reading + if (!this->is_open() || !(io_mode & std::ios_base::in)) + return -1; + // Make sure get area is in use + if (this->gptr() && (this->gptr() < this->egptr())) + return std::streamsize(this->egptr() - this->gptr()); + else + return 0; +} + +// Fill get area from gzipped file +gzfilebuf::int_type +gzfilebuf::underflow() +{ + // If something is left in the get area by chance, return it + // (this shouldn't normally happen, as underflow is only supposed + // to be called when gptr >= egptr, but it serves as error check) + if (this->gptr() && (this->gptr() < this->egptr())) + return traits_type::to_int_type(*(this->gptr())); + + // If the file hasn't been opened for reading, produce error + if (!this->is_open() || !(io_mode & std::ios_base::in)) + return traits_type::eof(); + + // Attempt to fill internal buffer from gzipped file + // (buffer must be guaranteed to exist...) + int bytes_read = gzread(file, buffer, buffer_size); + // Indicates error or EOF + if (bytes_read <= 0) + { + // Reset get area + this->setg(buffer, buffer, buffer); + return traits_type::eof(); + } + // Make all bytes read from file available as get area + this->setg(buffer, buffer, buffer + bytes_read); + + // Return next character in get area + return traits_type::to_int_type(*(this->gptr())); +} + +// Write put area to gzipped file +gzfilebuf::int_type +gzfilebuf::overflow(int_type c) +{ + // Determine whether put area is in use + if (this->pbase()) + { + // Double-check pointer range + if (this->pptr() > this->epptr() || this->pptr() < this->pbase()) + return traits_type::eof(); + // Add extra character to buffer if not EOF + if (!traits_type::eq_int_type(c, traits_type::eof())) + { + *(this->pptr()) = traits_type::to_char_type(c); + this->pbump(1); + } + // Number of characters to write to file + int bytes_to_write = this->pptr() - this->pbase(); + // Overflow doesn't fail if nothing is to be written + if (bytes_to_write > 0) + { + // If the file hasn't been opened for writing, produce error + if (!this->is_open() || !(io_mode & std::ios_base::out)) + return traits_type::eof(); + // If gzipped file won't accept all bytes written to it, fail + if (gzwrite(file, this->pbase(), bytes_to_write) != bytes_to_write) + return traits_type::eof(); + // Reset next pointer to point to pbase on success + this->pbump(-bytes_to_write); + } + } + // Write extra character to file if not EOF + else if (!traits_type::eq_int_type(c, traits_type::eof())) + { + // If the file hasn't been opened for writing, produce error + if (!this->is_open() || !(io_mode & std::ios_base::out)) + return traits_type::eof(); + // Impromptu char buffer (allows "unbuffered" output) + char_type last_char = traits_type::to_char_type(c); + // If gzipped file won't accept this character, fail + if (gzwrite(file, &last_char, 1) != 1) + return traits_type::eof(); + } + + // If you got here, you have succeeded (even if c was EOF) + // The return value should therefore be non-EOF + if (traits_type::eq_int_type(c, traits_type::eof())) + return traits_type::not_eof(c); + else + return c; +} + +// Assign new buffer +std::streambuf* +gzfilebuf::setbuf(char_type* p, + std::streamsize n) +{ + // First make sure stuff is sync'ed, for safety + if (this->sync() == -1) + return NULL; + // If buffering is turned off on purpose via setbuf(0,0), still allocate one... + // "Unbuffered" only really refers to put [27.8.1.4.10], while get needs at + // least a buffer of size 1 (very inefficient though, therefore make it bigger?) + // This follows from [27.5.2.4.3]/12 (gptr needs to point at something, it seems) + if (!p || !n) + { + // Replace existing buffer (if any) with small internal buffer + this->disable_buffer(); + buffer = NULL; + buffer_size = 0; + own_buffer = true; + this->enable_buffer(); + } + else + { + // Replace existing buffer (if any) with external buffer + this->disable_buffer(); + buffer = p; + buffer_size = n; + own_buffer = false; + this->enable_buffer(); + } + return this; +} + +// Write put area to gzipped file (i.e. ensures that put area is empty) +int +gzfilebuf::sync() +{ + return traits_type::eq_int_type(this->overflow(), traits_type::eof()) ? -1 : 0; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +// Allocate internal buffer +void +gzfilebuf::enable_buffer() +{ + // If internal buffer required, allocate one + if (own_buffer && !buffer) + { + // Check for buffered vs. "unbuffered" + if (buffer_size > 0) + { + // Allocate internal buffer + buffer = new char_type[buffer_size]; + // Get area starts empty and will be expanded by underflow as need arises + this->setg(buffer, buffer, buffer); + // Setup entire internal buffer as put area. + // The one-past-end pointer actually points to the last element of the buffer, + // so that overflow(c) can safely add the extra character c to the sequence. + // These pointers remain in place for the duration of the buffer + this->setp(buffer, buffer + buffer_size - 1); + } + else + { + // Even in "unbuffered" case, (small?) get buffer is still required + buffer_size = SMALLBUFSIZE; + buffer = new char_type[buffer_size]; + this->setg(buffer, buffer, buffer); + // "Unbuffered" means no put buffer + this->setp(0, 0); + } + } + else + { + // If buffer already allocated, reset buffer pointers just to make sure no + // stale chars are lying around + this->setg(buffer, buffer, buffer); + this->setp(buffer, buffer + buffer_size - 1); + } +} + +// Destroy internal buffer +void +gzfilebuf::disable_buffer() +{ + // If internal buffer exists, deallocate it + if (own_buffer && buffer) + { + // Preserve unbuffered status by zeroing size + if (!this->pbase()) + buffer_size = 0; + delete[] buffer; + buffer = NULL; + this->setg(0, 0, 0); + this->setp(0, 0); + } + else + { + // Reset buffer pointers to initial state if external buffer exists + this->setg(buffer, buffer, buffer); + if (buffer) + this->setp(buffer, buffer + buffer_size - 1); + else + this->setp(0, 0); + } +} + +/*****************************************************************************/ + +// Default constructor initializes stream buffer +gzifstream::gzifstream() +: std::istream(NULL), sb() +{ this->init(&sb); } + +// Initialize stream buffer and open file +gzifstream::gzifstream(const char* name, + std::ios_base::openmode mode) +: std::istream(NULL), sb() +{ + this->init(&sb); + this->open(name, mode); +} + +// Initialize stream buffer and attach to file +gzifstream::gzifstream(int fd, + std::ios_base::openmode mode) +: std::istream(NULL), sb() +{ + this->init(&sb); + this->attach(fd, mode); +} + +// Open file and go into fail() state if unsuccessful +void +gzifstream::open(const char* name, + std::ios_base::openmode mode) +{ + if (!sb.open(name, mode | std::ios_base::in)) + this->setstate(std::ios_base::failbit); + else + this->clear(); +} + +// Attach to file and go into fail() state if unsuccessful +void +gzifstream::attach(int fd, + std::ios_base::openmode mode) +{ + if (!sb.attach(fd, mode | std::ios_base::in)) + this->setstate(std::ios_base::failbit); + else + this->clear(); +} + +// Close file +void +gzifstream::close() +{ + if (!sb.close()) + this->setstate(std::ios_base::failbit); +} + +/*****************************************************************************/ + +// Default constructor initializes stream buffer +gzofstream::gzofstream() +: std::ostream(NULL), sb() +{ this->init(&sb); } + +// Initialize stream buffer and open file +gzofstream::gzofstream(const char* name, + std::ios_base::openmode mode) +: std::ostream(NULL), sb() +{ + this->init(&sb); + this->open(name, mode); +} + +// Initialize stream buffer and attach to file +gzofstream::gzofstream(int fd, + std::ios_base::openmode mode) +: std::ostream(NULL), sb() +{ + this->init(&sb); + this->attach(fd, mode); +} + +// Open file and go into fail() state if unsuccessful +void +gzofstream::open(const char* name, + std::ios_base::openmode mode) +{ + if (!sb.open(name, mode | std::ios_base::out)) + this->setstate(std::ios_base::failbit); + else + this->clear(); +} + +// Attach to file and go into fail() state if unsuccessful +void +gzofstream::attach(int fd, + std::ios_base::openmode mode) +{ + if (!sb.attach(fd, mode | std::ios_base::out)) + this->setstate(std::ios_base::failbit); + else + this->clear(); +} + +// Close file +void +gzofstream::close() +{ + if (!sb.close()) + this->setstate(std::ios_base::failbit); +} diff --git a/contrib/zlib/contrib/iostream3/zfstream.h b/contrib/zlib/contrib/iostream3/zfstream.h new file mode 100644 index 00000000..8574479a --- /dev/null +++ b/contrib/zlib/contrib/iostream3/zfstream.h @@ -0,0 +1,466 @@ +/* + * A C++ I/O streams interface to the zlib gz* functions + * + * by Ludwig Schwardt + * original version by Kevin Ruland + * + * This version is standard-compliant and compatible with gcc 3.x. + */ + +#ifndef ZFSTREAM_H +#define ZFSTREAM_H + +#include // not iostream, since we don't need cin/cout +#include +#include "zlib.h" + +/*****************************************************************************/ + +/** + * @brief Gzipped file stream buffer class. + * + * This class implements basic_filebuf for gzipped files. It doesn't yet support + * seeking (allowed by zlib but slow/limited), putback and read/write access + * (tricky). Otherwise, it attempts to be a drop-in replacement for the standard + * file streambuf. +*/ +class gzfilebuf : public std::streambuf +{ +public: + // Default constructor. + gzfilebuf(); + + // Destructor. + virtual + ~gzfilebuf(); + + /** + * @brief Set compression level and strategy on the fly. + * @param comp_level Compression level (see zlib.h for allowed values) + * @param comp_strategy Compression strategy (see zlib.h for allowed values) + * @return Z_OK on success, Z_STREAM_ERROR otherwise. + * + * Unfortunately, these parameters cannot be modified separately, as the + * previous zfstream version assumed. Since the strategy is seldom changed, + * it can default and setcompression(level) then becomes like the old + * setcompressionlevel(level). + */ + int + setcompression(int comp_level, + int comp_strategy = Z_DEFAULT_STRATEGY); + + /** + * @brief Check if file is open. + * @return True if file is open. + */ + bool + is_open() const { return (file != NULL); } + + /** + * @brief Open gzipped file. + * @param name File name. + * @param mode Open mode flags. + * @return @c this on success, NULL on failure. + */ + gzfilebuf* + open(const char* name, + std::ios_base::openmode mode); + + /** + * @brief Attach to already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags. + * @return @c this on success, NULL on failure. + */ + gzfilebuf* + attach(int fd, + std::ios_base::openmode mode); + + /** + * @brief Close gzipped file. + * @return @c this on success, NULL on failure. + */ + gzfilebuf* + close(); + +protected: + /** + * @brief Convert ios open mode int to mode string used by zlib. + * @return True if valid mode flag combination. + */ + bool + open_mode(std::ios_base::openmode mode, + char* c_mode) const; + + /** + * @brief Number of characters available in stream buffer. + * @return Number of characters. + * + * This indicates number of characters in get area of stream buffer. + * These characters can be read without accessing the gzipped file. + */ + virtual std::streamsize + showmanyc(); + + /** + * @brief Fill get area from gzipped file. + * @return First character in get area on success, EOF on error. + * + * This actually reads characters from gzipped file to stream + * buffer. Always buffered. + */ + virtual int_type + underflow(); + + /** + * @brief Write put area to gzipped file. + * @param c Extra character to add to buffer contents. + * @return Non-EOF on success, EOF on error. + * + * This actually writes characters in stream buffer to + * gzipped file. With unbuffered output this is done one + * character at a time. + */ + virtual int_type + overflow(int_type c = traits_type::eof()); + + /** + * @brief Installs external stream buffer. + * @param p Pointer to char buffer. + * @param n Size of external buffer. + * @return @c this on success, NULL on failure. + * + * Call setbuf(0,0) to enable unbuffered output. + */ + virtual std::streambuf* + setbuf(char_type* p, + std::streamsize n); + + /** + * @brief Flush stream buffer to file. + * @return 0 on success, -1 on error. + * + * This calls underflow(EOF) to do the job. + */ + virtual int + sync(); + +// +// Some future enhancements +// +// virtual int_type uflow(); +// virtual int_type pbackfail(int_type c = traits_type::eof()); +// virtual pos_type +// seekoff(off_type off, +// std::ios_base::seekdir way, +// std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out); +// virtual pos_type +// seekpos(pos_type sp, +// std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out); + +private: + /** + * @brief Allocate internal buffer. + * + * This function is safe to call multiple times. It will ensure + * that a proper internal buffer exists if it is required. If the + * buffer already exists or is external, the buffer pointers will be + * reset to their original state. + */ + void + enable_buffer(); + + /** + * @brief Destroy internal buffer. + * + * This function is safe to call multiple times. It will ensure + * that the internal buffer is deallocated if it exists. In any + * case, it will also reset the buffer pointers. + */ + void + disable_buffer(); + + /** + * Underlying file pointer. + */ + gzFile file; + + /** + * Mode in which file was opened. + */ + std::ios_base::openmode io_mode; + + /** + * @brief True if this object owns file descriptor. + * + * This makes the class responsible for closing the file + * upon destruction. + */ + bool own_fd; + + /** + * @brief Stream buffer. + * + * For simplicity this remains allocated on the free store for the + * entire life span of the gzfilebuf object, unless replaced by setbuf. + */ + char_type* buffer; + + /** + * @brief Stream buffer size. + * + * Defaults to system default buffer size (typically 8192 bytes). + * Modified by setbuf. + */ + std::streamsize buffer_size; + + /** + * @brief True if this object owns stream buffer. + * + * This makes the class responsible for deleting the buffer + * upon destruction. + */ + bool own_buffer; +}; + +/*****************************************************************************/ + +/** + * @brief Gzipped file input stream class. + * + * This class implements ifstream for gzipped files. Seeking and putback + * is not supported yet. +*/ +class gzifstream : public std::istream +{ +public: + // Default constructor + gzifstream(); + + /** + * @brief Construct stream on gzipped file to be opened. + * @param name File name. + * @param mode Open mode flags (forced to contain ios::in). + */ + explicit + gzifstream(const char* name, + std::ios_base::openmode mode = std::ios_base::in); + + /** + * @brief Construct stream on already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags (forced to contain ios::in). + */ + explicit + gzifstream(int fd, + std::ios_base::openmode mode = std::ios_base::in); + + /** + * Obtain underlying stream buffer. + */ + gzfilebuf* + rdbuf() const + { return const_cast(&sb); } + + /** + * @brief Check if file is open. + * @return True if file is open. + */ + bool + is_open() { return sb.is_open(); } + + /** + * @brief Open gzipped file. + * @param name File name. + * @param mode Open mode flags (forced to contain ios::in). + * + * Stream will be in state good() if file opens successfully; + * otherwise in state fail(). This differs from the behavior of + * ifstream, which never sets the state to good() and therefore + * won't allow you to reuse the stream for a second file unless + * you manually clear() the state. The choice is a matter of + * convenience. + */ + void + open(const char* name, + std::ios_base::openmode mode = std::ios_base::in); + + /** + * @brief Attach to already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags (forced to contain ios::in). + * + * Stream will be in state good() if attach succeeded; otherwise + * in state fail(). + */ + void + attach(int fd, + std::ios_base::openmode mode = std::ios_base::in); + + /** + * @brief Close gzipped file. + * + * Stream will be in state fail() if close failed. + */ + void + close(); + +private: + /** + * Underlying stream buffer. + */ + gzfilebuf sb; +}; + +/*****************************************************************************/ + +/** + * @brief Gzipped file output stream class. + * + * This class implements ofstream for gzipped files. Seeking and putback + * is not supported yet. +*/ +class gzofstream : public std::ostream +{ +public: + // Default constructor + gzofstream(); + + /** + * @brief Construct stream on gzipped file to be opened. + * @param name File name. + * @param mode Open mode flags (forced to contain ios::out). + */ + explicit + gzofstream(const char* name, + std::ios_base::openmode mode = std::ios_base::out); + + /** + * @brief Construct stream on already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags (forced to contain ios::out). + */ + explicit + gzofstream(int fd, + std::ios_base::openmode mode = std::ios_base::out); + + /** + * Obtain underlying stream buffer. + */ + gzfilebuf* + rdbuf() const + { return const_cast(&sb); } + + /** + * @brief Check if file is open. + * @return True if file is open. + */ + bool + is_open() { return sb.is_open(); } + + /** + * @brief Open gzipped file. + * @param name File name. + * @param mode Open mode flags (forced to contain ios::out). + * + * Stream will be in state good() if file opens successfully; + * otherwise in state fail(). This differs from the behavior of + * ofstream, which never sets the state to good() and therefore + * won't allow you to reuse the stream for a second file unless + * you manually clear() the state. The choice is a matter of + * convenience. + */ + void + open(const char* name, + std::ios_base::openmode mode = std::ios_base::out); + + /** + * @brief Attach to already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags (forced to contain ios::out). + * + * Stream will be in state good() if attach succeeded; otherwise + * in state fail(). + */ + void + attach(int fd, + std::ios_base::openmode mode = std::ios_base::out); + + /** + * @brief Close gzipped file. + * + * Stream will be in state fail() if close failed. + */ + void + close(); + +private: + /** + * Underlying stream buffer. + */ + gzfilebuf sb; +}; + +/*****************************************************************************/ + +/** + * @brief Gzipped file output stream manipulator class. + * + * This class defines a two-argument manipulator for gzofstream. It is used + * as base for the setcompression(int,int) manipulator. +*/ +template + class gzomanip2 + { + public: + // Allows insertor to peek at internals + template + friend gzofstream& + operator<<(gzofstream&, + const gzomanip2&); + + // Constructor + gzomanip2(gzofstream& (*f)(gzofstream&, T1, T2), + T1 v1, + T2 v2); + private: + // Underlying manipulator function + gzofstream& + (*func)(gzofstream&, T1, T2); + + // Arguments for manipulator function + T1 val1; + T2 val2; + }; + +/*****************************************************************************/ + +// Manipulator function thunks through to stream buffer +inline gzofstream& +setcompression(gzofstream &gzs, int l, int s = Z_DEFAULT_STRATEGY) +{ + (gzs.rdbuf())->setcompression(l, s); + return gzs; +} + +// Manipulator constructor stores arguments +template + inline + gzomanip2::gzomanip2(gzofstream &(*f)(gzofstream &, T1, T2), + T1 v1, + T2 v2) + : func(f), val1(v1), val2(v2) + { } + +// Insertor applies underlying manipulator function to stream +template + inline gzofstream& + operator<<(gzofstream& s, const gzomanip2& m) + { return (*m.func)(s, m.val1, m.val2); } + +// Insert this onto stream to simplify setting of compression level +inline gzomanip2 +setcompression(int l, int s = Z_DEFAULT_STRATEGY) +{ return gzomanip2(&setcompression, l, s); } + +#endif // ZFSTREAM_H diff --git a/contrib/zlib/contrib/masmx64/bld_ml64.bat b/contrib/zlib/contrib/masmx64/bld_ml64.bat new file mode 100644 index 00000000..f74bcef5 --- /dev/null +++ b/contrib/zlib/contrib/masmx64/bld_ml64.bat @@ -0,0 +1,2 @@ +ml64.exe /Flinffasx64 /c /Zi inffasx64.asm +ml64.exe /Flgvmat64 /c /Zi gvmat64.asm diff --git a/contrib/zlib/contrib/masmx64/gvmat64.asm b/contrib/zlib/contrib/masmx64/gvmat64.asm new file mode 100644 index 00000000..c1817f1b --- /dev/null +++ b/contrib/zlib/contrib/masmx64/gvmat64.asm @@ -0,0 +1,553 @@ +;uInt longest_match_x64( +; deflate_state *s, +; IPos cur_match); /* current match */ + +; gvmat64.asm -- Asm portion of the optimized longest_match for 32 bits x86_64 +; (AMD64 on Athlon 64, Opteron, Phenom +; and Intel EM64T on Pentium 4 with EM64T, Pentium D, Core 2 Duo, Core I5/I7) +; Copyright (C) 1995-2010 Jean-loup Gailly, Brian Raiter and Gilles Vollant. +; +; File written by Gilles Vollant, by converting to assembly the longest_match +; from Jean-loup Gailly in deflate.c of zLib and infoZip zip. +; +; and by taking inspiration on asm686 with masm, optimised assembly code +; from Brian Raiter, written 1998 +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Permission is granted to anyone to use this software for any purpose, +; including commercial applications, and to alter it and redistribute it +; freely, subject to the following restrictions: +; +; 1. The origin of this software must not be misrepresented; you must not +; claim that you wrote the original software. If you use this software +; in a product, an acknowledgment in the product documentation would be +; appreciated but is not required. +; 2. Altered source versions must be plainly marked as such, and must not be +; misrepresented as being the original software +; 3. This notice may not be removed or altered from any source distribution. +; +; +; +; http://www.zlib.net +; http://www.winimage.com/zLibDll +; http://www.muppetlabs.com/~breadbox/software/assembly.html +; +; to compile this file for infozip Zip, I use option: +; ml64.exe /Flgvmat64 /c /Zi /DINFOZIP gvmat64.asm +; +; to compile this file for zLib, I use option: +; ml64.exe /Flgvmat64 /c /Zi gvmat64.asm +; Be carrefull to adapt zlib1222add below to your version of zLib +; (if you use a version of zLib before 1.0.4 or after 1.2.2.2, change +; value of zlib1222add later) +; +; This file compile with Microsoft Macro Assembler (x64) for AMD64 +; +; ml64.exe is given with Visual Studio 2005/2008/2010 and Windows WDK +; +; (you can get Windows WDK with ml64 for AMD64 from +; http://www.microsoft.com/whdc/Devtools/wdk/default.mspx for low price) +; + + +;uInt longest_match(s, cur_match) +; deflate_state *s; +; IPos cur_match; /* current match */ +.code +longest_match PROC + + +;LocalVarsSize equ 88 + LocalVarsSize equ 72 + +; register used : rax,rbx,rcx,rdx,rsi,rdi,r8,r9,r10,r11,r12 +; free register : r14,r15 +; register can be saved : rsp + + chainlenwmask equ rsp + 8 - LocalVarsSize ; high word: current chain len + ; low word: s->wmask +;window equ rsp + xx - LocalVarsSize ; local copy of s->window ; stored in r10 +;windowbestlen equ rsp + xx - LocalVarsSize ; s->window + bestlen , use r10+r11 +;scanstart equ rsp + xx - LocalVarsSize ; first two bytes of string ; stored in r12w +;scanend equ rsp + xx - LocalVarsSize ; last two bytes of string use ebx +;scanalign equ rsp + xx - LocalVarsSize ; dword-misalignment of string r13 +;bestlen equ rsp + xx - LocalVarsSize ; size of best match so far -> r11d +;scan equ rsp + xx - LocalVarsSize ; ptr to string wanting match -> r9 +IFDEF INFOZIP +ELSE + nicematch equ (rsp + 16 - LocalVarsSize) ; a good enough match size +ENDIF + +save_rdi equ rsp + 24 - LocalVarsSize +save_rsi equ rsp + 32 - LocalVarsSize +save_rbx equ rsp + 40 - LocalVarsSize +save_rbp equ rsp + 48 - LocalVarsSize +save_r12 equ rsp + 56 - LocalVarsSize +save_r13 equ rsp + 64 - LocalVarsSize +;save_r14 equ rsp + 72 - LocalVarsSize +;save_r15 equ rsp + 80 - LocalVarsSize + + +; summary of register usage +; scanend ebx +; scanendw bx +; chainlenwmask edx +; curmatch rsi +; curmatchd esi +; windowbestlen r8 +; scanalign r9 +; scanalignd r9d +; window r10 +; bestlen r11 +; bestlend r11d +; scanstart r12d +; scanstartw r12w +; scan r13 +; nicematch r14d +; limit r15 +; limitd r15d +; prev rcx + +; all the +4 offsets are due to the addition of pending_buf_size (in zlib +; in the deflate_state structure since the asm code was first written +; (if you compile with zlib 1.0.4 or older, remove the +4). +; Note : these value are good with a 8 bytes boundary pack structure + + + MAX_MATCH equ 258 + MIN_MATCH equ 3 + MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1) + + +;;; Offsets for fields in the deflate_state structure. These numbers +;;; are calculated from the definition of deflate_state, with the +;;; assumption that the compiler will dword-align the fields. (Thus, +;;; changing the definition of deflate_state could easily cause this +;;; program to crash horribly, without so much as a warning at +;;; compile time. Sigh.) + +; all the +zlib1222add offsets are due to the addition of fields +; in zlib in the deflate_state structure since the asm code was first written +; (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)"). +; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0"). +; if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8"). + + +IFDEF INFOZIP + +_DATA SEGMENT +COMM window_size:DWORD +; WMask ; 7fff +COMM window:BYTE:010040H +COMM prev:WORD:08000H +; MatchLen : unused +; PrevMatch : unused +COMM strstart:DWORD +COMM match_start:DWORD +; Lookahead : ignore +COMM prev_length:DWORD ; PrevLen +COMM max_chain_length:DWORD +COMM good_match:DWORD +COMM nice_match:DWORD +prev_ad equ OFFSET prev +window_ad equ OFFSET window +nicematch equ nice_match +_DATA ENDS +WMask equ 07fffh + +ELSE + + IFNDEF zlib1222add + zlib1222add equ 8 + ENDIF +dsWSize equ 56+zlib1222add+(zlib1222add/2) +dsWMask equ 64+zlib1222add+(zlib1222add/2) +dsWindow equ 72+zlib1222add +dsPrev equ 88+zlib1222add +dsMatchLen equ 128+zlib1222add +dsPrevMatch equ 132+zlib1222add +dsStrStart equ 140+zlib1222add +dsMatchStart equ 144+zlib1222add +dsLookahead equ 148+zlib1222add +dsPrevLen equ 152+zlib1222add +dsMaxChainLen equ 156+zlib1222add +dsGoodMatch equ 172+zlib1222add +dsNiceMatch equ 176+zlib1222add + +window_size equ [ rcx + dsWSize] +WMask equ [ rcx + dsWMask] +window_ad equ [ rcx + dsWindow] +prev_ad equ [ rcx + dsPrev] +strstart equ [ rcx + dsStrStart] +match_start equ [ rcx + dsMatchStart] +Lookahead equ [ rcx + dsLookahead] ; 0ffffffffh on infozip +prev_length equ [ rcx + dsPrevLen] +max_chain_length equ [ rcx + dsMaxChainLen] +good_match equ [ rcx + dsGoodMatch] +nice_match equ [ rcx + dsNiceMatch] +ENDIF + +; parameter 1 in r8(deflate state s), param 2 in rdx (cur match) + +; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and +; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp +; +; All registers must be preserved across the call, except for +; rax, rcx, rdx, r8, r9, r10, and r11, which are scratch. + + + +;;; Save registers that the compiler may be using, and adjust esp to +;;; make room for our stack frame. + + +;;; Retrieve the function arguments. r8d will hold cur_match +;;; throughout the entire function. edx will hold the pointer to the +;;; deflate_state structure during the function's setup (before +;;; entering the main loop. + +; parameter 1 in rcx (deflate_state* s), param 2 in edx -> r8 (cur match) + +; this clear high 32 bits of r8, which can be garbage in both r8 and rdx + + mov [save_rdi],rdi + mov [save_rsi],rsi + mov [save_rbx],rbx + mov [save_rbp],rbp +IFDEF INFOZIP + mov r8d,ecx +ELSE + mov r8d,edx +ENDIF + mov [save_r12],r12 + mov [save_r13],r13 +; mov [save_r14],r14 +; mov [save_r15],r15 + + +;;; uInt wmask = s->w_mask; +;;; unsigned chain_length = s->max_chain_length; +;;; if (s->prev_length >= s->good_match) { +;;; chain_length >>= 2; +;;; } + + mov edi, prev_length + mov esi, good_match + mov eax, WMask + mov ebx, max_chain_length + cmp edi, esi + jl LastMatchGood + shr ebx, 2 +LastMatchGood: + +;;; chainlen is decremented once beforehand so that the function can +;;; use the sign flag instead of the zero flag for the exit test. +;;; It is then shifted into the high word, to make room for the wmask +;;; value, which it will always accompany. + + dec ebx + shl ebx, 16 + or ebx, eax + +;;; on zlib only +;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + +IFDEF INFOZIP + mov [chainlenwmask], ebx +; on infozip nice_match = [nice_match] +ELSE + mov eax, nice_match + mov [chainlenwmask], ebx + mov r10d, Lookahead + cmp r10d, eax + cmovnl r10d, eax + mov [nicematch],r10d +ENDIF + +;;; register Bytef *scan = s->window + s->strstart; + mov r10, window_ad + mov ebp, strstart + lea r13, [r10 + rbp] + +;;; Determine how many bytes the scan ptr is off from being +;;; dword-aligned. + + mov r9,r13 + neg r13 + and r13,3 + +;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ? +;;; s->strstart - (IPos)MAX_DIST(s) : NIL; +IFDEF INFOZIP + mov eax,07efah ; MAX_DIST = (WSIZE-MIN_LOOKAHEAD) (0x8000-(3+8+1)) +ELSE + mov eax, window_size + sub eax, MIN_LOOKAHEAD +ENDIF + xor edi,edi + sub ebp, eax + + mov r11d, prev_length + + cmovng ebp,edi + +;;; int best_len = s->prev_length; + + +;;; Store the sum of s->window + best_len in esi locally, and in esi. + + lea rsi,[r10+r11] + +;;; register ush scan_start = *(ushf*)scan; +;;; register ush scan_end = *(ushf*)(scan+best_len-1); +;;; Posf *prev = s->prev; + + movzx r12d,word ptr [r9] + movzx ebx, word ptr [r9 + r11 - 1] + + mov rdi, prev_ad + +;;; Jump into the main loop. + + mov edx, [chainlenwmask] + + cmp bx,word ptr [rsi + r8 - 1] + jz LookupLoopIsZero + +LookupLoop1: + and r8d, edx + + movzx r8d, word ptr [rdi + r8*2] + cmp r8d, ebp + jbe LeaveNow + sub edx, 00010000h + js LeaveNow + +LoopEntry1: + cmp bx,word ptr [rsi + r8 - 1] + jz LookupLoopIsZero + +LookupLoop2: + and r8d, edx + + movzx r8d, word ptr [rdi + r8*2] + cmp r8d, ebp + jbe LeaveNow + sub edx, 00010000h + js LeaveNow + +LoopEntry2: + cmp bx,word ptr [rsi + r8 - 1] + jz LookupLoopIsZero + +LookupLoop4: + and r8d, edx + + movzx r8d, word ptr [rdi + r8*2] + cmp r8d, ebp + jbe LeaveNow + sub edx, 00010000h + js LeaveNow + +LoopEntry4: + + cmp bx,word ptr [rsi + r8 - 1] + jnz LookupLoop1 + jmp LookupLoopIsZero + + +;;; do { +;;; match = s->window + cur_match; +;;; if (*(ushf*)(match+best_len-1) != scan_end || +;;; *(ushf*)match != scan_start) continue; +;;; [...] +;;; } while ((cur_match = prev[cur_match & wmask]) > limit +;;; && --chain_length != 0); +;;; +;;; Here is the inner loop of the function. The function will spend the +;;; majority of its time in this loop, and majority of that time will +;;; be spent in the first ten instructions. +;;; +;;; Within this loop: +;;; ebx = scanend +;;; r8d = curmatch +;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) +;;; esi = windowbestlen - i.e., (window + bestlen) +;;; edi = prev +;;; ebp = limit + +LookupLoop: + and r8d, edx + + movzx r8d, word ptr [rdi + r8*2] + cmp r8d, ebp + jbe LeaveNow + sub edx, 00010000h + js LeaveNow + +LoopEntry: + + cmp bx,word ptr [rsi + r8 - 1] + jnz LookupLoop1 +LookupLoopIsZero: + cmp r12w, word ptr [r10 + r8] + jnz LookupLoop1 + + +;;; Store the current value of chainlen. + mov [chainlenwmask], edx + +;;; Point edi to the string under scrutiny, and esi to the string we +;;; are hoping to match it up with. In actuality, esi and edi are +;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is +;;; initialized to -(MAX_MATCH_8 - scanalign). + + lea rsi,[r8+r10] + mov rdx, 0fffffffffffffef8h; -(MAX_MATCH_8) + lea rsi, [rsi + r13 + 0108h] ;MAX_MATCH_8] + lea rdi, [r9 + r13 + 0108h] ;MAX_MATCH_8] + + prefetcht1 [rsi+rdx] + prefetcht1 [rdi+rdx] + + +;;; Test the strings for equality, 8 bytes at a time. At the end, +;;; adjust rdx so that it is offset to the exact byte that mismatched. +;;; +;;; We already know at this point that the first three bytes of the +;;; strings match each other, and they can be safely passed over before +;;; starting the compare loop. So what this code does is skip over 0-3 +;;; bytes, as much as necessary in order to dword-align the edi +;;; pointer. (rsi will still be misaligned three times out of four.) +;;; +;;; It should be confessed that this loop usually does not represent +;;; much of the total running time. Replacing it with a more +;;; straightforward "rep cmpsb" would not drastically degrade +;;; performance. + + +LoopCmps: + mov rax, [rsi + rdx] + xor rax, [rdi + rdx] + jnz LeaveLoopCmps + + mov rax, [rsi + rdx + 8] + xor rax, [rdi + rdx + 8] + jnz LeaveLoopCmps8 + + + mov rax, [rsi + rdx + 8+8] + xor rax, [rdi + rdx + 8+8] + jnz LeaveLoopCmps16 + + add rdx,8+8+8 + + jnz short LoopCmps + jmp short LenMaximum +LeaveLoopCmps16: add rdx,8 +LeaveLoopCmps8: add rdx,8 +LeaveLoopCmps: + + test eax, 0000FFFFh + jnz LenLower + + test eax,0ffffffffh + + jnz LenLower32 + + add rdx,4 + shr rax,32 + or ax,ax + jnz LenLower + +LenLower32: + shr eax,16 + add rdx,2 +LenLower: sub al, 1 + adc rdx, 0 +;;; Calculate the length of the match. If it is longer than MAX_MATCH, +;;; then automatically accept it as the best possible match and leave. + + lea rax, [rdi + rdx] + sub rax, r9 + cmp eax, MAX_MATCH + jge LenMaximum + +;;; If the length of the match is not longer than the best match we +;;; have so far, then forget it and return to the lookup loop. +;/////////////////////////////////// + + cmp eax, r11d + jg LongerMatch + + lea rsi,[r10+r11] + + mov rdi, prev_ad + mov edx, [chainlenwmask] + jmp LookupLoop + +;;; s->match_start = cur_match; +;;; best_len = len; +;;; if (len >= nice_match) break; +;;; scan_end = *(ushf*)(scan+best_len-1); + +LongerMatch: + mov r11d, eax + mov match_start, r8d + cmp eax, [nicematch] + jge LeaveNow + + lea rsi,[r10+rax] + + movzx ebx, word ptr [r9 + rax - 1] + mov rdi, prev_ad + mov edx, [chainlenwmask] + jmp LookupLoop + +;;; Accept the current string, with the maximum possible length. + +LenMaximum: + mov r11d,MAX_MATCH + mov match_start, r8d + +;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len; +;;; return s->lookahead; + +LeaveNow: +IFDEF INFOZIP + mov eax,r11d +ELSE + mov eax, Lookahead + cmp r11d, eax + cmovng eax, r11d +ENDIF + +;;; Restore the stack and return from whence we came. + + + mov rsi,[save_rsi] + mov rdi,[save_rdi] + mov rbx,[save_rbx] + mov rbp,[save_rbp] + mov r12,[save_r12] + mov r13,[save_r13] +; mov r14,[save_r14] +; mov r15,[save_r15] + + + ret 0 +; please don't remove this string ! +; Your can freely use gvmat64 in any free or commercial app +; but it is far better don't remove the string in the binary! + db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998, converted to amd 64 by Gilles Vollant 2005",0dh,0ah,0 +longest_match ENDP + +match_init PROC + ret 0 +match_init ENDP + + +END diff --git a/contrib/zlib/contrib/masmx64/inffas8664.c b/contrib/zlib/contrib/masmx64/inffas8664.c new file mode 100644 index 00000000..aa861a33 --- /dev/null +++ b/contrib/zlib/contrib/masmx64/inffas8664.c @@ -0,0 +1,186 @@ +/* inffas8664.c is a hand tuned assembler version of inffast.c - fast decoding + * version for AMD64 on Windows using Microsoft C compiler + * + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Copyright (C) 2003 Chris Anderson + * Please use the copyright conditions above. + * + * 2005 - Adaptation to Microsoft C Compiler for AMD64 by Gilles Vollant + * + * inffas8664.c call function inffas8664fnc in inffasx64.asm + * inffasx64.asm is automatically convert from AMD64 portion of inffas86.c + * + * Dec-29-2003 -- I added AMD64 inflate asm support. This version is also + * slightly quicker on x86 systems because, instead of using rep movsb to copy + * data, it uses rep movsw, which moves data in 2-byte chunks instead of single + * bytes. I've tested the AMD64 code on a Fedora Core 1 + the x86_64 updates + * from http://fedora.linux.duke.edu/fc1_x86_64 + * which is running on an Athlon 64 3000+ / Gigabyte GA-K8VT800M system with + * 1GB ram. The 64-bit version is about 4% faster than the 32-bit version, + * when decompressing mozilla-source-1.3.tar.gz. + * + * Mar-13-2003 -- Most of this is derived from inffast.S which is derived from + * the gcc -S output of zlib-1.2.0/inffast.c. Zlib-1.2.0 is in beta release at + * the moment. I have successfully compiled and tested this code with gcc2.96, + * gcc3.2, icc5.0, msvc6.0. It is very close to the speed of inffast.S + * compiled with gcc -DNO_MMX, but inffast.S is still faster on the P3 with MMX + * enabled. I will attempt to merge the MMX code into this version. Newer + * versions of this and inffast.S can be found at + * http://www.eetbeetee.com/zlib/ and http://www.charm.net/~christop/zlib/ + * + */ + +#include +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* Mark Adler's comments from inffast.c: */ + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ + + + + typedef struct inffast_ar { +/* 64 32 x86 x86_64 */ +/* ar offset register */ +/* 0 0 */ void *esp; /* esp save */ +/* 8 4 */ void *ebp; /* ebp save */ +/* 16 8 */ unsigned char FAR *in; /* esi rsi local strm->next_in */ +/* 24 12 */ unsigned char FAR *last; /* r9 while in < last */ +/* 32 16 */ unsigned char FAR *out; /* edi rdi local strm->next_out */ +/* 40 20 */ unsigned char FAR *beg; /* inflate()'s init next_out */ +/* 48 24 */ unsigned char FAR *end; /* r10 while out < end */ +/* 56 28 */ unsigned char FAR *window;/* size of window, wsize!=0 */ +/* 64 32 */ code const FAR *lcode; /* ebp rbp local strm->lencode */ +/* 72 36 */ code const FAR *dcode; /* r11 local strm->distcode */ +/* 80 40 */ size_t /*unsigned long */hold; /* edx rdx local strm->hold */ +/* 88 44 */ unsigned bits; /* ebx rbx local strm->bits */ +/* 92 48 */ unsigned wsize; /* window size */ +/* 96 52 */ unsigned write; /* window write index */ +/*100 56 */ unsigned lmask; /* r12 mask for lcode */ +/*104 60 */ unsigned dmask; /* r13 mask for dcode */ +/*108 64 */ unsigned len; /* r14 match length */ +/*112 68 */ unsigned dist; /* r15 match distance */ +/*116 72 */ unsigned status; /* set when state chng*/ + } type_ar; +#ifdef ASMINF + +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + type_ar ar; + void inffas8664fnc(struct inffast_ar * par); + + + +#if (defined( __GNUC__ ) && defined( __amd64__ ) && ! defined( __i386 )) || (defined(_MSC_VER) && defined(_M_AMD64)) +#define PAD_AVAIL_IN 6 +#define PAD_AVAIL_OUT 258 +#else +#define PAD_AVAIL_IN 5 +#define PAD_AVAIL_OUT 257 +#endif + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + + ar.in = strm->next_in; + ar.last = ar.in + (strm->avail_in - PAD_AVAIL_IN); + ar.out = strm->next_out; + ar.beg = ar.out - (start - strm->avail_out); + ar.end = ar.out + (strm->avail_out - PAD_AVAIL_OUT); + ar.wsize = state->wsize; + ar.write = state->wnext; + ar.window = state->window; + ar.hold = state->hold; + ar.bits = state->bits; + ar.lcode = state->lencode; + ar.dcode = state->distcode; + ar.lmask = (1U << state->lenbits) - 1; + ar.dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + + /* align in on 1/2 hold size boundary */ + while (((size_t)(void *)ar.in & (sizeof(ar.hold) / 2 - 1)) != 0) { + ar.hold += (unsigned long)*ar.in++ << ar.bits; + ar.bits += 8; + } + + inffas8664fnc(&ar); + + if (ar.status > 1) { + if (ar.status == 2) + strm->msg = "invalid literal/length code"; + else if (ar.status == 3) + strm->msg = "invalid distance code"; + else + strm->msg = "invalid distance too far back"; + state->mode = BAD; + } + else if ( ar.status == 1 ) { + state->mode = TYPE; + } + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + ar.len = ar.bits >> 3; + ar.in -= ar.len; + ar.bits -= ar.len << 3; + ar.hold &= (1U << ar.bits) - 1; + + /* update state and return */ + strm->next_in = ar.in; + strm->next_out = ar.out; + strm->avail_in = (unsigned)(ar.in < ar.last ? + PAD_AVAIL_IN + (ar.last - ar.in) : + PAD_AVAIL_IN - (ar.in - ar.last)); + strm->avail_out = (unsigned)(ar.out < ar.end ? + PAD_AVAIL_OUT + (ar.end - ar.out) : + PAD_AVAIL_OUT - (ar.out - ar.end)); + state->hold = (unsigned long)ar.hold; + state->bits = ar.bits; + return; +} + +#endif diff --git a/contrib/zlib/contrib/masmx64/inffasx64.asm b/contrib/zlib/contrib/masmx64/inffasx64.asm new file mode 100644 index 00000000..41ec8239 --- /dev/null +++ b/contrib/zlib/contrib/masmx64/inffasx64.asm @@ -0,0 +1,396 @@ +; inffasx64.asm is a hand tuned assembler version of inffast.c - fast decoding +; version for AMD64 on Windows using Microsoft C compiler +; +; inffasx64.asm is automatically convert from AMD64 portion of inffas86.c +; inffasx64.asm is called by inffas8664.c, which contain more info. + + +; to compile this file, I use option +; ml64.exe /Flinffasx64 /c /Zi inffasx64.asm +; with Microsoft Macro Assembler (x64) for AMD64 +; + +; This file compile with Microsoft Macro Assembler (x64) for AMD64 +; +; ml64.exe is given with Visual Studio 2005/2008/2010 and Windows WDK +; +; (you can get Windows WDK with ml64 for AMD64 from +; http://www.microsoft.com/whdc/Devtools/wdk/default.mspx for low price) +; + + +.code +inffas8664fnc PROC + +; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and +; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp +; +; All registers must be preserved across the call, except for +; rax, rcx, rdx, r8, r-9, r10, and r11, which are scratch. + + + mov [rsp-8],rsi + mov [rsp-16],rdi + mov [rsp-24],r12 + mov [rsp-32],r13 + mov [rsp-40],r14 + mov [rsp-48],r15 + mov [rsp-56],rbx + + mov rax,rcx + + mov [rax+8], rbp ; /* save regs rbp and rsp */ + mov [rax], rsp + + mov rsp, rax ; /* make rsp point to &ar */ + + mov rsi, [rsp+16] ; /* rsi = in */ + mov rdi, [rsp+32] ; /* rdi = out */ + mov r9, [rsp+24] ; /* r9 = last */ + mov r10, [rsp+48] ; /* r10 = end */ + mov rbp, [rsp+64] ; /* rbp = lcode */ + mov r11, [rsp+72] ; /* r11 = dcode */ + mov rdx, [rsp+80] ; /* rdx = hold */ + mov ebx, [rsp+88] ; /* ebx = bits */ + mov r12d, [rsp+100] ; /* r12d = lmask */ + mov r13d, [rsp+104] ; /* r13d = dmask */ + ; /* r14d = len */ + ; /* r15d = dist */ + + + cld + cmp r10, rdi + je L_one_time ; /* if only one decode left */ + cmp r9, rsi + + jne L_do_loop + + +L_one_time: + mov r8, r12 ; /* r8 = lmask */ + cmp bl, 32 + ja L_get_length_code_one_time + + lodsd ; /* eax = *(uint *)in++ */ + mov cl, bl ; /* cl = bits, needs it for shifting */ + add bl, 32 ; /* bits += 32 */ + shl rax, cl + or rdx, rax ; /* hold |= *((uint *)in)++ << bits */ + jmp L_get_length_code_one_time + +ALIGN 4 +L_while_test: + cmp r10, rdi + jbe L_break_loop + cmp r9, rsi + jbe L_break_loop + +L_do_loop: + mov r8, r12 ; /* r8 = lmask */ + cmp bl, 32 + ja L_get_length_code ; /* if (32 < bits) */ + + lodsd ; /* eax = *(uint *)in++ */ + mov cl, bl ; /* cl = bits, needs it for shifting */ + add bl, 32 ; /* bits += 32 */ + shl rax, cl + or rdx, rax ; /* hold |= *((uint *)in)++ << bits */ + +L_get_length_code: + and r8, rdx ; /* r8 &= hold */ + mov eax, [rbp+r8*4] ; /* eax = lcode[hold & lmask] */ + + mov cl, ah ; /* cl = this.bits */ + sub bl, ah ; /* bits -= this.bits */ + shr rdx, cl ; /* hold >>= this.bits */ + + test al, al + jnz L_test_for_length_base ; /* if (op != 0) 45.7% */ + + mov r8, r12 ; /* r8 = lmask */ + shr eax, 16 ; /* output this.val char */ + stosb + +L_get_length_code_one_time: + and r8, rdx ; /* r8 &= hold */ + mov eax, [rbp+r8*4] ; /* eax = lcode[hold & lmask] */ + +L_dolen: + mov cl, ah ; /* cl = this.bits */ + sub bl, ah ; /* bits -= this.bits */ + shr rdx, cl ; /* hold >>= this.bits */ + + test al, al + jnz L_test_for_length_base ; /* if (op != 0) 45.7% */ + + shr eax, 16 ; /* output this.val char */ + stosb + jmp L_while_test + +ALIGN 4 +L_test_for_length_base: + mov r14d, eax ; /* len = this */ + shr r14d, 16 ; /* len = this.val */ + mov cl, al + + test al, 16 + jz L_test_for_second_level_length ; /* if ((op & 16) == 0) 8% */ + and cl, 15 ; /* op &= 15 */ + jz L_decode_distance ; /* if (!op) */ + +L_add_bits_to_len: + sub bl, cl + xor eax, eax + inc eax + shl eax, cl + dec eax + and eax, edx ; /* eax &= hold */ + shr rdx, cl + add r14d, eax ; /* len += hold & mask[op] */ + +L_decode_distance: + mov r8, r13 ; /* r8 = dmask */ + cmp bl, 32 + ja L_get_distance_code ; /* if (32 < bits) */ + + lodsd ; /* eax = *(uint *)in++ */ + mov cl, bl ; /* cl = bits, needs it for shifting */ + add bl, 32 ; /* bits += 32 */ + shl rax, cl + or rdx, rax ; /* hold |= *((uint *)in)++ << bits */ + +L_get_distance_code: + and r8, rdx ; /* r8 &= hold */ + mov eax, [r11+r8*4] ; /* eax = dcode[hold & dmask] */ + +L_dodist: + mov r15d, eax ; /* dist = this */ + shr r15d, 16 ; /* dist = this.val */ + mov cl, ah + sub bl, ah ; /* bits -= this.bits */ + shr rdx, cl ; /* hold >>= this.bits */ + mov cl, al ; /* cl = this.op */ + + test al, 16 ; /* if ((op & 16) == 0) */ + jz L_test_for_second_level_dist + and cl, 15 ; /* op &= 15 */ + jz L_check_dist_one + +L_add_bits_to_dist: + sub bl, cl + xor eax, eax + inc eax + shl eax, cl + dec eax ; /* (1 << op) - 1 */ + and eax, edx ; /* eax &= hold */ + shr rdx, cl + add r15d, eax ; /* dist += hold & ((1 << op) - 1) */ + +L_check_window: + mov r8, rsi ; /* save in so from can use it's reg */ + mov rax, rdi + sub rax, [rsp+40] ; /* nbytes = out - beg */ + + cmp eax, r15d + jb L_clip_window ; /* if (dist > nbytes) 4.2% */ + + mov ecx, r14d ; /* ecx = len */ + mov rsi, rdi + sub rsi, r15 ; /* from = out - dist */ + + sar ecx, 1 + jnc L_copy_two ; /* if len % 2 == 0 */ + + rep movsw + mov al, [rsi] + mov [rdi], al + inc rdi + + mov rsi, r8 ; /* move in back to %rsi, toss from */ + jmp L_while_test + +L_copy_two: + rep movsw + mov rsi, r8 ; /* move in back to %rsi, toss from */ + jmp L_while_test + +ALIGN 4 +L_check_dist_one: + cmp r15d, 1 ; /* if dist 1, is a memset */ + jne L_check_window + cmp [rsp+40], rdi ; /* if out == beg, outside window */ + je L_check_window + + mov ecx, r14d ; /* ecx = len */ + mov al, [rdi-1] + mov ah, al + + sar ecx, 1 + jnc L_set_two + mov [rdi], al + inc rdi + +L_set_two: + rep stosw + jmp L_while_test + +ALIGN 4 +L_test_for_second_level_length: + test al, 64 + jnz L_test_for_end_of_block ; /* if ((op & 64) != 0) */ + + xor eax, eax + inc eax + shl eax, cl + dec eax + and eax, edx ; /* eax &= hold */ + add eax, r14d ; /* eax += len */ + mov eax, [rbp+rax*4] ; /* eax = lcode[val+(hold&mask[op])]*/ + jmp L_dolen + +ALIGN 4 +L_test_for_second_level_dist: + test al, 64 + jnz L_invalid_distance_code ; /* if ((op & 64) != 0) */ + + xor eax, eax + inc eax + shl eax, cl + dec eax + and eax, edx ; /* eax &= hold */ + add eax, r15d ; /* eax += dist */ + mov eax, [r11+rax*4] ; /* eax = dcode[val+(hold&mask[op])]*/ + jmp L_dodist + +ALIGN 4 +L_clip_window: + mov ecx, eax ; /* ecx = nbytes */ + mov eax, [rsp+92] ; /* eax = wsize, prepare for dist cmp */ + neg ecx ; /* nbytes = -nbytes */ + + cmp eax, r15d + jb L_invalid_distance_too_far ; /* if (dist > wsize) */ + + add ecx, r15d ; /* nbytes = dist - nbytes */ + cmp dword ptr [rsp+96], 0 + jne L_wrap_around_window ; /* if (write != 0) */ + + mov rsi, [rsp+56] ; /* from = window */ + sub eax, ecx ; /* eax -= nbytes */ + add rsi, rax ; /* from += wsize - nbytes */ + + mov eax, r14d ; /* eax = len */ + cmp r14d, ecx + jbe L_do_copy ; /* if (nbytes >= len) */ + + sub eax, ecx ; /* eax -= nbytes */ + rep movsb + mov rsi, rdi + sub rsi, r15 ; /* from = &out[ -dist ] */ + jmp L_do_copy + +ALIGN 4 +L_wrap_around_window: + mov eax, [rsp+96] ; /* eax = write */ + cmp ecx, eax + jbe L_contiguous_in_window ; /* if (write >= nbytes) */ + + mov esi, [rsp+92] ; /* from = wsize */ + add rsi, [rsp+56] ; /* from += window */ + add rsi, rax ; /* from += write */ + sub rsi, rcx ; /* from -= nbytes */ + sub ecx, eax ; /* nbytes -= write */ + + mov eax, r14d ; /* eax = len */ + cmp eax, ecx + jbe L_do_copy ; /* if (nbytes >= len) */ + + sub eax, ecx ; /* len -= nbytes */ + rep movsb + mov rsi, [rsp+56] ; /* from = window */ + mov ecx, [rsp+96] ; /* nbytes = write */ + cmp eax, ecx + jbe L_do_copy ; /* if (nbytes >= len) */ + + sub eax, ecx ; /* len -= nbytes */ + rep movsb + mov rsi, rdi + sub rsi, r15 ; /* from = out - dist */ + jmp L_do_copy + +ALIGN 4 +L_contiguous_in_window: + mov rsi, [rsp+56] ; /* rsi = window */ + add rsi, rax + sub rsi, rcx ; /* from += write - nbytes */ + + mov eax, r14d ; /* eax = len */ + cmp eax, ecx + jbe L_do_copy ; /* if (nbytes >= len) */ + + sub eax, ecx ; /* len -= nbytes */ + rep movsb + mov rsi, rdi + sub rsi, r15 ; /* from = out - dist */ + jmp L_do_copy ; /* if (nbytes >= len) */ + +ALIGN 4 +L_do_copy: + mov ecx, eax ; /* ecx = len */ + rep movsb + + mov rsi, r8 ; /* move in back to %esi, toss from */ + jmp L_while_test + +L_test_for_end_of_block: + test al, 32 + jz L_invalid_literal_length_code + mov dword ptr [rsp+116], 1 + jmp L_break_loop_with_status + +L_invalid_literal_length_code: + mov dword ptr [rsp+116], 2 + jmp L_break_loop_with_status + +L_invalid_distance_code: + mov dword ptr [rsp+116], 3 + jmp L_break_loop_with_status + +L_invalid_distance_too_far: + mov dword ptr [rsp+116], 4 + jmp L_break_loop_with_status + +L_break_loop: + mov dword ptr [rsp+116], 0 + +L_break_loop_with_status: +; /* put in, out, bits, and hold back into ar and pop esp */ + mov [rsp+16], rsi ; /* in */ + mov [rsp+32], rdi ; /* out */ + mov [rsp+88], ebx ; /* bits */ + mov [rsp+80], rdx ; /* hold */ + + mov rax, [rsp] ; /* restore rbp and rsp */ + mov rbp, [rsp+8] + mov rsp, rax + + + + mov rsi,[rsp-8] + mov rdi,[rsp-16] + mov r12,[rsp-24] + mov r13,[rsp-32] + mov r14,[rsp-40] + mov r15,[rsp-48] + mov rbx,[rsp-56] + + ret 0 +; : +; : "m" (ar) +; : "memory", "%rax", "%rbx", "%rcx", "%rdx", "%rsi", "%rdi", +; "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" +; ); + +inffas8664fnc ENDP +;_TEXT ENDS +END diff --git a/contrib/zlib/contrib/masmx64/readme.txt b/contrib/zlib/contrib/masmx64/readme.txt new file mode 100644 index 00000000..652571c7 --- /dev/null +++ b/contrib/zlib/contrib/masmx64/readme.txt @@ -0,0 +1,31 @@ +Summary +------- +This directory contains ASM implementations of the functions +longest_match() and inflate_fast(), for 64 bits x86 (both AMD64 and Intel EM64t), +for use with Microsoft Macro Assembler (x64) for AMD64 and Microsoft C++ 64 bits. + +gvmat64.asm is written by Gilles Vollant (2005), by using Brian Raiter 686/32 bits + assembly optimized version from Jean-loup Gailly original longest_match function + +inffasx64.asm and inffas8664.c were written by Chris Anderson, by optimizing + original function from Mark Adler + +Use instructions +---------------- +Assemble the .asm files using MASM and put the object files into the zlib source +directory. You can also get object files here: + + http://www.winimage.com/zLibDll/zlib124_masm_obj.zip + +define ASMV and ASMINF in your project. Include inffas8664.c in your source tree, +and inffasx64.obj and gvmat64.obj as object to link. + + +Build instructions +------------------ +run bld_64.bat with Microsoft Macro Assembler (x64) for AMD64 (ml64.exe) + +ml64.exe is given with Visual Studio 2005, Windows 2003 server DDK + +You can get Windows 2003 server DDK with ml64 and cl for AMD64 from + http://www.microsoft.com/whdc/devtools/ddk/default.mspx for low price) diff --git a/contrib/zlib/contrib/masmx86/bld_ml32.bat b/contrib/zlib/contrib/masmx86/bld_ml32.bat new file mode 100644 index 00000000..fcf5755e --- /dev/null +++ b/contrib/zlib/contrib/masmx86/bld_ml32.bat @@ -0,0 +1,2 @@ +ml /coff /Zi /c /Flmatch686.lst match686.asm +ml /coff /Zi /c /Flinffas32.lst inffas32.asm diff --git a/contrib/zlib/contrib/masmx86/inffas32.asm b/contrib/zlib/contrib/masmx86/inffas32.asm new file mode 100644 index 00000000..cb37a81e --- /dev/null +++ b/contrib/zlib/contrib/masmx86/inffas32.asm @@ -0,0 +1,1080 @@ +;/* inffas32.asm is a hand tuned assembler version of inffast.c -- fast decoding +; * +; * inffas32.asm is derivated from inffas86.c, with translation of assembly code +; * +; * Copyright (C) 1995-2003 Mark Adler +; * For conditions of distribution and use, see copyright notice in zlib.h +; * +; * Copyright (C) 2003 Chris Anderson +; * Please use the copyright conditions above. +; * +; * Mar-13-2003 -- Most of this is derived from inffast.S which is derived from +; * the gcc -S output of zlib-1.2.0/inffast.c. Zlib-1.2.0 is in beta release at +; * the moment. I have successfully compiled and tested this code with gcc2.96, +; * gcc3.2, icc5.0, msvc6.0. It is very close to the speed of inffast.S +; * compiled with gcc -DNO_MMX, but inffast.S is still faster on the P3 with MMX +; * enabled. I will attempt to merge the MMX code into this version. Newer +; * versions of this and inffast.S can be found at +; * http://www.eetbeetee.com/zlib/ and http://www.charm.net/~christop/zlib/ +; * +; * 2005 : modification by Gilles Vollant +; */ +; For Visual C++ 4.x and higher and ML 6.x and higher +; ml.exe is in directory \MASM611C of Win95 DDK +; ml.exe is also distributed in http://www.masm32.com/masmdl.htm +; and in VC++2003 toolkit at http://msdn.microsoft.com/visualc/vctoolkit2003/ +; +; +; compile with command line option +; ml /coff /Zi /c /Flinffas32.lst inffas32.asm + +; if you define NO_GZIP (see inflate.h), compile with +; ml /coff /Zi /c /Flinffas32.lst /DNO_GUNZIP inffas32.asm + + +; zlib122sup is 0 fort zlib 1.2.2.1 and lower +; zlib122sup is 8 fort zlib 1.2.2.2 and more (with addition of dmax and head +; in inflate_state in inflate.h) +zlib1222sup equ 8 + + +IFDEF GUNZIP + INFLATE_MODE_TYPE equ 11 + INFLATE_MODE_BAD equ 26 +ELSE + IFNDEF NO_GUNZIP + INFLATE_MODE_TYPE equ 11 + INFLATE_MODE_BAD equ 26 + ELSE + INFLATE_MODE_TYPE equ 3 + INFLATE_MODE_BAD equ 17 + ENDIF +ENDIF + + +; 75 "inffast.S" +;FILE "inffast.S" + +;;;GLOBAL _inflate_fast + +;;;SECTION .text + + + + .586p + .mmx + + name inflate_fast_x86 + .MODEL FLAT + +_DATA segment +inflate_fast_use_mmx: + dd 1 + + +_TEXT segment + + + +ALIGN 4 + db 'Fast decoding Code from Chris Anderson' + db 0 + +ALIGN 4 +invalid_literal_length_code_msg: + db 'invalid literal/length code' + db 0 + +ALIGN 4 +invalid_distance_code_msg: + db 'invalid distance code' + db 0 + +ALIGN 4 +invalid_distance_too_far_msg: + db 'invalid distance too far back' + db 0 + + +ALIGN 4 +inflate_fast_mask: +dd 0 +dd 1 +dd 3 +dd 7 +dd 15 +dd 31 +dd 63 +dd 127 +dd 255 +dd 511 +dd 1023 +dd 2047 +dd 4095 +dd 8191 +dd 16383 +dd 32767 +dd 65535 +dd 131071 +dd 262143 +dd 524287 +dd 1048575 +dd 2097151 +dd 4194303 +dd 8388607 +dd 16777215 +dd 33554431 +dd 67108863 +dd 134217727 +dd 268435455 +dd 536870911 +dd 1073741823 +dd 2147483647 +dd 4294967295 + + +mode_state equ 0 ;/* state->mode */ +wsize_state equ (32+zlib1222sup) ;/* state->wsize */ +write_state equ (36+4+zlib1222sup) ;/* state->write */ +window_state equ (40+4+zlib1222sup) ;/* state->window */ +hold_state equ (44+4+zlib1222sup) ;/* state->hold */ +bits_state equ (48+4+zlib1222sup) ;/* state->bits */ +lencode_state equ (64+4+zlib1222sup) ;/* state->lencode */ +distcode_state equ (68+4+zlib1222sup) ;/* state->distcode */ +lenbits_state equ (72+4+zlib1222sup) ;/* state->lenbits */ +distbits_state equ (76+4+zlib1222sup) ;/* state->distbits */ + + +;;SECTION .text +; 205 "inffast.S" +;GLOBAL inflate_fast_use_mmx + +;SECTION .data + + +; GLOBAL inflate_fast_use_mmx:object +;.size inflate_fast_use_mmx, 4 +; 226 "inffast.S" +;SECTION .text + +ALIGN 4 +_inflate_fast proc near +.FPO (16, 4, 0, 0, 1, 0) + push edi + push esi + push ebp + push ebx + pushfd + sub esp,64 + cld + + + + + mov esi, [esp+88] + mov edi, [esi+28] + + + + + + + + mov edx, [esi+4] + mov eax, [esi+0] + + add edx,eax + sub edx,11 + + mov [esp+44],eax + mov [esp+20],edx + + mov ebp, [esp+92] + mov ecx, [esi+16] + mov ebx, [esi+12] + + sub ebp,ecx + neg ebp + add ebp,ebx + + sub ecx,257 + add ecx,ebx + + mov [esp+60],ebx + mov [esp+40],ebp + mov [esp+16],ecx +; 285 "inffast.S" + mov eax, [edi+lencode_state] + mov ecx, [edi+distcode_state] + + mov [esp+8],eax + mov [esp+12],ecx + + mov eax,1 + mov ecx, [edi+lenbits_state] + shl eax,cl + dec eax + mov [esp+0],eax + + mov eax,1 + mov ecx, [edi+distbits_state] + shl eax,cl + dec eax + mov [esp+4],eax + + mov eax, [edi+wsize_state] + mov ecx, [edi+write_state] + mov edx, [edi+window_state] + + mov [esp+52],eax + mov [esp+48],ecx + mov [esp+56],edx + + mov ebp, [edi+hold_state] + mov ebx, [edi+bits_state] +; 321 "inffast.S" + mov esi, [esp+44] + mov ecx, [esp+20] + cmp ecx,esi + ja L_align_long + + add ecx,11 + sub ecx,esi + mov eax,12 + sub eax,ecx + lea edi, [esp+28] + rep movsb + mov ecx,eax + xor eax,eax + rep stosb + lea esi, [esp+28] + mov [esp+20],esi + jmp L_is_aligned + + +L_align_long: + test esi,3 + jz L_is_aligned + xor eax,eax + mov al, [esi] + inc esi + mov ecx,ebx + add ebx,8 + shl eax,cl + or ebp,eax + jmp L_align_long + +L_is_aligned: + mov edi, [esp+60] +; 366 "inffast.S" +L_check_mmx: + cmp dword ptr [inflate_fast_use_mmx],2 + je L_init_mmx + ja L_do_loop + + push eax + push ebx + push ecx + push edx + pushfd + mov eax, [esp] + xor dword ptr [esp],0200000h + + + + + popfd + pushfd + pop edx + xor edx,eax + jz L_dont_use_mmx + xor eax,eax + cpuid + cmp ebx,0756e6547h + jne L_dont_use_mmx + cmp ecx,06c65746eh + jne L_dont_use_mmx + cmp edx,049656e69h + jne L_dont_use_mmx + mov eax,1 + cpuid + shr eax,8 + and eax,15 + cmp eax,6 + jne L_dont_use_mmx + test edx,0800000h + jnz L_use_mmx + jmp L_dont_use_mmx +L_use_mmx: + mov dword ptr [inflate_fast_use_mmx],2 + jmp L_check_mmx_pop +L_dont_use_mmx: + mov dword ptr [inflate_fast_use_mmx],3 +L_check_mmx_pop: + pop edx + pop ecx + pop ebx + pop eax + jmp L_check_mmx +; 426 "inffast.S" +ALIGN 4 +L_do_loop: +; 437 "inffast.S" + cmp bl,15 + ja L_get_length_code + + xor eax,eax + lodsw + mov cl,bl + add bl,16 + shl eax,cl + or ebp,eax + +L_get_length_code: + mov edx, [esp+0] + mov ecx, [esp+8] + and edx,ebp + mov eax, [ecx+edx*4] + +L_dolen: + + + + + + + mov cl,ah + sub bl,ah + shr ebp,cl + + + + + + + test al,al + jnz L_test_for_length_base + + shr eax,16 + stosb + +L_while_test: + + + cmp [esp+16],edi + jbe L_break_loop + + cmp [esp+20],esi + ja L_do_loop + jmp L_break_loop + +L_test_for_length_base: +; 502 "inffast.S" + mov edx,eax + shr edx,16 + mov cl,al + + test al,16 + jz L_test_for_second_level_length + and cl,15 + jz L_save_len + cmp bl,cl + jae L_add_bits_to_len + + mov ch,cl + xor eax,eax + lodsw + mov cl,bl + add bl,16 + shl eax,cl + or ebp,eax + mov cl,ch + +L_add_bits_to_len: + mov eax,1 + shl eax,cl + dec eax + sub bl,cl + and eax,ebp + shr ebp,cl + add edx,eax + +L_save_len: + mov [esp+24],edx + + +L_decode_distance: +; 549 "inffast.S" + cmp bl,15 + ja L_get_distance_code + + xor eax,eax + lodsw + mov cl,bl + add bl,16 + shl eax,cl + or ebp,eax + +L_get_distance_code: + mov edx, [esp+4] + mov ecx, [esp+12] + and edx,ebp + mov eax, [ecx+edx*4] + + +L_dodist: + mov edx,eax + shr edx,16 + mov cl,ah + sub bl,ah + shr ebp,cl +; 584 "inffast.S" + mov cl,al + + test al,16 + jz L_test_for_second_level_dist + and cl,15 + jz L_check_dist_one + cmp bl,cl + jae L_add_bits_to_dist + + mov ch,cl + xor eax,eax + lodsw + mov cl,bl + add bl,16 + shl eax,cl + or ebp,eax + mov cl,ch + +L_add_bits_to_dist: + mov eax,1 + shl eax,cl + dec eax + sub bl,cl + and eax,ebp + shr ebp,cl + add edx,eax + jmp L_check_window + +L_check_window: +; 625 "inffast.S" + mov [esp+44],esi + mov eax,edi + sub eax, [esp+40] + + cmp eax,edx + jb L_clip_window + + mov ecx, [esp+24] + mov esi,edi + sub esi,edx + + sub ecx,3 + mov al, [esi] + mov [edi],al + mov al, [esi+1] + mov dl, [esi+2] + add esi,3 + mov [edi+1],al + mov [edi+2],dl + add edi,3 + rep movsb + + mov esi, [esp+44] + jmp L_while_test + +ALIGN 4 +L_check_dist_one: + cmp edx,1 + jne L_check_window + cmp [esp+40],edi + je L_check_window + + dec edi + mov ecx, [esp+24] + mov al, [edi] + sub ecx,3 + + mov [edi+1],al + mov [edi+2],al + mov [edi+3],al + add edi,4 + rep stosb + + jmp L_while_test + +ALIGN 4 +L_test_for_second_level_length: + + + + + test al,64 + jnz L_test_for_end_of_block + + mov eax,1 + shl eax,cl + dec eax + and eax,ebp + add eax,edx + mov edx, [esp+8] + mov eax, [edx+eax*4] + jmp L_dolen + +ALIGN 4 +L_test_for_second_level_dist: + + + + + test al,64 + jnz L_invalid_distance_code + + mov eax,1 + shl eax,cl + dec eax + and eax,ebp + add eax,edx + mov edx, [esp+12] + mov eax, [edx+eax*4] + jmp L_dodist + +ALIGN 4 +L_clip_window: +; 721 "inffast.S" + mov ecx,eax + mov eax, [esp+52] + neg ecx + mov esi, [esp+56] + + cmp eax,edx + jb L_invalid_distance_too_far + + add ecx,edx + cmp dword ptr [esp+48],0 + jne L_wrap_around_window + + sub eax,ecx + add esi,eax +; 749 "inffast.S" + mov eax, [esp+24] + cmp eax,ecx + jbe L_do_copy1 + + sub eax,ecx + rep movsb + mov esi,edi + sub esi,edx + jmp L_do_copy1 + + cmp eax,ecx + jbe L_do_copy1 + + sub eax,ecx + rep movsb + mov esi,edi + sub esi,edx + jmp L_do_copy1 + +L_wrap_around_window: +; 793 "inffast.S" + mov eax, [esp+48] + cmp ecx,eax + jbe L_contiguous_in_window + + add esi, [esp+52] + add esi,eax + sub esi,ecx + sub ecx,eax + + + mov eax, [esp+24] + cmp eax,ecx + jbe L_do_copy1 + + sub eax,ecx + rep movsb + mov esi, [esp+56] + mov ecx, [esp+48] + cmp eax,ecx + jbe L_do_copy1 + + sub eax,ecx + rep movsb + mov esi,edi + sub esi,edx + jmp L_do_copy1 + +L_contiguous_in_window: +; 836 "inffast.S" + add esi,eax + sub esi,ecx + + + mov eax, [esp+24] + cmp eax,ecx + jbe L_do_copy1 + + sub eax,ecx + rep movsb + mov esi,edi + sub esi,edx + +L_do_copy1: +; 862 "inffast.S" + mov ecx,eax + rep movsb + + mov esi, [esp+44] + jmp L_while_test +; 878 "inffast.S" +ALIGN 4 +L_init_mmx: + emms + + + + + + movd mm0,ebp + mov ebp,ebx +; 896 "inffast.S" + movd mm4,dword ptr [esp+0] + movq mm3,mm4 + movd mm5,dword ptr [esp+4] + movq mm2,mm5 + pxor mm1,mm1 + mov ebx, [esp+8] + jmp L_do_loop_mmx + +ALIGN 4 +L_do_loop_mmx: + psrlq mm0,mm1 + + cmp ebp,32 + ja L_get_length_code_mmx + + movd mm6,ebp + movd mm7,dword ptr [esi] + add esi,4 + psllq mm7,mm6 + add ebp,32 + por mm0,mm7 + +L_get_length_code_mmx: + pand mm4,mm0 + movd eax,mm4 + movq mm4,mm3 + mov eax, [ebx+eax*4] + +L_dolen_mmx: + movzx ecx,ah + movd mm1,ecx + sub ebp,ecx + + test al,al + jnz L_test_for_length_base_mmx + + shr eax,16 + stosb + +L_while_test_mmx: + + + cmp [esp+16],edi + jbe L_break_loop + + cmp [esp+20],esi + ja L_do_loop_mmx + jmp L_break_loop + +L_test_for_length_base_mmx: + + mov edx,eax + shr edx,16 + + test al,16 + jz L_test_for_second_level_length_mmx + and eax,15 + jz L_decode_distance_mmx + + psrlq mm0,mm1 + movd mm1,eax + movd ecx,mm0 + sub ebp,eax + and ecx, [inflate_fast_mask+eax*4] + add edx,ecx + +L_decode_distance_mmx: + psrlq mm0,mm1 + + cmp ebp,32 + ja L_get_dist_code_mmx + + movd mm6,ebp + movd mm7,dword ptr [esi] + add esi,4 + psllq mm7,mm6 + add ebp,32 + por mm0,mm7 + +L_get_dist_code_mmx: + mov ebx, [esp+12] + pand mm5,mm0 + movd eax,mm5 + movq mm5,mm2 + mov eax, [ebx+eax*4] + +L_dodist_mmx: + + movzx ecx,ah + mov ebx,eax + shr ebx,16 + sub ebp,ecx + movd mm1,ecx + + test al,16 + jz L_test_for_second_level_dist_mmx + and eax,15 + jz L_check_dist_one_mmx + +L_add_bits_to_dist_mmx: + psrlq mm0,mm1 + movd mm1,eax + movd ecx,mm0 + sub ebp,eax + and ecx, [inflate_fast_mask+eax*4] + add ebx,ecx + +L_check_window_mmx: + mov [esp+44],esi + mov eax,edi + sub eax, [esp+40] + + cmp eax,ebx + jb L_clip_window_mmx + + mov ecx,edx + mov esi,edi + sub esi,ebx + + sub ecx,3 + mov al, [esi] + mov [edi],al + mov al, [esi+1] + mov dl, [esi+2] + add esi,3 + mov [edi+1],al + mov [edi+2],dl + add edi,3 + rep movsb + + mov esi, [esp+44] + mov ebx, [esp+8] + jmp L_while_test_mmx + +ALIGN 4 +L_check_dist_one_mmx: + cmp ebx,1 + jne L_check_window_mmx + cmp [esp+40],edi + je L_check_window_mmx + + dec edi + mov ecx,edx + mov al, [edi] + sub ecx,3 + + mov [edi+1],al + mov [edi+2],al + mov [edi+3],al + add edi,4 + rep stosb + + mov ebx, [esp+8] + jmp L_while_test_mmx + +ALIGN 4 +L_test_for_second_level_length_mmx: + test al,64 + jnz L_test_for_end_of_block + + and eax,15 + psrlq mm0,mm1 + movd ecx,mm0 + and ecx, [inflate_fast_mask+eax*4] + add ecx,edx + mov eax, [ebx+ecx*4] + jmp L_dolen_mmx + +ALIGN 4 +L_test_for_second_level_dist_mmx: + test al,64 + jnz L_invalid_distance_code + + and eax,15 + psrlq mm0,mm1 + movd ecx,mm0 + and ecx, [inflate_fast_mask+eax*4] + mov eax, [esp+12] + add ecx,ebx + mov eax, [eax+ecx*4] + jmp L_dodist_mmx + +ALIGN 4 +L_clip_window_mmx: + + mov ecx,eax + mov eax, [esp+52] + neg ecx + mov esi, [esp+56] + + cmp eax,ebx + jb L_invalid_distance_too_far + + add ecx,ebx + cmp dword ptr [esp+48],0 + jne L_wrap_around_window_mmx + + sub eax,ecx + add esi,eax + + cmp edx,ecx + jbe L_do_copy1_mmx + + sub edx,ecx + rep movsb + mov esi,edi + sub esi,ebx + jmp L_do_copy1_mmx + + cmp edx,ecx + jbe L_do_copy1_mmx + + sub edx,ecx + rep movsb + mov esi,edi + sub esi,ebx + jmp L_do_copy1_mmx + +L_wrap_around_window_mmx: + + mov eax, [esp+48] + cmp ecx,eax + jbe L_contiguous_in_window_mmx + + add esi, [esp+52] + add esi,eax + sub esi,ecx + sub ecx,eax + + + cmp edx,ecx + jbe L_do_copy1_mmx + + sub edx,ecx + rep movsb + mov esi, [esp+56] + mov ecx, [esp+48] + cmp edx,ecx + jbe L_do_copy1_mmx + + sub edx,ecx + rep movsb + mov esi,edi + sub esi,ebx + jmp L_do_copy1_mmx + +L_contiguous_in_window_mmx: + + add esi,eax + sub esi,ecx + + + cmp edx,ecx + jbe L_do_copy1_mmx + + sub edx,ecx + rep movsb + mov esi,edi + sub esi,ebx + +L_do_copy1_mmx: + + + mov ecx,edx + rep movsb + + mov esi, [esp+44] + mov ebx, [esp+8] + jmp L_while_test_mmx +; 1174 "inffast.S" +L_invalid_distance_code: + + + + + + mov ecx, invalid_distance_code_msg + mov edx,INFLATE_MODE_BAD + jmp L_update_stream_state + +L_test_for_end_of_block: + + + + + + test al,32 + jz L_invalid_literal_length_code + + mov ecx,0 + mov edx,INFLATE_MODE_TYPE + jmp L_update_stream_state + +L_invalid_literal_length_code: + + + + + + mov ecx, invalid_literal_length_code_msg + mov edx,INFLATE_MODE_BAD + jmp L_update_stream_state + +L_invalid_distance_too_far: + + + + mov esi, [esp+44] + mov ecx, invalid_distance_too_far_msg + mov edx,INFLATE_MODE_BAD + jmp L_update_stream_state + +L_update_stream_state: + + mov eax, [esp+88] + test ecx,ecx + jz L_skip_msg + mov [eax+24],ecx +L_skip_msg: + mov eax, [eax+28] + mov [eax+mode_state],edx + jmp L_break_loop + +ALIGN 4 +L_break_loop: +; 1243 "inffast.S" + cmp dword ptr [inflate_fast_use_mmx],2 + jne L_update_next_in + + + + mov ebx,ebp + +L_update_next_in: +; 1266 "inffast.S" + mov eax, [esp+88] + mov ecx,ebx + mov edx, [eax+28] + shr ecx,3 + sub esi,ecx + shl ecx,3 + sub ebx,ecx + mov [eax+12],edi + mov [edx+bits_state],ebx + mov ecx,ebx + + lea ebx, [esp+28] + cmp [esp+20],ebx + jne L_buf_not_used + + sub esi,ebx + mov ebx, [eax+0] + mov [esp+20],ebx + add esi,ebx + mov ebx, [eax+4] + sub ebx,11 + add [esp+20],ebx + +L_buf_not_used: + mov [eax+0],esi + + mov ebx,1 + shl ebx,cl + dec ebx + + + + + + cmp dword ptr [inflate_fast_use_mmx],2 + jne L_update_hold + + + + psrlq mm0,mm1 + movd ebp,mm0 + + emms + +L_update_hold: + + + + and ebp,ebx + mov [edx+hold_state],ebp + + + + + mov ebx, [esp+20] + cmp ebx,esi + jbe L_last_is_smaller + + sub ebx,esi + add ebx,11 + mov [eax+4],ebx + jmp L_fixup_out +L_last_is_smaller: + sub esi,ebx + neg esi + add esi,11 + mov [eax+4],esi + + + + +L_fixup_out: + + mov ebx, [esp+16] + cmp ebx,edi + jbe L_end_is_smaller + + sub ebx,edi + add ebx,257 + mov [eax+16],ebx + jmp L_done +L_end_is_smaller: + sub edi,ebx + neg edi + add edi,257 + mov [eax+16],edi + + + + + +L_done: + add esp,64 + popfd + pop ebx + pop ebp + pop esi + pop edi + ret +_inflate_fast endp + +_TEXT ends +end diff --git a/contrib/zlib/contrib/masmx86/match686.asm b/contrib/zlib/contrib/masmx86/match686.asm new file mode 100644 index 00000000..69e0eed0 --- /dev/null +++ b/contrib/zlib/contrib/masmx86/match686.asm @@ -0,0 +1,479 @@ +; match686.asm -- Asm portion of the optimized longest_match for 32 bits x86 +; Copyright (C) 1995-1996 Jean-loup Gailly, Brian Raiter and Gilles Vollant. +; File written by Gilles Vollant, by converting match686.S from Brian Raiter +; for MASM. This is as assembly version of longest_match +; from Jean-loup Gailly in deflate.c +; +; http://www.zlib.net +; http://www.winimage.com/zLibDll +; http://www.muppetlabs.com/~breadbox/software/assembly.html +; +; For Visual C++ 4.x and higher and ML 6.x and higher +; ml.exe is distributed in +; http://www.microsoft.com/downloads/details.aspx?FamilyID=7a1c9da0-0510-44a2-b042-7ef370530c64 +; +; this file contain two implementation of longest_match +; +; this longest_match was written by Brian raiter (1998), optimized for Pentium Pro +; (and the faster known version of match_init on modern Core 2 Duo and AMD Phenom) +; +; for using an assembly version of longest_match, you need define ASMV in project +; +; compile the asm file running +; ml /coff /Zi /c /Flmatch686.lst match686.asm +; and do not include match686.obj in your project +; +; note: contrib of zLib 1.2.3 and earlier contained both a deprecated version for +; Pentium (prior Pentium Pro) and this version for Pentium Pro and modern processor +; with autoselect (with cpu detection code) +; if you want support the old pentium optimization, you can still use these version +; +; this file is not optimized for old pentium, but it compatible with all x86 32 bits +; processor (starting 80386) +; +; +; see below : zlib1222add must be adjuster if you use a zlib version < 1.2.2.2 + +;uInt longest_match(s, cur_match) +; deflate_state *s; +; IPos cur_match; /* current match */ + + NbStack equ 76 + cur_match equ dword ptr[esp+NbStack-0] + str_s equ dword ptr[esp+NbStack-4] +; 5 dword on top (ret,ebp,esi,edi,ebx) + adrret equ dword ptr[esp+NbStack-8] + pushebp equ dword ptr[esp+NbStack-12] + pushedi equ dword ptr[esp+NbStack-16] + pushesi equ dword ptr[esp+NbStack-20] + pushebx equ dword ptr[esp+NbStack-24] + + chain_length equ dword ptr [esp+NbStack-28] + limit equ dword ptr [esp+NbStack-32] + best_len equ dword ptr [esp+NbStack-36] + window equ dword ptr [esp+NbStack-40] + prev equ dword ptr [esp+NbStack-44] + scan_start equ word ptr [esp+NbStack-48] + wmask equ dword ptr [esp+NbStack-52] + match_start_ptr equ dword ptr [esp+NbStack-56] + nice_match equ dword ptr [esp+NbStack-60] + scan equ dword ptr [esp+NbStack-64] + + windowlen equ dword ptr [esp+NbStack-68] + match_start equ dword ptr [esp+NbStack-72] + strend equ dword ptr [esp+NbStack-76] + NbStackAdd equ (NbStack-24) + + .386p + + name gvmatch + .MODEL FLAT + + + +; all the +zlib1222add offsets are due to the addition of fields +; in zlib in the deflate_state structure since the asm code was first written +; (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)"). +; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0"). +; if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8"). + + zlib1222add equ 8 + +; Note : these value are good with a 8 bytes boundary pack structure + dep_chain_length equ 74h+zlib1222add + dep_window equ 30h+zlib1222add + dep_strstart equ 64h+zlib1222add + dep_prev_length equ 70h+zlib1222add + dep_nice_match equ 88h+zlib1222add + dep_w_size equ 24h+zlib1222add + dep_prev equ 38h+zlib1222add + dep_w_mask equ 2ch+zlib1222add + dep_good_match equ 84h+zlib1222add + dep_match_start equ 68h+zlib1222add + dep_lookahead equ 6ch+zlib1222add + + +_TEXT segment + +IFDEF NOUNDERLINE + public longest_match + public match_init +ELSE + public _longest_match + public _match_init +ENDIF + + MAX_MATCH equ 258 + MIN_MATCH equ 3 + MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1) + + + +MAX_MATCH equ 258 +MIN_MATCH equ 3 +MIN_LOOKAHEAD equ (MAX_MATCH + MIN_MATCH + 1) +MAX_MATCH_8_ equ ((MAX_MATCH + 7) AND 0FFF0h) + + +;;; stack frame offsets + +chainlenwmask equ esp + 0 ; high word: current chain len + ; low word: s->wmask +window equ esp + 4 ; local copy of s->window +windowbestlen equ esp + 8 ; s->window + bestlen +scanstart equ esp + 16 ; first two bytes of string +scanend equ esp + 12 ; last two bytes of string +scanalign equ esp + 20 ; dword-misalignment of string +nicematch equ esp + 24 ; a good enough match size +bestlen equ esp + 28 ; size of best match so far +scan equ esp + 32 ; ptr to string wanting match + +LocalVarsSize equ 36 +; saved ebx byte esp + 36 +; saved edi byte esp + 40 +; saved esi byte esp + 44 +; saved ebp byte esp + 48 +; return address byte esp + 52 +deflatestate equ esp + 56 ; the function arguments +curmatch equ esp + 60 + +;;; Offsets for fields in the deflate_state structure. These numbers +;;; are calculated from the definition of deflate_state, with the +;;; assumption that the compiler will dword-align the fields. (Thus, +;;; changing the definition of deflate_state could easily cause this +;;; program to crash horribly, without so much as a warning at +;;; compile time. Sigh.) + +dsWSize equ 36+zlib1222add +dsWMask equ 44+zlib1222add +dsWindow equ 48+zlib1222add +dsPrev equ 56+zlib1222add +dsMatchLen equ 88+zlib1222add +dsPrevMatch equ 92+zlib1222add +dsStrStart equ 100+zlib1222add +dsMatchStart equ 104+zlib1222add +dsLookahead equ 108+zlib1222add +dsPrevLen equ 112+zlib1222add +dsMaxChainLen equ 116+zlib1222add +dsGoodMatch equ 132+zlib1222add +dsNiceMatch equ 136+zlib1222add + + +;;; match686.asm -- Pentium-Pro-optimized version of longest_match() +;;; Written for zlib 1.1.2 +;;; Copyright (C) 1998 Brian Raiter +;;; You can look at http://www.muppetlabs.com/~breadbox/software/assembly.html +;;; +;; +;; This software is provided 'as-is', without any express or implied +;; warranty. In no event will the authors be held liable for any damages +;; arising from the use of this software. +;; +;; Permission is granted to anyone to use this software for any purpose, +;; including commercial applications, and to alter it and redistribute it +;; freely, subject to the following restrictions: +;; +;; 1. The origin of this software must not be misrepresented; you must not +;; claim that you wrote the original software. If you use this software +;; in a product, an acknowledgment in the product documentation would be +;; appreciated but is not required. +;; 2. Altered source versions must be plainly marked as such, and must not be +;; misrepresented as being the original software +;; 3. This notice may not be removed or altered from any source distribution. +;; + +;GLOBAL _longest_match, _match_init + + +;SECTION .text + +;;; uInt longest_match(deflate_state *deflatestate, IPos curmatch) + +;_longest_match: + IFDEF NOUNDERLINE + longest_match proc near + ELSE + _longest_match proc near + ENDIF +.FPO (9, 4, 0, 0, 1, 0) + +;;; Save registers that the compiler may be using, and adjust esp to +;;; make room for our stack frame. + + push ebp + push edi + push esi + push ebx + sub esp, LocalVarsSize + +;;; Retrieve the function arguments. ecx will hold cur_match +;;; throughout the entire function. edx will hold the pointer to the +;;; deflate_state structure during the function's setup (before +;;; entering the main loop. + + mov edx, [deflatestate] + mov ecx, [curmatch] + +;;; uInt wmask = s->w_mask; +;;; unsigned chain_length = s->max_chain_length; +;;; if (s->prev_length >= s->good_match) { +;;; chain_length >>= 2; +;;; } + + mov eax, [edx + dsPrevLen] + mov ebx, [edx + dsGoodMatch] + cmp eax, ebx + mov eax, [edx + dsWMask] + mov ebx, [edx + dsMaxChainLen] + jl LastMatchGood + shr ebx, 2 +LastMatchGood: + +;;; chainlen is decremented once beforehand so that the function can +;;; use the sign flag instead of the zero flag for the exit test. +;;; It is then shifted into the high word, to make room for the wmask +;;; value, which it will always accompany. + + dec ebx + shl ebx, 16 + or ebx, eax + mov [chainlenwmask], ebx + +;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + mov eax, [edx + dsNiceMatch] + mov ebx, [edx + dsLookahead] + cmp ebx, eax + jl LookaheadLess + mov ebx, eax +LookaheadLess: mov [nicematch], ebx + +;;; register Bytef *scan = s->window + s->strstart; + + mov esi, [edx + dsWindow] + mov [window], esi + mov ebp, [edx + dsStrStart] + lea edi, [esi + ebp] + mov [scan], edi + +;;; Determine how many bytes the scan ptr is off from being +;;; dword-aligned. + + mov eax, edi + neg eax + and eax, 3 + mov [scanalign], eax + +;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ? +;;; s->strstart - (IPos)MAX_DIST(s) : NIL; + + mov eax, [edx + dsWSize] + sub eax, MIN_LOOKAHEAD + sub ebp, eax + jg LimitPositive + xor ebp, ebp +LimitPositive: + +;;; int best_len = s->prev_length; + + mov eax, [edx + dsPrevLen] + mov [bestlen], eax + +;;; Store the sum of s->window + best_len in esi locally, and in esi. + + add esi, eax + mov [windowbestlen], esi + +;;; register ush scan_start = *(ushf*)scan; +;;; register ush scan_end = *(ushf*)(scan+best_len-1); +;;; Posf *prev = s->prev; + + movzx ebx, word ptr [edi] + mov [scanstart], ebx + movzx ebx, word ptr [edi + eax - 1] + mov [scanend], ebx + mov edi, [edx + dsPrev] + +;;; Jump into the main loop. + + mov edx, [chainlenwmask] + jmp short LoopEntry + +align 4 + +;;; do { +;;; match = s->window + cur_match; +;;; if (*(ushf*)(match+best_len-1) != scan_end || +;;; *(ushf*)match != scan_start) continue; +;;; [...] +;;; } while ((cur_match = prev[cur_match & wmask]) > limit +;;; && --chain_length != 0); +;;; +;;; Here is the inner loop of the function. The function will spend the +;;; majority of its time in this loop, and majority of that time will +;;; be spent in the first ten instructions. +;;; +;;; Within this loop: +;;; ebx = scanend +;;; ecx = curmatch +;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) +;;; esi = windowbestlen - i.e., (window + bestlen) +;;; edi = prev +;;; ebp = limit + +LookupLoop: + and ecx, edx + movzx ecx, word ptr [edi + ecx*2] + cmp ecx, ebp + jbe LeaveNow + sub edx, 00010000h + js LeaveNow +LoopEntry: movzx eax, word ptr [esi + ecx - 1] + cmp eax, ebx + jnz LookupLoop + mov eax, [window] + movzx eax, word ptr [eax + ecx] + cmp eax, [scanstart] + jnz LookupLoop + +;;; Store the current value of chainlen. + + mov [chainlenwmask], edx + +;;; Point edi to the string under scrutiny, and esi to the string we +;;; are hoping to match it up with. In actuality, esi and edi are +;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is +;;; initialized to -(MAX_MATCH_8 - scanalign). + + mov esi, [window] + mov edi, [scan] + add esi, ecx + mov eax, [scanalign] + mov edx, 0fffffef8h; -(MAX_MATCH_8) + lea edi, [edi + eax + 0108h] ;MAX_MATCH_8] + lea esi, [esi + eax + 0108h] ;MAX_MATCH_8] + +;;; Test the strings for equality, 8 bytes at a time. At the end, +;;; adjust edx so that it is offset to the exact byte that mismatched. +;;; +;;; We already know at this point that the first three bytes of the +;;; strings match each other, and they can be safely passed over before +;;; starting the compare loop. So what this code does is skip over 0-3 +;;; bytes, as much as necessary in order to dword-align the edi +;;; pointer. (esi will still be misaligned three times out of four.) +;;; +;;; It should be confessed that this loop usually does not represent +;;; much of the total running time. Replacing it with a more +;;; straightforward "rep cmpsb" would not drastically degrade +;;; performance. + +LoopCmps: + mov eax, [esi + edx] + xor eax, [edi + edx] + jnz LeaveLoopCmps + mov eax, [esi + edx + 4] + xor eax, [edi + edx + 4] + jnz LeaveLoopCmps4 + add edx, 8 + jnz LoopCmps + jmp short LenMaximum +LeaveLoopCmps4: add edx, 4 +LeaveLoopCmps: test eax, 0000FFFFh + jnz LenLower + add edx, 2 + shr eax, 16 +LenLower: sub al, 1 + adc edx, 0 + +;;; Calculate the length of the match. If it is longer than MAX_MATCH, +;;; then automatically accept it as the best possible match and leave. + + lea eax, [edi + edx] + mov edi, [scan] + sub eax, edi + cmp eax, MAX_MATCH + jge LenMaximum + +;;; If the length of the match is not longer than the best match we +;;; have so far, then forget it and return to the lookup loop. + + mov edx, [deflatestate] + mov ebx, [bestlen] + cmp eax, ebx + jg LongerMatch + mov esi, [windowbestlen] + mov edi, [edx + dsPrev] + mov ebx, [scanend] + mov edx, [chainlenwmask] + jmp LookupLoop + +;;; s->match_start = cur_match; +;;; best_len = len; +;;; if (len >= nice_match) break; +;;; scan_end = *(ushf*)(scan+best_len-1); + +LongerMatch: mov ebx, [nicematch] + mov [bestlen], eax + mov [edx + dsMatchStart], ecx + cmp eax, ebx + jge LeaveNow + mov esi, [window] + add esi, eax + mov [windowbestlen], esi + movzx ebx, word ptr [edi + eax - 1] + mov edi, [edx + dsPrev] + mov [scanend], ebx + mov edx, [chainlenwmask] + jmp LookupLoop + +;;; Accept the current string, with the maximum possible length. + +LenMaximum: mov edx, [deflatestate] + mov dword ptr [bestlen], MAX_MATCH + mov [edx + dsMatchStart], ecx + +;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len; +;;; return s->lookahead; + +LeaveNow: + mov edx, [deflatestate] + mov ebx, [bestlen] + mov eax, [edx + dsLookahead] + cmp ebx, eax + jg LookaheadRet + mov eax, ebx +LookaheadRet: + +;;; Restore the stack and return from whence we came. + + add esp, LocalVarsSize + pop ebx + pop esi + pop edi + pop ebp + + ret +; please don't remove this string ! +; Your can freely use match686 in any free or commercial app if you don't remove the string in the binary! + db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998",0dh,0ah + + + IFDEF NOUNDERLINE + longest_match endp + ELSE + _longest_match endp + ENDIF + + IFDEF NOUNDERLINE + match_init proc near + ret + match_init endp + ELSE + _match_init proc near + ret + _match_init endp + ENDIF + + +_TEXT ends +end diff --git a/contrib/zlib/contrib/masmx86/readme.txt b/contrib/zlib/contrib/masmx86/readme.txt new file mode 100644 index 00000000..3f888867 --- /dev/null +++ b/contrib/zlib/contrib/masmx86/readme.txt @@ -0,0 +1,27 @@ + +Summary +------- +This directory contains ASM implementations of the functions +longest_match() and inflate_fast(). + + +Use instructions +---------------- +Assemble using MASM, and copy the object files into the zlib source +directory, then run the appropriate makefile, as suggested below. You can +donwload MASM from here: + + http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=7a1c9da0-0510-44a2-b042-7ef370530c64 + +You can also get objects files here: + + http://www.winimage.com/zLibDll/zlib124_masm_obj.zip + +Build instructions +------------------ +* With Microsoft C and MASM: +nmake -f win32/Makefile.msc LOC="-DASMV -DASMINF" OBJA="match686.obj inffas32.obj" + +* With Borland C and TASM: +make -f win32/Makefile.bor LOCAL_ZLIB="-DASMV -DASMINF" OBJA="match686.obj inffas32.obj" OBJPA="+match686c.obj+match686.obj+inffas32.obj" + diff --git a/contrib/zlib/contrib/minizip/Makefile b/contrib/zlib/contrib/minizip/Makefile new file mode 100644 index 00000000..84eaad20 --- /dev/null +++ b/contrib/zlib/contrib/minizip/Makefile @@ -0,0 +1,25 @@ +CC=cc +CFLAGS=-O -I../.. + +UNZ_OBJS = miniunz.o unzip.o ioapi.o ../../libz.a +ZIP_OBJS = minizip.o zip.o ioapi.o ../../libz.a + +.c.o: + $(CC) -c $(CFLAGS) $*.c + +all: miniunz minizip + +miniunz: $(UNZ_OBJS) + $(CC) $(CFLAGS) -o $@ $(UNZ_OBJS) + +minizip: $(ZIP_OBJS) + $(CC) $(CFLAGS) -o $@ $(ZIP_OBJS) + +test: miniunz minizip + ./minizip test readme.txt + ./miniunz -l test.zip + mv readme.txt readme.old + ./miniunz test.zip + +clean: + /bin/rm -f *.o *~ minizip miniunz diff --git a/contrib/zlib/contrib/minizip/Makefile.am b/contrib/zlib/contrib/minizip/Makefile.am new file mode 100644 index 00000000..d343011e --- /dev/null +++ b/contrib/zlib/contrib/minizip/Makefile.am @@ -0,0 +1,45 @@ +lib_LTLIBRARIES = libminizip.la + +if COND_DEMOS +bin_PROGRAMS = miniunzip minizip +endif + +zlib_top_srcdir = $(top_srcdir)/../.. +zlib_top_builddir = $(top_builddir)/../.. + +AM_CPPFLAGS = -I$(zlib_top_srcdir) +AM_LDFLAGS = -L$(zlib_top_builddir) + +if WIN32 +iowin32_src = iowin32.c +iowin32_h = iowin32.h +endif + +libminizip_la_SOURCES = \ + ioapi.c \ + mztools.c \ + unzip.c \ + zip.c \ + ${iowin32_src} + +libminizip_la_LDFLAGS = $(AM_LDFLAGS) -version-info 1:0:0 -lz + +minizip_includedir = $(includedir)/minizip +minizip_include_HEADERS = \ + crypt.h \ + ioapi.h \ + mztools.h \ + unzip.h \ + zip.h \ + ${iowin32_h} + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = minizip.pc + +EXTRA_PROGRAMS = miniunzip minizip + +miniunzip_SOURCES = miniunz.c +miniunzip_LDADD = libminizip.la + +minizip_SOURCES = minizip.c +minizip_LDADD = libminizip.la -lz diff --git a/contrib/zlib/contrib/minizip/MiniZip64_Changes.txt b/contrib/zlib/contrib/minizip/MiniZip64_Changes.txt new file mode 100644 index 00000000..13a1bd91 --- /dev/null +++ b/contrib/zlib/contrib/minizip/MiniZip64_Changes.txt @@ -0,0 +1,6 @@ + +MiniZip 1.1 was derrived from MiniZip at version 1.01f + +Change in 1.0 (Okt 2009) + - **TODO - Add history** + diff --git a/contrib/zlib/contrib/minizip/MiniZip64_info.txt b/contrib/zlib/contrib/minizip/MiniZip64_info.txt new file mode 100644 index 00000000..57d71524 --- /dev/null +++ b/contrib/zlib/contrib/minizip/MiniZip64_info.txt @@ -0,0 +1,74 @@ +MiniZip - Copyright (c) 1998-2010 - by Gilles Vollant - version 1.1 64 bits from Mathias Svensson + +Introduction +--------------------- +MiniZip 1.1 is built from MiniZip 1.0 by Gilles Vollant ( http://www.winimage.com/zLibDll/minizip.html ) + +When adding ZIP64 support into minizip it would result into risk of breaking compatibility with minizip 1.0. +All possible work was done for compatibility. + + +Background +--------------------- +When adding ZIP64 support Mathias Svensson found that Even Rouault have added ZIP64 +support for unzip.c into minizip for a open source project called gdal ( http://www.gdal.org/ ) + +That was used as a starting point. And after that ZIP64 support was added to zip.c +some refactoring and code cleanup was also done. + + +Changed from MiniZip 1.0 to MiniZip 1.1 +--------------------------------------- +* Added ZIP64 support for unzip ( by Even Rouault ) +* Added ZIP64 support for zip ( by Mathias Svensson ) +* Reverted some changed that Even Rouault did. +* Bunch of patches received from Gulles Vollant that he received for MiniZip from various users. +* Added unzip patch for BZIP Compression method (patch create by Daniel Borca) +* Added BZIP Compress method for zip +* Did some refactoring and code cleanup + + +Credits + + Gilles Vollant - Original MiniZip author + Even Rouault - ZIP64 unzip Support + Daniel Borca - BZip Compression method support in unzip + Mathias Svensson - ZIP64 zip support + Mathias Svensson - BZip Compression method support in zip + + Resources + + ZipLayout http://result42.com/projects/ZipFileLayout + Command line tool for Windows that shows the layout and information of the headers in a zip archive. + Used when debugging and validating the creation of zip files using MiniZip64 + + + ZIP App Note http://www.pkware.com/documents/casestudies/APPNOTE.TXT + Zip File specification + + +Notes. + * To be able to use BZip compression method in zip64.c or unzip64.c the BZIP2 lib is needed and HAVE_BZIP2 need to be defined. + +License +---------------------------------------------------------- + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + +---------------------------------------------------------- + diff --git a/contrib/zlib/contrib/minizip/configure.ac b/contrib/zlib/contrib/minizip/configure.ac new file mode 100644 index 00000000..5b119709 --- /dev/null +++ b/contrib/zlib/contrib/minizip/configure.ac @@ -0,0 +1,32 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_INIT([minizip], [1.2.11], [bugzilla.redhat.com]) +AC_CONFIG_SRCDIR([minizip.c]) +AM_INIT_AUTOMAKE([foreign]) +LT_INIT + +AC_MSG_CHECKING([whether to build example programs]) +AC_ARG_ENABLE([demos], AC_HELP_STRING([--enable-demos], [build example programs])) +AM_CONDITIONAL([COND_DEMOS], [test "$enable_demos" = yes]) +if test "$enable_demos" = yes +then + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + +case "${host}" in + *-mingw* | mingw*) + WIN32="yes" + ;; + *) + ;; +esac +AM_CONDITIONAL([WIN32], [test "${WIN32}" = "yes"]) + + +AC_SUBST([HAVE_UNISTD_H], [0]) +AC_CHECK_HEADER([unistd.h], [HAVE_UNISTD_H=1], []) +AC_CONFIG_FILES([Makefile minizip.pc]) +AC_OUTPUT diff --git a/contrib/zlib/contrib/minizip/crypt.h b/contrib/zlib/contrib/minizip/crypt.h new file mode 100644 index 00000000..1e9e8200 --- /dev/null +++ b/contrib/zlib/contrib/minizip/crypt.h @@ -0,0 +1,131 @@ +/* crypt.h -- base code for crypt/uncrypt ZIPfile + + + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + + This code is a modified version of crypting code in Infozip distribution + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + If you don't need crypting in your application, just define symbols + NOCRYPT and NOUNCRYPT. + + This code support the "Traditional PKWARE Encryption". + + The new AES encryption added on Zip format by Winzip (see the page + http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong + Encryption is not supported. +*/ + +#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) + +/*********************************************************************** + * Return the next byte in the pseudo-random sequence + */ +static int decrypt_byte(unsigned long* pkeys, const z_crc_t* pcrc_32_tab) +{ + unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an + * unpredictable manner on 16-bit systems; not a problem + * with any known compiler so far, though */ + + temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; + return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); +} + +/*********************************************************************** + * Update the encryption keys with the next byte of plain text + */ +static int update_keys(unsigned long* pkeys,const z_crc_t* pcrc_32_tab,int c) +{ + (*(pkeys+0)) = CRC32((*(pkeys+0)), c); + (*(pkeys+1)) += (*(pkeys+0)) & 0xff; + (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; + { + register int keyshift = (int)((*(pkeys+1)) >> 24); + (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); + } + return c; +} + + +/*********************************************************************** + * Initialize the encryption keys and the random header according to + * the given password. + */ +static void init_keys(const char* passwd,unsigned long* pkeys,const z_crc_t* pcrc_32_tab) +{ + *(pkeys+0) = 305419896L; + *(pkeys+1) = 591751049L; + *(pkeys+2) = 878082192L; + while (*passwd != '\0') { + update_keys(pkeys,pcrc_32_tab,(int)*passwd); + passwd++; + } +} + +#define zdecode(pkeys,pcrc_32_tab,c) \ + (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) + +#define zencode(pkeys,pcrc_32_tab,c,t) \ + (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) + +#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED + +#define RAND_HEAD_LEN 12 + /* "last resort" source for second part of crypt seed pattern */ +# ifndef ZCR_SEED2 +# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ +# endif + +static int crypthead(const char* passwd, /* password string */ + unsigned char* buf, /* where to write header */ + int bufSize, + unsigned long* pkeys, + const z_crc_t* pcrc_32_tab, + unsigned long crcForCrypting) +{ + int n; /* index in random header */ + int t; /* temporary */ + int c; /* random byte */ + unsigned char header[RAND_HEAD_LEN-2]; /* random header */ + static unsigned calls = 0; /* ensure different random header each time */ + + if (bufSize> 7) & 0xff; + header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); + } + /* Encrypt random header (last two bytes is high word of crc) */ + init_keys(passwd, pkeys, pcrc_32_tab); + for (n = 0; n < RAND_HEAD_LEN-2; n++) + { + buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); + } + buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); + buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); + return n; +} + +#endif diff --git a/contrib/zlib/contrib/minizip/ioapi.c b/contrib/zlib/contrib/minizip/ioapi.c new file mode 100644 index 00000000..7f5c191b --- /dev/null +++ b/contrib/zlib/contrib/minizip/ioapi.c @@ -0,0 +1,247 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + +*/ + +#if defined(_WIN32) && (!(defined(_CRT_SECURE_NO_WARNINGS))) + #define _CRT_SECURE_NO_WARNINGS +#endif + +#if defined(__APPLE__) || defined(IOAPI_NO_64) +// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions +#define FOPEN_FUNC(filename, mode) fopen(filename, mode) +#define FTELLO_FUNC(stream) ftello(stream) +#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin) +#else +#define FOPEN_FUNC(filename, mode) fopen64(filename, mode) +#define FTELLO_FUNC(stream) ftello64(stream) +#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin) +#endif + + +#include "ioapi.h" + +voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) +{ + if (pfilefunc->zfile_func64.zopen64_file != NULL) + return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); + else + { + return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode); + } +} + +long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); + else + { + uLong offsetTruncated = (uLong)offset; + if (offsetTruncated != offset) + return -1; + else + return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); + } +} + +ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); + else + { + uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); + if ((tell_uLong) == MAXU32) + return (ZPOS64_T)-1; + else + return tell_uLong; + } +} + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) +{ + p_filefunc64_32->zfile_func64.zopen64_file = NULL; + p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; + p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; + p_filefunc64_32->zfile_func64.ztell64_file = NULL; + p_filefunc64_32->zfile_func64.zseek64_file = NULL; + p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; + p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; + p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; +} + + + +static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); +static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size)); +static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); +static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); +static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); + +static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = fopen(filename, mode_fopen); + return file; +} + +static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = FOPEN_FUNC((const char*)filename, mode_fopen); + return file; +} + + +static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) +{ + long ret; + ret = ftell((FILE *)stream); + return ret; +} + + +static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) +{ + ZPOS64_T ret; + ret = FTELLO_FUNC((FILE *)stream); + return ret; +} + +static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin) +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + if (fseek((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + return ret; +} + +static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + + if(FSEEKO_FUNC((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + + return ret; +} + + +static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = fclose((FILE *)stream); + return ret; +} + +static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = ferror((FILE *)stream); + return ret; +} + +void fill_fopen_filefunc (pzlib_filefunc_def) + zlib_filefunc_def* pzlib_filefunc_def; +{ + pzlib_filefunc_def->zopen_file = fopen_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell_file = ftell_file_func; + pzlib_filefunc_def->zseek_file = fseek_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} + +void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = fopen64_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell64_file = ftell64_file_func; + pzlib_filefunc_def->zseek64_file = fseek64_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} diff --git a/contrib/zlib/contrib/minizip/ioapi.h b/contrib/zlib/contrib/minizip/ioapi.h new file mode 100644 index 00000000..8dcbdb06 --- /dev/null +++ b/contrib/zlib/contrib/minizip/ioapi.h @@ -0,0 +1,208 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + Changes + + Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this) + Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux. + More if/def section may be needed to support other platforms + Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows. + (but you should use iowin32.c for windows instead) + +*/ + +#ifndef _ZLIBIOAPI64_H +#define _ZLIBIOAPI64_H + +#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) + + // Linux needs this to support file operation on files larger then 4+GB + // But might need better if/def to select just the platforms that needs them. + + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif + +#endif + +#include +#include +#include "zlib.h" + +#if defined(USE_FILE32API) +#define fopen64 fopen +#define ftello64 ftell +#define fseeko64 fseek +#else +#ifdef __FreeBSD__ +#define fopen64 fopen +#define ftello64 ftello +#define fseeko64 fseeko +#endif +#ifdef _MSC_VER + #define fopen64 fopen + #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) + #define ftello64 _ftelli64 + #define fseeko64 _fseeki64 + #else // old MSC + #define ftello64 ftell + #define fseeko64 fseek + #endif +#endif +#endif + +/* +#ifndef ZPOS64_T + #ifdef _WIN32 + #define ZPOS64_T fpos_t + #else + #include + #define ZPOS64_T uint64_t + #endif +#endif +*/ + +#ifdef HAVE_MINIZIP64_CONF_H +#include "mz64conf.h" +#endif + +/* a type choosen by DEFINE */ +#ifdef HAVE_64BIT_INT_CUSTOM +typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; +#else +#ifdef HAS_STDINT_H +#include "stdint.h" +typedef uint64_t ZPOS64_T; +#else + +/* Maximum unsigned 32-bit value used as placeholder for zip64 */ +#define MAXU32 0xffffffff + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef unsigned __int64 ZPOS64_T; +#else +typedef unsigned long long int ZPOS64_T; +#endif +#endif +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) + +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + + +#ifndef ZCALLBACK + #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) + #define ZCALLBACK CALLBACK + #else + #define ZCALLBACK + #endif +#endif + + + + +typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); +typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + +typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); + + +/* here is the "old" 32 bits structure structure */ +typedef struct zlib_filefunc_def_s +{ + open_file_func zopen_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc_def; + +typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); + +typedef struct zlib_filefunc64_def_s +{ + open64_file_func zopen64_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell64_file_func ztell64_file; + seek64_file_func zseek64_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc64_def; + +void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +/* now internal definition, only for zip.c and unzip.h */ +typedef struct zlib_filefunc64_32_def_s +{ + zlib_filefunc64_def zfile_func64; + open_file_func zopen32_file; + tell_file_func ztell32_file; + seek_file_func zseek32_file; +} zlib_filefunc64_32_def; + + +#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) +//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) +#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) + +voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); +long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); +ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); + +#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) +#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) +#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/zlib/contrib/minizip/iowin32.c b/contrib/zlib/contrib/minizip/iowin32.c new file mode 100644 index 00000000..274f39eb --- /dev/null +++ b/contrib/zlib/contrib/minizip/iowin32.c @@ -0,0 +1,462 @@ +/* iowin32.c -- IO base function header for compress/uncompress .zip + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + +*/ + +#include + +#include "zlib.h" +#include "ioapi.h" +#include "iowin32.h" + +#ifndef INVALID_HANDLE_VALUE +#define INVALID_HANDLE_VALUE (0xFFFFFFFF) +#endif + +#ifndef INVALID_SET_FILE_POINTER +#define INVALID_SET_FILE_POINTER ((DWORD)-1) +#endif + + +// see Include/shared/winapifamily.h in the Windows Kit +#if defined(WINAPI_FAMILY_PARTITION) && (!(defined(IOWIN32_USING_WINRT_API))) +#if WINAPI_FAMILY_ONE_PARTITION(WINAPI_FAMILY, WINAPI_PARTITION_APP) +#define IOWIN32_USING_WINRT_API 1 +#endif +#endif + +voidpf ZCALLBACK win32_open_file_func OF((voidpf opaque, const char* filename, int mode)); +uLong ZCALLBACK win32_read_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +uLong ZCALLBACK win32_write_file_func OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +ZPOS64_T ZCALLBACK win32_tell64_file_func OF((voidpf opaque, voidpf stream)); +long ZCALLBACK win32_seek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +int ZCALLBACK win32_close_file_func OF((voidpf opaque, voidpf stream)); +int ZCALLBACK win32_error_file_func OF((voidpf opaque, voidpf stream)); + +typedef struct +{ + HANDLE hf; + int error; +} WIN32FILE_IOWIN; + + +static void win32_translate_open_mode(int mode, + DWORD* lpdwDesiredAccess, + DWORD* lpdwCreationDisposition, + DWORD* lpdwShareMode, + DWORD* lpdwFlagsAndAttributes) +{ + *lpdwDesiredAccess = *lpdwShareMode = *lpdwFlagsAndAttributes = *lpdwCreationDisposition = 0; + + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + { + *lpdwDesiredAccess = GENERIC_READ; + *lpdwCreationDisposition = OPEN_EXISTING; + *lpdwShareMode = FILE_SHARE_READ; + } + else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + { + *lpdwDesiredAccess = GENERIC_WRITE | GENERIC_READ; + *lpdwCreationDisposition = OPEN_EXISTING; + } + else if (mode & ZLIB_FILEFUNC_MODE_CREATE) + { + *lpdwDesiredAccess = GENERIC_WRITE | GENERIC_READ; + *lpdwCreationDisposition = CREATE_ALWAYS; + } +} + +static voidpf win32_build_iowin(HANDLE hFile) +{ + voidpf ret=NULL; + + if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE)) + { + WIN32FILE_IOWIN w32fiow; + w32fiow.hf = hFile; + w32fiow.error = 0; + ret = malloc(sizeof(WIN32FILE_IOWIN)); + + if (ret==NULL) + CloseHandle(hFile); + else + *((WIN32FILE_IOWIN*)ret) = w32fiow; + } + return ret; +} + +voidpf ZCALLBACK win32_open64_file_func (voidpf opaque,const void* filename,int mode) +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = NULL; + + win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); + +#ifdef IOWIN32_USING_WINRT_API +#ifdef UNICODE + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFile2((LPCTSTR)filename, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL); +#else + if ((filename!=NULL) && (dwDesiredAccess != 0)) + { + WCHAR filenameW[FILENAME_MAX + 0x200 + 1]; + MultiByteToWideChar(CP_ACP,0,(const char*)filename,-1,filenameW,FILENAME_MAX + 0x200); + hFile = CreateFile2(filenameW, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL); + } +#endif +#else + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); +#endif + + return win32_build_iowin(hFile); +} + + +voidpf ZCALLBACK win32_open64_file_funcA (voidpf opaque,const void* filename,int mode) +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = NULL; + + win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); + +#ifdef IOWIN32_USING_WINRT_API + if ((filename!=NULL) && (dwDesiredAccess != 0)) + { + WCHAR filenameW[FILENAME_MAX + 0x200 + 1]; + MultiByteToWideChar(CP_ACP,0,(const char*)filename,-1,filenameW,FILENAME_MAX + 0x200); + hFile = CreateFile2(filenameW, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL); + } +#else + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFileA((LPCSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); +#endif + + return win32_build_iowin(hFile); +} + + +voidpf ZCALLBACK win32_open64_file_funcW (voidpf opaque,const void* filename,int mode) +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = NULL; + + win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); + +#ifdef IOWIN32_USING_WINRT_API + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFile2((LPCWSTR)filename, dwDesiredAccess, dwShareMode, dwCreationDisposition,NULL); +#else + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFileW((LPCWSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); +#endif + + return win32_build_iowin(hFile); +} + + +voidpf ZCALLBACK win32_open_file_func (voidpf opaque,const char* filename,int mode) +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = NULL; + + win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); + +#ifdef IOWIN32_USING_WINRT_API +#ifdef UNICODE + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFile2((LPCTSTR)filename, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL); +#else + if ((filename!=NULL) && (dwDesiredAccess != 0)) + { + WCHAR filenameW[FILENAME_MAX + 0x200 + 1]; + MultiByteToWideChar(CP_ACP,0,(const char*)filename,-1,filenameW,FILENAME_MAX + 0x200); + hFile = CreateFile2(filenameW, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL); + } +#endif +#else + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); +#endif + + return win32_build_iowin(hFile); +} + + +uLong ZCALLBACK win32_read_file_func (voidpf opaque, voidpf stream, void* buf,uLong size) +{ + uLong ret=0; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + + if (hFile != NULL) + { + if (!ReadFile(hFile, buf, size, &ret, NULL)) + { + DWORD dwErr = GetLastError(); + if (dwErr == ERROR_HANDLE_EOF) + dwErr = 0; + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + } + } + + return ret; +} + + +uLong ZCALLBACK win32_write_file_func (voidpf opaque,voidpf stream,const void* buf,uLong size) +{ + uLong ret=0; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + + if (hFile != NULL) + { + if (!WriteFile(hFile, buf, size, &ret, NULL)) + { + DWORD dwErr = GetLastError(); + if (dwErr == ERROR_HANDLE_EOF) + dwErr = 0; + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + } + } + + return ret; +} + +static BOOL MySetFilePointerEx(HANDLE hFile, LARGE_INTEGER pos, LARGE_INTEGER *newPos, DWORD dwMoveMethod) +{ +#ifdef IOWIN32_USING_WINRT_API + return SetFilePointerEx(hFile, pos, newPos, dwMoveMethod); +#else + LONG lHigh = pos.HighPart; + DWORD dwNewPos = SetFilePointer(hFile, pos.LowPart, &lHigh, dwMoveMethod); + BOOL fOk = TRUE; + if (dwNewPos == 0xFFFFFFFF) + if (GetLastError() != NO_ERROR) + fOk = FALSE; + if ((newPos != NULL) && (fOk)) + { + newPos->LowPart = dwNewPos; + newPos->HighPart = lHigh; + } + return fOk; +#endif +} + +long ZCALLBACK win32_tell_file_func (voidpf opaque,voidpf stream) +{ + long ret=-1; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + if (hFile != NULL) + { + LARGE_INTEGER pos; + pos.QuadPart = 0; + + if (!MySetFilePointerEx(hFile, pos, &pos, FILE_CURRENT)) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = -1; + } + else + ret=(long)pos.LowPart; + } + return ret; +} + +ZPOS64_T ZCALLBACK win32_tell64_file_func (voidpf opaque, voidpf stream) +{ + ZPOS64_T ret= (ZPOS64_T)-1; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream)->hf; + + if (hFile) + { + LARGE_INTEGER pos; + pos.QuadPart = 0; + + if (!MySetFilePointerEx(hFile, pos, &pos, FILE_CURRENT)) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = (ZPOS64_T)-1; + } + else + ret=pos.QuadPart; + } + return ret; +} + + +long ZCALLBACK win32_seek_file_func (voidpf opaque,voidpf stream,uLong offset,int origin) +{ + DWORD dwMoveMethod=0xFFFFFFFF; + HANDLE hFile = NULL; + + long ret=-1; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + dwMoveMethod = FILE_CURRENT; + break; + case ZLIB_FILEFUNC_SEEK_END : + dwMoveMethod = FILE_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + dwMoveMethod = FILE_BEGIN; + break; + default: return -1; + } + + if (hFile != NULL) + { + LARGE_INTEGER pos; + pos.QuadPart = offset; + if (!MySetFilePointerEx(hFile, pos, NULL, dwMoveMethod)) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = -1; + } + else + ret=0; + } + return ret; +} + +long ZCALLBACK win32_seek64_file_func (voidpf opaque, voidpf stream,ZPOS64_T offset,int origin) +{ + DWORD dwMoveMethod=0xFFFFFFFF; + HANDLE hFile = NULL; + long ret=-1; + + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream)->hf; + + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + dwMoveMethod = FILE_CURRENT; + break; + case ZLIB_FILEFUNC_SEEK_END : + dwMoveMethod = FILE_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + dwMoveMethod = FILE_BEGIN; + break; + default: return -1; + } + + if (hFile) + { + LARGE_INTEGER pos; + pos.QuadPart = offset; + if (!MySetFilePointerEx(hFile, pos, NULL, dwMoveMethod)) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = -1; + } + else + ret=0; + } + return ret; +} + +int ZCALLBACK win32_close_file_func (voidpf opaque, voidpf stream) +{ + int ret=-1; + + if (stream!=NULL) + { + HANDLE hFile; + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + if (hFile != NULL) + { + CloseHandle(hFile); + ret=0; + } + free(stream); + } + return ret; +} + +int ZCALLBACK win32_error_file_func (voidpf opaque,voidpf stream) +{ + int ret=-1; + if (stream!=NULL) + { + ret = ((WIN32FILE_IOWIN*)stream) -> error; + } + return ret; +} + +void fill_win32_filefunc (zlib_filefunc_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen_file = win32_open_file_func; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell_file = win32_tell_file_func; + pzlib_filefunc_def->zseek_file = win32_seek_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} + +void fill_win32_filefunc64(zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = win32_open64_file_func; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell64_file = win32_tell64_file_func; + pzlib_filefunc_def->zseek64_file = win32_seek64_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} + + +void fill_win32_filefunc64A(zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = win32_open64_file_funcA; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell64_file = win32_tell64_file_func; + pzlib_filefunc_def->zseek64_file = win32_seek64_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} + + +void fill_win32_filefunc64W(zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = win32_open64_file_funcW; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell64_file = win32_tell64_file_func; + pzlib_filefunc_def->zseek64_file = win32_seek64_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} diff --git a/contrib/zlib/contrib/minizip/iowin32.h b/contrib/zlib/contrib/minizip/iowin32.h new file mode 100644 index 00000000..0ca0969a --- /dev/null +++ b/contrib/zlib/contrib/minizip/iowin32.h @@ -0,0 +1,28 @@ +/* iowin32.h -- IO base function header for compress/uncompress .zip + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + +*/ + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +void fill_win32_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); +void fill_win32_filefunc64 OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_win32_filefunc64A OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_win32_filefunc64W OF((zlib_filefunc64_def* pzlib_filefunc_def)); + +#ifdef __cplusplus +} +#endif diff --git a/contrib/zlib/contrib/minizip/make_vms.com b/contrib/zlib/contrib/minizip/make_vms.com new file mode 100644 index 00000000..9ac13a98 --- /dev/null +++ b/contrib/zlib/contrib/minizip/make_vms.com @@ -0,0 +1,25 @@ +$ if f$search("ioapi.h_orig") .eqs. "" then copy ioapi.h ioapi.h_orig +$ open/write zdef vmsdefs.h +$ copy sys$input: zdef +$ deck +#define unix +#define fill_zlib_filefunc64_32_def_from_filefunc32 fillzffunc64from +#define Write_Zip64EndOfCentralDirectoryLocator Write_Zip64EoDLocator +#define Write_Zip64EndOfCentralDirectoryRecord Write_Zip64EoDRecord +#define Write_EndOfCentralDirectoryRecord Write_EoDRecord +$ eod +$ close zdef +$ copy vmsdefs.h,ioapi.h_orig ioapi.h +$ cc/include=[--]/prefix=all ioapi.c +$ cc/include=[--]/prefix=all miniunz.c +$ cc/include=[--]/prefix=all unzip.c +$ cc/include=[--]/prefix=all minizip.c +$ cc/include=[--]/prefix=all zip.c +$ link miniunz,unzip,ioapi,[--]libz.olb/lib +$ link minizip,zip,ioapi,[--]libz.olb/lib +$ mcr []minizip test minizip_info.txt +$ mcr []miniunz -l test.zip +$ rename minizip_info.txt; minizip_info.txt_old +$ mcr []miniunz test.zip +$ delete test.zip;* +$exit diff --git a/contrib/zlib/contrib/minizip/miniunz.c b/contrib/zlib/contrib/minizip/miniunz.c new file mode 100644 index 00000000..3d65401b --- /dev/null +++ b/contrib/zlib/contrib/minizip/miniunz.c @@ -0,0 +1,660 @@ +/* + miniunz.c + Version 1.1, February 14h, 2010 + sample part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) +*/ + +#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif +#endif + +#ifdef __APPLE__ +// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions +#define FOPEN_FUNC(filename, mode) fopen(filename, mode) +#define FTELLO_FUNC(stream) ftello(stream) +#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin) +#else +#define FOPEN_FUNC(filename, mode) fopen64(filename, mode) +#define FTELLO_FUNC(stream) ftello64(stream) +#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin) +#endif + + +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +# include +# include +#else +# include +# include +#endif + + +#include "unzip.h" + +#define CASESENSITIVITY (0) +#define WRITEBUFFERSIZE (8192) +#define MAXFILENAME (256) + +#ifdef _WIN32 +#define USEWIN32IOAPI +#include "iowin32.h" +#endif +/* + mini unzip, demo of unzip package + + usage : + Usage : miniunz [-exvlo] file.zip [file_to_extract] [-d extractdir] + + list the file in the zipfile, and print the content of FILE_ID.ZIP or README.TXT + if it exists +*/ + + +/* change_file_date : change the date/time of a file + filename : the filename of the file where date/time must be modified + dosdate : the new date at the MSDos format (4 bytes) + tmu_date : the SAME new date at the tm_unz format */ +void change_file_date(filename,dosdate,tmu_date) + const char *filename; + uLong dosdate; + tm_unz tmu_date; +{ +#ifdef _WIN32 + HANDLE hFile; + FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite; + + hFile = CreateFileA(filename,GENERIC_READ | GENERIC_WRITE, + 0,NULL,OPEN_EXISTING,0,NULL); + GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite); + DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal); + LocalFileTimeToFileTime(&ftLocal,&ftm); + SetFileTime(hFile,&ftm,&ftLastAcc,&ftm); + CloseHandle(hFile); +#else +#ifdef unix || __APPLE__ + struct utimbuf ut; + struct tm newdate; + newdate.tm_sec = tmu_date.tm_sec; + newdate.tm_min=tmu_date.tm_min; + newdate.tm_hour=tmu_date.tm_hour; + newdate.tm_mday=tmu_date.tm_mday; + newdate.tm_mon=tmu_date.tm_mon; + if (tmu_date.tm_year > 1900) + newdate.tm_year=tmu_date.tm_year - 1900; + else + newdate.tm_year=tmu_date.tm_year ; + newdate.tm_isdst=-1; + + ut.actime=ut.modtime=mktime(&newdate); + utime(filename,&ut); +#endif +#endif +} + + +/* mymkdir and change_file_date are not 100 % portable + As I don't know well Unix, I wait feedback for the unix portion */ + +int mymkdir(dirname) + const char* dirname; +{ + int ret=0; +#ifdef _WIN32 + ret = _mkdir(dirname); +#elif unix + ret = mkdir (dirname,0775); +#elif __APPLE__ + ret = mkdir (dirname,0775); +#endif + return ret; +} + +int makedir (newdir) + char *newdir; +{ + char *buffer ; + char *p; + int len = (int)strlen(newdir); + + if (len <= 0) + return 0; + + buffer = (char*)malloc(len+1); + if (buffer==NULL) + { + printf("Error allocating memory\n"); + return UNZ_INTERNALERROR; + } + strcpy(buffer,newdir); + + if (buffer[len-1] == '/') { + buffer[len-1] = '\0'; + } + if (mymkdir(buffer) == 0) + { + free(buffer); + return 1; + } + + p = buffer+1; + while (1) + { + char hold; + + while(*p && *p != '\\' && *p != '/') + p++; + hold = *p; + *p = 0; + if ((mymkdir(buffer) == -1) && (errno == ENOENT)) + { + printf("couldn't create directory %s\n",buffer); + free(buffer); + return 0; + } + if (hold == 0) + break; + *p++ = hold; + } + free(buffer); + return 1; +} + +void do_banner() +{ + printf("MiniUnz 1.01b, demo of zLib + Unz package written by Gilles Vollant\n"); + printf("more info at http://www.winimage.com/zLibDll/unzip.html\n\n"); +} + +void do_help() +{ + printf("Usage : miniunz [-e] [-x] [-v] [-l] [-o] [-p password] file.zip [file_to_extr.] [-d extractdir]\n\n" \ + " -e Extract without pathname (junk paths)\n" \ + " -x Extract with pathname\n" \ + " -v list files\n" \ + " -l list files\n" \ + " -d directory to extract into\n" \ + " -o overwrite files without prompting\n" \ + " -p extract crypted file using password\n\n"); +} + +void Display64BitsSize(ZPOS64_T n, int size_char) +{ + /* to avoid compatibility problem , we do here the conversion */ + char number[21]; + int offset=19; + int pos_string = 19; + number[20]=0; + for (;;) { + number[offset]=(char)((n%10)+'0'); + if (number[offset] != '0') + pos_string=offset; + n/=10; + if (offset==0) + break; + offset--; + } + { + int size_display_string = 19-pos_string; + while (size_char > size_display_string) + { + size_char--; + printf(" "); + } + } + + printf("%s",&number[pos_string]); +} + +int do_list(uf) + unzFile uf; +{ + uLong i; + unz_global_info64 gi; + int err; + + err = unzGetGlobalInfo64(uf,&gi); + if (err!=UNZ_OK) + printf("error %d with zipfile in unzGetGlobalInfo \n",err); + printf(" Length Method Size Ratio Date Time CRC-32 Name\n"); + printf(" ------ ------ ---- ----- ---- ---- ------ ----\n"); + for (i=0;i0) + ratio = (uLong)((file_info.compressed_size*100)/file_info.uncompressed_size); + + /* display a '*' if the file is crypted */ + if ((file_info.flag & 1) != 0) + charCrypt='*'; + + if (file_info.compression_method==0) + string_method="Stored"; + else + if (file_info.compression_method==Z_DEFLATED) + { + uInt iLevel=(uInt)((file_info.flag & 0x6)/2); + if (iLevel==0) + string_method="Defl:N"; + else if (iLevel==1) + string_method="Defl:X"; + else if ((iLevel==2) || (iLevel==3)) + string_method="Defl:F"; /* 2:fast , 3 : extra fast*/ + } + else + if (file_info.compression_method==Z_BZIP2ED) + { + string_method="BZip2 "; + } + else + string_method="Unkn. "; + + Display64BitsSize(file_info.uncompressed_size,7); + printf(" %6s%c",string_method,charCrypt); + Display64BitsSize(file_info.compressed_size,7); + printf(" %3lu%% %2.2lu-%2.2lu-%2.2lu %2.2lu:%2.2lu %8.8lx %s\n", + ratio, + (uLong)file_info.tmu_date.tm_mon + 1, + (uLong)file_info.tmu_date.tm_mday, + (uLong)file_info.tmu_date.tm_year % 100, + (uLong)file_info.tmu_date.tm_hour,(uLong)file_info.tmu_date.tm_min, + (uLong)file_info.crc,filename_inzip); + if ((i+1)='a') && (rep<='z')) + rep -= 0x20; + } + while ((rep!='Y') && (rep!='N') && (rep!='A')); + } + + if (rep == 'N') + skip = 1; + + if (rep == 'A') + *popt_overwrite=1; + } + + if ((skip==0) && (err==UNZ_OK)) + { + fout=FOPEN_FUNC(write_filename,"wb"); + /* some zipfile don't contain directory alone before file */ + if ((fout==NULL) && ((*popt_extract_without_path)==0) && + (filename_withoutpath!=(char*)filename_inzip)) + { + char c=*(filename_withoutpath-1); + *(filename_withoutpath-1)='\0'; + makedir(write_filename); + *(filename_withoutpath-1)=c; + fout=FOPEN_FUNC(write_filename,"wb"); + } + + if (fout==NULL) + { + printf("error opening %s\n",write_filename); + } + } + + if (fout!=NULL) + { + printf(" extracting: %s\n",write_filename); + + do + { + err = unzReadCurrentFile(uf,buf,size_buf); + if (err<0) + { + printf("error %d with zipfile in unzReadCurrentFile\n",err); + break; + } + if (err>0) + if (fwrite(buf,err,1,fout)!=1) + { + printf("error in writing extracted file\n"); + err=UNZ_ERRNO; + break; + } + } + while (err>0); + if (fout) + fclose(fout); + + if (err==0) + change_file_date(write_filename,file_info.dosDate, + file_info.tmu_date); + } + + if (err==UNZ_OK) + { + err = unzCloseCurrentFile (uf); + if (err!=UNZ_OK) + { + printf("error %d with zipfile in unzCloseCurrentFile\n",err); + } + } + else + unzCloseCurrentFile(uf); /* don't lose the error */ + } + + free(buf); + return err; +} + + +int do_extract(uf,opt_extract_without_path,opt_overwrite,password) + unzFile uf; + int opt_extract_without_path; + int opt_overwrite; + const char* password; +{ + uLong i; + unz_global_info64 gi; + int err; + FILE* fout=NULL; + + err = unzGetGlobalInfo64(uf,&gi); + if (err!=UNZ_OK) + printf("error %d with zipfile in unzGetGlobalInfo \n",err); + + for (i=0;i insert n+1 empty lines +.\" for manpage-specific macros, see man(7) +.SH NAME +miniunzip - uncompress and examine ZIP archives +.SH SYNOPSIS +.B miniunzip +.RI [ -exvlo ] +zipfile [ files_to_extract ] [-d tempdir] +.SH DESCRIPTION +.B minizip +is a simple tool which allows the extraction of compressed file +archives in the ZIP format used by the MS-DOS utility PKZIP. It was +written as a demonstration of the +.IR zlib (3) +library and therefore lack many of the features of the +.IR unzip (1) +program. +.SH OPTIONS +A number of options are supported. With the exception of +.BI \-d\ tempdir +these must be supplied before any +other arguments and are: +.TP +.BI \-l\ ,\ \-\-v +List the files in the archive without extracting them. +.TP +.B \-o +Overwrite files without prompting for confirmation. +.TP +.B \-x +Extract files (default). +.PP +The +.I zipfile +argument is the name of the archive to process. The next argument can be used +to specify a single file to extract from the archive. + +Lastly, the following option can be specified at the end of the command-line: +.TP +.BI \-d\ tempdir +Extract the archive in the directory +.I tempdir +rather than the current directory. +.SH SEE ALSO +.BR minizip (1), +.BR zlib (3), +.BR unzip (1). +.SH AUTHOR +This program was written by Gilles Vollant. This manual page was +written by Mark Brown . The -d tempdir option +was added by Dirk Eddelbuettel . diff --git a/contrib/zlib/contrib/minizip/minizip.1 b/contrib/zlib/contrib/minizip/minizip.1 new file mode 100644 index 00000000..1154484c --- /dev/null +++ b/contrib/zlib/contrib/minizip/minizip.1 @@ -0,0 +1,46 @@ +.\" Hey, EMACS: -*- nroff -*- +.TH minizip 1 "May 2, 2001" +.\" Please adjust this date whenever revising the manpage. +.\" +.\" Some roff macros, for reference: +.\" .nh disable hyphenation +.\" .hy enable hyphenation +.\" .ad l left justify +.\" .ad b justify to both left and right margins +.\" .nf disable filling +.\" .fi enable filling +.\" .br insert line break +.\" .sp insert n+1 empty lines +.\" for manpage-specific macros, see man(7) +.SH NAME +minizip - create ZIP archives +.SH SYNOPSIS +.B minizip +.RI [ -o ] +zipfile [ " files" ... ] +.SH DESCRIPTION +.B minizip +is a simple tool which allows the creation of compressed file archives +in the ZIP format used by the MS-DOS utility PKZIP. It was written as +a demonstration of the +.IR zlib (3) +library and therefore lack many of the features of the +.IR zip (1) +program. +.SH OPTIONS +The first argument supplied is the name of the ZIP archive to create or +.RI -o +in which case it is ignored and the second argument treated as the +name of the ZIP file. If the ZIP file already exists it will be +overwritten. +.PP +Subsequent arguments specify a list of files to place in the ZIP +archive. If none are specified then an empty archive will be created. +.SH SEE ALSO +.BR miniunzip (1), +.BR zlib (3), +.BR zip (1). +.SH AUTHOR +This program was written by Gilles Vollant. This manual page was +written by Mark Brown . + diff --git a/contrib/zlib/contrib/minizip/minizip.c b/contrib/zlib/contrib/minizip/minizip.c new file mode 100644 index 00000000..4288962e --- /dev/null +++ b/contrib/zlib/contrib/minizip/minizip.c @@ -0,0 +1,520 @@ +/* + minizip.c + Version 1.1, February 14h, 2010 + sample part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) +*/ + + +#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif +#endif + +#ifdef __APPLE__ +// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions +#define FOPEN_FUNC(filename, mode) fopen(filename, mode) +#define FTELLO_FUNC(stream) ftello(stream) +#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin) +#else +#define FOPEN_FUNC(filename, mode) fopen64(filename, mode) +#define FTELLO_FUNC(stream) ftello64(stream) +#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin) +#endif + + + +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +# include +# include +#else +# include +# include +# include +# include +#endif + +#include "zip.h" + +#ifdef _WIN32 + #define USEWIN32IOAPI + #include "iowin32.h" +#endif + + + +#define WRITEBUFFERSIZE (16384) +#define MAXFILENAME (256) + +#ifdef _WIN32 +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + int ret = 0; + { + FILETIME ftLocal; + HANDLE hFind; + WIN32_FIND_DATAA ff32; + + hFind = FindFirstFileA(f,&ff32); + if (hFind != INVALID_HANDLE_VALUE) + { + FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal); + FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0); + FindClose(hFind); + ret = 1; + } + } + return ret; +} +#else +#ifdef unix || __APPLE__ +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + int ret=0; + struct stat s; /* results of stat() */ + struct tm* filedate; + time_t tm_t=0; + + if (strcmp(f,"-")!=0) + { + char name[MAXFILENAME+1]; + int len = strlen(f); + if (len > MAXFILENAME) + len = MAXFILENAME; + + strncpy(name, f,MAXFILENAME-1); + /* strncpy doesnt append the trailing NULL, of the string is too long. */ + name[ MAXFILENAME ] = '\0'; + + if (name[len - 1] == '/') + name[len - 1] = '\0'; + /* not all systems allow stat'ing a file with / appended */ + if (stat(name,&s)==0) + { + tm_t = s.st_mtime; + ret = 1; + } + } + filedate = localtime(&tm_t); + + tmzip->tm_sec = filedate->tm_sec; + tmzip->tm_min = filedate->tm_min; + tmzip->tm_hour = filedate->tm_hour; + tmzip->tm_mday = filedate->tm_mday; + tmzip->tm_mon = filedate->tm_mon ; + tmzip->tm_year = filedate->tm_year; + + return ret; +} +#else +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + return 0; +} +#endif +#endif + + + + +int check_exist_file(filename) + const char* filename; +{ + FILE* ftestexist; + int ret = 1; + ftestexist = FOPEN_FUNC(filename,"rb"); + if (ftestexist==NULL) + ret = 0; + else + fclose(ftestexist); + return ret; +} + +void do_banner() +{ + printf("MiniZip 1.1, demo of zLib + MiniZip64 package, written by Gilles Vollant\n"); + printf("more info on MiniZip at http://www.winimage.com/zLibDll/minizip.html\n\n"); +} + +void do_help() +{ + printf("Usage : minizip [-o] [-a] [-0 to -9] [-p password] [-j] file.zip [files_to_add]\n\n" \ + " -o Overwrite existing file.zip\n" \ + " -a Append to existing file.zip\n" \ + " -0 Store only\n" \ + " -1 Compress faster\n" \ + " -9 Compress better\n\n" \ + " -j exclude path. store only the file name.\n\n"); +} + +/* calculate the CRC32 of a file, + because to encrypt a file, we need known the CRC32 of the file before */ +int getFileCrc(const char* filenameinzip,void*buf,unsigned long size_buf,unsigned long* result_crc) +{ + unsigned long calculate_crc=0; + int err=ZIP_OK; + FILE * fin = FOPEN_FUNC(filenameinzip,"rb"); + + unsigned long size_read = 0; + unsigned long total_read = 0; + if (fin==NULL) + { + err = ZIP_ERRNO; + } + + if (err == ZIP_OK) + do + { + err = ZIP_OK; + size_read = (int)fread(buf,1,size_buf,fin); + if (size_read < size_buf) + if (feof(fin)==0) + { + printf("error in reading %s\n",filenameinzip); + err = ZIP_ERRNO; + } + + if (size_read>0) + calculate_crc = crc32(calculate_crc,buf,size_read); + total_read += size_read; + + } while ((err == ZIP_OK) && (size_read>0)); + + if (fin) + fclose(fin); + + *result_crc=calculate_crc; + printf("file %s crc %lx\n", filenameinzip, calculate_crc); + return err; +} + +int isLargeFile(const char* filename) +{ + int largeFile = 0; + ZPOS64_T pos = 0; + FILE* pFile = FOPEN_FUNC(filename, "rb"); + + if(pFile != NULL) + { + int n = FSEEKO_FUNC(pFile, 0, SEEK_END); + pos = FTELLO_FUNC(pFile); + + printf("File : %s is %lld bytes\n", filename, pos); + + if(pos >= 0xffffffff) + largeFile = 1; + + fclose(pFile); + } + + return largeFile; +} + +int main(argc,argv) + int argc; + char *argv[]; +{ + int i; + int opt_overwrite=0; + int opt_compress_level=Z_DEFAULT_COMPRESSION; + int opt_exclude_path=0; + int zipfilenamearg = 0; + char filename_try[MAXFILENAME+16]; + int zipok; + int err=0; + int size_buf=0; + void* buf=NULL; + const char* password=NULL; + + + do_banner(); + if (argc==1) + { + do_help(); + return 0; + } + else + { + for (i=1;i='0') && (c<='9')) + opt_compress_level = c-'0'; + if ((c=='j') || (c=='J')) + opt_exclude_path = 1; + + if (((c=='p') || (c=='P')) && (i+1='a') && (rep<='z')) + rep -= 0x20; + } + while ((rep!='Y') && (rep!='N') && (rep!='A')); + if (rep=='N') + zipok = 0; + if (rep=='A') + opt_overwrite = 2; + } + } + + if (zipok==1) + { + zipFile zf; + int errclose; +# ifdef USEWIN32IOAPI + zlib_filefunc64_def ffunc; + fill_win32_filefunc64A(&ffunc); + zf = zipOpen2_64(filename_try,(opt_overwrite==2) ? 2 : 0,NULL,&ffunc); +# else + zf = zipOpen64(filename_try,(opt_overwrite==2) ? 2 : 0); +# endif + + if (zf == NULL) + { + printf("error opening %s\n",filename_try); + err= ZIP_ERRNO; + } + else + printf("creating %s\n",filename_try); + + for (i=zipfilenamearg+1;(i='0') || (argv[i][1]<='9'))) && + (strlen(argv[i]) == 2))) + { + FILE * fin; + int size_read; + const char* filenameinzip = argv[i]; + const char *savefilenameinzip; + zip_fileinfo zi; + unsigned long crcFile=0; + int zip64 = 0; + + zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour = + zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0; + zi.dosDate = 0; + zi.internal_fa = 0; + zi.external_fa = 0; + filetime(filenameinzip,&zi.tmz_date,&zi.dosDate); + +/* + err = zipOpenNewFileInZip(zf,filenameinzip,&zi, + NULL,0,NULL,0,NULL / * comment * /, + (opt_compress_level != 0) ? Z_DEFLATED : 0, + opt_compress_level); +*/ + if ((password != NULL) && (err==ZIP_OK)) + err = getFileCrc(filenameinzip,buf,size_buf,&crcFile); + + zip64 = isLargeFile(filenameinzip); + + /* The path name saved, should not include a leading slash. */ + /*if it did, windows/xp and dynazip couldn't read the zip file. */ + savefilenameinzip = filenameinzip; + while( savefilenameinzip[0] == '\\' || savefilenameinzip[0] == '/' ) + { + savefilenameinzip++; + } + + /*should the zip file contain any path at all?*/ + if( opt_exclude_path ) + { + const char *tmpptr; + const char *lastslash = 0; + for( tmpptr = savefilenameinzip; *tmpptr; tmpptr++) + { + if( *tmpptr == '\\' || *tmpptr == '/') + { + lastslash = tmpptr; + } + } + if( lastslash != NULL ) + { + savefilenameinzip = lastslash+1; // base filename follows last slash. + } + } + + /**/ + err = zipOpenNewFileInZip3_64(zf,savefilenameinzip,&zi, + NULL,0,NULL,0,NULL /* comment*/, + (opt_compress_level != 0) ? Z_DEFLATED : 0, + opt_compress_level,0, + /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */ + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + password,crcFile, zip64); + + if (err != ZIP_OK) + printf("error in opening %s in zipfile\n",filenameinzip); + else + { + fin = FOPEN_FUNC(filenameinzip,"rb"); + if (fin==NULL) + { + err=ZIP_ERRNO; + printf("error in opening %s for reading\n",filenameinzip); + } + } + + if (err == ZIP_OK) + do + { + err = ZIP_OK; + size_read = (int)fread(buf,1,size_buf,fin); + if (size_read < size_buf) + if (feof(fin)==0) + { + printf("error in reading %s\n",filenameinzip); + err = ZIP_ERRNO; + } + + if (size_read>0) + { + err = zipWriteInFileInZip (zf,buf,size_read); + if (err<0) + { + printf("error in writing %s in the zipfile\n", + filenameinzip); + } + + } + } while ((err == ZIP_OK) && (size_read>0)); + + if (fin) + fclose(fin); + + if (err<0) + err=ZIP_ERRNO; + else + { + err = zipCloseFileInZip(zf); + if (err!=ZIP_OK) + printf("error in closing %s in the zipfile\n", + filenameinzip); + } + } + } + errclose = zipClose(zf,NULL); + if (errclose != ZIP_OK) + printf("error in closing %s\n",filename_try); + } + else + { + do_help(); + } + + free(buf); + return 0; +} diff --git a/contrib/zlib/contrib/minizip/minizip.pc.in b/contrib/zlib/contrib/minizip/minizip.pc.in new file mode 100644 index 00000000..69b5b7fd --- /dev/null +++ b/contrib/zlib/contrib/minizip/minizip.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@/minizip + +Name: minizip +Description: Minizip zip file manipulation library +Requires: +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lminizip +Libs.private: -lz +Cflags: -I${includedir} diff --git a/contrib/zlib/contrib/minizip/mztools.c b/contrib/zlib/contrib/minizip/mztools.c new file mode 100644 index 00000000..96891c2e --- /dev/null +++ b/contrib/zlib/contrib/minizip/mztools.c @@ -0,0 +1,291 @@ +/* + Additional tools for Minizip + Code: Xavier Roche '2004 + License: Same as ZLIB (www.gzip.org) +*/ + +/* Code */ +#include +#include +#include +#include "zlib.h" +#include "unzip.h" + +#define READ_8(adr) ((unsigned char)*(adr)) +#define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) ) +#define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) ) + +#define WRITE_8(buff, n) do { \ + *((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \ +} while(0) +#define WRITE_16(buff, n) do { \ + WRITE_8((unsigned char*)(buff), n); \ + WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \ +} while(0) +#define WRITE_32(buff, n) do { \ + WRITE_16((unsigned char*)(buff), (n) & 0xffff); \ + WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \ +} while(0) + +extern int ZEXPORT unzRepair(file, fileOut, fileOutTmp, nRecovered, bytesRecovered) +const char* file; +const char* fileOut; +const char* fileOutTmp; +uLong* nRecovered; +uLong* bytesRecovered; +{ + int err = Z_OK; + FILE* fpZip = fopen(file, "rb"); + FILE* fpOut = fopen(fileOut, "wb"); + FILE* fpOutCD = fopen(fileOutTmp, "wb"); + if (fpZip != NULL && fpOut != NULL) { + int entries = 0; + uLong totalBytes = 0; + char header[30]; + char filename[1024]; + char extra[1024]; + int offset = 0; + int offsetCD = 0; + while ( fread(header, 1, 30, fpZip) == 30 ) { + int currentOffset = offset; + + /* File entry */ + if (READ_32(header) == 0x04034b50) { + unsigned int version = READ_16(header + 4); + unsigned int gpflag = READ_16(header + 6); + unsigned int method = READ_16(header + 8); + unsigned int filetime = READ_16(header + 10); + unsigned int filedate = READ_16(header + 12); + unsigned int crc = READ_32(header + 14); /* crc */ + unsigned int cpsize = READ_32(header + 18); /* compressed size */ + unsigned int uncpsize = READ_32(header + 22); /* uncompressed sz */ + unsigned int fnsize = READ_16(header + 26); /* file name length */ + unsigned int extsize = READ_16(header + 28); /* extra field length */ + filename[0] = extra[0] = '\0'; + + /* Header */ + if (fwrite(header, 1, 30, fpOut) == 30) { + offset += 30; + } else { + err = Z_ERRNO; + break; + } + + /* Filename */ + if (fnsize > 0) { + if (fnsize < sizeof(filename)) { + if (fread(filename, 1, fnsize, fpZip) == fnsize) { + if (fwrite(filename, 1, fnsize, fpOut) == fnsize) { + offset += fnsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_STREAM_ERROR; + break; + } + + /* Extra field */ + if (extsize > 0) { + if (extsize < sizeof(extra)) { + if (fread(extra, 1, extsize, fpZip) == extsize) { + if (fwrite(extra, 1, extsize, fpOut) == extsize) { + offset += extsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } + + /* Data */ + { + int dataSize = cpsize; + if (dataSize == 0) { + dataSize = uncpsize; + } + if (dataSize > 0) { + char* data = malloc(dataSize); + if (data != NULL) { + if ((int)fread(data, 1, dataSize, fpZip) == dataSize) { + if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) { + offset += dataSize; + totalBytes += dataSize; + } else { + err = Z_ERRNO; + } + } else { + err = Z_ERRNO; + } + free(data); + if (err != Z_OK) { + break; + } + } else { + err = Z_MEM_ERROR; + break; + } + } + } + + /* Central directory entry */ + { + char header[46]; + char* comment = ""; + int comsize = (int) strlen(comment); + WRITE_32(header, 0x02014b50); + WRITE_16(header + 4, version); + WRITE_16(header + 6, version); + WRITE_16(header + 8, gpflag); + WRITE_16(header + 10, method); + WRITE_16(header + 12, filetime); + WRITE_16(header + 14, filedate); + WRITE_32(header + 16, crc); + WRITE_32(header + 20, cpsize); + WRITE_32(header + 24, uncpsize); + WRITE_16(header + 28, fnsize); + WRITE_16(header + 30, extsize); + WRITE_16(header + 32, comsize); + WRITE_16(header + 34, 0); /* disk # */ + WRITE_16(header + 36, 0); /* int attrb */ + WRITE_32(header + 38, 0); /* ext attrb */ + WRITE_32(header + 42, currentOffset); + /* Header */ + if (fwrite(header, 1, 46, fpOutCD) == 46) { + offsetCD += 46; + + /* Filename */ + if (fnsize > 0) { + if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) { + offsetCD += fnsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_STREAM_ERROR; + break; + } + + /* Extra field */ + if (extsize > 0) { + if (fwrite(extra, 1, extsize, fpOutCD) == extsize) { + offsetCD += extsize; + } else { + err = Z_ERRNO; + break; + } + } + + /* Comment field */ + if (comsize > 0) { + if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) { + offsetCD += comsize; + } else { + err = Z_ERRNO; + break; + } + } + + + } else { + err = Z_ERRNO; + break; + } + } + + /* Success */ + entries++; + + } else { + break; + } + } + + /* Final central directory */ + { + int entriesZip = entries; + char header[22]; + char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools"; + int comsize = (int) strlen(comment); + if (entriesZip > 0xffff) { + entriesZip = 0xffff; + } + WRITE_32(header, 0x06054b50); + WRITE_16(header + 4, 0); /* disk # */ + WRITE_16(header + 6, 0); /* disk # */ + WRITE_16(header + 8, entriesZip); /* hack */ + WRITE_16(header + 10, entriesZip); /* hack */ + WRITE_32(header + 12, offsetCD); /* size of CD */ + WRITE_32(header + 16, offset); /* offset to CD */ + WRITE_16(header + 20, comsize); /* comment */ + + /* Header */ + if (fwrite(header, 1, 22, fpOutCD) == 22) { + + /* Comment field */ + if (comsize > 0) { + if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) { + err = Z_ERRNO; + } + } + + } else { + err = Z_ERRNO; + } + } + + /* Final merge (file + central directory) */ + fclose(fpOutCD); + if (err == Z_OK) { + fpOutCD = fopen(fileOutTmp, "rb"); + if (fpOutCD != NULL) { + int nRead; + char buffer[8192]; + while ( (nRead = (int)fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) { + if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) { + err = Z_ERRNO; + break; + } + } + fclose(fpOutCD); + } + } + + /* Close */ + fclose(fpZip); + fclose(fpOut); + + /* Wipe temporary file */ + (void)remove(fileOutTmp); + + /* Number of recovered entries */ + if (err == Z_OK) { + if (nRecovered != NULL) { + *nRecovered = entries; + } + if (bytesRecovered != NULL) { + *bytesRecovered = totalBytes; + } + } + } else { + err = Z_STREAM_ERROR; + } + return err; +} diff --git a/contrib/zlib/contrib/minizip/mztools.h b/contrib/zlib/contrib/minizip/mztools.h new file mode 100644 index 00000000..a49a426e --- /dev/null +++ b/contrib/zlib/contrib/minizip/mztools.h @@ -0,0 +1,37 @@ +/* + Additional tools for Minizip + Code: Xavier Roche '2004 + License: Same as ZLIB (www.gzip.org) +*/ + +#ifndef _zip_tools_H +#define _zip_tools_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#include "unzip.h" + +/* Repair a ZIP file (missing central directory) + file: file to recover + fileOut: output file after recovery + fileOutTmp: temporary file name used for recovery +*/ +extern int ZEXPORT unzRepair(const char* file, + const char* fileOut, + const char* fileOutTmp, + uLong* nRecovered, + uLong* bytesRecovered); + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/contrib/zlib/contrib/minizip/unzip.c b/contrib/zlib/contrib/minizip/unzip.c new file mode 100644 index 00000000..bcfb9416 --- /dev/null +++ b/contrib/zlib/contrib/minizip/unzip.c @@ -0,0 +1,2125 @@ +/* unzip.c -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + + ------------------------------------------------------------------------------------ + Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of + compatibility with older software. The following is from the original crypt.c. + Code woven in by Terry Thorsen 1/2003. + + Copyright (c) 1990-2000 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.h) for terms of use. + If, for some reason, all these files are missing, the Info-ZIP license + also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html + + crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + ------------------------------------------------------------------------------------ + + Changes in unzip.c + + 2007-2008 - Even Rouault - Addition of cpl_unzGetCurrentFileZStreamPos + 2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz* + 2007-2008 - Even Rouault - Remove old C style function prototypes + 2007-2008 - Even Rouault - Add unzip support for ZIP64 + + Copyright (C) 2007-2008 Even Rouault + + + Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again). + Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G + should only read the compressed/uncompressed size from the Zip64 format if + the size from normal header was 0xFFFFFFFF + Oct-2009 - Mathias Svensson - Applied some bug fixes from paches recived from Gilles Vollant + Oct-2009 - Mathias Svensson - Applied support to unzip files with compression mathod BZIP2 (bzip2 lib is required) + Patch created by Daniel Borca + + Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer + + Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson + +*/ + + +#include +#include +#include + +#ifndef NOUNCRYPT + #define NOUNCRYPT +#endif + +#include "zlib.h" +#include "unzip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + + +#ifndef CASESENSITIVITYDEFAULT_NO +# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) +# define CASESENSITIVITYDEFAULT_NO +# endif +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + +const char unz_copyright[] = + " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info64_internal_s +{ + ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */ +} unz_file_info64_internal; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + ZPOS64_T offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + ZPOS64_T pos_local_extrafield; /* position in the local extra field in read*/ + ZPOS64_T total_out_64; + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ + ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + int raw; +} file_in_zip64_read_info_s; + + +/* unz64_s contain internal information about the zipfile +*/ +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + int is64bitOpenFunction; + voidpf filestream; /* io structore of the zipfile */ + unz_global_info64 gi; /* public global information */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + ZPOS64_T num_file; /* number of the current file in the zipfile*/ + ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/ + ZPOS64_T current_file_ok; /* flag about the usability of the current file*/ + ZPOS64_T central_pos; /* position of the beginning of the central dir*/ + + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info64 cur_file_info; /* public info about the current file in zip*/ + unz_file_info64_internal cur_file_info_internal; /* private info about it*/ + file_in_zip64_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ + int encrypted; + + int isZip64; + +# ifndef NOUNCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const z_crc_t* pcrc_32_tab; +# endif +} unz64_s; + + +#ifndef NOUNCRYPT +#include "crypt.h" +#endif + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been successfully opened for reading. +*/ + + +local int unz64local_getByte OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + int *pi)); + +local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int unz64local_getShort OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX)); + + +local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX) +{ + ZPOS64_T x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (ZPOS64_T)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<24; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<32; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<40; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<48; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<56; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2) +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int ZEXPORT unzStringFileNameCompare (const char* fileName1, + const char* fileName2, + int iCaseSensitivity) + +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); +local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + + +/* + Locate the Central directory 64 of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream)); + +local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + uLong uL; + ZPOS64_T relativeOffset; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + if (uPosFound == 0) + return 0; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature, already checked */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + /* number of the disk with the start of the zip64 end of central directory */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 0) + return 0; + + /* relative offset of the zip64 end of central directory record */ + if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK) + return 0; + + /* total number of disks */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 1) + return 0; + + /* Goto end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + if (uL != 0x06064b50) + return 0; + + return relativeOffset; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer + "zlib/zlib114.zip". + If the zipfile cannot be opened (file doesn't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +local unzFile unzOpenInternal (const void *path, + zlib_filefunc64_32_def* pzlib_filefunc64_32_def, + int is64bitOpenFunction) +{ + unz64_s us; + unz64_s *s; + ZPOS64_T central_pos; + uLong uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + ZPOS64_T number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + if (unz_copyright[0]!=' ') + return NULL; + + us.z_filefunc.zseek32_file = NULL; + us.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def==NULL) + fill_fopen64_filefunc(&us.z_filefunc.zfile_func64); + else + us.z_filefunc = *pzlib_filefunc64_32_def; + us.is64bitOpenFunction = is64bitOpenFunction; + + + + us.filestream = ZOPEN64(us.z_filefunc, + path, + ZLIB_FILEFUNC_MODE_READ | + ZLIB_FILEFUNC_MODE_EXISTING); + if (us.filestream==NULL) + return NULL; + + central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream); + if (central_pos) + { + uLong uS; + ZPOS64_T uL64; + + us.isZip64 = 1; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* size of zip64 end of central directory record */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version made by */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version needed to extract */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory on this disk */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + us.gi.size_comment = 0; + } + else + { + central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream); + if (central_pos==0) + err=UNZ_ERRNO; + + us.isZip64 = 0; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.gi.number_entry = uL; + + /* total number of entries in the central dir */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + number_entry_CD = uL; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.size_central_dir = uL; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.offset_central_dir = uL; + + /* zipfile comment length */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + } + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + ZCLOSE64(s->z_filefunc, s->filestream); + TRYFREE(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + +extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + /* to do : check if number_entry is not truncated */ + pglobal_info32->number_entry = (uLong)s->gi.number_entry; + pglobal_info32->size_comment = s->gi.size_comment; + return UNZ_OK; +} +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm) +{ + ZPOS64_T uDate; + uDate = (ZPOS64_T)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +local int unz64local_GetCurrentFileInfoInternal OF((unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +local int unz64local_GetCurrentFileInfoInternal (unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize) +{ + unz64_s* s; + unz_file_info64 file_info; + unz_file_info64_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + uLong uL; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pos_in_central_dir+s->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.compressed_size = uL; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.uncompressed_size = uL; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + // relative offset of local header + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info_internal.offset_curfile = uL; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + // Read extrafield + if ((err==UNZ_OK) && (extraField!=NULL)) + { + ZPOS64_T uSizeRead ; + if (file_info.size_file_extraz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + + lSeek += file_info.size_file_extra - (uLong)uSizeRead; + } + else + lSeek += file_info.size_file_extra; + + + if ((err==UNZ_OK) && (file_info.size_file_extra != 0)) + { + uLong acc = 0; + + // since lSeek now points to after the extra field we need to move back + lSeek -= file_info.size_file_extra; + + if (lSeek!=0) + { + if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + while(acc < file_info.size_file_extra) + { + uLong headerId; + uLong dataSize; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK) + err=UNZ_ERRNO; + + /* ZIP64 extra fields */ + if (headerId == 0x0001) + { + uLong uL; + + if(file_info.uncompressed_size == MAXU32) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.compressed_size == MAXU32) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info_internal.offset_curfile == MAXU32) + { + /* Relative Header offset */ + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.disk_num_start == MAXU32) + { + /* Disk Start Number */ + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + } + + } + else + { + if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0) + err=UNZ_ERRNO; + } + + acc += 2 + 2 + dataSize; + } + } + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int ZEXPORT unzGetCurrentFileInfo64 (unzFile file, + unz_file_info64 * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, + unz_file_info * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + int err; + unz_file_info64 file_info64; + err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); + if ((err==UNZ_OK) && (pfile_info != NULL)) + { + pfile_info->version = file_info64.version; + pfile_info->version_needed = file_info64.version_needed; + pfile_info->flag = file_info64.flag; + pfile_info->compression_method = file_info64.compression_method; + pfile_info->dosDate = file_info64.dosDate; + pfile_info->crc = file_info64.crc; + + pfile_info->size_filename = file_info64.size_filename; + pfile_info->size_file_extra = file_info64.size_file_extra; + pfile_info->size_file_comment = file_info64.size_file_comment; + + pfile_info->disk_num_start = file_info64.disk_num_start; + pfile_info->internal_fa = file_info64.internal_fa; + pfile_info->external_fa = file_info64.external_fa; + + pfile_info->tmu_date = file_info64.tmu_date, + + + pfile_info->compressed_size = (uLong)file_info64.compressed_size; + pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size; + + } + return err; +} +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int ZEXPORT unzGoToFirstFile (unzFile file) +{ + int err=UNZ_OK; + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int ZEXPORT unzGoToNextFile (unzFile file) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) +{ + unz64_s* s; + int err; + + /* We remember the 'current' position in the file so that we can jump + * back there if we fail. + */ + unz_file_info64 cur_file_infoSaved; + unz_file_info64_internal cur_file_info_internalSaved; + ZPOS64_T num_fileSaved; + ZPOS64_T pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + /* Save the current state */ + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + cur_file_infoSaved = s->cur_file_info; + cur_file_info_internalSaved = s->cur_file_info_internal; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + err = unzGetCurrentFileInfo64(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (err == UNZ_OK) + { + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + } + + /* We failed, so restore the state of the 'current file' to where we + * were. + */ + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + s->cur_file_info = cur_file_infoSaved; + s->cur_file_info_internal = cur_file_info_internalSaved; + return err; +} + + +/* +/////////////////////////////////////////// +// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) +// I need random access +// +// Further optimization could be realized by adding an ability +// to cache the directory in memory. The goal being a single +// comprehensive file read to put the file I need in a memory. +*/ + +/* +typedef struct unz_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; // offset in file + ZPOS64_T num_of_file; // # of file +} unz_file_pos; +*/ + +extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) +{ + unz64_s* s; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + file_pos->pos_in_zip_directory = s->pos_in_central_dir; + file_pos->num_of_file = s->num_file; + + return UNZ_OK; +} + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + int err = unzGetFilePos64(file,&file_pos64); + if (err==UNZ_OK) + { + file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory; + file_pos->num_of_file = (uLong)file_pos64.num_of_file; + } + return err; +} + +extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) +{ + unz64_s* s; + int err; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + /* jump to the right spot */ + s->pos_in_central_dir = file_pos->pos_in_zip_directory; + s->num_file = file_pos->num_of_file; + + /* set the current file */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + /* return results */ + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + if (file_pos == NULL) + return UNZ_PARAMERROR; + + file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory; + file_pos64.num_of_file = file_pos->num_of_file; + return unzGoToFilePos64(file,&file_pos64); +} + +/* +// Unzip Helper Functions - should be here? +/////////////////////////////////////////// +*/ + +/* + Read the local header of the current zipfile + Check the coherency of the local header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) +*/ +local int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar, + ZPOS64_T * poffset_local_extrafield, + uInt * psize_local_extrafield) +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (ZSEEK64(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method, + int* level, int raw, const char* password) +{ + int err=UNZ_OK; + uInt iSizeVar; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + ZPOS64_T offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ +# ifndef NOUNCRYPT + char source[12]; +# else + if (password != NULL) + return UNZ_PARAMERROR; +# endif + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + pfile_in_zip_read_info->raw=raw; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if (method!=NULL) + *method = (int)s->cur_file_info.compression_method; + + if (level!=NULL) + { + *level = 6; + switch (s->cur_file_info.flag & 0x06) + { + case 6 : *level = 1; break; + case 4 : *level = 2; break; + case 2 : *level = 9; break; + } + } + + if ((s->cur_file_info.compression_method!=0) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + + err=UNZ_BADZIPFILE; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->total_out_64=0; + pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; + pfile_in_zip_read_info->filestream=s->filestream; + pfile_in_zip_read_info->z_filefunc=s->z_filefunc; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw)) + { +#ifdef HAVE_BZIP2 + pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0; + pfile_in_zip_read_info->bstream.bzfree = (free_func)0; + pfile_in_zip_read_info->bstream.opaque = (voidpf)0; + pfile_in_zip_read_info->bstream.state = (voidpf)0; + + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = (voidpf)0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } +#else + pfile_in_zip_read_info->raw=1; +#endif + } + else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw)) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = 0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_DEFLATED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + s->pfile_in_zip_read = pfile_in_zip_read_info; + s->encrypted = 0; + +# ifndef NOUNCRYPT + if (password != NULL) + { + int i; + s->pcrc_32_tab = get_crc_table(); + init_keys(password,s->keys,s->pcrc_32_tab); + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pfile_in_zip_read->pos_in_zipfile + + s->pfile_in_zip_read->byte_before_the_zipfile, + SEEK_SET)!=0) + return UNZ_INTERNALERROR; + if(ZREAD64(s->z_filefunc, s->filestream,source, 12)<12) + return UNZ_INTERNALERROR; + + for (i = 0; i<12; i++) + zdecode(s->keys,s->pcrc_32_tab,source[i]); + + s->pfile_in_zip_read->pos_in_zipfile+=12; + s->encrypted=1; + } +# endif + + + return UNZ_OK; +} + +extern int ZEXPORT unzOpenCurrentFile (unzFile file) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); +} + +extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char* password) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, password); +} + +extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw) +{ + return unzOpenCurrentFile3(file, method, level, raw, NULL); +} + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + s=(unz64_s*)file; + if (file==NULL) + return 0; //UNZ_PARAMERROR; + pfile_in_zip_read_info=s->pfile_in_zip_read; + if (pfile_in_zip_read_info==NULL) + return 0; //UNZ_PARAMERROR; + return pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile; +} + +/** Addition for GDAL : END */ + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len) +{ + int err=UNZ_OK; + uInt iRead = 0; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if (pfile_in_zip_read_info->read_buffer == NULL) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && + (!(pfile_in_zip_read_info->raw))) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + if ((len>pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in) && + (pfile_in_zip_read_info->raw)) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->read_buffer, + uReadThis)!=uReadThis) + return UNZ_ERRNO; + + +# ifndef NOUNCRYPT + if(s->encrypted) + { + uInt i; + for(i=0;iread_buffer[i] = + zdecode(s->keys,s->pcrc_32_tab, + pfile_in_zip_read_info->read_buffer[i]); + } +# endif + + + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) + { + uInt uDoCopy,i ; + + if ((pfile_in_zip_read_info->stream.avail_in == 0) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + return (iRead==0) ? UNZ_EOF : iRead; + + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + + pfile_in_zip_read_info->bstream.next_in = (char*)pfile_in_zip_read_info->stream.next_in; + pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in; + pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in; + pfile_in_zip_read_info->bstream.total_in_hi32 = 0; + pfile_in_zip_read_info->bstream.next_out = (char*)pfile_in_zip_read_info->stream.next_out; + pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out; + pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out; + pfile_in_zip_read_info->bstream.total_out_hi32 = 0; + + uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32; + bufBefore = (const Bytef *)pfile_in_zip_read_info->bstream.next_out; + + err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream); + + uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); + pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->bstream.next_in; + pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in; + pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32; + pfile_in_zip_read_info->stream.next_out = (Bytef*)pfile_in_zip_read_info->bstream.next_out; + pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out; + pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32; + + if (err==BZ_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=BZ_OK) + break; +#endif + } // end Z_BZIP2ED + else + { + ZPOS64_T uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + ZPOS64_T uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) + err = Z_DATA_ERROR; + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern z_off_t ZEXPORT unztell (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + +extern ZPOS64_T ZEXPORT unztell64 (unzFile file) +{ + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return (ZPOS64_T)-1; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return (ZPOS64_T)-1; + + return pfile_in_zip_read_info->total_out_64; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int ZEXPORT unzeof (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* +Read extra field from the current file (opened by unzOpenCurrentFile) +This is the local-header version of the extra field (sometimes, there is +more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + uInt read_now; + ZPOS64_T size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + buf,read_now)!=read_now) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int ZEXPORT unzCloseCurrentFile (unzFile file) +{ + int err=UNZ_OK; + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && + (!pfile_in_zip_read_info->raw)) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) + inflateEnd(&pfile_in_zip_read_info->stream); +#ifdef HAVE_BZIP2 + else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) + BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); +#endif + + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf) +{ + unz64_s* s; + uLong uReadThis ; + if (file==NULL) + return (int)UNZ_PARAMERROR; + s=(unz64_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (ZSEEK64(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (ZREAD64(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + +/* Additions by RX '2004 */ +extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) +{ + unz64_s* s; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return 0; + if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) + if (s->num_file==s->gi.number_entry) + return 0; + return s->pos_in_central_dir; +} + +extern uLong ZEXPORT unzGetOffset (unzFile file) +{ + ZPOS64_T offset64; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + offset64 = unzGetOffset64(file); + return (uLong)offset64; +} + +extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + s->pos_in_central_dir = pos; + s->num_file = s->gi.number_entry; /* hack */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos) +{ + return unzSetOffset64(file,pos); +} diff --git a/contrib/zlib/contrib/minizip/unzip.h b/contrib/zlib/contrib/minizip/unzip.h new file mode 100644 index 00000000..2104e391 --- /dev/null +++ b/contrib/zlib/contrib/minizip/unzip.h @@ -0,0 +1,437 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + --------------------------------------------------------------------------------- + + Changes + + See header of unzip64.c + +*/ + +#ifndef _unz64_H +#define _unz64_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info64_s +{ + ZPOS64_T number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info64; + +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info64_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + ZPOS64_T compressed_size; /* compressed size 8 bytes */ + ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info64; + +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((const char *path)); +extern unzFile ZEXPORT unzOpen64 OF((const void *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer + "zlib/zlib113.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. + the "64" function take a const void* pointer, because the path is just the + value passed to the open64_file_func callback. + Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path + is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* + does not describe the reality +*/ + + +extern unzFile ZEXPORT unzOpen2 OF((const char *path, + zlib_filefunc_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unzOpen, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, + zlib_filefunc64_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unz64Open, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzCloseCurrentFile before call unzClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); + +extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, + unz_global_info64 *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +/* ****************************************** */ +/* Ryan supplied functions */ +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; /* offset in zip file directory */ + uLong num_of_file; /* # of file */ +} unz_file_pos; + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos); + +typedef struct unz64_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ + ZPOS64_T num_of_file; /* # of file */ +} unz64_file_pos; + +extern int ZEXPORT unzGetFilePos64( + unzFile file, + unz64_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos64( + unzFile file, + const unz64_file_pos* file_pos); + +/* ****************************************** */ + +extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, + unz_file_info64 *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); + +/** Addition for GDAL : END */ + + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, + const char* password)); +/* + Open for reading data the current file in the zipfile. + password is a crypting password + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, + int* method, + int* level, + int raw)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + +extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, + int* method, + int* level, + int raw, + const char* password)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); + +extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +/***************************************************************************/ + +/* Get the current file offset */ +extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file); +extern uLong ZEXPORT unzGetOffset (unzFile file); + +/* Set the current file offset */ +extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos); +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); + + + +#ifdef __cplusplus +} +#endif + +#endif /* _unz64_H */ diff --git a/contrib/zlib/contrib/minizip/zip.c b/contrib/zlib/contrib/minizip/zip.c new file mode 100644 index 00000000..44e88a9c --- /dev/null +++ b/contrib/zlib/contrib/minizip/zip.c @@ -0,0 +1,2007 @@ +/* zip.c -- IO on .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + Changes + Oct-2009 - Mathias Svensson - Remove old C style function prototypes + Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives + Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions. + Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data + It is used when recreting zip archive with RAW when deleting items from a zip. + ZIP64 data is automatically added to items that needs it, and existing ZIP64 data need to be removed. + Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required) + Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer + +*/ + + +#include +#include +#include +#include +#include "zlib.h" +#include "zip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +#ifndef VERSIONMADEBY +# define VERSIONMADEBY (0x0) /* platform depedent */ +#endif + +#ifndef Z_BUFSIZE +#define Z_BUFSIZE (64*1024) //(16384) +#endif + +#ifndef Z_MAXFILENAMEINZIP +#define Z_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +/* +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) +*/ + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + + +// NOT sure that this work on ALL platform +#define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32)) + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +#ifndef DEF_MEM_LEVEL +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +#endif +const char zip_copyright[] =" zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + + +#define SIZEDATA_INDATABLOCK (4096-(4*4)) + +#define LOCALHEADERMAGIC (0x04034b50) +#define CENTRALHEADERMAGIC (0x02014b50) +#define ENDHEADERMAGIC (0x06054b50) +#define ZIP64ENDHEADERMAGIC (0x6064b50) +#define ZIP64ENDLOCHEADERMAGIC (0x7064b50) + +#define FLAG_LOCALHEADER_OFFSET (0x06) +#define CRC_LOCALHEADER_OFFSET (0x0e) + +#define SIZECENTRALHEADER (0x2e) /* 46 */ + +typedef struct linkedlist_datablock_internal_s +{ + struct linkedlist_datablock_internal_s* next_datablock; + uLong avail_in_this_block; + uLong filled_in_this_block; + uLong unused; /* for future use and alignment */ + unsigned char data[SIZEDATA_INDATABLOCK]; +} linkedlist_datablock_internal; + +typedef struct linkedlist_data_s +{ + linkedlist_datablock_internal* first_block; + linkedlist_datablock_internal* last_block; +} linkedlist_data; + + +typedef struct +{ + z_stream stream; /* zLib stream structure for inflate */ +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + int stream_initialised; /* 1 is stream is initialised */ + uInt pos_in_buffered_data; /* last written byte in buffered_data */ + + ZPOS64_T pos_local_header; /* offset of the local header of the file + currenty writing */ + char* central_header; /* central header data for the current file */ + uLong size_centralExtra; + uLong size_centralheader; /* size of the central header for cur file */ + uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader but that are not used */ + uLong flag; /* flag of the file currently writing */ + + int method; /* compression method of file currenty wr.*/ + int raw; /* 1 for directly writing raw data */ + Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ + uLong dosDate; + uLong crc32; + int encrypt; + int zip64; /* Add ZIP64 extened information in the extra field */ + ZPOS64_T pos_zip64extrainfo; + ZPOS64_T totalCompressedData; + ZPOS64_T totalUncompressedData; +#ifndef NOCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const z_crc_t* pcrc_32_tab; + int crypt_header_size; +#endif +} curfile64_info; + +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + linkedlist_data central_dir;/* datablock with central dir in construction*/ + int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ + curfile64_info ci; /* info on the file curretly writing */ + + ZPOS64_T begin_pos; /* position of the beginning of the zipfile */ + ZPOS64_T add_position_when_writing_offset; + ZPOS64_T number_entry; + +#ifndef NO_ADDFILEINEXISTINGZIP + char *globalcomment; +#endif + +} zip64_internal; + + +#ifndef NOCRYPT +#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED +#include "crypt.h" +#endif + +local linkedlist_datablock_internal* allocate_new_datablock() +{ + linkedlist_datablock_internal* ldi; + ldi = (linkedlist_datablock_internal*) + ALLOC(sizeof(linkedlist_datablock_internal)); + if (ldi!=NULL) + { + ldi->next_datablock = NULL ; + ldi->filled_in_this_block = 0 ; + ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; + } + return ldi; +} + +local void free_datablock(linkedlist_datablock_internal* ldi) +{ + while (ldi!=NULL) + { + linkedlist_datablock_internal* ldinext = ldi->next_datablock; + TRYFREE(ldi); + ldi = ldinext; + } +} + +local void init_linkedlist(linkedlist_data* ll) +{ + ll->first_block = ll->last_block = NULL; +} + +local void free_linkedlist(linkedlist_data* ll) +{ + free_datablock(ll->first_block); + ll->first_block = ll->last_block = NULL; +} + + +local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len) +{ + linkedlist_datablock_internal* ldi; + const unsigned char* from_copy; + + if (ll==NULL) + return ZIP_INTERNALERROR; + + if (ll->last_block == NULL) + { + ll->first_block = ll->last_block = allocate_new_datablock(); + if (ll->first_block == NULL) + return ZIP_INTERNALERROR; + } + + ldi = ll->last_block; + from_copy = (unsigned char*)buf; + + while (len>0) + { + uInt copy_this; + uInt i; + unsigned char* to_copy; + + if (ldi->avail_in_this_block==0) + { + ldi->next_datablock = allocate_new_datablock(); + if (ldi->next_datablock == NULL) + return ZIP_INTERNALERROR; + ldi = ldi->next_datablock ; + ll->last_block = ldi; + } + + if (ldi->avail_in_this_block < len) + copy_this = (uInt)ldi->avail_in_this_block; + else + copy_this = (uInt)len; + + to_copy = &(ldi->data[ldi->filled_in_this_block]); + + for (i=0;ifilled_in_this_block += copy_this; + ldi->avail_in_this_block -= copy_this; + from_copy += copy_this ; + len -= copy_this; + } + return ZIP_OK; +} + + + +/****************************************************************************/ + +#ifndef NO_ADDFILEINEXISTINGZIP +/* =========================================================================== + Inputs a long in LSB order to the given file + nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T) +*/ + +local int zip64local_putValue OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte)); +local int zip64local_putValue (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte) +{ + unsigned char buf[8]; + int n; + for (n = 0; n < nbByte; n++) + { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + if (x != 0) + { /* data overflow - hack for ZIP64 (X Roche) */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } + + if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) + return ZIP_ERRNO; + else + return ZIP_OK; +} + +local void zip64local_putValue_inmemory OF((void* dest, ZPOS64_T x, int nbByte)); +local void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte) +{ + unsigned char* buf=(unsigned char*)dest; + int n; + for (n = 0; n < nbByte; n++) { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + + if (x != 0) + { /* data overflow - hack for ZIP64 */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } +} + +/****************************************************************************/ + + +local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm) +{ + uLong year = (uLong)ptm->tm_year; + if (year>=1980) + year-=1980; + else if (year>=80) + year-=80; + return + (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | + ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); +} + + +/****************************************************************************/ + +local int zip64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)); + +local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def,voidpf filestream,int* pi) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return ZIP_OK; + } + else + { + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return ZIP_ERRNO; + else + return ZIP_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int zip64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); + +local int zip64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) +{ + uLong x ; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int zip64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); + +local int zip64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) +{ + uLong x ; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<16; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int zip64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)); + + +local int zip64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) +{ + ZPOS64_T x; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (ZPOS64_T)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<8; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<16; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<24; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<32; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<40; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<48; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<56; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + + return err; +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); + +local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + +/* +Locate the End of Zip64 Central directory locator and from there find the CD of a zipfile (at the end, just before +the global comment) +*/ +local ZPOS64_T zip64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); + +local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + uLong uL; + ZPOS64_T relativeOffset; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + { + // Signature "0x07064b50" Zip64 end of central directory locater + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) + { + uPosFound = uReadPos+i; + break; + } + } + + if (uPosFound!=0) + break; + } + + TRYFREE(buf); + if (uPosFound == 0) + return 0; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature, already checked */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + + /* number of the disk with the start of the zip64 end of central directory */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + if (uL != 0) + return 0; + + /* relative offset of the zip64 end of central directory record */ + if (zip64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=ZIP_OK) + return 0; + + /* total number of disks */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + if (uL != 1) + return 0; + + /* Goto Zip64 end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + + if (uL != 0x06064b50) // signature of 'Zip64 end of central directory' + return 0; + + return relativeOffset; +} + +int LoadCentralDirectoryRecord(zip64_internal* pziinit) +{ + int err=ZIP_OK; + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory */ + ZPOS64_T central_pos; + uLong uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + ZPOS64_T number_entry; + ZPOS64_T number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + uLong VersionMadeBy; + uLong VersionNeeded; + uLong size_comment; + + int hasZIP64Record = 0; + + // check first if we find a ZIP64 record + central_pos = zip64local_SearchCentralDir64(&pziinit->z_filefunc,pziinit->filestream); + if(central_pos > 0) + { + hasZIP64Record = 1; + } + else if(central_pos == 0) + { + central_pos = zip64local_SearchCentralDir(&pziinit->z_filefunc,pziinit->filestream); + } + +/* disable to allow appending to empty ZIP archive + if (central_pos==0) + err=ZIP_ERRNO; +*/ + + if(hasZIP64Record) + { + ZPOS64_T sizeEndOfCentralDirectory; + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* size of zip64 end of central directory record */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &sizeEndOfCentralDirectory)!=ZIP_OK) + err=ZIP_ERRNO; + + /* version made by */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionMadeBy)!=ZIP_OK) + err=ZIP_ERRNO; + + /* version needed to extract */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionNeeded)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central directory on this disk */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &number_entry)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central directory */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&number_entry_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) + err=ZIP_BADZIPFILE; + + /* size of the central directory */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&size_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&offset_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + // TODO.. + // read the comment from the standard central header. + size_comment = 0; + } + else + { + // Read End of central Directory info + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central dir on this disk */ + number_entry = 0; + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + number_entry = uL; + + /* total number of entries in the central dir */ + number_entry_CD = 0; + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + number_entry_CD = uL; + + if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) + err=ZIP_BADZIPFILE; + + /* size of the central directory */ + size_central_dir = 0; + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + size_central_dir = uL; + + /* offset of start of central directory with respect to the starting disk number */ + offset_central_dir = 0; + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + offset_central_dir = uL; + + + /* zipfile global comment length */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &size_comment)!=ZIP_OK) + err=ZIP_ERRNO; + } + + if ((central_posz_filefunc, pziinit->filestream); + return ZIP_ERRNO; + } + + if (size_comment>0) + { + pziinit->globalcomment = (char*)ALLOC(size_comment+1); + if (pziinit->globalcomment) + { + size_comment = ZREAD64(pziinit->z_filefunc, pziinit->filestream, pziinit->globalcomment,size_comment); + pziinit->globalcomment[size_comment]=0; + } + } + + byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir); + pziinit->add_position_when_writing_offset = byte_before_the_zipfile; + + { + ZPOS64_T size_central_dir_to_read = size_central_dir; + size_t buf_size = SIZEDATA_INDATABLOCK; + void* buf_read = (void*)ALLOC(buf_size); + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + while ((size_central_dir_to_read>0) && (err==ZIP_OK)) + { + ZPOS64_T read_this = SIZEDATA_INDATABLOCK; + if (read_this > size_central_dir_to_read) + read_this = size_central_dir_to_read; + + if (ZREAD64(pziinit->z_filefunc, pziinit->filestream,buf_read,(uLong)read_this) != read_this) + err=ZIP_ERRNO; + + if (err==ZIP_OK) + err = add_data_in_datablock(&pziinit->central_dir,buf_read, (uLong)read_this); + + size_central_dir_to_read-=read_this; + } + TRYFREE(buf_read); + } + pziinit->begin_pos = byte_before_the_zipfile; + pziinit->number_entry = number_entry_CD; + + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + return err; +} + + +#endif /* !NO_ADDFILEINEXISTINGZIP*/ + + +/************************************************************/ +extern zipFile ZEXPORT zipOpen3 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def) +{ + zip64_internal ziinit; + zip64_internal* zi; + int err=ZIP_OK; + + ziinit.z_filefunc.zseek32_file = NULL; + ziinit.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def==NULL) + fill_fopen64_filefunc(&ziinit.z_filefunc.zfile_func64); + else + ziinit.z_filefunc = *pzlib_filefunc64_32_def; + + ziinit.filestream = ZOPEN64(ziinit.z_filefunc, + pathname, + (append == APPEND_STATUS_CREATE) ? + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) : + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING)); + + if (ziinit.filestream == NULL) + return NULL; + + if (append == APPEND_STATUS_CREATEAFTER) + ZSEEK64(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END); + + ziinit.begin_pos = ZTELL64(ziinit.z_filefunc,ziinit.filestream); + ziinit.in_opened_file_inzip = 0; + ziinit.ci.stream_initialised = 0; + ziinit.number_entry = 0; + ziinit.add_position_when_writing_offset = 0; + init_linkedlist(&(ziinit.central_dir)); + + + + zi = (zip64_internal*)ALLOC(sizeof(zip64_internal)); + if (zi==NULL) + { + ZCLOSE64(ziinit.z_filefunc,ziinit.filestream); + return NULL; + } + + /* now we add file in a zipfile */ +# ifndef NO_ADDFILEINEXISTINGZIP + ziinit.globalcomment = NULL; + if (append == APPEND_STATUS_ADDINZIP) + { + // Read and Cache Central Directory Records + err = LoadCentralDirectoryRecord(&ziinit); + } + + if (globalcomment) + { + *globalcomment = ziinit.globalcomment; + } +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + + if (err != ZIP_OK) + { +# ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(ziinit.globalcomment); +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + TRYFREE(zi); + return NULL; + } + else + { + *zi = ziinit; + return (zipFile)zi; + } +} + +extern zipFile ZEXPORT zipOpen2 (const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def) +{ + if (pzlib_filefunc32_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def); + return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); + } + else + return zipOpen3(pathname, append, globalcomment, NULL); +} + +extern zipFile ZEXPORT zipOpen2_64 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def) +{ + if (pzlib_filefunc_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; + zlib_filefunc64_32_def_fill.ztell32_file = NULL; + zlib_filefunc64_32_def_fill.zseek32_file = NULL; + return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); + } + else + return zipOpen3(pathname, append, globalcomment, NULL); +} + + + +extern zipFile ZEXPORT zipOpen (const char* pathname, int append) +{ + return zipOpen3((const void*)pathname,append,NULL,NULL); +} + +extern zipFile ZEXPORT zipOpen64 (const void* pathname, int append) +{ + return zipOpen3(pathname,append,NULL,NULL); +} + +int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local) +{ + /* write the local header */ + int err; + uInt size_filename = (uInt)strlen(filename); + uInt size_extrafield = size_extrafield_local; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC, 4); + + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);/* version needed to extract */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */ + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); + + // CRC / Compressed size / Uncompressed size will be filled in later and rewritten later + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* compressed size, unknown */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */ + } + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* uncompressed size, unknown */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */ + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); + + if(zi->ci.zip64) + { + size_extrafield += 20; + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield,2); + + if ((err==ZIP_OK) && (size_filename > 0)) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) + err = ZIP_ERRNO; + } + + if ((err==ZIP_OK) && (size_extrafield_local > 0)) + { + if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local) + err = ZIP_ERRNO; + } + + + if ((err==ZIP_OK) && (zi->ci.zip64)) + { + // write the Zip64 extended info + short HeaderID = 1; + short DataSize = 16; + ZPOS64_T CompressedSize = 0; + ZPOS64_T UncompressedSize = 0; + + // Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file) + zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)HeaderID,2); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)DataSize,2); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)UncompressedSize,8); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)CompressedSize,8); + } + + return err; +} + +/* + NOTE. + When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped + before calling this function it can be done with zipRemoveExtraInfoBlock + + It is not done here because then we need to realloc a new buffer since parameters are 'const' and I want to minimize + unnecessary allocations. + */ +extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, + uLong versionMadeBy, uLong flagBase, int zip64) +{ + zip64_internal* zi; + uInt size_filename; + uInt size_comment; + uInt i; + int err = ZIP_OK; + +# ifdef NOCRYPT + (crcForCrypting); + if (password != NULL) + return ZIP_PARAMERROR; +# endif + + if (file == NULL) + return ZIP_PARAMERROR; + +#ifdef HAVE_BZIP2 + if ((method!=0) && (method!=Z_DEFLATED) && (method!=Z_BZIP2ED)) + return ZIP_PARAMERROR; +#else + if ((method!=0) && (method!=Z_DEFLATED)) + return ZIP_PARAMERROR; +#endif + + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + if (err != ZIP_OK) + return err; + } + + if (filename==NULL) + filename="-"; + + if (comment==NULL) + size_comment = 0; + else + size_comment = (uInt)strlen(comment); + + size_filename = (uInt)strlen(filename); + + if (zipfi == NULL) + zi->ci.dosDate = 0; + else + { + if (zipfi->dosDate != 0) + zi->ci.dosDate = zipfi->dosDate; + else + zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date); + } + + zi->ci.flag = flagBase; + if ((level==8) || (level==9)) + zi->ci.flag |= 2; + if (level==2) + zi->ci.flag |= 4; + if (level==1) + zi->ci.flag |= 6; + if (password != NULL) + zi->ci.flag |= 1; + + zi->ci.crc32 = 0; + zi->ci.method = method; + zi->ci.encrypt = 0; + zi->ci.stream_initialised = 0; + zi->ci.pos_in_buffered_data = 0; + zi->ci.raw = raw; + zi->ci.pos_local_header = ZTELL64(zi->z_filefunc,zi->filestream); + + zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global + size_comment; + zi->ci.size_centralExtraFree = 32; // Extra space we have reserved in case we need to add ZIP64 extra info data + + zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader + zi->ci.size_centralExtraFree); + + zi->ci.size_centralExtra = size_extrafield_global; + zip64local_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); + /* version info */ + zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)versionMadeBy,2); + zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2); + zip64local_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); + zip64local_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); + zip64local_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); + zip64local_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ + zip64local_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ + zip64local_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ + zip64local_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); + zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); + zip64local_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); + zip64local_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ + + if (zipfi==NULL) + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); + else + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); + + if (zipfi==NULL) + zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); + else + zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); + + if(zi->ci.pos_local_header >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)0xffffffff,4); + else + zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header - zi->add_position_when_writing_offset,4); + + for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = + *(((const char*)extrafield_global)+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ + size_extrafield_global+i) = *(comment+i); + if (zi->ci.central_header == NULL) + return ZIP_INTERNALERROR; + + zi->ci.zip64 = zip64; + zi->ci.totalCompressedData = 0; + zi->ci.totalUncompressedData = 0; + zi->ci.pos_zip64extrainfo = 0; + + err = Write_LocalFileHeader(zi, filename, size_extrafield_local, extrafield_local); + +#ifdef HAVE_BZIP2 + zi->ci.bstream.avail_in = (uInt)0; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + zi->ci.bstream.total_in_hi32 = 0; + zi->ci.bstream.total_in_lo32 = 0; + zi->ci.bstream.total_out_hi32 = 0; + zi->ci.bstream.total_out_lo32 = 0; +#endif + + zi->ci.stream.avail_in = (uInt)0; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + zi->ci.stream.total_in = 0; + zi->ci.stream.total_out = 0; + zi->ci.stream.data_type = Z_BINARY; + +#ifdef HAVE_BZIP2 + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED || zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) +#else + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) +#endif + { + if(zi->ci.method == Z_DEFLATED) + { + zi->ci.stream.zalloc = (alloc_func)0; + zi->ci.stream.zfree = (free_func)0; + zi->ci.stream.opaque = (voidpf)0; + + if (windowBits>0) + windowBits = -windowBits; + + err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy); + + if (err==Z_OK) + zi->ci.stream_initialised = Z_DEFLATED; + } + else if(zi->ci.method == Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + // Init BZip stuff here + zi->ci.bstream.bzalloc = 0; + zi->ci.bstream.bzfree = 0; + zi->ci.bstream.opaque = (voidpf)0; + + err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0,35); + if(err == BZ_OK) + zi->ci.stream_initialised = Z_BZIP2ED; +#endif + } + + } + +# ifndef NOCRYPT + zi->ci.crypt_header_size = 0; + if ((err==Z_OK) && (password != NULL)) + { + unsigned char bufHead[RAND_HEAD_LEN]; + unsigned int sizeHead; + zi->ci.encrypt = 1; + zi->ci.pcrc_32_tab = get_crc_table(); + /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ + + sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting); + zi->ci.crypt_header_size = sizeHead; + + if (ZWRITE64(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead) + err = ZIP_ERRNO; + } +# endif + + if (err==Z_OK) + zi->in_opened_file_inzip = 1; + return err; +} + +extern int ZEXPORT zipOpenNewFileInZip4 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, + uLong versionMadeBy, uLong flagBase) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, versionMadeBy, flagBase, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void*extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void*extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, 0); +} + +local int zip64FlushWriteBuffer(zip64_internal* zi) +{ + int err=ZIP_OK; + + if (zi->ci.encrypt != 0) + { +#ifndef NOCRYPT + uInt i; + int t; + for (i=0;ici.pos_in_buffered_data;i++) + zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i],t); +#endif + } + + if (ZWRITE64(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) != zi->ci.pos_in_buffered_data) + err = ZIP_ERRNO; + + zi->ci.totalCompressedData += zi->ci.pos_in_buffered_data; + +#ifdef HAVE_BZIP2 + if(zi->ci.method == Z_BZIP2ED) + { + zi->ci.totalUncompressedData += zi->ci.bstream.total_in_lo32; + zi->ci.bstream.total_in_lo32 = 0; + zi->ci.bstream.total_in_hi32 = 0; + } + else +#endif + { + zi->ci.totalUncompressedData += zi->ci.stream.total_in; + zi->ci.stream.total_in = 0; + } + + + zi->ci.pos_in_buffered_data = 0; + + return err; +} + +extern int ZEXPORT zipWriteInFileInZip (zipFile file,const void* buf,unsigned int len) +{ + zip64_internal* zi; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + + zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len); + +#ifdef HAVE_BZIP2 + if(zi->ci.method == Z_BZIP2ED && (!zi->ci.raw)) + { + zi->ci.bstream.next_in = (void*)buf; + zi->ci.bstream.avail_in = len; + err = BZ_RUN_OK; + + while ((err==BZ_RUN_OK) && (zi->ci.bstream.avail_in>0)) + { + if (zi->ci.bstream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + } + + + if(err != BZ_RUN_OK) + break; + + if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { + uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32; +// uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32; + err=BZ2_bzCompress(&zi->ci.bstream, BZ_RUN); + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo) ; + } + } + + if(err == BZ_RUN_OK) + err = ZIP_OK; + } + else +#endif + { + zi->ci.stream.next_in = (Bytef*)buf; + zi->ci.stream.avail_in = len; + + while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) + { + if (zi->ci.stream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + + + if(err != ZIP_OK) + break; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + uLong uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_NO_FLUSH); + if(uTotalOutBefore > zi->ci.stream.total_out) + { + int bBreak = 0; + bBreak++; + } + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + } + else + { + uInt copy_this,i; + if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) + copy_this = zi->ci.stream.avail_in; + else + copy_this = zi->ci.stream.avail_out; + + for (i = 0; i < copy_this; i++) + *(((char*)zi->ci.stream.next_out)+i) = + *(((const char*)zi->ci.stream.next_in)+i); + { + zi->ci.stream.avail_in -= copy_this; + zi->ci.stream.avail_out-= copy_this; + zi->ci.stream.next_in+= copy_this; + zi->ci.stream.next_out+= copy_this; + zi->ci.stream.total_in+= copy_this; + zi->ci.stream.total_out+= copy_this; + zi->ci.pos_in_buffered_data += copy_this; + } + } + }// while(...) + } + + return err; +} + +extern int ZEXPORT zipCloseFileInZipRaw (zipFile file, uLong uncompressed_size, uLong crc32) +{ + return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32); +} + +extern int ZEXPORT zipCloseFileInZipRaw64 (zipFile file, ZPOS64_T uncompressed_size, uLong crc32) +{ + zip64_internal* zi; + ZPOS64_T compressed_size; + uLong invalidValue = 0xffffffff; + short datasize = 0; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + zi->ci.stream.avail_in = 0; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + while (err==ZIP_OK) + { + uLong uTotalOutBefore; + if (zi->ci.stream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_FINISH); + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + } + } + else if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { +#ifdef HAVE_BZIP2 + err = BZ_FINISH_OK; + while (err==BZ_FINISH_OK) + { + uLong uTotalOutBefore; + if (zi->ci.bstream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + } + uTotalOutBefore = zi->ci.bstream.total_out_lo32; + err=BZ2_bzCompress(&zi->ci.bstream, BZ_FINISH); + if(err == BZ_STREAM_END) + err = Z_STREAM_END; + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore); + } + + if(err == BZ_FINISH_OK) + err = ZIP_OK; +#endif + } + + if (err==Z_STREAM_END) + err=ZIP_OK; /* this is normal */ + + if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) + { + if (zip64FlushWriteBuffer(zi)==ZIP_ERRNO) + err = ZIP_ERRNO; + } + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + int tmp_err = deflateEnd(&zi->ci.stream); + if (err == ZIP_OK) + err = tmp_err; + zi->ci.stream_initialised = 0; + } +#ifdef HAVE_BZIP2 + else if((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { + int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream); + if (err==ZIP_OK) + err = tmperr; + zi->ci.stream_initialised = 0; + } +#endif + + if (!zi->ci.raw) + { + crc32 = (uLong)zi->ci.crc32; + uncompressed_size = zi->ci.totalUncompressedData; + } + compressed_size = zi->ci.totalCompressedData; + +# ifndef NOCRYPT + compressed_size += zi->ci.crypt_header_size; +# endif + + // update Current Item crc and sizes, + if(compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff) + { + /*version Made by*/ + zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)45,2); + /*version needed*/ + zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)45,2); + + } + + zip64local_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ + + + if(compressed_size >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+20, invalidValue,4); /*compr size*/ + else + zip64local_putValue_inmemory(zi->ci.central_header+20, compressed_size,4); /*compr size*/ + + /// set internal file attributes field + if (zi->ci.stream.data_type == Z_ASCII) + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); + + if(uncompressed_size >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+24, invalidValue,4); /*uncompr size*/ + else + zip64local_putValue_inmemory(zi->ci.central_header+24, uncompressed_size,4); /*uncompr size*/ + + // Add ZIP64 extra info field for uncompressed size + if(uncompressed_size >= 0xffffffff) + datasize += 8; + + // Add ZIP64 extra info field for compressed size + if(compressed_size >= 0xffffffff) + datasize += 8; + + // Add ZIP64 extra info field for relative offset to local file header of current file + if(zi->ci.pos_local_header >= 0xffffffff) + datasize += 8; + + if(datasize > 0) + { + char* p = NULL; + + if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree) + { + // we can not write more data to the buffer that we have room for. + return ZIP_BADZIPFILE; + } + + p = zi->ci.central_header + zi->ci.size_centralheader; + + // Add Extra Information Header for 'ZIP64 information' + zip64local_putValue_inmemory(p, 0x0001, 2); // HeaderID + p += 2; + zip64local_putValue_inmemory(p, datasize, 2); // DataSize + p += 2; + + if(uncompressed_size >= 0xffffffff) + { + zip64local_putValue_inmemory(p, uncompressed_size, 8); + p += 8; + } + + if(compressed_size >= 0xffffffff) + { + zip64local_putValue_inmemory(p, compressed_size, 8); + p += 8; + } + + if(zi->ci.pos_local_header >= 0xffffffff) + { + zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8); + p += 8; + } + + // Update how much extra free space we got in the memory buffer + // and increase the centralheader size so the new ZIP64 fields are included + // ( 4 below is the size of HeaderID and DataSize field ) + zi->ci.size_centralExtraFree -= datasize + 4; + zi->ci.size_centralheader += datasize + 4; + + // Update the extra info size field + zi->ci.size_centralExtra += datasize + 4; + zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)zi->ci.size_centralExtra,2); + } + + if (err==ZIP_OK) + err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, (uLong)zi->ci.size_centralheader); + + free(zi->ci.central_header); + + if (err==ZIP_OK) + { + // Update the LocalFileHeader with the new values. + + ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); + + if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ + + if(uncompressed_size >= 0xffffffff || compressed_size >= 0xffffffff ) + { + if(zi->ci.pos_zip64extrainfo > 0) + { + // Update the size in the ZIP64 extended field. + if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_zip64extrainfo + 4,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) /* compressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8); + } + else + err = ZIP_BADZIPFILE; // Caller passed zip64 = 0, so no room for zip64 info -> fatal + } + else + { + if (err==ZIP_OK) /* compressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); + } + + if (ZSEEK64(zi->z_filefunc,zi->filestream, cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + } + + zi->number_entry ++; + zi->in_opened_file_inzip = 0; + + return err; +} + +extern int ZEXPORT zipCloseFileInZip (zipFile file) +{ + return zipCloseFileInZipRaw (file,0,0); +} + +int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip) +{ + int err = ZIP_OK; + ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writing_offset; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDLOCHEADERMAGIC,4); + + /*num disks*/ + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + /*relative offset*/ + if (err==ZIP_OK) /* Relative offset to the Zip64EndOfCentralDirectory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, pos,8); + + /*total disks*/ /* Do not support spawning of disk so always say 1 here*/ + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)1,4); + + return err; +} + +int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) +{ + int err = ZIP_OK; + + uLong Zip64DataSize = 44; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* size of this 'zip64 end of central directory' */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)Zip64DataSize,8); // why ZPOS64_T of this ? + + if (err==ZIP_OK) /* version made by */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); + + if (err==ZIP_OK) /* version needed */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); + + if (err==ZIP_OK) /* number of this disk */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); + + if (err==ZIP_OK) /* total number of entries in the central dir */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); + + if (err==ZIP_OK) /* size of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)size_centraldir,8); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ + { + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writing_offset; + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8); + } + return err; +} +int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) +{ + int err = ZIP_OK; + + /*signature*/ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* number of this disk */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + { + { + if(zi->number_entry >= 0xFFFF) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + } + } + + if (err==ZIP_OK) /* total number of entries in the central dir */ + { + if(zi->number_entry >= 0xFFFF) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + } + + if (err==ZIP_OK) /* size of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ + { + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writing_offset; + if(pos >= 0xffffffff) + { + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)0xffffffff,4); + } + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writing_offset),4); + } + + return err; +} + +int Write_GlobalComment(zip64_internal* zi, const char* global_comment) +{ + int err = ZIP_OK; + uInt size_global_comment = 0; + + if(global_comment != NULL) + size_global_comment = (uInt)strlen(global_comment); + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); + + if (err == ZIP_OK && size_global_comment > 0) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream, global_comment, size_global_comment) != size_global_comment) + err = ZIP_ERRNO; + } + return err; +} + +extern int ZEXPORT zipClose (zipFile file, const char* global_comment) +{ + zip64_internal* zi; + int err = 0; + uLong size_centraldir = 0; + ZPOS64_T centraldir_pos_inzip; + ZPOS64_T pos; + + if (file == NULL) + return ZIP_PARAMERROR; + + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + } + +#ifndef NO_ADDFILEINEXISTINGZIP + if (global_comment==NULL) + global_comment = zi->globalcomment; +#endif + + centraldir_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); + + if (err==ZIP_OK) + { + linkedlist_datablock_internal* ldi = zi->central_dir.first_block; + while (ldi!=NULL) + { + if ((err==ZIP_OK) && (ldi->filled_in_this_block>0)) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream, ldi->data, ldi->filled_in_this_block) != ldi->filled_in_this_block) + err = ZIP_ERRNO; + } + + size_centraldir += ldi->filled_in_this_block; + ldi = ldi->next_datablock; + } + } + free_linkedlist(&(zi->central_dir)); + + pos = centraldir_pos_inzip - zi->add_position_when_writing_offset; + if(pos >= 0xffffffff || zi->number_entry > 0xFFFF) + { + ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream); + Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); + + Write_Zip64EndOfCentralDirectoryLocator(zi, Zip64EOCDpos); + } + + if (err==ZIP_OK) + err = Write_EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); + + if(err == ZIP_OK) + err = Write_GlobalComment(zi, global_comment); + + if (ZCLOSE64(zi->z_filefunc,zi->filestream) != 0) + if (err == ZIP_OK) + err = ZIP_ERRNO; + +#ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(zi->globalcomment); +#endif + TRYFREE(zi); + + return err; +} + +extern int ZEXPORT zipRemoveExtraInfoBlock (char* pData, int* dataLen, short sHeader) +{ + char* p = pData; + int size = 0; + char* pNewHeader; + char* pTmp; + short header; + short dataSize; + + int retVal = ZIP_OK; + + if(pData == NULL || *dataLen < 4) + return ZIP_PARAMERROR; + + pNewHeader = (char*)ALLOC(*dataLen); + pTmp = pNewHeader; + + while(p < (pData + *dataLen)) + { + header = *(short*)p; + dataSize = *(((short*)p)+1); + + if( header == sHeader ) // Header found. + { + p += dataSize + 4; // skip it. do not copy to temp buffer + } + else + { + // Extra Info block should not be removed, So copy it to the temp buffer. + memcpy(pTmp, p, dataSize + 4); + p += dataSize + 4; + size += dataSize + 4; + } + + } + + if(size < *dataLen) + { + // clean old extra info block. + memset(pData,0, *dataLen); + + // copy the new extra info block over the old + if(size > 0) + memcpy(pData, pNewHeader, size); + + // set the new extra info size + *dataLen = size; + + retVal = ZIP_OK; + } + else + retVal = ZIP_ERRNO; + + TRYFREE(pNewHeader); + + return retVal; +} diff --git a/contrib/zlib/contrib/minizip/zip.h b/contrib/zlib/contrib/minizip/zip.h new file mode 100644 index 00000000..8aaebb62 --- /dev/null +++ b/contrib/zlib/contrib/minizip/zip.h @@ -0,0 +1,362 @@ +/* zip.h -- IO on .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + --------------------------------------------------------------------------- + + Changes + + See header of zip.h + +*/ + +#ifndef _zip12_H +#define _zip12_H + +#ifdef __cplusplus +extern "C" { +#endif + +//#define HAVE_BZIP2 + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagzipFile__ { int unused; } zipFile__; +typedef zipFile__ *zipFile; +#else +typedef voidp zipFile; +#endif + +#define ZIP_OK (0) +#define ZIP_EOF (0) +#define ZIP_ERRNO (Z_ERRNO) +#define ZIP_PARAMERROR (-102) +#define ZIP_BADZIPFILE (-103) +#define ZIP_INTERNALERROR (-104) + +#ifndef DEF_MEM_LEVEL +# if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +# else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +# endif +#endif +/* default memLevel */ + +/* tm_zip contain date/time info */ +typedef struct tm_zip_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_zip; + +typedef struct +{ + tm_zip tmz_date; /* date in understandable format */ + uLong dosDate; /* if dos_date == 0, tmu_date is used */ +/* uLong flag; */ /* general purpose bit flag 2 bytes */ + + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ +} zip_fileinfo; + +typedef const char* zipcharpc; + + +#define APPEND_STATUS_CREATE (0) +#define APPEND_STATUS_CREATEAFTER (1) +#define APPEND_STATUS_ADDINZIP (2) + +extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); +extern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append)); +/* + Create a zipfile. + pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on + an Unix computer "zlib/zlib113.zip". + if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip + will be created at the end of the file. + (useful if the file contain a self extractor code) + if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will + add files in existing zip (be sure you don't add file that doesn't exist) + If the zipfile cannot be opened, the return value is NULL. + Else, the return value is a zipFile Handle, usable with other function + of this zip package. +*/ + +/* Note : there is no delete function into a zipfile. + If you want delete file into a zipfile, you must open a zipfile, and create another + Of couse, you can use RAW reading and writing to copy the file you did not want delte +*/ + +extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc_def* pzlib_filefunc_def)); + +extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc64_def* pzlib_filefunc_def)); + +extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level)); + +extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int zip64)); + +/* + Open a file in the ZIP for writing. + filename : the filename in zip (if NULL, '-' without quote will be used + *zipfi contain supplemental information + if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local + contains the extrafield data the the local header + if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global + contains the extrafield data the the local header + if comment != NULL, comment contain the comment string + method contain the compression method (0 for store, Z_DEFLATED for deflate) + level contain the level of compression (can be Z_DEFAULT_COMPRESSION) + zip64 is set to 1 if a zip64 extended information block should be added to the local file header. + this MUST be '1' if the uncompressed size is >= 0xffffffff. + +*/ + + +extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw)); + + +extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int zip64)); +/* + Same than zipOpenNewFileInZip, except if raw=1, we write raw file + */ + +extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting)); + +extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + int zip64 + )); + +/* + Same than zipOpenNewFileInZip2, except + windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 + password : crypting password (NULL for no crypting) + crcForCrypting : crc of file to compress (needed for crypting) + */ + +extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase + )); + + +extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase, + int zip64 + )); +/* + Same than zipOpenNewFileInZip4, except + versionMadeBy : value for Version made by field + flag : value for flag field (compression level info will be added) + */ + + +extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, + const void* buf, + unsigned len)); +/* + Write data in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); +/* + Close the current file in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, + uLong uncompressed_size, + uLong crc32)); + +extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file, + ZPOS64_T uncompressed_size, + uLong crc32)); + +/* + Close the current file in the zipfile, for file opened with + parameter raw=1 in zipOpenNewFileInZip2 + uncompressed_size and crc32 are value for the uncompressed size +*/ + +extern int ZEXPORT zipClose OF((zipFile file, + const char* global_comment)); +/* + Close the zipfile +*/ + + +extern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader)); +/* + zipRemoveExtraInfoBlock - Added by Mathias Svensson + + Remove extra information block from a extra information data for the local file header or central directory header + + It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode. + + 0x0001 is the signature header for the ZIP64 extra information blocks + + usage. + Remove ZIP64 Extra information from a central director extra field data + zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001); + + Remove ZIP64 Extra information from a Local File Header extra field data + zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001); +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _zip64_H */ diff --git a/contrib/zlib/contrib/pascal/example.pas b/contrib/zlib/contrib/pascal/example.pas new file mode 100644 index 00000000..5518b36a --- /dev/null +++ b/contrib/zlib/contrib/pascal/example.pas @@ -0,0 +1,599 @@ +(* example.c -- usage example of the zlib compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Pascal translation + * Copyright (C) 1998 by Jacques Nomssi Nzali. + * For conditions of distribution and use, see copyright notice in readme.txt + * + * Adaptation to the zlibpas interface + * Copyright (C) 2003 by Cosmin Truta. + * For conditions of distribution and use, see copyright notice in readme.txt + *) + +program example; + +{$DEFINE TEST_COMPRESS} +{DO NOT $DEFINE TEST_GZIO} +{$DEFINE TEST_DEFLATE} +{$DEFINE TEST_INFLATE} +{$DEFINE TEST_FLUSH} +{$DEFINE TEST_SYNC} +{$DEFINE TEST_DICT} + +uses SysUtils, zlibpas; + +const TESTFILE = 'foo.gz'; + +(* "hello world" would be more standard, but the repeated "hello" + * stresses the compression code better, sorry... + *) +const hello: PChar = 'hello, hello!'; + +const dictionary: PChar = 'hello'; + +var dictId: LongInt; (* Adler32 value of the dictionary *) + +procedure CHECK_ERR(err: Integer; msg: String); +begin + if err <> Z_OK then + begin + WriteLn(msg, ' error: ', err); + Halt(1); + end; +end; + +procedure EXIT_ERR(const msg: String); +begin + WriteLn('Error: ', msg); + Halt(1); +end; + +(* =========================================================================== + * Test compress and uncompress + *) +{$IFDEF TEST_COMPRESS} +procedure test_compress(compr: Pointer; comprLen: LongInt; + uncompr: Pointer; uncomprLen: LongInt); +var err: Integer; + len: LongInt; +begin + len := StrLen(hello)+1; + + err := compress(compr, comprLen, hello, len); + CHECK_ERR(err, 'compress'); + + StrCopy(PChar(uncompr), 'garbage'); + + err := uncompress(uncompr, uncomprLen, compr, comprLen); + CHECK_ERR(err, 'uncompress'); + + if StrComp(PChar(uncompr), hello) <> 0 then + EXIT_ERR('bad uncompress') + else + WriteLn('uncompress(): ', PChar(uncompr)); +end; +{$ENDIF} + +(* =========================================================================== + * Test read/write of .gz files + *) +{$IFDEF TEST_GZIO} +procedure test_gzio(const fname: PChar; (* compressed file name *) + uncompr: Pointer; + uncomprLen: LongInt); +var err: Integer; + len: Integer; + zfile: gzFile; + pos: LongInt; +begin + len := StrLen(hello)+1; + + zfile := gzopen(fname, 'wb'); + if zfile = NIL then + begin + WriteLn('gzopen error'); + Halt(1); + end; + gzputc(zfile, 'h'); + if gzputs(zfile, 'ello') <> 4 then + begin + WriteLn('gzputs err: ', gzerror(zfile, err)); + Halt(1); + end; + {$IFDEF GZ_FORMAT_STRING} + if gzprintf(zfile, ', %s!', 'hello') <> 8 then + begin + WriteLn('gzprintf err: ', gzerror(zfile, err)); + Halt(1); + end; + {$ELSE} + if gzputs(zfile, ', hello!') <> 8 then + begin + WriteLn('gzputs err: ', gzerror(zfile, err)); + Halt(1); + end; + {$ENDIF} + gzseek(zfile, 1, SEEK_CUR); (* add one zero byte *) + gzclose(zfile); + + zfile := gzopen(fname, 'rb'); + if zfile = NIL then + begin + WriteLn('gzopen error'); + Halt(1); + end; + + StrCopy(PChar(uncompr), 'garbage'); + + if gzread(zfile, uncompr, uncomprLen) <> len then + begin + WriteLn('gzread err: ', gzerror(zfile, err)); + Halt(1); + end; + if StrComp(PChar(uncompr), hello) <> 0 then + begin + WriteLn('bad gzread: ', PChar(uncompr)); + Halt(1); + end + else + WriteLn('gzread(): ', PChar(uncompr)); + + pos := gzseek(zfile, -8, SEEK_CUR); + if (pos <> 6) or (gztell(zfile) <> pos) then + begin + WriteLn('gzseek error, pos=', pos, ', gztell=', gztell(zfile)); + Halt(1); + end; + + if gzgetc(zfile) <> ' ' then + begin + WriteLn('gzgetc error'); + Halt(1); + end; + + if gzungetc(' ', zfile) <> ' ' then + begin + WriteLn('gzungetc error'); + Halt(1); + end; + + gzgets(zfile, PChar(uncompr), uncomprLen); + uncomprLen := StrLen(PChar(uncompr)); + if uncomprLen <> 7 then (* " hello!" *) + begin + WriteLn('gzgets err after gzseek: ', gzerror(zfile, err)); + Halt(1); + end; + if StrComp(PChar(uncompr), hello + 6) <> 0 then + begin + WriteLn('bad gzgets after gzseek'); + Halt(1); + end + else + WriteLn('gzgets() after gzseek: ', PChar(uncompr)); + + gzclose(zfile); +end; +{$ENDIF} + +(* =========================================================================== + * Test deflate with small buffers + *) +{$IFDEF TEST_DEFLATE} +procedure test_deflate(compr: Pointer; comprLen: LongInt); +var c_stream: z_stream; (* compression stream *) + err: Integer; + len: LongInt; +begin + len := StrLen(hello)+1; + + c_stream.zalloc := NIL; + c_stream.zfree := NIL; + c_stream.opaque := NIL; + + err := deflateInit(c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, 'deflateInit'); + + c_stream.next_in := hello; + c_stream.next_out := compr; + + while (c_stream.total_in <> len) and + (c_stream.total_out < comprLen) do + begin + c_stream.avail_out := 1; { force small buffers } + c_stream.avail_in := 1; + err := deflate(c_stream, Z_NO_FLUSH); + CHECK_ERR(err, 'deflate'); + end; + + (* Finish the stream, still forcing small buffers: *) + while TRUE do + begin + c_stream.avail_out := 1; + err := deflate(c_stream, Z_FINISH); + if err = Z_STREAM_END then + break; + CHECK_ERR(err, 'deflate'); + end; + + err := deflateEnd(c_stream); + CHECK_ERR(err, 'deflateEnd'); +end; +{$ENDIF} + +(* =========================================================================== + * Test inflate with small buffers + *) +{$IFDEF TEST_INFLATE} +procedure test_inflate(compr: Pointer; comprLen : LongInt; + uncompr: Pointer; uncomprLen : LongInt); +var err: Integer; + d_stream: z_stream; (* decompression stream *) +begin + StrCopy(PChar(uncompr), 'garbage'); + + d_stream.zalloc := NIL; + d_stream.zfree := NIL; + d_stream.opaque := NIL; + + d_stream.next_in := compr; + d_stream.avail_in := 0; + d_stream.next_out := uncompr; + + err := inflateInit(d_stream); + CHECK_ERR(err, 'inflateInit'); + + while (d_stream.total_out < uncomprLen) and + (d_stream.total_in < comprLen) do + begin + d_stream.avail_out := 1; (* force small buffers *) + d_stream.avail_in := 1; + err := inflate(d_stream, Z_NO_FLUSH); + if err = Z_STREAM_END then + break; + CHECK_ERR(err, 'inflate'); + end; + + err := inflateEnd(d_stream); + CHECK_ERR(err, 'inflateEnd'); + + if StrComp(PChar(uncompr), hello) <> 0 then + EXIT_ERR('bad inflate') + else + WriteLn('inflate(): ', PChar(uncompr)); +end; +{$ENDIF} + +(* =========================================================================== + * Test deflate with large buffers and dynamic change of compression level + *) +{$IFDEF TEST_DEFLATE} +procedure test_large_deflate(compr: Pointer; comprLen: LongInt; + uncompr: Pointer; uncomprLen: LongInt); +var c_stream: z_stream; (* compression stream *) + err: Integer; +begin + c_stream.zalloc := NIL; + c_stream.zfree := NIL; + c_stream.opaque := NIL; + + err := deflateInit(c_stream, Z_BEST_SPEED); + CHECK_ERR(err, 'deflateInit'); + + c_stream.next_out := compr; + c_stream.avail_out := Integer(comprLen); + + (* At this point, uncompr is still mostly zeroes, so it should compress + * very well: + *) + c_stream.next_in := uncompr; + c_stream.avail_in := Integer(uncomprLen); + err := deflate(c_stream, Z_NO_FLUSH); + CHECK_ERR(err, 'deflate'); + if c_stream.avail_in <> 0 then + EXIT_ERR('deflate not greedy'); + + (* Feed in already compressed data and switch to no compression: *) + deflateParams(c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); + c_stream.next_in := compr; + c_stream.avail_in := Integer(comprLen div 2); + err := deflate(c_stream, Z_NO_FLUSH); + CHECK_ERR(err, 'deflate'); + + (* Switch back to compressing mode: *) + deflateParams(c_stream, Z_BEST_COMPRESSION, Z_FILTERED); + c_stream.next_in := uncompr; + c_stream.avail_in := Integer(uncomprLen); + err := deflate(c_stream, Z_NO_FLUSH); + CHECK_ERR(err, 'deflate'); + + err := deflate(c_stream, Z_FINISH); + if err <> Z_STREAM_END then + EXIT_ERR('deflate should report Z_STREAM_END'); + + err := deflateEnd(c_stream); + CHECK_ERR(err, 'deflateEnd'); +end; +{$ENDIF} + +(* =========================================================================== + * Test inflate with large buffers + *) +{$IFDEF TEST_INFLATE} +procedure test_large_inflate(compr: Pointer; comprLen: LongInt; + uncompr: Pointer; uncomprLen: LongInt); +var err: Integer; + d_stream: z_stream; (* decompression stream *) +begin + StrCopy(PChar(uncompr), 'garbage'); + + d_stream.zalloc := NIL; + d_stream.zfree := NIL; + d_stream.opaque := NIL; + + d_stream.next_in := compr; + d_stream.avail_in := Integer(comprLen); + + err := inflateInit(d_stream); + CHECK_ERR(err, 'inflateInit'); + + while TRUE do + begin + d_stream.next_out := uncompr; (* discard the output *) + d_stream.avail_out := Integer(uncomprLen); + err := inflate(d_stream, Z_NO_FLUSH); + if err = Z_STREAM_END then + break; + CHECK_ERR(err, 'large inflate'); + end; + + err := inflateEnd(d_stream); + CHECK_ERR(err, 'inflateEnd'); + + if d_stream.total_out <> 2 * uncomprLen + comprLen div 2 then + begin + WriteLn('bad large inflate: ', d_stream.total_out); + Halt(1); + end + else + WriteLn('large_inflate(): OK'); +end; +{$ENDIF} + +(* =========================================================================== + * Test deflate with full flush + *) +{$IFDEF TEST_FLUSH} +procedure test_flush(compr: Pointer; var comprLen : LongInt); +var c_stream: z_stream; (* compression stream *) + err: Integer; + len: Integer; +begin + len := StrLen(hello)+1; + + c_stream.zalloc := NIL; + c_stream.zfree := NIL; + c_stream.opaque := NIL; + + err := deflateInit(c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, 'deflateInit'); + + c_stream.next_in := hello; + c_stream.next_out := compr; + c_stream.avail_in := 3; + c_stream.avail_out := Integer(comprLen); + err := deflate(c_stream, Z_FULL_FLUSH); + CHECK_ERR(err, 'deflate'); + + Inc(PByteArray(compr)^[3]); (* force an error in first compressed block *) + c_stream.avail_in := len - 3; + + err := deflate(c_stream, Z_FINISH); + if err <> Z_STREAM_END then + CHECK_ERR(err, 'deflate'); + + err := deflateEnd(c_stream); + CHECK_ERR(err, 'deflateEnd'); + + comprLen := c_stream.total_out; +end; +{$ENDIF} + +(* =========================================================================== + * Test inflateSync() + *) +{$IFDEF TEST_SYNC} +procedure test_sync(compr: Pointer; comprLen: LongInt; + uncompr: Pointer; uncomprLen : LongInt); +var err: Integer; + d_stream: z_stream; (* decompression stream *) +begin + StrCopy(PChar(uncompr), 'garbage'); + + d_stream.zalloc := NIL; + d_stream.zfree := NIL; + d_stream.opaque := NIL; + + d_stream.next_in := compr; + d_stream.avail_in := 2; (* just read the zlib header *) + + err := inflateInit(d_stream); + CHECK_ERR(err, 'inflateInit'); + + d_stream.next_out := uncompr; + d_stream.avail_out := Integer(uncomprLen); + + inflate(d_stream, Z_NO_FLUSH); + CHECK_ERR(err, 'inflate'); + + d_stream.avail_in := Integer(comprLen-2); (* read all compressed data *) + err := inflateSync(d_stream); (* but skip the damaged part *) + CHECK_ERR(err, 'inflateSync'); + + err := inflate(d_stream, Z_FINISH); + if err <> Z_DATA_ERROR then + EXIT_ERR('inflate should report DATA_ERROR'); + (* Because of incorrect adler32 *) + + err := inflateEnd(d_stream); + CHECK_ERR(err, 'inflateEnd'); + + WriteLn('after inflateSync(): hel', PChar(uncompr)); +end; +{$ENDIF} + +(* =========================================================================== + * Test deflate with preset dictionary + *) +{$IFDEF TEST_DICT} +procedure test_dict_deflate(compr: Pointer; comprLen: LongInt); +var c_stream: z_stream; (* compression stream *) + err: Integer; +begin + c_stream.zalloc := NIL; + c_stream.zfree := NIL; + c_stream.opaque := NIL; + + err := deflateInit(c_stream, Z_BEST_COMPRESSION); + CHECK_ERR(err, 'deflateInit'); + + err := deflateSetDictionary(c_stream, dictionary, StrLen(dictionary)); + CHECK_ERR(err, 'deflateSetDictionary'); + + dictId := c_stream.adler; + c_stream.next_out := compr; + c_stream.avail_out := Integer(comprLen); + + c_stream.next_in := hello; + c_stream.avail_in := StrLen(hello)+1; + + err := deflate(c_stream, Z_FINISH); + if err <> Z_STREAM_END then + EXIT_ERR('deflate should report Z_STREAM_END'); + + err := deflateEnd(c_stream); + CHECK_ERR(err, 'deflateEnd'); +end; +{$ENDIF} + +(* =========================================================================== + * Test inflate with a preset dictionary + *) +{$IFDEF TEST_DICT} +procedure test_dict_inflate(compr: Pointer; comprLen: LongInt; + uncompr: Pointer; uncomprLen: LongInt); +var err: Integer; + d_stream: z_stream; (* decompression stream *) +begin + StrCopy(PChar(uncompr), 'garbage'); + + d_stream.zalloc := NIL; + d_stream.zfree := NIL; + d_stream.opaque := NIL; + + d_stream.next_in := compr; + d_stream.avail_in := Integer(comprLen); + + err := inflateInit(d_stream); + CHECK_ERR(err, 'inflateInit'); + + d_stream.next_out := uncompr; + d_stream.avail_out := Integer(uncomprLen); + + while TRUE do + begin + err := inflate(d_stream, Z_NO_FLUSH); + if err = Z_STREAM_END then + break; + if err = Z_NEED_DICT then + begin + if d_stream.adler <> dictId then + EXIT_ERR('unexpected dictionary'); + err := inflateSetDictionary(d_stream, dictionary, StrLen(dictionary)); + end; + CHECK_ERR(err, 'inflate with dict'); + end; + + err := inflateEnd(d_stream); + CHECK_ERR(err, 'inflateEnd'); + + if StrComp(PChar(uncompr), hello) <> 0 then + EXIT_ERR('bad inflate with dict') + else + WriteLn('inflate with dictionary: ', PChar(uncompr)); +end; +{$ENDIF} + +var compr, uncompr: Pointer; + comprLen, uncomprLen: LongInt; + +begin + if zlibVersion^ <> ZLIB_VERSION[1] then + EXIT_ERR('Incompatible zlib version'); + + WriteLn('zlib version: ', zlibVersion); + WriteLn('zlib compile flags: ', Format('0x%x', [zlibCompileFlags])); + + comprLen := 10000 * SizeOf(Integer); (* don't overflow on MSDOS *) + uncomprLen := comprLen; + GetMem(compr, comprLen); + GetMem(uncompr, uncomprLen); + if (compr = NIL) or (uncompr = NIL) then + EXIT_ERR('Out of memory'); + (* compr and uncompr are cleared to avoid reading uninitialized + * data and to ensure that uncompr compresses well. + *) + FillChar(compr^, comprLen, 0); + FillChar(uncompr^, uncomprLen, 0); + + {$IFDEF TEST_COMPRESS} + WriteLn('** Testing compress'); + test_compress(compr, comprLen, uncompr, uncomprLen); + {$ENDIF} + + {$IFDEF TEST_GZIO} + WriteLn('** Testing gzio'); + if ParamCount >= 1 then + test_gzio(ParamStr(1), uncompr, uncomprLen) + else + test_gzio(TESTFILE, uncompr, uncomprLen); + {$ENDIF} + + {$IFDEF TEST_DEFLATE} + WriteLn('** Testing deflate with small buffers'); + test_deflate(compr, comprLen); + {$ENDIF} + {$IFDEF TEST_INFLATE} + WriteLn('** Testing inflate with small buffers'); + test_inflate(compr, comprLen, uncompr, uncomprLen); + {$ENDIF} + + {$IFDEF TEST_DEFLATE} + WriteLn('** Testing deflate with large buffers'); + test_large_deflate(compr, comprLen, uncompr, uncomprLen); + {$ENDIF} + {$IFDEF TEST_INFLATE} + WriteLn('** Testing inflate with large buffers'); + test_large_inflate(compr, comprLen, uncompr, uncomprLen); + {$ENDIF} + + {$IFDEF TEST_FLUSH} + WriteLn('** Testing deflate with full flush'); + test_flush(compr, comprLen); + {$ENDIF} + {$IFDEF TEST_SYNC} + WriteLn('** Testing inflateSync'); + test_sync(compr, comprLen, uncompr, uncomprLen); + {$ENDIF} + comprLen := uncomprLen; + + {$IFDEF TEST_DICT} + WriteLn('** Testing deflate and inflate with preset dictionary'); + test_dict_deflate(compr, comprLen); + test_dict_inflate(compr, comprLen, uncompr, uncomprLen); + {$ENDIF} + + FreeMem(compr, comprLen); + FreeMem(uncompr, uncomprLen); +end. diff --git a/contrib/zlib/contrib/pascal/readme.txt b/contrib/zlib/contrib/pascal/readme.txt new file mode 100644 index 00000000..60e87c8a --- /dev/null +++ b/contrib/zlib/contrib/pascal/readme.txt @@ -0,0 +1,76 @@ + +This directory contains a Pascal (Delphi, Kylix) interface to the +zlib data compression library. + + +Directory listing +================= + +zlibd32.mak makefile for Borland C++ +example.pas usage example of zlib +zlibpas.pas the Pascal interface to zlib +readme.txt this file + + +Compatibility notes +=================== + +- Although the name "zlib" would have been more normal for the + zlibpas unit, this name is already taken by Borland's ZLib unit. + This is somehow unfortunate, because that unit is not a genuine + interface to the full-fledged zlib functionality, but a suite of + class wrappers around zlib streams. Other essential features, + such as checksums, are missing. + It would have been more appropriate for that unit to have a name + like "ZStreams", or something similar. + +- The C and zlib-supplied types int, uInt, long, uLong, etc. are + translated directly into Pascal types of similar sizes (Integer, + LongInt, etc.), to avoid namespace pollution. In particular, + there is no conversion of unsigned int into a Pascal unsigned + integer. The Word type is non-portable and has the same size + (16 bits) both in a 16-bit and in a 32-bit environment, unlike + Integer. Even if there is a 32-bit Cardinal type, there is no + real need for unsigned int in zlib under a 32-bit environment. + +- Except for the callbacks, the zlib function interfaces are + assuming the calling convention normally used in Pascal + (__pascal for DOS and Windows16, __fastcall for Windows32). + Since the cdecl keyword is used, the old Turbo Pascal does + not work with this interface. + +- The gz* function interfaces are not translated, to avoid + interfacing problems with the C runtime library. Besides, + gzprintf(gzFile file, const char *format, ...) + cannot be translated into Pascal. + + +Legal issues +============ + +The zlibpas interface is: + Copyright (C) 1995-2003 Jean-loup Gailly and Mark Adler. + Copyright (C) 1998 by Bob Dellaca. + Copyright (C) 2003 by Cosmin Truta. + +The example program is: + Copyright (C) 1995-2003 by Jean-loup Gailly. + Copyright (C) 1998,1999,2000 by Jacques Nomssi Nzali. + Copyright (C) 2003 by Cosmin Truta. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + diff --git a/contrib/zlib/contrib/pascal/zlibd32.mak b/contrib/zlib/contrib/pascal/zlibd32.mak new file mode 100644 index 00000000..9bb00b7c --- /dev/null +++ b/contrib/zlib/contrib/pascal/zlibd32.mak @@ -0,0 +1,99 @@ +# Makefile for zlib +# For use with Delphi and C++ Builder under Win32 +# Updated for zlib 1.2.x by Cosmin Truta + +# ------------ Borland C++ ------------ + +# This project uses the Delphi (fastcall/register) calling convention: +LOC = -DZEXPORT=__fastcall -DZEXPORTVA=__cdecl + +CC = bcc32 +LD = bcc32 +AR = tlib +# do not use "-pr" in CFLAGS +CFLAGS = -a -d -k- -O2 $(LOC) +LDFLAGS = + + +# variables +ZLIB_LIB = zlib.lib + +OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzclose.obj gzlib.obj gzread.obj +OBJ2 = gzwrite.obj infback.obj inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj +OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzclose.obj+gzlib.obj+gzread.obj +OBJP2 = +gzwrite.obj+infback.obj+inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj + + +# targets +all: $(ZLIB_LIB) example.exe minigzip.exe + +.c.obj: + $(CC) -c $(CFLAGS) $*.c + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzclose.obj: gzclose.c zlib.h zconf.h gzguts.h + +gzlib.obj: gzlib.c zlib.h zconf.h gzguts.h + +gzread.obj: gzread.c zlib.h zconf.h gzguts.h + +gzwrite.obj: gzwrite.c zlib.h zconf.h gzguts.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: test/example.c zlib.h zconf.h + +minigzip.obj: test/minigzip.c zlib.h zconf.h + + +# For the sake of the old Borland make, +# the command line is cut to fit in the MS-DOS 128 byte limit: +$(ZLIB_LIB): $(OBJ1) $(OBJ2) + -del $(ZLIB_LIB) + $(AR) $(ZLIB_LIB) $(OBJP1) + $(AR) $(ZLIB_LIB) $(OBJP2) + + +# testing +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +example.exe: example.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB) + +minigzip.exe: minigzip.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB) + + +# cleanup +clean: + -del *.obj + -del *.exe + -del *.lib + -del *.tds + -del zlib.bak + -del foo.gz + diff --git a/contrib/zlib/contrib/pascal/zlibpas.pas b/contrib/zlib/contrib/pascal/zlibpas.pas new file mode 100644 index 00000000..a0dff11b --- /dev/null +++ b/contrib/zlib/contrib/pascal/zlibpas.pas @@ -0,0 +1,276 @@ +(* zlibpas -- Pascal interface to the zlib data compression library + * + * Copyright (C) 2003 Cosmin Truta. + * Derived from original sources by Bob Dellaca. + * For conditions of distribution and use, see copyright notice in readme.txt + *) + +unit zlibpas; + +interface + +const + ZLIB_VERSION = '1.2.11'; + ZLIB_VERNUM = $12a0; + +type + alloc_func = function(opaque: Pointer; items, size: Integer): Pointer; + cdecl; + free_func = procedure(opaque, address: Pointer); + cdecl; + + in_func = function(opaque: Pointer; var buf: PByte): Integer; + cdecl; + out_func = function(opaque: Pointer; buf: PByte; size: Integer): Integer; + cdecl; + + z_streamp = ^z_stream; + z_stream = packed record + next_in: PChar; (* next input byte *) + avail_in: Integer; (* number of bytes available at next_in *) + total_in: LongInt; (* total nb of input bytes read so far *) + + next_out: PChar; (* next output byte should be put there *) + avail_out: Integer; (* remaining free space at next_out *) + total_out: LongInt; (* total nb of bytes output so far *) + + msg: PChar; (* last error message, NULL if no error *) + state: Pointer; (* not visible by applications *) + + zalloc: alloc_func; (* used to allocate the internal state *) + zfree: free_func; (* used to free the internal state *) + opaque: Pointer; (* private data object passed to zalloc and zfree *) + + data_type: Integer; (* best guess about the data type: ascii or binary *) + adler: LongInt; (* adler32 value of the uncompressed data *) + reserved: LongInt; (* reserved for future use *) + end; + + gz_headerp = ^gz_header; + gz_header = packed record + text: Integer; (* true if compressed data believed to be text *) + time: LongInt; (* modification time *) + xflags: Integer; (* extra flags (not used when writing a gzip file) *) + os: Integer; (* operating system *) + extra: PChar; (* pointer to extra field or Z_NULL if none *) + extra_len: Integer; (* extra field length (valid if extra != Z_NULL) *) + extra_max: Integer; (* space at extra (only when reading header) *) + name: PChar; (* pointer to zero-terminated file name or Z_NULL *) + name_max: Integer; (* space at name (only when reading header) *) + comment: PChar; (* pointer to zero-terminated comment or Z_NULL *) + comm_max: Integer; (* space at comment (only when reading header) *) + hcrc: Integer; (* true if there was or will be a header crc *) + done: Integer; (* true when done reading gzip header *) + end; + +(* constants *) +const + Z_NO_FLUSH = 0; + Z_PARTIAL_FLUSH = 1; + Z_SYNC_FLUSH = 2; + Z_FULL_FLUSH = 3; + Z_FINISH = 4; + Z_BLOCK = 5; + Z_TREES = 6; + + Z_OK = 0; + Z_STREAM_END = 1; + Z_NEED_DICT = 2; + Z_ERRNO = -1; + Z_STREAM_ERROR = -2; + Z_DATA_ERROR = -3; + Z_MEM_ERROR = -4; + Z_BUF_ERROR = -5; + Z_VERSION_ERROR = -6; + + Z_NO_COMPRESSION = 0; + Z_BEST_SPEED = 1; + Z_BEST_COMPRESSION = 9; + Z_DEFAULT_COMPRESSION = -1; + + Z_FILTERED = 1; + Z_HUFFMAN_ONLY = 2; + Z_RLE = 3; + Z_FIXED = 4; + Z_DEFAULT_STRATEGY = 0; + + Z_BINARY = 0; + Z_TEXT = 1; + Z_ASCII = 1; + Z_UNKNOWN = 2; + + Z_DEFLATED = 8; + +(* basic functions *) +function zlibVersion: PChar; +function deflateInit(var strm: z_stream; level: Integer): Integer; +function deflate(var strm: z_stream; flush: Integer): Integer; +function deflateEnd(var strm: z_stream): Integer; +function inflateInit(var strm: z_stream): Integer; +function inflate(var strm: z_stream; flush: Integer): Integer; +function inflateEnd(var strm: z_stream): Integer; + +(* advanced functions *) +function deflateInit2(var strm: z_stream; level, method, windowBits, + memLevel, strategy: Integer): Integer; +function deflateSetDictionary(var strm: z_stream; const dictionary: PChar; + dictLength: Integer): Integer; +function deflateCopy(var dest, source: z_stream): Integer; +function deflateReset(var strm: z_stream): Integer; +function deflateParams(var strm: z_stream; level, strategy: Integer): Integer; +function deflateTune(var strm: z_stream; good_length, max_lazy, nice_length, max_chain: Integer): Integer; +function deflateBound(var strm: z_stream; sourceLen: LongInt): LongInt; +function deflatePending(var strm: z_stream; var pending: Integer; var bits: Integer): Integer; +function deflatePrime(var strm: z_stream; bits, value: Integer): Integer; +function deflateSetHeader(var strm: z_stream; head: gz_header): Integer; +function inflateInit2(var strm: z_stream; windowBits: Integer): Integer; +function inflateSetDictionary(var strm: z_stream; const dictionary: PChar; + dictLength: Integer): Integer; +function inflateSync(var strm: z_stream): Integer; +function inflateCopy(var dest, source: z_stream): Integer; +function inflateReset(var strm: z_stream): Integer; +function inflateReset2(var strm: z_stream; windowBits: Integer): Integer; +function inflatePrime(var strm: z_stream; bits, value: Integer): Integer; +function inflateMark(var strm: z_stream): LongInt; +function inflateGetHeader(var strm: z_stream; var head: gz_header): Integer; +function inflateBackInit(var strm: z_stream; + windowBits: Integer; window: PChar): Integer; +function inflateBack(var strm: z_stream; in_fn: in_func; in_desc: Pointer; + out_fn: out_func; out_desc: Pointer): Integer; +function inflateBackEnd(var strm: z_stream): Integer; +function zlibCompileFlags: LongInt; + +(* utility functions *) +function compress(dest: PChar; var destLen: LongInt; + const source: PChar; sourceLen: LongInt): Integer; +function compress2(dest: PChar; var destLen: LongInt; + const source: PChar; sourceLen: LongInt; + level: Integer): Integer; +function compressBound(sourceLen: LongInt): LongInt; +function uncompress(dest: PChar; var destLen: LongInt; + const source: PChar; sourceLen: LongInt): Integer; + +(* checksum functions *) +function adler32(adler: LongInt; const buf: PChar; len: Integer): LongInt; +function adler32_combine(adler1, adler2, len2: LongInt): LongInt; +function crc32(crc: LongInt; const buf: PChar; len: Integer): LongInt; +function crc32_combine(crc1, crc2, len2: LongInt): LongInt; + +(* various hacks, don't look :) *) +function deflateInit_(var strm: z_stream; level: Integer; + const version: PChar; stream_size: Integer): Integer; +function inflateInit_(var strm: z_stream; const version: PChar; + stream_size: Integer): Integer; +function deflateInit2_(var strm: z_stream; + level, method, windowBits, memLevel, strategy: Integer; + const version: PChar; stream_size: Integer): Integer; +function inflateInit2_(var strm: z_stream; windowBits: Integer; + const version: PChar; stream_size: Integer): Integer; +function inflateBackInit_(var strm: z_stream; + windowBits: Integer; window: PChar; + const version: PChar; stream_size: Integer): Integer; + + +implementation + +{$L adler32.obj} +{$L compress.obj} +{$L crc32.obj} +{$L deflate.obj} +{$L infback.obj} +{$L inffast.obj} +{$L inflate.obj} +{$L inftrees.obj} +{$L trees.obj} +{$L uncompr.obj} +{$L zutil.obj} + +function adler32; external; +function adler32_combine; external; +function compress; external; +function compress2; external; +function compressBound; external; +function crc32; external; +function crc32_combine; external; +function deflate; external; +function deflateBound; external; +function deflateCopy; external; +function deflateEnd; external; +function deflateInit_; external; +function deflateInit2_; external; +function deflateParams; external; +function deflatePending; external; +function deflatePrime; external; +function deflateReset; external; +function deflateSetDictionary; external; +function deflateSetHeader; external; +function deflateTune; external; +function inflate; external; +function inflateBack; external; +function inflateBackEnd; external; +function inflateBackInit_; external; +function inflateCopy; external; +function inflateEnd; external; +function inflateGetHeader; external; +function inflateInit_; external; +function inflateInit2_; external; +function inflateMark; external; +function inflatePrime; external; +function inflateReset; external; +function inflateReset2; external; +function inflateSetDictionary; external; +function inflateSync; external; +function uncompress; external; +function zlibCompileFlags; external; +function zlibVersion; external; + +function deflateInit(var strm: z_stream; level: Integer): Integer; +begin + Result := deflateInit_(strm, level, ZLIB_VERSION, sizeof(z_stream)); +end; + +function deflateInit2(var strm: z_stream; level, method, windowBits, memLevel, + strategy: Integer): Integer; +begin + Result := deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + ZLIB_VERSION, sizeof(z_stream)); +end; + +function inflateInit(var strm: z_stream): Integer; +begin + Result := inflateInit_(strm, ZLIB_VERSION, sizeof(z_stream)); +end; + +function inflateInit2(var strm: z_stream; windowBits: Integer): Integer; +begin + Result := inflateInit2_(strm, windowBits, ZLIB_VERSION, sizeof(z_stream)); +end; + +function inflateBackInit(var strm: z_stream; + windowBits: Integer; window: PChar): Integer; +begin + Result := inflateBackInit_(strm, windowBits, window, + ZLIB_VERSION, sizeof(z_stream)); +end; + +function _malloc(Size: Integer): Pointer; cdecl; +begin + GetMem(Result, Size); +end; + +procedure _free(Block: Pointer); cdecl; +begin + FreeMem(Block); +end; + +procedure _memset(P: Pointer; B: Byte; count: Integer); cdecl; +begin + FillChar(P^, count, B); +end; + +procedure _memcpy(dest, source: Pointer; count: Integer); cdecl; +begin + Move(source^, dest^, count); +end; + +end. diff --git a/contrib/zlib/contrib/puff/Makefile b/contrib/zlib/contrib/puff/Makefile new file mode 100644 index 00000000..0e2594c8 --- /dev/null +++ b/contrib/zlib/contrib/puff/Makefile @@ -0,0 +1,42 @@ +CFLAGS=-O + +puff: puff.o pufftest.o + +puff.o: puff.h + +pufftest.o: puff.h + +test: puff + puff zeros.raw + +puft: puff.c puff.h pufftest.o + cc -fprofile-arcs -ftest-coverage -o puft puff.c pufftest.o + +# puff full coverage test (should say 100%) +cov: puft + @rm -f *.gcov *.gcda + @puft -w zeros.raw 2>&1 | cat > /dev/null + @echo '04' | xxd -r -p | puft 2> /dev/null || test $$? -eq 2 + @echo '00' | xxd -r -p | puft 2> /dev/null || test $$? -eq 2 + @echo '00 00 00 00 00' | xxd -r -p | puft 2> /dev/null || test $$? -eq 254 + @echo '00 01 00 fe ff' | xxd -r -p | puft 2> /dev/null || test $$? -eq 2 + @echo '01 01 00 fe ff 0a' | xxd -r -p | puft -f 2>&1 | cat > /dev/null + @echo '02 7e ff ff' | xxd -r -p | puft 2> /dev/null || test $$? -eq 246 + @echo '02' | xxd -r -p | puft 2> /dev/null || test $$? -eq 2 + @echo '04 80 49 92 24 49 92 24 0f b4 ff ff c3 04' | xxd -r -p | puft 2> /dev/null || test $$? -eq 2 + @echo '04 80 49 92 24 49 92 24 71 ff ff 93 11 00' | xxd -r -p | puft 2> /dev/null || test $$? -eq 249 + @echo '04 c0 81 08 00 00 00 00 20 7f eb 0b 00 00' | xxd -r -p | puft 2> /dev/null || test $$? -eq 246 + @echo '0b 00 00' | xxd -r -p | puft -f 2>&1 | cat > /dev/null + @echo '1a 07' | xxd -r -p | puft 2> /dev/null || test $$? -eq 246 + @echo '0c c0 81 00 00 00 00 00 90 ff 6b 04' | xxd -r -p | puft 2> /dev/null || test $$? -eq 245 + @puft -f zeros.raw 2>&1 | cat > /dev/null + @echo 'fc 00 00' | xxd -r -p | puft 2> /dev/null || test $$? -eq 253 + @echo '04 00 fe ff' | xxd -r -p | puft 2> /dev/null || test $$? -eq 252 + @echo '04 00 24 49' | xxd -r -p | puft 2> /dev/null || test $$? -eq 251 + @echo '04 80 49 92 24 49 92 24 0f b4 ff ff c3 84' | xxd -r -p | puft 2> /dev/null || test $$? -eq 248 + @echo '04 00 24 e9 ff ff' | xxd -r -p | puft 2> /dev/null || test $$? -eq 250 + @echo '04 00 24 e9 ff 6d' | xxd -r -p | puft 2> /dev/null || test $$? -eq 247 + @gcov -n puff.c + +clean: + rm -f puff puft *.o *.gc* diff --git a/contrib/zlib/contrib/puff/README b/contrib/zlib/contrib/puff/README new file mode 100644 index 00000000..bbc4cb59 --- /dev/null +++ b/contrib/zlib/contrib/puff/README @@ -0,0 +1,63 @@ +Puff -- A Simple Inflate +3 Mar 2003 +Mark Adler +madler@alumni.caltech.edu + +What this is -- + +puff.c provides the routine puff() to decompress the deflate data format. It +does so more slowly than zlib, but the code is about one-fifth the size of the +inflate code in zlib, and written to be very easy to read. + +Why I wrote this -- + +puff.c was written to document the deflate format unambiguously, by virtue of +being working C code. It is meant to supplement RFC 1951, which formally +describes the deflate format. I have received many questions on details of the +deflate format, and I hope that reading this code will answer those questions. +puff.c is heavily commented with details of the deflate format, especially +those little nooks and cranies of the format that might not be obvious from a +specification. + +puff.c may also be useful in applications where code size or memory usage is a +very limited resource, and speed is not as important. + +How to use it -- + +Well, most likely you should just be reading puff.c and using zlib for actual +applications, but if you must ... + +Include puff.h in your code, which provides this prototype: + +int puff(unsigned char *dest, /* pointer to destination pointer */ + unsigned long *destlen, /* amount of output space */ + unsigned char *source, /* pointer to source data pointer */ + unsigned long *sourcelen); /* amount of input available */ + +Then you can call puff() to decompress a deflate stream that is in memory in +its entirety at source, to a sufficiently sized block of memory for the +decompressed data at dest. puff() is the only external symbol in puff.c The +only C library functions that puff.c needs are setjmp() and longjmp(), which +are used to simplify error checking in the code to improve readabilty. puff.c +does no memory allocation, and uses less than 2K bytes off of the stack. + +If destlen is not enough space for the uncompressed data, then inflate will +return an error without writing more than destlen bytes. Note that this means +that in order to decompress the deflate data successfully, you need to know +the size of the uncompressed data ahead of time. + +If needed, puff() can determine the size of the uncompressed data with no +output space. This is done by passing dest equal to (unsigned char *)0. Then +the initial value of *destlen is ignored and *destlen is set to the length of +the uncompressed data. So if the size of the uncompressed data is not known, +then two passes of puff() can be used--first to determine the size, and second +to do the actual inflation after allocating the appropriate memory. Not +pretty, but it works. (This is one of the reasons you should be using zlib.) + +The deflate format is self-terminating. If the deflate stream does not end +in *sourcelen bytes, puff() will return an error without reading at or past +endsource. + +On return, *sourcelen is updated to the amount of input data consumed, and +*destlen is updated to the size of the uncompressed data. See the comments +in puff.c for the possible return codes for puff(). diff --git a/contrib/zlib/contrib/puff/puff.c b/contrib/zlib/contrib/puff/puff.c new file mode 100644 index 00000000..c6c90d71 --- /dev/null +++ b/contrib/zlib/contrib/puff/puff.c @@ -0,0 +1,840 @@ +/* + * puff.c + * Copyright (C) 2002-2013 Mark Adler + * For conditions of distribution and use, see copyright notice in puff.h + * version 2.3, 21 Jan 2013 + * + * puff.c is a simple inflate written to be an unambiguous way to specify the + * deflate format. It is not written for speed but rather simplicity. As a + * side benefit, this code might actually be useful when small code is more + * important than speed, such as bootstrap applications. For typical deflate + * data, zlib's inflate() is about four times as fast as puff(). zlib's + * inflate compiles to around 20K on my machine, whereas puff.c compiles to + * around 4K on my machine (a PowerPC using GNU cc). If the faster decode() + * function here is used, then puff() is only twice as slow as zlib's + * inflate(). + * + * All dynamically allocated memory comes from the stack. The stack required + * is less than 2K bytes. This code is compatible with 16-bit int's and + * assumes that long's are at least 32 bits. puff.c uses the short data type, + * assumed to be 16 bits, for arrays in order to conserve memory. The code + * works whether integers are stored big endian or little endian. + * + * In the comments below are "Format notes" that describe the inflate process + * and document some of the less obvious aspects of the format. This source + * code is meant to supplement RFC 1951, which formally describes the deflate + * format: + * + * http://www.zlib.org/rfc-deflate.html + */ + +/* + * Change history: + * + * 1.0 10 Feb 2002 - First version + * 1.1 17 Feb 2002 - Clarifications of some comments and notes + * - Update puff() dest and source pointers on negative + * errors to facilitate debugging deflators + * - Remove longest from struct huffman -- not needed + * - Simplify offs[] index in construct() + * - Add input size and checking, using longjmp() to + * maintain easy readability + * - Use short data type for large arrays + * - Use pointers instead of long to specify source and + * destination sizes to avoid arbitrary 4 GB limits + * 1.2 17 Mar 2002 - Add faster version of decode(), doubles speed (!), + * but leave simple version for readabilty + * - Make sure invalid distances detected if pointers + * are 16 bits + * - Fix fixed codes table error + * - Provide a scanning mode for determining size of + * uncompressed data + * 1.3 20 Mar 2002 - Go back to lengths for puff() parameters [Gailly] + * - Add a puff.h file for the interface + * - Add braces in puff() for else do [Gailly] + * - Use indexes instead of pointers for readability + * 1.4 31 Mar 2002 - Simplify construct() code set check + * - Fix some comments + * - Add FIXLCODES #define + * 1.5 6 Apr 2002 - Minor comment fixes + * 1.6 7 Aug 2002 - Minor format changes + * 1.7 3 Mar 2003 - Added test code for distribution + * - Added zlib-like license + * 1.8 9 Jan 2004 - Added some comments on no distance codes case + * 1.9 21 Feb 2008 - Fix bug on 16-bit integer architectures [Pohland] + * - Catch missing end-of-block symbol error + * 2.0 25 Jul 2008 - Add #define to permit distance too far back + * - Add option in TEST code for puff to write the data + * - Add option in TEST code to skip input bytes + * - Allow TEST code to read from piped stdin + * 2.1 4 Apr 2010 - Avoid variable initialization for happier compilers + * - Avoid unsigned comparisons for even happier compilers + * 2.2 25 Apr 2010 - Fix bug in variable initializations [Oberhumer] + * - Add const where appropriate [Oberhumer] + * - Split if's and ?'s for coverage testing + * - Break out test code to separate file + * - Move NIL to puff.h + * - Allow incomplete code only if single code length is 1 + * - Add full code coverage test to Makefile + * 2.3 21 Jan 2013 - Check for invalid code length codes in dynamic blocks + */ + +#include /* for setjmp(), longjmp(), and jmp_buf */ +#include "puff.h" /* prototype for puff() */ + +#define local static /* for local function definitions */ + +/* + * Maximums for allocations and loops. It is not useful to change these -- + * they are fixed by the deflate format. + */ +#define MAXBITS 15 /* maximum bits in a code */ +#define MAXLCODES 286 /* maximum number of literal/length codes */ +#define MAXDCODES 30 /* maximum number of distance codes */ +#define MAXCODES (MAXLCODES+MAXDCODES) /* maximum codes lengths to read */ +#define FIXLCODES 288 /* number of fixed literal/length codes */ + +/* input and output state */ +struct state { + /* output state */ + unsigned char *out; /* output buffer */ + unsigned long outlen; /* available space at out */ + unsigned long outcnt; /* bytes written to out so far */ + + /* input state */ + const unsigned char *in; /* input buffer */ + unsigned long inlen; /* available input at in */ + unsigned long incnt; /* bytes read so far */ + int bitbuf; /* bit buffer */ + int bitcnt; /* number of bits in bit buffer */ + + /* input limit error return state for bits() and decode() */ + jmp_buf env; +}; + +/* + * Return need bits from the input stream. This always leaves less than + * eight bits in the buffer. bits() works properly for need == 0. + * + * Format notes: + * + * - Bits are stored in bytes from the least significant bit to the most + * significant bit. Therefore bits are dropped from the bottom of the bit + * buffer, using shift right, and new bytes are appended to the top of the + * bit buffer, using shift left. + */ +local int bits(struct state *s, int need) +{ + long val; /* bit accumulator (can use up to 20 bits) */ + + /* load at least need bits into val */ + val = s->bitbuf; + while (s->bitcnt < need) { + if (s->incnt == s->inlen) + longjmp(s->env, 1); /* out of input */ + val |= (long)(s->in[s->incnt++]) << s->bitcnt; /* load eight bits */ + s->bitcnt += 8; + } + + /* drop need bits and update buffer, always zero to seven bits left */ + s->bitbuf = (int)(val >> need); + s->bitcnt -= need; + + /* return need bits, zeroing the bits above that */ + return (int)(val & ((1L << need) - 1)); +} + +/* + * Process a stored block. + * + * Format notes: + * + * - After the two-bit stored block type (00), the stored block length and + * stored bytes are byte-aligned for fast copying. Therefore any leftover + * bits in the byte that has the last bit of the type, as many as seven, are + * discarded. The value of the discarded bits are not defined and should not + * be checked against any expectation. + * + * - The second inverted copy of the stored block length does not have to be + * checked, but it's probably a good idea to do so anyway. + * + * - A stored block can have zero length. This is sometimes used to byte-align + * subsets of the compressed data for random access or partial recovery. + */ +local int stored(struct state *s) +{ + unsigned len; /* length of stored block */ + + /* discard leftover bits from current byte (assumes s->bitcnt < 8) */ + s->bitbuf = 0; + s->bitcnt = 0; + + /* get length and check against its one's complement */ + if (s->incnt + 4 > s->inlen) + return 2; /* not enough input */ + len = s->in[s->incnt++]; + len |= s->in[s->incnt++] << 8; + if (s->in[s->incnt++] != (~len & 0xff) || + s->in[s->incnt++] != ((~len >> 8) & 0xff)) + return -2; /* didn't match complement! */ + + /* copy len bytes from in to out */ + if (s->incnt + len > s->inlen) + return 2; /* not enough input */ + if (s->out != NIL) { + if (s->outcnt + len > s->outlen) + return 1; /* not enough output space */ + while (len--) + s->out[s->outcnt++] = s->in[s->incnt++]; + } + else { /* just scanning */ + s->outcnt += len; + s->incnt += len; + } + + /* done with a valid stored block */ + return 0; +} + +/* + * Huffman code decoding tables. count[1..MAXBITS] is the number of symbols of + * each length, which for a canonical code are stepped through in order. + * symbol[] are the symbol values in canonical order, where the number of + * entries is the sum of the counts in count[]. The decoding process can be + * seen in the function decode() below. + */ +struct huffman { + short *count; /* number of symbols of each length */ + short *symbol; /* canonically ordered symbols */ +}; + +/* + * Decode a code from the stream s using huffman table h. Return the symbol or + * a negative value if there is an error. If all of the lengths are zero, i.e. + * an empty code, or if the code is incomplete and an invalid code is received, + * then -10 is returned after reading MAXBITS bits. + * + * Format notes: + * + * - The codes as stored in the compressed data are bit-reversed relative to + * a simple integer ordering of codes of the same lengths. Hence below the + * bits are pulled from the compressed data one at a time and used to + * build the code value reversed from what is in the stream in order to + * permit simple integer comparisons for decoding. A table-based decoding + * scheme (as used in zlib) does not need to do this reversal. + * + * - The first code for the shortest length is all zeros. Subsequent codes of + * the same length are simply integer increments of the previous code. When + * moving up a length, a zero bit is appended to the code. For a complete + * code, the last code of the longest length will be all ones. + * + * - Incomplete codes are handled by this decoder, since they are permitted + * in the deflate format. See the format notes for fixed() and dynamic(). + */ +#ifdef SLOW +local int decode(struct state *s, const struct huffman *h) +{ + int len; /* current number of bits in code */ + int code; /* len bits being decoded */ + int first; /* first code of length len */ + int count; /* number of codes of length len */ + int index; /* index of first code of length len in symbol table */ + + code = first = index = 0; + for (len = 1; len <= MAXBITS; len++) { + code |= bits(s, 1); /* get next bit */ + count = h->count[len]; + if (code - count < first) /* if length len, return symbol */ + return h->symbol[index + (code - first)]; + index += count; /* else update for next length */ + first += count; + first <<= 1; + code <<= 1; + } + return -10; /* ran out of codes */ +} + +/* + * A faster version of decode() for real applications of this code. It's not + * as readable, but it makes puff() twice as fast. And it only makes the code + * a few percent larger. + */ +#else /* !SLOW */ +local int decode(struct state *s, const struct huffman *h) +{ + int len; /* current number of bits in code */ + int code; /* len bits being decoded */ + int first; /* first code of length len */ + int count; /* number of codes of length len */ + int index; /* index of first code of length len in symbol table */ + int bitbuf; /* bits from stream */ + int left; /* bits left in next or left to process */ + short *next; /* next number of codes */ + + bitbuf = s->bitbuf; + left = s->bitcnt; + code = first = index = 0; + len = 1; + next = h->count + 1; + while (1) { + while (left--) { + code |= bitbuf & 1; + bitbuf >>= 1; + count = *next++; + if (code - count < first) { /* if length len, return symbol */ + s->bitbuf = bitbuf; + s->bitcnt = (s->bitcnt - len) & 7; + return h->symbol[index + (code - first)]; + } + index += count; /* else update for next length */ + first += count; + first <<= 1; + code <<= 1; + len++; + } + left = (MAXBITS+1) - len; + if (left == 0) + break; + if (s->incnt == s->inlen) + longjmp(s->env, 1); /* out of input */ + bitbuf = s->in[s->incnt++]; + if (left > 8) + left = 8; + } + return -10; /* ran out of codes */ +} +#endif /* SLOW */ + +/* + * Given the list of code lengths length[0..n-1] representing a canonical + * Huffman code for n symbols, construct the tables required to decode those + * codes. Those tables are the number of codes of each length, and the symbols + * sorted by length, retaining their original order within each length. The + * return value is zero for a complete code set, negative for an over- + * subscribed code set, and positive for an incomplete code set. The tables + * can be used if the return value is zero or positive, but they cannot be used + * if the return value is negative. If the return value is zero, it is not + * possible for decode() using that table to return an error--any stream of + * enough bits will resolve to a symbol. If the return value is positive, then + * it is possible for decode() using that table to return an error for received + * codes past the end of the incomplete lengths. + * + * Not used by decode(), but used for error checking, h->count[0] is the number + * of the n symbols not in the code. So n - h->count[0] is the number of + * codes. This is useful for checking for incomplete codes that have more than + * one symbol, which is an error in a dynamic block. + * + * Assumption: for all i in 0..n-1, 0 <= length[i] <= MAXBITS + * This is assured by the construction of the length arrays in dynamic() and + * fixed() and is not verified by construct(). + * + * Format notes: + * + * - Permitted and expected examples of incomplete codes are one of the fixed + * codes and any code with a single symbol which in deflate is coded as one + * bit instead of zero bits. See the format notes for fixed() and dynamic(). + * + * - Within a given code length, the symbols are kept in ascending order for + * the code bits definition. + */ +local int construct(struct huffman *h, const short *length, int n) +{ + int symbol; /* current symbol when stepping through length[] */ + int len; /* current length when stepping through h->count[] */ + int left; /* number of possible codes left of current length */ + short offs[MAXBITS+1]; /* offsets in symbol table for each length */ + + /* count number of codes of each length */ + for (len = 0; len <= MAXBITS; len++) + h->count[len] = 0; + for (symbol = 0; symbol < n; symbol++) + (h->count[length[symbol]])++; /* assumes lengths are within bounds */ + if (h->count[0] == n) /* no codes! */ + return 0; /* complete, but decode() will fail */ + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; /* one possible code of zero length */ + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; /* one more bit, double codes left */ + left -= h->count[len]; /* deduct count from possible codes */ + if (left < 0) + return left; /* over-subscribed--return negative */ + } /* left > 0 means incomplete */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + h->count[len]; + + /* + * put symbols in table sorted by length, by symbol order within each + * length + */ + for (symbol = 0; symbol < n; symbol++) + if (length[symbol] != 0) + h->symbol[offs[length[symbol]]++] = symbol; + + /* return zero for complete set, positive for incomplete set */ + return left; +} + +/* + * Decode literal/length and distance codes until an end-of-block code. + * + * Format notes: + * + * - Compressed data that is after the block type if fixed or after the code + * description if dynamic is a combination of literals and length/distance + * pairs terminated by and end-of-block code. Literals are simply Huffman + * coded bytes. A length/distance pair is a coded length followed by a + * coded distance to represent a string that occurs earlier in the + * uncompressed data that occurs again at the current location. + * + * - Literals, lengths, and the end-of-block code are combined into a single + * code of up to 286 symbols. They are 256 literals (0..255), 29 length + * symbols (257..285), and the end-of-block symbol (256). + * + * - There are 256 possible lengths (3..258), and so 29 symbols are not enough + * to represent all of those. Lengths 3..10 and 258 are in fact represented + * by just a length symbol. Lengths 11..257 are represented as a symbol and + * some number of extra bits that are added as an integer to the base length + * of the length symbol. The number of extra bits is determined by the base + * length symbol. These are in the static arrays below, lens[] for the base + * lengths and lext[] for the corresponding number of extra bits. + * + * - The reason that 258 gets its own symbol is that the longest length is used + * often in highly redundant files. Note that 258 can also be coded as the + * base value 227 plus the maximum extra value of 31. While a good deflate + * should never do this, it is not an error, and should be decoded properly. + * + * - If a length is decoded, including its extra bits if any, then it is + * followed a distance code. There are up to 30 distance symbols. Again + * there are many more possible distances (1..32768), so extra bits are added + * to a base value represented by the symbol. The distances 1..4 get their + * own symbol, but the rest require extra bits. The base distances and + * corresponding number of extra bits are below in the static arrays dist[] + * and dext[]. + * + * - Literal bytes are simply written to the output. A length/distance pair is + * an instruction to copy previously uncompressed bytes to the output. The + * copy is from distance bytes back in the output stream, copying for length + * bytes. + * + * - Distances pointing before the beginning of the output data are not + * permitted. + * + * - Overlapped copies, where the length is greater than the distance, are + * allowed and common. For example, a distance of one and a length of 258 + * simply copies the last byte 258 times. A distance of four and a length of + * twelve copies the last four bytes three times. A simple forward copy + * ignoring whether the length is greater than the distance or not implements + * this correctly. You should not use memcpy() since its behavior is not + * defined for overlapped arrays. You should not use memmove() or bcopy() + * since though their behavior -is- defined for overlapping arrays, it is + * defined to do the wrong thing in this case. + */ +local int codes(struct state *s, + const struct huffman *lencode, + const struct huffman *distcode) +{ + int symbol; /* decoded symbol */ + int len; /* length for copy */ + unsigned dist; /* distance for copy */ + static const short lens[29] = { /* Size base for length codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258}; + static const short lext[29] = { /* Extra bits for length codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0}; + static const short dists[30] = { /* Offset base for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; + static const short dext[30] = { /* Extra bits for distance codes 0..29 */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + + /* decode literals and length/distance pairs */ + do { + symbol = decode(s, lencode); + if (symbol < 0) + return symbol; /* invalid symbol */ + if (symbol < 256) { /* literal: symbol is the byte */ + /* write out the literal */ + if (s->out != NIL) { + if (s->outcnt == s->outlen) + return 1; + s->out[s->outcnt] = symbol; + } + s->outcnt++; + } + else if (symbol > 256) { /* length */ + /* get and compute length */ + symbol -= 257; + if (symbol >= 29) + return -10; /* invalid fixed code */ + len = lens[symbol] + bits(s, lext[symbol]); + + /* get and check distance */ + symbol = decode(s, distcode); + if (symbol < 0) + return symbol; /* invalid symbol */ + dist = dists[symbol] + bits(s, dext[symbol]); +#ifndef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + if (dist > s->outcnt) + return -11; /* distance too far back */ +#endif + + /* copy length bytes from distance bytes back */ + if (s->out != NIL) { + if (s->outcnt + len > s->outlen) + return 1; + while (len--) { + s->out[s->outcnt] = +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + dist > s->outcnt ? + 0 : +#endif + s->out[s->outcnt - dist]; + s->outcnt++; + } + } + else + s->outcnt += len; + } + } while (symbol != 256); /* end of block symbol */ + + /* done with a valid fixed or dynamic block */ + return 0; +} + +/* + * Process a fixed codes block. + * + * Format notes: + * + * - This block type can be useful for compressing small amounts of data for + * which the size of the code descriptions in a dynamic block exceeds the + * benefit of custom codes for that block. For fixed codes, no bits are + * spent on code descriptions. Instead the code lengths for literal/length + * codes and distance codes are fixed. The specific lengths for each symbol + * can be seen in the "for" loops below. + * + * - The literal/length code is complete, but has two symbols that are invalid + * and should result in an error if received. This cannot be implemented + * simply as an incomplete code since those two symbols are in the "middle" + * of the code. They are eight bits long and the longest literal/length\ + * code is nine bits. Therefore the code must be constructed with those + * symbols, and the invalid symbols must be detected after decoding. + * + * - The fixed distance codes also have two invalid symbols that should result + * in an error if received. Since all of the distance codes are the same + * length, this can be implemented as an incomplete code. Then the invalid + * codes are detected while decoding. + */ +local int fixed(struct state *s) +{ + static int virgin = 1; + static short lencnt[MAXBITS+1], lensym[FIXLCODES]; + static short distcnt[MAXBITS+1], distsym[MAXDCODES]; + static struct huffman lencode, distcode; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + int symbol; + short lengths[FIXLCODES]; + + /* construct lencode and distcode */ + lencode.count = lencnt; + lencode.symbol = lensym; + distcode.count = distcnt; + distcode.symbol = distsym; + + /* literal/length table */ + for (symbol = 0; symbol < 144; symbol++) + lengths[symbol] = 8; + for (; symbol < 256; symbol++) + lengths[symbol] = 9; + for (; symbol < 280; symbol++) + lengths[symbol] = 7; + for (; symbol < FIXLCODES; symbol++) + lengths[symbol] = 8; + construct(&lencode, lengths, FIXLCODES); + + /* distance table */ + for (symbol = 0; symbol < MAXDCODES; symbol++) + lengths[symbol] = 5; + construct(&distcode, lengths, MAXDCODES); + + /* do this just once */ + virgin = 0; + } + + /* decode data until end-of-block code */ + return codes(s, &lencode, &distcode); +} + +/* + * Process a dynamic codes block. + * + * Format notes: + * + * - A dynamic block starts with a description of the literal/length and + * distance codes for that block. New dynamic blocks allow the compressor to + * rapidly adapt to changing data with new codes optimized for that data. + * + * - The codes used by the deflate format are "canonical", which means that + * the actual bits of the codes are generated in an unambiguous way simply + * from the number of bits in each code. Therefore the code descriptions + * are simply a list of code lengths for each symbol. + * + * - The code lengths are stored in order for the symbols, so lengths are + * provided for each of the literal/length symbols, and for each of the + * distance symbols. + * + * - If a symbol is not used in the block, this is represented by a zero as + * as the code length. This does not mean a zero-length code, but rather + * that no code should be created for this symbol. There is no way in the + * deflate format to represent a zero-length code. + * + * - The maximum number of bits in a code is 15, so the possible lengths for + * any code are 1..15. + * + * - The fact that a length of zero is not permitted for a code has an + * interesting consequence. Normally if only one symbol is used for a given + * code, then in fact that code could be represented with zero bits. However + * in deflate, that code has to be at least one bit. So for example, if + * only a single distance base symbol appears in a block, then it will be + * represented by a single code of length one, in particular one 0 bit. This + * is an incomplete code, since if a 1 bit is received, it has no meaning, + * and should result in an error. So incomplete distance codes of one symbol + * should be permitted, and the receipt of invalid codes should be handled. + * + * - It is also possible to have a single literal/length code, but that code + * must be the end-of-block code, since every dynamic block has one. This + * is not the most efficient way to create an empty block (an empty fixed + * block is fewer bits), but it is allowed by the format. So incomplete + * literal/length codes of one symbol should also be permitted. + * + * - If there are only literal codes and no lengths, then there are no distance + * codes. This is represented by one distance code with zero bits. + * + * - The list of up to 286 length/literal lengths and up to 30 distance lengths + * are themselves compressed using Huffman codes and run-length encoding. In + * the list of code lengths, a 0 symbol means no code, a 1..15 symbol means + * that length, and the symbols 16, 17, and 18 are run-length instructions. + * Each of 16, 17, and 18 are follwed by extra bits to define the length of + * the run. 16 copies the last length 3 to 6 times. 17 represents 3 to 10 + * zero lengths, and 18 represents 11 to 138 zero lengths. Unused symbols + * are common, hence the special coding for zero lengths. + * + * - The symbols for 0..18 are Huffman coded, and so that code must be + * described first. This is simply a sequence of up to 19 three-bit values + * representing no code (0) or the code length for that symbol (1..7). + * + * - A dynamic block starts with three fixed-size counts from which is computed + * the number of literal/length code lengths, the number of distance code + * lengths, and the number of code length code lengths (ok, you come up with + * a better name!) in the code descriptions. For the literal/length and + * distance codes, lengths after those provided are considered zero, i.e. no + * code. The code length code lengths are received in a permuted order (see + * the order[] array below) to make a short code length code length list more + * likely. As it turns out, very short and very long codes are less likely + * to be seen in a dynamic code description, hence what may appear initially + * to be a peculiar ordering. + * + * - Given the number of literal/length code lengths (nlen) and distance code + * lengths (ndist), then they are treated as one long list of nlen + ndist + * code lengths. Therefore run-length coding can and often does cross the + * boundary between the two sets of lengths. + * + * - So to summarize, the code description at the start of a dynamic block is + * three counts for the number of code lengths for the literal/length codes, + * the distance codes, and the code length codes. This is followed by the + * code length code lengths, three bits each. This is used to construct the + * code length code which is used to read the remainder of the lengths. Then + * the literal/length code lengths and distance lengths are read as a single + * set of lengths using the code length codes. Codes are constructed from + * the resulting two sets of lengths, and then finally you can start + * decoding actual compressed data in the block. + * + * - For reference, a "typical" size for the code description in a dynamic + * block is around 80 bytes. + */ +local int dynamic(struct state *s) +{ + int nlen, ndist, ncode; /* number of lengths in descriptor */ + int index; /* index of lengths[] */ + int err; /* construct() return value */ + short lengths[MAXCODES]; /* descriptor code lengths */ + short lencnt[MAXBITS+1], lensym[MAXLCODES]; /* lencode memory */ + short distcnt[MAXBITS+1], distsym[MAXDCODES]; /* distcode memory */ + struct huffman lencode, distcode; /* length and distance codes */ + static const short order[19] = /* permutation of code length codes */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* construct lencode and distcode */ + lencode.count = lencnt; + lencode.symbol = lensym; + distcode.count = distcnt; + distcode.symbol = distsym; + + /* get number of lengths in each table, check lengths */ + nlen = bits(s, 5) + 257; + ndist = bits(s, 5) + 1; + ncode = bits(s, 4) + 4; + if (nlen > MAXLCODES || ndist > MAXDCODES) + return -3; /* bad counts */ + + /* read code length code lengths (really), missing lengths are zero */ + for (index = 0; index < ncode; index++) + lengths[order[index]] = bits(s, 3); + for (; index < 19; index++) + lengths[order[index]] = 0; + + /* build huffman table for code lengths codes (use lencode temporarily) */ + err = construct(&lencode, lengths, 19); + if (err != 0) /* require complete code set here */ + return -4; + + /* read length/literal and distance code length tables */ + index = 0; + while (index < nlen + ndist) { + int symbol; /* decoded value */ + int len; /* last length to repeat */ + + symbol = decode(s, &lencode); + if (symbol < 0) + return symbol; /* invalid symbol */ + if (symbol < 16) /* length in 0..15 */ + lengths[index++] = symbol; + else { /* repeat instruction */ + len = 0; /* assume repeating zeros */ + if (symbol == 16) { /* repeat last length 3..6 times */ + if (index == 0) + return -5; /* no last length! */ + len = lengths[index - 1]; /* last length */ + symbol = 3 + bits(s, 2); + } + else if (symbol == 17) /* repeat zero 3..10 times */ + symbol = 3 + bits(s, 3); + else /* == 18, repeat zero 11..138 times */ + symbol = 11 + bits(s, 7); + if (index + symbol > nlen + ndist) + return -6; /* too many lengths! */ + while (symbol--) /* repeat last or zero symbol times */ + lengths[index++] = len; + } + } + + /* check for end-of-block code -- there better be one! */ + if (lengths[256] == 0) + return -9; + + /* build huffman table for literal/length codes */ + err = construct(&lencode, lengths, nlen); + if (err && (err < 0 || nlen != lencode.count[0] + lencode.count[1])) + return -7; /* incomplete code ok only for single length 1 code */ + + /* build huffman table for distance codes */ + err = construct(&distcode, lengths + nlen, ndist); + if (err && (err < 0 || ndist != distcode.count[0] + distcode.count[1])) + return -8; /* incomplete code ok only for single length 1 code */ + + /* decode data until end-of-block code */ + return codes(s, &lencode, &distcode); +} + +/* + * Inflate source to dest. On return, destlen and sourcelen are updated to the + * size of the uncompressed data and the size of the deflate data respectively. + * On success, the return value of puff() is zero. If there is an error in the + * source data, i.e. it is not in the deflate format, then a negative value is + * returned. If there is not enough input available or there is not enough + * output space, then a positive error is returned. In that case, destlen and + * sourcelen are not updated to facilitate retrying from the beginning with the + * provision of more input data or more output space. In the case of invalid + * inflate data (a negative error), the dest and source pointers are updated to + * facilitate the debugging of deflators. + * + * puff() also has a mode to determine the size of the uncompressed output with + * no output written. For this dest must be (unsigned char *)0. In this case, + * the input value of *destlen is ignored, and on return *destlen is set to the + * size of the uncompressed output. + * + * The return codes are: + * + * 2: available inflate data did not terminate + * 1: output space exhausted before completing inflate + * 0: successful inflate + * -1: invalid block type (type == 3) + * -2: stored block length did not match one's complement + * -3: dynamic block code description: too many length or distance codes + * -4: dynamic block code description: code lengths codes incomplete + * -5: dynamic block code description: repeat lengths with no first length + * -6: dynamic block code description: repeat more than specified lengths + * -7: dynamic block code description: invalid literal/length code lengths + * -8: dynamic block code description: invalid distance code lengths + * -9: dynamic block code description: missing end-of-block code + * -10: invalid literal/length or distance code in fixed or dynamic block + * -11: distance is too far back in fixed or dynamic block + * + * Format notes: + * + * - Three bits are read for each block to determine the kind of block and + * whether or not it is the last block. Then the block is decoded and the + * process repeated if it was not the last block. + * + * - The leftover bits in the last byte of the deflate data after the last + * block (if it was a fixed or dynamic block) are undefined and have no + * expected values to check. + */ +int puff(unsigned char *dest, /* pointer to destination pointer */ + unsigned long *destlen, /* amount of output space */ + const unsigned char *source, /* pointer to source data pointer */ + unsigned long *sourcelen) /* amount of input available */ +{ + struct state s; /* input/output state */ + int last, type; /* block information */ + int err; /* return value */ + + /* initialize output state */ + s.out = dest; + s.outlen = *destlen; /* ignored if dest is NIL */ + s.outcnt = 0; + + /* initialize input state */ + s.in = source; + s.inlen = *sourcelen; + s.incnt = 0; + s.bitbuf = 0; + s.bitcnt = 0; + + /* return if bits() or decode() tries to read past available input */ + if (setjmp(s.env) != 0) /* if came back here via longjmp() */ + err = 2; /* then skip do-loop, return error */ + else { + /* process blocks until last block or error */ + do { + last = bits(&s, 1); /* one if last block */ + type = bits(&s, 2); /* block type 0..3 */ + err = type == 0 ? + stored(&s) : + (type == 1 ? + fixed(&s) : + (type == 2 ? + dynamic(&s) : + -1)); /* type == 3, invalid */ + if (err != 0) + break; /* return with error */ + } while (!last); + } + + /* update the lengths and return */ + if (err <= 0) { + *destlen = s.outcnt; + *sourcelen = s.incnt; + } + return err; +} diff --git a/contrib/zlib/contrib/puff/puff.h b/contrib/zlib/contrib/puff/puff.h new file mode 100644 index 00000000..e23a2454 --- /dev/null +++ b/contrib/zlib/contrib/puff/puff.h @@ -0,0 +1,35 @@ +/* puff.h + Copyright (C) 2002-2013 Mark Adler, all rights reserved + version 2.3, 21 Jan 2013 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler madler@alumni.caltech.edu + */ + + +/* + * See puff.c for purpose and usage. + */ +#ifndef NIL +# define NIL ((unsigned char *)0) /* for no output option */ +#endif + +int puff(unsigned char *dest, /* pointer to destination pointer */ + unsigned long *destlen, /* amount of output space */ + const unsigned char *source, /* pointer to source data pointer */ + unsigned long *sourcelen); /* amount of input available */ diff --git a/contrib/zlib/contrib/puff/pufftest.c b/contrib/zlib/contrib/puff/pufftest.c new file mode 100644 index 00000000..77648148 --- /dev/null +++ b/contrib/zlib/contrib/puff/pufftest.c @@ -0,0 +1,165 @@ +/* + * pufftest.c + * Copyright (C) 2002-2013 Mark Adler + * For conditions of distribution and use, see copyright notice in puff.h + * version 2.3, 21 Jan 2013 + */ + +/* Example of how to use puff(). + + Usage: puff [-w] [-f] [-nnn] file + ... | puff [-w] [-f] [-nnn] + + where file is the input file with deflate data, nnn is the number of bytes + of input to skip before inflating (e.g. to skip a zlib or gzip header), and + -w is used to write the decompressed data to stdout. -f is for coverage + testing, and causes pufftest to fail with not enough output space (-f does + a write like -w, so -w is not required). */ + +#include +#include +#include "puff.h" + +#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +#define local static + +/* Return size times approximately the cube root of 2, keeping the result as 1, + 3, or 5 times a power of 2 -- the result is always > size, until the result + is the maximum value of an unsigned long, where it remains. This is useful + to keep reallocations less than ~33% over the actual data. */ +local size_t bythirds(size_t size) +{ + int n; + size_t m; + + m = size; + for (n = 0; m; n++) + m >>= 1; + if (n < 3) + return size + 1; + n -= 3; + m = size >> n; + m += m == 6 ? 2 : 1; + m <<= n; + return m > size ? m : (size_t)(-1); +} + +/* Read the input file *name, or stdin if name is NULL, into allocated memory. + Reallocate to larger buffers until the entire file is read in. Return a + pointer to the allocated data, or NULL if there was a memory allocation + failure. *len is the number of bytes of data read from the input file (even + if load() returns NULL). If the input file was empty or could not be opened + or read, *len is zero. */ +local void *load(const char *name, size_t *len) +{ + size_t size; + void *buf, *swap; + FILE *in; + + *len = 0; + buf = malloc(size = 4096); + if (buf == NULL) + return NULL; + in = name == NULL ? stdin : fopen(name, "rb"); + if (in != NULL) { + for (;;) { + *len += fread((char *)buf + *len, 1, size - *len, in); + if (*len < size) break; + size = bythirds(size); + if (size == *len || (swap = realloc(buf, size)) == NULL) { + free(buf); + buf = NULL; + break; + } + buf = swap; + } + fclose(in); + } + return buf; +} + +int main(int argc, char **argv) +{ + int ret, put = 0, fail = 0; + unsigned skip = 0; + char *arg, *name = NULL; + unsigned char *source = NULL, *dest; + size_t len = 0; + unsigned long sourcelen, destlen; + + /* process arguments */ + while (arg = *++argv, --argc) + if (arg[0] == '-') { + if (arg[1] == 'w' && arg[2] == 0) + put = 1; + else if (arg[1] == 'f' && arg[2] == 0) + fail = 1, put = 1; + else if (arg[1] >= '0' && arg[1] <= '9') + skip = (unsigned)atoi(arg + 1); + else { + fprintf(stderr, "invalid option %s\n", arg); + return 3; + } + } + else if (name != NULL) { + fprintf(stderr, "only one file name allowed\n"); + return 3; + } + else + name = arg; + source = load(name, &len); + if (source == NULL) { + fprintf(stderr, "memory allocation failure\n"); + return 4; + } + if (len == 0) { + fprintf(stderr, "could not read %s, or it was empty\n", + name == NULL ? "" : name); + free(source); + return 3; + } + if (skip >= len) { + fprintf(stderr, "skip request of %d leaves no input\n", skip); + free(source); + return 3; + } + + /* test inflate data with offset skip */ + len -= skip; + sourcelen = (unsigned long)len; + ret = puff(NIL, &destlen, source + skip, &sourcelen); + if (ret) + fprintf(stderr, "puff() failed with return code %d\n", ret); + else { + fprintf(stderr, "puff() succeeded uncompressing %lu bytes\n", destlen); + if (sourcelen < len) fprintf(stderr, "%lu compressed bytes unused\n", + len - sourcelen); + } + + /* if requested, inflate again and write decompressd data to stdout */ + if (put && ret == 0) { + if (fail) + destlen >>= 1; + dest = malloc(destlen); + if (dest == NULL) { + fprintf(stderr, "memory allocation failure\n"); + free(source); + return 4; + } + puff(dest, &destlen, source + skip, &sourcelen); + SET_BINARY_MODE(stdout); + fwrite(dest, 1, destlen, stdout); + free(dest); + } + + /* clean up */ + free(source); + return ret; +} diff --git a/contrib/zlib/contrib/puff/zeros.raw b/contrib/zlib/contrib/puff/zeros.raw new file mode 100644 index 00000000..0a90e76b Binary files /dev/null and b/contrib/zlib/contrib/puff/zeros.raw differ diff --git a/contrib/zlib/contrib/testzlib/testzlib.c b/contrib/zlib/contrib/testzlib/testzlib.c new file mode 100644 index 00000000..8626c92a --- /dev/null +++ b/contrib/zlib/contrib/testzlib/testzlib.c @@ -0,0 +1,275 @@ +#include +#include +#include + +#include "zlib.h" + + +void MyDoMinus64(LARGE_INTEGER *R,LARGE_INTEGER A,LARGE_INTEGER B) +{ + R->HighPart = A.HighPart - B.HighPart; + if (A.LowPart >= B.LowPart) + R->LowPart = A.LowPart - B.LowPart; + else + { + R->LowPart = A.LowPart - B.LowPart; + R->HighPart --; + } +} + +#ifdef _M_X64 +// see http://msdn2.microsoft.com/library/twchhe95(en-us,vs.80).aspx for __rdtsc +unsigned __int64 __rdtsc(void); +void BeginCountRdtsc(LARGE_INTEGER * pbeginTime64) +{ + // printf("rdtsc = %I64x\n",__rdtsc()); + pbeginTime64->QuadPart=__rdtsc(); +} + +LARGE_INTEGER GetResRdtsc(LARGE_INTEGER beginTime64,BOOL fComputeTimeQueryPerf) +{ + LARGE_INTEGER LIres; + unsigned _int64 res=__rdtsc()-((unsigned _int64)(beginTime64.QuadPart)); + LIres.QuadPart=res; + // printf("rdtsc = %I64x\n",__rdtsc()); + return LIres; +} +#else +#ifdef _M_IX86 +void myGetRDTSC32(LARGE_INTEGER * pbeginTime64) +{ + DWORD dwEdx,dwEax; + _asm + { + rdtsc + mov dwEax,eax + mov dwEdx,edx + } + pbeginTime64->LowPart=dwEax; + pbeginTime64->HighPart=dwEdx; +} + +void BeginCountRdtsc(LARGE_INTEGER * pbeginTime64) +{ + myGetRDTSC32(pbeginTime64); +} + +LARGE_INTEGER GetResRdtsc(LARGE_INTEGER beginTime64,BOOL fComputeTimeQueryPerf) +{ + LARGE_INTEGER LIres,endTime64; + myGetRDTSC32(&endTime64); + + LIres.LowPart=LIres.HighPart=0; + MyDoMinus64(&LIres,endTime64,beginTime64); + return LIres; +} +#else +void myGetRDTSC32(LARGE_INTEGER * pbeginTime64) +{ +} + +void BeginCountRdtsc(LARGE_INTEGER * pbeginTime64) +{ +} + +LARGE_INTEGER GetResRdtsc(LARGE_INTEGER beginTime64,BOOL fComputeTimeQueryPerf) +{ + LARGE_INTEGER lr; + lr.QuadPart=0; + return lr; +} +#endif +#endif + +void BeginCountPerfCounter(LARGE_INTEGER * pbeginTime64,BOOL fComputeTimeQueryPerf) +{ + if ((!fComputeTimeQueryPerf) || (!QueryPerformanceCounter(pbeginTime64))) + { + pbeginTime64->LowPart = GetTickCount(); + pbeginTime64->HighPart = 0; + } +} + +DWORD GetMsecSincePerfCounter(LARGE_INTEGER beginTime64,BOOL fComputeTimeQueryPerf) +{ + LARGE_INTEGER endTime64,ticksPerSecond,ticks; + DWORDLONG ticksShifted,tickSecShifted; + DWORD dwLog=16+0; + DWORD dwRet; + if ((!fComputeTimeQueryPerf) || (!QueryPerformanceCounter(&endTime64))) + dwRet = (GetTickCount() - beginTime64.LowPart)*1; + else + { + MyDoMinus64(&ticks,endTime64,beginTime64); + QueryPerformanceFrequency(&ticksPerSecond); + + + { + ticksShifted = Int64ShrlMod32(*(DWORDLONG*)&ticks,dwLog); + tickSecShifted = Int64ShrlMod32(*(DWORDLONG*)&ticksPerSecond,dwLog); + + } + + dwRet = (DWORD)((((DWORD)ticksShifted)*1000)/(DWORD)(tickSecShifted)); + dwRet *=1; + } + return dwRet; +} + +int ReadFileMemory(const char* filename,long* plFileSize,unsigned char** pFilePtr) +{ + FILE* stream; + unsigned char* ptr; + int retVal=1; + stream=fopen(filename, "rb"); + if (stream==NULL) + return 0; + + fseek(stream,0,SEEK_END); + + *plFileSize=ftell(stream); + fseek(stream,0,SEEK_SET); + ptr=malloc((*plFileSize)+1); + if (ptr==NULL) + retVal=0; + else + { + if (fread(ptr, 1, *plFileSize,stream) != (*plFileSize)) + retVal=0; + } + fclose(stream); + *pFilePtr=ptr; + return retVal; +} + +int main(int argc, char *argv[]) +{ + int BlockSizeCompress=0x8000; + int BlockSizeUncompress=0x8000; + int cprLevel=Z_DEFAULT_COMPRESSION ; + long lFileSize; + unsigned char* FilePtr; + long lBufferSizeCpr; + long lBufferSizeUncpr; + long lCompressedSize=0; + unsigned char* CprPtr; + unsigned char* UncprPtr; + long lSizeCpr,lSizeUncpr; + DWORD dwGetTick,dwMsecQP; + LARGE_INTEGER li_qp,li_rdtsc,dwResRdtsc; + + if (argc<=1) + { + printf("run TestZlib [BlockSizeCompress] [BlockSizeUncompress] [compres. level]\n"); + return 0; + } + + if (ReadFileMemory(argv[1],&lFileSize,&FilePtr)==0) + { + printf("error reading %s\n",argv[1]); + return 1; + } + else printf("file %s read, %u bytes\n",argv[1],lFileSize); + + if (argc>=3) + BlockSizeCompress=atol(argv[2]); + + if (argc>=4) + BlockSizeUncompress=atol(argv[3]); + + if (argc>=5) + cprLevel=(int)atol(argv[4]); + + lBufferSizeCpr = lFileSize + (lFileSize/0x10) + 0x200; + lBufferSizeUncpr = lBufferSizeCpr; + + CprPtr=(unsigned char*)malloc(lBufferSizeCpr + BlockSizeCompress); + + BeginCountPerfCounter(&li_qp,TRUE); + dwGetTick=GetTickCount(); + BeginCountRdtsc(&li_rdtsc); + { + z_stream zcpr; + int ret=Z_OK; + long lOrigToDo = lFileSize; + long lOrigDone = 0; + int step=0; + memset(&zcpr,0,sizeof(z_stream)); + deflateInit(&zcpr,cprLevel); + + zcpr.next_in = FilePtr; + zcpr.next_out = CprPtr; + + + do + { + long all_read_before = zcpr.total_in; + zcpr.avail_in = min(lOrigToDo,BlockSizeCompress); + zcpr.avail_out = BlockSizeCompress; + ret=deflate(&zcpr,(zcpr.avail_in==lOrigToDo) ? Z_FINISH : Z_SYNC_FLUSH); + lOrigDone += (zcpr.total_in-all_read_before); + lOrigToDo -= (zcpr.total_in-all_read_before); + step++; + } while (ret==Z_OK); + + lSizeCpr=zcpr.total_out; + deflateEnd(&zcpr); + dwGetTick=GetTickCount()-dwGetTick; + dwMsecQP=GetMsecSincePerfCounter(li_qp,TRUE); + dwResRdtsc=GetResRdtsc(li_rdtsc,TRUE); + printf("total compress size = %u, in %u step\n",lSizeCpr,step); + printf("time = %u msec = %f sec\n",dwGetTick,dwGetTick/(double)1000.); + printf("defcpr time QP = %u msec = %f sec\n",dwMsecQP,dwMsecQP/(double)1000.); + printf("defcpr result rdtsc = %I64x\n\n",dwResRdtsc.QuadPart); + } + + CprPtr=(unsigned char*)realloc(CprPtr,lSizeCpr); + UncprPtr=(unsigned char*)malloc(lBufferSizeUncpr + BlockSizeUncompress); + + BeginCountPerfCounter(&li_qp,TRUE); + dwGetTick=GetTickCount(); + BeginCountRdtsc(&li_rdtsc); + { + z_stream zcpr; + int ret=Z_OK; + long lOrigToDo = lSizeCpr; + long lOrigDone = 0; + int step=0; + memset(&zcpr,0,sizeof(z_stream)); + inflateInit(&zcpr); + + zcpr.next_in = CprPtr; + zcpr.next_out = UncprPtr; + + + do + { + long all_read_before = zcpr.total_in; + zcpr.avail_in = min(lOrigToDo,BlockSizeUncompress); + zcpr.avail_out = BlockSizeUncompress; + ret=inflate(&zcpr,Z_SYNC_FLUSH); + lOrigDone += (zcpr.total_in-all_read_before); + lOrigToDo -= (zcpr.total_in-all_read_before); + step++; + } while (ret==Z_OK); + + lSizeUncpr=zcpr.total_out; + inflateEnd(&zcpr); + dwGetTick=GetTickCount()-dwGetTick; + dwMsecQP=GetMsecSincePerfCounter(li_qp,TRUE); + dwResRdtsc=GetResRdtsc(li_rdtsc,TRUE); + printf("total uncompress size = %u, in %u step\n",lSizeUncpr,step); + printf("time = %u msec = %f sec\n",dwGetTick,dwGetTick/(double)1000.); + printf("uncpr time QP = %u msec = %f sec\n",dwMsecQP,dwMsecQP/(double)1000.); + printf("uncpr result rdtsc = %I64x\n\n",dwResRdtsc.QuadPart); + } + + if (lSizeUncpr==lFileSize) + { + if (memcmp(FilePtr,UncprPtr,lFileSize)==0) + printf("compare ok\n"); + + } + + return 0; +} diff --git a/contrib/zlib/contrib/testzlib/testzlib.txt b/contrib/zlib/contrib/testzlib/testzlib.txt new file mode 100644 index 00000000..e508bb22 --- /dev/null +++ b/contrib/zlib/contrib/testzlib/testzlib.txt @@ -0,0 +1,10 @@ +To build testzLib with Visual Studio 2005: + +copy to a directory file from : +- root of zLib tree +- contrib/testzlib +- contrib/masmx86 +- contrib/masmx64 +- contrib/vstudio/vc7 + +and open testzlib8.sln \ No newline at end of file diff --git a/contrib/zlib/contrib/untgz/Makefile b/contrib/zlib/contrib/untgz/Makefile new file mode 100644 index 00000000..b54266fb --- /dev/null +++ b/contrib/zlib/contrib/untgz/Makefile @@ -0,0 +1,14 @@ +CC=cc +CFLAGS=-g + +untgz: untgz.o ../../libz.a + $(CC) $(CFLAGS) -o untgz untgz.o -L../.. -lz + +untgz.o: untgz.c ../../zlib.h + $(CC) $(CFLAGS) -c -I../.. untgz.c + +../../libz.a: + cd ../..; ./configure; make + +clean: + rm -f untgz untgz.o *~ diff --git a/contrib/zlib/contrib/untgz/Makefile.msc b/contrib/zlib/contrib/untgz/Makefile.msc new file mode 100644 index 00000000..77b86022 --- /dev/null +++ b/contrib/zlib/contrib/untgz/Makefile.msc @@ -0,0 +1,17 @@ +CC=cl +CFLAGS=-MD + +untgz.exe: untgz.obj ..\..\zlib.lib + $(CC) $(CFLAGS) untgz.obj ..\..\zlib.lib + +untgz.obj: untgz.c ..\..\zlib.h + $(CC) $(CFLAGS) -c -I..\.. untgz.c + +..\..\zlib.lib: + cd ..\.. + $(MAKE) -f win32\makefile.msc + cd contrib\untgz + +clean: + -del untgz.obj + -del untgz.exe diff --git a/contrib/zlib/contrib/untgz/untgz.c b/contrib/zlib/contrib/untgz/untgz.c new file mode 100644 index 00000000..2c391e59 --- /dev/null +++ b/contrib/zlib/contrib/untgz/untgz.c @@ -0,0 +1,674 @@ +/* + * untgz.c -- Display contents and extract files from a gzip'd TAR file + * + * written by Pedro A. Aranda Gutierrez + * adaptation to Unix by Jean-loup Gailly + * various fixes by Cosmin Truta + */ + +#include +#include +#include +#include +#include + +#include "zlib.h" + +#ifdef unix +# include +#else +# include +# include +#endif + +#ifdef WIN32 +#include +# ifndef F_OK +# define F_OK 0 +# endif +# define mkdir(dirname,mode) _mkdir(dirname) +# ifdef _MSC_VER +# define access(path,mode) _access(path,mode) +# define chmod(path,mode) _chmod(path,mode) +# define strdup(str) _strdup(str) +# endif +#else +# include +#endif + + +/* values used in typeflag field */ + +#define REGTYPE '0' /* regular file */ +#define AREGTYPE '\0' /* regular file */ +#define LNKTYPE '1' /* link */ +#define SYMTYPE '2' /* reserved */ +#define CHRTYPE '3' /* character special */ +#define BLKTYPE '4' /* block special */ +#define DIRTYPE '5' /* directory */ +#define FIFOTYPE '6' /* FIFO special */ +#define CONTTYPE '7' /* reserved */ + +/* GNU tar extensions */ + +#define GNUTYPE_DUMPDIR 'D' /* file names from dumped directory */ +#define GNUTYPE_LONGLINK 'K' /* long link name */ +#define GNUTYPE_LONGNAME 'L' /* long file name */ +#define GNUTYPE_MULTIVOL 'M' /* continuation of file from another volume */ +#define GNUTYPE_NAMES 'N' /* file name that does not fit into main hdr */ +#define GNUTYPE_SPARSE 'S' /* sparse file */ +#define GNUTYPE_VOLHDR 'V' /* tape/volume header */ + + +/* tar header */ + +#define BLOCKSIZE 512 +#define SHORTNAMESIZE 100 + +struct tar_header +{ /* byte offset */ + char name[100]; /* 0 */ + char mode[8]; /* 100 */ + char uid[8]; /* 108 */ + char gid[8]; /* 116 */ + char size[12]; /* 124 */ + char mtime[12]; /* 136 */ + char chksum[8]; /* 148 */ + char typeflag; /* 156 */ + char linkname[100]; /* 157 */ + char magic[6]; /* 257 */ + char version[2]; /* 263 */ + char uname[32]; /* 265 */ + char gname[32]; /* 297 */ + char devmajor[8]; /* 329 */ + char devminor[8]; /* 337 */ + char prefix[155]; /* 345 */ + /* 500 */ +}; + +union tar_buffer +{ + char buffer[BLOCKSIZE]; + struct tar_header header; +}; + +struct attr_item +{ + struct attr_item *next; + char *fname; + int mode; + time_t time; +}; + +enum { TGZ_EXTRACT, TGZ_LIST, TGZ_INVALID }; + +char *TGZfname OF((const char *)); +void TGZnotfound OF((const char *)); + +int getoct OF((char *, int)); +char *strtime OF((time_t *)); +int setfiletime OF((char *, time_t)); +void push_attr OF((struct attr_item **, char *, int, time_t)); +void restore_attr OF((struct attr_item **)); + +int ExprMatch OF((char *, char *)); + +int makedir OF((char *)); +int matchname OF((int, int, char **, char *)); + +void error OF((const char *)); +int tar OF((gzFile, int, int, int, char **)); + +void help OF((int)); +int main OF((int, char **)); + +char *prog; + +const char *TGZsuffix[] = { "\0", ".tar", ".tar.gz", ".taz", ".tgz", NULL }; + +/* return the file name of the TGZ archive */ +/* or NULL if it does not exist */ + +char *TGZfname (const char *arcname) +{ + static char buffer[1024]; + int origlen,i; + + strcpy(buffer,arcname); + origlen = strlen(buffer); + + for (i=0; TGZsuffix[i]; i++) + { + strcpy(buffer+origlen,TGZsuffix[i]); + if (access(buffer,F_OK) == 0) + return buffer; + } + return NULL; +} + + +/* error message for the filename */ + +void TGZnotfound (const char *arcname) +{ + int i; + + fprintf(stderr,"%s: Couldn't find ",prog); + for (i=0;TGZsuffix[i];i++) + fprintf(stderr,(TGZsuffix[i+1]) ? "%s%s, " : "or %s%s\n", + arcname, + TGZsuffix[i]); + exit(1); +} + + +/* convert octal digits to int */ +/* on error return -1 */ + +int getoct (char *p,int width) +{ + int result = 0; + char c; + + while (width--) + { + c = *p++; + if (c == 0) + break; + if (c == ' ') + continue; + if (c < '0' || c > '7') + return -1; + result = result * 8 + (c - '0'); + } + return result; +} + + +/* convert time_t to string */ +/* use the "YYYY/MM/DD hh:mm:ss" format */ + +char *strtime (time_t *t) +{ + struct tm *local; + static char result[32]; + + local = localtime(t); + sprintf(result,"%4d/%02d/%02d %02d:%02d:%02d", + local->tm_year+1900, local->tm_mon+1, local->tm_mday, + local->tm_hour, local->tm_min, local->tm_sec); + return result; +} + + +/* set file time */ + +int setfiletime (char *fname,time_t ftime) +{ +#ifdef WIN32 + static int isWinNT = -1; + SYSTEMTIME st; + FILETIME locft, modft; + struct tm *loctm; + HANDLE hFile; + int result; + + loctm = localtime(&ftime); + if (loctm == NULL) + return -1; + + st.wYear = (WORD)loctm->tm_year + 1900; + st.wMonth = (WORD)loctm->tm_mon + 1; + st.wDayOfWeek = (WORD)loctm->tm_wday; + st.wDay = (WORD)loctm->tm_mday; + st.wHour = (WORD)loctm->tm_hour; + st.wMinute = (WORD)loctm->tm_min; + st.wSecond = (WORD)loctm->tm_sec; + st.wMilliseconds = 0; + if (!SystemTimeToFileTime(&st, &locft) || + !LocalFileTimeToFileTime(&locft, &modft)) + return -1; + + if (isWinNT < 0) + isWinNT = (GetVersion() < 0x80000000) ? 1 : 0; + hFile = CreateFile(fname, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, + (isWinNT ? FILE_FLAG_BACKUP_SEMANTICS : 0), + NULL); + if (hFile == INVALID_HANDLE_VALUE) + return -1; + result = SetFileTime(hFile, NULL, NULL, &modft) ? 0 : -1; + CloseHandle(hFile); + return result; +#else + struct utimbuf settime; + + settime.actime = settime.modtime = ftime; + return utime(fname,&settime); +#endif +} + + +/* push file attributes */ + +void push_attr(struct attr_item **list,char *fname,int mode,time_t time) +{ + struct attr_item *item; + + item = (struct attr_item *)malloc(sizeof(struct attr_item)); + if (item == NULL) + error("Out of memory"); + item->fname = strdup(fname); + item->mode = mode; + item->time = time; + item->next = *list; + *list = item; +} + + +/* restore file attributes */ + +void restore_attr(struct attr_item **list) +{ + struct attr_item *item, *prev; + + for (item = *list; item != NULL; ) + { + setfiletime(item->fname,item->time); + chmod(item->fname,item->mode); + prev = item; + item = item->next; + free(prev); + } + *list = NULL; +} + + +/* match regular expression */ + +#define ISSPECIAL(c) (((c) == '*') || ((c) == '/')) + +int ExprMatch (char *string,char *expr) +{ + while (1) + { + if (ISSPECIAL(*expr)) + { + if (*expr == '/') + { + if (*string != '\\' && *string != '/') + return 0; + string ++; expr++; + } + else if (*expr == '*') + { + if (*expr ++ == 0) + return 1; + while (*++string != *expr) + if (*string == 0) + return 0; + } + } + else + { + if (*string != *expr) + return 0; + if (*expr++ == 0) + return 1; + string++; + } + } +} + + +/* recursive mkdir */ +/* abort on ENOENT; ignore other errors like "directory already exists" */ +/* return 1 if OK */ +/* 0 on error */ + +int makedir (char *newdir) +{ + char *buffer = strdup(newdir); + char *p; + int len = strlen(buffer); + + if (len <= 0) { + free(buffer); + return 0; + } + if (buffer[len-1] == '/') { + buffer[len-1] = '\0'; + } + if (mkdir(buffer, 0755) == 0) + { + free(buffer); + return 1; + } + + p = buffer+1; + while (1) + { + char hold; + + while(*p && *p != '\\' && *p != '/') + p++; + hold = *p; + *p = 0; + if ((mkdir(buffer, 0755) == -1) && (errno == ENOENT)) + { + fprintf(stderr,"%s: Couldn't create directory %s\n",prog,buffer); + free(buffer); + return 0; + } + if (hold == 0) + break; + *p++ = hold; + } + free(buffer); + return 1; +} + + +int matchname (int arg,int argc,char **argv,char *fname) +{ + if (arg == argc) /* no arguments given (untgz tgzarchive) */ + return 1; + + while (arg < argc) + if (ExprMatch(fname,argv[arg++])) + return 1; + + return 0; /* ignore this for the moment being */ +} + + +/* tar file list or extract */ + +int tar (gzFile in,int action,int arg,int argc,char **argv) +{ + union tar_buffer buffer; + int len; + int err; + int getheader = 1; + int remaining = 0; + FILE *outfile = NULL; + char fname[BLOCKSIZE]; + int tarmode; + time_t tartime; + struct attr_item *attributes = NULL; + + if (action == TGZ_LIST) + printf(" date time size file\n" + " ---------- -------- --------- -------------------------------------\n"); + while (1) + { + len = gzread(in, &buffer, BLOCKSIZE); + if (len < 0) + error(gzerror(in, &err)); + /* + * Always expect complete blocks to process + * the tar information. + */ + if (len != BLOCKSIZE) + { + action = TGZ_INVALID; /* force error exit */ + remaining = 0; /* force I/O cleanup */ + } + + /* + * If we have to get a tar header + */ + if (getheader >= 1) + { + /* + * if we met the end of the tar + * or the end-of-tar block, + * we are done + */ + if (len == 0 || buffer.header.name[0] == 0) + break; + + tarmode = getoct(buffer.header.mode,8); + tartime = (time_t)getoct(buffer.header.mtime,12); + if (tarmode == -1 || tartime == (time_t)-1) + { + buffer.header.name[0] = 0; + action = TGZ_INVALID; + } + + if (getheader == 1) + { + strncpy(fname,buffer.header.name,SHORTNAMESIZE); + if (fname[SHORTNAMESIZE-1] != 0) + fname[SHORTNAMESIZE] = 0; + } + else + { + /* + * The file name is longer than SHORTNAMESIZE + */ + if (strncmp(fname,buffer.header.name,SHORTNAMESIZE-1) != 0) + error("bad long name"); + getheader = 1; + } + + /* + * Act according to the type flag + */ + switch (buffer.header.typeflag) + { + case DIRTYPE: + if (action == TGZ_LIST) + printf(" %s %s\n",strtime(&tartime),fname); + if (action == TGZ_EXTRACT) + { + makedir(fname); + push_attr(&attributes,fname,tarmode,tartime); + } + break; + case REGTYPE: + case AREGTYPE: + remaining = getoct(buffer.header.size,12); + if (remaining == -1) + { + action = TGZ_INVALID; + break; + } + if (action == TGZ_LIST) + printf(" %s %9d %s\n",strtime(&tartime),remaining,fname); + else if (action == TGZ_EXTRACT) + { + if (matchname(arg,argc,argv,fname)) + { + outfile = fopen(fname,"wb"); + if (outfile == NULL) { + /* try creating directory */ + char *p = strrchr(fname, '/'); + if (p != NULL) { + *p = '\0'; + makedir(fname); + *p = '/'; + outfile = fopen(fname,"wb"); + } + } + if (outfile != NULL) + printf("Extracting %s\n",fname); + else + fprintf(stderr, "%s: Couldn't create %s",prog,fname); + } + else + outfile = NULL; + } + getheader = 0; + break; + case GNUTYPE_LONGLINK: + case GNUTYPE_LONGNAME: + remaining = getoct(buffer.header.size,12); + if (remaining < 0 || remaining >= BLOCKSIZE) + { + action = TGZ_INVALID; + break; + } + len = gzread(in, fname, BLOCKSIZE); + if (len < 0) + error(gzerror(in, &err)); + if (fname[BLOCKSIZE-1] != 0 || (int)strlen(fname) > remaining) + { + action = TGZ_INVALID; + break; + } + getheader = 2; + break; + default: + if (action == TGZ_LIST) + printf(" %s <---> %s\n",strtime(&tartime),fname); + break; + } + } + else + { + unsigned int bytes = (remaining > BLOCKSIZE) ? BLOCKSIZE : remaining; + + if (outfile != NULL) + { + if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes) + { + fprintf(stderr, + "%s: Error writing %s -- skipping\n",prog,fname); + fclose(outfile); + outfile = NULL; + remove(fname); + } + } + remaining -= bytes; + } + + if (remaining == 0) + { + getheader = 1; + if (outfile != NULL) + { + fclose(outfile); + outfile = NULL; + if (action != TGZ_INVALID) + push_attr(&attributes,fname,tarmode,tartime); + } + } + + /* + * Abandon if errors are found + */ + if (action == TGZ_INVALID) + { + error("broken archive"); + break; + } + } + + /* + * Restore file modes and time stamps + */ + restore_attr(&attributes); + + if (gzclose(in) != Z_OK) + error("failed gzclose"); + + return 0; +} + + +/* ============================================================ */ + +void help(int exitval) +{ + printf("untgz version 0.2.1\n" + " using zlib version %s\n\n", + zlibVersion()); + printf("Usage: untgz file.tgz extract all files\n" + " untgz file.tgz fname ... extract selected files\n" + " untgz -l file.tgz list archive contents\n" + " untgz -h display this help\n"); + exit(exitval); +} + +void error(const char *msg) +{ + fprintf(stderr, "%s: %s\n", prog, msg); + exit(1); +} + + +/* ============================================================ */ + +#if defined(WIN32) && defined(__GNUC__) +int _CRT_glob = 0; /* disable argument globbing in MinGW */ +#endif + +int main(int argc,char **argv) +{ + int action = TGZ_EXTRACT; + int arg = 1; + char *TGZfile; + gzFile *f; + + prog = strrchr(argv[0],'\\'); + if (prog == NULL) + { + prog = strrchr(argv[0],'/'); + if (prog == NULL) + { + prog = strrchr(argv[0],':'); + if (prog == NULL) + prog = argv[0]; + else + prog++; + } + else + prog++; + } + else + prog++; + + if (argc == 1) + help(0); + + if (strcmp(argv[arg],"-l") == 0) + { + action = TGZ_LIST; + if (argc == ++arg) + help(0); + } + else if (strcmp(argv[arg],"-h") == 0) + { + help(0); + } + + if ((TGZfile = TGZfname(argv[arg])) == NULL) + TGZnotfound(argv[arg]); + + ++arg; + if ((action == TGZ_LIST) && (arg != argc)) + help(1); + +/* + * Process the TGZ file + */ + switch(action) + { + case TGZ_LIST: + case TGZ_EXTRACT: + f = gzopen(TGZfile,"rb"); + if (f == NULL) + { + fprintf(stderr,"%s: Couldn't gzopen %s\n",prog,TGZfile); + return 1; + } + exit(tar(f, action, arg, argc, argv)); + break; + + default: + error("Unknown option"); + exit(1); + } + + return 0; +} diff --git a/contrib/zlib/contrib/vstudio/readme.txt b/contrib/zlib/contrib/vstudio/readme.txt new file mode 100644 index 00000000..48cccc0d --- /dev/null +++ b/contrib/zlib/contrib/vstudio/readme.txt @@ -0,0 +1,78 @@ +Building instructions for the DLL versions of Zlib 1.2.11 +======================================================== + +This directory contains projects that build zlib and minizip using +Microsoft Visual C++ 9.0/10.0. + +You don't need to build these projects yourself. You can download the +binaries from: + http://www.winimage.com/zLibDll + +More information can be found at this site. + + + + + +Build instructions for Visual Studio 2008 (32 bits or 64 bits) +-------------------------------------------------------------- +- Decompress current zlib, including all contrib/* files +- Compile assembly code (with Visual Studio Command Prompt) by running: + bld_ml64.bat (in contrib\masmx64) + bld_ml32.bat (in contrib\masmx86) +- Open contrib\vstudio\vc9\zlibvc.sln with Microsoft Visual C++ 2008 +- Or run: vcbuild /rebuild contrib\vstudio\vc9\zlibvc.sln "Release|Win32" + +Build instructions for Visual Studio 2010 (32 bits or 64 bits) +-------------------------------------------------------------- +- Decompress current zlib, including all contrib/* files +- Open contrib\vstudio\vc10\zlibvc.sln with Microsoft Visual C++ 2010 + +Build instructions for Visual Studio 2012 (32 bits or 64 bits) +-------------------------------------------------------------- +- Decompress current zlib, including all contrib/* files +- Open contrib\vstudio\vc11\zlibvc.sln with Microsoft Visual C++ 2012 + +Build instructions for Visual Studio 2013 (32 bits or 64 bits) +-------------------------------------------------------------- +- Decompress current zlib, including all contrib/* files +- Open contrib\vstudio\vc12\zlibvc.sln with Microsoft Visual C++ 2013 + +Build instructions for Visual Studio 2015 (32 bits or 64 bits) +-------------------------------------------------------------- +- Decompress current zlib, including all contrib/* files +- Open contrib\vstudio\vc14\zlibvc.sln with Microsoft Visual C++ 2015 + + +Important +--------- +- To use zlibwapi.dll in your application, you must define the + macro ZLIB_WINAPI when compiling your application's source files. + + +Additional notes +---------------- +- This DLL, named zlibwapi.dll, is compatible to the old zlib.dll built + by Gilles Vollant from the zlib 1.1.x sources, and distributed at + http://www.winimage.com/zLibDll + It uses the WINAPI calling convention for the exported functions, and + includes the minizip functionality. If your application needs that + particular build of zlib.dll, you can rename zlibwapi.dll to zlib.dll. + +- The new DLL was renamed because there exist several incompatible + versions of zlib.dll on the Internet. + +- There is also an official DLL build of zlib, named zlib1.dll. This one + is exporting the functions using the CDECL convention. See the file + win32\DLL_FAQ.txt found in this zlib distribution. + +- There used to be a ZLIB_DLL macro in zlib 1.1.x, but now this symbol + has a slightly different effect. To avoid compatibility problems, do + not define it here. + + +Gilles Vollant +info@winimage.com + +Visual Studio 2013 and 2015 Projects from Sean Hunt +seandhunt_7@yahoo.com diff --git a/contrib/zlib/contrib/vstudio/vc10/miniunz.vcxproj b/contrib/zlib/contrib/vstudio/vc10/miniunz.vcxproj new file mode 100644 index 00000000..1b362421 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc10/miniunz.vcxproj @@ -0,0 +1,310 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {C52F9E7B-498A-42BE-8DB4-85A15694382A} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\MiniUnzip$(Configuration)\ + x86\MiniUnzip$(Configuration)\Tmp\ + true + false + x86\MiniUnzip$(Configuration)\ + x86\MiniUnzip$(Configuration)\Tmp\ + false + false + x64\MiniUnzip$(Configuration)\ + x64\MiniUnzip$(Configuration)\Tmp\ + true + false + ia64\MiniUnzip$(Configuration)\ + ia64\MiniUnzip$(Configuration)\Tmp\ + true + false + x64\MiniUnzip$(Configuration)\ + x64\MiniUnzip$(Configuration)\Tmp\ + false + false + ia64\MiniUnzip$(Configuration)\ + ia64\MiniUnzip$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebug + false + + + $(IntDir) + Level3 + EditAndContinue + + + x86\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + $(OutDir)miniunz.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + Console + true + true + false + + + MachineX86 + + + + + X64 + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + $(OutDir)miniunz.pdb + Console + MachineX64 + + + + + Itanium + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + $(OutDir)miniunz.pdb + Console + MachineIA64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + Console + true + true + MachineX64 + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + Console + true + true + MachineIA64 + + + + + + + + {8fd826f8-3739-44e6-8cc8-997122e53b8d} + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc10/miniunz.vcxproj.filters b/contrib/zlib/contrib/vstudio/vc10/miniunz.vcxproj.filters new file mode 100644 index 00000000..0bd12210 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc10/miniunz.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {048af943-022b-4db6-beeb-a54c34774ee2} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {c1d600d2-888f-4aea-b73e-8b0dd9befa0c} + h;hpp;hxx;hm;inl;inc + + + {0844199a-966b-4f19-81db-1e0125e141b9} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc10/minizip.vcxproj b/contrib/zlib/contrib/vstudio/vc10/minizip.vcxproj new file mode 100644 index 00000000..ccd3651d --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc10/minizip.vcxproj @@ -0,0 +1,307 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\MiniZip$(Configuration)\ + x86\MiniZip$(Configuration)\Tmp\ + true + false + x86\MiniZip$(Configuration)\ + x86\MiniZip$(Configuration)\Tmp\ + false + x64\$(Configuration)\ + x64\$(Configuration)\ + true + false + ia64\$(Configuration)\ + ia64\$(Configuration)\ + true + false + x64\$(Configuration)\ + x64\$(Configuration)\ + false + ia64\$(Configuration)\ + ia64\$(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebug + false + + + $(IntDir) + Level3 + EditAndContinue + + + x86\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + $(OutDir)minizip.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + Console + true + true + false + + + MachineX86 + + + + + X64 + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + $(OutDir)minizip.pdb + Console + MachineX64 + + + + + Itanium + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + $(OutDir)minizip.pdb + Console + MachineIA64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + Console + true + true + MachineX64 + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + Console + true + true + MachineIA64 + + + + + + + + {8fd826f8-3739-44e6-8cc8-997122e53b8d} + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc10/minizip.vcxproj.filters b/contrib/zlib/contrib/vstudio/vc10/minizip.vcxproj.filters new file mode 100644 index 00000000..7076d76f --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc10/minizip.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {c0419b40-bf50-40da-b153-ff74215b79de} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {bb87b070-735b-478e-92ce-7383abb2f36c} + h;hpp;hxx;hm;inl;inc + + + {f46ab6a6-548f-43cb-ae96-681abb5bd5db} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc10/testzlib.vcxproj b/contrib/zlib/contrib/vstudio/vc10/testzlib.vcxproj new file mode 100644 index 00000000..476b8ea4 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc10/testzlib.vcxproj @@ -0,0 +1,420 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + ReleaseWithoutAsm + Itanium + + + ReleaseWithoutAsm + Win32 + + + ReleaseWithoutAsm + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B} + testzlib + Win32Proj + + + + Application + MultiByte + true + + + Application + MultiByte + true + + + Application + MultiByte + + + Application + MultiByte + true + + + Application + MultiByte + true + + + Application + MultiByte + + + Application + true + + + Application + true + + + Application + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\TestZlib$(Configuration)\ + x86\TestZlib$(Configuration)\Tmp\ + true + false + x86\TestZlib$(Configuration)\ + x86\TestZlib$(Configuration)\Tmp\ + false + false + x86\TestZlib$(Configuration)\ + x86\TestZlib$(Configuration)\Tmp\ + false + false + x64\TestZlib$(Configuration)\ + x64\TestZlib$(Configuration)\Tmp\ + false + ia64\TestZlib$(Configuration)\ + ia64\TestZlib$(Configuration)\Tmp\ + true + false + x64\TestZlib$(Configuration)\ + x64\TestZlib$(Configuration)\Tmp\ + false + ia64\TestZlib$(Configuration)\ + ia64\TestZlib$(Configuration)\Tmp\ + false + false + x64\TestZlib$(Configuration)\ + x64\TestZlib$(Configuration)\Tmp\ + false + ia64\TestZlib$(Configuration)\ + ia64\TestZlib$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebug + false + + + AssemblyAndSourceCode + $(IntDir) + Level3 + EditAndContinue + + + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)testzlib.exe + true + $(OutDir)testzlib.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + Console + true + true + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)testzlib.exe + true + Console + true + true + false + + + MachineX86 + + + + + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + Default + MultiThreadedDebugDLL + false + $(IntDir) + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + + + + + Itanium + + + Disabled + ..\..\..;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + AssemblyAndSourceCode + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + $(OutDir)testzlib.pdb + Console + MachineIA64 + + + + + ..\..\..;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + Default + MultiThreadedDLL + false + $(IntDir) + + + %(AdditionalDependencies) + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + Console + true + true + MachineIA64 + + + + + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + Default + MultiThreadedDLL + false + $(IntDir) + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + Console + true + true + MachineIA64 + + + + + + + + + + true + true + true + true + true + true + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc10/testzlib.vcxproj.filters b/contrib/zlib/contrib/vstudio/vc10/testzlib.vcxproj.filters new file mode 100644 index 00000000..32764910 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc10/testzlib.vcxproj.filters @@ -0,0 +1,58 @@ + + + + + {c1f6a2e3-5da5-4955-8653-310d3efe05a9} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {c2aaffdc-2c95-4d6f-8466-4bec5890af2c} + h;hpp;hxx;hm;inl;inc + + + {c274fe07-05f2-461c-964b-f6341e4e7eb5} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc10/testzlibdll.vcxproj b/contrib/zlib/contrib/vstudio/vc10/testzlibdll.vcxproj new file mode 100644 index 00000000..8e38876f --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc10/testzlibdll.vcxproj @@ -0,0 +1,310 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {C52F9E7B-498A-42BE-8DB4-85A15694366A} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\TestZlibDll$(Configuration)\ + x86\TestZlibDll$(Configuration)\Tmp\ + true + false + x86\TestZlibDll$(Configuration)\ + x86\TestZlibDll$(Configuration)\Tmp\ + false + false + x64\TestZlibDll$(Configuration)\ + x64\TestZlibDll$(Configuration)\Tmp\ + true + false + ia64\TestZlibDll$(Configuration)\ + ia64\TestZlibDll$(Configuration)\Tmp\ + true + false + x64\TestZlibDll$(Configuration)\ + x64\TestZlibDll$(Configuration)\Tmp\ + false + false + ia64\TestZlibDll$(Configuration)\ + ia64\TestZlibDll$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebug + false + + + $(IntDir) + Level3 + EditAndContinue + + + x86\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + $(OutDir)testzlib.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + Console + true + true + false + + + MachineX86 + + + + + X64 + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + $(OutDir)testzlib.pdb + Console + MachineX64 + + + + + Itanium + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + $(OutDir)testzlib.pdb + Console + MachineIA64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + Console + true + true + MachineX64 + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + Console + true + true + MachineIA64 + + + + + + + + {8fd826f8-3739-44e6-8cc8-997122e53b8d} + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc10/testzlibdll.vcxproj.filters b/contrib/zlib/contrib/vstudio/vc10/testzlibdll.vcxproj.filters new file mode 100644 index 00000000..ab87f09f --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc10/testzlibdll.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {fa61a89f-93fc-4c89-b29e-36224b7592f4} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {d4b85da0-2ba2-4934-b57f-e2584e3848ee} + h;hpp;hxx;hm;inl;inc + + + {e573e075-00bd-4a7d-bd67-a8cc9bfc5aca} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc10/zlib.rc b/contrib/zlib/contrib/vstudio/vc10/zlib.rc new file mode 100644 index 00000000..c4e4b016 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc10/zlib.rc @@ -0,0 +1,32 @@ +#include + +#define IDR_VERSION1 1 +IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE + FILEVERSION 1, 2, 11, 0 + PRODUCTVERSION 1, 2, 11, 0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS 0 + FILEOS VOS_DOS_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0 // not used +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + //language ID = U.S. English, char set = Windows, Multilingual + + BEGIN + VALUE "FileDescription", "zlib data compression and ZIP file I/O library\0" + VALUE "FileVersion", "1.2.11\0" + VALUE "InternalName", "zlib\0" + VALUE "OriginalFilename", "zlibwapi.dll\0" + VALUE "ProductName", "ZLib.DLL\0" + VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0" + VALUE "LegalCopyright", "(C) 1995-2017 Jean-loup Gailly & Mark Adler\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1252 + END +END diff --git a/contrib/zlib/contrib/vstudio/vc10/zlibstat.vcxproj b/contrib/zlib/contrib/vstudio/vc10/zlibstat.vcxproj new file mode 100644 index 00000000..45389a35 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc10/zlibstat.vcxproj @@ -0,0 +1,473 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + ReleaseWithoutAsm + Itanium + + + ReleaseWithoutAsm + Win32 + + + ReleaseWithoutAsm + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8} + + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\ZlibStat$(Configuration)\ + x86\ZlibStat$(Configuration)\Tmp\ + x86\ZlibStat$(Configuration)\ + x86\ZlibStat$(Configuration)\Tmp\ + x86\ZlibStat$(Configuration)\ + x86\ZlibStat$(Configuration)\Tmp\ + x64\ZlibStat$(Configuration)\ + x64\ZlibStat$(Configuration)\Tmp\ + ia64\ZlibStat$(Configuration)\ + ia64\ZlibStat$(Configuration)\Tmp\ + x64\ZlibStat$(Configuration)\ + x64\ZlibStat$(Configuration)\Tmp\ + ia64\ZlibStat$(Configuration)\ + ia64\ZlibStat$(Configuration)\Tmp\ + x64\ZlibStat$(Configuration)\ + x64\ZlibStat$(Configuration)\Tmp\ + ia64\ZlibStat$(Configuration)\ + ia64\ZlibStat$(Configuration)\Tmp\ + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + + + MultiThreadedDebug + false + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + OldStyle + + + 0x040c + + + /MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + cd ..\..\masmx86 +bld_ml32.bat + + + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions) + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)zlibstat.lib + true + + + cd ..\..\masmx86 +bld_ml32.bat + + + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + X64 + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + OldStyle + + + 0x040c + + + /MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + cd ..\..\masmx64 +bld_ml64.bat + + + + + Itanium + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + OldStyle + + + 0x040c + + + /MACHINE:IA64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + X64 + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions) + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + $(OutDir)zlibstat.lib + true + + + cd ..\..\masmx64 +bld_ml64.bat + + + + + Itanium + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:IA64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + X64 + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + Itanium + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:IA64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + + + + + + + + + + true + true + true + true + true + true + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc10/zlibstat.vcxproj.filters b/contrib/zlib/contrib/vstudio/vc10/zlibstat.vcxproj.filters new file mode 100644 index 00000000..0c8b2501 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc10/zlibstat.vcxproj.filters @@ -0,0 +1,77 @@ + + + + + {174213f6-7f66-4ae8-a3a8-a1e0a1e6ffdd} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + + + Source Files + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc10/zlibvc.def b/contrib/zlib/contrib/vstudio/vc10/zlibvc.def new file mode 100644 index 00000000..f876c3bc --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc10/zlibvc.def @@ -0,0 +1,153 @@ +LIBRARY +; zlib data compression and ZIP file I/O library + +VERSION 1.2 + +EXPORTS + adler32 @1 + compress @2 + crc32 @3 + deflate @4 + deflateCopy @5 + deflateEnd @6 + deflateInit2_ @7 + deflateInit_ @8 + deflateParams @9 + deflateReset @10 + deflateSetDictionary @11 + gzclose @12 + gzdopen @13 + gzerror @14 + gzflush @15 + gzopen @16 + gzread @17 + gzwrite @18 + inflate @19 + inflateEnd @20 + inflateInit2_ @21 + inflateInit_ @22 + inflateReset @23 + inflateSetDictionary @24 + inflateSync @25 + uncompress @26 + zlibVersion @27 + gzprintf @28 + gzputc @29 + gzgetc @30 + gzseek @31 + gzrewind @32 + gztell @33 + gzeof @34 + gzsetparams @35 + zError @36 + inflateSyncPoint @37 + get_crc_table @38 + compress2 @39 + gzputs @40 + gzgets @41 + inflateCopy @42 + inflateBackInit_ @43 + inflateBack @44 + inflateBackEnd @45 + compressBound @46 + deflateBound @47 + gzclearerr @48 + gzungetc @49 + zlibCompileFlags @50 + deflatePrime @51 + deflatePending @52 + + unzOpen @61 + unzClose @62 + unzGetGlobalInfo @63 + unzGetCurrentFileInfo @64 + unzGoToFirstFile @65 + unzGoToNextFile @66 + unzOpenCurrentFile @67 + unzReadCurrentFile @68 + unzOpenCurrentFile3 @69 + unztell @70 + unzeof @71 + unzCloseCurrentFile @72 + unzGetGlobalComment @73 + unzStringFileNameCompare @74 + unzLocateFile @75 + unzGetLocalExtrafield @76 + unzOpen2 @77 + unzOpenCurrentFile2 @78 + unzOpenCurrentFilePassword @79 + + zipOpen @80 + zipOpenNewFileInZip @81 + zipWriteInFileInZip @82 + zipCloseFileInZip @83 + zipClose @84 + zipOpenNewFileInZip2 @86 + zipCloseFileInZipRaw @87 + zipOpen2 @88 + zipOpenNewFileInZip3 @89 + + unzGetFilePos @100 + unzGoToFilePos @101 + + fill_win32_filefunc @110 + +; zlibwapi v1.2.4 added: + fill_win32_filefunc64 @111 + fill_win32_filefunc64A @112 + fill_win32_filefunc64W @113 + + unzOpen64 @120 + unzOpen2_64 @121 + unzGetGlobalInfo64 @122 + unzGetCurrentFileInfo64 @124 + unzGetCurrentFileZStreamPos64 @125 + unztell64 @126 + unzGetFilePos64 @127 + unzGoToFilePos64 @128 + + zipOpen64 @130 + zipOpen2_64 @131 + zipOpenNewFileInZip64 @132 + zipOpenNewFileInZip2_64 @133 + zipOpenNewFileInZip3_64 @134 + zipOpenNewFileInZip4_64 @135 + zipCloseFileInZipRaw64 @136 + +; zlib1 v1.2.4 added: + adler32_combine @140 + crc32_combine @142 + deflateSetHeader @144 + deflateTune @145 + gzbuffer @146 + gzclose_r @147 + gzclose_w @148 + gzdirect @149 + gzoffset @150 + inflateGetHeader @156 + inflateMark @157 + inflatePrime @158 + inflateReset2 @159 + inflateUndermine @160 + +; zlib1 v1.2.6 added: + gzgetc_ @161 + inflateResetKeep @163 + deflateResetKeep @164 + +; zlib1 v1.2.7 added: + gzopen_w @165 + +; zlib1 v1.2.8 added: + inflateGetDictionary @166 + gzvprintf @167 + +; zlib1 v1.2.9 added: + inflateCodesUsed @168 + inflateValidate @169 + uncompress2 @170 + gzfread @171 + gzfwrite @172 + deflateGetDictionary @173 + adler32_z @174 + crc32_z @175 diff --git a/contrib/zlib/contrib/vstudio/vc10/zlibvc.sln b/contrib/zlib/contrib/vstudio/vc10/zlibvc.sln new file mode 100644 index 00000000..649f40c7 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc10/zlibvc.sln @@ -0,0 +1,135 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibvc", "zlibvc.vcxproj", "{8FD826F8-3739-44E6-8CC8-997122E53B8D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibstat", "zlibstat.vcxproj", "{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testzlib", "testzlib.vcxproj", "{AA6666AA-E09F-4135-9C0C-4FE50C3C654B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testzlibdll", "testzlibdll.vcxproj", "{C52F9E7B-498A-42BE-8DB4-85A15694366A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minizip", "minizip.vcxproj", "{48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniunz", "miniunz.vcxproj", "{C52F9E7B-498A-42BE-8DB4-85A15694382A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Itanium = Debug|Itanium + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Itanium = Release|Itanium + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + ReleaseWithoutAsm|Itanium = ReleaseWithoutAsm|Itanium + ReleaseWithoutAsm|Win32 = ReleaseWithoutAsm|Win32 + ReleaseWithoutAsm|x64 = ReleaseWithoutAsm|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Itanium.ActiveCfg = Debug|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Itanium.Build.0 = Debug|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.ActiveCfg = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.Build.0 = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|x64.ActiveCfg = Debug|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|x64.Build.0 = Debug|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Itanium.ActiveCfg = Release|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Itanium.Build.0 = Release|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.ActiveCfg = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.Build.0 = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|x64.ActiveCfg = Release|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|x64.Build.0 = Release|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Itanium.Build.0 = ReleaseWithoutAsm|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Itanium.ActiveCfg = Debug|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Itanium.Build.0 = Debug|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.ActiveCfg = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.Build.0 = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|x64.ActiveCfg = Debug|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|x64.Build.0 = Debug|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Itanium.ActiveCfg = Release|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Itanium.Build.0 = Release|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.ActiveCfg = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.Build.0 = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.ActiveCfg = Release|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.Build.0 = Release|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Itanium.Build.0 = ReleaseWithoutAsm|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.ActiveCfg = Debug|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.Build.0 = Debug|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.ActiveCfg = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.Build.0 = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.ActiveCfg = Debug|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.Build.0 = Debug|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.ActiveCfg = Release|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.Build.0 = Release|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.ActiveCfg = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.Build.0 = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.ActiveCfg = Release|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.Build.0 = Release|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.Build.0 = ReleaseWithoutAsm|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Itanium.ActiveCfg = Debug|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Itanium.Build.0 = Debug|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Win32.Build.0 = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|x64.ActiveCfg = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|x64.Build.0 = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Itanium.ActiveCfg = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Itanium.Build.0 = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Win32.Build.0 = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|x64.Build.0 = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Itanium.Build.0 = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.ActiveCfg = Debug|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.Build.0 = Debug|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.ActiveCfg = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.Build.0 = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.ActiveCfg = Debug|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.Build.0 = Debug|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.ActiveCfg = Release|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.Build.0 = Release|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.Build.0 = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.ActiveCfg = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.Build.0 = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.Build.0 = Release|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Itanium.ActiveCfg = Debug|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Itanium.Build.0 = Debug|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Win32.Build.0 = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|x64.ActiveCfg = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|x64.Build.0 = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Itanium.ActiveCfg = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Itanium.Build.0 = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Win32.Build.0 = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|x64.Build.0 = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Itanium.Build.0 = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/contrib/zlib/contrib/vstudio/vc10/zlibvc.vcxproj b/contrib/zlib/contrib/vstudio/vc10/zlibvc.vcxproj new file mode 100644 index 00000000..7d7c49a6 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc10/zlibvc.vcxproj @@ -0,0 +1,657 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + ReleaseWithoutAsm + Itanium + + + ReleaseWithoutAsm + Win32 + + + ReleaseWithoutAsm + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {8FD826F8-3739-44E6-8CC8-997122E53B8D} + + + + DynamicLibrary + false + true + + + DynamicLibrary + false + true + + + DynamicLibrary + false + + + DynamicLibrary + false + true + + + DynamicLibrary + false + true + + + DynamicLibrary + false + + + DynamicLibrary + false + true + + + DynamicLibrary + false + true + + + DynamicLibrary + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\ZlibDll$(Configuration)\ + x86\ZlibDll$(Configuration)\Tmp\ + true + false + x86\ZlibDll$(Configuration)\ + x86\ZlibDll$(Configuration)\Tmp\ + false + false + x86\ZlibDll$(Configuration)\ + x86\ZlibDll$(Configuration)\Tmp\ + false + false + x64\ZlibDll$(Configuration)\ + x64\ZlibDll$(Configuration)\Tmp\ + true + false + ia64\ZlibDll$(Configuration)\ + ia64\ZlibDll$(Configuration)\Tmp\ + true + false + x64\ZlibDll$(Configuration)\ + x64\ZlibDll$(Configuration)\Tmp\ + false + false + ia64\ZlibDll$(Configuration)\ + ia64\ZlibDll$(Configuration)\Tmp\ + false + false + x64\ZlibDll$(Configuration)\ + x64\ZlibDll$(Configuration)\Tmp\ + false + false + ia64\ZlibDll$(Configuration)\ + ia64\ZlibDll$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + zlibwapid + zlibwapi + zlibwapi + zlibwapid + zlibwapi + zlibwapi + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + $(OutDir)zlibvc.tlb + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;%(PreprocessorDefinitions) + + + MultiThreadedDebug + false + $(IntDir)zlibvc.pch + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + /MACHINE:I386 %(AdditionalOptions) + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + true + .\zlibvc.def + true + true + Windows + false + + + + + cd ..\..\masmx86 +bld_ml32.bat + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + /MACHINE:I386 %(AdditionalOptions) + true + false + .\zlibvc.def + true + Windows + false + + + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + /MACHINE:I386 %(AdditionalOptions) + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + true + false + .\zlibvc.def + true + Windows + false + + + + + cd ..\..\masmx86 +bld_ml32.bat + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + X64 + $(OutDir)zlibvc.tlb + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibvc.pch + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + true + .\zlibvc.def + true + true + Windows + MachineX64 + + + cd ..\..\masmx64 +bld_ml64.bat + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Itanium + $(OutDir)zlibvc.tlb + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibvc.pch + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + .\zlibvc.def + true + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineIA64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + X64 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + true + false + .\zlibvc.def + true + Windows + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Itanium + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineIA64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + X64 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + true + false + .\zlibvc.def + true + Windows + MachineX64 + + + cd ..\..\masmx64 +bld_ml64.bat + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Itanium + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineIA64 + + + + + + + + + + + + + + true + true + true + true + true + true + + + + + + + + + + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc10/zlibvc.vcxproj.filters b/contrib/zlib/contrib/vstudio/vc10/zlibvc.vcxproj.filters new file mode 100644 index 00000000..22786824 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc10/zlibvc.vcxproj.filters @@ -0,0 +1,118 @@ + + + + + {07934a85-8b61-443d-a0ee-b2eedb74f3cd} + cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90 + + + {1d99675b-433d-4a21-9e50-ed4ab8b19762} + h;hpp;hxx;hm;inl;fi;fd + + + {431c0958-fa71-44d0-9084-2d19d100c0cc} + ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc11/miniunz.vcxproj b/contrib/zlib/contrib/vstudio/vc11/miniunz.vcxproj new file mode 100644 index 00000000..99be63d6 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc11/miniunz.vcxproj @@ -0,0 +1,314 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {C52F9E7B-498A-42BE-8DB4-85A15694382A} + Win32Proj + + + + Application + MultiByte + v110 + + + Application + Unicode + v110 + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\MiniUnzip$(Configuration)\ + x86\MiniUnzip$(Configuration)\Tmp\ + true + false + x86\MiniUnzip$(Configuration)\ + x86\MiniUnzip$(Configuration)\Tmp\ + false + false + x64\MiniUnzip$(Configuration)\ + x64\MiniUnzip$(Configuration)\Tmp\ + true + false + ia64\MiniUnzip$(Configuration)\ + ia64\MiniUnzip$(Configuration)\Tmp\ + true + false + x64\MiniUnzip$(Configuration)\ + x64\MiniUnzip$(Configuration)\Tmp\ + false + false + ia64\MiniUnzip$(Configuration)\ + ia64\MiniUnzip$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + $(OutDir)miniunz.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + Console + true + true + false + + + MachineX86 + + + + + X64 + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + $(OutDir)miniunz.pdb + Console + MachineX64 + + + + + Itanium + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + $(OutDir)miniunz.pdb + Console + MachineIA64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + Console + true + true + MachineX64 + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + Console + true + true + MachineIA64 + + + + + + + + {8fd826f8-3739-44e6-8cc8-997122e53b8d} + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc11/minizip.vcxproj b/contrib/zlib/contrib/vstudio/vc11/minizip.vcxproj new file mode 100644 index 00000000..d6e98f4d --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc11/minizip.vcxproj @@ -0,0 +1,311 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B} + Win32Proj + + + + Application + MultiByte + v110 + + + Application + Unicode + v110 + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\MiniZip$(Configuration)\ + x86\MiniZip$(Configuration)\Tmp\ + true + false + x86\MiniZip$(Configuration)\ + x86\MiniZip$(Configuration)\Tmp\ + false + x64\$(Configuration)\ + x64\$(Configuration)\ + true + false + ia64\$(Configuration)\ + ia64\$(Configuration)\ + true + false + x64\$(Configuration)\ + x64\$(Configuration)\ + false + ia64\$(Configuration)\ + ia64\$(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + $(OutDir)minizip.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + Console + true + true + false + + + MachineX86 + + + + + X64 + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + $(OutDir)minizip.pdb + Console + MachineX64 + + + + + Itanium + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + $(OutDir)minizip.pdb + Console + MachineIA64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + Console + true + true + MachineX64 + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + Console + true + true + MachineIA64 + + + + + + + + {8fd826f8-3739-44e6-8cc8-997122e53b8d} + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc11/testzlib.vcxproj b/contrib/zlib/contrib/vstudio/vc11/testzlib.vcxproj new file mode 100644 index 00000000..0115dd17 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc11/testzlib.vcxproj @@ -0,0 +1,426 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + ReleaseWithoutAsm + Itanium + + + ReleaseWithoutAsm + Win32 + + + ReleaseWithoutAsm + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B} + testzlib + Win32Proj + + + + Application + MultiByte + true + v110 + + + Application + MultiByte + true + v110 + + + Application + Unicode + v110 + + + Application + MultiByte + true + + + Application + MultiByte + true + + + Application + MultiByte + + + Application + true + v110 + + + Application + true + v110 + + + Application + v110 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\TestZlib$(Configuration)\ + x86\TestZlib$(Configuration)\Tmp\ + true + false + x86\TestZlib$(Configuration)\ + x86\TestZlib$(Configuration)\Tmp\ + false + false + x86\TestZlib$(Configuration)\ + x86\TestZlib$(Configuration)\Tmp\ + false + false + x64\TestZlib$(Configuration)\ + x64\TestZlib$(Configuration)\Tmp\ + false + ia64\TestZlib$(Configuration)\ + ia64\TestZlib$(Configuration)\Tmp\ + true + false + x64\TestZlib$(Configuration)\ + x64\TestZlib$(Configuration)\Tmp\ + false + ia64\TestZlib$(Configuration)\ + ia64\TestZlib$(Configuration)\Tmp\ + false + false + x64\TestZlib$(Configuration)\ + x64\TestZlib$(Configuration)\Tmp\ + false + ia64\TestZlib$(Configuration)\ + ia64\TestZlib$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + AssemblyAndSourceCode + $(IntDir) + Level3 + ProgramDatabase + + + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)testzlib.exe + true + $(OutDir)testzlib.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + Console + true + true + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)testzlib.exe + true + Console + true + true + false + + + MachineX86 + + + + + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + Default + MultiThreadedDebugDLL + false + $(IntDir) + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + + + + + Itanium + + + Disabled + ..\..\..;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + AssemblyAndSourceCode + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + $(OutDir)testzlib.pdb + Console + MachineIA64 + + + + + ..\..\..;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + Default + MultiThreadedDLL + false + $(IntDir) + + + %(AdditionalDependencies) + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + Console + true + true + MachineIA64 + + + + + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + Default + MultiThreadedDLL + false + $(IntDir) + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + Console + true + true + MachineIA64 + + + + + + + + + + true + true + true + true + true + true + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc11/testzlibdll.vcxproj b/contrib/zlib/contrib/vstudio/vc11/testzlibdll.vcxproj new file mode 100644 index 00000000..9d36336e --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc11/testzlibdll.vcxproj @@ -0,0 +1,314 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {C52F9E7B-498A-42BE-8DB4-85A15694366A} + Win32Proj + + + + Application + MultiByte + v110 + + + Application + Unicode + v110 + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\TestZlibDll$(Configuration)\ + x86\TestZlibDll$(Configuration)\Tmp\ + true + false + x86\TestZlibDll$(Configuration)\ + x86\TestZlibDll$(Configuration)\Tmp\ + false + false + x64\TestZlibDll$(Configuration)\ + x64\TestZlibDll$(Configuration)\Tmp\ + true + false + ia64\TestZlibDll$(Configuration)\ + ia64\TestZlibDll$(Configuration)\Tmp\ + true + false + x64\TestZlibDll$(Configuration)\ + x64\TestZlibDll$(Configuration)\Tmp\ + false + false + ia64\TestZlibDll$(Configuration)\ + ia64\TestZlibDll$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + $(OutDir)testzlib.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + Console + true + true + false + + + MachineX86 + + + + + X64 + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + $(OutDir)testzlib.pdb + Console + MachineX64 + + + + + Itanium + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + $(OutDir)testzlib.pdb + Console + MachineIA64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + Console + true + true + MachineX64 + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + Console + true + true + MachineIA64 + + + + + + + + {8fd826f8-3739-44e6-8cc8-997122e53b8d} + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc11/zlib.rc b/contrib/zlib/contrib/vstudio/vc11/zlib.rc new file mode 100644 index 00000000..c4e4b016 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc11/zlib.rc @@ -0,0 +1,32 @@ +#include + +#define IDR_VERSION1 1 +IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE + FILEVERSION 1, 2, 11, 0 + PRODUCTVERSION 1, 2, 11, 0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS 0 + FILEOS VOS_DOS_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0 // not used +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + //language ID = U.S. English, char set = Windows, Multilingual + + BEGIN + VALUE "FileDescription", "zlib data compression and ZIP file I/O library\0" + VALUE "FileVersion", "1.2.11\0" + VALUE "InternalName", "zlib\0" + VALUE "OriginalFilename", "zlibwapi.dll\0" + VALUE "ProductName", "ZLib.DLL\0" + VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0" + VALUE "LegalCopyright", "(C) 1995-2017 Jean-loup Gailly & Mark Adler\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1252 + END +END diff --git a/contrib/zlib/contrib/vstudio/vc11/zlibstat.vcxproj b/contrib/zlib/contrib/vstudio/vc11/zlibstat.vcxproj new file mode 100644 index 00000000..64b4d869 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc11/zlibstat.vcxproj @@ -0,0 +1,464 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + ReleaseWithoutAsm + Itanium + + + ReleaseWithoutAsm + Win32 + + + ReleaseWithoutAsm + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8} + + + + StaticLibrary + false + v110 + + + StaticLibrary + false + v110 + + + StaticLibrary + false + v110 + Unicode + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + v110 + + + StaticLibrary + false + v110 + + + StaticLibrary + false + v110 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\ZlibStat$(Configuration)\ + x86\ZlibStat$(Configuration)\Tmp\ + x86\ZlibStat$(Configuration)\ + x86\ZlibStat$(Configuration)\Tmp\ + x86\ZlibStat$(Configuration)\ + x86\ZlibStat$(Configuration)\Tmp\ + x64\ZlibStat$(Configuration)\ + x64\ZlibStat$(Configuration)\Tmp\ + ia64\ZlibStat$(Configuration)\ + ia64\ZlibStat$(Configuration)\Tmp\ + x64\ZlibStat$(Configuration)\ + x64\ZlibStat$(Configuration)\Tmp\ + ia64\ZlibStat$(Configuration)\ + ia64\ZlibStat$(Configuration)\Tmp\ + x64\ZlibStat$(Configuration)\ + x64\ZlibStat$(Configuration)\Tmp\ + ia64\ZlibStat$(Configuration)\ + ia64\ZlibStat$(Configuration)\Tmp\ + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + OldStyle + + + 0x040c + + + /MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions) + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)zlibstat.lib + true + + + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + X64 + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + OldStyle + + + 0x040c + + + /MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + Itanium + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + OldStyle + + + 0x040c + + + /MACHINE:IA64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + X64 + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions) + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + $(OutDir)zlibstat.lib + true + + + + + Itanium + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:IA64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + X64 + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + Itanium + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:IA64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + + + + + + + + + + true + true + true + true + true + true + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc11/zlibvc.def b/contrib/zlib/contrib/vstudio/vc11/zlibvc.def new file mode 100644 index 00000000..f876c3bc --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc11/zlibvc.def @@ -0,0 +1,153 @@ +LIBRARY +; zlib data compression and ZIP file I/O library + +VERSION 1.2 + +EXPORTS + adler32 @1 + compress @2 + crc32 @3 + deflate @4 + deflateCopy @5 + deflateEnd @6 + deflateInit2_ @7 + deflateInit_ @8 + deflateParams @9 + deflateReset @10 + deflateSetDictionary @11 + gzclose @12 + gzdopen @13 + gzerror @14 + gzflush @15 + gzopen @16 + gzread @17 + gzwrite @18 + inflate @19 + inflateEnd @20 + inflateInit2_ @21 + inflateInit_ @22 + inflateReset @23 + inflateSetDictionary @24 + inflateSync @25 + uncompress @26 + zlibVersion @27 + gzprintf @28 + gzputc @29 + gzgetc @30 + gzseek @31 + gzrewind @32 + gztell @33 + gzeof @34 + gzsetparams @35 + zError @36 + inflateSyncPoint @37 + get_crc_table @38 + compress2 @39 + gzputs @40 + gzgets @41 + inflateCopy @42 + inflateBackInit_ @43 + inflateBack @44 + inflateBackEnd @45 + compressBound @46 + deflateBound @47 + gzclearerr @48 + gzungetc @49 + zlibCompileFlags @50 + deflatePrime @51 + deflatePending @52 + + unzOpen @61 + unzClose @62 + unzGetGlobalInfo @63 + unzGetCurrentFileInfo @64 + unzGoToFirstFile @65 + unzGoToNextFile @66 + unzOpenCurrentFile @67 + unzReadCurrentFile @68 + unzOpenCurrentFile3 @69 + unztell @70 + unzeof @71 + unzCloseCurrentFile @72 + unzGetGlobalComment @73 + unzStringFileNameCompare @74 + unzLocateFile @75 + unzGetLocalExtrafield @76 + unzOpen2 @77 + unzOpenCurrentFile2 @78 + unzOpenCurrentFilePassword @79 + + zipOpen @80 + zipOpenNewFileInZip @81 + zipWriteInFileInZip @82 + zipCloseFileInZip @83 + zipClose @84 + zipOpenNewFileInZip2 @86 + zipCloseFileInZipRaw @87 + zipOpen2 @88 + zipOpenNewFileInZip3 @89 + + unzGetFilePos @100 + unzGoToFilePos @101 + + fill_win32_filefunc @110 + +; zlibwapi v1.2.4 added: + fill_win32_filefunc64 @111 + fill_win32_filefunc64A @112 + fill_win32_filefunc64W @113 + + unzOpen64 @120 + unzOpen2_64 @121 + unzGetGlobalInfo64 @122 + unzGetCurrentFileInfo64 @124 + unzGetCurrentFileZStreamPos64 @125 + unztell64 @126 + unzGetFilePos64 @127 + unzGoToFilePos64 @128 + + zipOpen64 @130 + zipOpen2_64 @131 + zipOpenNewFileInZip64 @132 + zipOpenNewFileInZip2_64 @133 + zipOpenNewFileInZip3_64 @134 + zipOpenNewFileInZip4_64 @135 + zipCloseFileInZipRaw64 @136 + +; zlib1 v1.2.4 added: + adler32_combine @140 + crc32_combine @142 + deflateSetHeader @144 + deflateTune @145 + gzbuffer @146 + gzclose_r @147 + gzclose_w @148 + gzdirect @149 + gzoffset @150 + inflateGetHeader @156 + inflateMark @157 + inflatePrime @158 + inflateReset2 @159 + inflateUndermine @160 + +; zlib1 v1.2.6 added: + gzgetc_ @161 + inflateResetKeep @163 + deflateResetKeep @164 + +; zlib1 v1.2.7 added: + gzopen_w @165 + +; zlib1 v1.2.8 added: + inflateGetDictionary @166 + gzvprintf @167 + +; zlib1 v1.2.9 added: + inflateCodesUsed @168 + inflateValidate @169 + uncompress2 @170 + gzfread @171 + gzfwrite @172 + deflateGetDictionary @173 + adler32_z @174 + crc32_z @175 diff --git a/contrib/zlib/contrib/vstudio/vc11/zlibvc.sln b/contrib/zlib/contrib/vstudio/vc11/zlibvc.sln new file mode 100644 index 00000000..b7e38126 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc11/zlibvc.sln @@ -0,0 +1,117 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibvc", "zlibvc.vcxproj", "{8FD826F8-3739-44E6-8CC8-997122E53B8D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibstat", "zlibstat.vcxproj", "{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testzlib", "testzlib.vcxproj", "{AA6666AA-E09F-4135-9C0C-4FE50C3C654B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testzlibdll", "testzlibdll.vcxproj", "{C52F9E7B-498A-42BE-8DB4-85A15694366A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minizip", "minizip.vcxproj", "{48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniunz", "miniunz.vcxproj", "{C52F9E7B-498A-42BE-8DB4-85A15694382A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Itanium = Debug|Itanium + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Itanium = Release|Itanium + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + ReleaseWithoutAsm|Itanium = ReleaseWithoutAsm|Itanium + ReleaseWithoutAsm|Win32 = ReleaseWithoutAsm|Win32 + ReleaseWithoutAsm|x64 = ReleaseWithoutAsm|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Itanium.ActiveCfg = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.ActiveCfg = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.Build.0 = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|x64.ActiveCfg = Debug|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|x64.Build.0 = Debug|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Itanium.ActiveCfg = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.ActiveCfg = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.Build.0 = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|x64.ActiveCfg = Release|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|x64.Build.0 = Release|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Itanium.ActiveCfg = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.ActiveCfg = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.Build.0 = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|x64.ActiveCfg = Debug|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|x64.Build.0 = Debug|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Itanium.ActiveCfg = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.ActiveCfg = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.Build.0 = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.ActiveCfg = Release|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.Build.0 = Release|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.ActiveCfg = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.ActiveCfg = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.Build.0 = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.ActiveCfg = Debug|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.Build.0 = Debug|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.ActiveCfg = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.ActiveCfg = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.Build.0 = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.ActiveCfg = Release|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.Build.0 = Release|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Itanium.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Win32.Build.0 = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|x64.ActiveCfg = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|x64.Build.0 = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Itanium.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Win32.Build.0 = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|x64.Build.0 = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.ActiveCfg = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.ActiveCfg = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.Build.0 = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.ActiveCfg = Debug|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.Build.0 = Debug|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.Build.0 = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.ActiveCfg = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.Build.0 = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Itanium.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Win32.Build.0 = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|x64.ActiveCfg = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|x64.Build.0 = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Itanium.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Win32.Build.0 = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|x64.Build.0 = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/contrib/zlib/contrib/vstudio/vc11/zlibvc.vcxproj b/contrib/zlib/contrib/vstudio/vc11/zlibvc.vcxproj new file mode 100644 index 00000000..c4cffccf --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc11/zlibvc.vcxproj @@ -0,0 +1,688 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + ReleaseWithoutAsm + Itanium + + + ReleaseWithoutAsm + Win32 + + + ReleaseWithoutAsm + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {8FD826F8-3739-44E6-8CC8-997122E53B8D} + + + + DynamicLibrary + false + true + v110 + + + DynamicLibrary + false + true + v110 + + + DynamicLibrary + false + v110 + Unicode + + + DynamicLibrary + false + true + + + DynamicLibrary + false + true + + + DynamicLibrary + false + + + DynamicLibrary + false + true + v110 + + + DynamicLibrary + false + true + v110 + + + DynamicLibrary + false + v110 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\ZlibDll$(Configuration)\ + x86\ZlibDll$(Configuration)\Tmp\ + true + false + x86\ZlibDll$(Configuration)\ + x86\ZlibDll$(Configuration)\Tmp\ + false + false + x86\ZlibDll$(Configuration)\ + x86\ZlibDll$(Configuration)\Tmp\ + false + false + x64\ZlibDll$(Configuration)\ + x64\ZlibDll$(Configuration)\Tmp\ + true + false + ia64\ZlibDll$(Configuration)\ + ia64\ZlibDll$(Configuration)\Tmp\ + true + false + x64\ZlibDll$(Configuration)\ + x64\ZlibDll$(Configuration)\Tmp\ + false + false + ia64\ZlibDll$(Configuration)\ + ia64\ZlibDll$(Configuration)\Tmp\ + false + false + x64\ZlibDll$(Configuration)\ + x64\ZlibDll$(Configuration)\Tmp\ + false + false + ia64\ZlibDll$(Configuration)\ + ia64\ZlibDll$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + zlibwapi + zlibwapi + zlibwapi + zlibwapi + zlibwapi + zlibwapi + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + $(OutDir)zlibvc.tlb + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibvc.pch + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + /MACHINE:I386 %(AdditionalOptions) + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)zlibwapi.dll + true + .\zlibvc.def + true + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + false + + + $(OutDir)zlibwapi.lib + + + cd ..\..\masmx86 +bld_ml32.bat + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + /MACHINE:I386 %(AdditionalOptions) + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + false + + + $(OutDir)zlibwapi.lib + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + /MACHINE:I386 %(AdditionalOptions) + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + false + + + $(OutDir)zlibwapi.lib + + + cd ..\..\masmx86 +bld_ml32.bat + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + X64 + $(OutDir)zlibvc.tlb + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibvc.pch + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + $(OutDir)zlibwapi.dll + true + .\zlibvc.def + true + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineX64 + + + cd ..\..\contrib\masmx64 +bld_ml64.bat + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Itanium + $(OutDir)zlibvc.tlb + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibvc.pch + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + .\zlibvc.def + true + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineIA64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + X64 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Itanium + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineIA64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + X64 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineX64 + + + cd ..\..\masmx64 +bld_ml64.bat + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Itanium + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineIA64 + + + + + + + + + + + + + + true + true + true + true + true + true + + + + + + + + + + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc12/miniunz.vcxproj b/contrib/zlib/contrib/vstudio/vc12/miniunz.vcxproj new file mode 100644 index 00000000..d88ac7fc --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc12/miniunz.vcxproj @@ -0,0 +1,316 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {C52F9E7B-498A-42BE-8DB4-85A15694382A} + Win32Proj + + + + Application + MultiByte + v120 + + + Application + Unicode + v120 + + + Application + MultiByte + v120 + + + Application + MultiByte + v120 + + + Application + MultiByte + v120 + + + Application + MultiByte + v120 + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\MiniUnzip$(Configuration)\ + x86\MiniUnzip$(Configuration)\Tmp\ + true + false + x86\MiniUnzip$(Configuration)\ + x86\MiniUnzip$(Configuration)\Tmp\ + false + false + x64\MiniUnzip$(Configuration)\ + x64\MiniUnzip$(Configuration)\Tmp\ + true + false + ia64\MiniUnzip$(Configuration)\ + ia64\MiniUnzip$(Configuration)\Tmp\ + true + false + x64\MiniUnzip$(Configuration)\ + x64\MiniUnzip$(Configuration)\Tmp\ + false + false + ia64\MiniUnzip$(Configuration)\ + ia64\MiniUnzip$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + $(OutDir)miniunz.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + Console + true + true + false + + + MachineX86 + + + + + X64 + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + $(OutDir)miniunz.pdb + Console + MachineX64 + + + + + Itanium + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + $(OutDir)miniunz.pdb + Console + MachineIA64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + Console + true + true + MachineX64 + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + Console + true + true + MachineIA64 + + + + + + + + {8fd826f8-3739-44e6-8cc8-997122e53b8d} + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc12/minizip.vcxproj b/contrib/zlib/contrib/vstudio/vc12/minizip.vcxproj new file mode 100644 index 00000000..f1f239c9 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc12/minizip.vcxproj @@ -0,0 +1,313 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B} + Win32Proj + + + + Application + MultiByte + v120 + + + Application + Unicode + v120 + + + Application + MultiByte + v120 + + + Application + MultiByte + v120 + + + Application + MultiByte + v120 + + + Application + MultiByte + v120 + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\MiniZip$(Configuration)\ + x86\MiniZip$(Configuration)\Tmp\ + true + false + x86\MiniZip$(Configuration)\ + x86\MiniZip$(Configuration)\Tmp\ + false + x64\$(Configuration)\ + x64\$(Configuration)\ + true + false + ia64\$(Configuration)\ + ia64\$(Configuration)\ + true + false + x64\$(Configuration)\ + x64\$(Configuration)\ + false + ia64\$(Configuration)\ + ia64\$(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + $(OutDir)minizip.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + Console + true + true + false + + + MachineX86 + + + + + X64 + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + $(OutDir)minizip.pdb + Console + MachineX64 + + + + + Itanium + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + $(OutDir)minizip.pdb + Console + MachineIA64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + Console + true + true + MachineX64 + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + Console + true + true + MachineIA64 + + + + + + + + {8fd826f8-3739-44e6-8cc8-997122e53b8d} + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc12/testzlib.vcxproj b/contrib/zlib/contrib/vstudio/vc12/testzlib.vcxproj new file mode 100644 index 00000000..64b2cbe3 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc12/testzlib.vcxproj @@ -0,0 +1,430 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + ReleaseWithoutAsm + Itanium + + + ReleaseWithoutAsm + Win32 + + + ReleaseWithoutAsm + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B} + testzlib + Win32Proj + + + + Application + MultiByte + true + v120 + + + Application + MultiByte + true + v120 + + + Application + Unicode + v120 + + + Application + MultiByte + true + v120 + + + Application + MultiByte + true + v120 + + + Application + MultiByte + v120 + + + Application + true + v120 + + + Application + true + v120 + + + Application + v120 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\TestZlib$(Configuration)\ + x86\TestZlib$(Configuration)\Tmp\ + true + false + x86\TestZlib$(Configuration)\ + x86\TestZlib$(Configuration)\Tmp\ + false + false + x86\TestZlib$(Configuration)\ + x86\TestZlib$(Configuration)\Tmp\ + false + false + x64\TestZlib$(Configuration)\ + x64\TestZlib$(Configuration)\Tmp\ + false + ia64\TestZlib$(Configuration)\ + ia64\TestZlib$(Configuration)\Tmp\ + true + false + x64\TestZlib$(Configuration)\ + x64\TestZlib$(Configuration)\Tmp\ + false + ia64\TestZlib$(Configuration)\ + ia64\TestZlib$(Configuration)\Tmp\ + false + false + x64\TestZlib$(Configuration)\ + x64\TestZlib$(Configuration)\Tmp\ + false + ia64\TestZlib$(Configuration)\ + ia64\TestZlib$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + AssemblyAndSourceCode + $(IntDir) + Level3 + ProgramDatabase + + + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)testzlib.exe + true + $(OutDir)testzlib.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + Console + true + true + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)testzlib.exe + true + Console + true + true + false + + + MachineX86 + false + + + + + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + Default + MultiThreadedDebugDLL + false + $(IntDir) + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + + + + + Itanium + + + Disabled + ..\..\..;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + AssemblyAndSourceCode + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + $(OutDir)testzlib.pdb + Console + MachineIA64 + + + + + ..\..\..;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + Default + MultiThreadedDLL + false + $(IntDir) + + + %(AdditionalDependencies) + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + Console + true + true + MachineIA64 + + + + + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + Default + MultiThreadedDLL + false + $(IntDir) + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + Console + true + true + MachineIA64 + + + + + + + + + + true + true + true + true + true + true + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc12/testzlibdll.vcxproj b/contrib/zlib/contrib/vstudio/vc12/testzlibdll.vcxproj new file mode 100644 index 00000000..c66573a8 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc12/testzlibdll.vcxproj @@ -0,0 +1,316 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {C52F9E7B-498A-42BE-8DB4-85A15694366A} + Win32Proj + + + + Application + MultiByte + v120 + + + Application + Unicode + v120 + + + Application + MultiByte + v120 + + + Application + MultiByte + v120 + + + Application + MultiByte + v120 + + + Application + MultiByte + v120 + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\TestZlibDll$(Configuration)\ + x86\TestZlibDll$(Configuration)\Tmp\ + true + false + x86\TestZlibDll$(Configuration)\ + x86\TestZlibDll$(Configuration)\Tmp\ + false + false + x64\TestZlibDll$(Configuration)\ + x64\TestZlibDll$(Configuration)\Tmp\ + true + false + ia64\TestZlibDll$(Configuration)\ + ia64\TestZlibDll$(Configuration)\Tmp\ + true + false + x64\TestZlibDll$(Configuration)\ + x64\TestZlibDll$(Configuration)\Tmp\ + false + false + ia64\TestZlibDll$(Configuration)\ + ia64\TestZlibDll$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + $(OutDir)testzlib.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + Console + true + true + false + + + MachineX86 + + + + + X64 + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + $(OutDir)testzlib.pdb + Console + MachineX64 + + + + + Itanium + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + $(OutDir)testzlib.pdb + Console + MachineIA64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + Console + true + true + MachineX64 + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + Console + true + true + MachineIA64 + + + + + + + + {8fd826f8-3739-44e6-8cc8-997122e53b8d} + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc12/zlib.rc b/contrib/zlib/contrib/vstudio/vc12/zlib.rc new file mode 100644 index 00000000..c4e4b016 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc12/zlib.rc @@ -0,0 +1,32 @@ +#include + +#define IDR_VERSION1 1 +IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE + FILEVERSION 1, 2, 11, 0 + PRODUCTVERSION 1, 2, 11, 0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS 0 + FILEOS VOS_DOS_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0 // not used +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + //language ID = U.S. English, char set = Windows, Multilingual + + BEGIN + VALUE "FileDescription", "zlib data compression and ZIP file I/O library\0" + VALUE "FileVersion", "1.2.11\0" + VALUE "InternalName", "zlib\0" + VALUE "OriginalFilename", "zlibwapi.dll\0" + VALUE "ProductName", "ZLib.DLL\0" + VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0" + VALUE "LegalCopyright", "(C) 1995-2017 Jean-loup Gailly & Mark Adler\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1252 + END +END diff --git a/contrib/zlib/contrib/vstudio/vc12/zlibstat.vcxproj b/contrib/zlib/contrib/vstudio/vc12/zlibstat.vcxproj new file mode 100644 index 00000000..3fdee7c5 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc12/zlibstat.vcxproj @@ -0,0 +1,467 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + ReleaseWithoutAsm + Itanium + + + ReleaseWithoutAsm + Win32 + + + ReleaseWithoutAsm + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8} + + + + StaticLibrary + false + v120 + + + StaticLibrary + false + v120 + + + StaticLibrary + false + v120 + Unicode + + + StaticLibrary + false + v120 + + + StaticLibrary + false + v120 + + + StaticLibrary + false + v120 + + + StaticLibrary + false + v120 + + + StaticLibrary + false + v120 + + + StaticLibrary + false + v120 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\ZlibStat$(Configuration)\ + x86\ZlibStat$(Configuration)\Tmp\ + x86\ZlibStat$(Configuration)\ + x86\ZlibStat$(Configuration)\Tmp\ + x86\ZlibStat$(Configuration)\ + x86\ZlibStat$(Configuration)\Tmp\ + x64\ZlibStat$(Configuration)\ + x64\ZlibStat$(Configuration)\Tmp\ + ia64\ZlibStat$(Configuration)\ + ia64\ZlibStat$(Configuration)\Tmp\ + x64\ZlibStat$(Configuration)\ + x64\ZlibStat$(Configuration)\Tmp\ + ia64\ZlibStat$(Configuration)\ + ia64\ZlibStat$(Configuration)\Tmp\ + x64\ZlibStat$(Configuration)\ + x64\ZlibStat$(Configuration)\Tmp\ + ia64\ZlibStat$(Configuration)\ + ia64\ZlibStat$(Configuration)\Tmp\ + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + OldStyle + + + 0x040c + + + /MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions) + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)zlibstat.lib + true + + + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + X64 + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + OldStyle + + + 0x040c + + + /MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + Itanium + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + OldStyle + + + 0x040c + + + /MACHINE:IA64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + X64 + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions) + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + $(OutDir)zlibstat.lib + true + + + + + Itanium + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:IA64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + X64 + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + Itanium + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:IA64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + + + + + + + + + + true + true + true + true + true + true + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc12/zlibvc.def b/contrib/zlib/contrib/vstudio/vc12/zlibvc.def new file mode 100644 index 00000000..f876c3bc --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc12/zlibvc.def @@ -0,0 +1,153 @@ +LIBRARY +; zlib data compression and ZIP file I/O library + +VERSION 1.2 + +EXPORTS + adler32 @1 + compress @2 + crc32 @3 + deflate @4 + deflateCopy @5 + deflateEnd @6 + deflateInit2_ @7 + deflateInit_ @8 + deflateParams @9 + deflateReset @10 + deflateSetDictionary @11 + gzclose @12 + gzdopen @13 + gzerror @14 + gzflush @15 + gzopen @16 + gzread @17 + gzwrite @18 + inflate @19 + inflateEnd @20 + inflateInit2_ @21 + inflateInit_ @22 + inflateReset @23 + inflateSetDictionary @24 + inflateSync @25 + uncompress @26 + zlibVersion @27 + gzprintf @28 + gzputc @29 + gzgetc @30 + gzseek @31 + gzrewind @32 + gztell @33 + gzeof @34 + gzsetparams @35 + zError @36 + inflateSyncPoint @37 + get_crc_table @38 + compress2 @39 + gzputs @40 + gzgets @41 + inflateCopy @42 + inflateBackInit_ @43 + inflateBack @44 + inflateBackEnd @45 + compressBound @46 + deflateBound @47 + gzclearerr @48 + gzungetc @49 + zlibCompileFlags @50 + deflatePrime @51 + deflatePending @52 + + unzOpen @61 + unzClose @62 + unzGetGlobalInfo @63 + unzGetCurrentFileInfo @64 + unzGoToFirstFile @65 + unzGoToNextFile @66 + unzOpenCurrentFile @67 + unzReadCurrentFile @68 + unzOpenCurrentFile3 @69 + unztell @70 + unzeof @71 + unzCloseCurrentFile @72 + unzGetGlobalComment @73 + unzStringFileNameCompare @74 + unzLocateFile @75 + unzGetLocalExtrafield @76 + unzOpen2 @77 + unzOpenCurrentFile2 @78 + unzOpenCurrentFilePassword @79 + + zipOpen @80 + zipOpenNewFileInZip @81 + zipWriteInFileInZip @82 + zipCloseFileInZip @83 + zipClose @84 + zipOpenNewFileInZip2 @86 + zipCloseFileInZipRaw @87 + zipOpen2 @88 + zipOpenNewFileInZip3 @89 + + unzGetFilePos @100 + unzGoToFilePos @101 + + fill_win32_filefunc @110 + +; zlibwapi v1.2.4 added: + fill_win32_filefunc64 @111 + fill_win32_filefunc64A @112 + fill_win32_filefunc64W @113 + + unzOpen64 @120 + unzOpen2_64 @121 + unzGetGlobalInfo64 @122 + unzGetCurrentFileInfo64 @124 + unzGetCurrentFileZStreamPos64 @125 + unztell64 @126 + unzGetFilePos64 @127 + unzGoToFilePos64 @128 + + zipOpen64 @130 + zipOpen2_64 @131 + zipOpenNewFileInZip64 @132 + zipOpenNewFileInZip2_64 @133 + zipOpenNewFileInZip3_64 @134 + zipOpenNewFileInZip4_64 @135 + zipCloseFileInZipRaw64 @136 + +; zlib1 v1.2.4 added: + adler32_combine @140 + crc32_combine @142 + deflateSetHeader @144 + deflateTune @145 + gzbuffer @146 + gzclose_r @147 + gzclose_w @148 + gzdirect @149 + gzoffset @150 + inflateGetHeader @156 + inflateMark @157 + inflatePrime @158 + inflateReset2 @159 + inflateUndermine @160 + +; zlib1 v1.2.6 added: + gzgetc_ @161 + inflateResetKeep @163 + deflateResetKeep @164 + +; zlib1 v1.2.7 added: + gzopen_w @165 + +; zlib1 v1.2.8 added: + inflateGetDictionary @166 + gzvprintf @167 + +; zlib1 v1.2.9 added: + inflateCodesUsed @168 + inflateValidate @169 + uncompress2 @170 + gzfread @171 + gzfwrite @172 + deflateGetDictionary @173 + adler32_z @174 + crc32_z @175 diff --git a/contrib/zlib/contrib/vstudio/vc12/zlibvc.sln b/contrib/zlib/contrib/vstudio/vc12/zlibvc.sln new file mode 100644 index 00000000..dcda2298 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc12/zlibvc.sln @@ -0,0 +1,119 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.40629.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibvc", "zlibvc.vcxproj", "{8FD826F8-3739-44E6-8CC8-997122E53B8D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibstat", "zlibstat.vcxproj", "{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testzlib", "testzlib.vcxproj", "{AA6666AA-E09F-4135-9C0C-4FE50C3C654B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testzlibdll", "testzlibdll.vcxproj", "{C52F9E7B-498A-42BE-8DB4-85A15694366A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minizip", "minizip.vcxproj", "{48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniunz", "miniunz.vcxproj", "{C52F9E7B-498A-42BE-8DB4-85A15694382A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Itanium = Debug|Itanium + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Itanium = Release|Itanium + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + ReleaseWithoutAsm|Itanium = ReleaseWithoutAsm|Itanium + ReleaseWithoutAsm|Win32 = ReleaseWithoutAsm|Win32 + ReleaseWithoutAsm|x64 = ReleaseWithoutAsm|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Itanium.ActiveCfg = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.ActiveCfg = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.Build.0 = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|x64.ActiveCfg = Debug|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|x64.Build.0 = Debug|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Itanium.ActiveCfg = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.ActiveCfg = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.Build.0 = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|x64.ActiveCfg = Release|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|x64.Build.0 = Release|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Itanium.ActiveCfg = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.ActiveCfg = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.Build.0 = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|x64.ActiveCfg = Debug|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|x64.Build.0 = Debug|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Itanium.ActiveCfg = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.ActiveCfg = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.Build.0 = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.ActiveCfg = Release|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.Build.0 = Release|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.ActiveCfg = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.ActiveCfg = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.Build.0 = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.ActiveCfg = Debug|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.Build.0 = Debug|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.ActiveCfg = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.ActiveCfg = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.Build.0 = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.ActiveCfg = Release|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.Build.0 = Release|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Itanium.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Win32.Build.0 = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|x64.ActiveCfg = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|x64.Build.0 = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Itanium.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Win32.Build.0 = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|x64.Build.0 = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.ActiveCfg = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.ActiveCfg = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.Build.0 = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.ActiveCfg = Debug|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.Build.0 = Debug|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.Build.0 = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.ActiveCfg = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.Build.0 = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Itanium.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Win32.Build.0 = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|x64.ActiveCfg = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|x64.Build.0 = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Itanium.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Win32.Build.0 = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|x64.Build.0 = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/contrib/zlib/contrib/vstudio/vc12/zlibvc.vcxproj b/contrib/zlib/contrib/vstudio/vc12/zlibvc.vcxproj new file mode 100644 index 00000000..ab2b6c36 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc12/zlibvc.vcxproj @@ -0,0 +1,692 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + ReleaseWithoutAsm + Itanium + + + ReleaseWithoutAsm + Win32 + + + ReleaseWithoutAsm + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {8FD826F8-3739-44E6-8CC8-997122E53B8D} + + + + DynamicLibrary + false + true + v120 + + + DynamicLibrary + false + true + v120 + + + DynamicLibrary + false + v120 + Unicode + + + DynamicLibrary + false + true + v120 + + + DynamicLibrary + false + true + v120 + + + DynamicLibrary + false + v120 + + + DynamicLibrary + false + true + v120 + + + DynamicLibrary + false + true + v120 + + + DynamicLibrary + false + v120 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\ZlibDll$(Configuration)\ + x86\ZlibDll$(Configuration)\Tmp\ + true + false + x86\ZlibDll$(Configuration)\ + x86\ZlibDll$(Configuration)\Tmp\ + false + false + x86\ZlibDll$(Configuration)\ + x86\ZlibDll$(Configuration)\Tmp\ + false + false + x64\ZlibDll$(Configuration)\ + x64\ZlibDll$(Configuration)\Tmp\ + true + false + ia64\ZlibDll$(Configuration)\ + ia64\ZlibDll$(Configuration)\Tmp\ + true + false + x64\ZlibDll$(Configuration)\ + x64\ZlibDll$(Configuration)\Tmp\ + false + false + ia64\ZlibDll$(Configuration)\ + ia64\ZlibDll$(Configuration)\Tmp\ + false + false + x64\ZlibDll$(Configuration)\ + x64\ZlibDll$(Configuration)\Tmp\ + false + false + ia64\ZlibDll$(Configuration)\ + ia64\ZlibDll$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + zlibwapi + zlibwapi + zlibwapi + zlibwapi + zlibwapi + zlibwapi + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + $(OutDir)zlibvc.tlb + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibvc.pch + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + /MACHINE:I386 %(AdditionalOptions) + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)zlibwapi.dll + true + .\zlibvc.def + true + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + false + + + $(OutDir)zlibwapi.lib + + + cd ..\..\masmx86 +bld_ml32.bat + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + /MACHINE:I386 %(AdditionalOptions) + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + false + + + $(OutDir)zlibwapi.lib + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + /MACHINE:I386 %(AdditionalOptions) + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + false + + + $(OutDir)zlibwapi.lib + false + + + cd ..\..\masmx86 +bld_ml32.bat + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + X64 + $(OutDir)zlibvc.tlb + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibvc.pch + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + $(OutDir)zlibwapi.dll + true + .\zlibvc.def + true + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineX64 + + + cd ..\..\contrib\masmx64 +bld_ml64.bat + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Itanium + $(OutDir)zlibvc.tlb + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibvc.pch + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + .\zlibvc.def + true + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineIA64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + X64 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Itanium + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineIA64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + X64 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineX64 + + + cd ..\..\masmx64 +bld_ml64.bat + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Itanium + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineIA64 + + + + + + + + + + + + + + true + true + true + true + true + true + + + + + + + + + + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc14/miniunz.vcxproj b/contrib/zlib/contrib/vstudio/vc14/miniunz.vcxproj new file mode 100644 index 00000000..9b5c0758 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc14/miniunz.vcxproj @@ -0,0 +1,316 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {C52F9E7B-498A-42BE-8DB4-85A15694382A} + Win32Proj + + + + Application + MultiByte + v140 + + + Application + Unicode + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\MiniUnzip$(Configuration)\ + x86\MiniUnzip$(Configuration)\Tmp\ + true + false + x86\MiniUnzip$(Configuration)\ + x86\MiniUnzip$(Configuration)\Tmp\ + false + false + x64\MiniUnzip$(Configuration)\ + x64\MiniUnzip$(Configuration)\Tmp\ + true + false + ia64\MiniUnzip$(Configuration)\ + ia64\MiniUnzip$(Configuration)\Tmp\ + true + false + x64\MiniUnzip$(Configuration)\ + x64\MiniUnzip$(Configuration)\Tmp\ + false + false + ia64\MiniUnzip$(Configuration)\ + ia64\MiniUnzip$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + $(OutDir)miniunz.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + Console + true + true + false + + + MachineX86 + + + + + X64 + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + $(OutDir)miniunz.pdb + Console + MachineX64 + + + + + Itanium + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + $(OutDir)miniunz.pdb + Console + MachineIA64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + Console + true + true + MachineX64 + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + Console + true + true + MachineIA64 + + + + + + + + {8fd826f8-3739-44e6-8cc8-997122e53b8d} + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc14/minizip.vcxproj b/contrib/zlib/contrib/vstudio/vc14/minizip.vcxproj new file mode 100644 index 00000000..968a410a --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc14/minizip.vcxproj @@ -0,0 +1,313 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B} + Win32Proj + + + + Application + MultiByte + v140 + + + Application + Unicode + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\MiniZip$(Configuration)\ + x86\MiniZip$(Configuration)\Tmp\ + true + false + x86\MiniZip$(Configuration)\ + x86\MiniZip$(Configuration)\Tmp\ + false + x64\$(Configuration)\ + x64\$(Configuration)\ + true + false + ia64\$(Configuration)\ + ia64\$(Configuration)\ + true + false + x64\$(Configuration)\ + x64\$(Configuration)\ + false + ia64\$(Configuration)\ + ia64\$(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + $(OutDir)minizip.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + Console + true + true + false + + + MachineX86 + + + + + X64 + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + $(OutDir)minizip.pdb + Console + MachineX64 + + + + + Itanium + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + $(OutDir)minizip.pdb + Console + MachineIA64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + Console + true + true + MachineX64 + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + Console + true + true + MachineIA64 + + + + + + + + {8fd826f8-3739-44e6-8cc8-997122e53b8d} + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc14/testzlib.vcxproj b/contrib/zlib/contrib/vstudio/vc14/testzlib.vcxproj new file mode 100644 index 00000000..2c371252 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc14/testzlib.vcxproj @@ -0,0 +1,430 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + ReleaseWithoutAsm + Itanium + + + ReleaseWithoutAsm + Win32 + + + ReleaseWithoutAsm + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B} + testzlib + Win32Proj + + + + Application + MultiByte + true + v140 + + + Application + MultiByte + true + v140 + + + Application + Unicode + v140 + + + Application + MultiByte + true + v140 + + + Application + MultiByte + true + v140 + + + Application + MultiByte + v140 + + + Application + true + v140 + + + Application + true + v140 + + + Application + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\TestZlib$(Configuration)\ + x86\TestZlib$(Configuration)\Tmp\ + true + false + x86\TestZlib$(Configuration)\ + x86\TestZlib$(Configuration)\Tmp\ + false + false + x86\TestZlib$(Configuration)\ + x86\TestZlib$(Configuration)\Tmp\ + false + false + x64\TestZlib$(Configuration)\ + x64\TestZlib$(Configuration)\Tmp\ + false + ia64\TestZlib$(Configuration)\ + ia64\TestZlib$(Configuration)\Tmp\ + true + false + x64\TestZlib$(Configuration)\ + x64\TestZlib$(Configuration)\Tmp\ + false + ia64\TestZlib$(Configuration)\ + ia64\TestZlib$(Configuration)\Tmp\ + false + false + x64\TestZlib$(Configuration)\ + x64\TestZlib$(Configuration)\Tmp\ + false + ia64\TestZlib$(Configuration)\ + ia64\TestZlib$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + AssemblyAndSourceCode + $(IntDir) + Level3 + ProgramDatabase + + + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)testzlib.exe + true + $(OutDir)testzlib.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + Console + true + true + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)testzlib.exe + true + Console + true + true + false + + + MachineX86 + false + + + + + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + Default + MultiThreadedDebugDLL + false + $(IntDir) + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + + + + + Itanium + + + Disabled + ..\..\..;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + AssemblyAndSourceCode + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + $(OutDir)testzlib.pdb + Console + MachineIA64 + + + + + ..\..\..;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + Default + MultiThreadedDLL + false + $(IntDir) + + + %(AdditionalDependencies) + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + Console + true + true + MachineIA64 + + + + + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + Default + MultiThreadedDLL + false + $(IntDir) + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + Console + true + true + MachineIA64 + + + + + + + + + + true + true + true + true + true + true + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc14/testzlibdll.vcxproj b/contrib/zlib/contrib/vstudio/vc14/testzlibdll.vcxproj new file mode 100644 index 00000000..d87474de --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc14/testzlibdll.vcxproj @@ -0,0 +1,316 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {C52F9E7B-498A-42BE-8DB4-85A15694366A} + Win32Proj + + + + Application + MultiByte + v140 + + + Application + Unicode + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\TestZlibDll$(Configuration)\ + x86\TestZlibDll$(Configuration)\Tmp\ + true + false + x86\TestZlibDll$(Configuration)\ + x86\TestZlibDll$(Configuration)\Tmp\ + false + false + x64\TestZlibDll$(Configuration)\ + x64\TestZlibDll$(Configuration)\Tmp\ + true + false + ia64\TestZlibDll$(Configuration)\ + ia64\TestZlibDll$(Configuration)\Tmp\ + true + false + x64\TestZlibDll$(Configuration)\ + x64\TestZlibDll$(Configuration)\Tmp\ + false + false + ia64\TestZlibDll$(Configuration)\ + ia64\TestZlibDll$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + $(OutDir)testzlib.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + Console + true + true + false + + + MachineX86 + + + + + X64 + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + $(OutDir)testzlib.pdb + Console + MachineX64 + + + + + Itanium + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + $(OutDir)testzlib.pdb + Console + MachineIA64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + Console + true + true + MachineX64 + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + Console + true + true + MachineIA64 + + + + + + + + {8fd826f8-3739-44e6-8cc8-997122e53b8d} + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc14/zlib.rc b/contrib/zlib/contrib/vstudio/vc14/zlib.rc new file mode 100644 index 00000000..c4e4b016 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc14/zlib.rc @@ -0,0 +1,32 @@ +#include + +#define IDR_VERSION1 1 +IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE + FILEVERSION 1, 2, 11, 0 + PRODUCTVERSION 1, 2, 11, 0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS 0 + FILEOS VOS_DOS_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0 // not used +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + //language ID = U.S. English, char set = Windows, Multilingual + + BEGIN + VALUE "FileDescription", "zlib data compression and ZIP file I/O library\0" + VALUE "FileVersion", "1.2.11\0" + VALUE "InternalName", "zlib\0" + VALUE "OriginalFilename", "zlibwapi.dll\0" + VALUE "ProductName", "ZLib.DLL\0" + VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0" + VALUE "LegalCopyright", "(C) 1995-2017 Jean-loup Gailly & Mark Adler\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1252 + END +END diff --git a/contrib/zlib/contrib/vstudio/vc14/zlibstat.vcxproj b/contrib/zlib/contrib/vstudio/vc14/zlibstat.vcxproj new file mode 100644 index 00000000..3e4b9863 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc14/zlibstat.vcxproj @@ -0,0 +1,467 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + ReleaseWithoutAsm + Itanium + + + ReleaseWithoutAsm + Win32 + + + ReleaseWithoutAsm + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8} + + + + StaticLibrary + false + v140 + + + StaticLibrary + false + v140 + + + StaticLibrary + false + v140 + Unicode + + + StaticLibrary + false + v140 + + + StaticLibrary + false + v140 + + + StaticLibrary + false + v140 + + + StaticLibrary + false + v140 + + + StaticLibrary + false + v140 + + + StaticLibrary + false + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\ZlibStat$(Configuration)\ + x86\ZlibStat$(Configuration)\Tmp\ + x86\ZlibStat$(Configuration)\ + x86\ZlibStat$(Configuration)\Tmp\ + x86\ZlibStat$(Configuration)\ + x86\ZlibStat$(Configuration)\Tmp\ + x64\ZlibStat$(Configuration)\ + x64\ZlibStat$(Configuration)\Tmp\ + ia64\ZlibStat$(Configuration)\ + ia64\ZlibStat$(Configuration)\Tmp\ + x64\ZlibStat$(Configuration)\ + x64\ZlibStat$(Configuration)\Tmp\ + ia64\ZlibStat$(Configuration)\ + ia64\ZlibStat$(Configuration)\Tmp\ + x64\ZlibStat$(Configuration)\ + x64\ZlibStat$(Configuration)\Tmp\ + ia64\ZlibStat$(Configuration)\ + ia64\ZlibStat$(Configuration)\Tmp\ + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + OldStyle + + + 0x040c + + + /MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions) + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)zlibstat.lib + true + + + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + X64 + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + OldStyle + + + 0x040c + + + /MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + Itanium + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + OldStyle + + + 0x040c + + + /MACHINE:IA64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + X64 + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions) + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + $(OutDir)zlibstat.lib + true + + + + + Itanium + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:IA64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + X64 + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + Itanium + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:IA64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + + + + + + + + + + true + true + true + true + true + true + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc14/zlibvc.def b/contrib/zlib/contrib/vstudio/vc14/zlibvc.def new file mode 100644 index 00000000..f876c3bc --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc14/zlibvc.def @@ -0,0 +1,153 @@ +LIBRARY +; zlib data compression and ZIP file I/O library + +VERSION 1.2 + +EXPORTS + adler32 @1 + compress @2 + crc32 @3 + deflate @4 + deflateCopy @5 + deflateEnd @6 + deflateInit2_ @7 + deflateInit_ @8 + deflateParams @9 + deflateReset @10 + deflateSetDictionary @11 + gzclose @12 + gzdopen @13 + gzerror @14 + gzflush @15 + gzopen @16 + gzread @17 + gzwrite @18 + inflate @19 + inflateEnd @20 + inflateInit2_ @21 + inflateInit_ @22 + inflateReset @23 + inflateSetDictionary @24 + inflateSync @25 + uncompress @26 + zlibVersion @27 + gzprintf @28 + gzputc @29 + gzgetc @30 + gzseek @31 + gzrewind @32 + gztell @33 + gzeof @34 + gzsetparams @35 + zError @36 + inflateSyncPoint @37 + get_crc_table @38 + compress2 @39 + gzputs @40 + gzgets @41 + inflateCopy @42 + inflateBackInit_ @43 + inflateBack @44 + inflateBackEnd @45 + compressBound @46 + deflateBound @47 + gzclearerr @48 + gzungetc @49 + zlibCompileFlags @50 + deflatePrime @51 + deflatePending @52 + + unzOpen @61 + unzClose @62 + unzGetGlobalInfo @63 + unzGetCurrentFileInfo @64 + unzGoToFirstFile @65 + unzGoToNextFile @66 + unzOpenCurrentFile @67 + unzReadCurrentFile @68 + unzOpenCurrentFile3 @69 + unztell @70 + unzeof @71 + unzCloseCurrentFile @72 + unzGetGlobalComment @73 + unzStringFileNameCompare @74 + unzLocateFile @75 + unzGetLocalExtrafield @76 + unzOpen2 @77 + unzOpenCurrentFile2 @78 + unzOpenCurrentFilePassword @79 + + zipOpen @80 + zipOpenNewFileInZip @81 + zipWriteInFileInZip @82 + zipCloseFileInZip @83 + zipClose @84 + zipOpenNewFileInZip2 @86 + zipCloseFileInZipRaw @87 + zipOpen2 @88 + zipOpenNewFileInZip3 @89 + + unzGetFilePos @100 + unzGoToFilePos @101 + + fill_win32_filefunc @110 + +; zlibwapi v1.2.4 added: + fill_win32_filefunc64 @111 + fill_win32_filefunc64A @112 + fill_win32_filefunc64W @113 + + unzOpen64 @120 + unzOpen2_64 @121 + unzGetGlobalInfo64 @122 + unzGetCurrentFileInfo64 @124 + unzGetCurrentFileZStreamPos64 @125 + unztell64 @126 + unzGetFilePos64 @127 + unzGoToFilePos64 @128 + + zipOpen64 @130 + zipOpen2_64 @131 + zipOpenNewFileInZip64 @132 + zipOpenNewFileInZip2_64 @133 + zipOpenNewFileInZip3_64 @134 + zipOpenNewFileInZip4_64 @135 + zipCloseFileInZipRaw64 @136 + +; zlib1 v1.2.4 added: + adler32_combine @140 + crc32_combine @142 + deflateSetHeader @144 + deflateTune @145 + gzbuffer @146 + gzclose_r @147 + gzclose_w @148 + gzdirect @149 + gzoffset @150 + inflateGetHeader @156 + inflateMark @157 + inflatePrime @158 + inflateReset2 @159 + inflateUndermine @160 + +; zlib1 v1.2.6 added: + gzgetc_ @161 + inflateResetKeep @163 + deflateResetKeep @164 + +; zlib1 v1.2.7 added: + gzopen_w @165 + +; zlib1 v1.2.8 added: + inflateGetDictionary @166 + gzvprintf @167 + +; zlib1 v1.2.9 added: + inflateCodesUsed @168 + inflateValidate @169 + uncompress2 @170 + gzfread @171 + gzfwrite @172 + deflateGetDictionary @173 + adler32_z @174 + crc32_z @175 diff --git a/contrib/zlib/contrib/vstudio/vc14/zlibvc.sln b/contrib/zlib/contrib/vstudio/vc14/zlibvc.sln new file mode 100644 index 00000000..6f4a1076 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc14/zlibvc.sln @@ -0,0 +1,119 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibvc", "zlibvc.vcxproj", "{8FD826F8-3739-44E6-8CC8-997122E53B8D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibstat", "zlibstat.vcxproj", "{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testzlib", "testzlib.vcxproj", "{AA6666AA-E09F-4135-9C0C-4FE50C3C654B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testzlibdll", "testzlibdll.vcxproj", "{C52F9E7B-498A-42BE-8DB4-85A15694366A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minizip", "minizip.vcxproj", "{48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniunz", "miniunz.vcxproj", "{C52F9E7B-498A-42BE-8DB4-85A15694382A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Itanium = Debug|Itanium + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Itanium = Release|Itanium + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + ReleaseWithoutAsm|Itanium = ReleaseWithoutAsm|Itanium + ReleaseWithoutAsm|Win32 = ReleaseWithoutAsm|Win32 + ReleaseWithoutAsm|x64 = ReleaseWithoutAsm|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Itanium.ActiveCfg = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.ActiveCfg = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.Build.0 = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|x64.ActiveCfg = Debug|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|x64.Build.0 = Debug|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Itanium.ActiveCfg = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.ActiveCfg = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.Build.0 = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|x64.ActiveCfg = Release|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|x64.Build.0 = Release|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Itanium.ActiveCfg = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.ActiveCfg = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.Build.0 = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|x64.ActiveCfg = Debug|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|x64.Build.0 = Debug|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Itanium.ActiveCfg = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.ActiveCfg = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.Build.0 = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.ActiveCfg = Release|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.Build.0 = Release|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.ActiveCfg = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.ActiveCfg = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.Build.0 = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.ActiveCfg = Debug|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.Build.0 = Debug|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.ActiveCfg = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.ActiveCfg = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.Build.0 = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.ActiveCfg = Release|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.Build.0 = Release|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Itanium.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Win32.Build.0 = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|x64.ActiveCfg = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|x64.Build.0 = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Itanium.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Win32.Build.0 = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|x64.Build.0 = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.ActiveCfg = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.ActiveCfg = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.Build.0 = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.ActiveCfg = Debug|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.Build.0 = Debug|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.Build.0 = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.ActiveCfg = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.Build.0 = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Itanium.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Win32.Build.0 = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|x64.ActiveCfg = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|x64.Build.0 = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Itanium.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Win32.Build.0 = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|x64.Build.0 = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/contrib/zlib/contrib/vstudio/vc14/zlibvc.vcxproj b/contrib/zlib/contrib/vstudio/vc14/zlibvc.vcxproj new file mode 100644 index 00000000..f8f673cb --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc14/zlibvc.vcxproj @@ -0,0 +1,692 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + ReleaseWithoutAsm + Itanium + + + ReleaseWithoutAsm + Win32 + + + ReleaseWithoutAsm + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {8FD826F8-3739-44E6-8CC8-997122E53B8D} + + + + DynamicLibrary + false + true + v140 + + + DynamicLibrary + false + true + v140 + + + DynamicLibrary + false + v140 + Unicode + + + DynamicLibrary + false + true + v140 + + + DynamicLibrary + false + true + v140 + + + DynamicLibrary + false + v140 + + + DynamicLibrary + false + true + v140 + + + DynamicLibrary + false + true + v140 + + + DynamicLibrary + false + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\ZlibDll$(Configuration)\ + x86\ZlibDll$(Configuration)\Tmp\ + true + false + x86\ZlibDll$(Configuration)\ + x86\ZlibDll$(Configuration)\Tmp\ + false + false + x86\ZlibDll$(Configuration)\ + x86\ZlibDll$(Configuration)\Tmp\ + false + false + x64\ZlibDll$(Configuration)\ + x64\ZlibDll$(Configuration)\Tmp\ + true + false + ia64\ZlibDll$(Configuration)\ + ia64\ZlibDll$(Configuration)\Tmp\ + true + false + x64\ZlibDll$(Configuration)\ + x64\ZlibDll$(Configuration)\Tmp\ + false + false + ia64\ZlibDll$(Configuration)\ + ia64\ZlibDll$(Configuration)\Tmp\ + false + false + x64\ZlibDll$(Configuration)\ + x64\ZlibDll$(Configuration)\Tmp\ + false + false + ia64\ZlibDll$(Configuration)\ + ia64\ZlibDll$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + zlibwapi + zlibwapi + zlibwapi + zlibwapi + zlibwapi + zlibwapi + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + $(OutDir)zlibvc.tlb + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibvc.pch + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + /MACHINE:I386 %(AdditionalOptions) + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)zlibwapi.dll + true + .\zlibvc.def + true + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + false + + + $(OutDir)zlibwapi.lib + + + cd ..\..\masmx86 +bld_ml32.bat + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + /MACHINE:I386 %(AdditionalOptions) + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + false + + + $(OutDir)zlibwapi.lib + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + /MACHINE:I386 %(AdditionalOptions) + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + false + + + $(OutDir)zlibwapi.lib + false + + + cd ..\..\masmx86 +bld_ml32.bat + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + X64 + $(OutDir)zlibvc.tlb + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibvc.pch + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + $(OutDir)zlibwapi.dll + true + .\zlibvc.def + true + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineX64 + + + cd ..\..\contrib\masmx64 +bld_ml64.bat + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Itanium + $(OutDir)zlibvc.tlb + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibvc.pch + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + .\zlibvc.def + true + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineIA64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + X64 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Itanium + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineIA64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + X64 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineX64 + + + cd ..\..\masmx64 +bld_ml64.bat + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Itanium + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineIA64 + + + + + + + + + + + + + + true + true + true + true + true + true + + + + + + + + + + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/zlib/contrib/vstudio/vc9/miniunz.vcproj b/contrib/zlib/contrib/vstudio/vc9/miniunz.vcproj new file mode 100644 index 00000000..038a9e5f --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc9/miniunz.vcproj @@ -0,0 +1,565 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/contrib/zlib/contrib/vstudio/vc9/minizip.vcproj b/contrib/zlib/contrib/vstudio/vc9/minizip.vcproj new file mode 100644 index 00000000..ad402399 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc9/minizip.vcproj @@ -0,0 +1,562 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/contrib/zlib/contrib/vstudio/vc9/testzlib.vcproj b/contrib/zlib/contrib/vstudio/vc9/testzlib.vcproj new file mode 100644 index 00000000..c9f19d24 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc9/testzlib.vcproj @@ -0,0 +1,852 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/contrib/zlib/contrib/vstudio/vc9/testzlibdll.vcproj b/contrib/zlib/contrib/vstudio/vc9/testzlibdll.vcproj new file mode 100644 index 00000000..d7530fd7 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc9/testzlibdll.vcproj @@ -0,0 +1,565 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/contrib/zlib/contrib/vstudio/vc9/zlib.rc b/contrib/zlib/contrib/vstudio/vc9/zlib.rc new file mode 100644 index 00000000..c4e4b016 --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc9/zlib.rc @@ -0,0 +1,32 @@ +#include + +#define IDR_VERSION1 1 +IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE + FILEVERSION 1, 2, 11, 0 + PRODUCTVERSION 1, 2, 11, 0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS 0 + FILEOS VOS_DOS_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0 // not used +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + //language ID = U.S. English, char set = Windows, Multilingual + + BEGIN + VALUE "FileDescription", "zlib data compression and ZIP file I/O library\0" + VALUE "FileVersion", "1.2.11\0" + VALUE "InternalName", "zlib\0" + VALUE "OriginalFilename", "zlibwapi.dll\0" + VALUE "ProductName", "ZLib.DLL\0" + VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0" + VALUE "LegalCopyright", "(C) 1995-2017 Jean-loup Gailly & Mark Adler\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1252 + END +END diff --git a/contrib/zlib/contrib/vstudio/vc9/zlibstat.vcproj b/contrib/zlib/contrib/vstudio/vc9/zlibstat.vcproj new file mode 100644 index 00000000..d4ffb46b --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc9/zlibstat.vcproj @@ -0,0 +1,835 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/contrib/zlib/contrib/vstudio/vc9/zlibvc.def b/contrib/zlib/contrib/vstudio/vc9/zlibvc.def new file mode 100644 index 00000000..f876c3bc --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc9/zlibvc.def @@ -0,0 +1,153 @@ +LIBRARY +; zlib data compression and ZIP file I/O library + +VERSION 1.2 + +EXPORTS + adler32 @1 + compress @2 + crc32 @3 + deflate @4 + deflateCopy @5 + deflateEnd @6 + deflateInit2_ @7 + deflateInit_ @8 + deflateParams @9 + deflateReset @10 + deflateSetDictionary @11 + gzclose @12 + gzdopen @13 + gzerror @14 + gzflush @15 + gzopen @16 + gzread @17 + gzwrite @18 + inflate @19 + inflateEnd @20 + inflateInit2_ @21 + inflateInit_ @22 + inflateReset @23 + inflateSetDictionary @24 + inflateSync @25 + uncompress @26 + zlibVersion @27 + gzprintf @28 + gzputc @29 + gzgetc @30 + gzseek @31 + gzrewind @32 + gztell @33 + gzeof @34 + gzsetparams @35 + zError @36 + inflateSyncPoint @37 + get_crc_table @38 + compress2 @39 + gzputs @40 + gzgets @41 + inflateCopy @42 + inflateBackInit_ @43 + inflateBack @44 + inflateBackEnd @45 + compressBound @46 + deflateBound @47 + gzclearerr @48 + gzungetc @49 + zlibCompileFlags @50 + deflatePrime @51 + deflatePending @52 + + unzOpen @61 + unzClose @62 + unzGetGlobalInfo @63 + unzGetCurrentFileInfo @64 + unzGoToFirstFile @65 + unzGoToNextFile @66 + unzOpenCurrentFile @67 + unzReadCurrentFile @68 + unzOpenCurrentFile3 @69 + unztell @70 + unzeof @71 + unzCloseCurrentFile @72 + unzGetGlobalComment @73 + unzStringFileNameCompare @74 + unzLocateFile @75 + unzGetLocalExtrafield @76 + unzOpen2 @77 + unzOpenCurrentFile2 @78 + unzOpenCurrentFilePassword @79 + + zipOpen @80 + zipOpenNewFileInZip @81 + zipWriteInFileInZip @82 + zipCloseFileInZip @83 + zipClose @84 + zipOpenNewFileInZip2 @86 + zipCloseFileInZipRaw @87 + zipOpen2 @88 + zipOpenNewFileInZip3 @89 + + unzGetFilePos @100 + unzGoToFilePos @101 + + fill_win32_filefunc @110 + +; zlibwapi v1.2.4 added: + fill_win32_filefunc64 @111 + fill_win32_filefunc64A @112 + fill_win32_filefunc64W @113 + + unzOpen64 @120 + unzOpen2_64 @121 + unzGetGlobalInfo64 @122 + unzGetCurrentFileInfo64 @124 + unzGetCurrentFileZStreamPos64 @125 + unztell64 @126 + unzGetFilePos64 @127 + unzGoToFilePos64 @128 + + zipOpen64 @130 + zipOpen2_64 @131 + zipOpenNewFileInZip64 @132 + zipOpenNewFileInZip2_64 @133 + zipOpenNewFileInZip3_64 @134 + zipOpenNewFileInZip4_64 @135 + zipCloseFileInZipRaw64 @136 + +; zlib1 v1.2.4 added: + adler32_combine @140 + crc32_combine @142 + deflateSetHeader @144 + deflateTune @145 + gzbuffer @146 + gzclose_r @147 + gzclose_w @148 + gzdirect @149 + gzoffset @150 + inflateGetHeader @156 + inflateMark @157 + inflatePrime @158 + inflateReset2 @159 + inflateUndermine @160 + +; zlib1 v1.2.6 added: + gzgetc_ @161 + inflateResetKeep @163 + deflateResetKeep @164 + +; zlib1 v1.2.7 added: + gzopen_w @165 + +; zlib1 v1.2.8 added: + inflateGetDictionary @166 + gzvprintf @167 + +; zlib1 v1.2.9 added: + inflateCodesUsed @168 + inflateValidate @169 + uncompress2 @170 + gzfread @171 + gzfwrite @172 + deflateGetDictionary @173 + adler32_z @174 + crc32_z @175 diff --git a/contrib/zlib/contrib/vstudio/vc9/zlibvc.sln b/contrib/zlib/contrib/vstudio/vc9/zlibvc.sln new file mode 100644 index 00000000..75c64c3f --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc9/zlibvc.sln @@ -0,0 +1,144 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibvc", "zlibvc.vcproj", "{8FD826F8-3739-44E6-8CC8-997122E53B8D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibstat", "zlibstat.vcproj", "{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testzlib", "testzlib.vcproj", "{AA6666AA-E09F-4135-9C0C-4FE50C3C654B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestZlibDll", "testzlibdll.vcproj", "{C52F9E7B-498A-42BE-8DB4-85A15694366A}" + ProjectSection(ProjectDependencies) = postProject + {8FD826F8-3739-44E6-8CC8-997122E53B8D} = {8FD826F8-3739-44E6-8CC8-997122E53B8D} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minizip", "minizip.vcproj", "{48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}" + ProjectSection(ProjectDependencies) = postProject + {8FD826F8-3739-44E6-8CC8-997122E53B8D} = {8FD826F8-3739-44E6-8CC8-997122E53B8D} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniunz", "miniunz.vcproj", "{C52F9E7B-498A-42BE-8DB4-85A15694382A}" + ProjectSection(ProjectDependencies) = postProject + {8FD826F8-3739-44E6-8CC8-997122E53B8D} = {8FD826F8-3739-44E6-8CC8-997122E53B8D} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Itanium = Debug|Itanium + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Itanium = Release|Itanium + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + ReleaseWithoutAsm|Itanium = ReleaseWithoutAsm|Itanium + ReleaseWithoutAsm|Win32 = ReleaseWithoutAsm|Win32 + ReleaseWithoutAsm|x64 = ReleaseWithoutAsm|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Itanium.ActiveCfg = Debug|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Itanium.Build.0 = Debug|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.ActiveCfg = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.Build.0 = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|x64.ActiveCfg = Debug|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|x64.Build.0 = Debug|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Itanium.ActiveCfg = Release|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Itanium.Build.0 = Release|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.ActiveCfg = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.Build.0 = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|x64.ActiveCfg = Release|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|x64.Build.0 = Release|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Itanium.Build.0 = ReleaseWithoutAsm|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Itanium.ActiveCfg = Debug|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Itanium.Build.0 = Debug|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.ActiveCfg = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.Build.0 = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|x64.ActiveCfg = Debug|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|x64.Build.0 = Debug|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Itanium.ActiveCfg = Release|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Itanium.Build.0 = Release|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.ActiveCfg = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.Build.0 = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.ActiveCfg = Release|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.Build.0 = Release|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Itanium.Build.0 = ReleaseWithoutAsm|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.ActiveCfg = Debug|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.Build.0 = Debug|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.ActiveCfg = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.Build.0 = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.ActiveCfg = Debug|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.Build.0 = Debug|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.ActiveCfg = Release|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.Build.0 = Release|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.ActiveCfg = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.Build.0 = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.ActiveCfg = Release|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.Build.0 = Release|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.Build.0 = ReleaseWithoutAsm|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Itanium.ActiveCfg = Debug|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Itanium.Build.0 = Debug|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Win32.Build.0 = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|x64.ActiveCfg = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|x64.Build.0 = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Itanium.ActiveCfg = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Itanium.Build.0 = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Win32.Build.0 = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|x64.Build.0 = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Itanium.Build.0 = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.ActiveCfg = Debug|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.Build.0 = Debug|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.ActiveCfg = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.Build.0 = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.ActiveCfg = Debug|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.Build.0 = Debug|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.ActiveCfg = Release|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.Build.0 = Release|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.Build.0 = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.ActiveCfg = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.Build.0 = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.Build.0 = Release|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Itanium.ActiveCfg = Debug|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Itanium.Build.0 = Debug|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Win32.Build.0 = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|x64.ActiveCfg = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|x64.Build.0 = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Itanium.ActiveCfg = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Itanium.Build.0 = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Win32.Build.0 = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|x64.Build.0 = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Itanium.Build.0 = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/contrib/zlib/contrib/vstudio/vc9/zlibvc.vcproj b/contrib/zlib/contrib/vstudio/vc9/zlibvc.vcproj new file mode 100644 index 00000000..95bb241f --- /dev/null +++ b/contrib/zlib/contrib/vstudio/vc9/zlibvc.vcproj @@ -0,0 +1,1156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/contrib/zlib/crc32.c b/contrib/zlib/crc32.c new file mode 100644 index 00000000..9580440c --- /dev/null +++ b/contrib/zlib/crc32.c @@ -0,0 +1,442 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2006, 2010, 2011, 2012, 2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id$ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + + DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h. + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +/* Definitions for doing the crc four data bytes at a time. */ +#if !defined(NOBYFOUR) && defined(Z_U4) +# define BYFOUR +#endif +#ifdef BYFOUR + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, z_size_t)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, z_size_t)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +/* Local functions for crc concatenation */ +local unsigned long gf2_matrix_times OF((unsigned long *mat, + unsigned long vec)); +local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); +local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2)); + + +#ifdef DYNAMIC_CRC_TABLE + +local volatile int crc_table_empty = 1; +local z_crc_t FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const z_crc_t FAR *)); +#endif /* MAKECRCH */ +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + z_crc_t c; + int n, k; + z_crc_t poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static volatile int first = 1; /* flag to limit concurrent making */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* See if another task is already doing this (not thread-safe, but better + than nothing -- significantly reduces duration of vulnerability in + case the advice about DYNAMIC_CRC_TABLE is ignored) */ + if (first) { + first = 0; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0; + for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++) + poly |= (z_crc_t)1 << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (z_crc_t)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, + and then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = ZSWAP32(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = ZSWAP32(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + } + else { /* not first */ + /* wait for the other guy to finish (not efficient, but rare) */ + while (crc_table_empty) + ; + } + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const z_crc_t FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const z_crc_t FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", + (unsigned long)(table[n]), + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const z_crc_t FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const z_crc_t FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32_z(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + z_size_t len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + z_crc_t endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + uInt len; +{ + return crc32_z(crc, buf, len); +} + +#ifdef BYFOUR + +/* + This BYFOUR code accesses the passed unsigned char * buffer with a 32-bit + integer pointer type. This violates the strict aliasing rule, where a + compiler can assume, for optimization purposes, that two pointers to + fundamentally different types won't ever point to the same memory. This can + manifest as a problem only if one of the pointers is written to. This code + only reads from those pointers. So long as this code remains isolated in + this compilation unit, there won't be a problem. For this reason, this code + should not be copied and pasted into a compilation unit in which other code + writes to the buffer that is passed to these routines. + */ + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + z_size_t len; +{ + register z_crc_t c; + register const z_crc_t FAR *buf4; + + c = (z_crc_t)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const z_crc_t FAR *)(const void FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *buf4++; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + z_size_t len; +{ + register z_crc_t c; + register const z_crc_t FAR *buf4; + + c = ZSWAP32((z_crc_t)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const z_crc_t FAR *)(const void FAR *)buf; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(ZSWAP32(c)); +} + +#endif /* BYFOUR */ + +#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ + +/* ========================================================================= */ +local unsigned long gf2_matrix_times(mat, vec) + unsigned long *mat; + unsigned long vec; +{ + unsigned long sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* ========================================================================= */ +local void gf2_matrix_square(square, mat) + unsigned long *square; + unsigned long *mat; +{ + int n; + + for (n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* ========================================================================= */ +local uLong crc32_combine_(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off64_t len2; +{ + int n; + unsigned long row; + unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ + unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case (also disallow negative lengths) */ + if (len2 <= 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320UL; /* CRC-32 polynomial */ + row = 1; + for (n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(even, odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(odd, even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + do { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(even, odd); + if (len2 & 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + if (len2 == 0) + break; + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(odd, even); + if (len2 & 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_t len2; +{ + return crc32_combine_(crc1, crc2, len2); +} + +uLong ZEXPORT crc32_combine64(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off64_t len2; +{ + return crc32_combine_(crc1, crc2, len2); +} diff --git a/contrib/zlib/crc32.h b/contrib/zlib/crc32.h new file mode 100644 index 00000000..9e0c7781 --- /dev/null +++ b/contrib/zlib/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const z_crc_t FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/contrib/zlib/deflate.c b/contrib/zlib/deflate.c new file mode 100644 index 00000000..1ec76144 --- /dev/null +++ b/contrib/zlib/deflate.c @@ -0,0 +1,2163 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://tools.ietf.org/html/rfc1951 + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id$ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.11 Copyright 1995-2017 Jean-loup Gailly and Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local int deflateStateCheck OF((z_streamp strm)); +local void slide_hash OF((deflate_state *s)); +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local block_state deflate_rle OF((deflate_state *s, int flush)); +local block_state deflate_huff OF((deflate_state *s, int flush)); +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local unsigned read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifdef ASMV +# pragma message("Assembler code may have bugs -- use at your own risk") + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif + +#ifdef ZLIB_DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */ +#define RANK(f) (((f) * 2) - ((f) > 4 ? 9 : 0)) + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to UPDATE_HASH are made with consecutive input + * characters, so that a running hash key can be computed from the previous + * key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to INSERT_STRING are made with consecutive input + * characters and the first MIN_MATCH bytes of str are valid (except for + * the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* =========================================================================== + * Slide the hash table when sliding the window down (could be avoided with 32 + * bit values at the expense of memory usage). We slide even when level == 0 to + * keep the hash table consistent if we switch back to level > 0 later. + */ +local void slide_hash(s) + deflate_state *s; +{ + unsigned n, m; + Posf *p; + uInt wsize = s->w_size; + + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m - wsize : NIL); + } while (--n); + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m - wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif +} + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED || (windowBits == 8 && wrap != 1)) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + s->status = INIT_STATE; /* to pass state test in deflateReset() */ + + s->wrap = wrap; + s->gzhead = Z_NULL; + s->w_bits = (uInt)windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = (uInt)memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->high_water = 0; /* nothing written to s->window yet */ + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= + * Check for a valid deflate stream state. Return 0 if ok, 1 if not. + */ +local int deflateStateCheck (strm) + z_streamp strm; +{ + deflate_state *s; + if (strm == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) + return 1; + s = strm->state; + if (s == Z_NULL || s->strm != strm || (s->status != INIT_STATE && +#ifdef GZIP + s->status != GZIP_STATE && +#endif + s->status != EXTRA_STATE && + s->status != NAME_STATE && + s->status != COMMENT_STATE && + s->status != HCRC_STATE && + s->status != BUSY_STATE && + s->status != FINISH_STATE)) + return 1; + return 0; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt str, n; + int wrap; + unsigned avail; + z_const unsigned char *next; + + if (deflateStateCheck(strm) || dictionary == Z_NULL) + return Z_STREAM_ERROR; + s = strm->state; + wrap = s->wrap; + if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead) + return Z_STREAM_ERROR; + + /* when using zlib wrappers, compute Adler-32 for provided dictionary */ + if (wrap == 1) + strm->adler = adler32(strm->adler, dictionary, dictLength); + s->wrap = 0; /* avoid computing Adler-32 in read_buf */ + + /* if dictionary would fill window, just replace the history */ + if (dictLength >= s->w_size) { + if (wrap == 0) { /* already empty otherwise */ + CLEAR_HASH(s); + s->strstart = 0; + s->block_start = 0L; + s->insert = 0; + } + dictionary += dictLength - s->w_size; /* use the tail */ + dictLength = s->w_size; + } + + /* insert dictionary into window and hash */ + avail = strm->avail_in; + next = strm->next_in; + strm->avail_in = dictLength; + strm->next_in = (z_const Bytef *)dictionary; + fill_window(s); + while (s->lookahead >= MIN_MATCH) { + str = s->strstart; + n = s->lookahead - (MIN_MATCH-1); + do { + UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); +#ifndef FASTEST + s->prev[str & s->w_mask] = s->head[s->ins_h]; +#endif + s->head[s->ins_h] = (Pos)str; + str++; + } while (--n); + s->strstart = str; + s->lookahead = MIN_MATCH-1; + fill_window(s); + } + s->strstart += s->lookahead; + s->block_start = (long)s->strstart; + s->insert = s->lookahead; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + strm->next_in = next; + strm->avail_in = avail; + s->wrap = wrap; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength) + z_streamp strm; + Bytef *dictionary; + uInt *dictLength; +{ + deflate_state *s; + uInt len; + + if (deflateStateCheck(strm)) + return Z_STREAM_ERROR; + s = strm->state; + len = s->strstart + s->lookahead; + if (len > s->w_size) + len = s->w_size; + if (dictionary != Z_NULL && len) + zmemcpy(dictionary, s->window + s->strstart + s->lookahead - len, len); + if (dictLength != Z_NULL) + *dictLength = len; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateResetKeep (strm) + z_streamp strm; +{ + deflate_state *s; + + if (deflateStateCheck(strm)) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = +#ifdef GZIP + s->wrap == 2 ? GZIP_STATE : +#endif + s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + int ret; + + ret = deflateResetKeep(strm); + if (ret == Z_OK) + lm_init(strm->state); + return ret; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetHeader (strm, head) + z_streamp strm; + gz_headerp head; +{ + if (deflateStateCheck(strm) || strm->state->wrap != 2) + return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePending (strm, pending, bits) + unsigned *pending; + int *bits; + z_streamp strm; +{ + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + if (pending != Z_NULL) + *pending = strm->state->pending; + if (bits != Z_NULL) + *bits = strm->state->bi_valid; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + deflate_state *s; + int put; + + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + s = strm->state; + if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3)) + return Z_BUF_ERROR; + do { + put = Buf_size - s->bi_valid; + if (put > bits) + put = bits; + s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid); + s->bi_valid += put; + _tr_flush_bits(s); + value >>= put; + bits -= put; + } while (bits); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if ((strategy != s->strategy || func != configuration_table[level].func) && + s->high_water) { + /* Flush the last buffer: */ + int err = deflate(strm, Z_BLOCK); + if (err == Z_STREAM_ERROR) + return err; + if (strm->avail_out == 0) + return Z_BUF_ERROR; + } + if (s->level != level) { + if (s->level == 0 && s->matches != 0) { + if (s->matches == 1) + slide_hash(s); + else + CLEAR_HASH(s); + s->matches = 0; + } + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) + z_streamp strm; + int good_length; + int max_lazy; + int nice_length; + int max_chain; +{ + deflate_state *s; + + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = (uInt)good_length; + s->max_lazy_match = (uInt)max_lazy; + s->nice_match = nice_length; + s->max_chain_length = (uInt)max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds for + * every combination of windowBits and memLevel. But even the conservative + * upper bound of about 14% expansion does not seem onerous for output buffer + * allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong complen, wraplen; + + /* conservative upper bound for compressed data */ + complen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; + + /* if can't get parameters, return conservative bound plus zlib wrapper */ + if (deflateStateCheck(strm)) + return complen + 6; + + /* compute wrapper length */ + s = strm->state; + switch (s->wrap) { + case 0: /* raw deflate */ + wraplen = 0; + break; + case 1: /* zlib wrapper */ + wraplen = 6 + (s->strstart ? 4 : 0); + break; +#ifdef GZIP + case 2: /* gzip wrapper */ + wraplen = 18; + if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ + Bytef *str; + if (s->gzhead->extra != Z_NULL) + wraplen += 2 + s->gzhead->extra_len; + str = s->gzhead->name; + if (str != Z_NULL) + do { + wraplen++; + } while (*str++); + str = s->gzhead->comment; + if (str != Z_NULL) + do { + wraplen++; + } while (*str++); + if (s->gzhead->hcrc) + wraplen += 2; + } + break; +#endif + default: /* for compiler happiness */ + wraplen = 6; + } + + /* if not default parameters, return conservative bound */ + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return complen + wraplen; + + /* default settings: return tight bound for that case */ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + + (sourceLen >> 25) + 13 - 6 + wraplen; +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output, except for + * some deflate_stored() output, goes through this function so some + * applications may wish to modify it to avoid allocating a large + * strm->next_out buffer and copying into it. (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len; + deflate_state *s = strm->state; + + _tr_flush_bits(s); + len = s->pending; + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, s->pending_out, len); + strm->next_out += len; + s->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + s->pending -= len; + if (s->pending == 0) { + s->pending_out = s->pending_buf; + } +} + +/* =========================================================================== + * Update the header CRC with the bytes s->pending_buf[beg..s->pending - 1]. + */ +#define HCRC_UPDATE(beg) \ + do { \ + if (s->gzhead->hcrc && s->pending > (beg)) \ + strm->adler = crc32(strm->adler, s->pending_buf + (beg), \ + s->pending - (beg)); \ + } while (0) + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->avail_in != 0 && strm->next_in == Z_NULL) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + old_flush = s->last_flush; + s->last_flush = flush; + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Write the header */ + if (s->status == INIT_STATE) { + /* zlib header */ + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } +#ifdef GZIP + if (s->status == GZIP_STATE) { + /* gzip header */ + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == Z_NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != Z_NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != Z_NULL) { + ulg beg = s->pending; /* start of bytes to update crc */ + uInt left = (s->gzhead->extra_len & 0xffff) - s->gzindex; + while (s->pending + left > s->pending_buf_size) { + uInt copy = s->pending_buf_size - s->pending; + zmemcpy(s->pending_buf + s->pending, + s->gzhead->extra + s->gzindex, copy); + s->pending = s->pending_buf_size; + HCRC_UPDATE(beg); + s->gzindex += copy; + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + beg = 0; + left -= copy; + } + zmemcpy(s->pending_buf + s->pending, + s->gzhead->extra + s->gzindex, left); + s->pending += left; + HCRC_UPDATE(beg); + s->gzindex = 0; + } + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != Z_NULL) { + ulg beg = s->pending; /* start of bytes to update crc */ + int val; + do { + if (s->pending == s->pending_buf_size) { + HCRC_UPDATE(beg); + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + beg = 0; + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + HCRC_UPDATE(beg); + s->gzindex = 0; + } + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != Z_NULL) { + ulg beg = s->pending; /* start of bytes to update crc */ + int val; + do { + if (s->pending == s->pending_buf_size) { + HCRC_UPDATE(beg); + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + beg = 0; + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + HCRC_UPDATE(beg); + } + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) { + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + } + s->status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } +#endif + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = s->level == 0 ? deflate_stored(s, flush) : + s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : + s->strategy == Z_RLE ? deflate_rle(s, flush) : + (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + if (s->lookahead == 0) { + s->strstart = 0; + s->block_start = 0L; + s->insert = 0; + } + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + + status = strm->state->status; + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (deflateStateCheck(source) || dest == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local unsigned read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + zmemcpy(buf, strm->next_in, len); + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, buf, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, buf, len); + } +#endif + strm->next_in += len; + strm->total_in += len; + + return len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->insert = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifndef FASTEST +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = (int)s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ + +#else /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for FASTEST only + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#endif /* FASTEST */ + +#ifdef ZLIB_DEBUG + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* ZLIB_DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + unsigned n; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize - more); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + slide_hash(s); + more += wsize; + } + if (s->strm->avail_in == 0) break; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead + s->insert >= MIN_MATCH) { + uInt str = s->strstart - s->insert; + s->ins_h = s->window[str]; + UPDATE_HASH(s, s->ins_h, s->window[str + 1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + while (s->insert) { + UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); +#ifndef FASTEST + s->prev[str & s->w_mask] = s->head[s->ins_h]; +#endif + s->head[s->ins_h] = (Pos)str; + str++; + s->insert--; + if (s->lookahead + s->insert < MIN_MATCH) + break; + } + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); + + /* If the WIN_INIT bytes after the end of the current data have never been + * written, then zero those bytes in order to avoid memory check reports of + * the use of uninitialized (or uninitialised as Julian writes) bytes by + * the longest match routines. Update the high water mark for the next + * time through here. WIN_INIT is set to MAX_MATCH since the longest match + * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. + */ + if (s->high_water < s->window_size) { + ulg curr = s->strstart + (ulg)(s->lookahead); + ulg init; + + if (s->high_water < curr) { + /* Previous high water mark below current data -- zero WIN_INIT + * bytes or up to end of window, whichever is less. + */ + init = s->window_size - curr; + if (init > WIN_INIT) + init = WIN_INIT; + zmemzero(s->window + curr, (unsigned)init); + s->high_water = curr + init; + } + else if (s->high_water < (ulg)curr + WIN_INIT) { + /* High water mark at or above current data, but below current data + * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up + * to end of window, whichever is less. + */ + init = (ulg)curr + WIN_INIT - s->high_water; + if (init > s->window_size - s->high_water) + init = s->window_size - s->high_water; + zmemzero(s->window + s->high_water, (unsigned)init); + s->high_water += init; + } + } + + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "not enough room for search"); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, last) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (last)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, last) { \ + FLUSH_BLOCK_ONLY(s, last); \ + if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ +} + +/* Maximum stored block length in deflate format (not including header). */ +#define MAX_STORED 65535 + +/* Minimum of a and b. */ +#define MIN(a, b) ((a) > (b) ? (b) : (a)) + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * + * In case deflateParams() is used to later switch to a non-zero compression + * level, s->matches (otherwise unused when storing) keeps track of the number + * of hash table slides to perform. If s->matches is 1, then one hash table + * slide will be done when switching. If s->matches is 2, the maximum value + * allowed here, then the hash table will be cleared, since two or more slides + * is the same as a clear. + * + * deflate_stored() is written to minimize the number of times an input byte is + * copied. It is most efficient with large input and output buffers, which + * maximizes the opportunites to have a single copy from next_in to next_out. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Smallest worthy block size when not flushing or finishing. By default + * this is 32K. This can be as small as 507 bytes for memLevel == 1. For + * large input and output buffers, the stored block size will be larger. + */ + unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size); + + /* Copy as many min_block or larger stored blocks directly to next_out as + * possible. If flushing, copy the remaining available input to next_out as + * stored blocks, if there is enough space. + */ + unsigned len, left, have, last = 0; + unsigned used = s->strm->avail_in; + do { + /* Set len to the maximum size block that we can copy directly with the + * available input data and output space. Set left to how much of that + * would be copied from what's left in the window. + */ + len = MAX_STORED; /* maximum deflate stored block length */ + have = (s->bi_valid + 42) >> 3; /* number of header bytes */ + if (s->strm->avail_out < have) /* need room for header */ + break; + /* maximum stored block length that will fit in avail_out: */ + have = s->strm->avail_out - have; + left = s->strstart - s->block_start; /* bytes left in window */ + if (len > (ulg)left + s->strm->avail_in) + len = left + s->strm->avail_in; /* limit len to the input */ + if (len > have) + len = have; /* limit len to the output */ + + /* If the stored block would be less than min_block in length, or if + * unable to copy all of the available input when flushing, then try + * copying to the window and the pending buffer instead. Also don't + * write an empty block when flushing -- deflate() does that. + */ + if (len < min_block && ((len == 0 && flush != Z_FINISH) || + flush == Z_NO_FLUSH || + len != left + s->strm->avail_in)) + break; + + /* Make a dummy stored block in pending to get the header bytes, + * including any pending bits. This also updates the debugging counts. + */ + last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0; + _tr_stored_block(s, (char *)0, 0L, last); + + /* Replace the lengths in the dummy stored block with len. */ + s->pending_buf[s->pending - 4] = len; + s->pending_buf[s->pending - 3] = len >> 8; + s->pending_buf[s->pending - 2] = ~len; + s->pending_buf[s->pending - 1] = ~len >> 8; + + /* Write the stored block header bytes. */ + flush_pending(s->strm); + +#ifdef ZLIB_DEBUG + /* Update debugging counts for the data about to be copied. */ + s->compressed_len += len << 3; + s->bits_sent += len << 3; +#endif + + /* Copy uncompressed bytes from the window to next_out. */ + if (left) { + if (left > len) + left = len; + zmemcpy(s->strm->next_out, s->window + s->block_start, left); + s->strm->next_out += left; + s->strm->avail_out -= left; + s->strm->total_out += left; + s->block_start += left; + len -= left; + } + + /* Copy uncompressed bytes directly from next_in to next_out, updating + * the check value. + */ + if (len) { + read_buf(s->strm, s->strm->next_out, len); + s->strm->next_out += len; + s->strm->avail_out -= len; + s->strm->total_out += len; + } + } while (last == 0); + + /* Update the sliding window with the last s->w_size bytes of the copied + * data, or append all of the copied data to the existing window if less + * than s->w_size bytes were copied. Also update the number of bytes to + * insert in the hash tables, in the event that deflateParams() switches to + * a non-zero compression level. + */ + used -= s->strm->avail_in; /* number of input bytes directly copied */ + if (used) { + /* If any input was used, then no unused input remains in the window, + * therefore s->block_start == s->strstart. + */ + if (used >= s->w_size) { /* supplant the previous history */ + s->matches = 2; /* clear hash */ + zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size); + s->strstart = s->w_size; + } + else { + if (s->window_size - s->strstart <= used) { + /* Slide the window down. */ + s->strstart -= s->w_size; + zmemcpy(s->window, s->window + s->w_size, s->strstart); + if (s->matches < 2) + s->matches++; /* add a pending slide_hash() */ + } + zmemcpy(s->window + s->strstart, s->strm->next_in - used, used); + s->strstart += used; + } + s->block_start = s->strstart; + s->insert += MIN(used, s->w_size - s->insert); + } + if (s->high_water < s->strstart) + s->high_water = s->strstart; + + /* If the last block was written to next_out, then done. */ + if (last) + return finish_done; + + /* If flushing and all input has been consumed, then done. */ + if (flush != Z_NO_FLUSH && flush != Z_FINISH && + s->strm->avail_in == 0 && (long)s->strstart == s->block_start) + return block_done; + + /* Fill the window with any remaining input. */ + have = s->window_size - s->strstart - 1; + if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) { + /* Slide the window down. */ + s->block_start -= s->w_size; + s->strstart -= s->w_size; + zmemcpy(s->window, s->window + s->w_size, s->strstart); + if (s->matches < 2) + s->matches++; /* add a pending slide_hash() */ + have += s->w_size; /* more space now */ + } + if (have > s->strm->avail_in) + have = s->strm->avail_in; + if (have) { + read_buf(s->strm, s->window + s->strstart, have); + s->strstart += have; + } + if (s->high_water < s->strstart) + s->high_water = s->strstart; + + /* There was not enough avail_out to write a complete worthy or flushed + * stored block to next_out. Write a stored block to pending instead, if we + * have enough input for a worthy block, or if flushing and there is enough + * room for the remaining input as a stored block in the pending buffer. + */ + have = (s->bi_valid + 42) >> 3; /* number of header bytes */ + /* maximum stored block length that will fit in pending: */ + have = MIN(s->pending_buf_size - have, MAX_STORED); + min_block = MIN(have, s->w_size); + left = s->strstart - s->block_start; + if (left >= min_block || + ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH && + s->strm->avail_in == 0 && left <= have)) { + len = MIN(left, have); + last = flush == Z_FINISH && s->strm->avail_in == 0 && + len == left ? 1 : 0; + _tr_stored_block(s, (charf *)s->window + s->block_start, len, last); + s->block_start += len; + flush_pending(s->strm); + } + + /* We've done all we can with the available input and output. */ + return last ? finish_started : need_more; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = NIL; + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s->match_length = longest_match (s, hash_head); + /* longest_match() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->last_lit) + FLUSH_BLOCK(s, 0); + return block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = NIL; + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s->match_length = longest_match (s, hash_head); + /* longest_match() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->last_lit) + FLUSH_BLOCK(s, 0); + return block_done; +} +#endif /* FASTEST */ + +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + uInt prev; /* byte at distance one to match */ + Bytef *scan, *strend; /* scan goes up to strend for length of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest run, plus one for the unrolled loop. + */ + if (s->lookahead <= MAX_MATCH) { + fill_window(s); + if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + s->match_length = 0; + if (s->lookahead >= MIN_MATCH && s->strstart > 0) { + scan = s->window + s->strstart - 1; + prev = *scan; + if (prev == *++scan && prev == *++scan && prev == *++scan) { + strend = s->window + s->strstart + MAX_MATCH; + do { + } while (prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + scan < strend); + s->match_length = MAX_MATCH - (uInt)(strend - scan); + if (s->match_length > s->lookahead) + s->match_length = s->lookahead; + } + Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, s->match_length); + + _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + s->strstart += s->match_length; + s->match_length = 0; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->last_lit) + FLUSH_BLOCK(s, 0); + return block_done; +} + +/* =========================================================================== + * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. + * (It will be regenerated if this run of deflate switches away from Huffman.) + */ +local block_state deflate_huff(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we have a literal to write. */ + if (s->lookahead == 0) { + fill_window(s); + if (s->lookahead == 0) { + if (flush == Z_NO_FLUSH) + return need_more; + break; /* flush the current block */ + } + } + + /* Output a literal byte */ + s->match_length = 0; + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + if (bflush) FLUSH_BLOCK(s, 0); + } + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->last_lit) + FLUSH_BLOCK(s, 0); + return block_done; +} diff --git a/contrib/zlib/deflate.h b/contrib/zlib/deflate.h new file mode 100644 index 00000000..23ecdd31 --- /dev/null +++ b/contrib/zlib/deflate.h @@ -0,0 +1,349 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2016 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define Buf_size 16 +/* size of bit buffer in bi_buf */ + +#define INIT_STATE 42 /* zlib header -> BUSY_STATE */ +#ifdef GZIP +# define GZIP_STATE 57 /* gzip header -> BUSY_STATE | EXTRA_STATE */ +#endif +#define EXTRA_STATE 69 /* gzip extra block -> NAME_STATE */ +#define NAME_STATE 73 /* gzip file name -> COMMENT_STATE */ +#define COMMENT_STATE 91 /* gzip comment -> HCRC_STATE */ +#define HCRC_STATE 103 /* gzip header CRC -> BUSY_STATE */ +#define BUSY_STATE 113 /* deflate -> FINISH_STATE */ +#define FINISH_STATE 666 /* stream complete */ +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + const static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + ulg pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + ulg gzindex; /* where in extra, name, or comment */ + Byte method; /* can only be DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to suppress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + uInt insert; /* bytes at end of window left to insert */ + +#ifdef ZLIB_DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + + ulg high_water; + /* High water mark offset in window for initialized bytes -- bytes above + * this are set to zero in order to avoid memory check warnings when + * longest match routines access bytes past the input. This is then + * updated to the new high water mark. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (Bytef)(c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + +#define WIN_INIT MAX_MATCH +/* Number of bytes after end of data in window to initialize in order to avoid + memory checker errors from longest match routines */ + + /* in trees.c */ +void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); +int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, + ulg stored_len, int last)); +void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s)); +void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); +void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, + ulg stored_len, int last)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef ZLIB_DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch ZLIB_INTERNAL _length_code[]; + extern uch ZLIB_INTERNAL _dist_code[]; +#else + extern const uch ZLIB_INTERNAL _length_code[]; + extern const uch ZLIB_INTERNAL _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (uch)(length); \ + ush dist = (ush)(distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/contrib/zlib/doc/algorithm.txt b/contrib/zlib/doc/algorithm.txt new file mode 100644 index 00000000..c97f4950 --- /dev/null +++ b/contrib/zlib/doc/algorithm.txt @@ -0,0 +1,209 @@ +1. Compression algorithm (deflate) + +The deflation algorithm used by gzip (also zip and zlib) is a variation of +LZ77 (Lempel-Ziv 1977, see reference below). It finds duplicated strings in +the input data. The second occurrence of a string is replaced by a +pointer to the previous string, in the form of a pair (distance, +length). Distances are limited to 32K bytes, and lengths are limited +to 258 bytes. When a string does not occur anywhere in the previous +32K bytes, it is emitted as a sequence of literal bytes. (In this +description, `string' must be taken as an arbitrary sequence of bytes, +and is not restricted to printable characters.) + +Literals or match lengths are compressed with one Huffman tree, and +match distances are compressed with another tree. The trees are stored +in a compact form at the start of each block. The blocks can have any +size (except that the compressed data for one block must fit in +available memory). A block is terminated when deflate() determines that +it would be useful to start another block with fresh trees. (This is +somewhat similar to the behavior of LZW-based _compress_.) + +Duplicated strings are found using a hash table. All input strings of +length 3 are inserted in the hash table. A hash index is computed for +the next 3 bytes. If the hash chain for this index is not empty, all +strings in the chain are compared with the current input string, and +the longest match is selected. + +The hash chains are searched starting with the most recent strings, to +favor small distances and thus take advantage of the Huffman encoding. +The hash chains are singly linked. There are no deletions from the +hash chains, the algorithm simply discards matches that are too old. + +To avoid a worst-case situation, very long hash chains are arbitrarily +truncated at a certain length, determined by a runtime option (level +parameter of deflateInit). So deflate() does not always find the longest +possible match but generally finds a match which is long enough. + +deflate() also defers the selection of matches with a lazy evaluation +mechanism. After a match of length N has been found, deflate() searches for +a longer match at the next input byte. If a longer match is found, the +previous match is truncated to a length of one (thus producing a single +literal byte) and the process of lazy evaluation begins again. Otherwise, +the original match is kept, and the next match search is attempted only N +steps later. + +The lazy match evaluation is also subject to a runtime parameter. If +the current match is long enough, deflate() reduces the search for a longer +match, thus speeding up the whole process. If compression ratio is more +important than speed, deflate() attempts a complete second search even if +the first match is already long enough. + +The lazy match evaluation is not performed for the fastest compression +modes (level parameter 1 to 3). For these fast modes, new strings +are inserted in the hash table only when no match was found, or +when the match is not too long. This degrades the compression ratio +but saves time since there are both fewer insertions and fewer searches. + + +2. Decompression algorithm (inflate) + +2.1 Introduction + +The key question is how to represent a Huffman code (or any prefix code) so +that you can decode fast. The most important characteristic is that shorter +codes are much more common than longer codes, so pay attention to decoding the +short codes fast, and let the long codes take longer to decode. + +inflate() sets up a first level table that covers some number of bits of +input less than the length of longest code. It gets that many bits from the +stream, and looks it up in the table. The table will tell if the next +code is that many bits or less and how many, and if it is, it will tell +the value, else it will point to the next level table for which inflate() +grabs more bits and tries to decode a longer code. + +How many bits to make the first lookup is a tradeoff between the time it +takes to decode and the time it takes to build the table. If building the +table took no time (and if you had infinite memory), then there would only +be a first level table to cover all the way to the longest code. However, +building the table ends up taking a lot longer for more bits since short +codes are replicated many times in such a table. What inflate() does is +simply to make the number of bits in the first table a variable, and then +to set that variable for the maximum speed. + +For inflate, which has 286 possible codes for the literal/length tree, the size +of the first table is nine bits. Also the distance trees have 30 possible +values, and the size of the first table is six bits. Note that for each of +those cases, the table ended up one bit longer than the ``average'' code +length, i.e. the code length of an approximately flat code which would be a +little more than eight bits for 286 symbols and a little less than five bits +for 30 symbols. + + +2.2 More details on the inflate table lookup + +Ok, you want to know what this cleverly obfuscated inflate tree actually +looks like. You are correct that it's not a Huffman tree. It is simply a +lookup table for the first, let's say, nine bits of a Huffman symbol. The +symbol could be as short as one bit or as long as 15 bits. If a particular +symbol is shorter than nine bits, then that symbol's translation is duplicated +in all those entries that start with that symbol's bits. For example, if the +symbol is four bits, then it's duplicated 32 times in a nine-bit table. If a +symbol is nine bits long, it appears in the table once. + +If the symbol is longer than nine bits, then that entry in the table points +to another similar table for the remaining bits. Again, there are duplicated +entries as needed. The idea is that most of the time the symbol will be short +and there will only be one table look up. (That's whole idea behind data +compression in the first place.) For the less frequent long symbols, there +will be two lookups. If you had a compression method with really long +symbols, you could have as many levels of lookups as is efficient. For +inflate, two is enough. + +So a table entry either points to another table (in which case nine bits in +the above example are gobbled), or it contains the translation for the symbol +and the number of bits to gobble. Then you start again with the next +ungobbled bit. + +You may wonder: why not just have one lookup table for how ever many bits the +longest symbol is? The reason is that if you do that, you end up spending +more time filling in duplicate symbol entries than you do actually decoding. +At least for deflate's output that generates new trees every several 10's of +kbytes. You can imagine that filling in a 2^15 entry table for a 15-bit code +would take too long if you're only decoding several thousand symbols. At the +other extreme, you could make a new table for every bit in the code. In fact, +that's essentially a Huffman tree. But then you spend too much time +traversing the tree while decoding, even for short symbols. + +So the number of bits for the first lookup table is a trade of the time to +fill out the table vs. the time spent looking at the second level and above of +the table. + +Here is an example, scaled down: + +The code being decoded, with 10 symbols, from 1 to 6 bits long: + +A: 0 +B: 10 +C: 1100 +D: 11010 +E: 11011 +F: 11100 +G: 11101 +H: 11110 +I: 111110 +J: 111111 + +Let's make the first table three bits long (eight entries): + +000: A,1 +001: A,1 +010: A,1 +011: A,1 +100: B,2 +101: B,2 +110: -> table X (gobble 3 bits) +111: -> table Y (gobble 3 bits) + +Each entry is what the bits decode as and how many bits that is, i.e. how +many bits to gobble. Or the entry points to another table, with the number of +bits to gobble implicit in the size of the table. + +Table X is two bits long since the longest code starting with 110 is five bits +long: + +00: C,1 +01: C,1 +10: D,2 +11: E,2 + +Table Y is three bits long since the longest code starting with 111 is six +bits long: + +000: F,2 +001: F,2 +010: G,2 +011: G,2 +100: H,2 +101: H,2 +110: I,3 +111: J,3 + +So what we have here are three tables with a total of 20 entries that had to +be constructed. That's compared to 64 entries for a single table. Or +compared to 16 entries for a Huffman tree (six two entry tables and one four +entry table). Assuming that the code ideally represents the probability of +the symbols, it takes on the average 1.25 lookups per symbol. That's compared +to one lookup for the single table, or 1.66 lookups per symbol for the +Huffman tree. + +There, I think that gives you a picture of what's going on. For inflate, the +meaning of a particular symbol is often more than just a letter. It can be a +byte (a "literal"), or it can be either a length or a distance which +indicates a base value and a number of bits to fetch after the code that is +added to the base value. Or it might be the special end-of-block code. The +data structures created in inftrees.c try to encode all that information +compactly in the tables. + + +Jean-loup Gailly Mark Adler +jloup@gzip.org madler@alumni.caltech.edu + + +References: + +[LZ77] Ziv J., Lempel A., ``A Universal Algorithm for Sequential Data +Compression,'' IEEE Transactions on Information Theory, Vol. 23, No. 3, +pp. 337-343. + +``DEFLATE Compressed Data Format Specification'' available in +http://tools.ietf.org/html/rfc1951 diff --git a/contrib/zlib/doc/rfc1950.txt b/contrib/zlib/doc/rfc1950.txt new file mode 100644 index 00000000..ce6428a0 --- /dev/null +++ b/contrib/zlib/doc/rfc1950.txt @@ -0,0 +1,619 @@ + + + + + + +Network Working Group P. Deutsch +Request for Comments: 1950 Aladdin Enterprises +Category: Informational J-L. Gailly + Info-ZIP + May 1996 + + + ZLIB Compressed Data Format Specification version 3.3 + +Status of This Memo + + This memo provides information for the Internet community. This memo + does not specify an Internet standard of any kind. Distribution of + this memo is unlimited. + +IESG Note: + + The IESG takes no position on the validity of any Intellectual + Property Rights statements contained in this document. + +Notices + + Copyright (c) 1996 L. Peter Deutsch and Jean-Loup Gailly + + Permission is granted to copy and distribute this document for any + purpose and without charge, including translations into other + languages and incorporation into compilations, provided that the + copyright notice and this notice are preserved, and that any + substantive changes or deletions from the original are clearly + marked. + + A pointer to the latest version of this and related documentation in + HTML format can be found at the URL + . + +Abstract + + This specification defines a lossless compressed data format. The + data can be produced or consumed, even for an arbitrarily long + sequentially presented input data stream, using only an a priori + bounded amount of intermediate storage. The format presently uses + the DEFLATE compression method but can be easily extended to use + other compression methods. It can be implemented readily in a manner + not covered by patents. This specification also defines the ADLER-32 + checksum (an extension and improvement of the Fletcher checksum), + used for detection of data corruption, and provides an algorithm for + computing it. + + + + +Deutsch & Gailly Informational [Page 1] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + +Table of Contents + + 1. Introduction ................................................... 2 + 1.1. Purpose ................................................... 2 + 1.2. Intended audience ......................................... 3 + 1.3. Scope ..................................................... 3 + 1.4. Compliance ................................................ 3 + 1.5. Definitions of terms and conventions used ................ 3 + 1.6. Changes from previous versions ............................ 3 + 2. Detailed specification ......................................... 3 + 2.1. Overall conventions ....................................... 3 + 2.2. Data format ............................................... 4 + 2.3. Compliance ................................................ 7 + 3. References ..................................................... 7 + 4. Source code .................................................... 8 + 5. Security Considerations ........................................ 8 + 6. Acknowledgements ............................................... 8 + 7. Authors' Addresses ............................................. 8 + 8. Appendix: Rationale ............................................ 9 + 9. Appendix: Sample code ..........................................10 + +1. Introduction + + 1.1. Purpose + + The purpose of this specification is to define a lossless + compressed data format that: + + * Is independent of CPU type, operating system, file system, + and character set, and hence can be used for interchange; + + * Can be produced or consumed, even for an arbitrarily long + sequentially presented input data stream, using only an a + priori bounded amount of intermediate storage, and hence can + be used in data communications or similar structures such as + Unix filters; + + * Can use a number of different compression methods; + + * Can be implemented readily in a manner not covered by + patents, and hence can be practiced freely. + + The data format defined by this specification does not attempt to + allow random access to compressed data. + + + + + + + +Deutsch & Gailly Informational [Page 2] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + + 1.2. Intended audience + + This specification is intended for use by implementors of software + to compress data into zlib format and/or decompress data from zlib + format. + + The text of the specification assumes a basic background in + programming at the level of bits and other primitive data + representations. + + 1.3. Scope + + The specification specifies a compressed data format that can be + used for in-memory compression of a sequence of arbitrary bytes. + + 1.4. Compliance + + Unless otherwise indicated below, a compliant decompressor must be + able to accept and decompress any data set that conforms to all + the specifications presented here; a compliant compressor must + produce data sets that conform to all the specifications presented + here. + + 1.5. Definitions of terms and conventions used + + byte: 8 bits stored or transmitted as a unit (same as an octet). + (For this specification, a byte is exactly 8 bits, even on + machines which store a character on a number of bits different + from 8.) See below, for the numbering of bits within a byte. + + 1.6. Changes from previous versions + + Version 3.1 was the first public release of this specification. + In version 3.2, some terminology was changed and the Adler-32 + sample code was rewritten for clarity. In version 3.3, the + support for a preset dictionary was introduced, and the + specification was converted to RFC style. + +2. Detailed specification + + 2.1. Overall conventions + + In the diagrams below, a box like this: + + +---+ + | | <-- the vertical bars might be missing + +---+ + + + + +Deutsch & Gailly Informational [Page 3] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + + represents one byte; a box like this: + + +==============+ + | | + +==============+ + + represents a variable number of bytes. + + Bytes stored within a computer do not have a "bit order", since + they are always treated as a unit. However, a byte considered as + an integer between 0 and 255 does have a most- and least- + significant bit, and since we write numbers with the most- + significant digit on the left, we also write bytes with the most- + significant bit on the left. In the diagrams below, we number the + bits of a byte so that bit 0 is the least-significant bit, i.e., + the bits are numbered: + + +--------+ + |76543210| + +--------+ + + Within a computer, a number may occupy multiple bytes. All + multi-byte numbers in the format described here are stored with + the MOST-significant byte first (at the lower memory address). + For example, the decimal number 520 is stored as: + + 0 1 + +--------+--------+ + |00000010|00001000| + +--------+--------+ + ^ ^ + | | + | + less significant byte = 8 + + more significant byte = 2 x 256 + + 2.2. Data format + + A zlib stream has the following structure: + + 0 1 + +---+---+ + |CMF|FLG| (more-->) + +---+---+ + + + + + + + + +Deutsch & Gailly Informational [Page 4] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + + (if FLG.FDICT set) + + 0 1 2 3 + +---+---+---+---+ + | DICTID | (more-->) + +---+---+---+---+ + + +=====================+---+---+---+---+ + |...compressed data...| ADLER32 | + +=====================+---+---+---+---+ + + Any data which may appear after ADLER32 are not part of the zlib + stream. + + CMF (Compression Method and flags) + This byte is divided into a 4-bit compression method and a 4- + bit information field depending on the compression method. + + bits 0 to 3 CM Compression method + bits 4 to 7 CINFO Compression info + + CM (Compression method) + This identifies the compression method used in the file. CM = 8 + denotes the "deflate" compression method with a window size up + to 32K. This is the method used by gzip and PNG (see + references [1] and [2] in Chapter 3, below, for the reference + documents). CM = 15 is reserved. It might be used in a future + version of this specification to indicate the presence of an + extra field before the compressed data. + + CINFO (Compression info) + For CM = 8, CINFO is the base-2 logarithm of the LZ77 window + size, minus eight (CINFO=7 indicates a 32K window size). Values + of CINFO above 7 are not allowed in this version of the + specification. CINFO is not defined in this specification for + CM not equal to 8. + + FLG (FLaGs) + This flag byte is divided as follows: + + bits 0 to 4 FCHECK (check bits for CMF and FLG) + bit 5 FDICT (preset dictionary) + bits 6 to 7 FLEVEL (compression level) + + The FCHECK value must be such that CMF and FLG, when viewed as + a 16-bit unsigned integer stored in MSB order (CMF*256 + FLG), + is a multiple of 31. + + + + +Deutsch & Gailly Informational [Page 5] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + + FDICT (Preset dictionary) + If FDICT is set, a DICT dictionary identifier is present + immediately after the FLG byte. The dictionary is a sequence of + bytes which are initially fed to the compressor without + producing any compressed output. DICT is the Adler-32 checksum + of this sequence of bytes (see the definition of ADLER32 + below). The decompressor can use this identifier to determine + which dictionary has been used by the compressor. + + FLEVEL (Compression level) + These flags are available for use by specific compression + methods. The "deflate" method (CM = 8) sets these flags as + follows: + + 0 - compressor used fastest algorithm + 1 - compressor used fast algorithm + 2 - compressor used default algorithm + 3 - compressor used maximum compression, slowest algorithm + + The information in FLEVEL is not needed for decompression; it + is there to indicate if recompression might be worthwhile. + + compressed data + For compression method 8, the compressed data is stored in the + deflate compressed data format as described in the document + "DEFLATE Compressed Data Format Specification" by L. Peter + Deutsch. (See reference [3] in Chapter 3, below) + + Other compressed data formats are not specified in this version + of the zlib specification. + + ADLER32 (Adler-32 checksum) + This contains a checksum value of the uncompressed data + (excluding any dictionary data) computed according to Adler-32 + algorithm. This algorithm is a 32-bit extension and improvement + of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073 + standard. See references [4] and [5] in Chapter 3, below) + + Adler-32 is composed of two sums accumulated per byte: s1 is + the sum of all bytes, s2 is the sum of all s1 values. Both sums + are done modulo 65521. s1 is initialized to 1, s2 to zero. The + Adler-32 checksum is stored as s2*65536 + s1 in most- + significant-byte first (network) order. + + + + + + + + +Deutsch & Gailly Informational [Page 6] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + + 2.3. Compliance + + A compliant compressor must produce streams with correct CMF, FLG + and ADLER32, but need not support preset dictionaries. When the + zlib data format is used as part of another standard data format, + the compressor may use only preset dictionaries that are specified + by this other data format. If this other format does not use the + preset dictionary feature, the compressor must not set the FDICT + flag. + + A compliant decompressor must check CMF, FLG, and ADLER32, and + provide an error indication if any of these have incorrect values. + A compliant decompressor must give an error indication if CM is + not one of the values defined in this specification (only the + value 8 is permitted in this version), since another value could + indicate the presence of new features that would cause subsequent + data to be interpreted incorrectly. A compliant decompressor must + give an error indication if FDICT is set and DICTID is not the + identifier of a known preset dictionary. A decompressor may + ignore FLEVEL and still be compliant. When the zlib data format + is being used as a part of another standard format, a compliant + decompressor must support all the preset dictionaries specified by + the other format. When the other format does not use the preset + dictionary feature, a compliant decompressor must reject any + stream in which the FDICT flag is set. + +3. References + + [1] Deutsch, L.P.,"GZIP Compressed Data Format Specification", + available in ftp://ftp.uu.net/pub/archiving/zip/doc/ + + [2] Thomas Boutell, "PNG (Portable Network Graphics) specification", + available in ftp://ftp.uu.net/graphics/png/documents/ + + [3] Deutsch, L.P.,"DEFLATE Compressed Data Format Specification", + available in ftp://ftp.uu.net/pub/archiving/zip/doc/ + + [4] Fletcher, J. G., "An Arithmetic Checksum for Serial + Transmissions," IEEE Transactions on Communications, Vol. COM-30, + No. 1, January 1982, pp. 247-252. + + [5] ITU-T Recommendation X.224, Annex D, "Checksum Algorithms," + November, 1993, pp. 144, 145. (Available from + gopher://info.itu.ch). ITU-T X.244 is also the same as ISO 8073. + + + + + + + +Deutsch & Gailly Informational [Page 7] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + +4. Source code + + Source code for a C language implementation of a "zlib" compliant + library is available at ftp://ftp.uu.net/pub/archiving/zip/zlib/. + +5. Security Considerations + + A decoder that fails to check the ADLER32 checksum value may be + subject to undetected data corruption. + +6. Acknowledgements + + Trademarks cited in this document are the property of their + respective owners. + + Jean-Loup Gailly and Mark Adler designed the zlib format and wrote + the related software described in this specification. Glenn + Randers-Pehrson converted this document to RFC and HTML format. + +7. Authors' Addresses + + L. Peter Deutsch + Aladdin Enterprises + 203 Santa Margarita Ave. + Menlo Park, CA 94025 + + Phone: (415) 322-0103 (AM only) + FAX: (415) 322-1734 + EMail: + + + Jean-Loup Gailly + + EMail: + + Questions about the technical content of this specification can be + sent by email to + + Jean-Loup Gailly and + Mark Adler + + Editorial comments on this specification can be sent by email to + + L. Peter Deutsch and + Glenn Randers-Pehrson + + + + + + +Deutsch & Gailly Informational [Page 8] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + +8. Appendix: Rationale + + 8.1. Preset dictionaries + + A preset dictionary is specially useful to compress short input + sequences. The compressor can take advantage of the dictionary + context to encode the input in a more compact manner. The + decompressor can be initialized with the appropriate context by + virtually decompressing a compressed version of the dictionary + without producing any output. However for certain compression + algorithms such as the deflate algorithm this operation can be + achieved without actually performing any decompression. + + The compressor and the decompressor must use exactly the same + dictionary. The dictionary may be fixed or may be chosen among a + certain number of predefined dictionaries, according to the kind + of input data. The decompressor can determine which dictionary has + been chosen by the compressor by checking the dictionary + identifier. This document does not specify the contents of + predefined dictionaries, since the optimal dictionaries are + application specific. Standard data formats using this feature of + the zlib specification must precisely define the allowed + dictionaries. + + 8.2. The Adler-32 algorithm + + The Adler-32 algorithm is much faster than the CRC32 algorithm yet + still provides an extremely low probability of undetected errors. + + The modulo on unsigned long accumulators can be delayed for 5552 + bytes, so the modulo operation time is negligible. If the bytes + are a, b, c, the second sum is 3a + 2b + c + 3, and so is position + and order sensitive, unlike the first sum, which is just a + checksum. That 65521 is prime is important to avoid a possible + large class of two-byte errors that leave the check unchanged. + (The Fletcher checksum uses 255, which is not prime and which also + makes the Fletcher check insensitive to single byte changes 0 <-> + 255.) + + The sum s1 is initialized to 1 instead of zero to make the length + of the sequence part of s2, so that the length does not have to be + checked separately. (Any sequence of zeroes has a Fletcher + checksum of zero.) + + + + + + + + +Deutsch & Gailly Informational [Page 9] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + +9. Appendix: Sample code + + The following C code computes the Adler-32 checksum of a data buffer. + It is written for clarity, not for speed. The sample code is in the + ANSI C programming language. Non C users may find it easier to read + with these hints: + + & Bitwise AND operator. + >> Bitwise right shift operator. When applied to an + unsigned quantity, as here, right shift inserts zero bit(s) + at the left. + << Bitwise left shift operator. Left shift inserts zero + bit(s) at the right. + ++ "n++" increments the variable n. + % modulo operator: a % b is the remainder of a divided by b. + + #define BASE 65521 /* largest prime smaller than 65536 */ + + /* + Update a running Adler-32 checksum with the bytes buf[0..len-1] + and return the updated checksum. The Adler-32 checksum should be + initialized to 1. + + Usage example: + + unsigned long adler = 1L; + + while (read_buffer(buffer, length) != EOF) { + adler = update_adler32(adler, buffer, length); + } + if (adler != original_adler) error(); + */ + unsigned long update_adler32(unsigned long adler, + unsigned char *buf, int len) + { + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int n; + + for (n = 0; n < len; n++) { + s1 = (s1 + buf[n]) % BASE; + s2 = (s2 + s1) % BASE; + } + return (s2 << 16) + s1; + } + + /* Return the adler32 of the bytes buf[0..len-1] */ + + + + +Deutsch & Gailly Informational [Page 10] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + + unsigned long adler32(unsigned char *buf, int len) + { + return update_adler32(1L, buf, len); + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Deutsch & Gailly Informational [Page 11] + diff --git a/contrib/zlib/doc/rfc1951.txt b/contrib/zlib/doc/rfc1951.txt new file mode 100644 index 00000000..403c8c72 --- /dev/null +++ b/contrib/zlib/doc/rfc1951.txt @@ -0,0 +1,955 @@ + + + + + + +Network Working Group P. Deutsch +Request for Comments: 1951 Aladdin Enterprises +Category: Informational May 1996 + + + DEFLATE Compressed Data Format Specification version 1.3 + +Status of This Memo + + This memo provides information for the Internet community. This memo + does not specify an Internet standard of any kind. Distribution of + this memo is unlimited. + +IESG Note: + + The IESG takes no position on the validity of any Intellectual + Property Rights statements contained in this document. + +Notices + + Copyright (c) 1996 L. Peter Deutsch + + Permission is granted to copy and distribute this document for any + purpose and without charge, including translations into other + languages and incorporation into compilations, provided that the + copyright notice and this notice are preserved, and that any + substantive changes or deletions from the original are clearly + marked. + + A pointer to the latest version of this and related documentation in + HTML format can be found at the URL + . + +Abstract + + This specification defines a lossless compressed data format that + compresses data using a combination of the LZ77 algorithm and Huffman + coding, with efficiency comparable to the best currently available + general-purpose compression methods. The data can be produced or + consumed, even for an arbitrarily long sequentially presented input + data stream, using only an a priori bounded amount of intermediate + storage. The format can be implemented readily in a manner not + covered by patents. + + + + + + + + +Deutsch Informational [Page 1] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + +Table of Contents + + 1. Introduction ................................................... 2 + 1.1. Purpose ................................................... 2 + 1.2. Intended audience ......................................... 3 + 1.3. Scope ..................................................... 3 + 1.4. Compliance ................................................ 3 + 1.5. Definitions of terms and conventions used ................ 3 + 1.6. Changes from previous versions ............................ 4 + 2. Compressed representation overview ............................. 4 + 3. Detailed specification ......................................... 5 + 3.1. Overall conventions ....................................... 5 + 3.1.1. Packing into bytes .................................. 5 + 3.2. Compressed block format ................................... 6 + 3.2.1. Synopsis of prefix and Huffman coding ............... 6 + 3.2.2. Use of Huffman coding in the "deflate" format ....... 7 + 3.2.3. Details of block format ............................. 9 + 3.2.4. Non-compressed blocks (BTYPE=00) ................... 11 + 3.2.5. Compressed blocks (length and distance codes) ...... 11 + 3.2.6. Compression with fixed Huffman codes (BTYPE=01) .... 12 + 3.2.7. Compression with dynamic Huffman codes (BTYPE=10) .. 13 + 3.3. Compliance ............................................... 14 + 4. Compression algorithm details ................................. 14 + 5. References .................................................... 16 + 6. Security Considerations ....................................... 16 + 7. Source code ................................................... 16 + 8. Acknowledgements .............................................. 16 + 9. Author's Address .............................................. 17 + +1. Introduction + + 1.1. Purpose + + The purpose of this specification is to define a lossless + compressed data format that: + * Is independent of CPU type, operating system, file system, + and character set, and hence can be used for interchange; + * Can be produced or consumed, even for an arbitrarily long + sequentially presented input data stream, using only an a + priori bounded amount of intermediate storage, and hence + can be used in data communications or similar structures + such as Unix filters; + * Compresses data with efficiency comparable to the best + currently available general-purpose compression methods, + and in particular considerably better than the "compress" + program; + * Can be implemented readily in a manner not covered by + patents, and hence can be practiced freely; + + + +Deutsch Informational [Page 2] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + * Is compatible with the file format produced by the current + widely used gzip utility, in that conforming decompressors + will be able to read data produced by the existing gzip + compressor. + + The data format defined by this specification does not attempt to: + + * Allow random access to compressed data; + * Compress specialized data (e.g., raster graphics) as well + as the best currently available specialized algorithms. + + A simple counting argument shows that no lossless compression + algorithm can compress every possible input data set. For the + format defined here, the worst case expansion is 5 bytes per 32K- + byte block, i.e., a size increase of 0.015% for large data sets. + English text usually compresses by a factor of 2.5 to 3; + executable files usually compress somewhat less; graphical data + such as raster images may compress much more. + + 1.2. Intended audience + + This specification is intended for use by implementors of software + to compress data into "deflate" format and/or decompress data from + "deflate" format. + + The text of the specification assumes a basic background in + programming at the level of bits and other primitive data + representations. Familiarity with the technique of Huffman coding + is helpful but not required. + + 1.3. Scope + + The specification specifies a method for representing a sequence + of bytes as a (usually shorter) sequence of bits, and a method for + packing the latter bit sequence into bytes. + + 1.4. Compliance + + Unless otherwise indicated below, a compliant decompressor must be + able to accept and decompress any data set that conforms to all + the specifications presented here; a compliant compressor must + produce data sets that conform to all the specifications presented + here. + + 1.5. Definitions of terms and conventions used + + Byte: 8 bits stored or transmitted as a unit (same as an octet). + For this specification, a byte is exactly 8 bits, even on machines + + + +Deutsch Informational [Page 3] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + which store a character on a number of bits different from eight. + See below, for the numbering of bits within a byte. + + String: a sequence of arbitrary bytes. + + 1.6. Changes from previous versions + + There have been no technical changes to the deflate format since + version 1.1 of this specification. In version 1.2, some + terminology was changed. Version 1.3 is a conversion of the + specification to RFC style. + +2. Compressed representation overview + + A compressed data set consists of a series of blocks, corresponding + to successive blocks of input data. The block sizes are arbitrary, + except that non-compressible blocks are limited to 65,535 bytes. + + Each block is compressed using a combination of the LZ77 algorithm + and Huffman coding. The Huffman trees for each block are independent + of those for previous or subsequent blocks; the LZ77 algorithm may + use a reference to a duplicated string occurring in a previous block, + up to 32K input bytes before. + + Each block consists of two parts: a pair of Huffman code trees that + describe the representation of the compressed data part, and a + compressed data part. (The Huffman trees themselves are compressed + using Huffman encoding.) The compressed data consists of a series of + elements of two types: literal bytes (of strings that have not been + detected as duplicated within the previous 32K input bytes), and + pointers to duplicated strings, where a pointer is represented as a + pair . The representation used in the + "deflate" format limits distances to 32K bytes and lengths to 258 + bytes, but does not limit the size of a block, except for + uncompressible blocks, which are limited as noted above. + + Each type of value (literals, distances, and lengths) in the + compressed data is represented using a Huffman code, using one code + tree for literals and lengths and a separate code tree for distances. + The code trees for each block appear in a compact form just before + the compressed data for that block. + + + + + + + + + + +Deutsch Informational [Page 4] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + +3. Detailed specification + + 3.1. Overall conventions In the diagrams below, a box like this: + + +---+ + | | <-- the vertical bars might be missing + +---+ + + represents one byte; a box like this: + + +==============+ + | | + +==============+ + + represents a variable number of bytes. + + Bytes stored within a computer do not have a "bit order", since + they are always treated as a unit. However, a byte considered as + an integer between 0 and 255 does have a most- and least- + significant bit, and since we write numbers with the most- + significant digit on the left, we also write bytes with the most- + significant bit on the left. In the diagrams below, we number the + bits of a byte so that bit 0 is the least-significant bit, i.e., + the bits are numbered: + + +--------+ + |76543210| + +--------+ + + Within a computer, a number may occupy multiple bytes. All + multi-byte numbers in the format described here are stored with + the least-significant byte first (at the lower memory address). + For example, the decimal number 520 is stored as: + + 0 1 + +--------+--------+ + |00001000|00000010| + +--------+--------+ + ^ ^ + | | + | + more significant byte = 2 x 256 + + less significant byte = 8 + + 3.1.1. Packing into bytes + + This document does not address the issue of the order in which + bits of a byte are transmitted on a bit-sequential medium, + since the final data format described here is byte- rather than + + + +Deutsch Informational [Page 5] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + bit-oriented. However, we describe the compressed block format + in below, as a sequence of data elements of various bit + lengths, not a sequence of bytes. We must therefore specify + how to pack these data elements into bytes to form the final + compressed byte sequence: + + * Data elements are packed into bytes in order of + increasing bit number within the byte, i.e., starting + with the least-significant bit of the byte. + * Data elements other than Huffman codes are packed + starting with the least-significant bit of the data + element. + * Huffman codes are packed starting with the most- + significant bit of the code. + + In other words, if one were to print out the compressed data as + a sequence of bytes, starting with the first byte at the + *right* margin and proceeding to the *left*, with the most- + significant bit of each byte on the left as usual, one would be + able to parse the result from right to left, with fixed-width + elements in the correct MSB-to-LSB order and Huffman codes in + bit-reversed order (i.e., with the first bit of the code in the + relative LSB position). + + 3.2. Compressed block format + + 3.2.1. Synopsis of prefix and Huffman coding + + Prefix coding represents symbols from an a priori known + alphabet by bit sequences (codes), one code for each symbol, in + a manner such that different symbols may be represented by bit + sequences of different lengths, but a parser can always parse + an encoded string unambiguously symbol-by-symbol. + + We define a prefix code in terms of a binary tree in which the + two edges descending from each non-leaf node are labeled 0 and + 1 and in which the leaf nodes correspond one-for-one with (are + labeled with) the symbols of the alphabet; then the code for a + symbol is the sequence of 0's and 1's on the edges leading from + the root to the leaf labeled with that symbol. For example: + + + + + + + + + + + +Deutsch Informational [Page 6] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + /\ Symbol Code + 0 1 ------ ---- + / \ A 00 + /\ B B 1 + 0 1 C 011 + / \ D 010 + A /\ + 0 1 + / \ + D C + + A parser can decode the next symbol from an encoded input + stream by walking down the tree from the root, at each step + choosing the edge corresponding to the next input bit. + + Given an alphabet with known symbol frequencies, the Huffman + algorithm allows the construction of an optimal prefix code + (one which represents strings with those symbol frequencies + using the fewest bits of any possible prefix codes for that + alphabet). Such a code is called a Huffman code. (See + reference [1] in Chapter 5, references for additional + information on Huffman codes.) + + Note that in the "deflate" format, the Huffman codes for the + various alphabets must not exceed certain maximum code lengths. + This constraint complicates the algorithm for computing code + lengths from symbol frequencies. Again, see Chapter 5, + references for details. + + 3.2.2. Use of Huffman coding in the "deflate" format + + The Huffman codes used for each alphabet in the "deflate" + format have two additional rules: + + * All codes of a given bit length have lexicographically + consecutive values, in the same order as the symbols + they represent; + + * Shorter codes lexicographically precede longer codes. + + + + + + + + + + + + +Deutsch Informational [Page 7] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + We could recode the example above to follow this rule as + follows, assuming that the order of the alphabet is ABCD: + + Symbol Code + ------ ---- + A 10 + B 0 + C 110 + D 111 + + I.e., 0 precedes 10 which precedes 11x, and 110 and 111 are + lexicographically consecutive. + + Given this rule, we can define the Huffman code for an alphabet + just by giving the bit lengths of the codes for each symbol of + the alphabet in order; this is sufficient to determine the + actual codes. In our example, the code is completely defined + by the sequence of bit lengths (2, 1, 3, 3). The following + algorithm generates the codes as integers, intended to be read + from most- to least-significant bit. The code lengths are + initially in tree[I].Len; the codes are produced in + tree[I].Code. + + 1) Count the number of codes for each code length. Let + bl_count[N] be the number of codes of length N, N >= 1. + + 2) Find the numerical value of the smallest code for each + code length: + + code = 0; + bl_count[0] = 0; + for (bits = 1; bits <= MAX_BITS; bits++) { + code = (code + bl_count[bits-1]) << 1; + next_code[bits] = code; + } + + 3) Assign numerical values to all codes, using consecutive + values for all codes of the same length with the base + values determined at step 2. Codes that are never used + (which have a bit length of zero) must not be assigned a + value. + + for (n = 0; n <= max_code; n++) { + len = tree[n].Len; + if (len != 0) { + tree[n].Code = next_code[len]; + next_code[len]++; + } + + + +Deutsch Informational [Page 8] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + } + + Example: + + Consider the alphabet ABCDEFGH, with bit lengths (3, 3, 3, 3, + 3, 2, 4, 4). After step 1, we have: + + N bl_count[N] + - ----------- + 2 1 + 3 5 + 4 2 + + Step 2 computes the following next_code values: + + N next_code[N] + - ------------ + 1 0 + 2 0 + 3 2 + 4 14 + + Step 3 produces the following code values: + + Symbol Length Code + ------ ------ ---- + A 3 010 + B 3 011 + C 3 100 + D 3 101 + E 3 110 + F 2 00 + G 4 1110 + H 4 1111 + + 3.2.3. Details of block format + + Each block of compressed data begins with 3 header bits + containing the following data: + + first bit BFINAL + next 2 bits BTYPE + + Note that the header bits do not necessarily begin on a byte + boundary, since a block does not necessarily occupy an integral + number of bytes. + + + + + +Deutsch Informational [Page 9] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + BFINAL is set if and only if this is the last block of the data + set. + + BTYPE specifies how the data are compressed, as follows: + + 00 - no compression + 01 - compressed with fixed Huffman codes + 10 - compressed with dynamic Huffman codes + 11 - reserved (error) + + The only difference between the two compressed cases is how the + Huffman codes for the literal/length and distance alphabets are + defined. + + In all cases, the decoding algorithm for the actual data is as + follows: + + do + read block header from input stream. + if stored with no compression + skip any remaining bits in current partially + processed byte + read LEN and NLEN (see next section) + copy LEN bytes of data to output + otherwise + if compressed with dynamic Huffman codes + read representation of code trees (see + subsection below) + loop (until end of block code recognized) + decode literal/length value from input stream + if value < 256 + copy value (literal byte) to output stream + otherwise + if value = end of block (256) + break from loop + otherwise (value = 257..285) + decode distance from input stream + + move backwards distance bytes in the output + stream, and copy length bytes from this + position to the output stream. + end loop + while not last block + + Note that a duplicated string reference may refer to a string + in a previous block; i.e., the backward distance may cross one + or more block boundaries. However a distance cannot refer past + the beginning of the output stream. (An application using a + + + +Deutsch Informational [Page 10] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + preset dictionary might discard part of the output stream; a + distance can refer to that part of the output stream anyway) + Note also that the referenced string may overlap the current + position; for example, if the last 2 bytes decoded have values + X and Y, a string reference with + adds X,Y,X,Y,X to the output stream. + + We now specify each compression method in turn. + + 3.2.4. Non-compressed blocks (BTYPE=00) + + Any bits of input up to the next byte boundary are ignored. + The rest of the block consists of the following information: + + 0 1 2 3 4... + +---+---+---+---+================================+ + | LEN | NLEN |... LEN bytes of literal data...| + +---+---+---+---+================================+ + + LEN is the number of data bytes in the block. NLEN is the + one's complement of LEN. + + 3.2.5. Compressed blocks (length and distance codes) + + As noted above, encoded data blocks in the "deflate" format + consist of sequences of symbols drawn from three conceptually + distinct alphabets: either literal bytes, from the alphabet of + byte values (0..255), or pairs, + where the length is drawn from (3..258) and the distance is + drawn from (1..32,768). In fact, the literal and length + alphabets are merged into a single alphabet (0..285), where + values 0..255 represent literal bytes, the value 256 indicates + end-of-block, and values 257..285 represent length codes + (possibly in conjunction with extra bits following the symbol + code) as follows: + + + + + + + + + + + + + + + + +Deutsch Informational [Page 11] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + Extra Extra Extra + Code Bits Length(s) Code Bits Lengths Code Bits Length(s) + ---- ---- ------ ---- ---- ------- ---- ---- ------- + 257 0 3 267 1 15,16 277 4 67-82 + 258 0 4 268 1 17,18 278 4 83-98 + 259 0 5 269 2 19-22 279 4 99-114 + 260 0 6 270 2 23-26 280 4 115-130 + 261 0 7 271 2 27-30 281 5 131-162 + 262 0 8 272 2 31-34 282 5 163-194 + 263 0 9 273 3 35-42 283 5 195-226 + 264 0 10 274 3 43-50 284 5 227-257 + 265 1 11,12 275 3 51-58 285 0 258 + 266 1 13,14 276 3 59-66 + + The extra bits should be interpreted as a machine integer + stored with the most-significant bit first, e.g., bits 1110 + represent the value 14. + + Extra Extra Extra + Code Bits Dist Code Bits Dist Code Bits Distance + ---- ---- ---- ---- ---- ------ ---- ---- -------- + 0 0 1 10 4 33-48 20 9 1025-1536 + 1 0 2 11 4 49-64 21 9 1537-2048 + 2 0 3 12 5 65-96 22 10 2049-3072 + 3 0 4 13 5 97-128 23 10 3073-4096 + 4 1 5,6 14 6 129-192 24 11 4097-6144 + 5 1 7,8 15 6 193-256 25 11 6145-8192 + 6 2 9-12 16 7 257-384 26 12 8193-12288 + 7 2 13-16 17 7 385-512 27 12 12289-16384 + 8 3 17-24 18 8 513-768 28 13 16385-24576 + 9 3 25-32 19 8 769-1024 29 13 24577-32768 + + 3.2.6. Compression with fixed Huffman codes (BTYPE=01) + + The Huffman codes for the two alphabets are fixed, and are not + represented explicitly in the data. The Huffman code lengths + for the literal/length alphabet are: + + Lit Value Bits Codes + --------- ---- ----- + 0 - 143 8 00110000 through + 10111111 + 144 - 255 9 110010000 through + 111111111 + 256 - 279 7 0000000 through + 0010111 + 280 - 287 8 11000000 through + 11000111 + + + +Deutsch Informational [Page 12] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + The code lengths are sufficient to generate the actual codes, + as described above; we show the codes in the table for added + clarity. Literal/length values 286-287 will never actually + occur in the compressed data, but participate in the code + construction. + + Distance codes 0-31 are represented by (fixed-length) 5-bit + codes, with possible additional bits as shown in the table + shown in Paragraph 3.2.5, above. Note that distance codes 30- + 31 will never actually occur in the compressed data. + + 3.2.7. Compression with dynamic Huffman codes (BTYPE=10) + + The Huffman codes for the two alphabets appear in the block + immediately after the header bits and before the actual + compressed data, first the literal/length code and then the + distance code. Each code is defined by a sequence of code + lengths, as discussed in Paragraph 3.2.2, above. For even + greater compactness, the code length sequences themselves are + compressed using a Huffman code. The alphabet for code lengths + is as follows: + + 0 - 15: Represent code lengths of 0 - 15 + 16: Copy the previous code length 3 - 6 times. + The next 2 bits indicate repeat length + (0 = 3, ... , 3 = 6) + Example: Codes 8, 16 (+2 bits 11), + 16 (+2 bits 10) will expand to + 12 code lengths of 8 (1 + 6 + 5) + 17: Repeat a code length of 0 for 3 - 10 times. + (3 bits of length) + 18: Repeat a code length of 0 for 11 - 138 times + (7 bits of length) + + A code length of 0 indicates that the corresponding symbol in + the literal/length or distance alphabet will not occur in the + block, and should not participate in the Huffman code + construction algorithm given earlier. If only one distance + code is used, it is encoded using one bit, not zero bits; in + this case there is a single code length of one, with one unused + code. One distance code of zero bits means that there are no + distance codes used at all (the data is all literals). + + We can now define the format of the block: + + 5 Bits: HLIT, # of Literal/Length codes - 257 (257 - 286) + 5 Bits: HDIST, # of Distance codes - 1 (1 - 32) + 4 Bits: HCLEN, # of Code Length codes - 4 (4 - 19) + + + +Deutsch Informational [Page 13] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + (HCLEN + 4) x 3 bits: code lengths for the code length + alphabet given just above, in the order: 16, 17, 18, + 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 + + These code lengths are interpreted as 3-bit integers + (0-7); as above, a code length of 0 means the + corresponding symbol (literal/length or distance code + length) is not used. + + HLIT + 257 code lengths for the literal/length alphabet, + encoded using the code length Huffman code + + HDIST + 1 code lengths for the distance alphabet, + encoded using the code length Huffman code + + The actual compressed data of the block, + encoded using the literal/length and distance Huffman + codes + + The literal/length symbol 256 (end of data), + encoded using the literal/length Huffman code + + The code length repeat codes can cross from HLIT + 257 to the + HDIST + 1 code lengths. In other words, all code lengths form + a single sequence of HLIT + HDIST + 258 values. + + 3.3. Compliance + + A compressor may limit further the ranges of values specified in + the previous section and still be compliant; for example, it may + limit the range of backward pointers to some value smaller than + 32K. Similarly, a compressor may limit the size of blocks so that + a compressible block fits in memory. + + A compliant decompressor must accept the full range of possible + values defined in the previous section, and must accept blocks of + arbitrary size. + +4. Compression algorithm details + + While it is the intent of this document to define the "deflate" + compressed data format without reference to any particular + compression algorithm, the format is related to the compressed + formats produced by LZ77 (Lempel-Ziv 1977, see reference [2] below); + since many variations of LZ77 are patented, it is strongly + recommended that the implementor of a compressor follow the general + algorithm presented here, which is known not to be patented per se. + The material in this section is not part of the definition of the + + + +Deutsch Informational [Page 14] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + specification per se, and a compressor need not follow it in order to + be compliant. + + The compressor terminates a block when it determines that starting a + new block with fresh trees would be useful, or when the block size + fills up the compressor's block buffer. + + The compressor uses a chained hash table to find duplicated strings, + using a hash function that operates on 3-byte sequences. At any + given point during compression, let XYZ be the next 3 input bytes to + be examined (not necessarily all different, of course). First, the + compressor examines the hash chain for XYZ. If the chain is empty, + the compressor simply writes out X as a literal byte and advances one + byte in the input. If the hash chain is not empty, indicating that + the sequence XYZ (or, if we are unlucky, some other 3 bytes with the + same hash function value) has occurred recently, the compressor + compares all strings on the XYZ hash chain with the actual input data + sequence starting at the current point, and selects the longest + match. + + The compressor searches the hash chains starting with the most recent + strings, to favor small distances and thus take advantage of the + Huffman encoding. The hash chains are singly linked. There are no + deletions from the hash chains; the algorithm simply discards matches + that are too old. To avoid a worst-case situation, very long hash + chains are arbitrarily truncated at a certain length, determined by a + run-time parameter. + + To improve overall compression, the compressor optionally defers the + selection of matches ("lazy matching"): after a match of length N has + been found, the compressor searches for a longer match starting at + the next input byte. If it finds a longer match, it truncates the + previous match to a length of one (thus producing a single literal + byte) and then emits the longer match. Otherwise, it emits the + original match, and, as described above, advances N bytes before + continuing. + + Run-time parameters also control this "lazy match" procedure. If + compression ratio is most important, the compressor attempts a + complete second search regardless of the length of the first match. + In the normal case, if the current match is "long enough", the + compressor reduces the search for a longer match, thus speeding up + the process. If speed is most important, the compressor inserts new + strings in the hash table only when no match was found, or when the + match is not "too long". This degrades the compression ratio but + saves time since there are both fewer insertions and fewer searches. + + + + + +Deutsch Informational [Page 15] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + +5. References + + [1] Huffman, D. A., "A Method for the Construction of Minimum + Redundancy Codes", Proceedings of the Institute of Radio + Engineers, September 1952, Volume 40, Number 9, pp. 1098-1101. + + [2] Ziv J., Lempel A., "A Universal Algorithm for Sequential Data + Compression", IEEE Transactions on Information Theory, Vol. 23, + No. 3, pp. 337-343. + + [3] Gailly, J.-L., and Adler, M., ZLIB documentation and sources, + available in ftp://ftp.uu.net/pub/archiving/zip/doc/ + + [4] Gailly, J.-L., and Adler, M., GZIP documentation and sources, + available as gzip-*.tar in ftp://prep.ai.mit.edu/pub/gnu/ + + [5] Schwartz, E. S., and Kallick, B. "Generating a canonical prefix + encoding." Comm. ACM, 7,3 (Mar. 1964), pp. 166-169. + + [6] Hirschberg and Lelewer, "Efficient decoding of prefix codes," + Comm. ACM, 33,4, April 1990, pp. 449-459. + +6. Security Considerations + + Any data compression method involves the reduction of redundancy in + the data. Consequently, any corruption of the data is likely to have + severe effects and be difficult to correct. Uncompressed text, on + the other hand, will probably still be readable despite the presence + of some corrupted bytes. + + It is recommended that systems using this data format provide some + means of validating the integrity of the compressed data. See + reference [3], for example. + +7. Source code + + Source code for a C language implementation of a "deflate" compliant + compressor and decompressor is available within the zlib package at + ftp://ftp.uu.net/pub/archiving/zip/zlib/. + +8. Acknowledgements + + Trademarks cited in this document are the property of their + respective owners. + + Phil Katz designed the deflate format. Jean-Loup Gailly and Mark + Adler wrote the related software described in this specification. + Glenn Randers-Pehrson converted this document to RFC and HTML format. + + + +Deutsch Informational [Page 16] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + +9. Author's Address + + L. Peter Deutsch + Aladdin Enterprises + 203 Santa Margarita Ave. + Menlo Park, CA 94025 + + Phone: (415) 322-0103 (AM only) + FAX: (415) 322-1734 + EMail: + + Questions about the technical content of this specification can be + sent by email to: + + Jean-Loup Gailly and + Mark Adler + + Editorial comments on this specification can be sent by email to: + + L. Peter Deutsch and + Glenn Randers-Pehrson + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Deutsch Informational [Page 17] + diff --git a/contrib/zlib/doc/rfc1952.txt b/contrib/zlib/doc/rfc1952.txt new file mode 100644 index 00000000..a8e51b45 --- /dev/null +++ b/contrib/zlib/doc/rfc1952.txt @@ -0,0 +1,675 @@ + + + + + + +Network Working Group P. Deutsch +Request for Comments: 1952 Aladdin Enterprises +Category: Informational May 1996 + + + GZIP file format specification version 4.3 + +Status of This Memo + + This memo provides information for the Internet community. This memo + does not specify an Internet standard of any kind. Distribution of + this memo is unlimited. + +IESG Note: + + The IESG takes no position on the validity of any Intellectual + Property Rights statements contained in this document. + +Notices + + Copyright (c) 1996 L. Peter Deutsch + + Permission is granted to copy and distribute this document for any + purpose and without charge, including translations into other + languages and incorporation into compilations, provided that the + copyright notice and this notice are preserved, and that any + substantive changes or deletions from the original are clearly + marked. + + A pointer to the latest version of this and related documentation in + HTML format can be found at the URL + . + +Abstract + + This specification defines a lossless compressed data format that is + compatible with the widely used GZIP utility. The format includes a + cyclic redundancy check value for detecting data corruption. The + format presently uses the DEFLATE method of compression but can be + easily extended to use other compression methods. The format can be + implemented readily in a manner not covered by patents. + + + + + + + + + + +Deutsch Informational [Page 1] + +RFC 1952 GZIP File Format Specification May 1996 + + +Table of Contents + + 1. Introduction ................................................... 2 + 1.1. Purpose ................................................... 2 + 1.2. Intended audience ......................................... 3 + 1.3. Scope ..................................................... 3 + 1.4. Compliance ................................................ 3 + 1.5. Definitions of terms and conventions used ................. 3 + 1.6. Changes from previous versions ............................ 3 + 2. Detailed specification ......................................... 4 + 2.1. Overall conventions ....................................... 4 + 2.2. File format ............................................... 5 + 2.3. Member format ............................................. 5 + 2.3.1. Member header and trailer ........................... 6 + 2.3.1.1. Extra field ................................... 8 + 2.3.1.2. Compliance .................................... 9 + 3. References .................................................. 9 + 4. Security Considerations .................................... 10 + 5. Acknowledgements ........................................... 10 + 6. Author's Address ........................................... 10 + 7. Appendix: Jean-Loup Gailly's gzip utility .................. 11 + 8. Appendix: Sample CRC Code .................................. 11 + +1. Introduction + + 1.1. Purpose + + The purpose of this specification is to define a lossless + compressed data format that: + + * Is independent of CPU type, operating system, file system, + and character set, and hence can be used for interchange; + * Can compress or decompress a data stream (as opposed to a + randomly accessible file) to produce another data stream, + using only an a priori bounded amount of intermediate + storage, and hence can be used in data communications or + similar structures such as Unix filters; + * Compresses data with efficiency comparable to the best + currently available general-purpose compression methods, + and in particular considerably better than the "compress" + program; + * Can be implemented readily in a manner not covered by + patents, and hence can be practiced freely; + * Is compatible with the file format produced by the current + widely used gzip utility, in that conforming decompressors + will be able to read data produced by the existing gzip + compressor. + + + + +Deutsch Informational [Page 2] + +RFC 1952 GZIP File Format Specification May 1996 + + + The data format defined by this specification does not attempt to: + + * Provide random access to compressed data; + * Compress specialized data (e.g., raster graphics) as well as + the best currently available specialized algorithms. + + 1.2. Intended audience + + This specification is intended for use by implementors of software + to compress data into gzip format and/or decompress data from gzip + format. + + The text of the specification assumes a basic background in + programming at the level of bits and other primitive data + representations. + + 1.3. Scope + + The specification specifies a compression method and a file format + (the latter assuming only that a file can store a sequence of + arbitrary bytes). It does not specify any particular interface to + a file system or anything about character sets or encodings + (except for file names and comments, which are optional). + + 1.4. Compliance + + Unless otherwise indicated below, a compliant decompressor must be + able to accept and decompress any file that conforms to all the + specifications presented here; a compliant compressor must produce + files that conform to all the specifications presented here. The + material in the appendices is not part of the specification per se + and is not relevant to compliance. + + 1.5. Definitions of terms and conventions used + + byte: 8 bits stored or transmitted as a unit (same as an octet). + (For this specification, a byte is exactly 8 bits, even on + machines which store a character on a number of bits different + from 8.) See below for the numbering of bits within a byte. + + 1.6. Changes from previous versions + + There have been no technical changes to the gzip format since + version 4.1 of this specification. In version 4.2, some + terminology was changed, and the sample CRC code was rewritten for + clarity and to eliminate the requirement for the caller to do pre- + and post-conditioning. Version 4.3 is a conversion of the + specification to RFC style. + + + +Deutsch Informational [Page 3] + +RFC 1952 GZIP File Format Specification May 1996 + + +2. Detailed specification + + 2.1. Overall conventions + + In the diagrams below, a box like this: + + +---+ + | | <-- the vertical bars might be missing + +---+ + + represents one byte; a box like this: + + +==============+ + | | + +==============+ + + represents a variable number of bytes. + + Bytes stored within a computer do not have a "bit order", since + they are always treated as a unit. However, a byte considered as + an integer between 0 and 255 does have a most- and least- + significant bit, and since we write numbers with the most- + significant digit on the left, we also write bytes with the most- + significant bit on the left. In the diagrams below, we number the + bits of a byte so that bit 0 is the least-significant bit, i.e., + the bits are numbered: + + +--------+ + |76543210| + +--------+ + + This document does not address the issue of the order in which + bits of a byte are transmitted on a bit-sequential medium, since + the data format described here is byte- rather than bit-oriented. + + Within a computer, a number may occupy multiple bytes. All + multi-byte numbers in the format described here are stored with + the least-significant byte first (at the lower memory address). + For example, the decimal number 520 is stored as: + + 0 1 + +--------+--------+ + |00001000|00000010| + +--------+--------+ + ^ ^ + | | + | + more significant byte = 2 x 256 + + less significant byte = 8 + + + +Deutsch Informational [Page 4] + +RFC 1952 GZIP File Format Specification May 1996 + + + 2.2. File format + + A gzip file consists of a series of "members" (compressed data + sets). The format of each member is specified in the following + section. The members simply appear one after another in the file, + with no additional information before, between, or after them. + + 2.3. Member format + + Each member has the following structure: + + +---+---+---+---+---+---+---+---+---+---+ + |ID1|ID2|CM |FLG| MTIME |XFL|OS | (more-->) + +---+---+---+---+---+---+---+---+---+---+ + + (if FLG.FEXTRA set) + + +---+---+=================================+ + | XLEN |...XLEN bytes of "extra field"...| (more-->) + +---+---+=================================+ + + (if FLG.FNAME set) + + +=========================================+ + |...original file name, zero-terminated...| (more-->) + +=========================================+ + + (if FLG.FCOMMENT set) + + +===================================+ + |...file comment, zero-terminated...| (more-->) + +===================================+ + + (if FLG.FHCRC set) + + +---+---+ + | CRC16 | + +---+---+ + + +=======================+ + |...compressed blocks...| (more-->) + +=======================+ + + 0 1 2 3 4 5 6 7 + +---+---+---+---+---+---+---+---+ + | CRC32 | ISIZE | + +---+---+---+---+---+---+---+---+ + + + + +Deutsch Informational [Page 5] + +RFC 1952 GZIP File Format Specification May 1996 + + + 2.3.1. Member header and trailer + + ID1 (IDentification 1) + ID2 (IDentification 2) + These have the fixed values ID1 = 31 (0x1f, \037), ID2 = 139 + (0x8b, \213), to identify the file as being in gzip format. + + CM (Compression Method) + This identifies the compression method used in the file. CM + = 0-7 are reserved. CM = 8 denotes the "deflate" + compression method, which is the one customarily used by + gzip and which is documented elsewhere. + + FLG (FLaGs) + This flag byte is divided into individual bits as follows: + + bit 0 FTEXT + bit 1 FHCRC + bit 2 FEXTRA + bit 3 FNAME + bit 4 FCOMMENT + bit 5 reserved + bit 6 reserved + bit 7 reserved + + If FTEXT is set, the file is probably ASCII text. This is + an optional indication, which the compressor may set by + checking a small amount of the input data to see whether any + non-ASCII characters are present. In case of doubt, FTEXT + is cleared, indicating binary data. For systems which have + different file formats for ascii text and binary data, the + decompressor can use FTEXT to choose the appropriate format. + We deliberately do not specify the algorithm used to set + this bit, since a compressor always has the option of + leaving it cleared and a decompressor always has the option + of ignoring it and letting some other program handle issues + of data conversion. + + If FHCRC is set, a CRC16 for the gzip header is present, + immediately before the compressed data. The CRC16 consists + of the two least significant bytes of the CRC32 for all + bytes of the gzip header up to and not including the CRC16. + [The FHCRC bit was never set by versions of gzip up to + 1.2.4, even though it was documented with a different + meaning in gzip 1.2.4.] + + If FEXTRA is set, optional extra fields are present, as + described in a following section. + + + +Deutsch Informational [Page 6] + +RFC 1952 GZIP File Format Specification May 1996 + + + If FNAME is set, an original file name is present, + terminated by a zero byte. The name must consist of ISO + 8859-1 (LATIN-1) characters; on operating systems using + EBCDIC or any other character set for file names, the name + must be translated to the ISO LATIN-1 character set. This + is the original name of the file being compressed, with any + directory components removed, and, if the file being + compressed is on a file system with case insensitive names, + forced to lower case. There is no original file name if the + data was compressed from a source other than a named file; + for example, if the source was stdin on a Unix system, there + is no file name. + + If FCOMMENT is set, a zero-terminated file comment is + present. This comment is not interpreted; it is only + intended for human consumption. The comment must consist of + ISO 8859-1 (LATIN-1) characters. Line breaks should be + denoted by a single line feed character (10 decimal). + + Reserved FLG bits must be zero. + + MTIME (Modification TIME) + This gives the most recent modification time of the original + file being compressed. The time is in Unix format, i.e., + seconds since 00:00:00 GMT, Jan. 1, 1970. (Note that this + may cause problems for MS-DOS and other systems that use + local rather than Universal time.) If the compressed data + did not come from a file, MTIME is set to the time at which + compression started. MTIME = 0 means no time stamp is + available. + + XFL (eXtra FLags) + These flags are available for use by specific compression + methods. The "deflate" method (CM = 8) sets these flags as + follows: + + XFL = 2 - compressor used maximum compression, + slowest algorithm + XFL = 4 - compressor used fastest algorithm + + OS (Operating System) + This identifies the type of file system on which compression + took place. This may be useful in determining end-of-line + convention for text files. The currently defined values are + as follows: + + + + + + +Deutsch Informational [Page 7] + +RFC 1952 GZIP File Format Specification May 1996 + + + 0 - FAT filesystem (MS-DOS, OS/2, NT/Win32) + 1 - Amiga + 2 - VMS (or OpenVMS) + 3 - Unix + 4 - VM/CMS + 5 - Atari TOS + 6 - HPFS filesystem (OS/2, NT) + 7 - Macintosh + 8 - Z-System + 9 - CP/M + 10 - TOPS-20 + 11 - NTFS filesystem (NT) + 12 - QDOS + 13 - Acorn RISCOS + 255 - unknown + + XLEN (eXtra LENgth) + If FLG.FEXTRA is set, this gives the length of the optional + extra field. See below for details. + + CRC32 (CRC-32) + This contains a Cyclic Redundancy Check value of the + uncompressed data computed according to CRC-32 algorithm + used in the ISO 3309 standard and in section 8.1.1.6.2 of + ITU-T recommendation V.42. (See http://www.iso.ch for + ordering ISO documents. See gopher://info.itu.ch for an + online version of ITU-T V.42.) + + ISIZE (Input SIZE) + This contains the size of the original (uncompressed) input + data modulo 2^32. + + 2.3.1.1. Extra field + + If the FLG.FEXTRA bit is set, an "extra field" is present in + the header, with total length XLEN bytes. It consists of a + series of subfields, each of the form: + + +---+---+---+---+==================================+ + |SI1|SI2| LEN |... LEN bytes of subfield data ...| + +---+---+---+---+==================================+ + + SI1 and SI2 provide a subfield ID, typically two ASCII letters + with some mnemonic value. Jean-Loup Gailly + is maintaining a registry of subfield + IDs; please send him any subfield ID you wish to use. Subfield + IDs with SI2 = 0 are reserved for future use. The following + IDs are currently defined: + + + +Deutsch Informational [Page 8] + +RFC 1952 GZIP File Format Specification May 1996 + + + SI1 SI2 Data + ---------- ---------- ---- + 0x41 ('A') 0x70 ('P') Apollo file type information + + LEN gives the length of the subfield data, excluding the 4 + initial bytes. + + 2.3.1.2. Compliance + + A compliant compressor must produce files with correct ID1, + ID2, CM, CRC32, and ISIZE, but may set all the other fields in + the fixed-length part of the header to default values (255 for + OS, 0 for all others). The compressor must set all reserved + bits to zero. + + A compliant decompressor must check ID1, ID2, and CM, and + provide an error indication if any of these have incorrect + values. It must examine FEXTRA/XLEN, FNAME, FCOMMENT and FHCRC + at least so it can skip over the optional fields if they are + present. It need not examine any other part of the header or + trailer; in particular, a decompressor may ignore FTEXT and OS + and always produce binary output, and still be compliant. A + compliant decompressor must give an error indication if any + reserved bit is non-zero, since such a bit could indicate the + presence of a new field that would cause subsequent data to be + interpreted incorrectly. + +3. References + + [1] "Information Processing - 8-bit single-byte coded graphic + character sets - Part 1: Latin alphabet No.1" (ISO 8859-1:1987). + The ISO 8859-1 (Latin-1) character set is a superset of 7-bit + ASCII. Files defining this character set are available as + iso_8859-1.* in ftp://ftp.uu.net/graphics/png/documents/ + + [2] ISO 3309 + + [3] ITU-T recommendation V.42 + + [4] Deutsch, L.P.,"DEFLATE Compressed Data Format Specification", + available in ftp://ftp.uu.net/pub/archiving/zip/doc/ + + [5] Gailly, J.-L., GZIP documentation, available as gzip-*.tar in + ftp://prep.ai.mit.edu/pub/gnu/ + + [6] Sarwate, D.V., "Computation of Cyclic Redundancy Checks via Table + Look-Up", Communications of the ACM, 31(8), pp.1008-1013. + + + + +Deutsch Informational [Page 9] + +RFC 1952 GZIP File Format Specification May 1996 + + + [7] Schwaderer, W.D., "CRC Calculation", April 85 PC Tech Journal, + pp.118-133. + + [8] ftp://ftp.adelaide.edu.au/pub/rocksoft/papers/crc_v3.txt, + describing the CRC concept. + +4. Security Considerations + + Any data compression method involves the reduction of redundancy in + the data. Consequently, any corruption of the data is likely to have + severe effects and be difficult to correct. Uncompressed text, on + the other hand, will probably still be readable despite the presence + of some corrupted bytes. + + It is recommended that systems using this data format provide some + means of validating the integrity of the compressed data, such as by + setting and checking the CRC-32 check value. + +5. Acknowledgements + + Trademarks cited in this document are the property of their + respective owners. + + Jean-Loup Gailly designed the gzip format and wrote, with Mark Adler, + the related software described in this specification. Glenn + Randers-Pehrson converted this document to RFC and HTML format. + +6. Author's Address + + L. Peter Deutsch + Aladdin Enterprises + 203 Santa Margarita Ave. + Menlo Park, CA 94025 + + Phone: (415) 322-0103 (AM only) + FAX: (415) 322-1734 + EMail: + + Questions about the technical content of this specification can be + sent by email to: + + Jean-Loup Gailly and + Mark Adler + + Editorial comments on this specification can be sent by email to: + + L. Peter Deutsch and + Glenn Randers-Pehrson + + + +Deutsch Informational [Page 10] + +RFC 1952 GZIP File Format Specification May 1996 + + +7. Appendix: Jean-Loup Gailly's gzip utility + + The most widely used implementation of gzip compression, and the + original documentation on which this specification is based, were + created by Jean-Loup Gailly . Since this + implementation is a de facto standard, we mention some more of its + features here. Again, the material in this section is not part of + the specification per se, and implementations need not follow it to + be compliant. + + When compressing or decompressing a file, gzip preserves the + protection, ownership, and modification time attributes on the local + file system, since there is no provision for representing protection + attributes in the gzip file format itself. Since the file format + includes a modification time, the gzip decompressor provides a + command line switch that assigns the modification time from the file, + rather than the local modification time of the compressed input, to + the decompressed output. + +8. Appendix: Sample CRC Code + + The following sample code represents a practical implementation of + the CRC (Cyclic Redundancy Check). (See also ISO 3309 and ITU-T V.42 + for a formal specification.) + + The sample code is in the ANSI C programming language. Non C users + may find it easier to read with these hints: + + & Bitwise AND operator. + ^ Bitwise exclusive-OR operator. + >> Bitwise right shift operator. When applied to an + unsigned quantity, as here, right shift inserts zero + bit(s) at the left. + ! Logical NOT operator. + ++ "n++" increments the variable n. + 0xNNN 0x introduces a hexadecimal (base 16) constant. + Suffix L indicates a long value (at least 32 bits). + + /* Table of CRCs of all 8-bit messages. */ + unsigned long crc_table[256]; + + /* Flag: has the table been computed? Initially false. */ + int crc_table_computed = 0; + + /* Make the table for a fast CRC. */ + void make_crc_table(void) + { + unsigned long c; + + + +Deutsch Informational [Page 11] + +RFC 1952 GZIP File Format Specification May 1996 + + + int n, k; + for (n = 0; n < 256; n++) { + c = (unsigned long) n; + for (k = 0; k < 8; k++) { + if (c & 1) { + c = 0xedb88320L ^ (c >> 1); + } else { + c = c >> 1; + } + } + crc_table[n] = c; + } + crc_table_computed = 1; + } + + /* + Update a running crc with the bytes buf[0..len-1] and return + the updated crc. The crc should be initialized to zero. Pre- and + post-conditioning (one's complement) is performed within this + function so it shouldn't be done by the caller. Usage example: + + unsigned long crc = 0L; + + while (read_buffer(buffer, length) != EOF) { + crc = update_crc(crc, buffer, length); + } + if (crc != original_crc) error(); + */ + unsigned long update_crc(unsigned long crc, + unsigned char *buf, int len) + { + unsigned long c = crc ^ 0xffffffffL; + int n; + + if (!crc_table_computed) + make_crc_table(); + for (n = 0; n < len; n++) { + c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); + } + return c ^ 0xffffffffL; + } + + /* Return the CRC of the bytes buf[0..len-1]. */ + unsigned long crc(unsigned char *buf, int len) + { + return update_crc(0L, buf, len); + } + + + + +Deutsch Informational [Page 12] + diff --git a/contrib/zlib/doc/txtvsbin.txt b/contrib/zlib/doc/txtvsbin.txt new file mode 100644 index 00000000..3d0f0634 --- /dev/null +++ b/contrib/zlib/doc/txtvsbin.txt @@ -0,0 +1,107 @@ +A Fast Method for Identifying Plain Text Files +============================================== + + +Introduction +------------ + +Given a file coming from an unknown source, it is sometimes desirable +to find out whether the format of that file is plain text. Although +this may appear like a simple task, a fully accurate detection of the +file type requires heavy-duty semantic analysis on the file contents. +It is, however, possible to obtain satisfactory results by employing +various heuristics. + +Previous versions of PKZip and other zip-compatible compression tools +were using a crude detection scheme: if more than 80% (4/5) of the bytes +found in a certain buffer are within the range [7..127], the file is +labeled as plain text, otherwise it is labeled as binary. A prominent +limitation of this scheme is the restriction to Latin-based alphabets. +Other alphabets, like Greek, Cyrillic or Asian, make extensive use of +the bytes within the range [128..255], and texts using these alphabets +are most often misidentified by this scheme; in other words, the rate +of false negatives is sometimes too high, which means that the recall +is low. Another weakness of this scheme is a reduced precision, due to +the false positives that may occur when binary files containing large +amounts of textual characters are misidentified as plain text. + +In this article we propose a new, simple detection scheme that features +a much increased precision and a near-100% recall. This scheme is +designed to work on ASCII, Unicode and other ASCII-derived alphabets, +and it handles single-byte encodings (ISO-8859, MacRoman, KOI8, etc.) +and variable-sized encodings (ISO-2022, UTF-8, etc.). Wider encodings +(UCS-2/UTF-16 and UCS-4/UTF-32) are not handled, however. + + +The Algorithm +------------- + +The algorithm works by dividing the set of bytecodes [0..255] into three +categories: +- The white list of textual bytecodes: + 9 (TAB), 10 (LF), 13 (CR), 32 (SPACE) to 255. +- The gray list of tolerated bytecodes: + 7 (BEL), 8 (BS), 11 (VT), 12 (FF), 26 (SUB), 27 (ESC). +- The black list of undesired, non-textual bytecodes: + 0 (NUL) to 6, 14 to 31. + +If a file contains at least one byte that belongs to the white list and +no byte that belongs to the black list, then the file is categorized as +plain text; otherwise, it is categorized as binary. (The boundary case, +when the file is empty, automatically falls into the latter category.) + + +Rationale +--------- + +The idea behind this algorithm relies on two observations. + +The first observation is that, although the full range of 7-bit codes +[0..127] is properly specified by the ASCII standard, most control +characters in the range [0..31] are not used in practice. The only +widely-used, almost universally-portable control codes are 9 (TAB), +10 (LF) and 13 (CR). There are a few more control codes that are +recognized on a reduced range of platforms and text viewers/editors: +7 (BEL), 8 (BS), 11 (VT), 12 (FF), 26 (SUB) and 27 (ESC); but these +codes are rarely (if ever) used alone, without being accompanied by +some printable text. Even the newer, portable text formats such as +XML avoid using control characters outside the list mentioned here. + +The second observation is that most of the binary files tend to contain +control characters, especially 0 (NUL). Even though the older text +detection schemes observe the presence of non-ASCII codes from the range +[128..255], the precision rarely has to suffer if this upper range is +labeled as textual, because the files that are genuinely binary tend to +contain both control characters and codes from the upper range. On the +other hand, the upper range needs to be labeled as textual, because it +is used by virtually all ASCII extensions. In particular, this range is +used for encoding non-Latin scripts. + +Since there is no counting involved, other than simply observing the +presence or the absence of some byte values, the algorithm produces +consistent results, regardless what alphabet encoding is being used. +(If counting were involved, it could be possible to obtain different +results on a text encoded, say, using ISO-8859-16 versus UTF-8.) + +There is an extra category of plain text files that are "polluted" with +one or more black-listed codes, either by mistake or by peculiar design +considerations. In such cases, a scheme that tolerates a small fraction +of black-listed codes would provide an increased recall (i.e. more true +positives). This, however, incurs a reduced precision overall, since +false positives are more likely to appear in binary files that contain +large chunks of textual data. Furthermore, "polluted" plain text should +be regarded as binary by general-purpose text detection schemes, because +general-purpose text processing algorithms might not be applicable. +Under this premise, it is safe to say that our detection method provides +a near-100% recall. + +Experiments have been run on many files coming from various platforms +and applications. We tried plain text files, system logs, source code, +formatted office documents, compiled object code, etc. The results +confirm the optimistic assumptions about the capabilities of this +algorithm. + + +-- +Cosmin Truta +Last updated: 2006-May-28 diff --git a/contrib/zlib/examples/README.examples b/contrib/zlib/examples/README.examples new file mode 100644 index 00000000..56a31714 --- /dev/null +++ b/contrib/zlib/examples/README.examples @@ -0,0 +1,49 @@ +This directory contains examples of the use of zlib and other relevant +programs and documentation. + +enough.c + calculation and justification of ENOUGH parameter in inftrees.h + - calculates the maximum table space used in inflate tree + construction over all possible Huffman codes + +fitblk.c + compress just enough input to nearly fill a requested output size + - zlib isn't designed to do this, but fitblk does it anyway + +gun.c + uncompress a gzip file + - illustrates the use of inflateBack() for high speed file-to-file + decompression using call-back functions + - is approximately twice as fast as gzip -d + - also provides Unix uncompress functionality, again twice as fast + +gzappend.c + append to a gzip file + - illustrates the use of the Z_BLOCK flush parameter for inflate() + - illustrates the use of deflatePrime() to start at any bit + +gzjoin.c + join gzip files without recalculating the crc or recompressing + - illustrates the use of the Z_BLOCK flush parameter for inflate() + - illustrates the use of crc32_combine() + +gzlog.c +gzlog.h + efficiently and robustly maintain a message log file in gzip format + - illustrates use of raw deflate, Z_PARTIAL_FLUSH, deflatePrime(), + and deflateSetDictionary() + - illustrates use of a gzip header extra field + +zlib_how.html + painfully comprehensive description of zpipe.c (see below) + - describes in excruciating detail the use of deflate() and inflate() + +zpipe.c + reads and writes zlib streams from stdin to stdout + - illustrates the proper use of deflate() and inflate() + - deeply commented in zlib_how.html (see above) + +zran.c + index a zlib or gzip stream and randomly access it + - illustrates the use of Z_BLOCK, inflatePrime(), and + inflateSetDictionary() to provide random access diff --git a/contrib/zlib/examples/enough.c b/contrib/zlib/examples/enough.c new file mode 100644 index 00000000..b9911443 --- /dev/null +++ b/contrib/zlib/examples/enough.c @@ -0,0 +1,572 @@ +/* enough.c -- determine the maximum size of inflate's Huffman code tables over + * all possible valid and complete Huffman codes, subject to a length limit. + * Copyright (C) 2007, 2008, 2012 Mark Adler + * Version 1.4 18 August 2012 Mark Adler + */ + +/* Version history: + 1.0 3 Jan 2007 First version (derived from codecount.c version 1.4) + 1.1 4 Jan 2007 Use faster incremental table usage computation + Prune examine() search on previously visited states + 1.2 5 Jan 2007 Comments clean up + As inflate does, decrease root for short codes + Refuse cases where inflate would increase root + 1.3 17 Feb 2008 Add argument for initial root table size + Fix bug for initial root table size == max - 1 + Use a macro to compute the history index + 1.4 18 Aug 2012 Avoid shifts more than bits in type (caused endless loop!) + Clean up comparisons of different types + Clean up code indentation + */ + +/* + Examine all possible Huffman codes for a given number of symbols and a + maximum code length in bits to determine the maximum table size for zilb's + inflate. Only complete Huffman codes are counted. + + Two codes are considered distinct if the vectors of the number of codes per + length are not identical. So permutations of the symbol assignments result + in the same code for the counting, as do permutations of the assignments of + the bit values to the codes (i.e. only canonical codes are counted). + + We build a code from shorter to longer lengths, determining how many symbols + are coded at each length. At each step, we have how many symbols remain to + be coded, what the last code length used was, and how many bit patterns of + that length remain unused. Then we add one to the code length and double the + number of unused patterns to graduate to the next code length. We then + assign all portions of the remaining symbols to that code length that + preserve the properties of a correct and eventually complete code. Those + properties are: we cannot use more bit patterns than are available; and when + all the symbols are used, there are exactly zero possible bit patterns + remaining. + + The inflate Huffman decoding algorithm uses two-level lookup tables for + speed. There is a single first-level table to decode codes up to root bits + in length (root == 9 in the current inflate implementation). The table + has 1 << root entries and is indexed by the next root bits of input. Codes + shorter than root bits have replicated table entries, so that the correct + entry is pointed to regardless of the bits that follow the short code. If + the code is longer than root bits, then the table entry points to a second- + level table. The size of that table is determined by the longest code with + that root-bit prefix. If that longest code has length len, then the table + has size 1 << (len - root), to index the remaining bits in that set of + codes. Each subsequent root-bit prefix then has its own sub-table. The + total number of table entries required by the code is calculated + incrementally as the number of codes at each bit length is populated. When + all of the codes are shorter than root bits, then root is reduced to the + longest code length, resulting in a single, smaller, one-level table. + + The inflate algorithm also provides for small values of root (relative to + the log2 of the number of symbols), where the shortest code has more bits + than root. In that case, root is increased to the length of the shortest + code. This program, by design, does not handle that case, so it is verified + that the number of symbols is less than 2^(root + 1). + + In order to speed up the examination (by about ten orders of magnitude for + the default arguments), the intermediate states in the build-up of a code + are remembered and previously visited branches are pruned. The memory + required for this will increase rapidly with the total number of symbols and + the maximum code length in bits. However this is a very small price to pay + for the vast speedup. + + First, all of the possible Huffman codes are counted, and reachable + intermediate states are noted by a non-zero count in a saved-results array. + Second, the intermediate states that lead to (root + 1) bit or longer codes + are used to look at all sub-codes from those junctures for their inflate + memory usage. (The amount of memory used is not affected by the number of + codes of root bits or less in length.) Third, the visited states in the + construction of those sub-codes and the associated calculation of the table + size is recalled in order to avoid recalculating from the same juncture. + Beginning the code examination at (root + 1) bit codes, which is enabled by + identifying the reachable nodes, accounts for about six of the orders of + magnitude of improvement for the default arguments. About another four + orders of magnitude come from not revisiting previous states. Out of + approximately 2x10^16 possible Huffman codes, only about 2x10^6 sub-codes + need to be examined to cover all of the possible table memory usage cases + for the default arguments of 286 symbols limited to 15-bit codes. + + Note that an unsigned long long type is used for counting. It is quite easy + to exceed the capacity of an eight-byte integer with a large number of + symbols and a large maximum code length, so multiple-precision arithmetic + would need to replace the unsigned long long arithmetic in that case. This + program will abort if an overflow occurs. The big_t type identifies where + the counting takes place. + + An unsigned long long type is also used for calculating the number of + possible codes remaining at the maximum length. This limits the maximum + code length to the number of bits in a long long minus the number of bits + needed to represent the symbols in a flat code. The code_t type identifies + where the bit pattern counting takes place. + */ + +#include +#include +#include +#include + +#define local static + +/* special data types */ +typedef unsigned long long big_t; /* type for code counting */ +typedef unsigned long long code_t; /* type for bit pattern counting */ +struct tab { /* type for been here check */ + size_t len; /* length of bit vector in char's */ + char *vec; /* allocated bit vector */ +}; + +/* The array for saving results, num[], is indexed with this triplet: + + syms: number of symbols remaining to code + left: number of available bit patterns at length len + len: number of bits in the codes currently being assigned + + Those indices are constrained thusly when saving results: + + syms: 3..totsym (totsym == total symbols to code) + left: 2..syms - 1, but only the evens (so syms == 8 -> 2, 4, 6) + len: 1..max - 1 (max == maximum code length in bits) + + syms == 2 is not saved since that immediately leads to a single code. left + must be even, since it represents the number of available bit patterns at + the current length, which is double the number at the previous length. + left ends at syms-1 since left == syms immediately results in a single code. + (left > sym is not allowed since that would result in an incomplete code.) + len is less than max, since the code completes immediately when len == max. + + The offset into the array is calculated for the three indices with the + first one (syms) being outermost, and the last one (len) being innermost. + We build the array with length max-1 lists for the len index, with syms-3 + of those for each symbol. There are totsym-2 of those, with each one + varying in length as a function of sym. See the calculation of index in + count() for the index, and the calculation of size in main() for the size + of the array. + + For the deflate example of 286 symbols limited to 15-bit codes, the array + has 284,284 entries, taking up 2.17 MB for an 8-byte big_t. More than + half of the space allocated for saved results is actually used -- not all + possible triplets are reached in the generation of valid Huffman codes. + */ + +/* The array for tracking visited states, done[], is itself indexed identically + to the num[] array as described above for the (syms, left, len) triplet. + Each element in the array is further indexed by the (mem, rem) doublet, + where mem is the amount of inflate table space used so far, and rem is the + remaining unused entries in the current inflate sub-table. Each indexed + element is simply one bit indicating whether the state has been visited or + not. Since the ranges for mem and rem are not known a priori, each bit + vector is of a variable size, and grows as needed to accommodate the visited + states. mem and rem are used to calculate a single index in a triangular + array. Since the range of mem is expected in the default case to be about + ten times larger than the range of rem, the array is skewed to reduce the + memory usage, with eight times the range for mem than for rem. See the + calculations for offset and bit in beenhere() for the details. + + For the deflate example of 286 symbols limited to 15-bit codes, the bit + vectors grow to total approximately 21 MB, in addition to the 4.3 MB done[] + array itself. + */ + +/* Globals to avoid propagating constants or constant pointers recursively */ +local int max; /* maximum allowed bit length for the codes */ +local int root; /* size of base code table in bits */ +local int large; /* largest code table so far */ +local size_t size; /* number of elements in num and done */ +local int *code; /* number of symbols assigned to each bit length */ +local big_t *num; /* saved results array for code counting */ +local struct tab *done; /* states already evaluated array */ + +/* Index function for num[] and done[] */ +#define INDEX(i,j,k) (((size_t)((i-1)>>1)*((i-2)>>1)+(j>>1)-1)*(max-1)+k-1) + +/* Free allocated space. Uses globals code, num, and done. */ +local void cleanup(void) +{ + size_t n; + + if (done != NULL) { + for (n = 0; n < size; n++) + if (done[n].len) + free(done[n].vec); + free(done); + } + if (num != NULL) + free(num); + if (code != NULL) + free(code); +} + +/* Return the number of possible Huffman codes using bit patterns of lengths + len through max inclusive, coding syms symbols, with left bit patterns of + length len unused -- return -1 if there is an overflow in the counting. + Keep a record of previous results in num to prevent repeating the same + calculation. Uses the globals max and num. */ +local big_t count(int syms, int len, int left) +{ + big_t sum; /* number of possible codes from this juncture */ + big_t got; /* value returned from count() */ + int least; /* least number of syms to use at this juncture */ + int most; /* most number of syms to use at this juncture */ + int use; /* number of bit patterns to use in next call */ + size_t index; /* index of this case in *num */ + + /* see if only one possible code */ + if (syms == left) + return 1; + + /* note and verify the expected state */ + assert(syms > left && left > 0 && len < max); + + /* see if we've done this one already */ + index = INDEX(syms, left, len); + got = num[index]; + if (got) + return got; /* we have -- return the saved result */ + + /* we need to use at least this many bit patterns so that the code won't be + incomplete at the next length (more bit patterns than symbols) */ + least = (left << 1) - syms; + if (least < 0) + least = 0; + + /* we can use at most this many bit patterns, lest there not be enough + available for the remaining symbols at the maximum length (if there were + no limit to the code length, this would become: most = left - 1) */ + most = (((code_t)left << (max - len)) - syms) / + (((code_t)1 << (max - len)) - 1); + + /* count all possible codes from this juncture and add them up */ + sum = 0; + for (use = least; use <= most; use++) { + got = count(syms - use, len + 1, (left - use) << 1); + sum += got; + if (got == (big_t)0 - 1 || sum < got) /* overflow */ + return (big_t)0 - 1; + } + + /* verify that all recursive calls are productive */ + assert(sum != 0); + + /* save the result and return it */ + num[index] = sum; + return sum; +} + +/* Return true if we've been here before, set to true if not. Set a bit in a + bit vector to indicate visiting this state. Each (syms,len,left) state + has a variable size bit vector indexed by (mem,rem). The bit vector is + lengthened if needed to allow setting the (mem,rem) bit. */ +local int beenhere(int syms, int len, int left, int mem, int rem) +{ + size_t index; /* index for this state's bit vector */ + size_t offset; /* offset in this state's bit vector */ + int bit; /* mask for this state's bit */ + size_t length; /* length of the bit vector in bytes */ + char *vector; /* new or enlarged bit vector */ + + /* point to vector for (syms,left,len), bit in vector for (mem,rem) */ + index = INDEX(syms, left, len); + mem -= 1 << root; + offset = (mem >> 3) + rem; + offset = ((offset * (offset + 1)) >> 1) + rem; + bit = 1 << (mem & 7); + + /* see if we've been here */ + length = done[index].len; + if (offset < length && (done[index].vec[offset] & bit) != 0) + return 1; /* done this! */ + + /* we haven't been here before -- set the bit to show we have now */ + + /* see if we need to lengthen the vector in order to set the bit */ + if (length <= offset) { + /* if we have one already, enlarge it, zero out the appended space */ + if (length) { + do { + length <<= 1; + } while (length <= offset); + vector = realloc(done[index].vec, length); + if (vector != NULL) + memset(vector + done[index].len, 0, length - done[index].len); + } + + /* otherwise we need to make a new vector and zero it out */ + else { + length = 1 << (len - root); + while (length <= offset) + length <<= 1; + vector = calloc(length, sizeof(char)); + } + + /* in either case, bail if we can't get the memory */ + if (vector == NULL) { + fputs("abort: unable to allocate enough memory\n", stderr); + cleanup(); + exit(1); + } + + /* install the new vector */ + done[index].len = length; + done[index].vec = vector; + } + + /* set the bit */ + done[index].vec[offset] |= bit; + return 0; +} + +/* Examine all possible codes from the given node (syms, len, left). Compute + the amount of memory required to build inflate's decoding tables, where the + number of code structures used so far is mem, and the number remaining in + the current sub-table is rem. Uses the globals max, code, root, large, and + done. */ +local void examine(int syms, int len, int left, int mem, int rem) +{ + int least; /* least number of syms to use at this juncture */ + int most; /* most number of syms to use at this juncture */ + int use; /* number of bit patterns to use in next call */ + + /* see if we have a complete code */ + if (syms == left) { + /* set the last code entry */ + code[len] = left; + + /* complete computation of memory used by this code */ + while (rem < left) { + left -= rem; + rem = 1 << (len - root); + mem += rem; + } + assert(rem == left); + + /* if this is a new maximum, show the entries used and the sub-code */ + if (mem > large) { + large = mem; + printf("max %d: ", mem); + for (use = root + 1; use <= max; use++) + if (code[use]) + printf("%d[%d] ", code[use], use); + putchar('\n'); + fflush(stdout); + } + + /* remove entries as we drop back down in the recursion */ + code[len] = 0; + return; + } + + /* prune the tree if we can */ + if (beenhere(syms, len, left, mem, rem)) + return; + + /* we need to use at least this many bit patterns so that the code won't be + incomplete at the next length (more bit patterns than symbols) */ + least = (left << 1) - syms; + if (least < 0) + least = 0; + + /* we can use at most this many bit patterns, lest there not be enough + available for the remaining symbols at the maximum length (if there were + no limit to the code length, this would become: most = left - 1) */ + most = (((code_t)left << (max - len)) - syms) / + (((code_t)1 << (max - len)) - 1); + + /* occupy least table spaces, creating new sub-tables as needed */ + use = least; + while (rem < use) { + use -= rem; + rem = 1 << (len - root); + mem += rem; + } + rem -= use; + + /* examine codes from here, updating table space as we go */ + for (use = least; use <= most; use++) { + code[len] = use; + examine(syms - use, len + 1, (left - use) << 1, + mem + (rem ? 1 << (len - root) : 0), rem << 1); + if (rem == 0) { + rem = 1 << (len - root); + mem += rem; + } + rem--; + } + + /* remove entries as we drop back down in the recursion */ + code[len] = 0; +} + +/* Look at all sub-codes starting with root + 1 bits. Look at only the valid + intermediate code states (syms, left, len). For each completed code, + calculate the amount of memory required by inflate to build the decoding + tables. Find the maximum amount of memory required and show the code that + requires that maximum. Uses the globals max, root, and num. */ +local void enough(int syms) +{ + int n; /* number of remaing symbols for this node */ + int left; /* number of unused bit patterns at this length */ + size_t index; /* index of this case in *num */ + + /* clear code */ + for (n = 0; n <= max; n++) + code[n] = 0; + + /* look at all (root + 1) bit and longer codes */ + large = 1 << root; /* base table */ + if (root < max) /* otherwise, there's only a base table */ + for (n = 3; n <= syms; n++) + for (left = 2; left < n; left += 2) + { + /* look at all reachable (root + 1) bit nodes, and the + resulting codes (complete at root + 2 or more) */ + index = INDEX(n, left, root + 1); + if (root + 1 < max && num[index]) /* reachable node */ + examine(n, root + 1, left, 1 << root, 0); + + /* also look at root bit codes with completions at root + 1 + bits (not saved in num, since complete), just in case */ + if (num[index - 1] && n <= left << 1) + examine((n - left) << 1, root + 1, (n - left) << 1, + 1 << root, 0); + } + + /* done */ + printf("done: maximum of %d table entries\n", large); +} + +/* + Examine and show the total number of possible Huffman codes for a given + maximum number of symbols, initial root table size, and maximum code length + in bits -- those are the command arguments in that order. The default + values are 286, 9, and 15 respectively, for the deflate literal/length code. + The possible codes are counted for each number of coded symbols from two to + the maximum. The counts for each of those and the total number of codes are + shown. The maximum number of inflate table entires is then calculated + across all possible codes. Each new maximum number of table entries and the + associated sub-code (starting at root + 1 == 10 bits) is shown. + + To count and examine Huffman codes that are not length-limited, provide a + maximum length equal to the number of symbols minus one. + + For the deflate literal/length code, use "enough". For the deflate distance + code, use "enough 30 6". + + This uses the %llu printf format to print big_t numbers, which assumes that + big_t is an unsigned long long. If the big_t type is changed (for example + to a multiple precision type), the method of printing will also need to be + updated. + */ +int main(int argc, char **argv) +{ + int syms; /* total number of symbols to code */ + int n; /* number of symbols to code for this run */ + big_t got; /* return value of count() */ + big_t sum; /* accumulated number of codes over n */ + code_t word; /* for counting bits in code_t */ + + /* set up globals for cleanup() */ + code = NULL; + num = NULL; + done = NULL; + + /* get arguments -- default to the deflate literal/length code */ + syms = 286; + root = 9; + max = 15; + if (argc > 1) { + syms = atoi(argv[1]); + if (argc > 2) { + root = atoi(argv[2]); + if (argc > 3) + max = atoi(argv[3]); + } + } + if (argc > 4 || syms < 2 || root < 1 || max < 1) { + fputs("invalid arguments, need: [sym >= 2 [root >= 1 [max >= 1]]]\n", + stderr); + return 1; + } + + /* if not restricting the code length, the longest is syms - 1 */ + if (max > syms - 1) + max = syms - 1; + + /* determine the number of bits in a code_t */ + for (n = 0, word = 1; word; n++, word <<= 1) + ; + + /* make sure that the calculation of most will not overflow */ + if (max > n || (code_t)(syms - 2) >= (((code_t)0 - 1) >> (max - 1))) { + fputs("abort: code length too long for internal types\n", stderr); + return 1; + } + + /* reject impossible code requests */ + if ((code_t)(syms - 1) > ((code_t)1 << max) - 1) { + fprintf(stderr, "%d symbols cannot be coded in %d bits\n", + syms, max); + return 1; + } + + /* allocate code vector */ + code = calloc(max + 1, sizeof(int)); + if (code == NULL) { + fputs("abort: unable to allocate enough memory\n", stderr); + return 1; + } + + /* determine size of saved results array, checking for overflows, + allocate and clear the array (set all to zero with calloc()) */ + if (syms == 2) /* iff max == 1 */ + num = NULL; /* won't be saving any results */ + else { + size = syms >> 1; + if (size > ((size_t)0 - 1) / (n = (syms - 1) >> 1) || + (size *= n, size > ((size_t)0 - 1) / (n = max - 1)) || + (size *= n, size > ((size_t)0 - 1) / sizeof(big_t)) || + (num = calloc(size, sizeof(big_t))) == NULL) { + fputs("abort: unable to allocate enough memory\n", stderr); + cleanup(); + return 1; + } + } + + /* count possible codes for all numbers of symbols, add up counts */ + sum = 0; + for (n = 2; n <= syms; n++) { + got = count(n, 1, 2); + sum += got; + if (got == (big_t)0 - 1 || sum < got) { /* overflow */ + fputs("abort: can't count that high!\n", stderr); + cleanup(); + return 1; + } + printf("%llu %d-codes\n", got, n); + } + printf("%llu total codes for 2 to %d symbols", sum, syms); + if (max < syms - 1) + printf(" (%d-bit length limit)\n", max); + else + puts(" (no length limit)"); + + /* allocate and clear done array for beenhere() */ + if (syms == 2) + done = NULL; + else if (size > ((size_t)0 - 1) / sizeof(struct tab) || + (done = calloc(size, sizeof(struct tab))) == NULL) { + fputs("abort: unable to allocate enough memory\n", stderr); + cleanup(); + return 1; + } + + /* find and show maximum inflate table usage */ + if (root > max) /* reduce root to max length */ + root = max; + if ((code_t)syms < ((code_t)1 << (root + 1))) + enough(syms); + else + puts("cannot handle minimum code lengths > root"); + + /* done */ + cleanup(); + return 0; +} diff --git a/contrib/zlib/examples/fitblk.c b/contrib/zlib/examples/fitblk.c new file mode 100644 index 00000000..c61de5c9 --- /dev/null +++ b/contrib/zlib/examples/fitblk.c @@ -0,0 +1,233 @@ +/* fitblk.c: example of fitting compressed output to a specified size + Not copyrighted -- provided to the public domain + Version 1.1 25 November 2004 Mark Adler */ + +/* Version history: + 1.0 24 Nov 2004 First version + 1.1 25 Nov 2004 Change deflateInit2() to deflateInit() + Use fixed-size, stack-allocated raw buffers + Simplify code moving compression to subroutines + Use assert() for internal errors + Add detailed description of approach + */ + +/* Approach to just fitting a requested compressed size: + + fitblk performs three compression passes on a portion of the input + data in order to determine how much of that input will compress to + nearly the requested output block size. The first pass generates + enough deflate blocks to produce output to fill the requested + output size plus a specfied excess amount (see the EXCESS define + below). The last deflate block may go quite a bit past that, but + is discarded. The second pass decompresses and recompresses just + the compressed data that fit in the requested plus excess sized + buffer. The deflate process is terminated after that amount of + input, which is less than the amount consumed on the first pass. + The last deflate block of the result will be of a comparable size + to the final product, so that the header for that deflate block and + the compression ratio for that block will be about the same as in + the final product. The third compression pass decompresses the + result of the second step, but only the compressed data up to the + requested size minus an amount to allow the compressed stream to + complete (see the MARGIN define below). That will result in a + final compressed stream whose length is less than or equal to the + requested size. Assuming sufficient input and a requested size + greater than a few hundred bytes, the shortfall will typically be + less than ten bytes. + + If the input is short enough that the first compression completes + before filling the requested output size, then that compressed + stream is return with no recompression. + + EXCESS is chosen to be just greater than the shortfall seen in a + two pass approach similar to the above. That shortfall is due to + the last deflate block compressing more efficiently with a smaller + header on the second pass. EXCESS is set to be large enough so + that there is enough uncompressed data for the second pass to fill + out the requested size, and small enough so that the final deflate + block of the second pass will be close in size to the final deflate + block of the third and final pass. MARGIN is chosen to be just + large enough to assure that the final compression has enough room + to complete in all cases. + */ + +#include +#include +#include +#include "zlib.h" + +#define local static + +/* print nastygram and leave */ +local void quit(char *why) +{ + fprintf(stderr, "fitblk abort: %s\n", why); + exit(1); +} + +#define RAWLEN 4096 /* intermediate uncompressed buffer size */ + +/* compress from file to def until provided buffer is full or end of + input reached; return last deflate() return value, or Z_ERRNO if + there was read error on the file */ +local int partcompress(FILE *in, z_streamp def) +{ + int ret, flush; + unsigned char raw[RAWLEN]; + + flush = Z_NO_FLUSH; + do { + def->avail_in = fread(raw, 1, RAWLEN, in); + if (ferror(in)) + return Z_ERRNO; + def->next_in = raw; + if (feof(in)) + flush = Z_FINISH; + ret = deflate(def, flush); + assert(ret != Z_STREAM_ERROR); + } while (def->avail_out != 0 && flush == Z_NO_FLUSH); + return ret; +} + +/* recompress from inf's input to def's output; the input for inf and + the output for def are set in those structures before calling; + return last deflate() return value, or Z_MEM_ERROR if inflate() + was not able to allocate enough memory when it needed to */ +local int recompress(z_streamp inf, z_streamp def) +{ + int ret, flush; + unsigned char raw[RAWLEN]; + + flush = Z_NO_FLUSH; + do { + /* decompress */ + inf->avail_out = RAWLEN; + inf->next_out = raw; + ret = inflate(inf, Z_NO_FLUSH); + assert(ret != Z_STREAM_ERROR && ret != Z_DATA_ERROR && + ret != Z_NEED_DICT); + if (ret == Z_MEM_ERROR) + return ret; + + /* compress what was decompresed until done or no room */ + def->avail_in = RAWLEN - inf->avail_out; + def->next_in = raw; + if (inf->avail_out != 0) + flush = Z_FINISH; + ret = deflate(def, flush); + assert(ret != Z_STREAM_ERROR); + } while (ret != Z_STREAM_END && def->avail_out != 0); + return ret; +} + +#define EXCESS 256 /* empirically determined stream overage */ +#define MARGIN 8 /* amount to back off for completion */ + +/* compress from stdin to fixed-size block on stdout */ +int main(int argc, char **argv) +{ + int ret; /* return code */ + unsigned size; /* requested fixed output block size */ + unsigned have; /* bytes written by deflate() call */ + unsigned char *blk; /* intermediate and final stream */ + unsigned char *tmp; /* close to desired size stream */ + z_stream def, inf; /* zlib deflate and inflate states */ + + /* get requested output size */ + if (argc != 2) + quit("need one argument: size of output block"); + ret = strtol(argv[1], argv + 1, 10); + if (argv[1][0] != 0) + quit("argument must be a number"); + if (ret < 8) /* 8 is minimum zlib stream size */ + quit("need positive size of 8 or greater"); + size = (unsigned)ret; + + /* allocate memory for buffers and compression engine */ + blk = malloc(size + EXCESS); + def.zalloc = Z_NULL; + def.zfree = Z_NULL; + def.opaque = Z_NULL; + ret = deflateInit(&def, Z_DEFAULT_COMPRESSION); + if (ret != Z_OK || blk == NULL) + quit("out of memory"); + + /* compress from stdin until output full, or no more input */ + def.avail_out = size + EXCESS; + def.next_out = blk; + ret = partcompress(stdin, &def); + if (ret == Z_ERRNO) + quit("error reading input"); + + /* if it all fit, then size was undersubscribed -- done! */ + if (ret == Z_STREAM_END && def.avail_out >= EXCESS) { + /* write block to stdout */ + have = size + EXCESS - def.avail_out; + if (fwrite(blk, 1, have, stdout) != have || ferror(stdout)) + quit("error writing output"); + + /* clean up and print results to stderr */ + ret = deflateEnd(&def); + assert(ret != Z_STREAM_ERROR); + free(blk); + fprintf(stderr, + "%u bytes unused out of %u requested (all input)\n", + size - have, size); + return 0; + } + + /* it didn't all fit -- set up for recompression */ + inf.zalloc = Z_NULL; + inf.zfree = Z_NULL; + inf.opaque = Z_NULL; + inf.avail_in = 0; + inf.next_in = Z_NULL; + ret = inflateInit(&inf); + tmp = malloc(size + EXCESS); + if (ret != Z_OK || tmp == NULL) + quit("out of memory"); + ret = deflateReset(&def); + assert(ret != Z_STREAM_ERROR); + + /* do first recompression close to the right amount */ + inf.avail_in = size + EXCESS; + inf.next_in = blk; + def.avail_out = size + EXCESS; + def.next_out = tmp; + ret = recompress(&inf, &def); + if (ret == Z_MEM_ERROR) + quit("out of memory"); + + /* set up for next reocmpression */ + ret = inflateReset(&inf); + assert(ret != Z_STREAM_ERROR); + ret = deflateReset(&def); + assert(ret != Z_STREAM_ERROR); + + /* do second and final recompression (third compression) */ + inf.avail_in = size - MARGIN; /* assure stream will complete */ + inf.next_in = tmp; + def.avail_out = size; + def.next_out = blk; + ret = recompress(&inf, &def); + if (ret == Z_MEM_ERROR) + quit("out of memory"); + assert(ret == Z_STREAM_END); /* otherwise MARGIN too small */ + + /* done -- write block to stdout */ + have = size - def.avail_out; + if (fwrite(blk, 1, have, stdout) != have || ferror(stdout)) + quit("error writing output"); + + /* clean up and print results to stderr */ + free(tmp); + ret = inflateEnd(&inf); + assert(ret != Z_STREAM_ERROR); + ret = deflateEnd(&def); + assert(ret != Z_STREAM_ERROR); + free(blk); + fprintf(stderr, + "%u bytes unused out of %u requested (%lu input)\n", + size - have, size, def.total_in); + return 0; +} diff --git a/contrib/zlib/examples/gun.c b/contrib/zlib/examples/gun.c new file mode 100644 index 00000000..be44fa51 --- /dev/null +++ b/contrib/zlib/examples/gun.c @@ -0,0 +1,702 @@ +/* gun.c -- simple gunzip to give an example of the use of inflateBack() + * Copyright (C) 2003, 2005, 2008, 2010, 2012 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + Version 1.7 12 August 2012 Mark Adler */ + +/* Version history: + 1.0 16 Feb 2003 First version for testing of inflateBack() + 1.1 21 Feb 2005 Decompress concatenated gzip streams + Remove use of "this" variable (C++ keyword) + Fix return value for in() + Improve allocation failure checking + Add typecasting for void * structures + Add -h option for command version and usage + Add a bunch of comments + 1.2 20 Mar 2005 Add Unix compress (LZW) decompression + Copy file attributes from input file to output file + 1.3 12 Jun 2005 Add casts for error messages [Oberhumer] + 1.4 8 Dec 2006 LZW decompression speed improvements + 1.5 9 Feb 2008 Avoid warning in latest version of gcc + 1.6 17 Jan 2010 Avoid signed/unsigned comparison warnings + 1.7 12 Aug 2012 Update for z_const usage in zlib 1.2.8 + */ + +/* + gun [ -t ] [ name ... ] + + decompresses the data in the named gzip files. If no arguments are given, + gun will decompress from stdin to stdout. The names must end in .gz, -gz, + .z, -z, _z, or .Z. The uncompressed data will be written to a file name + with the suffix stripped. On success, the original file is deleted. On + failure, the output file is deleted. For most failures, the command will + continue to process the remaining names on the command line. A memory + allocation failure will abort the command. If -t is specified, then the + listed files or stdin will be tested as gzip files for integrity (without + checking for a proper suffix), no output will be written, and no files + will be deleted. + + Like gzip, gun allows concatenated gzip streams and will decompress them, + writing all of the uncompressed data to the output. Unlike gzip, gun allows + an empty file on input, and will produce no error writing an empty output + file. + + gun will also decompress files made by Unix compress, which uses LZW + compression. These files are automatically detected by virtue of their + magic header bytes. Since the end of Unix compress stream is marked by the + end-of-file, they cannot be concantenated. If a Unix compress stream is + encountered in an input file, it is the last stream in that file. + + Like gunzip and uncompress, the file attributes of the original compressed + file are maintained in the final uncompressed file, to the extent that the + user permissions allow it. + + On my Mac OS X PowerPC G4, gun is almost twice as fast as gunzip (version + 1.2.4) is on the same file, when gun is linked with zlib 1.2.2. Also the + LZW decompression provided by gun is about twice as fast as the standard + Unix uncompress command. + */ + +/* external functions and related types and constants */ +#include /* fprintf() */ +#include /* malloc(), free() */ +#include /* strerror(), strcmp(), strlen(), memcpy() */ +#include /* errno */ +#include /* open() */ +#include /* read(), write(), close(), chown(), unlink() */ +#include +#include /* stat(), chmod() */ +#include /* utime() */ +#include "zlib.h" /* inflateBackInit(), inflateBack(), */ + /* inflateBackEnd(), crc32() */ + +/* function declaration */ +#define local static + +/* buffer constants */ +#define SIZE 32768U /* input and output buffer sizes */ +#define PIECE 16384 /* limits i/o chunks for 16-bit int case */ + +/* structure for infback() to pass to input function in() -- it maintains the + input file and a buffer of size SIZE */ +struct ind { + int infile; + unsigned char *inbuf; +}; + +/* Load input buffer, assumed to be empty, and return bytes loaded and a + pointer to them. read() is called until the buffer is full, or until it + returns end-of-file or error. Return 0 on error. */ +local unsigned in(void *in_desc, z_const unsigned char **buf) +{ + int ret; + unsigned len; + unsigned char *next; + struct ind *me = (struct ind *)in_desc; + + next = me->inbuf; + *buf = next; + len = 0; + do { + ret = PIECE; + if ((unsigned)ret > SIZE - len) + ret = (int)(SIZE - len); + ret = (int)read(me->infile, next, ret); + if (ret == -1) { + len = 0; + break; + } + next += ret; + len += ret; + } while (ret != 0 && len < SIZE); + return len; +} + +/* structure for infback() to pass to output function out() -- it maintains the + output file, a running CRC-32 check on the output and the total number of + bytes output, both for checking against the gzip trailer. (The length in + the gzip trailer is stored modulo 2^32, so it's ok if a long is 32 bits and + the output is greater than 4 GB.) */ +struct outd { + int outfile; + int check; /* true if checking crc and total */ + unsigned long crc; + unsigned long total; +}; + +/* Write output buffer and update the CRC-32 and total bytes written. write() + is called until all of the output is written or an error is encountered. + On success out() returns 0. For a write failure, out() returns 1. If the + output file descriptor is -1, then nothing is written. + */ +local int out(void *out_desc, unsigned char *buf, unsigned len) +{ + int ret; + struct outd *me = (struct outd *)out_desc; + + if (me->check) { + me->crc = crc32(me->crc, buf, len); + me->total += len; + } + if (me->outfile != -1) + do { + ret = PIECE; + if ((unsigned)ret > len) + ret = (int)len; + ret = (int)write(me->outfile, buf, ret); + if (ret == -1) + return 1; + buf += ret; + len -= ret; + } while (len != 0); + return 0; +} + +/* next input byte macro for use inside lunpipe() and gunpipe() */ +#define NEXT() (have ? 0 : (have = in(indp, &next)), \ + last = have ? (have--, (int)(*next++)) : -1) + +/* memory for gunpipe() and lunpipe() -- + the first 256 entries of prefix[] and suffix[] are never used, could + have offset the index, but it's faster to waste the memory */ +unsigned char inbuf[SIZE]; /* input buffer */ +unsigned char outbuf[SIZE]; /* output buffer */ +unsigned short prefix[65536]; /* index to LZW prefix string */ +unsigned char suffix[65536]; /* one-character LZW suffix */ +unsigned char match[65280 + 2]; /* buffer for reversed match or gzip + 32K sliding window */ + +/* throw out what's left in the current bits byte buffer (this is a vestigial + aspect of the compressed data format derived from an implementation that + made use of a special VAX machine instruction!) */ +#define FLUSHCODE() \ + do { \ + left = 0; \ + rem = 0; \ + if (chunk > have) { \ + chunk -= have; \ + have = 0; \ + if (NEXT() == -1) \ + break; \ + chunk--; \ + if (chunk > have) { \ + chunk = have = 0; \ + break; \ + } \ + } \ + have -= chunk; \ + next += chunk; \ + chunk = 0; \ + } while (0) + +/* Decompress a compress (LZW) file from indp to outfile. The compress magic + header (two bytes) has already been read and verified. There are have bytes + of buffered input at next. strm is used for passing error information back + to gunpipe(). + + lunpipe() will return Z_OK on success, Z_BUF_ERROR for an unexpected end of + file, read error, or write error (a write error indicated by strm->next_in + not equal to Z_NULL), or Z_DATA_ERROR for invalid input. + */ +local int lunpipe(unsigned have, z_const unsigned char *next, struct ind *indp, + int outfile, z_stream *strm) +{ + int last; /* last byte read by NEXT(), or -1 if EOF */ + unsigned chunk; /* bytes left in current chunk */ + int left; /* bits left in rem */ + unsigned rem; /* unused bits from input */ + int bits; /* current bits per code */ + unsigned code; /* code, table traversal index */ + unsigned mask; /* mask for current bits codes */ + int max; /* maximum bits per code for this stream */ + unsigned flags; /* compress flags, then block compress flag */ + unsigned end; /* last valid entry in prefix/suffix tables */ + unsigned temp; /* current code */ + unsigned prev; /* previous code */ + unsigned final; /* last character written for previous code */ + unsigned stack; /* next position for reversed string */ + unsigned outcnt; /* bytes in output buffer */ + struct outd outd; /* output structure */ + unsigned char *p; + + /* set up output */ + outd.outfile = outfile; + outd.check = 0; + + /* process remainder of compress header -- a flags byte */ + flags = NEXT(); + if (last == -1) + return Z_BUF_ERROR; + if (flags & 0x60) { + strm->msg = (char *)"unknown lzw flags set"; + return Z_DATA_ERROR; + } + max = flags & 0x1f; + if (max < 9 || max > 16) { + strm->msg = (char *)"lzw bits out of range"; + return Z_DATA_ERROR; + } + if (max == 9) /* 9 doesn't really mean 9 */ + max = 10; + flags &= 0x80; /* true if block compress */ + + /* clear table */ + bits = 9; + mask = 0x1ff; + end = flags ? 256 : 255; + + /* set up: get first 9-bit code, which is the first decompressed byte, but + don't create a table entry until the next code */ + if (NEXT() == -1) /* no compressed data is ok */ + return Z_OK; + final = prev = (unsigned)last; /* low 8 bits of code */ + if (NEXT() == -1) /* missing a bit */ + return Z_BUF_ERROR; + if (last & 1) { /* code must be < 256 */ + strm->msg = (char *)"invalid lzw code"; + return Z_DATA_ERROR; + } + rem = (unsigned)last >> 1; /* remaining 7 bits */ + left = 7; + chunk = bits - 2; /* 7 bytes left in this chunk */ + outbuf[0] = (unsigned char)final; /* write first decompressed byte */ + outcnt = 1; + + /* decode codes */ + stack = 0; + for (;;) { + /* if the table will be full after this, increment the code size */ + if (end >= mask && bits < max) { + FLUSHCODE(); + bits++; + mask <<= 1; + mask++; + } + + /* get a code of length bits */ + if (chunk == 0) /* decrement chunk modulo bits */ + chunk = bits; + code = rem; /* low bits of code */ + if (NEXT() == -1) { /* EOF is end of compressed data */ + /* write remaining buffered output */ + if (outcnt && out(&outd, outbuf, outcnt)) { + strm->next_in = outbuf; /* signal write error */ + return Z_BUF_ERROR; + } + return Z_OK; + } + code += (unsigned)last << left; /* middle (or high) bits of code */ + left += 8; + chunk--; + if (bits > left) { /* need more bits */ + if (NEXT() == -1) /* can't end in middle of code */ + return Z_BUF_ERROR; + code += (unsigned)last << left; /* high bits of code */ + left += 8; + chunk--; + } + code &= mask; /* mask to current code length */ + left -= bits; /* number of unused bits */ + rem = (unsigned)last >> (8 - left); /* unused bits from last byte */ + + /* process clear code (256) */ + if (code == 256 && flags) { + FLUSHCODE(); + bits = 9; /* initialize bits and mask */ + mask = 0x1ff; + end = 255; /* empty table */ + continue; /* get next code */ + } + + /* special code to reuse last match */ + temp = code; /* save the current code */ + if (code > end) { + /* Be picky on the allowed code here, and make sure that the code + we drop through (prev) will be a valid index so that random + input does not cause an exception. The code != end + 1 check is + empirically derived, and not checked in the original uncompress + code. If this ever causes a problem, that check could be safely + removed. Leaving this check in greatly improves gun's ability + to detect random or corrupted input after a compress header. + In any case, the prev > end check must be retained. */ + if (code != end + 1 || prev > end) { + strm->msg = (char *)"invalid lzw code"; + return Z_DATA_ERROR; + } + match[stack++] = (unsigned char)final; + code = prev; + } + + /* walk through linked list to generate output in reverse order */ + p = match + stack; + while (code >= 256) { + *p++ = suffix[code]; + code = prefix[code]; + } + stack = p - match; + match[stack++] = (unsigned char)code; + final = code; + + /* link new table entry */ + if (end < mask) { + end++; + prefix[end] = (unsigned short)prev; + suffix[end] = (unsigned char)final; + } + + /* set previous code for next iteration */ + prev = temp; + + /* write output in forward order */ + while (stack > SIZE - outcnt) { + while (outcnt < SIZE) + outbuf[outcnt++] = match[--stack]; + if (out(&outd, outbuf, outcnt)) { + strm->next_in = outbuf; /* signal write error */ + return Z_BUF_ERROR; + } + outcnt = 0; + } + p = match + stack; + do { + outbuf[outcnt++] = *--p; + } while (p > match); + stack = 0; + + /* loop for next code with final and prev as the last match, rem and + left provide the first 0..7 bits of the next code, end is the last + valid table entry */ + } +} + +/* Decompress a gzip file from infile to outfile. strm is assumed to have been + successfully initialized with inflateBackInit(). The input file may consist + of a series of gzip streams, in which case all of them will be decompressed + to the output file. If outfile is -1, then the gzip stream(s) integrity is + checked and nothing is written. + + The return value is a zlib error code: Z_MEM_ERROR if out of memory, + Z_DATA_ERROR if the header or the compressed data is invalid, or if the + trailer CRC-32 check or length doesn't match, Z_BUF_ERROR if the input ends + prematurely or a write error occurs, or Z_ERRNO if junk (not a another gzip + stream) follows a valid gzip stream. + */ +local int gunpipe(z_stream *strm, int infile, int outfile) +{ + int ret, first, last; + unsigned have, flags, len; + z_const unsigned char *next = NULL; + struct ind ind, *indp; + struct outd outd; + + /* setup input buffer */ + ind.infile = infile; + ind.inbuf = inbuf; + indp = &ind; + + /* decompress concatenated gzip streams */ + have = 0; /* no input data read in yet */ + first = 1; /* looking for first gzip header */ + strm->next_in = Z_NULL; /* so Z_BUF_ERROR means EOF */ + for (;;) { + /* look for the two magic header bytes for a gzip stream */ + if (NEXT() == -1) { + ret = Z_OK; + break; /* empty gzip stream is ok */ + } + if (last != 31 || (NEXT() != 139 && last != 157)) { + strm->msg = (char *)"incorrect header check"; + ret = first ? Z_DATA_ERROR : Z_ERRNO; + break; /* not a gzip or compress header */ + } + first = 0; /* next non-header is junk */ + + /* process a compress (LZW) file -- can't be concatenated after this */ + if (last == 157) { + ret = lunpipe(have, next, indp, outfile, strm); + break; + } + + /* process remainder of gzip header */ + ret = Z_BUF_ERROR; + if (NEXT() != 8) { /* only deflate method allowed */ + if (last == -1) break; + strm->msg = (char *)"unknown compression method"; + ret = Z_DATA_ERROR; + break; + } + flags = NEXT(); /* header flags */ + NEXT(); /* discard mod time, xflgs, os */ + NEXT(); + NEXT(); + NEXT(); + NEXT(); + NEXT(); + if (last == -1) break; + if (flags & 0xe0) { + strm->msg = (char *)"unknown header flags set"; + ret = Z_DATA_ERROR; + break; + } + if (flags & 4) { /* extra field */ + len = NEXT(); + len += (unsigned)(NEXT()) << 8; + if (last == -1) break; + while (len > have) { + len -= have; + have = 0; + if (NEXT() == -1) break; + len--; + } + if (last == -1) break; + have -= len; + next += len; + } + if (flags & 8) /* file name */ + while (NEXT() != 0 && last != -1) + ; + if (flags & 16) /* comment */ + while (NEXT() != 0 && last != -1) + ; + if (flags & 2) { /* header crc */ + NEXT(); + NEXT(); + } + if (last == -1) break; + + /* set up output */ + outd.outfile = outfile; + outd.check = 1; + outd.crc = crc32(0L, Z_NULL, 0); + outd.total = 0; + + /* decompress data to output */ + strm->next_in = next; + strm->avail_in = have; + ret = inflateBack(strm, in, indp, out, &outd); + if (ret != Z_STREAM_END) break; + next = strm->next_in; + have = strm->avail_in; + strm->next_in = Z_NULL; /* so Z_BUF_ERROR means EOF */ + + /* check trailer */ + ret = Z_BUF_ERROR; + if (NEXT() != (int)(outd.crc & 0xff) || + NEXT() != (int)((outd.crc >> 8) & 0xff) || + NEXT() != (int)((outd.crc >> 16) & 0xff) || + NEXT() != (int)((outd.crc >> 24) & 0xff)) { + /* crc error */ + if (last != -1) { + strm->msg = (char *)"incorrect data check"; + ret = Z_DATA_ERROR; + } + break; + } + if (NEXT() != (int)(outd.total & 0xff) || + NEXT() != (int)((outd.total >> 8) & 0xff) || + NEXT() != (int)((outd.total >> 16) & 0xff) || + NEXT() != (int)((outd.total >> 24) & 0xff)) { + /* length error */ + if (last != -1) { + strm->msg = (char *)"incorrect length check"; + ret = Z_DATA_ERROR; + } + break; + } + + /* go back and look for another gzip stream */ + } + + /* clean up and return */ + return ret; +} + +/* Copy file attributes, from -> to, as best we can. This is best effort, so + no errors are reported. The mode bits, including suid, sgid, and the sticky + bit are copied (if allowed), the owner's user id and group id are copied + (again if allowed), and the access and modify times are copied. */ +local void copymeta(char *from, char *to) +{ + struct stat was; + struct utimbuf when; + + /* get all of from's Unix meta data, return if not a regular file */ + if (stat(from, &was) != 0 || (was.st_mode & S_IFMT) != S_IFREG) + return; + + /* set to's mode bits, ignore errors */ + (void)chmod(to, was.st_mode & 07777); + + /* copy owner's user and group, ignore errors */ + (void)chown(to, was.st_uid, was.st_gid); + + /* copy access and modify times, ignore errors */ + when.actime = was.st_atime; + when.modtime = was.st_mtime; + (void)utime(to, &when); +} + +/* Decompress the file inname to the file outnname, of if test is true, just + decompress without writing and check the gzip trailer for integrity. If + inname is NULL or an empty string, read from stdin. If outname is NULL or + an empty string, write to stdout. strm is a pre-initialized inflateBack + structure. When appropriate, copy the file attributes from inname to + outname. + + gunzip() returns 1 if there is an out-of-memory error or an unexpected + return code from gunpipe(). Otherwise it returns 0. + */ +local int gunzip(z_stream *strm, char *inname, char *outname, int test) +{ + int ret; + int infile, outfile; + + /* open files */ + if (inname == NULL || *inname == 0) { + inname = "-"; + infile = 0; /* stdin */ + } + else { + infile = open(inname, O_RDONLY, 0); + if (infile == -1) { + fprintf(stderr, "gun cannot open %s\n", inname); + return 0; + } + } + if (test) + outfile = -1; + else if (outname == NULL || *outname == 0) { + outname = "-"; + outfile = 1; /* stdout */ + } + else { + outfile = open(outname, O_CREAT | O_TRUNC | O_WRONLY, 0666); + if (outfile == -1) { + close(infile); + fprintf(stderr, "gun cannot create %s\n", outname); + return 0; + } + } + errno = 0; + + /* decompress */ + ret = gunpipe(strm, infile, outfile); + if (outfile > 2) close(outfile); + if (infile > 2) close(infile); + + /* interpret result */ + switch (ret) { + case Z_OK: + case Z_ERRNO: + if (infile > 2 && outfile > 2) { + copymeta(inname, outname); /* copy attributes */ + unlink(inname); + } + if (ret == Z_ERRNO) + fprintf(stderr, "gun warning: trailing garbage ignored in %s\n", + inname); + break; + case Z_DATA_ERROR: + if (outfile > 2) unlink(outname); + fprintf(stderr, "gun data error on %s: %s\n", inname, strm->msg); + break; + case Z_MEM_ERROR: + if (outfile > 2) unlink(outname); + fprintf(stderr, "gun out of memory error--aborting\n"); + return 1; + case Z_BUF_ERROR: + if (outfile > 2) unlink(outname); + if (strm->next_in != Z_NULL) { + fprintf(stderr, "gun write error on %s: %s\n", + outname, strerror(errno)); + } + else if (errno) { + fprintf(stderr, "gun read error on %s: %s\n", + inname, strerror(errno)); + } + else { + fprintf(stderr, "gun unexpected end of file on %s\n", + inname); + } + break; + default: + if (outfile > 2) unlink(outname); + fprintf(stderr, "gun internal error--aborting\n"); + return 1; + } + return 0; +} + +/* Process the gun command line arguments. See the command syntax near the + beginning of this source file. */ +int main(int argc, char **argv) +{ + int ret, len, test; + char *outname; + unsigned char *window; + z_stream strm; + + /* initialize inflateBack state for repeated use */ + window = match; /* reuse LZW match buffer */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + ret = inflateBackInit(&strm, 15, window); + if (ret != Z_OK) { + fprintf(stderr, "gun out of memory error--aborting\n"); + return 1; + } + + /* decompress each file to the same name with the suffix removed */ + argc--; + argv++; + test = 0; + if (argc && strcmp(*argv, "-h") == 0) { + fprintf(stderr, "gun 1.6 (17 Jan 2010)\n"); + fprintf(stderr, "Copyright (C) 2003-2010 Mark Adler\n"); + fprintf(stderr, "usage: gun [-t] [file1.gz [file2.Z ...]]\n"); + return 0; + } + if (argc && strcmp(*argv, "-t") == 0) { + test = 1; + argc--; + argv++; + } + if (argc) + do { + if (test) + outname = NULL; + else { + len = (int)strlen(*argv); + if (strcmp(*argv + len - 3, ".gz") == 0 || + strcmp(*argv + len - 3, "-gz") == 0) + len -= 3; + else if (strcmp(*argv + len - 2, ".z") == 0 || + strcmp(*argv + len - 2, "-z") == 0 || + strcmp(*argv + len - 2, "_z") == 0 || + strcmp(*argv + len - 2, ".Z") == 0) + len -= 2; + else { + fprintf(stderr, "gun error: no gz type on %s--skipping\n", + *argv); + continue; + } + outname = malloc(len + 1); + if (outname == NULL) { + fprintf(stderr, "gun out of memory error--aborting\n"); + ret = 1; + break; + } + memcpy(outname, *argv, len); + outname[len] = 0; + } + ret = gunzip(&strm, *argv, outname, test); + if (outname != NULL) free(outname); + if (ret) break; + } while (argv++, --argc); + else + ret = gunzip(&strm, NULL, NULL, test); + + /* clean up */ + inflateBackEnd(&strm); + return ret; +} diff --git a/contrib/zlib/examples/gzappend.c b/contrib/zlib/examples/gzappend.c new file mode 100644 index 00000000..662dec37 --- /dev/null +++ b/contrib/zlib/examples/gzappend.c @@ -0,0 +1,504 @@ +/* gzappend -- command to append to a gzip file + + Copyright (C) 2003, 2012 Mark Adler, all rights reserved + version 1.2, 11 Oct 2012 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler madler@alumni.caltech.edu + */ + +/* + * Change history: + * + * 1.0 19 Oct 2003 - First version + * 1.1 4 Nov 2003 - Expand and clarify some comments and notes + * - Add version and copyright to help + * - Send help to stdout instead of stderr + * - Add some preemptive typecasts + * - Add L to constants in lseek() calls + * - Remove some debugging information in error messages + * - Use new data_type definition for zlib 1.2.1 + * - Simplfy and unify file operations + * - Finish off gzip file in gztack() + * - Use deflatePrime() instead of adding empty blocks + * - Keep gzip file clean on appended file read errors + * - Use in-place rotate instead of auxiliary buffer + * (Why you ask? Because it was fun to write!) + * 1.2 11 Oct 2012 - Fix for proper z_const usage + * - Check for input buffer malloc failure + */ + +/* + gzappend takes a gzip file and appends to it, compressing files from the + command line or data from stdin. The gzip file is written to directly, to + avoid copying that file, in case it's large. Note that this results in the + unfriendly behavior that if gzappend fails, the gzip file is corrupted. + + This program was written to illustrate the use of the new Z_BLOCK option of + zlib 1.2.x's inflate() function. This option returns from inflate() at each + block boundary to facilitate locating and modifying the last block bit at + the start of the final deflate block. Also whether using Z_BLOCK or not, + another required feature of zlib 1.2.x is that inflate() now provides the + number of unusued bits in the last input byte used. gzappend will not work + with versions of zlib earlier than 1.2.1. + + gzappend first decompresses the gzip file internally, discarding all but + the last 32K of uncompressed data, and noting the location of the last block + bit and the number of unused bits in the last byte of the compressed data. + The gzip trailer containing the CRC-32 and length of the uncompressed data + is verified. This trailer will be later overwritten. + + Then the last block bit is cleared by seeking back in the file and rewriting + the byte that contains it. Seeking forward, the last byte of the compressed + data is saved along with the number of unused bits to initialize deflate. + + A deflate process is initialized, using the last 32K of the uncompressed + data from the gzip file to initialize the dictionary. If the total + uncompressed data was less than 32K, then all of it is used to initialize + the dictionary. The deflate output bit buffer is also initialized with the + last bits from the original deflate stream. From here on, the data to + append is simply compressed using deflate, and written to the gzip file. + When that is complete, the new CRC-32 and uncompressed length are written + as the trailer of the gzip file. + */ + +#include +#include +#include +#include +#include +#include "zlib.h" + +#define local static +#define LGCHUNK 14 +#define CHUNK (1U << LGCHUNK) +#define DSIZE 32768U + +/* print an error message and terminate with extreme prejudice */ +local void bye(char *msg1, char *msg2) +{ + fprintf(stderr, "gzappend error: %s%s\n", msg1, msg2); + exit(1); +} + +/* return the greatest common divisor of a and b using Euclid's algorithm, + modified to be fast when one argument much greater than the other, and + coded to avoid unnecessary swapping */ +local unsigned gcd(unsigned a, unsigned b) +{ + unsigned c; + + while (a && b) + if (a > b) { + c = b; + while (a - c >= c) + c <<= 1; + a -= c; + } + else { + c = a; + while (b - c >= c) + c <<= 1; + b -= c; + } + return a + b; +} + +/* rotate list[0..len-1] left by rot positions, in place */ +local void rotate(unsigned char *list, unsigned len, unsigned rot) +{ + unsigned char tmp; + unsigned cycles; + unsigned char *start, *last, *to, *from; + + /* normalize rot and handle degenerate cases */ + if (len < 2) return; + if (rot >= len) rot %= len; + if (rot == 0) return; + + /* pointer to last entry in list */ + last = list + (len - 1); + + /* do simple left shift by one */ + if (rot == 1) { + tmp = *list; + memcpy(list, list + 1, len - 1); + *last = tmp; + return; + } + + /* do simple right shift by one */ + if (rot == len - 1) { + tmp = *last; + memmove(list + 1, list, len - 1); + *list = tmp; + return; + } + + /* otherwise do rotate as a set of cycles in place */ + cycles = gcd(len, rot); /* number of cycles */ + do { + start = from = list + cycles; /* start index is arbitrary */ + tmp = *from; /* save entry to be overwritten */ + for (;;) { + to = from; /* next step in cycle */ + from += rot; /* go right rot positions */ + if (from > last) from -= len; /* (pointer better not wrap) */ + if (from == start) break; /* all but one shifted */ + *to = *from; /* shift left */ + } + *to = tmp; /* complete the circle */ + } while (--cycles); +} + +/* structure for gzip file read operations */ +typedef struct { + int fd; /* file descriptor */ + int size; /* 1 << size is bytes in buf */ + unsigned left; /* bytes available at next */ + unsigned char *buf; /* buffer */ + z_const unsigned char *next; /* next byte in buffer */ + char *name; /* file name for error messages */ +} file; + +/* reload buffer */ +local int readin(file *in) +{ + int len; + + len = read(in->fd, in->buf, 1 << in->size); + if (len == -1) bye("error reading ", in->name); + in->left = (unsigned)len; + in->next = in->buf; + return len; +} + +/* read from file in, exit if end-of-file */ +local int readmore(file *in) +{ + if (readin(in) == 0) bye("unexpected end of ", in->name); + return 0; +} + +#define read1(in) (in->left == 0 ? readmore(in) : 0, \ + in->left--, *(in->next)++) + +/* skip over n bytes of in */ +local void skip(file *in, unsigned n) +{ + unsigned bypass; + + if (n > in->left) { + n -= in->left; + bypass = n & ~((1U << in->size) - 1); + if (bypass) { + if (lseek(in->fd, (off_t)bypass, SEEK_CUR) == -1) + bye("seeking ", in->name); + n -= bypass; + } + readmore(in); + if (n > in->left) + bye("unexpected end of ", in->name); + } + in->left -= n; + in->next += n; +} + +/* read a four-byte unsigned integer, little-endian, from in */ +unsigned long read4(file *in) +{ + unsigned long val; + + val = read1(in); + val += (unsigned)read1(in) << 8; + val += (unsigned long)read1(in) << 16; + val += (unsigned long)read1(in) << 24; + return val; +} + +/* skip over gzip header */ +local void gzheader(file *in) +{ + int flags; + unsigned n; + + if (read1(in) != 31 || read1(in) != 139) bye(in->name, " not a gzip file"); + if (read1(in) != 8) bye("unknown compression method in", in->name); + flags = read1(in); + if (flags & 0xe0) bye("unknown header flags set in", in->name); + skip(in, 6); + if (flags & 4) { + n = read1(in); + n += (unsigned)(read1(in)) << 8; + skip(in, n); + } + if (flags & 8) while (read1(in) != 0) ; + if (flags & 16) while (read1(in) != 0) ; + if (flags & 2) skip(in, 2); +} + +/* decompress gzip file "name", return strm with a deflate stream ready to + continue compression of the data in the gzip file, and return a file + descriptor pointing to where to write the compressed data -- the deflate + stream is initialized to compress using level "level" */ +local int gzscan(char *name, z_stream *strm, int level) +{ + int ret, lastbit, left, full; + unsigned have; + unsigned long crc, tot; + unsigned char *window; + off_t lastoff, end; + file gz; + + /* open gzip file */ + gz.name = name; + gz.fd = open(name, O_RDWR, 0); + if (gz.fd == -1) bye("cannot open ", name); + gz.buf = malloc(CHUNK); + if (gz.buf == NULL) bye("out of memory", ""); + gz.size = LGCHUNK; + gz.left = 0; + + /* skip gzip header */ + gzheader(&gz); + + /* prepare to decompress */ + window = malloc(DSIZE); + if (window == NULL) bye("out of memory", ""); + strm->zalloc = Z_NULL; + strm->zfree = Z_NULL; + strm->opaque = Z_NULL; + ret = inflateInit2(strm, -15); + if (ret != Z_OK) bye("out of memory", " or library mismatch"); + + /* decompress the deflate stream, saving append information */ + lastbit = 0; + lastoff = lseek(gz.fd, 0L, SEEK_CUR) - gz.left; + left = 0; + strm->avail_in = gz.left; + strm->next_in = gz.next; + crc = crc32(0L, Z_NULL, 0); + have = full = 0; + do { + /* if needed, get more input */ + if (strm->avail_in == 0) { + readmore(&gz); + strm->avail_in = gz.left; + strm->next_in = gz.next; + } + + /* set up output to next available section of sliding window */ + strm->avail_out = DSIZE - have; + strm->next_out = window + have; + + /* inflate and check for errors */ + ret = inflate(strm, Z_BLOCK); + if (ret == Z_STREAM_ERROR) bye("internal stream error!", ""); + if (ret == Z_MEM_ERROR) bye("out of memory", ""); + if (ret == Z_DATA_ERROR) + bye("invalid compressed data--format violated in", name); + + /* update crc and sliding window pointer */ + crc = crc32(crc, window + have, DSIZE - have - strm->avail_out); + if (strm->avail_out) + have = DSIZE - strm->avail_out; + else { + have = 0; + full = 1; + } + + /* process end of block */ + if (strm->data_type & 128) { + if (strm->data_type & 64) + left = strm->data_type & 0x1f; + else { + lastbit = strm->data_type & 0x1f; + lastoff = lseek(gz.fd, 0L, SEEK_CUR) - strm->avail_in; + } + } + } while (ret != Z_STREAM_END); + inflateEnd(strm); + gz.left = strm->avail_in; + gz.next = strm->next_in; + + /* save the location of the end of the compressed data */ + end = lseek(gz.fd, 0L, SEEK_CUR) - gz.left; + + /* check gzip trailer and save total for deflate */ + if (crc != read4(&gz)) + bye("invalid compressed data--crc mismatch in ", name); + tot = strm->total_out; + if ((tot & 0xffffffffUL) != read4(&gz)) + bye("invalid compressed data--length mismatch in", name); + + /* if not at end of file, warn */ + if (gz.left || readin(&gz)) + fprintf(stderr, + "gzappend warning: junk at end of gzip file overwritten\n"); + + /* clear last block bit */ + lseek(gz.fd, lastoff - (lastbit != 0), SEEK_SET); + if (read(gz.fd, gz.buf, 1) != 1) bye("reading after seek on ", name); + *gz.buf = (unsigned char)(*gz.buf ^ (1 << ((8 - lastbit) & 7))); + lseek(gz.fd, -1L, SEEK_CUR); + if (write(gz.fd, gz.buf, 1) != 1) bye("writing after seek to ", name); + + /* if window wrapped, build dictionary from window by rotating */ + if (full) { + rotate(window, DSIZE, have); + have = DSIZE; + } + + /* set up deflate stream with window, crc, total_in, and leftover bits */ + ret = deflateInit2(strm, level, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); + if (ret != Z_OK) bye("out of memory", ""); + deflateSetDictionary(strm, window, have); + strm->adler = crc; + strm->total_in = tot; + if (left) { + lseek(gz.fd, --end, SEEK_SET); + if (read(gz.fd, gz.buf, 1) != 1) bye("reading after seek on ", name); + deflatePrime(strm, 8 - left, *gz.buf); + } + lseek(gz.fd, end, SEEK_SET); + + /* clean up and return */ + free(window); + free(gz.buf); + return gz.fd; +} + +/* append file "name" to gzip file gd using deflate stream strm -- if last + is true, then finish off the deflate stream at the end */ +local void gztack(char *name, int gd, z_stream *strm, int last) +{ + int fd, len, ret; + unsigned left; + unsigned char *in, *out; + + /* open file to compress and append */ + fd = 0; + if (name != NULL) { + fd = open(name, O_RDONLY, 0); + if (fd == -1) + fprintf(stderr, "gzappend warning: %s not found, skipping ...\n", + name); + } + + /* allocate buffers */ + in = malloc(CHUNK); + out = malloc(CHUNK); + if (in == NULL || out == NULL) bye("out of memory", ""); + + /* compress input file and append to gzip file */ + do { + /* get more input */ + len = read(fd, in, CHUNK); + if (len == -1) { + fprintf(stderr, + "gzappend warning: error reading %s, skipping rest ...\n", + name); + len = 0; + } + strm->avail_in = (unsigned)len; + strm->next_in = in; + if (len) strm->adler = crc32(strm->adler, in, (unsigned)len); + + /* compress and write all available output */ + do { + strm->avail_out = CHUNK; + strm->next_out = out; + ret = deflate(strm, last && len == 0 ? Z_FINISH : Z_NO_FLUSH); + left = CHUNK - strm->avail_out; + while (left) { + len = write(gd, out + CHUNK - strm->avail_out - left, left); + if (len == -1) bye("writing gzip file", ""); + left -= (unsigned)len; + } + } while (strm->avail_out == 0 && ret != Z_STREAM_END); + } while (len != 0); + + /* write trailer after last entry */ + if (last) { + deflateEnd(strm); + out[0] = (unsigned char)(strm->adler); + out[1] = (unsigned char)(strm->adler >> 8); + out[2] = (unsigned char)(strm->adler >> 16); + out[3] = (unsigned char)(strm->adler >> 24); + out[4] = (unsigned char)(strm->total_in); + out[5] = (unsigned char)(strm->total_in >> 8); + out[6] = (unsigned char)(strm->total_in >> 16); + out[7] = (unsigned char)(strm->total_in >> 24); + len = 8; + do { + ret = write(gd, out + 8 - len, len); + if (ret == -1) bye("writing gzip file", ""); + len -= ret; + } while (len); + close(gd); + } + + /* clean up and return */ + free(out); + free(in); + if (fd > 0) close(fd); +} + +/* process the compression level option if present, scan the gzip file, and + append the specified files, or append the data from stdin if no other file + names are provided on the command line -- the gzip file must be writable + and seekable */ +int main(int argc, char **argv) +{ + int gd, level; + z_stream strm; + + /* ignore command name */ + argc--; argv++; + + /* provide usage if no arguments */ + if (*argv == NULL) { + printf( + "gzappend 1.2 (11 Oct 2012) Copyright (C) 2003, 2012 Mark Adler\n" + ); + printf( + "usage: gzappend [-level] file.gz [ addthis [ andthis ... ]]\n"); + return 0; + } + + /* set compression level */ + level = Z_DEFAULT_COMPRESSION; + if (argv[0][0] == '-') { + if (argv[0][1] < '0' || argv[0][1] > '9' || argv[0][2] != 0) + bye("invalid compression level", ""); + level = argv[0][1] - '0'; + if (*++argv == NULL) bye("no gzip file name after options", ""); + } + + /* prepare to append to gzip file */ + gd = gzscan(*argv++, &strm, level); + + /* append files on command line, or from stdin if none */ + if (*argv == NULL) + gztack(NULL, gd, &strm, 1); + else + do { + gztack(*argv, gd, &strm, argv[1] == NULL); + } while (*++argv != NULL); + return 0; +} diff --git a/contrib/zlib/examples/gzjoin.c b/contrib/zlib/examples/gzjoin.c new file mode 100644 index 00000000..89e80984 --- /dev/null +++ b/contrib/zlib/examples/gzjoin.c @@ -0,0 +1,449 @@ +/* gzjoin -- command to join gzip files into one gzip file + + Copyright (C) 2004, 2005, 2012 Mark Adler, all rights reserved + version 1.2, 14 Aug 2012 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler madler@alumni.caltech.edu + */ + +/* + * Change history: + * + * 1.0 11 Dec 2004 - First version + * 1.1 12 Jun 2005 - Changed ssize_t to long for portability + * 1.2 14 Aug 2012 - Clean up for z_const usage + */ + +/* + gzjoin takes one or more gzip files on the command line and writes out a + single gzip file that will uncompress to the concatenation of the + uncompressed data from the individual gzip files. gzjoin does this without + having to recompress any of the data and without having to calculate a new + crc32 for the concatenated uncompressed data. gzjoin does however have to + decompress all of the input data in order to find the bits in the compressed + data that need to be modified to concatenate the streams. + + gzjoin does not do an integrity check on the input gzip files other than + checking the gzip header and decompressing the compressed data. They are + otherwise assumed to be complete and correct. + + Each joint between gzip files removes at least 18 bytes of previous trailer + and subsequent header, and inserts an average of about three bytes to the + compressed data in order to connect the streams. The output gzip file + has a minimal ten-byte gzip header with no file name or modification time. + + This program was written to illustrate the use of the Z_BLOCK option of + inflate() and the crc32_combine() function. gzjoin will not compile with + versions of zlib earlier than 1.2.3. + */ + +#include /* fputs(), fprintf(), fwrite(), putc() */ +#include /* exit(), malloc(), free() */ +#include /* open() */ +#include /* close(), read(), lseek() */ +#include "zlib.h" + /* crc32(), crc32_combine(), inflateInit2(), inflate(), inflateEnd() */ + +#define local static + +/* exit with an error (return a value to allow use in an expression) */ +local int bail(char *why1, char *why2) +{ + fprintf(stderr, "gzjoin error: %s%s, output incomplete\n", why1, why2); + exit(1); + return 0; +} + +/* -- simple buffered file input with access to the buffer -- */ + +#define CHUNK 32768 /* must be a power of two and fit in unsigned */ + +/* bin buffered input file type */ +typedef struct { + char *name; /* name of file for error messages */ + int fd; /* file descriptor */ + unsigned left; /* bytes remaining at next */ + unsigned char *next; /* next byte to read */ + unsigned char *buf; /* allocated buffer of length CHUNK */ +} bin; + +/* close a buffered file and free allocated memory */ +local void bclose(bin *in) +{ + if (in != NULL) { + if (in->fd != -1) + close(in->fd); + if (in->buf != NULL) + free(in->buf); + free(in); + } +} + +/* open a buffered file for input, return a pointer to type bin, or NULL on + failure */ +local bin *bopen(char *name) +{ + bin *in; + + in = malloc(sizeof(bin)); + if (in == NULL) + return NULL; + in->buf = malloc(CHUNK); + in->fd = open(name, O_RDONLY, 0); + if (in->buf == NULL || in->fd == -1) { + bclose(in); + return NULL; + } + in->left = 0; + in->next = in->buf; + in->name = name; + return in; +} + +/* load buffer from file, return -1 on read error, 0 or 1 on success, with + 1 indicating that end-of-file was reached */ +local int bload(bin *in) +{ + long len; + + if (in == NULL) + return -1; + if (in->left != 0) + return 0; + in->next = in->buf; + do { + len = (long)read(in->fd, in->buf + in->left, CHUNK - in->left); + if (len < 0) + return -1; + in->left += (unsigned)len; + } while (len != 0 && in->left < CHUNK); + return len == 0 ? 1 : 0; +} + +/* get a byte from the file, bail if end of file */ +#define bget(in) (in->left ? 0 : bload(in), \ + in->left ? (in->left--, *(in->next)++) : \ + bail("unexpected end of file on ", in->name)) + +/* get a four-byte little-endian unsigned integer from file */ +local unsigned long bget4(bin *in) +{ + unsigned long val; + + val = bget(in); + val += (unsigned long)(bget(in)) << 8; + val += (unsigned long)(bget(in)) << 16; + val += (unsigned long)(bget(in)) << 24; + return val; +} + +/* skip bytes in file */ +local void bskip(bin *in, unsigned skip) +{ + /* check pointer */ + if (in == NULL) + return; + + /* easy case -- skip bytes in buffer */ + if (skip <= in->left) { + in->left -= skip; + in->next += skip; + return; + } + + /* skip what's in buffer, discard buffer contents */ + skip -= in->left; + in->left = 0; + + /* seek past multiples of CHUNK bytes */ + if (skip > CHUNK) { + unsigned left; + + left = skip & (CHUNK - 1); + if (left == 0) { + /* exact number of chunks: seek all the way minus one byte to check + for end-of-file with a read */ + lseek(in->fd, skip - 1, SEEK_CUR); + if (read(in->fd, in->buf, 1) != 1) + bail("unexpected end of file on ", in->name); + return; + } + + /* skip the integral chunks, update skip with remainder */ + lseek(in->fd, skip - left, SEEK_CUR); + skip = left; + } + + /* read more input and skip remainder */ + bload(in); + if (skip > in->left) + bail("unexpected end of file on ", in->name); + in->left -= skip; + in->next += skip; +} + +/* -- end of buffered input functions -- */ + +/* skip the gzip header from file in */ +local void gzhead(bin *in) +{ + int flags; + + /* verify gzip magic header and compression method */ + if (bget(in) != 0x1f || bget(in) != 0x8b || bget(in) != 8) + bail(in->name, " is not a valid gzip file"); + + /* get and verify flags */ + flags = bget(in); + if ((flags & 0xe0) != 0) + bail("unknown reserved bits set in ", in->name); + + /* skip modification time, extra flags, and os */ + bskip(in, 6); + + /* skip extra field if present */ + if (flags & 4) { + unsigned len; + + len = bget(in); + len += (unsigned)(bget(in)) << 8; + bskip(in, len); + } + + /* skip file name if present */ + if (flags & 8) + while (bget(in) != 0) + ; + + /* skip comment if present */ + if (flags & 16) + while (bget(in) != 0) + ; + + /* skip header crc if present */ + if (flags & 2) + bskip(in, 2); +} + +/* write a four-byte little-endian unsigned integer to out */ +local void put4(unsigned long val, FILE *out) +{ + putc(val & 0xff, out); + putc((val >> 8) & 0xff, out); + putc((val >> 16) & 0xff, out); + putc((val >> 24) & 0xff, out); +} + +/* Load up zlib stream from buffered input, bail if end of file */ +local void zpull(z_streamp strm, bin *in) +{ + if (in->left == 0) + bload(in); + if (in->left == 0) + bail("unexpected end of file on ", in->name); + strm->avail_in = in->left; + strm->next_in = in->next; +} + +/* Write header for gzip file to out and initialize trailer. */ +local void gzinit(unsigned long *crc, unsigned long *tot, FILE *out) +{ + fwrite("\x1f\x8b\x08\0\0\0\0\0\0\xff", 1, 10, out); + *crc = crc32(0L, Z_NULL, 0); + *tot = 0; +} + +/* Copy the compressed data from name, zeroing the last block bit of the last + block if clr is true, and adding empty blocks as needed to get to a byte + boundary. If clr is false, then the last block becomes the last block of + the output, and the gzip trailer is written. crc and tot maintains the + crc and length (modulo 2^32) of the output for the trailer. The resulting + gzip file is written to out. gzinit() must be called before the first call + of gzcopy() to write the gzip header and to initialize crc and tot. */ +local void gzcopy(char *name, int clr, unsigned long *crc, unsigned long *tot, + FILE *out) +{ + int ret; /* return value from zlib functions */ + int pos; /* where the "last block" bit is in byte */ + int last; /* true if processing the last block */ + bin *in; /* buffered input file */ + unsigned char *start; /* start of compressed data in buffer */ + unsigned char *junk; /* buffer for uncompressed data -- discarded */ + z_off_t len; /* length of uncompressed data (support > 4 GB) */ + z_stream strm; /* zlib inflate stream */ + + /* open gzip file and skip header */ + in = bopen(name); + if (in == NULL) + bail("could not open ", name); + gzhead(in); + + /* allocate buffer for uncompressed data and initialize raw inflate + stream */ + junk = malloc(CHUNK); + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit2(&strm, -15); + if (junk == NULL || ret != Z_OK) + bail("out of memory", ""); + + /* inflate and copy compressed data, clear last-block bit if requested */ + len = 0; + zpull(&strm, in); + start = in->next; + last = start[0] & 1; + if (last && clr) + start[0] &= ~1; + strm.avail_out = 0; + for (;;) { + /* if input used and output done, write used input and get more */ + if (strm.avail_in == 0 && strm.avail_out != 0) { + fwrite(start, 1, strm.next_in - start, out); + start = in->buf; + in->left = 0; + zpull(&strm, in); + } + + /* decompress -- return early when end-of-block reached */ + strm.avail_out = CHUNK; + strm.next_out = junk; + ret = inflate(&strm, Z_BLOCK); + switch (ret) { + case Z_MEM_ERROR: + bail("out of memory", ""); + case Z_DATA_ERROR: + bail("invalid compressed data in ", in->name); + } + + /* update length of uncompressed data */ + len += CHUNK - strm.avail_out; + + /* check for block boundary (only get this when block copied out) */ + if (strm.data_type & 128) { + /* if that was the last block, then done */ + if (last) + break; + + /* number of unused bits in last byte */ + pos = strm.data_type & 7; + + /* find the next last-block bit */ + if (pos != 0) { + /* next last-block bit is in last used byte */ + pos = 0x100 >> pos; + last = strm.next_in[-1] & pos; + if (last && clr) + in->buf[strm.next_in - in->buf - 1] &= ~pos; + } + else { + /* next last-block bit is in next unused byte */ + if (strm.avail_in == 0) { + /* don't have that byte yet -- get it */ + fwrite(start, 1, strm.next_in - start, out); + start = in->buf; + in->left = 0; + zpull(&strm, in); + } + last = strm.next_in[0] & 1; + if (last && clr) + in->buf[strm.next_in - in->buf] &= ~1; + } + } + } + + /* update buffer with unused input */ + in->left = strm.avail_in; + in->next = in->buf + (strm.next_in - in->buf); + + /* copy used input, write empty blocks to get to byte boundary */ + pos = strm.data_type & 7; + fwrite(start, 1, in->next - start - 1, out); + last = in->next[-1]; + if (pos == 0 || !clr) + /* already at byte boundary, or last file: write last byte */ + putc(last, out); + else { + /* append empty blocks to last byte */ + last &= ((0x100 >> pos) - 1); /* assure unused bits are zero */ + if (pos & 1) { + /* odd -- append an empty stored block */ + putc(last, out); + if (pos == 1) + putc(0, out); /* two more bits in block header */ + fwrite("\0\0\xff\xff", 1, 4, out); + } + else { + /* even -- append 1, 2, or 3 empty fixed blocks */ + switch (pos) { + case 6: + putc(last | 8, out); + last = 0; + case 4: + putc(last | 0x20, out); + last = 0; + case 2: + putc(last | 0x80, out); + putc(0, out); + } + } + } + + /* update crc and tot */ + *crc = crc32_combine(*crc, bget4(in), len); + *tot += (unsigned long)len; + + /* clean up */ + inflateEnd(&strm); + free(junk); + bclose(in); + + /* write trailer if this is the last gzip file */ + if (!clr) { + put4(*crc, out); + put4(*tot, out); + } +} + +/* join the gzip files on the command line, write result to stdout */ +int main(int argc, char **argv) +{ + unsigned long crc, tot; /* running crc and total uncompressed length */ + + /* skip command name */ + argc--; + argv++; + + /* show usage if no arguments */ + if (argc == 0) { + fputs("gzjoin usage: gzjoin f1.gz [f2.gz [f3.gz ...]] > fjoin.gz\n", + stderr); + return 0; + } + + /* join gzip files on command line and write to stdout */ + gzinit(&crc, &tot, stdout); + while (argc--) + gzcopy(*argv++, argc, &crc, &tot, stdout); + + /* done */ + return 0; +} diff --git a/contrib/zlib/examples/gzlog.c b/contrib/zlib/examples/gzlog.c new file mode 100644 index 00000000..b8c29274 --- /dev/null +++ b/contrib/zlib/examples/gzlog.c @@ -0,0 +1,1059 @@ +/* + * gzlog.c + * Copyright (C) 2004, 2008, 2012, 2016 Mark Adler, all rights reserved + * For conditions of distribution and use, see copyright notice in gzlog.h + * version 2.2, 14 Aug 2012 + */ + +/* + gzlog provides a mechanism for frequently appending short strings to a gzip + file that is efficient both in execution time and compression ratio. The + strategy is to write the short strings in an uncompressed form to the end of + the gzip file, only compressing when the amount of uncompressed data has + reached a given threshold. + + gzlog also provides protection against interruptions in the process due to + system crashes. The status of the operation is recorded in an extra field + in the gzip file, and is only updated once the gzip file is brought to a + valid state. The last data to be appended or compressed is saved in an + auxiliary file, so that if the operation is interrupted, it can be completed + the next time an append operation is attempted. + + gzlog maintains another auxiliary file with the last 32K of data from the + compressed portion, which is preloaded for the compression of the subsequent + data. This minimizes the impact to the compression ratio of appending. + */ + +/* + Operations Concept: + + Files (log name "foo"): + foo.gz -- gzip file with the complete log + foo.add -- last message to append or last data to compress + foo.dict -- dictionary of the last 32K of data for next compression + foo.temp -- temporary dictionary file for compression after this one + foo.lock -- lock file for reading and writing the other files + foo.repairs -- log file for log file recovery operations (not compressed) + + gzip file structure: + - fixed-length (no file name) header with extra field (see below) + - compressed data ending initially with empty stored block + - uncompressed data filling out originally empty stored block and + subsequent stored blocks as needed (16K max each) + - gzip trailer + - no junk at end (no other gzip streams) + + When appending data, the information in the first three items above plus the + foo.add file are sufficient to recover an interrupted append operation. The + extra field has the necessary information to restore the start of the last + stored block and determine where to append the data in the foo.add file, as + well as the crc and length of the gzip data before the append operation. + + The foo.add file is created before the gzip file is marked for append, and + deleted after the gzip file is marked as complete. So if the append + operation is interrupted, the data to add will still be there. If due to + some external force, the foo.add file gets deleted between when the append + operation was interrupted and when recovery is attempted, the gzip file will + still be restored, but without the appended data. + + When compressing data, the information in the first two items above plus the + foo.add file are sufficient to recover an interrupted compress operation. + The extra field has the necessary information to find the end of the + compressed data, and contains both the crc and length of just the compressed + data and of the complete set of data including the contents of the foo.add + file. + + Again, the foo.add file is maintained during the compress operation in case + of an interruption. If in the unlikely event the foo.add file with the data + to be compressed is missing due to some external force, a gzip file with + just the previous compressed data will be reconstructed. In this case, all + of the data that was to be compressed is lost (approximately one megabyte). + This will not occur if all that happened was an interruption of the compress + operation. + + The third state that is marked is the replacement of the old dictionary with + the new dictionary after a compress operation. Once compression is + complete, the gzip file is marked as being in the replace state. This + completes the gzip file, so an interrupt after being so marked does not + result in recompression. Then the dictionary file is replaced, and the gzip + file is marked as completed. This state prevents the possibility of + restarting compression with the wrong dictionary file. + + All three operations are wrapped by a lock/unlock procedure. In order to + gain exclusive access to the log files, first a foo.lock file must be + exclusively created. When all operations are complete, the lock is + released by deleting the foo.lock file. If when attempting to create the + lock file, it already exists and the modify time of the lock file is more + than five minutes old (set by the PATIENCE define below), then the old + lock file is considered stale and deleted, and the exclusive creation of + the lock file is retried. To assure that there are no false assessments + of the staleness of the lock file, the operations periodically touch the + lock file to update the modified date. + + Following is the definition of the extra field with all of the information + required to enable the above append and compress operations and their + recovery if interrupted. Multi-byte values are stored little endian + (consistent with the gzip format). File pointers are eight bytes long. + The crc's and lengths for the gzip trailer are four bytes long. (Note that + the length at the end of a gzip file is used for error checking only, and + for large files is actually the length modulo 2^32.) The stored block + length is two bytes long. The gzip extra field two-byte identification is + "ap" for append. It is assumed that writing the extra field to the file is + an "atomic" operation. That is, either all of the extra field is written + to the file, or none of it is, if the operation is interrupted right at the + point of updating the extra field. This is a reasonable assumption, since + the extra field is within the first 52 bytes of the file, which is smaller + than any expected block size for a mass storage device (usually 512 bytes or + larger). + + Extra field (35 bytes): + - Pointer to first stored block length -- this points to the two-byte length + of the first stored block, which is followed by the two-byte, one's + complement of that length. The stored block length is preceded by the + three-bit header of the stored block, which is the actual start of the + stored block in the deflate format. See the bit offset field below. + - Pointer to the last stored block length. This is the same as above, but + for the last stored block of the uncompressed data in the gzip file. + Initially this is the same as the first stored block length pointer. + When the stored block gets to 16K (see the MAX_STORE define), then a new + stored block as added, at which point the last stored block length pointer + is different from the first stored block length pointer. When they are + different, the first bit of the last stored block header is eight bits, or + one byte back from the block length. + - Compressed data crc and length. This is the crc and length of the data + that is in the compressed portion of the deflate stream. These are used + only in the event that the foo.add file containing the data to compress is + lost after a compress operation is interrupted. + - Total data crc and length. This is the crc and length of all of the data + stored in the gzip file, compressed and uncompressed. It is used to + reconstruct the gzip trailer when compressing, as well as when recovering + interrupted operations. + - Final stored block length. This is used to quickly find where to append, + and allows the restoration of the original final stored block state when + an append operation is interrupted. + - First stored block start as the number of bits back from the final stored + block first length byte. This value is in the range of 3..10, and is + stored as the low three bits of the final byte of the extra field after + subtracting three (0..7). This allows the last-block bit of the stored + block header to be updated when a new stored block is added, for the case + when the first stored block and the last stored block are the same. (When + they are different, the numbers of bits back is known to be eight.) This + also allows for new compressed data to be appended to the old compressed + data in the compress operation, overwriting the previous first stored + block, or for the compressed data to be terminated and a valid gzip file + reconstructed on the off chance that a compression operation was + interrupted and the data to compress in the foo.add file was deleted. + - The operation in process. This is the next two bits in the last byte (the + bits under the mask 0x18). The are interpreted as 0: nothing in process, + 1: append in process, 2: compress in process, 3: replace in process. + - The top three bits of the last byte in the extra field are reserved and + are currently set to zero. + + Main procedure: + - Exclusively create the foo.lock file using the O_CREAT and O_EXCL modes of + the system open() call. If the modify time of an existing lock file is + more than PATIENCE seconds old, then the lock file is deleted and the + exclusive create is retried. + - Load the extra field from the foo.gz file, and see if an operation was in + progress but not completed. If so, apply the recovery procedure below. + - Perform the append procedure with the provided data. + - If the uncompressed data in the foo.gz file is 1MB or more, apply the + compress procedure. + - Delete the foo.lock file. + + Append procedure: + - Put what to append in the foo.add file so that the operation can be + restarted if this procedure is interrupted. + - Mark the foo.gz extra field with the append operation in progress. + + Restore the original last-block bit and stored block length of the last + stored block from the information in the extra field, in case a previous + append operation was interrupted. + - Append the provided data to the last stored block, creating new stored + blocks as needed and updating the stored blocks last-block bits and + lengths. + - Update the crc and length with the new data, and write the gzip trailer. + - Write over the extra field (with a single write operation) with the new + pointers, lengths, and crc's, and mark the gzip file as not in process. + Though there is still a foo.add file, it will be ignored since nothing + is in process. If a foo.add file is leftover from a previously + completed operation, it is truncated when writing new data to it. + - Delete the foo.add file. + + Compress and replace procedures: + - Read all of the uncompressed data in the stored blocks in foo.gz and write + it to foo.add. Also write foo.temp with the last 32K of that data to + provide a dictionary for the next invocation of this procedure. + - Rewrite the extra field marking foo.gz with a compression in process. + * If there is no data provided to compress (due to a missing foo.add file + when recovering), reconstruct and truncate the foo.gz file to contain + only the previous compressed data and proceed to the step after the next + one. Otherwise ... + - Compress the data with the dictionary in foo.dict, and write to the + foo.gz file starting at the bit immediately following the last previously + compressed block. If there is no foo.dict, proceed anyway with the + compression at slightly reduced efficiency. (For the foo.dict file to be + missing requires some external failure beyond simply the interruption of + a compress operation.) During this process, the foo.lock file is + periodically touched to assure that that file is not considered stale by + another process before we're done. The deflation is terminated with a + non-last empty static block (10 bits long), that is then located and + written over by a last-bit-set empty stored block. + - Append the crc and length of the data in the gzip file (previously + calculated during the append operations). + - Write over the extra field with the updated stored block offsets, bits + back, crc's, and lengths, and mark foo.gz as in process for a replacement + of the dictionary. + @ Delete the foo.add file. + - Replace foo.dict with foo.temp. + - Write over the extra field, marking foo.gz as complete. + + Recovery procedure: + - If not a replace recovery, read in the foo.add file, and provide that data + to the appropriate recovery below. If there is no foo.add file, provide + a zero data length to the recovery. In that case, the append recovery + restores the foo.gz to the previous compressed + uncompressed data state. + For the the compress recovery, a missing foo.add file results in foo.gz + being restored to the previous compressed-only data state. + - Append recovery: + - Pick up append at + step above + - Compress recovery: + - Pick up compress at * step above + - Replace recovery: + - Pick up compress at @ step above + - Log the repair with a date stamp in foo.repairs + */ + +#include +#include /* rename, fopen, fprintf, fclose */ +#include /* malloc, free */ +#include /* strlen, strrchr, strcpy, strncpy, strcmp */ +#include /* open */ +#include /* lseek, read, write, close, unlink, sleep, */ + /* ftruncate, fsync */ +#include /* errno */ +#include /* time, ctime */ +#include /* stat */ +#include /* utimes */ +#include "zlib.h" /* crc32 */ + +#include "gzlog.h" /* header for external access */ + +#define local static +typedef unsigned int uint; +typedef unsigned long ulong; + +/* Macro for debugging to deterministically force recovery operations */ +#ifdef GZLOG_DEBUG + #include /* longjmp */ + jmp_buf gzlog_jump; /* where to go back to */ + int gzlog_bail = 0; /* which point to bail at (1..8) */ + int gzlog_count = -1; /* number of times through to wait */ +# define BAIL(n) do { if (n == gzlog_bail && gzlog_count-- == 0) \ + longjmp(gzlog_jump, gzlog_bail); } while (0) +#else +# define BAIL(n) +#endif + +/* how old the lock file can be in seconds before considering it stale */ +#define PATIENCE 300 + +/* maximum stored block size in Kbytes -- must be in 1..63 */ +#define MAX_STORE 16 + +/* number of stored Kbytes to trigger compression (must be >= 32 to allow + dictionary construction, and <= 204 * MAX_STORE, in order for >> 10 to + discard the stored block headers contribution of five bytes each) */ +#define TRIGGER 1024 + +/* size of a deflate dictionary (this cannot be changed) */ +#define DICT 32768U + +/* values for the operation (2 bits) */ +#define NO_OP 0 +#define APPEND_OP 1 +#define COMPRESS_OP 2 +#define REPLACE_OP 3 + +/* macros to extract little-endian integers from an unsigned byte buffer */ +#define PULL2(p) ((p)[0]+((uint)((p)[1])<<8)) +#define PULL4(p) (PULL2(p)+((ulong)PULL2(p+2)<<16)) +#define PULL8(p) (PULL4(p)+((off_t)PULL4(p+4)<<32)) + +/* macros to store integers into a byte buffer in little-endian order */ +#define PUT2(p,a) do {(p)[0]=a;(p)[1]=(a)>>8;} while(0) +#define PUT4(p,a) do {PUT2(p,a);PUT2(p+2,a>>16);} while(0) +#define PUT8(p,a) do {PUT4(p,a);PUT4(p+4,a>>32);} while(0) + +/* internal structure for log information */ +#define LOGID "\106\035\172" /* should be three non-zero characters */ +struct log { + char id[4]; /* contains LOGID to detect inadvertent overwrites */ + int fd; /* file descriptor for .gz file, opened read/write */ + char *path; /* allocated path, e.g. "/var/log/foo" or "foo" */ + char *end; /* end of path, for appending suffices such as ".gz" */ + off_t first; /* offset of first stored block first length byte */ + int back; /* location of first block id in bits back from first */ + uint stored; /* bytes currently in last stored block */ + off_t last; /* offset of last stored block first length byte */ + ulong ccrc; /* crc of compressed data */ + ulong clen; /* length (modulo 2^32) of compressed data */ + ulong tcrc; /* crc of total data */ + ulong tlen; /* length (modulo 2^32) of total data */ + time_t lock; /* last modify time of our lock file */ +}; + +/* gzip header for gzlog */ +local unsigned char log_gzhead[] = { + 0x1f, 0x8b, /* magic gzip id */ + 8, /* compression method is deflate */ + 4, /* there is an extra field (no file name) */ + 0, 0, 0, 0, /* no modification time provided */ + 0, 0xff, /* no extra flags, no OS specified */ + 39, 0, 'a', 'p', 35, 0 /* extra field with "ap" subfield */ + /* 35 is EXTRA, 39 is EXTRA + 4 */ +}; + +#define HEAD sizeof(log_gzhead) /* should be 16 */ + +/* initial gzip extra field content (52 == HEAD + EXTRA + 1) */ +local unsigned char log_gzext[] = { + 52, 0, 0, 0, 0, 0, 0, 0, /* offset of first stored block length */ + 52, 0, 0, 0, 0, 0, 0, 0, /* offset of last stored block length */ + 0, 0, 0, 0, 0, 0, 0, 0, /* compressed data crc and length */ + 0, 0, 0, 0, 0, 0, 0, 0, /* total data crc and length */ + 0, 0, /* final stored block data length */ + 5 /* op is NO_OP, last bit 8 bits back */ +}; + +#define EXTRA sizeof(log_gzext) /* should be 35 */ + +/* initial gzip data and trailer */ +local unsigned char log_gzbody[] = { + 1, 0, 0, 0xff, 0xff, /* empty stored block (last) */ + 0, 0, 0, 0, /* crc */ + 0, 0, 0, 0 /* uncompressed length */ +}; + +#define BODY sizeof(log_gzbody) + +/* Exclusively create foo.lock in order to negotiate exclusive access to the + foo.* files. If the modify time of an existing lock file is greater than + PATIENCE seconds in the past, then consider the lock file to have been + abandoned, delete it, and try the exclusive create again. Save the lock + file modify time for verification of ownership. Return 0 on success, or -1 + on failure, usually due to an access restriction or invalid path. Note that + if stat() or unlink() fails, it may be due to another process noticing the + abandoned lock file a smidge sooner and deleting it, so those are not + flagged as an error. */ +local int log_lock(struct log *log) +{ + int fd; + struct stat st; + + strcpy(log->end, ".lock"); + while ((fd = open(log->path, O_CREAT | O_EXCL, 0644)) < 0) { + if (errno != EEXIST) + return -1; + if (stat(log->path, &st) == 0 && time(NULL) - st.st_mtime > PATIENCE) { + unlink(log->path); + continue; + } + sleep(2); /* relinquish the CPU for two seconds while waiting */ + } + close(fd); + if (stat(log->path, &st) == 0) + log->lock = st.st_mtime; + return 0; +} + +/* Update the modify time of the lock file to now, in order to prevent another + task from thinking that the lock is stale. Save the lock file modify time + for verification of ownership. */ +local void log_touch(struct log *log) +{ + struct stat st; + + strcpy(log->end, ".lock"); + utimes(log->path, NULL); + if (stat(log->path, &st) == 0) + log->lock = st.st_mtime; +} + +/* Check the log file modify time against what is expected. Return true if + this is not our lock. If it is our lock, touch it to keep it. */ +local int log_check(struct log *log) +{ + struct stat st; + + strcpy(log->end, ".lock"); + if (stat(log->path, &st) || st.st_mtime != log->lock) + return 1; + log_touch(log); + return 0; +} + +/* Unlock a previously acquired lock, but only if it's ours. */ +local void log_unlock(struct log *log) +{ + if (log_check(log)) + return; + strcpy(log->end, ".lock"); + unlink(log->path); + log->lock = 0; +} + +/* Check the gzip header and read in the extra field, filling in the values in + the log structure. Return op on success or -1 if the gzip header was not as + expected. op is the current operation in progress last written to the extra + field. This assumes that the gzip file has already been opened, with the + file descriptor log->fd. */ +local int log_head(struct log *log) +{ + int op; + unsigned char buf[HEAD + EXTRA]; + + if (lseek(log->fd, 0, SEEK_SET) < 0 || + read(log->fd, buf, HEAD + EXTRA) != HEAD + EXTRA || + memcmp(buf, log_gzhead, HEAD)) { + return -1; + } + log->first = PULL8(buf + HEAD); + log->last = PULL8(buf + HEAD + 8); + log->ccrc = PULL4(buf + HEAD + 16); + log->clen = PULL4(buf + HEAD + 20); + log->tcrc = PULL4(buf + HEAD + 24); + log->tlen = PULL4(buf + HEAD + 28); + log->stored = PULL2(buf + HEAD + 32); + log->back = 3 + (buf[HEAD + 34] & 7); + op = (buf[HEAD + 34] >> 3) & 3; + return op; +} + +/* Write over the extra field contents, marking the operation as op. Use fsync + to assure that the device is written to, and in the requested order. This + operation, and only this operation, is assumed to be atomic in order to + assure that the log is recoverable in the event of an interruption at any + point in the process. Return -1 if the write to foo.gz failed. */ +local int log_mark(struct log *log, int op) +{ + int ret; + unsigned char ext[EXTRA]; + + PUT8(ext, log->first); + PUT8(ext + 8, log->last); + PUT4(ext + 16, log->ccrc); + PUT4(ext + 20, log->clen); + PUT4(ext + 24, log->tcrc); + PUT4(ext + 28, log->tlen); + PUT2(ext + 32, log->stored); + ext[34] = log->back - 3 + (op << 3); + fsync(log->fd); + ret = lseek(log->fd, HEAD, SEEK_SET) < 0 || + write(log->fd, ext, EXTRA) != EXTRA ? -1 : 0; + fsync(log->fd); + return ret; +} + +/* Rewrite the last block header bits and subsequent zero bits to get to a byte + boundary, setting the last block bit if last is true, and then write the + remainder of the stored block header (length and one's complement). Leave + the file pointer after the end of the last stored block data. Return -1 if + there is a read or write failure on the foo.gz file */ +local int log_last(struct log *log, int last) +{ + int back, len, mask; + unsigned char buf[6]; + + /* determine the locations of the bytes and bits to modify */ + back = log->last == log->first ? log->back : 8; + len = back > 8 ? 2 : 1; /* bytes back from log->last */ + mask = 0x80 >> ((back - 1) & 7); /* mask for block last-bit */ + + /* get the byte to modify (one or two back) into buf[0] -- don't need to + read the byte if the last-bit is eight bits back, since in that case + the entire byte will be modified */ + buf[0] = 0; + if (back != 8 && (lseek(log->fd, log->last - len, SEEK_SET) < 0 || + read(log->fd, buf, 1) != 1)) + return -1; + + /* change the last-bit of the last stored block as requested -- note + that all bits above the last-bit are set to zero, per the type bits + of a stored block being 00 and per the convention that the bits to + bring the stream to a byte boundary are also zeros */ + buf[1] = 0; + buf[2 - len] = (*buf & (mask - 1)) + (last ? mask : 0); + + /* write the modified stored block header and lengths, move the file + pointer to after the last stored block data */ + PUT2(buf + 2, log->stored); + PUT2(buf + 4, log->stored ^ 0xffff); + return lseek(log->fd, log->last - len, SEEK_SET) < 0 || + write(log->fd, buf + 2 - len, len + 4) != len + 4 || + lseek(log->fd, log->stored, SEEK_CUR) < 0 ? -1 : 0; +} + +/* Append len bytes from data to the locked and open log file. len may be zero + if recovering and no .add file was found. In that case, the previous state + of the foo.gz file is restored. The data is appended uncompressed in + deflate stored blocks. Return -1 if there was an error reading or writing + the foo.gz file. */ +local int log_append(struct log *log, unsigned char *data, size_t len) +{ + uint put; + off_t end; + unsigned char buf[8]; + + /* set the last block last-bit and length, in case recovering an + interrupted append, then position the file pointer to append to the + block */ + if (log_last(log, 1)) + return -1; + + /* append, adding stored blocks and updating the offset of the last stored + block as needed, and update the total crc and length */ + while (len) { + /* append as much as we can to the last block */ + put = (MAX_STORE << 10) - log->stored; + if (put > len) + put = (uint)len; + if (put) { + if (write(log->fd, data, put) != put) + return -1; + BAIL(1); + log->tcrc = crc32(log->tcrc, data, put); + log->tlen += put; + log->stored += put; + data += put; + len -= put; + } + + /* if we need to, add a new empty stored block */ + if (len) { + /* mark current block as not last */ + if (log_last(log, 0)) + return -1; + + /* point to new, empty stored block */ + log->last += 4 + log->stored + 1; + log->stored = 0; + } + + /* mark last block as last, update its length */ + if (log_last(log, 1)) + return -1; + BAIL(2); + } + + /* write the new crc and length trailer, and truncate just in case (could + be recovering from partial append with a missing foo.add file) */ + PUT4(buf, log->tcrc); + PUT4(buf + 4, log->tlen); + if (write(log->fd, buf, 8) != 8 || + (end = lseek(log->fd, 0, SEEK_CUR)) < 0 || ftruncate(log->fd, end)) + return -1; + + /* write the extra field, marking the log file as done, delete .add file */ + if (log_mark(log, NO_OP)) + return -1; + strcpy(log->end, ".add"); + unlink(log->path); /* ignore error, since may not exist */ + return 0; +} + +/* Replace the foo.dict file with the foo.temp file. Also delete the foo.add + file, since the compress operation may have been interrupted before that was + done. Returns 1 if memory could not be allocated, or -1 if reading or + writing foo.gz fails, or if the rename fails for some reason other than + foo.temp not existing. foo.temp not existing is a permitted error, since + the replace operation may have been interrupted after the rename is done, + but before foo.gz is marked as complete. */ +local int log_replace(struct log *log) +{ + int ret; + char *dest; + + /* delete foo.add file */ + strcpy(log->end, ".add"); + unlink(log->path); /* ignore error, since may not exist */ + BAIL(3); + + /* rename foo.name to foo.dict, replacing foo.dict if it exists */ + strcpy(log->end, ".dict"); + dest = malloc(strlen(log->path) + 1); + if (dest == NULL) + return -2; + strcpy(dest, log->path); + strcpy(log->end, ".temp"); + ret = rename(log->path, dest); + free(dest); + if (ret && errno != ENOENT) + return -1; + BAIL(4); + + /* mark the foo.gz file as done */ + return log_mark(log, NO_OP); +} + +/* Compress the len bytes at data and append the compressed data to the + foo.gz deflate data immediately after the previous compressed data. This + overwrites the previous uncompressed data, which was stored in foo.add + and is the data provided in data[0..len-1]. If this operation is + interrupted, it picks up at the start of this routine, with the foo.add + file read in again. If there is no data to compress (len == 0), then we + simply terminate the foo.gz file after the previously compressed data, + appending a final empty stored block and the gzip trailer. Return -1 if + reading or writing the log.gz file failed, or -2 if there was a memory + allocation failure. */ +local int log_compress(struct log *log, unsigned char *data, size_t len) +{ + int fd; + uint got, max; + ssize_t dict; + off_t end; + z_stream strm; + unsigned char buf[DICT]; + + /* compress and append compressed data */ + if (len) { + /* set up for deflate, allocating memory */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8, + Z_DEFAULT_STRATEGY) != Z_OK) + return -2; + + /* read in dictionary (last 32K of data that was compressed) */ + strcpy(log->end, ".dict"); + fd = open(log->path, O_RDONLY, 0); + if (fd >= 0) { + dict = read(fd, buf, DICT); + close(fd); + if (dict < 0) { + deflateEnd(&strm); + return -1; + } + if (dict) + deflateSetDictionary(&strm, buf, (uint)dict); + } + log_touch(log); + + /* prime deflate with last bits of previous block, position write + pointer to write those bits and overwrite what follows */ + if (lseek(log->fd, log->first - (log->back > 8 ? 2 : 1), + SEEK_SET) < 0 || + read(log->fd, buf, 1) != 1 || lseek(log->fd, -1, SEEK_CUR) < 0) { + deflateEnd(&strm); + return -1; + } + deflatePrime(&strm, (8 - log->back) & 7, *buf); + + /* compress, finishing with a partial non-last empty static block */ + strm.next_in = data; + max = (((uint)0 - 1) >> 1) + 1; /* in case int smaller than size_t */ + do { + strm.avail_in = len > max ? max : (uint)len; + len -= strm.avail_in; + do { + strm.avail_out = DICT; + strm.next_out = buf; + deflate(&strm, len ? Z_NO_FLUSH : Z_PARTIAL_FLUSH); + got = DICT - strm.avail_out; + if (got && write(log->fd, buf, got) != got) { + deflateEnd(&strm); + return -1; + } + log_touch(log); + } while (strm.avail_out == 0); + } while (len); + deflateEnd(&strm); + BAIL(5); + + /* find start of empty static block -- scanning backwards the first one + bit is the second bit of the block, if the last byte is zero, then + we know the byte before that has a one in the top bit, since an + empty static block is ten bits long */ + if ((log->first = lseek(log->fd, -1, SEEK_CUR)) < 0 || + read(log->fd, buf, 1) != 1) + return -1; + log->first++; + if (*buf) { + log->back = 1; + while ((*buf & ((uint)1 << (8 - log->back++))) == 0) + ; /* guaranteed to terminate, since *buf != 0 */ + } + else + log->back = 10; + + /* update compressed crc and length */ + log->ccrc = log->tcrc; + log->clen = log->tlen; + } + else { + /* no data to compress -- fix up existing gzip stream */ + log->tcrc = log->ccrc; + log->tlen = log->clen; + } + + /* complete and truncate gzip stream */ + log->last = log->first; + log->stored = 0; + PUT4(buf, log->tcrc); + PUT4(buf + 4, log->tlen); + if (log_last(log, 1) || write(log->fd, buf, 8) != 8 || + (end = lseek(log->fd, 0, SEEK_CUR)) < 0 || ftruncate(log->fd, end)) + return -1; + BAIL(6); + + /* mark as being in the replace operation */ + if (log_mark(log, REPLACE_OP)) + return -1; + + /* execute the replace operation and mark the file as done */ + return log_replace(log); +} + +/* log a repair record to the .repairs file */ +local void log_log(struct log *log, int op, char *record) +{ + time_t now; + FILE *rec; + + now = time(NULL); + strcpy(log->end, ".repairs"); + rec = fopen(log->path, "a"); + if (rec == NULL) + return; + fprintf(rec, "%.24s %s recovery: %s\n", ctime(&now), op == APPEND_OP ? + "append" : (op == COMPRESS_OP ? "compress" : "replace"), record); + fclose(rec); + return; +} + +/* Recover the interrupted operation op. First read foo.add for recovering an + append or compress operation. Return -1 if there was an error reading or + writing foo.gz or reading an existing foo.add, or -2 if there was a memory + allocation failure. */ +local int log_recover(struct log *log, int op) +{ + int fd, ret = 0; + unsigned char *data = NULL; + size_t len = 0; + struct stat st; + + /* log recovery */ + log_log(log, op, "start"); + + /* load foo.add file if expected and present */ + if (op == APPEND_OP || op == COMPRESS_OP) { + strcpy(log->end, ".add"); + if (stat(log->path, &st) == 0 && st.st_size) { + len = (size_t)(st.st_size); + if ((off_t)len != st.st_size || + (data = malloc(st.st_size)) == NULL) { + log_log(log, op, "allocation failure"); + return -2; + } + if ((fd = open(log->path, O_RDONLY, 0)) < 0) { + log_log(log, op, ".add file read failure"); + return -1; + } + ret = (size_t)read(fd, data, len) != len; + close(fd); + if (ret) { + log_log(log, op, ".add file read failure"); + return -1; + } + log_log(log, op, "loaded .add file"); + } + else + log_log(log, op, "missing .add file!"); + } + + /* recover the interrupted operation */ + switch (op) { + case APPEND_OP: + ret = log_append(log, data, len); + break; + case COMPRESS_OP: + ret = log_compress(log, data, len); + break; + case REPLACE_OP: + ret = log_replace(log); + } + + /* log status */ + log_log(log, op, ret ? "failure" : "complete"); + + /* clean up */ + if (data != NULL) + free(data); + return ret; +} + +/* Close the foo.gz file (if open) and release the lock. */ +local void log_close(struct log *log) +{ + if (log->fd >= 0) + close(log->fd); + log->fd = -1; + log_unlock(log); +} + +/* Open foo.gz, verify the header, and load the extra field contents, after + first creating the foo.lock file to gain exclusive access to the foo.* + files. If foo.gz does not exist or is empty, then write the initial header, + extra, and body content of an empty foo.gz log file. If there is an error + creating the lock file due to access restrictions, or an error reading or + writing the foo.gz file, or if the foo.gz file is not a proper log file for + this object (e.g. not a gzip file or does not contain the expected extra + field), then return true. If there is an error, the lock is released. + Otherwise, the lock is left in place. */ +local int log_open(struct log *log) +{ + int op; + + /* release open file resource if left over -- can occur if lock lost + between gzlog_open() and gzlog_write() */ + if (log->fd >= 0) + close(log->fd); + log->fd = -1; + + /* negotiate exclusive access */ + if (log_lock(log) < 0) + return -1; + + /* open the log file, foo.gz */ + strcpy(log->end, ".gz"); + log->fd = open(log->path, O_RDWR | O_CREAT, 0644); + if (log->fd < 0) { + log_close(log); + return -1; + } + + /* if new, initialize foo.gz with an empty log, delete old dictionary */ + if (lseek(log->fd, 0, SEEK_END) == 0) { + if (write(log->fd, log_gzhead, HEAD) != HEAD || + write(log->fd, log_gzext, EXTRA) != EXTRA || + write(log->fd, log_gzbody, BODY) != BODY) { + log_close(log); + return -1; + } + strcpy(log->end, ".dict"); + unlink(log->path); + } + + /* verify log file and load extra field information */ + if ((op = log_head(log)) < 0) { + log_close(log); + return -1; + } + + /* check for interrupted process and if so, recover */ + if (op != NO_OP && log_recover(log, op)) { + log_close(log); + return -1; + } + + /* touch the lock file to prevent another process from grabbing it */ + log_touch(log); + return 0; +} + +/* See gzlog.h for the description of the external methods below */ +gzlog *gzlog_open(char *path) +{ + size_t n; + struct log *log; + + /* check arguments */ + if (path == NULL || *path == 0) + return NULL; + + /* allocate and initialize log structure */ + log = malloc(sizeof(struct log)); + if (log == NULL) + return NULL; + strcpy(log->id, LOGID); + log->fd = -1; + + /* save path and end of path for name construction */ + n = strlen(path); + log->path = malloc(n + 9); /* allow for ".repairs" */ + if (log->path == NULL) { + free(log); + return NULL; + } + strcpy(log->path, path); + log->end = log->path + n; + + /* gain exclusive access and verify log file -- may perform a + recovery operation if needed */ + if (log_open(log)) { + free(log->path); + free(log); + return NULL; + } + + /* return pointer to log structure */ + return log; +} + +/* gzlog_compress() return values: + 0: all good + -1: file i/o error (usually access issue) + -2: memory allocation failure + -3: invalid log pointer argument */ +int gzlog_compress(gzlog *logd) +{ + int fd, ret; + uint block; + size_t len, next; + unsigned char *data, buf[5]; + struct log *log = logd; + + /* check arguments */ + if (log == NULL || strcmp(log->id, LOGID)) + return -3; + + /* see if we lost the lock -- if so get it again and reload the extra + field information (it probably changed), recover last operation if + necessary */ + if (log_check(log) && log_open(log)) + return -1; + + /* create space for uncompressed data */ + len = ((size_t)(log->last - log->first) & ~(((size_t)1 << 10) - 1)) + + log->stored; + if ((data = malloc(len)) == NULL) + return -2; + + /* do statement here is just a cheap trick for error handling */ + do { + /* read in the uncompressed data */ + if (lseek(log->fd, log->first - 1, SEEK_SET) < 0) + break; + next = 0; + while (next < len) { + if (read(log->fd, buf, 5) != 5) + break; + block = PULL2(buf + 1); + if (next + block > len || + read(log->fd, (char *)data + next, block) != block) + break; + next += block; + } + if (lseek(log->fd, 0, SEEK_CUR) != log->last + 4 + log->stored) + break; + log_touch(log); + + /* write the uncompressed data to the .add file */ + strcpy(log->end, ".add"); + fd = open(log->path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd < 0) + break; + ret = (size_t)write(fd, data, len) != len; + if (ret | close(fd)) + break; + log_touch(log); + + /* write the dictionary for the next compress to the .temp file */ + strcpy(log->end, ".temp"); + fd = open(log->path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd < 0) + break; + next = DICT > len ? len : DICT; + ret = (size_t)write(fd, (char *)data + len - next, next) != next; + if (ret | close(fd)) + break; + log_touch(log); + + /* roll back to compressed data, mark the compress in progress */ + log->last = log->first; + log->stored = 0; + if (log_mark(log, COMPRESS_OP)) + break; + BAIL(7); + + /* compress and append the data (clears mark) */ + ret = log_compress(log, data, len); + free(data); + return ret; + } while (0); + + /* broke out of do above on i/o error */ + free(data); + return -1; +} + +/* gzlog_write() return values: + 0: all good + -1: file i/o error (usually access issue) + -2: memory allocation failure + -3: invalid log pointer argument */ +int gzlog_write(gzlog *logd, void *data, size_t len) +{ + int fd, ret; + struct log *log = logd; + + /* check arguments */ + if (log == NULL || strcmp(log->id, LOGID)) + return -3; + if (data == NULL || len <= 0) + return 0; + + /* see if we lost the lock -- if so get it again and reload the extra + field information (it probably changed), recover last operation if + necessary */ + if (log_check(log) && log_open(log)) + return -1; + + /* create and write .add file */ + strcpy(log->end, ".add"); + fd = open(log->path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd < 0) + return -1; + ret = (size_t)write(fd, data, len) != len; + if (ret | close(fd)) + return -1; + log_touch(log); + + /* mark log file with append in progress */ + if (log_mark(log, APPEND_OP)) + return -1; + BAIL(8); + + /* append data (clears mark) */ + if (log_append(log, data, len)) + return -1; + + /* check to see if it's time to compress -- if not, then done */ + if (((log->last - log->first) >> 10) + (log->stored >> 10) < TRIGGER) + return 0; + + /* time to compress */ + return gzlog_compress(log); +} + +/* gzlog_close() return values: + 0: ok + -3: invalid log pointer argument */ +int gzlog_close(gzlog *logd) +{ + struct log *log = logd; + + /* check arguments */ + if (log == NULL || strcmp(log->id, LOGID)) + return -3; + + /* close the log file and release the lock */ + log_close(log); + + /* free structure and return */ + if (log->path != NULL) + free(log->path); + strcpy(log->id, "bad"); + free(log); + return 0; +} diff --git a/contrib/zlib/examples/gzlog.h b/contrib/zlib/examples/gzlog.h new file mode 100644 index 00000000..86f0cecb --- /dev/null +++ b/contrib/zlib/examples/gzlog.h @@ -0,0 +1,91 @@ +/* gzlog.h + Copyright (C) 2004, 2008, 2012 Mark Adler, all rights reserved + version 2.2, 14 Aug 2012 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler madler@alumni.caltech.edu + */ + +/* Version History: + 1.0 26 Nov 2004 First version + 2.0 25 Apr 2008 Complete redesign for recovery of interrupted operations + Interface changed slightly in that now path is a prefix + Compression now occurs as needed during gzlog_write() + gzlog_write() now always leaves the log file as valid gzip + 2.1 8 Jul 2012 Fix argument checks in gzlog_compress() and gzlog_write() + 2.2 14 Aug 2012 Clean up signed comparisons + */ + +/* + The gzlog object allows writing short messages to a gzipped log file, + opening the log file locked for small bursts, and then closing it. The log + object works by appending stored (uncompressed) data to the gzip file until + 1 MB has been accumulated. At that time, the stored data is compressed, and + replaces the uncompressed data in the file. The log file is truncated to + its new size at that time. After each write operation, the log file is a + valid gzip file that can decompressed to recover what was written. + + The gzlog operations can be interupted at any point due to an application or + system crash, and the log file will be recovered the next time the log is + opened with gzlog_open(). + */ + +#ifndef GZLOG_H +#define GZLOG_H + +/* gzlog object type */ +typedef void gzlog; + +/* Open a gzlog object, creating the log file if it does not exist. Return + NULL on error. Note that gzlog_open() could take a while to complete if it + has to wait to verify that a lock is stale (possibly for five minutes), or + if there is significant contention with other instantiations of this object + when locking the resource. path is the prefix of the file names created by + this object. If path is "foo", then the log file will be "foo.gz", and + other auxiliary files will be created and destroyed during the process: + "foo.dict" for a compression dictionary, "foo.temp" for a temporary (next) + dictionary, "foo.add" for data being added or compressed, "foo.lock" for the + lock file, and "foo.repairs" to log recovery operations performed due to + interrupted gzlog operations. A gzlog_open() followed by a gzlog_close() + will recover a previously interrupted operation, if any. */ +gzlog *gzlog_open(char *path); + +/* Write to a gzlog object. Return zero on success, -1 if there is a file i/o + error on any of the gzlog files (this should not happen if gzlog_open() + succeeded, unless the device has run out of space or leftover auxiliary + files have permissions or ownership that prevent their use), -2 if there is + a memory allocation failure, or -3 if the log argument is invalid (e.g. if + it was not created by gzlog_open()). This function will write data to the + file uncompressed, until 1 MB has been accumulated, at which time that data + will be compressed. The log file will be a valid gzip file upon successful + return. */ +int gzlog_write(gzlog *log, void *data, size_t len); + +/* Force compression of any uncompressed data in the log. This should be used + sparingly, if at all. The main application would be when a log file will + not be appended to again. If this is used to compress frequently while + appending, it will both significantly increase the execution time and + reduce the compression ratio. The return codes are the same as for + gzlog_write(). */ +int gzlog_compress(gzlog *log); + +/* Close a gzlog object. Return zero on success, -3 if the log argument is + invalid. The log object is freed, and so cannot be referenced again. */ +int gzlog_close(gzlog *log); + +#endif diff --git a/contrib/zlib/examples/zlib_how.html b/contrib/zlib/examples/zlib_how.html new file mode 100644 index 00000000..444ff1c9 --- /dev/null +++ b/contrib/zlib/examples/zlib_how.html @@ -0,0 +1,545 @@ + + + + +zlib Usage Example + + + +

zlib Usage Example

+We often get questions about how the deflate() and inflate() functions should be used. +Users wonder when they should provide more input, when they should use more output, +what to do with a Z_BUF_ERROR, how to make sure the process terminates properly, and +so on. So for those who have read zlib.h (a few times), and +would like further edification, below is an annotated example in C of simple routines to compress and decompress +from an input file to an output file using deflate() and inflate() respectively. The +annotations are interspersed between lines of the code. So please read between the lines. +We hope this helps explain some of the intricacies of zlib. +

+Without further adieu, here is the program zpipe.c: +


+/* zpipe.c: example of proper use of zlib's inflate() and deflate()
+   Not copyrighted -- provided to the public domain
+   Version 1.4  11 December 2005  Mark Adler */
+
+/* Version history:
+   1.0  30 Oct 2004  First version
+   1.1   8 Nov 2004  Add void casting for unused return values
+                     Use switch statement for inflate() return values
+   1.2   9 Nov 2004  Add assertions to document zlib guarantees
+   1.3   6 Apr 2005  Remove incorrect assertion in inf()
+   1.4  11 Dec 2005  Add hack to avoid MSDOS end-of-line conversions
+                     Avoid some compiler warnings for input and output buffers
+ */
+
+We now include the header files for the required definitions. From +stdio.h we use fopen(), fread(), fwrite(), +feof(), ferror(), and fclose() for file i/o, and +fputs() for error messages. From string.h we use +strcmp() for command line argument processing. +From assert.h we use the assert() macro. +From zlib.h +we use the basic compression functions deflateInit(), +deflate(), and deflateEnd(), and the basic decompression +functions inflateInit(), inflate(), and +inflateEnd(). +

+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include "zlib.h"
+
+This is an ugly hack required to avoid corruption of the input and output data on +Windows/MS-DOS systems. Without this, those systems would assume that the input and output +files are text, and try to convert the end-of-line characters from one standard to +another. That would corrupt binary data, and in particular would render the compressed data unusable. +This sets the input and output to binary which suppresses the end-of-line conversions. +SET_BINARY_MODE() will be used later on stdin and stdout, at the beginning of main(). +

+#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
+#  include <fcntl.h>
+#  include <io.h>
+#  define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
+#else
+#  define SET_BINARY_MODE(file)
+#endif
+
+CHUNK is simply the buffer size for feeding data to and pulling data +from the zlib routines. Larger buffer sizes would be more efficient, +especially for inflate(). If the memory is available, buffers sizes +on the order of 128K or 256K bytes should be used. +

+#define CHUNK 16384
+
+The def() routine compresses data from an input file to an output file. The output data +will be in the zlib format, which is different from the gzip or zip +formats. The zlib format has a very small header of only two bytes to identify it as +a zlib stream and to provide decoding information, and a four-byte trailer with a fast +check value to verify the integrity of the uncompressed data after decoding. +

+/* Compress from file source to file dest until EOF on source.
+   def() returns Z_OK on success, Z_MEM_ERROR if memory could not be
+   allocated for processing, Z_STREAM_ERROR if an invalid compression
+   level is supplied, Z_VERSION_ERROR if the version of zlib.h and the
+   version of the library linked do not match, or Z_ERRNO if there is
+   an error reading or writing the files. */
+int def(FILE *source, FILE *dest, int level)
+{
+
+Here are the local variables for def(). ret will be used for zlib +return codes. flush will keep track of the current flushing state for deflate(), +which is either no flushing, or flush to completion after the end of the input file is reached. +have is the amount of data returned from deflate(). The strm structure +is used to pass information to and from the zlib routines, and to maintain the +deflate() state. in and out are the input and output buffers for +deflate(). +

+    int ret, flush;
+    unsigned have;
+    z_stream strm;
+    unsigned char in[CHUNK];
+    unsigned char out[CHUNK];
+
+The first thing we do is to initialize the zlib state for compression using +deflateInit(). This must be done before the first use of deflate(). +The zalloc, zfree, and opaque fields in the strm +structure must be initialized before calling deflateInit(). Here they are +set to the zlib constant Z_NULL to request that zlib use +the default memory allocation routines. An application may also choose to provide +custom memory allocation routines here. deflateInit() will allocate on the +order of 256K bytes for the internal state. +(See zlib Technical Details.) +

+deflateInit() is called with a pointer to the structure to be initialized and +the compression level, which is an integer in the range of -1 to 9. Lower compression +levels result in faster execution, but less compression. Higher levels result in +greater compression, but slower execution. The zlib constant Z_DEFAULT_COMPRESSION, +equal to -1, +provides a good compromise between compression and speed and is equivalent to level 6. +Level 0 actually does no compression at all, and in fact expands the data slightly to produce +the zlib format (it is not a byte-for-byte copy of the input). +More advanced applications of zlib +may use deflateInit2() here instead. Such an application may want to reduce how +much memory will be used, at some price in compression. Or it may need to request a +gzip header and trailer instead of a zlib header and trailer, or raw +encoding with no header or trailer at all. +

+We must check the return value of deflateInit() against the zlib constant +Z_OK to make sure that it was able to +allocate memory for the internal state, and that the provided arguments were valid. +deflateInit() will also check that the version of zlib that the zlib.h +file came from matches the version of zlib actually linked with the program. This +is especially important for environments in which zlib is a shared library. +

+Note that an application can initialize multiple, independent zlib streams, which can +operate in parallel. The state information maintained in the structure allows the zlib +routines to be reentrant. +


+    /* allocate deflate state */
+    strm.zalloc = Z_NULL;
+    strm.zfree = Z_NULL;
+    strm.opaque = Z_NULL;
+    ret = deflateInit(&strm, level);
+    if (ret != Z_OK)
+        return ret;
+
+With the pleasantries out of the way, now we can get down to business. The outer do-loop +reads all of the input file and exits at the bottom of the loop once end-of-file is reached. +This loop contains the only call of deflate(). So we must make sure that all of the +input data has been processed and that all of the output data has been generated and consumed +before we fall out of the loop at the bottom. +

+    /* compress until end of file */
+    do {
+
+We start off by reading data from the input file. The number of bytes read is put directly +into avail_in, and a pointer to those bytes is put into next_in. We also +check to see if end-of-file on the input has been reached. If we are at the end of file, then flush is set to the +zlib constant Z_FINISH, which is later passed to deflate() to +indicate that this is the last chunk of input data to compress. We need to use feof() +to check for end-of-file as opposed to seeing if fewer than CHUNK bytes have been read. The +reason is that if the input file length is an exact multiple of CHUNK, we will miss +the fact that we got to the end-of-file, and not know to tell deflate() to finish +up the compressed stream. If we are not yet at the end of the input, then the zlib +constant Z_NO_FLUSH will be passed to deflate to indicate that we are still +in the middle of the uncompressed data. +

+If there is an error in reading from the input file, the process is aborted with +deflateEnd() being called to free the allocated zlib state before returning +the error. We wouldn't want a memory leak, now would we? deflateEnd() can be called +at any time after the state has been initialized. Once that's done, deflateInit() (or +deflateInit2()) would have to be called to start a new compression process. There is +no point here in checking the deflateEnd() return code. The deallocation can't fail. +


+        strm.avail_in = fread(in, 1, CHUNK, source);
+        if (ferror(source)) {
+            (void)deflateEnd(&strm);
+            return Z_ERRNO;
+        }
+        flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
+        strm.next_in = in;
+
+The inner do-loop passes our chunk of input data to deflate(), and then +keeps calling deflate() until it is done producing output. Once there is no more +new output, deflate() is guaranteed to have consumed all of the input, i.e., +avail_in will be zero. +

+        /* run deflate() on input until output buffer not full, finish
+           compression if all of source has been read in */
+        do {
+
+Output space is provided to deflate() by setting avail_out to the number +of available output bytes and next_out to a pointer to that space. +

+            strm.avail_out = CHUNK;
+            strm.next_out = out;
+
+Now we call the compression engine itself, deflate(). It takes as many of the +avail_in bytes at next_in as it can process, and writes as many as +avail_out bytes to next_out. Those counters and pointers are then +updated past the input data consumed and the output data written. It is the amount of +output space available that may limit how much input is consumed. +Hence the inner loop to make sure that +all of the input is consumed by providing more output space each time. Since avail_in +and next_in are updated by deflate(), we don't have to mess with those +between deflate() calls until it's all used up. +

+The parameters to deflate() are a pointer to the strm structure containing +the input and output information and the internal compression engine state, and a parameter +indicating whether and how to flush data to the output. Normally deflate will consume +several K bytes of input data before producing any output (except for the header), in order +to accumulate statistics on the data for optimum compression. It will then put out a burst of +compressed data, and proceed to consume more input before the next burst. Eventually, +deflate() +must be told to terminate the stream, complete the compression with provided input data, and +write out the trailer check value. deflate() will continue to compress normally as long +as the flush parameter is Z_NO_FLUSH. Once the Z_FINISH parameter is provided, +deflate() will begin to complete the compressed output stream. However depending on how +much output space is provided, deflate() may have to be called several times until it +has provided the complete compressed stream, even after it has consumed all of the input. The flush +parameter must continue to be Z_FINISH for those subsequent calls. +

+There are other values of the flush parameter that are used in more advanced applications. You can +force deflate() to produce a burst of output that encodes all of the input data provided +so far, even if it wouldn't have otherwise, for example to control data latency on a link with +compressed data. You can also ask that deflate() do that as well as erase any history up to +that point so that what follows can be decompressed independently, for example for random access +applications. Both requests will degrade compression by an amount depending on how often such +requests are made. +

+deflate() has a return value that can indicate errors, yet we do not check it here. Why +not? Well, it turns out that deflate() can do no wrong here. Let's go through +deflate()'s return values and dispense with them one by one. The possible values are +Z_OK, Z_STREAM_END, Z_STREAM_ERROR, or Z_BUF_ERROR. Z_OK +is, well, ok. Z_STREAM_END is also ok and will be returned for the last call of +deflate(). This is already guaranteed by calling deflate() with Z_FINISH +until it has no more output. Z_STREAM_ERROR is only possible if the stream is not +initialized properly, but we did initialize it properly. There is no harm in checking for +Z_STREAM_ERROR here, for example to check for the possibility that some +other part of the application inadvertently clobbered the memory containing the zlib state. +Z_BUF_ERROR will be explained further below, but +suffice it to say that this is simply an indication that deflate() could not consume +more input or produce more output. deflate() can be called again with more output space +or more available input, which it will be in this code. +


+            ret = deflate(&strm, flush);    /* no bad return value */
+            assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
+
+Now we compute how much output deflate() provided on the last call, which is the +difference between how much space was provided before the call, and how much output space +is still available after the call. Then that data, if any, is written to the output file. +We can then reuse the output buffer for the next call of deflate(). Again if there +is a file i/o error, we call deflateEnd() before returning to avoid a memory leak. +

+            have = CHUNK - strm.avail_out;
+            if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
+                (void)deflateEnd(&strm);
+                return Z_ERRNO;
+            }
+
+The inner do-loop is repeated until the last deflate() call fails to fill the +provided output buffer. Then we know that deflate() has done as much as it can with +the provided input, and that all of that input has been consumed. We can then fall out of this +loop and reuse the input buffer. +

+The way we tell that deflate() has no more output is by seeing that it did not fill +the output buffer, leaving avail_out greater than zero. However suppose that +deflate() has no more output, but just so happened to exactly fill the output buffer! +avail_out is zero, and we can't tell that deflate() has done all it can. +As far as we know, deflate() +has more output for us. So we call it again. But now deflate() produces no output +at all, and avail_out remains unchanged as CHUNK. That deflate() call +wasn't able to do anything, either consume input or produce output, and so it returns +Z_BUF_ERROR. (See, I told you I'd cover this later.) However this is not a problem at +all. Now we finally have the desired indication that deflate() is really done, +and so we drop out of the inner loop to provide more input to deflate(). +

+With flush set to Z_FINISH, this final set of deflate() calls will +complete the output stream. Once that is done, subsequent calls of deflate() would return +Z_STREAM_ERROR if the flush parameter is not Z_FINISH, and do no more processing +until the state is reinitialized. +

+Some applications of zlib have two loops that call deflate() +instead of the single inner loop we have here. The first loop would call +without flushing and feed all of the data to deflate(). The second loop would call +deflate() with no more +data and the Z_FINISH parameter to complete the process. As you can see from this +example, that can be avoided by simply keeping track of the current flush state. +


+        } while (strm.avail_out == 0);
+        assert(strm.avail_in == 0);     /* all input will be used */
+
+Now we check to see if we have already processed all of the input file. That information was +saved in the flush variable, so we see if that was set to Z_FINISH. If so, +then we're done and we fall out of the outer loop. We're guaranteed to get Z_STREAM_END +from the last deflate() call, since we ran it until the last chunk of input was +consumed and all of the output was generated. +

+        /* done when last data in file processed */
+    } while (flush != Z_FINISH);
+    assert(ret == Z_STREAM_END);        /* stream will be complete */
+
+The process is complete, but we still need to deallocate the state to avoid a memory leak +(or rather more like a memory hemorrhage if you didn't do this). Then +finally we can return with a happy return value. +

+    /* clean up and return */
+    (void)deflateEnd(&strm);
+    return Z_OK;
+}
+
+Now we do the same thing for decompression in the inf() routine. inf() +decompresses what is hopefully a valid zlib stream from the input file and writes the +uncompressed data to the output file. Much of the discussion above for def() +applies to inf() as well, so the discussion here will focus on the differences between +the two. +

+/* Decompress from file source to file dest until stream ends or EOF.
+   inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be
+   allocated for processing, Z_DATA_ERROR if the deflate data is
+   invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and
+   the version of the library linked do not match, or Z_ERRNO if there
+   is an error reading or writing the files. */
+int inf(FILE *source, FILE *dest)
+{
+
+The local variables have the same functionality as they do for def(). The +only difference is that there is no flush variable, since inflate() +can tell from the zlib stream itself when the stream is complete. +

+    int ret;
+    unsigned have;
+    z_stream strm;
+    unsigned char in[CHUNK];
+    unsigned char out[CHUNK];
+
+The initialization of the state is the same, except that there is no compression level, +of course, and two more elements of the structure are initialized. avail_in +and next_in must be initialized before calling inflateInit(). This +is because the application has the option to provide the start of the zlib stream in +order for inflateInit() to have access to information about the compression +method to aid in memory allocation. In the current implementation of zlib +(up through versions 1.2.x), the method-dependent memory allocations are deferred to the first call of +inflate() anyway. However those fields must be initialized since later versions +of zlib that provide more compression methods may take advantage of this interface. +In any case, no decompression is performed by inflateInit(), so the +avail_out and next_out fields do not need to be initialized before calling. +

+Here avail_in is set to zero and next_in is set to Z_NULL to +indicate that no input data is being provided. +


+    /* allocate inflate state */
+    strm.zalloc = Z_NULL;
+    strm.zfree = Z_NULL;
+    strm.opaque = Z_NULL;
+    strm.avail_in = 0;
+    strm.next_in = Z_NULL;
+    ret = inflateInit(&strm);
+    if (ret != Z_OK)
+        return ret;
+
+The outer do-loop decompresses input until inflate() indicates +that it has reached the end of the compressed data and has produced all of the uncompressed +output. This is in contrast to def() which processes all of the input file. +If end-of-file is reached before the compressed data self-terminates, then the compressed +data is incomplete and an error is returned. +

+    /* decompress until deflate stream ends or end of file */
+    do {
+
+We read input data and set the strm structure accordingly. If we've reached the +end of the input file, then we leave the outer loop and report an error, since the +compressed data is incomplete. Note that we may read more data than is eventually consumed +by inflate(), if the input file continues past the zlib stream. +For applications where zlib streams are embedded in other data, this routine would +need to be modified to return the unused data, or at least indicate how much of the input +data was not used, so the application would know where to pick up after the zlib stream. +

+        strm.avail_in = fread(in, 1, CHUNK, source);
+        if (ferror(source)) {
+            (void)inflateEnd(&strm);
+            return Z_ERRNO;
+        }
+        if (strm.avail_in == 0)
+            break;
+        strm.next_in = in;
+
+The inner do-loop has the same function it did in def(), which is to +keep calling inflate() until has generated all of the output it can with the +provided input. +

+        /* run inflate() on input until output buffer not full */
+        do {
+
+Just like in def(), the same output space is provided for each call of inflate(). +

+            strm.avail_out = CHUNK;
+            strm.next_out = out;
+
+Now we run the decompression engine itself. There is no need to adjust the flush parameter, since +the zlib format is self-terminating. The main difference here is that there are +return values that we need to pay attention to. Z_DATA_ERROR +indicates that inflate() detected an error in the zlib compressed data format, +which means that either the data is not a zlib stream to begin with, or that the data was +corrupted somewhere along the way since it was compressed. The other error to be processed is +Z_MEM_ERROR, which can occur since memory allocation is deferred until inflate() +needs it, unlike deflate(), whose memory is allocated at the start by deflateInit(). +

+Advanced applications may use +deflateSetDictionary() to prime deflate() with a set of likely data to improve the +first 32K or so of compression. This is noted in the zlib header, so inflate() +requests that that dictionary be provided before it can start to decompress. Without the dictionary, +correct decompression is not possible. For this routine, we have no idea what the dictionary is, +so the Z_NEED_DICT indication is converted to a Z_DATA_ERROR. +

+inflate() can also return Z_STREAM_ERROR, which should not be possible here, +but could be checked for as noted above for def(). Z_BUF_ERROR does not need to be +checked for here, for the same reasons noted for def(). Z_STREAM_END will be +checked for later. +


+            ret = inflate(&strm, Z_NO_FLUSH);
+            assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
+            switch (ret) {
+            case Z_NEED_DICT:
+                ret = Z_DATA_ERROR;     /* and fall through */
+            case Z_DATA_ERROR:
+            case Z_MEM_ERROR:
+                (void)inflateEnd(&strm);
+                return ret;
+            }
+
+The output of inflate() is handled identically to that of deflate(). +

+            have = CHUNK - strm.avail_out;
+            if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
+                (void)inflateEnd(&strm);
+                return Z_ERRNO;
+            }
+
+The inner do-loop ends when inflate() has no more output as indicated +by not filling the output buffer, just as for deflate(). In this case, we cannot +assert that strm.avail_in will be zero, since the deflate stream may end before the file +does. +

+        } while (strm.avail_out == 0);
+
+The outer do-loop ends when inflate() reports that it has reached the +end of the input zlib stream, has completed the decompression and integrity +check, and has provided all of the output. This is indicated by the inflate() +return value Z_STREAM_END. The inner loop is guaranteed to leave ret +equal to Z_STREAM_END if the last chunk of the input file read contained the end +of the zlib stream. So if the return value is not Z_STREAM_END, the +loop continues to read more input. +

+        /* done when inflate() says it's done */
+    } while (ret != Z_STREAM_END);
+
+At this point, decompression successfully completed, or we broke out of the loop due to no +more data being available from the input file. If the last inflate() return value +is not Z_STREAM_END, then the zlib stream was incomplete and a data error +is returned. Otherwise, we return with a happy return value. Of course, inflateEnd() +is called first to avoid a memory leak. +

+    /* clean up and return */
+    (void)inflateEnd(&strm);
+    return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
+}
+
+That ends the routines that directly use zlib. The following routines make this +a command-line program by running data through the above routines from stdin to +stdout, and handling any errors reported by def() or inf(). +

+zerr() is used to interpret the possible error codes from def() +and inf(), as detailed in their comments above, and print out an error message. +Note that these are only a subset of the possible return values from deflate() +and inflate(). +


+/* report a zlib or i/o error */
+void zerr(int ret)
+{
+    fputs("zpipe: ", stderr);
+    switch (ret) {
+    case Z_ERRNO:
+        if (ferror(stdin))
+            fputs("error reading stdin\n", stderr);
+        if (ferror(stdout))
+            fputs("error writing stdout\n", stderr);
+        break;
+    case Z_STREAM_ERROR:
+        fputs("invalid compression level\n", stderr);
+        break;
+    case Z_DATA_ERROR:
+        fputs("invalid or incomplete deflate data\n", stderr);
+        break;
+    case Z_MEM_ERROR:
+        fputs("out of memory\n", stderr);
+        break;
+    case Z_VERSION_ERROR:
+        fputs("zlib version mismatch!\n", stderr);
+    }
+}
+
+Here is the main() routine used to test def() and inf(). The +zpipe command is simply a compression pipe from stdin to stdout, if +no arguments are given, or it is a decompression pipe if zpipe -d is used. If any other +arguments are provided, no compression or decompression is performed. Instead a usage +message is displayed. Examples are zpipe < foo.txt > foo.txt.z to compress, and +zpipe -d < foo.txt.z > foo.txt to decompress. +

+/* compress or decompress from stdin to stdout */
+int main(int argc, char **argv)
+{
+    int ret;
+
+    /* avoid end-of-line conversions */
+    SET_BINARY_MODE(stdin);
+    SET_BINARY_MODE(stdout);
+
+    /* do compression if no arguments */
+    if (argc == 1) {
+        ret = def(stdin, stdout, Z_DEFAULT_COMPRESSION);
+        if (ret != Z_OK)
+            zerr(ret);
+        return ret;
+    }
+
+    /* do decompression if -d specified */
+    else if (argc == 2 && strcmp(argv[1], "-d") == 0) {
+        ret = inf(stdin, stdout);
+        if (ret != Z_OK)
+            zerr(ret);
+        return ret;
+    }
+
+    /* otherwise, report usage */
+    else {
+        fputs("zpipe usage: zpipe [-d] < source > dest\n", stderr);
+        return 1;
+    }
+}
+
+
+Copyright (c) 2004, 2005 by Mark Adler
Last modified 11 December 2005
+ + diff --git a/contrib/zlib/examples/zpipe.c b/contrib/zlib/examples/zpipe.c new file mode 100644 index 00000000..83535d16 --- /dev/null +++ b/contrib/zlib/examples/zpipe.c @@ -0,0 +1,205 @@ +/* zpipe.c: example of proper use of zlib's inflate() and deflate() + Not copyrighted -- provided to the public domain + Version 1.4 11 December 2005 Mark Adler */ + +/* Version history: + 1.0 30 Oct 2004 First version + 1.1 8 Nov 2004 Add void casting for unused return values + Use switch statement for inflate() return values + 1.2 9 Nov 2004 Add assertions to document zlib guarantees + 1.3 6 Apr 2005 Remove incorrect assertion in inf() + 1.4 11 Dec 2005 Add hack to avoid MSDOS end-of-line conversions + Avoid some compiler warnings for input and output buffers + */ + +#include +#include +#include +#include "zlib.h" + +#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +#define CHUNK 16384 + +/* Compress from file source to file dest until EOF on source. + def() returns Z_OK on success, Z_MEM_ERROR if memory could not be + allocated for processing, Z_STREAM_ERROR if an invalid compression + level is supplied, Z_VERSION_ERROR if the version of zlib.h and the + version of the library linked do not match, or Z_ERRNO if there is + an error reading or writing the files. */ +int def(FILE *source, FILE *dest, int level) +{ + int ret, flush; + unsigned have; + z_stream strm; + unsigned char in[CHUNK]; + unsigned char out[CHUNK]; + + /* allocate deflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + ret = deflateInit(&strm, level); + if (ret != Z_OK) + return ret; + + /* compress until end of file */ + do { + strm.avail_in = fread(in, 1, CHUNK, source); + if (ferror(source)) { + (void)deflateEnd(&strm); + return Z_ERRNO; + } + flush = feof(source) ? Z_FINISH : Z_NO_FLUSH; + strm.next_in = in; + + /* run deflate() on input until output buffer not full, finish + compression if all of source has been read in */ + do { + strm.avail_out = CHUNK; + strm.next_out = out; + ret = deflate(&strm, flush); /* no bad return value */ + assert(ret != Z_STREAM_ERROR); /* state not clobbered */ + have = CHUNK - strm.avail_out; + if (fwrite(out, 1, have, dest) != have || ferror(dest)) { + (void)deflateEnd(&strm); + return Z_ERRNO; + } + } while (strm.avail_out == 0); + assert(strm.avail_in == 0); /* all input will be used */ + + /* done when last data in file processed */ + } while (flush != Z_FINISH); + assert(ret == Z_STREAM_END); /* stream will be complete */ + + /* clean up and return */ + (void)deflateEnd(&strm); + return Z_OK; +} + +/* Decompress from file source to file dest until stream ends or EOF. + inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be + allocated for processing, Z_DATA_ERROR if the deflate data is + invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and + the version of the library linked do not match, or Z_ERRNO if there + is an error reading or writing the files. */ +int inf(FILE *source, FILE *dest) +{ + int ret; + unsigned have; + z_stream strm; + unsigned char in[CHUNK]; + unsigned char out[CHUNK]; + + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit(&strm); + if (ret != Z_OK) + return ret; + + /* decompress until deflate stream ends or end of file */ + do { + strm.avail_in = fread(in, 1, CHUNK, source); + if (ferror(source)) { + (void)inflateEnd(&strm); + return Z_ERRNO; + } + if (strm.avail_in == 0) + break; + strm.next_in = in; + + /* run inflate() on input until output buffer not full */ + do { + strm.avail_out = CHUNK; + strm.next_out = out; + ret = inflate(&strm, Z_NO_FLUSH); + assert(ret != Z_STREAM_ERROR); /* state not clobbered */ + switch (ret) { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; /* and fall through */ + case Z_DATA_ERROR: + case Z_MEM_ERROR: + (void)inflateEnd(&strm); + return ret; + } + have = CHUNK - strm.avail_out; + if (fwrite(out, 1, have, dest) != have || ferror(dest)) { + (void)inflateEnd(&strm); + return Z_ERRNO; + } + } while (strm.avail_out == 0); + + /* done when inflate() says it's done */ + } while (ret != Z_STREAM_END); + + /* clean up and return */ + (void)inflateEnd(&strm); + return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; +} + +/* report a zlib or i/o error */ +void zerr(int ret) +{ + fputs("zpipe: ", stderr); + switch (ret) { + case Z_ERRNO: + if (ferror(stdin)) + fputs("error reading stdin\n", stderr); + if (ferror(stdout)) + fputs("error writing stdout\n", stderr); + break; + case Z_STREAM_ERROR: + fputs("invalid compression level\n", stderr); + break; + case Z_DATA_ERROR: + fputs("invalid or incomplete deflate data\n", stderr); + break; + case Z_MEM_ERROR: + fputs("out of memory\n", stderr); + break; + case Z_VERSION_ERROR: + fputs("zlib version mismatch!\n", stderr); + } +} + +/* compress or decompress from stdin to stdout */ +int main(int argc, char **argv) +{ + int ret; + + /* avoid end-of-line conversions */ + SET_BINARY_MODE(stdin); + SET_BINARY_MODE(stdout); + + /* do compression if no arguments */ + if (argc == 1) { + ret = def(stdin, stdout, Z_DEFAULT_COMPRESSION); + if (ret != Z_OK) + zerr(ret); + return ret; + } + + /* do decompression if -d specified */ + else if (argc == 2 && strcmp(argv[1], "-d") == 0) { + ret = inf(stdin, stdout); + if (ret != Z_OK) + zerr(ret); + return ret; + } + + /* otherwise, report usage */ + else { + fputs("zpipe usage: zpipe [-d] < source > dest\n", stderr); + return 1; + } +} diff --git a/contrib/zlib/examples/zran.c b/contrib/zlib/examples/zran.c new file mode 100644 index 00000000..4fec6594 --- /dev/null +++ b/contrib/zlib/examples/zran.c @@ -0,0 +1,409 @@ +/* zran.c -- example of zlib/gzip stream indexing and random access + * Copyright (C) 2005, 2012 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + Version 1.1 29 Sep 2012 Mark Adler */ + +/* Version History: + 1.0 29 May 2005 First version + 1.1 29 Sep 2012 Fix memory reallocation error + */ + +/* Illustrate the use of Z_BLOCK, inflatePrime(), and inflateSetDictionary() + for random access of a compressed file. A file containing a zlib or gzip + stream is provided on the command line. The compressed stream is decoded in + its entirety, and an index built with access points about every SPAN bytes + in the uncompressed output. The compressed file is left open, and can then + be read randomly, having to decompress on the average SPAN/2 uncompressed + bytes before getting to the desired block of data. + + An access point can be created at the start of any deflate block, by saving + the starting file offset and bit of that block, and the 32K bytes of + uncompressed data that precede that block. Also the uncompressed offset of + that block is saved to provide a referece for locating a desired starting + point in the uncompressed stream. build_index() works by decompressing the + input zlib or gzip stream a block at a time, and at the end of each block + deciding if enough uncompressed data has gone by to justify the creation of + a new access point. If so, that point is saved in a data structure that + grows as needed to accommodate the points. + + To use the index, an offset in the uncompressed data is provided, for which + the latest access point at or preceding that offset is located in the index. + The input file is positioned to the specified location in the index, and if + necessary the first few bits of the compressed data is read from the file. + inflate is initialized with those bits and the 32K of uncompressed data, and + the decompression then proceeds until the desired offset in the file is + reached. Then the decompression continues to read the desired uncompressed + data from the file. + + Another approach would be to generate the index on demand. In that case, + requests for random access reads from the compressed data would try to use + the index, but if a read far enough past the end of the index is required, + then further index entries would be generated and added. + + There is some fair bit of overhead to starting inflation for the random + access, mainly copying the 32K byte dictionary. So if small pieces of the + file are being accessed, it would make sense to implement a cache to hold + some lookahead and avoid many calls to extract() for small lengths. + + Another way to build an index would be to use inflateCopy(). That would + not be constrained to have access points at block boundaries, but requires + more memory per access point, and also cannot be saved to file due to the + use of pointers in the state. The approach here allows for storage of the + index in a file. + */ + +#include +#include +#include +#include "zlib.h" + +#define local static + +#define SPAN 1048576L /* desired distance between access points */ +#define WINSIZE 32768U /* sliding window size */ +#define CHUNK 16384 /* file input buffer size */ + +/* access point entry */ +struct point { + off_t out; /* corresponding offset in uncompressed data */ + off_t in; /* offset in input file of first full byte */ + int bits; /* number of bits (1-7) from byte at in - 1, or 0 */ + unsigned char window[WINSIZE]; /* preceding 32K of uncompressed data */ +}; + +/* access point list */ +struct access { + int have; /* number of list entries filled in */ + int size; /* number of list entries allocated */ + struct point *list; /* allocated list */ +}; + +/* Deallocate an index built by build_index() */ +local void free_index(struct access *index) +{ + if (index != NULL) { + free(index->list); + free(index); + } +} + +/* Add an entry to the access point list. If out of memory, deallocate the + existing list and return NULL. */ +local struct access *addpoint(struct access *index, int bits, + off_t in, off_t out, unsigned left, unsigned char *window) +{ + struct point *next; + + /* if list is empty, create it (start with eight points) */ + if (index == NULL) { + index = malloc(sizeof(struct access)); + if (index == NULL) return NULL; + index->list = malloc(sizeof(struct point) << 3); + if (index->list == NULL) { + free(index); + return NULL; + } + index->size = 8; + index->have = 0; + } + + /* if list is full, make it bigger */ + else if (index->have == index->size) { + index->size <<= 1; + next = realloc(index->list, sizeof(struct point) * index->size); + if (next == NULL) { + free_index(index); + return NULL; + } + index->list = next; + } + + /* fill in entry and increment how many we have */ + next = index->list + index->have; + next->bits = bits; + next->in = in; + next->out = out; + if (left) + memcpy(next->window, window + WINSIZE - left, left); + if (left < WINSIZE) + memcpy(next->window + left, window, WINSIZE - left); + index->have++; + + /* return list, possibly reallocated */ + return index; +} + +/* Make one entire pass through the compressed stream and build an index, with + access points about every span bytes of uncompressed output -- span is + chosen to balance the speed of random access against the memory requirements + of the list, about 32K bytes per access point. Note that data after the end + of the first zlib or gzip stream in the file is ignored. build_index() + returns the number of access points on success (>= 1), Z_MEM_ERROR for out + of memory, Z_DATA_ERROR for an error in the input file, or Z_ERRNO for a + file read error. On success, *built points to the resulting index. */ +local int build_index(FILE *in, off_t span, struct access **built) +{ + int ret; + off_t totin, totout; /* our own total counters to avoid 4GB limit */ + off_t last; /* totout value of last access point */ + struct access *index; /* access points being generated */ + z_stream strm; + unsigned char input[CHUNK]; + unsigned char window[WINSIZE]; + + /* initialize inflate */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit2(&strm, 47); /* automatic zlib or gzip decoding */ + if (ret != Z_OK) + return ret; + + /* inflate the input, maintain a sliding window, and build an index -- this + also validates the integrity of the compressed data using the check + information at the end of the gzip or zlib stream */ + totin = totout = last = 0; + index = NULL; /* will be allocated by first addpoint() */ + strm.avail_out = 0; + do { + /* get some compressed data from input file */ + strm.avail_in = fread(input, 1, CHUNK, in); + if (ferror(in)) { + ret = Z_ERRNO; + goto build_index_error; + } + if (strm.avail_in == 0) { + ret = Z_DATA_ERROR; + goto build_index_error; + } + strm.next_in = input; + + /* process all of that, or until end of stream */ + do { + /* reset sliding window if necessary */ + if (strm.avail_out == 0) { + strm.avail_out = WINSIZE; + strm.next_out = window; + } + + /* inflate until out of input, output, or at end of block -- + update the total input and output counters */ + totin += strm.avail_in; + totout += strm.avail_out; + ret = inflate(&strm, Z_BLOCK); /* return at end of block */ + totin -= strm.avail_in; + totout -= strm.avail_out; + if (ret == Z_NEED_DICT) + ret = Z_DATA_ERROR; + if (ret == Z_MEM_ERROR || ret == Z_DATA_ERROR) + goto build_index_error; + if (ret == Z_STREAM_END) + break; + + /* if at end of block, consider adding an index entry (note that if + data_type indicates an end-of-block, then all of the + uncompressed data from that block has been delivered, and none + of the compressed data after that block has been consumed, + except for up to seven bits) -- the totout == 0 provides an + entry point after the zlib or gzip header, and assures that the + index always has at least one access point; we avoid creating an + access point after the last block by checking bit 6 of data_type + */ + if ((strm.data_type & 128) && !(strm.data_type & 64) && + (totout == 0 || totout - last > span)) { + index = addpoint(index, strm.data_type & 7, totin, + totout, strm.avail_out, window); + if (index == NULL) { + ret = Z_MEM_ERROR; + goto build_index_error; + } + last = totout; + } + } while (strm.avail_in != 0); + } while (ret != Z_STREAM_END); + + /* clean up and return index (release unused entries in list) */ + (void)inflateEnd(&strm); + index->list = realloc(index->list, sizeof(struct point) * index->have); + index->size = index->have; + *built = index; + return index->size; + + /* return error */ + build_index_error: + (void)inflateEnd(&strm); + if (index != NULL) + free_index(index); + return ret; +} + +/* Use the index to read len bytes from offset into buf, return bytes read or + negative for error (Z_DATA_ERROR or Z_MEM_ERROR). If data is requested past + the end of the uncompressed data, then extract() will return a value less + than len, indicating how much as actually read into buf. This function + should not return a data error unless the file was modified since the index + was generated. extract() may also return Z_ERRNO if there is an error on + reading or seeking the input file. */ +local int extract(FILE *in, struct access *index, off_t offset, + unsigned char *buf, int len) +{ + int ret, skip; + z_stream strm; + struct point *here; + unsigned char input[CHUNK]; + unsigned char discard[WINSIZE]; + + /* proceed only if something reasonable to do */ + if (len < 0) + return 0; + + /* find where in stream to start */ + here = index->list; + ret = index->have; + while (--ret && here[1].out <= offset) + here++; + + /* initialize file and inflate state to start there */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit2(&strm, -15); /* raw inflate */ + if (ret != Z_OK) + return ret; + ret = fseeko(in, here->in - (here->bits ? 1 : 0), SEEK_SET); + if (ret == -1) + goto extract_ret; + if (here->bits) { + ret = getc(in); + if (ret == -1) { + ret = ferror(in) ? Z_ERRNO : Z_DATA_ERROR; + goto extract_ret; + } + (void)inflatePrime(&strm, here->bits, ret >> (8 - here->bits)); + } + (void)inflateSetDictionary(&strm, here->window, WINSIZE); + + /* skip uncompressed bytes until offset reached, then satisfy request */ + offset -= here->out; + strm.avail_in = 0; + skip = 1; /* while skipping to offset */ + do { + /* define where to put uncompressed data, and how much */ + if (offset == 0 && skip) { /* at offset now */ + strm.avail_out = len; + strm.next_out = buf; + skip = 0; /* only do this once */ + } + if (offset > WINSIZE) { /* skip WINSIZE bytes */ + strm.avail_out = WINSIZE; + strm.next_out = discard; + offset -= WINSIZE; + } + else if (offset != 0) { /* last skip */ + strm.avail_out = (unsigned)offset; + strm.next_out = discard; + offset = 0; + } + + /* uncompress until avail_out filled, or end of stream */ + do { + if (strm.avail_in == 0) { + strm.avail_in = fread(input, 1, CHUNK, in); + if (ferror(in)) { + ret = Z_ERRNO; + goto extract_ret; + } + if (strm.avail_in == 0) { + ret = Z_DATA_ERROR; + goto extract_ret; + } + strm.next_in = input; + } + ret = inflate(&strm, Z_NO_FLUSH); /* normal inflate */ + if (ret == Z_NEED_DICT) + ret = Z_DATA_ERROR; + if (ret == Z_MEM_ERROR || ret == Z_DATA_ERROR) + goto extract_ret; + if (ret == Z_STREAM_END) + break; + } while (strm.avail_out != 0); + + /* if reach end of stream, then don't keep trying to get more */ + if (ret == Z_STREAM_END) + break; + + /* do until offset reached and requested data read, or stream ends */ + } while (skip); + + /* compute number of uncompressed bytes read after offset */ + ret = skip ? 0 : len - strm.avail_out; + + /* clean up and return bytes read or error */ + extract_ret: + (void)inflateEnd(&strm); + return ret; +} + +/* Demonstrate the use of build_index() and extract() by processing the file + provided on the command line, and the extracting 16K from about 2/3rds of + the way through the uncompressed output, and writing that to stdout. */ +int main(int argc, char **argv) +{ + int len; + off_t offset; + FILE *in; + struct access *index = NULL; + unsigned char buf[CHUNK]; + + /* open input file */ + if (argc != 2) { + fprintf(stderr, "usage: zran file.gz\n"); + return 1; + } + in = fopen(argv[1], "rb"); + if (in == NULL) { + fprintf(stderr, "zran: could not open %s for reading\n", argv[1]); + return 1; + } + + /* build index */ + len = build_index(in, SPAN, &index); + if (len < 0) { + fclose(in); + switch (len) { + case Z_MEM_ERROR: + fprintf(stderr, "zran: out of memory\n"); + break; + case Z_DATA_ERROR: + fprintf(stderr, "zran: compressed data error in %s\n", argv[1]); + break; + case Z_ERRNO: + fprintf(stderr, "zran: read error on %s\n", argv[1]); + break; + default: + fprintf(stderr, "zran: error %d while building index\n", len); + } + return 1; + } + fprintf(stderr, "zran: built index with %d access points\n", len); + + /* use index by reading some bytes from an arbitrary offset */ + offset = (index->list[index->have - 1].out << 1) / 3; + len = extract(in, index, offset, buf, CHUNK); + if (len < 0) + fprintf(stderr, "zran: extraction failed: %s error\n", + len == Z_MEM_ERROR ? "out of memory" : "input corrupted"); + else { + fwrite(buf, 1, len, stdout); + fprintf(stderr, "zran: extracted %d bytes at %llu\n", len, offset); + } + + /* clean up and exit */ + free_index(index); + fclose(in); + return 0; +} diff --git a/contrib/zlib/gzclose.c b/contrib/zlib/gzclose.c new file mode 100644 index 00000000..caeb99a3 --- /dev/null +++ b/contrib/zlib/gzclose.c @@ -0,0 +1,25 @@ +/* gzclose.c -- zlib gzclose() function + * Copyright (C) 2004, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* gzclose() is in a separate file so that it is linked in only if it is used. + That way the other gzclose functions can be used instead to avoid linking in + unneeded compression or decompression routines. */ +int ZEXPORT gzclose(file) + gzFile file; +{ +#ifndef NO_GZCOMPRESS + gz_statep state; + + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file); +#else + return gzclose_r(file); +#endif +} diff --git a/contrib/zlib/gzguts.h b/contrib/zlib/gzguts.h new file mode 100644 index 00000000..990a4d25 --- /dev/null +++ b/contrib/zlib/gzguts.h @@ -0,0 +1,218 @@ +/* gzguts.h -- zlib internal header definitions for gz* operations + * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef _LARGEFILE64_SOURCE +# ifndef _LARGEFILE_SOURCE +# define _LARGEFILE_SOURCE 1 +# endif +# ifdef _FILE_OFFSET_BITS +# undef _FILE_OFFSET_BITS +# endif +#endif + +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include +#include "zlib.h" +#ifdef STDC +# include +# include +# include +#endif + +#ifndef _POSIX_SOURCE +# define _POSIX_SOURCE +#endif +#include + +#ifdef _WIN32 +# include +#endif + +#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) +# include +#endif + +#if defined(_WIN32) || defined(__CYGWIN__) +# define WIDECHAR +#endif + +#ifdef WINAPI_FAMILY +# define open _open +# define read _read +# define write _write +# define close _close +#endif + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS +/* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 +/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) +# define vsnprintf _vsnprintf +# endif +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +# ifdef VMS +# define NO_vsnprintf +# endif +# ifdef __OS400__ +# define NO_vsnprintf +# endif +# ifdef __MVS__ +# define NO_vsnprintf +# endif +#endif + +/* unlike snprintf (which is required in C99), _snprintf does not guarantee + null termination of the result -- however this is only used in gzlib.c where + the result is assured to fit in the space provided */ +#if defined(_MSC_VER) && _MSC_VER < 1900 +# define snprintf _snprintf +#endif + +#ifndef local +# define local static +#endif +/* since "static" is used to mean two completely different things in C, we + define "local" for the non-static meaning of "static", for readability + (compile with -Dlocal if your debugger can't find static symbols) */ + +/* gz* functions always use library allocation functions */ +#ifndef STDC + extern voidp malloc OF((uInt size)); + extern void free OF((voidpf ptr)); +#endif + +/* get errno and strerror definition */ +#if defined UNDER_CE +# include +# define zstrerror() gz_strwinerror((DWORD)GetLastError()) +#else +# ifndef NO_STRERROR +# include +# define zstrerror() strerror(errno) +# else +# define zstrerror() "stdio error (consult errno)" +# endif +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); +#endif + +/* default memLevel */ +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif + +/* default i/o buffer size -- double this for output when reading (this and + twice this must be able to fit in an unsigned type) */ +#define GZBUFSIZE 8192 + +/* gzip modes, also provide a little integrity check on the passed structure */ +#define GZ_NONE 0 +#define GZ_READ 7247 +#define GZ_WRITE 31153 +#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ + +/* values for gz_state how */ +#define LOOK 0 /* look for a gzip header */ +#define COPY 1 /* copy input directly */ +#define GZIP 2 /* decompress a gzip stream */ + +/* internal gzip file state data structure */ +typedef struct { + /* exposed contents for gzgetc() macro */ + struct gzFile_s x; /* "x" for exposed */ + /* x.have: number of bytes available at x.next */ + /* x.next: next output data to deliver or write */ + /* x.pos: current position in uncompressed data */ + /* used for both reading and writing */ + int mode; /* see gzip modes above */ + int fd; /* file descriptor */ + char *path; /* path or fd for error messages */ + unsigned size; /* buffer size, zero if not allocated yet */ + unsigned want; /* requested buffer size, default is GZBUFSIZE */ + unsigned char *in; /* input buffer (double-sized when writing) */ + unsigned char *out; /* output buffer (double-sized when reading) */ + int direct; /* 0 if processing gzip, 1 if transparent */ + /* just for reading */ + int how; /* 0: get header, 1: copy, 2: decompress */ + z_off64_t start; /* where the gzip data started, for rewinding */ + int eof; /* true if end of input file reached */ + int past; /* true if read requested past end */ + /* just for writing */ + int level; /* compression level */ + int strategy; /* compression strategy */ + /* seek request */ + z_off64_t skip; /* amount to skip (already rewound if backwards) */ + int seek; /* true if seek request pending */ + /* error information */ + int err; /* error code */ + char *msg; /* error message */ + /* zlib inflate or deflate stream */ + z_stream strm; /* stream structure in-place (not a pointer) */ +} gz_state; +typedef gz_state FAR *gz_statep; + +/* shared functions */ +void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); +#if defined UNDER_CE +char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); +#endif + +/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t + value -- needed when comparing unsigned to z_off64_t, which is signed + (possible z_off64_t types off_t, off64_t, and long are all signed) */ +#ifdef INT_MAX +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) +#else +unsigned ZLIB_INTERNAL gz_intmax OF((void)); +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) +#endif diff --git a/contrib/zlib/gzlib.c b/contrib/zlib/gzlib.c new file mode 100644 index 00000000..4105e6af --- /dev/null +++ b/contrib/zlib/gzlib.c @@ -0,0 +1,637 @@ +/* gzlib.c -- zlib functions common to reading and writing gzip files + * Copyright (C) 2004-2017 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +#if defined(_WIN32) && !defined(__BORLANDC__) && !defined(__MINGW32__) +# define LSEEK _lseeki64 +#else +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +# define LSEEK lseek64 +#else +# define LSEEK lseek +#endif +#endif + +/* Local functions */ +local void gz_reset OF((gz_statep)); +local gzFile gz_open OF((const void *, int, const char *)); + +#if defined UNDER_CE + +/* Map the Windows error number in ERROR to a locale-dependent error message + string and return a pointer to it. Typically, the values for ERROR come + from GetLastError. + + The string pointed to shall not be modified by the application, but may be + overwritten by a subsequent call to gz_strwinerror + + The gz_strwinerror function does not change the current setting of + GetLastError. */ +char ZLIB_INTERNAL *gz_strwinerror (error) + DWORD error; +{ + static char buf[1024]; + + wchar_t *msgbuf; + DWORD lasterr = GetLastError(); + DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + error, + 0, /* Default language */ + (LPVOID)&msgbuf, + 0, + NULL); + if (chars != 0) { + /* If there is an \r\n appended, zap it. */ + if (chars >= 2 + && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { + chars -= 2; + msgbuf[chars] = 0; + } + + if (chars > sizeof (buf) - 1) { + chars = sizeof (buf) - 1; + msgbuf[chars] = 0; + } + + wcstombs(buf, msgbuf, chars + 1); + LocalFree(msgbuf); + } + else { + sprintf(buf, "unknown win32 error (%ld)", error); + } + + SetLastError(lasterr); + return buf; +} + +#endif /* UNDER_CE */ + +/* Reset gzip file state */ +local void gz_reset(state) + gz_statep state; +{ + state->x.have = 0; /* no output data available */ + if (state->mode == GZ_READ) { /* for reading ... */ + state->eof = 0; /* not at end of file */ + state->past = 0; /* have not read past end yet */ + state->how = LOOK; /* look for gzip header */ + } + state->seek = 0; /* no seek request pending */ + gz_error(state, Z_OK, NULL); /* clear error */ + state->x.pos = 0; /* no uncompressed data yet */ + state->strm.avail_in = 0; /* no input data yet */ +} + +/* Open a gzip file either by name or file descriptor. */ +local gzFile gz_open(path, fd, mode) + const void *path; + int fd; + const char *mode; +{ + gz_statep state; + z_size_t len; + int oflag; +#ifdef O_CLOEXEC + int cloexec = 0; +#endif +#ifdef O_EXCL + int exclusive = 0; +#endif + + /* check input */ + if (path == NULL) + return NULL; + + /* allocate gzFile structure to return */ + state = (gz_statep)malloc(sizeof(gz_state)); + if (state == NULL) + return NULL; + state->size = 0; /* no buffers allocated yet */ + state->want = GZBUFSIZE; /* requested buffer size */ + state->msg = NULL; /* no error message yet */ + + /* interpret mode */ + state->mode = GZ_NONE; + state->level = Z_DEFAULT_COMPRESSION; + state->strategy = Z_DEFAULT_STRATEGY; + state->direct = 0; + while (*mode) { + if (*mode >= '0' && *mode <= '9') + state->level = *mode - '0'; + else + switch (*mode) { + case 'r': + state->mode = GZ_READ; + break; +#ifndef NO_GZCOMPRESS + case 'w': + state->mode = GZ_WRITE; + break; + case 'a': + state->mode = GZ_APPEND; + break; +#endif + case '+': /* can't read and write at the same time */ + free(state); + return NULL; + case 'b': /* ignore -- will request binary anyway */ + break; +#ifdef O_CLOEXEC + case 'e': + cloexec = 1; + break; +#endif +#ifdef O_EXCL + case 'x': + exclusive = 1; + break; +#endif + case 'f': + state->strategy = Z_FILTERED; + break; + case 'h': + state->strategy = Z_HUFFMAN_ONLY; + break; + case 'R': + state->strategy = Z_RLE; + break; + case 'F': + state->strategy = Z_FIXED; + break; + case 'T': + state->direct = 1; + break; + default: /* could consider as an error, but just ignore */ + ; + } + mode++; + } + + /* must provide an "r", "w", or "a" */ + if (state->mode == GZ_NONE) { + free(state); + return NULL; + } + + /* can't force transparent read */ + if (state->mode == GZ_READ) { + if (state->direct) { + free(state); + return NULL; + } + state->direct = 1; /* for empty file */ + } + + /* save the path name for error messages */ +#ifdef WIDECHAR + if (fd == -2) { + len = wcstombs(NULL, path, 0); + if (len == (z_size_t)-1) + len = 0; + } + else +#endif + len = strlen((const char *)path); + state->path = (char *)malloc(len + 1); + if (state->path == NULL) { + free(state); + return NULL; + } +#ifdef WIDECHAR + if (fd == -2) + if (len) + wcstombs(state->path, path, len + 1); + else + *(state->path) = 0; + else +#endif +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + (void)snprintf(state->path, len + 1, "%s", (const char *)path); +#else + strcpy(state->path, path); +#endif + + /* compute the flags for open() */ + oflag = +#ifdef O_LARGEFILE + O_LARGEFILE | +#endif +#ifdef O_BINARY + O_BINARY | +#endif +#ifdef O_CLOEXEC + (cloexec ? O_CLOEXEC : 0) | +#endif + (state->mode == GZ_READ ? + O_RDONLY : + (O_WRONLY | O_CREAT | +#ifdef O_EXCL + (exclusive ? O_EXCL : 0) | +#endif + (state->mode == GZ_WRITE ? + O_TRUNC : + O_APPEND))); + + /* open the file with the appropriate flags (or just use fd) */ + state->fd = fd > -1 ? fd : ( +#ifdef WIDECHAR + fd == -2 ? _wopen(path, oflag, 0666) : +#endif + open((const char *)path, oflag, 0666)); + if (state->fd == -1) { + free(state->path); + free(state); + return NULL; + } + if (state->mode == GZ_APPEND) { + LSEEK(state->fd, 0, SEEK_END); /* so gzoffset() is correct */ + state->mode = GZ_WRITE; /* simplify later checks */ + } + + /* save the current position for rewinding (only if reading) */ + if (state->mode == GZ_READ) { + state->start = LSEEK(state->fd, 0, SEEK_CUR); + if (state->start == -1) state->start = 0; + } + + /* initialize stream */ + gz_reset(state); + + /* return stream */ + return (gzFile)state; +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzopen(path, mode) + const char *path; + const char *mode; +{ + return gz_open(path, -1, mode); +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzopen64(path, mode) + const char *path; + const char *mode; +{ + return gz_open(path, -1, mode); +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzdopen(fd, mode) + int fd; + const char *mode; +{ + char *path; /* identifier for error messages */ + gzFile gz; + + if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL) + return NULL; +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + (void)snprintf(path, 7 + 3 * sizeof(int), "", fd); +#else + sprintf(path, "", fd); /* for debugging */ +#endif + gz = gz_open(path, fd, mode); + free(path); + return gz; +} + +/* -- see zlib.h -- */ +#ifdef WIDECHAR +gzFile ZEXPORT gzopen_w(path, mode) + const wchar_t *path; + const char *mode; +{ + return gz_open(path, -2, mode); +} +#endif + +/* -- see zlib.h -- */ +int ZEXPORT gzbuffer(file, size) + gzFile file; + unsigned size; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* make sure we haven't already allocated memory */ + if (state->size != 0) + return -1; + + /* check and set requested size */ + if ((size << 1) < size) + return -1; /* need to be able to double it */ + if (size < 2) + size = 2; /* need two bytes to check magic header */ + state->want = size; + return 0; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzrewind(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* back up and start over */ + if (LSEEK(state->fd, state->start, SEEK_SET) == -1) + return -1; + gz_reset(state); + return 0; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gzseek64(file, offset, whence) + gzFile file; + z_off64_t offset; + int whence; +{ + unsigned n; + z_off64_t ret; + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* check that there's no error */ + if (state->err != Z_OK && state->err != Z_BUF_ERROR) + return -1; + + /* can only seek from start or relative to current position */ + if (whence != SEEK_SET && whence != SEEK_CUR) + return -1; + + /* normalize offset to a SEEK_CUR specification */ + if (whence == SEEK_SET) + offset -= state->x.pos; + else if (state->seek) + offset += state->skip; + state->seek = 0; + + /* if within raw area while reading, just go there */ + if (state->mode == GZ_READ && state->how == COPY && + state->x.pos + offset >= 0) { + ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR); + if (ret == -1) + return -1; + state->x.have = 0; + state->eof = 0; + state->past = 0; + state->seek = 0; + gz_error(state, Z_OK, NULL); + state->strm.avail_in = 0; + state->x.pos += offset; + return state->x.pos; + } + + /* calculate skip amount, rewinding if needed for back seek when reading */ + if (offset < 0) { + if (state->mode != GZ_READ) /* writing -- can't go backwards */ + return -1; + offset += state->x.pos; + if (offset < 0) /* before start of file! */ + return -1; + if (gzrewind(file) == -1) /* rewind, then skip to offset */ + return -1; + } + + /* if reading, skip what's in output buffer (one less gzgetc() check) */ + if (state->mode == GZ_READ) { + n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ? + (unsigned)offset : state->x.have; + state->x.have -= n; + state->x.next += n; + state->x.pos += n; + offset -= n; + } + + /* request skip (if not zero) */ + if (offset) { + state->seek = 1; + state->skip = offset; + } + return state->x.pos + offset; +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gzseek(file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + z_off64_t ret; + + ret = gzseek64(file, (z_off64_t)offset, whence); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gztell64(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* return position */ + return state->x.pos + (state->seek ? state->skip : 0); +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gztell(file) + gzFile file; +{ + z_off64_t ret; + + ret = gztell64(file); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gzoffset64(file) + gzFile file; +{ + z_off64_t offset; + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* compute and return effective offset in file */ + offset = LSEEK(state->fd, 0, SEEK_CUR); + if (offset == -1) + return -1; + if (state->mode == GZ_READ) /* reading */ + offset -= state->strm.avail_in; /* don't count buffered input */ + return offset; +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gzoffset(file) + gzFile file; +{ + z_off64_t ret; + + ret = gzoffset64(file); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzeof(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return 0; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return 0; + + /* return end-of-file state */ + return state->mode == GZ_READ ? state->past : 0; +} + +/* -- see zlib.h -- */ +const char * ZEXPORT gzerror(file, errnum) + gzFile file; + int *errnum; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return NULL; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return NULL; + + /* return error information */ + if (errnum != NULL) + *errnum = state->err; + return state->err == Z_MEM_ERROR ? "out of memory" : + (state->msg == NULL ? "" : state->msg); +} + +/* -- see zlib.h -- */ +void ZEXPORT gzclearerr(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return; + + /* clear error and end-of-file */ + if (state->mode == GZ_READ) { + state->eof = 0; + state->past = 0; + } + gz_error(state, Z_OK, NULL); +} + +/* Create an error message in allocated memory and set state->err and + state->msg accordingly. Free any previous error message already there. Do + not try to free or allocate space if the error is Z_MEM_ERROR (out of + memory). Simply save the error message as a static string. If there is an + allocation failure constructing the error message, then convert the error to + out of memory. */ +void ZLIB_INTERNAL gz_error(state, err, msg) + gz_statep state; + int err; + const char *msg; +{ + /* free previously allocated message and clear */ + if (state->msg != NULL) { + if (state->err != Z_MEM_ERROR) + free(state->msg); + state->msg = NULL; + } + + /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */ + if (err != Z_OK && err != Z_BUF_ERROR) + state->x.have = 0; + + /* set error code, and if no message, then done */ + state->err = err; + if (msg == NULL) + return; + + /* for an out of memory error, return literal string when requested */ + if (err == Z_MEM_ERROR) + return; + + /* construct error message with path */ + if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) == + NULL) { + state->err = Z_MEM_ERROR; + return; + } +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, + "%s%s%s", state->path, ": ", msg); +#else + strcpy(state->msg, state->path); + strcat(state->msg, ": "); + strcat(state->msg, msg); +#endif +} + +#ifndef INT_MAX +/* portably return maximum value for an int (when limits.h presumed not + available) -- we need to do this to cover cases where 2's complement not + used, since C standard permits 1's complement and sign-bit representations, + otherwise we could just use ((unsigned)-1) >> 1 */ +unsigned ZLIB_INTERNAL gz_intmax() +{ + unsigned p, q; + + p = 1; + do { + q = p; + p <<= 1; + p++; + } while (p > q); + return q >> 1; +} +#endif diff --git a/contrib/zlib/gzread.c b/contrib/zlib/gzread.c new file mode 100644 index 00000000..956b91ea --- /dev/null +++ b/contrib/zlib/gzread.c @@ -0,0 +1,654 @@ +/* gzread.c -- zlib functions for reading gzip files + * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* Local functions */ +local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *)); +local int gz_avail OF((gz_statep)); +local int gz_look OF((gz_statep)); +local int gz_decomp OF((gz_statep)); +local int gz_fetch OF((gz_statep)); +local int gz_skip OF((gz_statep, z_off64_t)); +local z_size_t gz_read OF((gz_statep, voidp, z_size_t)); + +/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from + state->fd, and update state->eof, state->err, and state->msg as appropriate. + This function needs to loop on read(), since read() is not guaranteed to + read the number of bytes requested, depending on the type of descriptor. */ +local int gz_load(state, buf, len, have) + gz_statep state; + unsigned char *buf; + unsigned len; + unsigned *have; +{ + int ret; + unsigned get, max = ((unsigned)-1 >> 2) + 1; + + *have = 0; + do { + get = len - *have; + if (get > max) + get = max; + ret = read(state->fd, buf + *have, get); + if (ret <= 0) + break; + *have += (unsigned)ret; + } while (*have < len); + if (ret < 0) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + if (ret == 0) + state->eof = 1; + return 0; +} + +/* Load up input buffer and set eof flag if last data loaded -- return -1 on + error, 0 otherwise. Note that the eof flag is set when the end of the input + file is reached, even though there may be unused data in the buffer. Once + that data has been used, no more attempts will be made to read the file. + If strm->avail_in != 0, then the current data is moved to the beginning of + the input buffer, and then the remainder of the buffer is loaded with the + available data from the input file. */ +local int gz_avail(state) + gz_statep state; +{ + unsigned got; + z_streamp strm = &(state->strm); + + if (state->err != Z_OK && state->err != Z_BUF_ERROR) + return -1; + if (state->eof == 0) { + if (strm->avail_in) { /* copy what's there to the start */ + unsigned char *p = state->in; + unsigned const char *q = strm->next_in; + unsigned n = strm->avail_in; + do { + *p++ = *q++; + } while (--n); + } + if (gz_load(state, state->in + strm->avail_in, + state->size - strm->avail_in, &got) == -1) + return -1; + strm->avail_in += got; + strm->next_in = state->in; + } + return 0; +} + +/* Look for gzip header, set up for inflate or copy. state->x.have must be 0. + If this is the first time in, allocate required memory. state->how will be + left unchanged if there is no more input data available, will be set to COPY + if there is no gzip header and direct copying will be performed, or it will + be set to GZIP for decompression. If direct copying, then leftover input + data from the input buffer will be copied to the output buffer. In that + case, all further file reads will be directly to either the output buffer or + a user buffer. If decompressing, the inflate state will be initialized. + gz_look() will return 0 on success or -1 on failure. */ +local int gz_look(state) + gz_statep state; +{ + z_streamp strm = &(state->strm); + + /* allocate read buffers and inflate memory */ + if (state->size == 0) { + /* allocate buffers */ + state->in = (unsigned char *)malloc(state->want); + state->out = (unsigned char *)malloc(state->want << 1); + if (state->in == NULL || state->out == NULL) { + free(state->out); + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + state->size = state->want; + + /* allocate inflate memory */ + state->strm.zalloc = Z_NULL; + state->strm.zfree = Z_NULL; + state->strm.opaque = Z_NULL; + state->strm.avail_in = 0; + state->strm.next_in = Z_NULL; + if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) { /* gunzip */ + free(state->out); + free(state->in); + state->size = 0; + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + } + + /* get at least the magic bytes in the input buffer */ + if (strm->avail_in < 2) { + if (gz_avail(state) == -1) + return -1; + if (strm->avail_in == 0) + return 0; + } + + /* look for gzip magic bytes -- if there, do gzip decoding (note: there is + a logical dilemma here when considering the case of a partially written + gzip file, to wit, if a single 31 byte is written, then we cannot tell + whether this is a single-byte file, or just a partially written gzip + file -- for here we assume that if a gzip file is being written, then + the header will be written in a single operation, so that reading a + single byte is sufficient indication that it is not a gzip file) */ + if (strm->avail_in > 1 && + strm->next_in[0] == 31 && strm->next_in[1] == 139) { + inflateReset(strm); + state->how = GZIP; + state->direct = 0; + return 0; + } + + /* no gzip header -- if we were decoding gzip before, then this is trailing + garbage. Ignore the trailing garbage and finish. */ + if (state->direct == 0) { + strm->avail_in = 0; + state->eof = 1; + state->x.have = 0; + return 0; + } + + /* doing raw i/o, copy any leftover input to output -- this assumes that + the output buffer is larger than the input buffer, which also assures + space for gzungetc() */ + state->x.next = state->out; + if (strm->avail_in) { + memcpy(state->x.next, strm->next_in, strm->avail_in); + state->x.have = strm->avail_in; + strm->avail_in = 0; + } + state->how = COPY; + state->direct = 1; + return 0; +} + +/* Decompress from input to the provided next_out and avail_out in the state. + On return, state->x.have and state->x.next point to the just decompressed + data. If the gzip stream completes, state->how is reset to LOOK to look for + the next gzip stream or raw data, once state->x.have is depleted. Returns 0 + on success, -1 on failure. */ +local int gz_decomp(state) + gz_statep state; +{ + int ret = Z_OK; + unsigned had; + z_streamp strm = &(state->strm); + + /* fill output buffer up to end of deflate stream */ + had = strm->avail_out; + do { + /* get more input for inflate() */ + if (strm->avail_in == 0 && gz_avail(state) == -1) + return -1; + if (strm->avail_in == 0) { + gz_error(state, Z_BUF_ERROR, "unexpected end of file"); + break; + } + + /* decompress and handle errors */ + ret = inflate(strm, Z_NO_FLUSH); + if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { + gz_error(state, Z_STREAM_ERROR, + "internal error: inflate stream corrupt"); + return -1; + } + if (ret == Z_MEM_ERROR) { + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ + gz_error(state, Z_DATA_ERROR, + strm->msg == NULL ? "compressed data error" : strm->msg); + return -1; + } + } while (strm->avail_out && ret != Z_STREAM_END); + + /* update available output */ + state->x.have = had - strm->avail_out; + state->x.next = strm->next_out - state->x.have; + + /* if the gzip stream completed successfully, look for another */ + if (ret == Z_STREAM_END) + state->how = LOOK; + + /* good decompression */ + return 0; +} + +/* Fetch data and put it in the output buffer. Assumes state->x.have is 0. + Data is either copied from the input file or decompressed from the input + file depending on state->how. If state->how is LOOK, then a gzip header is + looked for to determine whether to copy or decompress. Returns -1 on error, + otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the + end of the input file has been reached and all data has been processed. */ +local int gz_fetch(state) + gz_statep state; +{ + z_streamp strm = &(state->strm); + + do { + switch(state->how) { + case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */ + if (gz_look(state) == -1) + return -1; + if (state->how == LOOK) + return 0; + break; + case COPY: /* -> COPY */ + if (gz_load(state, state->out, state->size << 1, &(state->x.have)) + == -1) + return -1; + state->x.next = state->out; + return 0; + case GZIP: /* -> GZIP or LOOK (if end of gzip stream) */ + strm->avail_out = state->size << 1; + strm->next_out = state->out; + if (gz_decomp(state) == -1) + return -1; + } + } while (state->x.have == 0 && (!state->eof || strm->avail_in)); + return 0; +} + +/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ +local int gz_skip(state, len) + gz_statep state; + z_off64_t len; +{ + unsigned n; + + /* skip over len bytes or reach end-of-file, whichever comes first */ + while (len) + /* skip over whatever is in output buffer */ + if (state->x.have) { + n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ? + (unsigned)len : state->x.have; + state->x.have -= n; + state->x.next += n; + state->x.pos += n; + len -= n; + } + + /* output buffer empty -- return if we're at the end of the input */ + else if (state->eof && state->strm.avail_in == 0) + break; + + /* need more data to skip -- load up output buffer */ + else { + /* get more output, looking for header if required */ + if (gz_fetch(state) == -1) + return -1; + } + return 0; +} + +/* Read len bytes into buf from file, or less than len up to the end of the + input. Return the number of bytes read. If zero is returned, either the + end of file was reached, or there was an error. state->err must be + consulted in that case to determine which. */ +local z_size_t gz_read(state, buf, len) + gz_statep state; + voidp buf; + z_size_t len; +{ + z_size_t got; + unsigned n; + + /* if len is zero, avoid unnecessary operations */ + if (len == 0) + return 0; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return 0; + } + + /* get len bytes to buf, or less than len if at the end */ + got = 0; + do { + /* set n to the maximum amount of len that fits in an unsigned int */ + n = -1; + if (n > len) + n = len; + + /* first just try copying data from the output buffer */ + if (state->x.have) { + if (state->x.have < n) + n = state->x.have; + memcpy(buf, state->x.next, n); + state->x.next += n; + state->x.have -= n; + } + + /* output buffer empty -- return if we're at the end of the input */ + else if (state->eof && state->strm.avail_in == 0) { + state->past = 1; /* tried to read past end */ + break; + } + + /* need output data -- for small len or new stream load up our output + buffer */ + else if (state->how == LOOK || n < (state->size << 1)) { + /* get more output, looking for header if required */ + if (gz_fetch(state) == -1) + return 0; + continue; /* no progress yet -- go back to copy above */ + /* the copy above assures that we will leave with space in the + output buffer, allowing at least one gzungetc() to succeed */ + } + + /* large len -- read directly into user buffer */ + else if (state->how == COPY) { /* read directly */ + if (gz_load(state, (unsigned char *)buf, n, &n) == -1) + return 0; + } + + /* large len -- decompress directly into user buffer */ + else { /* state->how == GZIP */ + state->strm.avail_out = n; + state->strm.next_out = (unsigned char *)buf; + if (gz_decomp(state) == -1) + return 0; + n = state->x.have; + state->x.have = 0; + } + + /* update progress */ + len -= n; + buf = (char *)buf + n; + got += n; + state->x.pos += n; + } while (len); + + /* return number of bytes read into user buffer */ + return got; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzread(file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* since an int is returned, make sure len fits in one, otherwise return + with an error (this avoids a flaw in the interface) */ + if ((int)len < 0) { + gz_error(state, Z_STREAM_ERROR, "request does not fit in an int"); + return -1; + } + + /* read len or fewer bytes to buf */ + len = gz_read(state, buf, len); + + /* check for an error */ + if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR) + return -1; + + /* return the number of bytes read (this is assured to fit in an int) */ + return (int)len; +} + +/* -- see zlib.h -- */ +z_size_t ZEXPORT gzfread(buf, size, nitems, file) + voidp buf; + z_size_t size; + z_size_t nitems; + gzFile file; +{ + z_size_t len; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return 0; + + /* compute bytes to read -- error on overflow */ + len = nitems * size; + if (size && len / size != nitems) { + gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); + return 0; + } + + /* read len or fewer bytes to buf, return the number of full items read */ + return len ? gz_read(state, buf, len) / size : 0; +} + +/* -- see zlib.h -- */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +#else +# undef gzgetc +#endif +int ZEXPORT gzgetc(file) + gzFile file; +{ + int ret; + unsigned char buf[1]; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* try output buffer (no need to check for skip request) */ + if (state->x.have) { + state->x.have--; + state->x.pos++; + return *(state->x.next)++; + } + + /* nothing there -- try gz_read() */ + ret = gz_read(state, buf, 1); + return ret < 1 ? -1 : buf[0]; +} + +int ZEXPORT gzgetc_(file) +gzFile file; +{ + return gzgetc(file); +} + +/* -- see zlib.h -- */ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return -1; + } + + /* can't push EOF */ + if (c < 0) + return -1; + + /* if output buffer empty, put byte at end (allows more pushing) */ + if (state->x.have == 0) { + state->x.have = 1; + state->x.next = state->out + (state->size << 1) - 1; + state->x.next[0] = (unsigned char)c; + state->x.pos--; + state->past = 0; + return c; + } + + /* if no room, give up (must have already done a gzungetc()) */ + if (state->x.have == (state->size << 1)) { + gz_error(state, Z_DATA_ERROR, "out of room to push characters"); + return -1; + } + + /* slide output data if needed and insert byte before existing data */ + if (state->x.next == state->out) { + unsigned char *src = state->out + state->x.have; + unsigned char *dest = state->out + (state->size << 1); + while (src > state->out) + *--dest = *--src; + state->x.next = dest; + } + state->x.have++; + state->x.next--; + state->x.next[0] = (unsigned char)c; + state->x.pos--; + state->past = 0; + return c; +} + +/* -- see zlib.h -- */ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + unsigned left, n; + char *str; + unsigned char *eol; + gz_statep state; + + /* check parameters and get internal structure */ + if (file == NULL || buf == NULL || len < 1) + return NULL; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return NULL; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return NULL; + } + + /* copy output bytes up to new line or len - 1, whichever comes first -- + append a terminating zero to the string (we don't check for a zero in + the contents, let the user worry about that) */ + str = buf; + left = (unsigned)len - 1; + if (left) do { + /* assure that something is in the output buffer */ + if (state->x.have == 0 && gz_fetch(state) == -1) + return NULL; /* error */ + if (state->x.have == 0) { /* end of file */ + state->past = 1; /* read past end */ + break; /* return what we have */ + } + + /* look for end-of-line in current output buffer */ + n = state->x.have > left ? left : state->x.have; + eol = (unsigned char *)memchr(state->x.next, '\n', n); + if (eol != NULL) + n = (unsigned)(eol - state->x.next) + 1; + + /* copy through end-of-line, or remainder if not found */ + memcpy(buf, state->x.next, n); + state->x.have -= n; + state->x.next += n; + state->x.pos += n; + left -= n; + buf += n; + } while (left && eol == NULL); + + /* return terminated string, or if nothing, end of file */ + if (buf == str) + return NULL; + buf[0] = 0; + return str; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzdirect(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* if the state is not known, but we can find out, then do so (this is + mainly for right after a gzopen() or gzdopen()) */ + if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) + (void)gz_look(state); + + /* return 1 if transparent, 0 if processing a gzip stream */ + return state->direct; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzclose_r(file) + gzFile file; +{ + int ret, err; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + /* check that we're reading */ + if (state->mode != GZ_READ) + return Z_STREAM_ERROR; + + /* free memory and close file */ + if (state->size) { + inflateEnd(&(state->strm)); + free(state->out); + free(state->in); + } + err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK; + gz_error(state, Z_OK, NULL); + free(state->path); + ret = close(state->fd); + free(state); + return ret ? Z_ERRNO : err; +} diff --git a/contrib/zlib/gzwrite.c b/contrib/zlib/gzwrite.c new file mode 100644 index 00000000..c7b5651d --- /dev/null +++ b/contrib/zlib/gzwrite.c @@ -0,0 +1,665 @@ +/* gzwrite.c -- zlib functions for writing gzip files + * Copyright (C) 2004-2017 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* Local functions */ +local int gz_init OF((gz_statep)); +local int gz_comp OF((gz_statep, int)); +local int gz_zero OF((gz_statep, z_off64_t)); +local z_size_t gz_write OF((gz_statep, voidpc, z_size_t)); + +/* Initialize state for writing a gzip file. Mark initialization by setting + state->size to non-zero. Return -1 on a memory allocation failure, or 0 on + success. */ +local int gz_init(state) + gz_statep state; +{ + int ret; + z_streamp strm = &(state->strm); + + /* allocate input buffer (double size for gzprintf) */ + state->in = (unsigned char *)malloc(state->want << 1); + if (state->in == NULL) { + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + + /* only need output buffer and deflate state if compressing */ + if (!state->direct) { + /* allocate output buffer */ + state->out = (unsigned char *)malloc(state->want); + if (state->out == NULL) { + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + + /* allocate deflate memory, set up for gzip compression */ + strm->zalloc = Z_NULL; + strm->zfree = Z_NULL; + strm->opaque = Z_NULL; + ret = deflateInit2(strm, state->level, Z_DEFLATED, + MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy); + if (ret != Z_OK) { + free(state->out); + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + strm->next_in = NULL; + } + + /* mark state as initialized */ + state->size = state->want; + + /* initialize write buffer if compressing */ + if (!state->direct) { + strm->avail_out = state->size; + strm->next_out = state->out; + state->x.next = strm->next_out; + } + return 0; +} + +/* Compress whatever is at avail_in and next_in and write to the output file. + Return -1 if there is an error writing to the output file or if gz_init() + fails to allocate memory, otherwise 0. flush is assumed to be a valid + deflate() flush value. If flush is Z_FINISH, then the deflate() state is + reset to start a new gzip stream. If gz->direct is true, then simply write + to the output file without compressing, and ignore flush. */ +local int gz_comp(state, flush) + gz_statep state; + int flush; +{ + int ret, writ; + unsigned have, put, max = ((unsigned)-1 >> 2) + 1; + z_streamp strm = &(state->strm); + + /* allocate memory if this is the first time through */ + if (state->size == 0 && gz_init(state) == -1) + return -1; + + /* write directly if requested */ + if (state->direct) { + while (strm->avail_in) { + put = strm->avail_in > max ? max : strm->avail_in; + writ = write(state->fd, strm->next_in, put); + if (writ < 0) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + strm->avail_in -= (unsigned)writ; + strm->next_in += writ; + } + return 0; + } + + /* run deflate() on provided input until it produces no more output */ + ret = Z_OK; + do { + /* write out current buffer contents if full, or if flushing, but if + doing Z_FINISH then don't write until we get to Z_STREAM_END */ + if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && + (flush != Z_FINISH || ret == Z_STREAM_END))) { + while (strm->next_out > state->x.next) { + put = strm->next_out - state->x.next > (int)max ? max : + (unsigned)(strm->next_out - state->x.next); + writ = write(state->fd, state->x.next, put); + if (writ < 0) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + state->x.next += writ; + } + if (strm->avail_out == 0) { + strm->avail_out = state->size; + strm->next_out = state->out; + state->x.next = state->out; + } + } + + /* compress */ + have = strm->avail_out; + ret = deflate(strm, flush); + if (ret == Z_STREAM_ERROR) { + gz_error(state, Z_STREAM_ERROR, + "internal error: deflate stream corrupt"); + return -1; + } + have -= strm->avail_out; + } while (have); + + /* if that completed a deflate stream, allow another to start */ + if (flush == Z_FINISH) + deflateReset(strm); + + /* all done, no errors */ + return 0; +} + +/* Compress len zeros to output. Return -1 on a write error or memory + allocation failure by gz_comp(), or 0 on success. */ +local int gz_zero(state, len) + gz_statep state; + z_off64_t len; +{ + int first; + unsigned n; + z_streamp strm = &(state->strm); + + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return -1; + + /* compress len zeros (len guaranteed > 0) */ + first = 1; + while (len) { + n = GT_OFF(state->size) || (z_off64_t)state->size > len ? + (unsigned)len : state->size; + if (first) { + memset(state->in, 0, n); + first = 0; + } + strm->avail_in = n; + strm->next_in = state->in; + state->x.pos += n; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return -1; + len -= n; + } + return 0; +} + +/* Write len bytes from buf to file. Return the number of bytes written. If + the returned value is less than len, then there was an error. */ +local z_size_t gz_write(state, buf, len) + gz_statep state; + voidpc buf; + z_size_t len; +{ + z_size_t put = len; + + /* if len is zero, avoid unnecessary operations */ + if (len == 0) + return 0; + + /* allocate memory if this is the first time through */ + if (state->size == 0 && gz_init(state) == -1) + return 0; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return 0; + } + + /* for small len, copy to input buffer, otherwise compress directly */ + if (len < state->size) { + /* copy to input buffer, compress when full */ + do { + unsigned have, copy; + + if (state->strm.avail_in == 0) + state->strm.next_in = state->in; + have = (unsigned)((state->strm.next_in + state->strm.avail_in) - + state->in); + copy = state->size - have; + if (copy > len) + copy = len; + memcpy(state->in + have, buf, copy); + state->strm.avail_in += copy; + state->x.pos += copy; + buf = (const char *)buf + copy; + len -= copy; + if (len && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + } while (len); + } + else { + /* consume whatever's left in the input buffer */ + if (state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + + /* directly compress user buffer to file */ + state->strm.next_in = (z_const Bytef *)buf; + do { + unsigned n = (unsigned)-1; + if (n > len) + n = len; + state->strm.avail_in = n; + state->x.pos += n; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + len -= n; + } while (len); + } + + /* input was all buffered or compressed */ + return put; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzwrite(file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* since an int is returned, make sure len fits in one, otherwise return + with an error (this avoids a flaw in the interface) */ + if ((int)len < 0) { + gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); + return 0; + } + + /* write len bytes from buf (the return value will fit in an int) */ + return (int)gz_write(state, buf, len); +} + +/* -- see zlib.h -- */ +z_size_t ZEXPORT gzfwrite(buf, size, nitems, file) + voidpc buf; + z_size_t size; + z_size_t nitems; + gzFile file; +{ + z_size_t len; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* compute bytes to read -- error on overflow */ + len = nitems * size; + if (size && len / size != nitems) { + gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); + return 0; + } + + /* write len bytes to buf, return the number of full items written */ + return len ? gz_write(state, buf, len) / size : 0; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned have; + unsigned char buf[1]; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return -1; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return -1; + } + + /* try writing to input buffer for speed (state->size == 0 if buffer not + initialized) */ + if (state->size) { + if (strm->avail_in == 0) + strm->next_in = state->in; + have = (unsigned)((strm->next_in + strm->avail_in) - state->in); + if (have < state->size) { + state->in[have] = (unsigned char)c; + strm->avail_in++; + state->x.pos++; + return c & 0xff; + } + } + + /* no room in buffer or not initialized, use gz_write() */ + buf[0] = (unsigned char)c; + if (gz_write(state, buf, 1) != 1) + return -1; + return c & 0xff; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzputs(file, str) + gzFile file; + const char *str; +{ + int ret; + z_size_t len; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return -1; + + /* write string */ + len = strlen(str); + ret = gz_write(state, str, len); + return ret == 0 && len != 0 ? -1 : ret; +} + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +#include + +/* -- see zlib.h -- */ +int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) +{ + int len; + unsigned left; + char *next; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* make sure we have some buffer space */ + if (state->size == 0 && gz_init(state) == -1) + return state->err; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return state->err; + } + + /* do the printf() into the input buffer, put length in len -- the input + buffer is double-sized just for this function, so there is guaranteed to + be state->size bytes available after the current contents */ + if (strm->avail_in == 0) + strm->next_in = state->in; + next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in); + next[state->size - 1] = 0; +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(next, format, va); + for (len = 0; len < state->size; len++) + if (next[len] == 0) break; +# else + len = vsprintf(next, format, va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(next, state->size, format, va); + len = strlen(next); +# else + len = vsnprintf(next, state->size, format, va); +# endif +#endif + + /* check that printf() results fit in buffer */ + if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0) + return 0; + + /* update buffer and position, compress first half if past that */ + strm->avail_in += (unsigned)len; + state->x.pos += len; + if (strm->avail_in >= state->size) { + left = strm->avail_in - state->size; + strm->avail_in = state->size; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return state->err; + memcpy(state->in, state->in + state->size, left); + strm->next_in = state->in; + strm->avail_in = left; + } + return len; +} + +int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) +{ + va_list va; + int ret; + + va_start(va, format); + ret = gzvprintf(file, format, va); + va_end(va); + return ret; +} + +#else /* !STDC && !Z_HAVE_STDARG_H */ + +/* -- see zlib.h -- */ +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + unsigned len, left; + char *next; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that can really pass pointer in ints */ + if (sizeof(int) != sizeof(void *)) + return Z_STREAM_ERROR; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* make sure we have some buffer space */ + if (state->size == 0 && gz_init(state) == -1) + return state->error; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return state->error; + } + + /* do the printf() into the input buffer, put length in len -- the input + buffer is double-sized just for this function, so there is guaranteed to + be state->size bytes available after the current contents */ + if (strm->avail_in == 0) + strm->next_in = state->in; + next = (char *)(strm->next_in + strm->avail_in); + next[state->size - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, + a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < size; len++) + if (next[len] == 0) + break; +# else + len = sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, + a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(next); +# else + len = snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + + /* check that printf() results fit in buffer */ + if (len == 0 || len >= state->size || next[state->size - 1] != 0) + return 0; + + /* update buffer and position, compress first half if past that */ + strm->avail_in += len; + state->x.pos += len; + if (strm->avail_in >= state->size) { + left = strm->avail_in - state->size; + strm->avail_in = state->size; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return state->err; + memcpy(state->in, state->in + state->size, left); + strm->next_in = state->in; + strm->avail_in = left; + } + return (int)len; +} + +#endif + +/* -- see zlib.h -- */ +int ZEXPORT gzflush(file, flush) + gzFile file; + int flush; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* check flush parameter */ + if (flush < 0 || flush > Z_FINISH) + return Z_STREAM_ERROR; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return state->err; + } + + /* compress remaining data with requested flush */ + (void)gz_comp(state, flush); + return state->err; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzsetparams(file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* if no change is requested, then do nothing */ + if (level == state->level && strategy == state->strategy) + return Z_OK; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return state->err; + } + + /* change compression parameters for subsequent input */ + if (state->size) { + /* flush previous input with previous parameters before changing */ + if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1) + return state->err; + deflateParams(strm, level, strategy); + } + state->level = level; + state->strategy = strategy; + return Z_OK; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzclose_w(file) + gzFile file; +{ + int ret = Z_OK; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + /* check that we're writing */ + if (state->mode != GZ_WRITE) + return Z_STREAM_ERROR; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + ret = state->err; + } + + /* flush, free memory, and close file */ + if (gz_comp(state, Z_FINISH) == -1) + ret = state->err; + if (state->size) { + if (!state->direct) { + (void)deflateEnd(&(state->strm)); + free(state->out); + } + free(state->in); + } + gz_error(state, Z_OK, NULL); + free(state->path); + if (close(state->fd) == -1) + ret = Z_ERRNO; + free(state); + return ret; +} diff --git a/contrib/zlib/infback.c b/contrib/zlib/infback.c new file mode 100644 index 00000000..59679ecb --- /dev/null +++ b/contrib/zlib/infback.c @@ -0,0 +1,640 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_streamp strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; + state->wbits = (uInt)windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->wnext = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_streamp strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + z_const unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + state->length = (unsigned)here.val; + + /* process literal */ + if (here.op == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(here.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)here.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(here.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/contrib/zlib/inffast.c b/contrib/zlib/inffast.c new file mode 100644 index 00000000..0dbd1dbc --- /dev/null +++ b/contrib/zlib/inffast.c @@ -0,0 +1,323 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2017 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef ASMINF +# pragma message("Assembler code may have bugs -- use at your own risk") +#else + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void ZLIB_INTERNAL inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + z_const unsigned char FAR *in; /* local strm->next_in */ + z_const unsigned char FAR *last; /* have enough input while in < last */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code here; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in; + last = in + (strm->avail_in - 5); + out = strm->next_out; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + wnext = state->wnext; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + here = lcode[hold & lmask]; + dolen: + op = (unsigned)(here.bits); + hold >>= op; + bits -= op; + op = (unsigned)(here.op); + if (op == 0) { /* literal */ + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + *out++ = (unsigned char)(here.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(here.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + here = dcode[hold & dmask]; + dodist: + op = (unsigned)(here.bits); + hold >>= op; + bits -= op; + op = (unsigned)(here.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(here.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + if (state->sane) { + strm->msg = + (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + if (len <= op - whave) { + do { + *out++ = 0; + } while (--len); + continue; + } + len -= op - whave; + do { + *out++ = 0; + } while (--op > whave); + if (op == 0) { + from = out - dist; + do { + *out++ = *from++; + } while (--len); + continue; + } +#endif + } + from = window; + if (wnext == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (wnext < op) { /* wrap around window */ + from += wsize + wnext - op; + op -= wnext; + if (op < len) { /* some from end of window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = window; + if (wnext < len) { /* some from start of window */ + op = wnext; + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += wnext - op; + if (op < len) { /* some from window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + *out++ = *from++; + *out++ = *from++; + *out++ = *from++; + len -= 3; + } + if (len) { + *out++ = *from++; + if (len > 1) + *out++ = *from++; + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + *out++ = *from++; + *out++ = *from++; + *out++ = *from++; + len -= 3; + } while (len > 2); + if (len) { + *out++ = *from++; + if (len > 1) + *out++ = *from++; + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + here = dcode[here.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + here = lcode[here.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in; + strm->next_out = out; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and wnext == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/contrib/zlib/inffast.h b/contrib/zlib/inffast.h new file mode 100644 index 00000000..e5c1aa4c --- /dev/null +++ b/contrib/zlib/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/contrib/zlib/inffixed.h b/contrib/zlib/inffixed.h new file mode 100644 index 00000000..d6283277 --- /dev/null +++ b/contrib/zlib/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. + It is part of the implementation of this library and is + subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/contrib/zlib/inflate.c b/contrib/zlib/inflate.c new file mode 100644 index 00000000..ac333e8c --- /dev/null +++ b/contrib/zlib/inflate.c @@ -0,0 +1,1561 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common wnext == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local int inflateStateCheck OF((z_streamp strm)); +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, + unsigned copy)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, + unsigned len)); + +local int inflateStateCheck(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) + return 1; + state = (struct inflate_state FAR *)strm->state; + if (state == Z_NULL || state->strm != strm || + state->mode < HEAD || state->mode > SYNC) + return 1; + return 0; +} + +int ZEXPORT inflateResetKeep(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + if (state->wrap) /* to support ill-conceived Java test suite */ + strm->adler = state->wrap & 1; + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + state->sane = 1; + state->back = -1; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + state->wsize = 0; + state->whave = 0; + state->wnext = 0; + return inflateResetKeep(strm); +} + +int ZEXPORT inflateReset2(strm, windowBits) +z_streamp strm; +int windowBits; +{ + int wrap; + struct inflate_state FAR *state; + + /* get the state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* extract wrap request from windowBits parameter */ + if (windowBits < 0) { + wrap = 0; + windowBits = -windowBits; + } + else { + wrap = (windowBits >> 4) + 5; +#ifdef GUNZIP + if (windowBits < 48) + windowBits &= 15; +#endif + } + + /* set number of window bits, free window if different */ + if (windowBits && (windowBits < 8 || windowBits > 15)) + return Z_STREAM_ERROR; + if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { + ZFREE(strm, state->window); + state->window = Z_NULL; + } + + /* update state and reset the rest of it */ + state->wrap = wrap; + state->wbits = (unsigned)windowBits; + return inflateReset(strm); +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + int ret; + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->strm = strm; + state->window = Z_NULL; + state->mode = HEAD; /* to pass state test in inflateReset2() */ + ret = inflateReset2(strm, windowBits); + if (ret != Z_OK) { + ZFREE(strm, state); + strm->state = Z_NULL; + } + return ret; +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits < 0) { + state->hold = 0; + state->bits = 0; + return Z_OK; + } + if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += (unsigned)value << state->bits; + state->bits += (uInt)bits; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op, + state.lencode[low].bits, state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, end, copy) +z_streamp strm; +const Bytef *end; +unsigned copy; +{ + struct inflate_state FAR *state; + unsigned dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->wnext = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + if (copy >= state->wsize) { + zmemcpy(state->window, end - state->wsize, state->wsize); + state->wnext = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->wnext; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->wnext, end - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, end - copy, copy); + state->wnext = copy; + state->whave = state->wsize; + } + else { + state->wnext += dist; + if (state->wnext == state->wsize) state->wnext = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + z_const unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (inflateStateCheck(strm) || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + if (state->wbits == 0) + state->wbits = 15; + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (state->wbits == 0) + state->wbits = len; + if (len > 15 || len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL) { + len = state->head->extra_len - state->length; + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = (Bytef)len; + } while (len && copy < have); + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = (Bytef)len; + } while (len && copy < have); + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if ((state->wrap & 4) && hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = ZSWAP32(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN_; /* decode codes */ + if (flush == Z_TREES) { + DROPBITS(2); + goto inf_leave; + } + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY_; + if (flush == Z_TREES) goto inf_leave; + case COPY_: + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (const code FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (const code FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (const code FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN_; + if (flush == Z_TREES) goto inf_leave; + case LEN_: + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + if (state->mode == TYPE) + state->back = -1; + break; + } + state->back = 0; + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + state->length = (unsigned)here.val; + if ((int)(here.op) == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + state->mode = LIT; + break; + } + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->back = -1; + state->mode = TYPE; + break; + } + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(here.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->was = state->length; + state->mode = DIST; + case DIST: + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)here.val; + state->extra = (unsigned)(here.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->whave) { + if (state->sane) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + Trace((stderr, "inflate.c too far\n")); + copy -= state->whave; + if (copy > state->length) copy = state->length; + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = 0; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; +#endif + } + if (copy > state->wnext) { + copy -= state->wnext; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->wnext - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if ((state->wrap & 4) && out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if ((state->wrap & 4) && ( +#ifdef GUNZIP + state->flags ? hold : +#endif + ZSWAP32(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (out != strm->avail_out && state->mode < BAD && + (state->mode < CHECK || flush != Z_FINISH))) + if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if ((state->wrap & 4) && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = (int)state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0) + + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (inflateStateCheck(strm)) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength) +z_streamp strm; +Bytef *dictionary; +uInt *dictLength; +{ + struct inflate_state FAR *state; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* copy dictionary */ + if (state->whave && dictionary != Z_NULL) { + zmemcpy(dictionary, state->window + state->wnext, + state->whave - state->wnext); + zmemcpy(dictionary + state->whave - state->wnext, + state->window, state->wnext); + } + if (dictLength != Z_NULL) + *dictLength = state->whave; + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long dictid; + int ret; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary identifier */ + if (state->mode == DICT) { + dictid = adler32(0L, Z_NULL, 0); + dictid = adler32(dictid, dictionary, dictLength); + if (dictid != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window using updatewindow(), which will amend the + existing dictionary if appropriate */ + ret = updatewindow(strm, dictionary + dictLength, dictLength); + if (ret) { + state->mode = MEM; + return Z_MEM_ERROR; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + struct inflate_state FAR *state; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +const unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (inflateStateCheck(source) || dest == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); + zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); + copy->strm = dest; + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} + +int ZEXPORT inflateUndermine(strm, subvert) +z_streamp strm; +int subvert; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + state->sane = !subvert; + return Z_OK; +#else + (void)subvert; + state->sane = 1; + return Z_DATA_ERROR; +#endif +} + +int ZEXPORT inflateValidate(strm, check) +z_streamp strm; +int check; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (check) + state->wrap |= 4; + else + state->wrap &= ~4; + return Z_OK; +} + +long ZEXPORT inflateMark(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) + return -(1L << 16); + state = (struct inflate_state FAR *)strm->state; + return (long)(((unsigned long)((long)state->back)) << 16) + + (state->mode == COPY ? state->length : + (state->mode == MATCH ? state->was - state->length : 0)); +} + +unsigned long ZEXPORT inflateCodesUsed(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (inflateStateCheck(strm)) return (unsigned long)-1; + state = (struct inflate_state FAR *)strm->state; + return (unsigned long)(state->next - state->codes); +} diff --git a/contrib/zlib/inflate.h b/contrib/zlib/inflate.h new file mode 100644 index 00000000..a46cce6b --- /dev/null +++ b/contrib/zlib/inflate.h @@ -0,0 +1,125 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD = 16180, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY_, /* i/o: same as COPY below, but only first time in */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN_, /* i: same as LEN below, but only first time in */ + LEN, /* i: waiting for length/lit/eob code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to BAD or MEM on error -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) or (raw) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> + HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + (raw) -> TYPEDO + Read deflate blocks: + TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK + STORED -> COPY_ -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN_ + LEN_ -> LEN + Read deflate codes in fixed or dynamic block: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* State maintained between inflate() calls -- approximately 7K bytes, not + including the allocated sliding window, which is up to 32K bytes. */ +struct inflate_state { + z_streamp strm; /* pointer back to this zlib stream */ + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip, + bit 2 true to validate check value */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ + int sane; /* if false, allow invalid distance too far */ + int back; /* bits back of last unprocessed length/lit */ + unsigned was; /* initial length of match */ +}; diff --git a/contrib/zlib/inftrees.c b/contrib/zlib/inftrees.c new file mode 100644 index 00000000..2ea08fc1 --- /dev/null +++ b/contrib/zlib/inftrees.c @@ -0,0 +1,304 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2017 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.11 Copyright 1995-2017 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code here; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + unsigned match; /* use base and extra for symbol >= match */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 77, 202}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)1; + here.val = (unsigned short)0; + *(*table)++ = here; /* make a table to force an error */ + *(*table)++ = here; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min < max; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for LENS and DIST tables against + the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in + the initial root table size constants. See the comments in inftrees.h + for more information. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + match = 20; + break; + case LENS: + base = lbase; + extra = lext; + match = 257; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + match = 0; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if ((type == LENS && used > ENOUGH_LENS) || + (type == DISTS && used > ENOUGH_DISTS)) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + here.bits = (unsigned char)(len - drop); + if (work[sym] + 1U < match) { + here.op = (unsigned char)0; + here.val = work[sym]; + } + else if (work[sym] >= match) { + here.op = (unsigned char)(extra[work[sym] - match]); + here.val = base[work[sym] - match]; + } + else { + here.op = (unsigned char)(32 + 64); /* end of block */ + here.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = here; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if ((type == LENS && used > ENOUGH_LENS) || + (type == DISTS && used > ENOUGH_DISTS)) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* fill in remaining table entry if code is incomplete (guaranteed to have + at most one remaining entry, since if the code is incomplete, the + maximum code length that was allowed to get this far is one bit) */ + if (huff != 0) { + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)(len - drop); + here.val = (unsigned short)0; + next[huff] = here; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/contrib/zlib/inftrees.h b/contrib/zlib/inftrees.h new file mode 100644 index 00000000..baa53a0b --- /dev/null +++ b/contrib/zlib/inftrees.h @@ -0,0 +1,62 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of the dynamic table. The maximum number of code structures is + 1444, which is the sum of 852 for literal/length codes and 592 for distance + codes. These values were found by exhaustive searches using the program + examples/enough.c found in the zlib distribtution. The arguments to that + program are the number of symbols, the initial root table size, and the + maximum bit length of a code. "enough 286 9 15" for literal/length codes + returns returns 852, and "enough 30 6 15" for distance codes returns 592. + The initial root table size (9 or 6) is found in the fifth argument of the + inflate_table() calls in inflate.c and infback.c. If the root table size is + changed, then these maximum sizes would be need to be recalculated and + updated. */ +#define ENOUGH_LENS 852 +#define ENOUGH_DISTS 592 +#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) + +/* Type of code to build for inflate_table() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/contrib/zlib/make_vms.com b/contrib/zlib/make_vms.com new file mode 100644 index 00000000..65e9d0cb --- /dev/null +++ b/contrib/zlib/make_vms.com @@ -0,0 +1,867 @@ +$! make libz under VMS written by +$! Martin P.J. Zinser +$! +$! In case of problems with the install you might contact me at +$! zinser@zinser.no-ip.info(preferred) or +$! martin.zinser@eurexchange.com (work) +$! +$! Make procedure history for Zlib +$! +$!------------------------------------------------------------------------------ +$! Version history +$! 0.01 20060120 First version to receive a number +$! 0.02 20061008 Adapt to new Makefile.in +$! 0.03 20091224 Add support for large file check +$! 0.04 20100110 Add new gzclose, gzlib, gzread, gzwrite +$! 0.05 20100221 Exchange zlibdefs.h by zconf.h.in +$! 0.06 20120111 Fix missing amiss_err, update zconf_h.in, fix new exmples +$! subdir path, update module search in makefile.in +$! 0.07 20120115 Triggered by work done by Alexey Chupahin completly redesigned +$! shared image creation +$! 0.08 20120219 Make it work on VAX again, pre-load missing symbols to shared +$! image +$! 0.09 20120305 SMS. P1 sets builder ("MMK", "MMS", " " (built-in)). +$! "" -> automatic, preference: MMK, MMS, built-in. +$! +$ on error then goto err_exit +$! +$ true = 1 +$ false = 0 +$ tmpnam = "temp_" + f$getjpi("","pid") +$ tt = tmpnam + ".txt" +$ tc = tmpnam + ".c" +$ th = tmpnam + ".h" +$ define/nolog tconfig 'th' +$ its_decc = false +$ its_vaxc = false +$ its_gnuc = false +$ s_case = False +$! +$! Setup variables holding "config" information +$! +$ Make = "''p1'" +$ name = "Zlib" +$ version = "?.?.?" +$ v_string = "ZLIB_VERSION" +$ v_file = "zlib.h" +$ ccopt = "/include = []" +$ lopts = "" +$ dnsrl = "" +$ aconf_in_file = "zconf.h.in#zconf.h_in#zconf_h.in" +$ conf_check_string = "" +$ linkonly = false +$ optfile = name + ".opt" +$ mapfile = name + ".map" +$ libdefs = "" +$ vax = f$getsyi("HW_MODEL").lt.1024 +$ axp = f$getsyi("HW_MODEL").ge.1024 .and. f$getsyi("HW_MODEL").lt.4096 +$ ia64 = f$getsyi("HW_MODEL").ge.4096 +$! +$! 2012-03-05 SMS. +$! Why is this needed? And if it is needed, why not simply ".not. vax"? +$! +$!!! if axp .or. ia64 then set proc/parse=extended +$! +$ whoami = f$parse(f$environment("Procedure"),,,,"NO_CONCEAL") +$ mydef = F$parse(whoami,,,"DEVICE") +$ mydir = f$parse(whoami,,,"DIRECTORY") - "][" +$ myproc = f$parse(whoami,,,"Name") + f$parse(whoami,,,"type") +$! +$! Check for MMK/MMS +$! +$ if (Make .eqs. "") +$ then +$ If F$Search ("Sys$System:MMS.EXE") .nes. "" Then Make = "MMS" +$ If F$Type (MMK) .eqs. "STRING" Then Make = "MMK" +$ else +$ Make = f$edit( Make, "trim") +$ endif +$! +$ gosub find_version +$! +$ open/write topt tmp.opt +$ open/write optf 'optfile' +$! +$ gosub check_opts +$! +$! Look for the compiler used +$! +$ gosub check_compiler +$ close topt +$ close optf +$! +$ if its_decc +$ then +$ ccopt = "/prefix=all" + ccopt +$ if f$trnlnm("SYS") .eqs. "" +$ then +$ if axp +$ then +$ define sys sys$library: +$ else +$ ccopt = "/decc" + ccopt +$ define sys decc$library_include: +$ endif +$ endif +$! +$! 2012-03-05 SMS. +$! Why /NAMES = AS_IS? Why not simply ".not. vax"? And why not on VAX? +$! +$ if axp .or. ia64 +$ then +$ ccopt = ccopt + "/name=as_is/opt=(inline=speed)" +$ s_case = true +$ endif +$ endif +$ if its_vaxc .or. its_gnuc +$ then +$ if f$trnlnm("SYS").eqs."" then define sys sys$library: +$ endif +$! +$! Build a fake configure input header +$! +$ open/write conf_hin config.hin +$ write conf_hin "#undef _LARGEFILE64_SOURCE" +$ close conf_hin +$! +$! +$ i = 0 +$FIND_ACONF: +$ fname = f$element(i,"#",aconf_in_file) +$ if fname .eqs. "#" then goto AMISS_ERR +$ if f$search(fname) .eqs. "" +$ then +$ i = i + 1 +$ goto find_aconf +$ endif +$ open/read/err=aconf_err aconf_in 'fname' +$ open/write aconf zconf.h +$ACONF_LOOP: +$ read/end_of_file=aconf_exit aconf_in line +$ work = f$edit(line, "compress,trim") +$ if f$extract(0,6,work) .nes. "#undef" +$ then +$ if f$extract(0,12,work) .nes. "#cmakedefine" +$ then +$ write aconf line +$ endif +$ else +$ cdef = f$element(1," ",work) +$ gosub check_config +$ endif +$ goto aconf_loop +$ACONF_EXIT: +$ write aconf "" +$ write aconf "/* VMS specifics added by make_vms.com: */" +$ write aconf "#define VMS 1" +$ write aconf "#include " +$ write aconf "#include " +$ write aconf "#ifdef _LARGEFILE" +$ write aconf "# define off64_t __off64_t" +$ write aconf "# define fopen64 fopen" +$ write aconf "# define fseeko64 fseeko" +$ write aconf "# define lseek64 lseek" +$ write aconf "# define ftello64 ftell" +$ write aconf "#endif" +$ write aconf "#if !defined( __VAX) && (__CRTL_VER >= 70312000)" +$ write aconf "# define HAVE_VSNPRINTF" +$ write aconf "#endif" +$ close aconf_in +$ close aconf +$ if f$search("''th'") .nes. "" then delete 'th';* +$! Build the thing plain or with mms +$! +$ write sys$output "Compiling Zlib sources ..." +$ if make.eqs."" +$ then +$ if (f$search( "example.obj;*") .nes. "") then delete example.obj;* +$ if (f$search( "minigzip.obj;*") .nes. "") then delete minigzip.obj;* +$ CALL MAKE adler32.OBJ "CC ''CCOPT' adler32" - + adler32.c zlib.h zconf.h +$ CALL MAKE compress.OBJ "CC ''CCOPT' compress" - + compress.c zlib.h zconf.h +$ CALL MAKE crc32.OBJ "CC ''CCOPT' crc32" - + crc32.c zlib.h zconf.h +$ CALL MAKE deflate.OBJ "CC ''CCOPT' deflate" - + deflate.c deflate.h zutil.h zlib.h zconf.h +$ CALL MAKE gzclose.OBJ "CC ''CCOPT' gzclose" - + gzclose.c zutil.h zlib.h zconf.h +$ CALL MAKE gzlib.OBJ "CC ''CCOPT' gzlib" - + gzlib.c zutil.h zlib.h zconf.h +$ CALL MAKE gzread.OBJ "CC ''CCOPT' gzread" - + gzread.c zutil.h zlib.h zconf.h +$ CALL MAKE gzwrite.OBJ "CC ''CCOPT' gzwrite" - + gzwrite.c zutil.h zlib.h zconf.h +$ CALL MAKE infback.OBJ "CC ''CCOPT' infback" - + infback.c zutil.h inftrees.h inflate.h inffast.h inffixed.h +$ CALL MAKE inffast.OBJ "CC ''CCOPT' inffast" - + inffast.c zutil.h zlib.h zconf.h inffast.h +$ CALL MAKE inflate.OBJ "CC ''CCOPT' inflate" - + inflate.c zutil.h zlib.h zconf.h infblock.h +$ CALL MAKE inftrees.OBJ "CC ''CCOPT' inftrees" - + inftrees.c zutil.h zlib.h zconf.h inftrees.h +$ CALL MAKE trees.OBJ "CC ''CCOPT' trees" - + trees.c deflate.h zutil.h zlib.h zconf.h +$ CALL MAKE uncompr.OBJ "CC ''CCOPT' uncompr" - + uncompr.c zlib.h zconf.h +$ CALL MAKE zutil.OBJ "CC ''CCOPT' zutil" - + zutil.c zutil.h zlib.h zconf.h +$ write sys$output "Building Zlib ..." +$ CALL MAKE libz.OLB "lib/crea libz.olb *.obj" *.OBJ +$ write sys$output "Building example..." +$ CALL MAKE example.OBJ "CC ''CCOPT' [.test]example" - + [.test]example.c zlib.h zconf.h +$ call make example.exe "LINK example,libz.olb/lib" example.obj libz.olb +$ write sys$output "Building minigzip..." +$ CALL MAKE minigzip.OBJ "CC ''CCOPT' [.test]minigzip" - + [.test]minigzip.c zlib.h zconf.h +$ call make minigzip.exe - + "LINK minigzip,libz.olb/lib" - + minigzip.obj libz.olb +$ else +$ gosub crea_mms +$ write sys$output "Make ''name' ''version' with ''Make' " +$ 'make' +$ endif +$! +$! Create shareable image +$! +$ gosub crea_olist +$ write sys$output "Creating libzshr.exe" +$ call map_2_shopt 'mapfile' 'optfile' +$ LINK_'lopts'/SHARE=libzshr.exe modules.opt/opt,'optfile'/opt +$ write sys$output "Zlib build completed" +$ delete/nolog tmp.opt;* +$ exit +$AMISS_ERR: +$ write sys$output "No source for config.hin found." +$ write sys$output "Tried any of ''aconf_in_file'" +$ goto err_exit +$CC_ERR: +$ write sys$output "C compiler required to build ''name'" +$ goto err_exit +$ERR_EXIT: +$ set message/facil/ident/sever/text +$ close/nolog optf +$ close/nolog topt +$ close/nolog aconf_in +$ close/nolog aconf +$ close/nolog out +$ close/nolog min +$ close/nolog mod +$ close/nolog h_in +$ write sys$output "Exiting..." +$ exit 2 +$! +$! +$MAKE: SUBROUTINE !SUBROUTINE TO CHECK DEPENDENCIES +$ V = 'F$Verify(0) +$! P1 = What we are trying to make +$! P2 = Command to make it +$! P3 - P8 What it depends on +$ +$ If F$Search(P1) .Eqs. "" Then Goto Makeit +$ Time = F$CvTime(F$File(P1,"RDT")) +$arg=3 +$Loop: +$ Argument = P'arg +$ If Argument .Eqs. "" Then Goto Exit +$ El=0 +$Loop2: +$ File = F$Element(El," ",Argument) +$ If File .Eqs. " " Then Goto Endl +$ AFile = "" +$Loop3: +$ OFile = AFile +$ AFile = F$Search(File) +$ If AFile .Eqs. "" .Or. AFile .Eqs. OFile Then Goto NextEl +$ If F$CvTime(F$File(AFile,"RDT")) .Ges. Time Then Goto Makeit +$ Goto Loop3 +$NextEL: +$ El = El + 1 +$ Goto Loop2 +$EndL: +$ arg=arg+1 +$ If arg .Le. 8 Then Goto Loop +$ Goto Exit +$ +$Makeit: +$ VV=F$VERIFY(0) +$ write sys$output P2 +$ 'P2 +$ VV='F$Verify(VV) +$Exit: +$ If V Then Set Verify +$ENDSUBROUTINE +$!------------------------------------------------------------------------------ +$! +$! Check command line options and set symbols accordingly +$! +$!------------------------------------------------------------------------------ +$! Version history +$! 0.01 20041206 First version to receive a number +$! 0.02 20060126 Add new "HELP" target +$ CHECK_OPTS: +$ i = 1 +$ OPT_LOOP: +$ if i .lt. 9 +$ then +$ cparm = f$edit(p'i',"upcase") +$! +$! Check if parameter actually contains something +$! +$ if f$edit(cparm,"trim") .nes. "" +$ then +$ if cparm .eqs. "DEBUG" +$ then +$ ccopt = ccopt + "/noopt/deb" +$ lopts = lopts + "/deb" +$ endif +$ if f$locate("CCOPT=",cparm) .lt. f$length(cparm) +$ then +$ start = f$locate("=",cparm) + 1 +$ len = f$length(cparm) - start +$ ccopt = ccopt + f$extract(start,len,cparm) +$ if f$locate("AS_IS",f$edit(ccopt,"UPCASE")) .lt. f$length(ccopt) - + then s_case = true +$ endif +$ if cparm .eqs. "LINK" then linkonly = true +$ if f$locate("LOPTS=",cparm) .lt. f$length(cparm) +$ then +$ start = f$locate("=",cparm) + 1 +$ len = f$length(cparm) - start +$ lopts = lopts + f$extract(start,len,cparm) +$ endif +$ if f$locate("CC=",cparm) .lt. f$length(cparm) +$ then +$ start = f$locate("=",cparm) + 1 +$ len = f$length(cparm) - start +$ cc_com = f$extract(start,len,cparm) + if (cc_com .nes. "DECC") .and. - + (cc_com .nes. "VAXC") .and. - + (cc_com .nes. "GNUC") +$ then +$ write sys$output "Unsupported compiler choice ''cc_com' ignored" +$ write sys$output "Use DECC, VAXC, or GNUC instead" +$ else +$ if cc_com .eqs. "DECC" then its_decc = true +$ if cc_com .eqs. "VAXC" then its_vaxc = true +$ if cc_com .eqs. "GNUC" then its_gnuc = true +$ endif +$ endif +$ if f$locate("MAKE=",cparm) .lt. f$length(cparm) +$ then +$ start = f$locate("=",cparm) + 1 +$ len = f$length(cparm) - start +$ mmks = f$extract(start,len,cparm) +$ if (mmks .eqs. "MMK") .or. (mmks .eqs. "MMS") +$ then +$ make = mmks +$ else +$ write sys$output "Unsupported make choice ''mmks' ignored" +$ write sys$output "Use MMK or MMS instead" +$ endif +$ endif +$ if cparm .eqs. "HELP" then gosub bhelp +$ endif +$ i = i + 1 +$ goto opt_loop +$ endif +$ return +$!------------------------------------------------------------------------------ +$! +$! Look for the compiler used +$! +$! Version history +$! 0.01 20040223 First version to receive a number +$! 0.02 20040229 Save/set value of decc$no_rooted_search_lists +$! 0.03 20060202 Extend handling of GNU C +$! 0.04 20090402 Compaq -> hp +$CHECK_COMPILER: +$ if (.not. (its_decc .or. its_vaxc .or. its_gnuc)) +$ then +$ its_decc = (f$search("SYS$SYSTEM:DECC$COMPILER.EXE") .nes. "") +$ its_vaxc = .not. its_decc .and. (F$Search("SYS$System:VAXC.Exe") .nes. "") +$ its_gnuc = .not. (its_decc .or. its_vaxc) .and. (f$trnlnm("gnu_cc") .nes. "") +$ endif +$! +$! Exit if no compiler available +$! +$ if (.not. (its_decc .or. its_vaxc .or. its_gnuc)) +$ then goto CC_ERR +$ else +$ if its_decc +$ then +$ write sys$output "CC compiler check ... hp C" +$ if f$trnlnm("decc$no_rooted_search_lists") .nes. "" +$ then +$ dnrsl = f$trnlnm("decc$no_rooted_search_lists") +$ endif +$ define/nolog decc$no_rooted_search_lists 1 +$ else +$ if its_vaxc then write sys$output "CC compiler check ... VAX C" +$ if its_gnuc +$ then +$ write sys$output "CC compiler check ... GNU C" +$ if f$trnlnm(topt) then write topt "gnu_cc:[000000]gcclib.olb/lib" +$ if f$trnlnm(optf) then write optf "gnu_cc:[000000]gcclib.olb/lib" +$ cc = "gcc" +$ endif +$ if f$trnlnm(topt) then write topt "sys$share:vaxcrtl.exe/share" +$ if f$trnlnm(optf) then write optf "sys$share:vaxcrtl.exe/share" +$ endif +$ endif +$ return +$!------------------------------------------------------------------------------ +$! +$! If MMS/MMK are available dump out the descrip.mms if required +$! +$CREA_MMS: +$ write sys$output "Creating descrip.mms..." +$ create descrip.mms +$ open/append out descrip.mms +$ copy sys$input: out +$ deck +# descrip.mms: MMS description file for building zlib on VMS +# written by Martin P.J. Zinser +# + +OBJS = adler32.obj, compress.obj, crc32.obj, gzclose.obj, gzlib.obj\ + gzread.obj, gzwrite.obj, uncompr.obj, infback.obj\ + deflate.obj, trees.obj, zutil.obj, inflate.obj, \ + inftrees.obj, inffast.obj + +$ eod +$ write out "CFLAGS=", ccopt +$ write out "LOPTS=", lopts +$ write out "all : example.exe minigzip.exe libz.olb" +$ copy sys$input: out +$ deck + @ write sys$output " Example applications available" + +libz.olb : libz.olb($(OBJS)) + @ write sys$output " libz available" + +example.exe : example.obj libz.olb + link $(LOPTS) example,libz.olb/lib + +minigzip.exe : minigzip.obj libz.olb + link $(LOPTS) minigzip,libz.olb/lib + +clean : + delete *.obj;*,libz.olb;*,*.opt;*,*.exe;* + + +# Other dependencies. +adler32.obj : adler32.c zutil.h zlib.h zconf.h +compress.obj : compress.c zlib.h zconf.h +crc32.obj : crc32.c zutil.h zlib.h zconf.h +deflate.obj : deflate.c deflate.h zutil.h zlib.h zconf.h +example.obj : [.test]example.c zlib.h zconf.h +gzclose.obj : gzclose.c zutil.h zlib.h zconf.h +gzlib.obj : gzlib.c zutil.h zlib.h zconf.h +gzread.obj : gzread.c zutil.h zlib.h zconf.h +gzwrite.obj : gzwrite.c zutil.h zlib.h zconf.h +inffast.obj : inffast.c zutil.h zlib.h zconf.h inftrees.h inffast.h +inflate.obj : inflate.c zutil.h zlib.h zconf.h +inftrees.obj : inftrees.c zutil.h zlib.h zconf.h inftrees.h +minigzip.obj : [.test]minigzip.c zlib.h zconf.h +trees.obj : trees.c deflate.h zutil.h zlib.h zconf.h +uncompr.obj : uncompr.c zlib.h zconf.h +zutil.obj : zutil.c zutil.h zlib.h zconf.h +infback.obj : infback.c zutil.h inftrees.h inflate.h inffast.h inffixed.h +$ eod +$ close out +$ return +$!------------------------------------------------------------------------------ +$! +$! Read list of core library sources from makefile.in and create options +$! needed to build shareable image +$! +$CREA_OLIST: +$ open/read min makefile.in +$ open/write mod modules.opt +$ src_check_list = "OBJZ =#OBJG =" +$MRLOOP: +$ read/end=mrdone min rec +$ i = 0 +$SRC_CHECK_LOOP: +$ src_check = f$element(i, "#", src_check_list) +$ i = i+1 +$ if src_check .eqs. "#" then goto mrloop +$ if (f$extract(0,6,rec) .nes. src_check) then goto src_check_loop +$ rec = rec - src_check +$ gosub extra_filnam +$ if (f$element(1,"\",rec) .eqs. "\") then goto mrloop +$MRSLOOP: +$ read/end=mrdone min rec +$ gosub extra_filnam +$ if (f$element(1,"\",rec) .nes. "\") then goto mrsloop +$MRDONE: +$ close min +$ close mod +$ return +$!------------------------------------------------------------------------------ +$! +$! Take record extracted in crea_olist and split it into single filenames +$! +$EXTRA_FILNAM: +$ myrec = f$edit(rec - "\", "trim,compress") +$ i = 0 +$FELOOP: +$ srcfil = f$element(i," ", myrec) +$ if (srcfil .nes. " ") +$ then +$ write mod f$parse(srcfil,,,"NAME"), ".obj" +$ i = i + 1 +$ goto feloop +$ endif +$ return +$!------------------------------------------------------------------------------ +$! +$! Find current Zlib version number +$! +$FIND_VERSION: +$ open/read h_in 'v_file' +$hloop: +$ read/end=hdone h_in rec +$ rec = f$edit(rec,"TRIM") +$ if (f$extract(0,1,rec) .nes. "#") then goto hloop +$ rec = f$edit(rec - "#", "TRIM") +$ if f$element(0," ",rec) .nes. "define" then goto hloop +$ if f$element(1," ",rec) .eqs. v_string +$ then +$ version = 'f$element(2," ",rec)' +$ goto hdone +$ endif +$ goto hloop +$hdone: +$ close h_in +$ return +$!------------------------------------------------------------------------------ +$! +$CHECK_CONFIG: +$! +$ in_ldef = f$locate(cdef,libdefs) +$ if (in_ldef .lt. f$length(libdefs)) +$ then +$ write aconf "#define ''cdef' 1" +$ libdefs = f$extract(0,in_ldef,libdefs) + - + f$extract(in_ldef + f$length(cdef) + 1, - + f$length(libdefs) - in_ldef - f$length(cdef) - 1, - + libdefs) +$ else +$ if (f$type('cdef') .eqs. "INTEGER") +$ then +$ write aconf "#define ''cdef' ", 'cdef' +$ else +$ if (f$type('cdef') .eqs. "STRING") +$ then +$ write aconf "#define ''cdef' ", """", '''cdef'', """" +$ else +$ gosub check_cc_def +$ endif +$ endif +$ endif +$ return +$!------------------------------------------------------------------------------ +$! +$! Check if this is a define relating to the properties of the C/C++ +$! compiler +$! +$ CHECK_CC_DEF: +$ if (cdef .eqs. "_LARGEFILE64_SOURCE") +$ then +$ copy sys$input: 'tc' +$ deck +#include "tconfig" +#define _LARGEFILE +#include + +int main(){ +FILE *fp; + fp = fopen("temp.txt","r"); + fseeko(fp,1,SEEK_SET); + fclose(fp); +} + +$ eod +$ test_inv = false +$ comm_h = false +$ gosub cc_prop_check +$ return +$ endif +$ write aconf "/* ", line, " */" +$ return +$!------------------------------------------------------------------------------ +$! +$! Check for properties of C/C++ compiler +$! +$! Version history +$! 0.01 20031020 First version to receive a number +$! 0.02 20031022 Added logic for defines with value +$! 0.03 20040309 Make sure local config file gets not deleted +$! 0.04 20041230 Also write include for configure run +$! 0.05 20050103 Add processing of "comment defines" +$CC_PROP_CHECK: +$ cc_prop = true +$ is_need = false +$ is_need = (f$extract(0,4,cdef) .eqs. "NEED") .or. (test_inv .eq. true) +$ if f$search(th) .eqs. "" then create 'th' +$ set message/nofac/noident/nosever/notext +$ on error then continue +$ cc 'tmpnam' +$ if .not. ($status) then cc_prop = false +$ on error then continue +$! The headers might lie about the capabilities of the RTL +$ link 'tmpnam',tmp.opt/opt +$ if .not. ($status) then cc_prop = false +$ set message/fac/ident/sever/text +$ on error then goto err_exit +$ delete/nolog 'tmpnam'.*;*/exclude='th' +$ if (cc_prop .and. .not. is_need) .or. - + (.not. cc_prop .and. is_need) +$ then +$ write sys$output "Checking for ''cdef'... yes" +$ if f$type('cdef_val'_yes) .nes. "" +$ then +$ if f$type('cdef_val'_yes) .eqs. "INTEGER" - + then call write_config f$fao("#define !AS !UL",cdef,'cdef_val'_yes) +$ if f$type('cdef_val'_yes) .eqs. "STRING" - + then call write_config f$fao("#define !AS !AS",cdef,'cdef_val'_yes) +$ else +$ call write_config f$fao("#define !AS 1",cdef) +$ endif +$ if (cdef .eqs. "HAVE_FSEEKO") .or. (cdef .eqs. "_LARGE_FILES") .or. - + (cdef .eqs. "_LARGEFILE64_SOURCE") then - + call write_config f$string("#define _LARGEFILE 1") +$ else +$ write sys$output "Checking for ''cdef'... no" +$ if (comm_h) +$ then + call write_config f$fao("/* !AS */",line) +$ else +$ if f$type('cdef_val'_no) .nes. "" +$ then +$ if f$type('cdef_val'_no) .eqs. "INTEGER" - + then call write_config f$fao("#define !AS !UL",cdef,'cdef_val'_no) +$ if f$type('cdef_val'_no) .eqs. "STRING" - + then call write_config f$fao("#define !AS !AS",cdef,'cdef_val'_no) +$ else +$ call write_config f$fao("#undef !AS",cdef) +$ endif +$ endif +$ endif +$ return +$!------------------------------------------------------------------------------ +$! +$! Check for properties of C/C++ compiler with multiple result values +$! +$! Version history +$! 0.01 20040127 First version +$! 0.02 20050103 Reconcile changes from cc_prop up to version 0.05 +$CC_MPROP_CHECK: +$ cc_prop = true +$ i = 1 +$ idel = 1 +$ MT_LOOP: +$ if f$type(result_'i') .eqs. "STRING" +$ then +$ set message/nofac/noident/nosever/notext +$ on error then continue +$ cc 'tmpnam'_'i' +$ if .not. ($status) then cc_prop = false +$ on error then continue +$! The headers might lie about the capabilities of the RTL +$ link 'tmpnam'_'i',tmp.opt/opt +$ if .not. ($status) then cc_prop = false +$ set message/fac/ident/sever/text +$ on error then goto err_exit +$ delete/nolog 'tmpnam'_'i'.*;* +$ if (cc_prop) +$ then +$ write sys$output "Checking for ''cdef'... ", mdef_'i' +$ if f$type(mdef_'i') .eqs. "INTEGER" - + then call write_config f$fao("#define !AS !UL",cdef,mdef_'i') +$ if f$type('cdef_val'_yes) .eqs. "STRING" - + then call write_config f$fao("#define !AS !AS",cdef,mdef_'i') +$ goto msym_clean +$ else +$ i = i + 1 +$ goto mt_loop +$ endif +$ endif +$ write sys$output "Checking for ''cdef'... no" +$ call write_config f$fao("#undef !AS",cdef) +$ MSYM_CLEAN: +$ if (idel .le. msym_max) +$ then +$ delete/sym mdef_'idel' +$ idel = idel + 1 +$ goto msym_clean +$ endif +$ return +$!------------------------------------------------------------------------------ +$! +$! Write configuration to both permanent and temporary config file +$! +$! Version history +$! 0.01 20031029 First version to receive a number +$! +$WRITE_CONFIG: SUBROUTINE +$ write aconf 'p1' +$ open/append confh 'th' +$ write confh 'p1' +$ close confh +$ENDSUBROUTINE +$!------------------------------------------------------------------------------ +$! +$! Analyze the project map file and create the symbol vector for a shareable +$! image from it +$! +$! Version history +$! 0.01 20120128 First version +$! 0.02 20120226 Add pre-load logic +$! +$ MAP_2_SHOPT: Subroutine +$! +$ SAY := "WRITE_ SYS$OUTPUT" +$! +$ IF F$SEARCH("''P1'") .EQS. "" +$ THEN +$ SAY "MAP_2_SHOPT-E-NOSUCHFILE: Error, inputfile ''p1' not available" +$ goto exit_m2s +$ ENDIF +$ IF "''P2'" .EQS. "" +$ THEN +$ SAY "MAP_2_SHOPT: Error, no output file provided" +$ goto exit_m2s +$ ENDIF +$! +$ module1 = "deflate#deflateEnd#deflateInit_#deflateParams#deflateSetDictionary" +$ module2 = "gzclose#gzerror#gzgetc#gzgets#gzopen#gzprintf#gzputc#gzputs#gzread" +$ module3 = "gzseek#gztell#inflate#inflateEnd#inflateInit_#inflateSetDictionary" +$ module4 = "inflateSync#uncompress#zlibVersion#compress" +$ open/read map 'p1 +$ if axp .or. ia64 +$ then +$ open/write aopt a.opt +$ open/write bopt b.opt +$ write aopt " CASE_SENSITIVE=YES" +$ write bopt "SYMBOL_VECTOR= (-" +$ mod_sym_num = 1 +$ MOD_SYM_LOOP: +$ if f$type(module'mod_sym_num') .nes. "" +$ then +$ mod_in = 0 +$ MOD_SYM_IN: +$ shared_proc = f$element(mod_in, "#", module'mod_sym_num') +$ if shared_proc .nes. "#" +$ then +$ write aopt f$fao(" symbol_vector=(!AS/!AS=PROCEDURE)",- + f$edit(shared_proc,"upcase"),shared_proc) +$ write bopt f$fao("!AS=PROCEDURE,-",shared_proc) +$ mod_in = mod_in + 1 +$ goto mod_sym_in +$ endif +$ mod_sym_num = mod_sym_num + 1 +$ goto mod_sym_loop +$ endif +$MAP_LOOP: +$ read/end=map_end map line +$ if (f$locate("{",line).lt. f$length(line)) .or. - + (f$locate("global:", line) .lt. f$length(line)) +$ then +$ proc = true +$ goto map_loop +$ endif +$ if f$locate("}",line).lt. f$length(line) then proc = false +$ if f$locate("local:", line) .lt. f$length(line) then proc = false +$ if proc +$ then +$ shared_proc = f$edit(line,"collapse") +$ chop_semi = f$locate(";", shared_proc) +$ if chop_semi .lt. f$length(shared_proc) then - + shared_proc = f$extract(0, chop_semi, shared_proc) +$ write aopt f$fao(" symbol_vector=(!AS/!AS=PROCEDURE)",- + f$edit(shared_proc,"upcase"),shared_proc) +$ write bopt f$fao("!AS=PROCEDURE,-",shared_proc) +$ endif +$ goto map_loop +$MAP_END: +$ close/nolog aopt +$ close/nolog bopt +$ open/append libopt 'p2' +$ open/read aopt a.opt +$ open/read bopt b.opt +$ALOOP: +$ read/end=aloop_end aopt line +$ write libopt line +$ goto aloop +$ALOOP_END: +$ close/nolog aopt +$ sv = "" +$BLOOP: +$ read/end=bloop_end bopt svn +$ if (svn.nes."") +$ then +$ if (sv.nes."") then write libopt sv +$ sv = svn +$ endif +$ goto bloop +$BLOOP_END: +$ write libopt f$extract(0,f$length(sv)-2,sv), "-" +$ write libopt ")" +$ close/nolog bopt +$ delete/nolog/noconf a.opt;*,b.opt;* +$ else +$ if vax +$ then +$ open/append libopt 'p2' +$ mod_sym_num = 1 +$ VMOD_SYM_LOOP: +$ if f$type(module'mod_sym_num') .nes. "" +$ then +$ mod_in = 0 +$ VMOD_SYM_IN: +$ shared_proc = f$element(mod_in, "#", module'mod_sym_num') +$ if shared_proc .nes. "#" +$ then +$ write libopt f$fao("UNIVERSAL=!AS",- + f$edit(shared_proc,"upcase")) +$ mod_in = mod_in + 1 +$ goto vmod_sym_in +$ endif +$ mod_sym_num = mod_sym_num + 1 +$ goto vmod_sym_loop +$ endif +$VMAP_LOOP: +$ read/end=vmap_end map line +$ if (f$locate("{",line).lt. f$length(line)) .or. - + (f$locate("global:", line) .lt. f$length(line)) +$ then +$ proc = true +$ goto vmap_loop +$ endif +$ if f$locate("}",line).lt. f$length(line) then proc = false +$ if f$locate("local:", line) .lt. f$length(line) then proc = false +$ if proc +$ then +$ shared_proc = f$edit(line,"collapse") +$ chop_semi = f$locate(";", shared_proc) +$ if chop_semi .lt. f$length(shared_proc) then - + shared_proc = f$extract(0, chop_semi, shared_proc) +$ write libopt f$fao("UNIVERSAL=!AS",- + f$edit(shared_proc,"upcase")) +$ endif +$ goto vmap_loop +$VMAP_END: +$ else +$ write sys$output "Unknown Architecture (Not VAX, AXP, or IA64)" +$ write sys$output "No options file created" +$ endif +$ endif +$ EXIT_M2S: +$ close/nolog map +$ close/nolog libopt +$ endsubroutine diff --git a/contrib/zlib/msdos/Makefile.bor b/contrib/zlib/msdos/Makefile.bor new file mode 100644 index 00000000..3d12a2c2 --- /dev/null +++ b/contrib/zlib/msdos/Makefile.bor @@ -0,0 +1,115 @@ +# Makefile for zlib +# Borland C++ +# Last updated: 15-Mar-2003 + +# To use, do "make -fmakefile.bor" +# To compile in small model, set below: MODEL=s + +# WARNING: the small model is supported but only for small values of +# MAX_WBITS and MAX_MEM_LEVEL. For example: +# -DMAX_WBITS=11 -DDEF_WBITS=11 -DMAX_MEM_LEVEL=3 +# If you wish to reduce the memory requirements (default 256K for big +# objects plus a few K), you can add to the LOC macro below: +# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14 +# See zconf.h for details about the memory requirements. + +# ------------ Turbo C++, Borland C++ ------------ + +# Optional nonstandard preprocessor flags (e.g. -DMAX_MEM_LEVEL=7) +# should be added to the environment via "set LOCAL_ZLIB=-DFOO" or added +# to the declaration of LOC here: +LOC = $(LOCAL_ZLIB) + +# type for CPU required: 0: 8086, 1: 80186, 2: 80286, 3: 80386, etc. +CPU_TYP = 0 + +# memory model: one of s, m, c, l (small, medium, compact, large) +MODEL=l + +# replace bcc with tcc for Turbo C++ 1.0, with bcc32 for the 32 bit version +CC=bcc +LD=bcc +AR=tlib + +# compiler flags +# replace "-O2" by "-O -G -a -d" for Turbo C++ 1.0 +CFLAGS=-O2 -Z -m$(MODEL) $(LOC) + +LDFLAGS=-m$(MODEL) -f- + + +# variables +ZLIB_LIB = zlib_$(MODEL).lib + +OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzclose.obj gzlib.obj gzread.obj +OBJ2 = gzwrite.obj infback.obj inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj +OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzclose.obj+gzlib.obj+gzread.obj +OBJP2 = +gzwrite.obj+infback.obj+inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj + + +# targets +all: $(ZLIB_LIB) example.exe minigzip.exe + +.c.obj: + $(CC) -c $(CFLAGS) $*.c + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzclose.obj: gzclose.c zlib.h zconf.h gzguts.h + +gzlib.obj: gzlib.c zlib.h zconf.h gzguts.h + +gzread.obj: gzread.c zlib.h zconf.h gzguts.h + +gzwrite.obj: gzwrite.c zlib.h zconf.h gzguts.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: test/example.c zlib.h zconf.h + +minigzip.obj: test/minigzip.c zlib.h zconf.h + + +# the command line is cut to fit in the MS-DOS 128 byte limit: +$(ZLIB_LIB): $(OBJ1) $(OBJ2) + -del $(ZLIB_LIB) + $(AR) $(ZLIB_LIB) $(OBJP1) + $(AR) $(ZLIB_LIB) $(OBJP2) + +example.exe: example.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB) + +minigzip.exe: minigzip.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB) + +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +clean: + -del *.obj + -del *.lib + -del *.exe + -del zlib_*.bak + -del foo.gz diff --git a/contrib/zlib/msdos/Makefile.dj2 b/contrib/zlib/msdos/Makefile.dj2 new file mode 100644 index 00000000..59d2037d --- /dev/null +++ b/contrib/zlib/msdos/Makefile.dj2 @@ -0,0 +1,104 @@ +# Makefile for zlib. Modified for djgpp v2.0 by F. J. Donahoe, 3/15/96. +# Copyright (C) 1995-1998 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile, or to compile and test, type: +# +# make -fmakefile.dj2; make test -fmakefile.dj2 +# +# To install libz.a, zconf.h and zlib.h in the djgpp directories, type: +# +# make install -fmakefile.dj2 +# +# after first defining LIBRARY_PATH and INCLUDE_PATH in djgpp.env as +# in the sample below if the pattern of the DJGPP distribution is to +# be followed. Remember that, while 'es around <=> are ignored in +# makefiles, they are *not* in batch files or in djgpp.env. +# - - - - - +# [make] +# INCLUDE_PATH=%\>;INCLUDE_PATH%%\DJDIR%\include +# LIBRARY_PATH=%\>;LIBRARY_PATH%%\DJDIR%\lib +# BUTT=-m486 +# - - - - - +# Alternately, these variables may be defined below, overriding the values +# in djgpp.env, as +# INCLUDE_PATH=c:\usr\include +# LIBRARY_PATH=c:\usr\lib + +CC=gcc + +#CFLAGS=-MMD -O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-MMD -g -DZLIB_DEBUG +CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ + -Wstrict-prototypes -Wmissing-prototypes + +# If cp.exe is available, replace "copy /Y" with "cp -fp" . +CP=copy /Y +# If gnu install.exe is available, replace $(CP) with ginstall. +INSTALL=$(CP) +# The default value of RM is "rm -f." If "rm.exe" is found, comment out: +RM=del +LDLIBS=-L. -lz +LD=$(CC) -s -o +LDSHARED=$(CC) + +INCL=zlib.h zconf.h +LIBS=libz.a + +AR=ar rcs + +prefix=/usr/local +exec_prefix = $(prefix) + +OBJS = adler32.o compress.o crc32.o gzclose.o gzlib.o gzread.o gzwrite.o \ + uncompr.o deflate.o trees.o zutil.o inflate.o infback.o inftrees.o inffast.o + +OBJA = +# to use the asm code: make OBJA=match.o + +TEST_OBJS = example.o minigzip.o + +all: example.exe minigzip.exe + +check: test +test: all + ./example + echo hello world | .\minigzip | .\minigzip -d + +%.o : %.c + $(CC) $(CFLAGS) -c $< -o $@ + +libz.a: $(OBJS) $(OBJA) + $(AR) $@ $(OBJS) $(OBJA) + +%.exe : %.o $(LIBS) + $(LD) $@ $< $(LDLIBS) + +# INCLUDE_PATH and LIBRARY_PATH were set for [make] in djgpp.env . + +.PHONY : uninstall clean + +install: $(INCL) $(LIBS) + -@if not exist $(INCLUDE_PATH)\nul mkdir $(INCLUDE_PATH) + -@if not exist $(LIBRARY_PATH)\nul mkdir $(LIBRARY_PATH) + $(INSTALL) zlib.h $(INCLUDE_PATH) + $(INSTALL) zconf.h $(INCLUDE_PATH) + $(INSTALL) libz.a $(LIBRARY_PATH) + +uninstall: + $(RM) $(INCLUDE_PATH)\zlib.h + $(RM) $(INCLUDE_PATH)\zconf.h + $(RM) $(LIBRARY_PATH)\libz.a + +clean: + $(RM) *.d + $(RM) *.o + $(RM) *.exe + $(RM) libz.a + $(RM) foo.gz + +DEPS := $(wildcard *.d) +ifneq ($(DEPS),) +include $(DEPS) +endif diff --git a/contrib/zlib/msdos/Makefile.emx b/contrib/zlib/msdos/Makefile.emx new file mode 100644 index 00000000..e30f67be --- /dev/null +++ b/contrib/zlib/msdos/Makefile.emx @@ -0,0 +1,69 @@ +# Makefile for zlib. Modified for emx 0.9c by Chr. Spieler, 6/17/98. +# Copyright (C) 1995-1998 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile, or to compile and test, type: +# +# make -fmakefile.emx; make test -fmakefile.emx +# + +CC=gcc + +#CFLAGS=-MMD -O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-MMD -g -DZLIB_DEBUG +CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ + -Wstrict-prototypes -Wmissing-prototypes + +# If cp.exe is available, replace "copy /Y" with "cp -fp" . +CP=copy /Y +# If gnu install.exe is available, replace $(CP) with ginstall. +INSTALL=$(CP) +# The default value of RM is "rm -f." If "rm.exe" is found, comment out: +RM=del +LDLIBS=-L. -lzlib +LD=$(CC) -s -o +LDSHARED=$(CC) + +INCL=zlib.h zconf.h +LIBS=zlib.a + +AR=ar rcs + +prefix=/usr/local +exec_prefix = $(prefix) + +OBJS = adler32.o compress.o crc32.o gzclose.o gzlib.o gzread.o gzwrite.o \ + uncompr.o deflate.o trees.o zutil.o inflate.o infback.o inftrees.o inffast.o + +TEST_OBJS = example.o minigzip.o + +all: example.exe minigzip.exe + +test: all + ./example + echo hello world | .\minigzip | .\minigzip -d + +%.o : %.c + $(CC) $(CFLAGS) -c $< -o $@ + +zlib.a: $(OBJS) + $(AR) $@ $(OBJS) + +%.exe : %.o $(LIBS) + $(LD) $@ $< $(LDLIBS) + + +.PHONY : clean + +clean: + $(RM) *.d + $(RM) *.o + $(RM) *.exe + $(RM) zlib.a + $(RM) foo.gz + +DEPS := $(wildcard *.d) +ifneq ($(DEPS),) +include $(DEPS) +endif diff --git a/contrib/zlib/msdos/Makefile.msc b/contrib/zlib/msdos/Makefile.msc new file mode 100644 index 00000000..ae837861 --- /dev/null +++ b/contrib/zlib/msdos/Makefile.msc @@ -0,0 +1,112 @@ +# Makefile for zlib +# Microsoft C 5.1 or later +# Last updated: 19-Mar-2003 + +# To use, do "make makefile.msc" +# To compile in small model, set below: MODEL=S + +# If you wish to reduce the memory requirements (default 256K for big +# objects plus a few K), you can add to the LOC macro below: +# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14 +# See zconf.h for details about the memory requirements. + +# ------------- Microsoft C 5.1 and later ------------- + +# Optional nonstandard preprocessor flags (e.g. -DMAX_MEM_LEVEL=7) +# should be added to the environment via "set LOCAL_ZLIB=-DFOO" or added +# to the declaration of LOC here: +LOC = $(LOCAL_ZLIB) + +# Type for CPU required: 0: 8086, 1: 80186, 2: 80286, 3: 80386, etc. +CPU_TYP = 0 + +# Memory model: one of S, M, C, L (small, medium, compact, large) +MODEL=L + +CC=cl +CFLAGS=-nologo -A$(MODEL) -G$(CPU_TYP) -W3 -Oait -Gs $(LOC) +#-Ox generates bad code with MSC 5.1 +LIB_CFLAGS=-Zl $(CFLAGS) + +LD=link +LDFLAGS=/noi/e/st:0x1500/noe/farcall/packcode +# "/farcall/packcode" are only useful for `large code' memory models +# but should be a "no-op" for small code models. + + +# variables +ZLIB_LIB = zlib_$(MODEL).lib + +OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzclose.obj gzlib.obj gzread.obj +OBJ2 = gzwrite.obj infback.obj inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj + + +# targets +all: $(ZLIB_LIB) example.exe minigzip.exe + +.c.obj: + $(CC) -c $(LIB_CFLAGS) $*.c + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzclose.obj: gzclose.c zlib.h zconf.h gzguts.h + +gzlib.obj: gzlib.c zlib.h zconf.h gzguts.h + +gzread.obj: gzread.c zlib.h zconf.h gzguts.h + +gzwrite.obj: gzwrite.c zlib.h zconf.h gzguts.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: test/example.c zlib.h zconf.h + $(CC) -c $(CFLAGS) $*.c + +minigzip.obj: test/minigzip.c zlib.h zconf.h + $(CC) -c $(CFLAGS) $*.c + + +# the command line is cut to fit in the MS-DOS 128 byte limit: +$(ZLIB_LIB): $(OBJ1) $(OBJ2) + if exist $(ZLIB_LIB) del $(ZLIB_LIB) + lib $(ZLIB_LIB) $(OBJ1); + lib $(ZLIB_LIB) $(OBJ2); + +example.exe: example.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) example.obj,,,$(ZLIB_LIB); + +minigzip.exe: minigzip.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) minigzip.obj,,,$(ZLIB_LIB); + +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +clean: + -del *.obj + -del *.lib + -del *.exe + -del *.map + -del zlib_*.bak + -del foo.gz diff --git a/contrib/zlib/msdos/Makefile.tc b/contrib/zlib/msdos/Makefile.tc new file mode 100644 index 00000000..5aec82a9 --- /dev/null +++ b/contrib/zlib/msdos/Makefile.tc @@ -0,0 +1,100 @@ +# Makefile for zlib +# Turbo C 2.01, Turbo C++ 1.01 +# Last updated: 15-Mar-2003 + +# To use, do "make -fmakefile.tc" +# To compile in small model, set below: MODEL=s + +# WARNING: the small model is supported but only for small values of +# MAX_WBITS and MAX_MEM_LEVEL. For example: +# -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3 +# If you wish to reduce the memory requirements (default 256K for big +# objects plus a few K), you can add to CFLAGS below: +# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14 +# See zconf.h for details about the memory requirements. + +# ------------ Turbo C 2.01, Turbo C++ 1.01 ------------ +MODEL=l +CC=tcc +LD=tcc +AR=tlib +# CFLAGS=-O2 -G -Z -m$(MODEL) -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3 +CFLAGS=-O2 -G -Z -m$(MODEL) +LDFLAGS=-m$(MODEL) -f- + + +# variables +ZLIB_LIB = zlib_$(MODEL).lib + +OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzclose.obj gzlib.obj gzread.obj +OBJ2 = gzwrite.obj infback.obj inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj +OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzclose.obj+gzlib.obj+gzread.obj +OBJP2 = +gzwrite.obj+infback.obj+inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj + + +# targets +all: $(ZLIB_LIB) example.exe minigzip.exe + +.c.obj: + $(CC) -c $(CFLAGS) $*.c + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzclose.obj: gzclose.c zlib.h zconf.h gzguts.h + +gzlib.obj: gzlib.c zlib.h zconf.h gzguts.h + +gzread.obj: gzread.c zlib.h zconf.h gzguts.h + +gzwrite.obj: gzwrite.c zlib.h zconf.h gzguts.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: test/example.c zlib.h zconf.h + +minigzip.obj: test/minigzip.c zlib.h zconf.h + + +# the command line is cut to fit in the MS-DOS 128 byte limit: +$(ZLIB_LIB): $(OBJ1) $(OBJ2) + -del $(ZLIB_LIB) + $(AR) $(ZLIB_LIB) $(OBJP1) + $(AR) $(ZLIB_LIB) $(OBJP2) + +example.exe: example.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB) + +minigzip.exe: minigzip.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB) + +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +clean: + -del *.obj + -del *.lib + -del *.exe + -del zlib_*.bak + -del foo.gz diff --git a/contrib/zlib/nintendods/Makefile b/contrib/zlib/nintendods/Makefile new file mode 100644 index 00000000..21337d01 --- /dev/null +++ b/contrib/zlib/nintendods/Makefile @@ -0,0 +1,126 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +include $(DEVKITARM)/ds_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# DATA is a list of directories containing data files +# INCLUDES is a list of directories containing header files +#--------------------------------------------------------------------------------- +TARGET := $(shell basename $(CURDIR)) +BUILD := build +SOURCES := ../../ +DATA := data +INCLUDES := include + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -mthumb -mthumb-interwork + +CFLAGS := -Wall -O2\ + -march=armv5te -mtune=arm946e-s \ + -fomit-frame-pointer -ffast-math \ + $(ARCH) + +CFLAGS += $(INCLUDE) -DARM9 +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions + +ASFLAGS := $(ARCH) -march=armv5te -mtune=arm946e-s +LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(LIBNDS) + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/lib/libz.a + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +.PHONY: $(BUILD) clean all + +#--------------------------------------------------------------------------------- +all: $(BUILD) + @[ -d $@ ] || mkdir -p include + @cp ../../*.h include + +lib: + @[ -d $@ ] || mkdir -p $@ + +$(BUILD): lib + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) lib + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT) : $(OFILES) + +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/contrib/zlib/nintendods/README b/contrib/zlib/nintendods/README new file mode 100644 index 00000000..ba7a37db --- /dev/null +++ b/contrib/zlib/nintendods/README @@ -0,0 +1,5 @@ +This Makefile requires devkitARM (http://www.devkitpro.org/category/devkitarm/) and works inside "contrib/nds". It is based on a devkitARM template. + +Eduardo Costa +January 3, 2009 + diff --git a/contrib/zlib/old/Makefile.emx b/contrib/zlib/old/Makefile.emx new file mode 100644 index 00000000..612b0379 --- /dev/null +++ b/contrib/zlib/old/Makefile.emx @@ -0,0 +1,69 @@ +# Makefile for zlib. Modified for emx/rsxnt by Chr. Spieler, 6/16/98. +# Copyright (C) 1995-1998 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile, or to compile and test, type: +# +# make -fmakefile.emx; make test -fmakefile.emx +# + +CC=gcc -Zwin32 + +#CFLAGS=-MMD -O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-MMD -g -DZLIB_DEBUG +CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ + -Wstrict-prototypes -Wmissing-prototypes + +# If cp.exe is available, replace "copy /Y" with "cp -fp" . +CP=copy /Y +# If gnu install.exe is available, replace $(CP) with ginstall. +INSTALL=$(CP) +# The default value of RM is "rm -f." If "rm.exe" is found, comment out: +RM=del +LDLIBS=-L. -lzlib +LD=$(CC) -s -o +LDSHARED=$(CC) + +INCL=zlib.h zconf.h +LIBS=zlib.a + +AR=ar rcs + +prefix=/usr/local +exec_prefix = $(prefix) + +OBJS = adler32.o compress.o crc32.o deflate.o gzclose.o gzlib.o gzread.o \ + gzwrite.o infback.o inffast.o inflate.o inftrees.o trees.o uncompr.o zutil.o + +TEST_OBJS = example.o minigzip.o + +all: example.exe minigzip.exe + +test: all + ./example + echo hello world | .\minigzip | .\minigzip -d + +%.o : %.c + $(CC) $(CFLAGS) -c $< -o $@ + +zlib.a: $(OBJS) + $(AR) $@ $(OBJS) + +%.exe : %.o $(LIBS) + $(LD) $@ $< $(LDLIBS) + + +.PHONY : clean + +clean: + $(RM) *.d + $(RM) *.o + $(RM) *.exe + $(RM) zlib.a + $(RM) foo.gz + +DEPS := $(wildcard *.d) +ifneq ($(DEPS),) +include $(DEPS) +endif diff --git a/contrib/zlib/old/Makefile.riscos b/contrib/zlib/old/Makefile.riscos new file mode 100644 index 00000000..57e29d3f --- /dev/null +++ b/contrib/zlib/old/Makefile.riscos @@ -0,0 +1,151 @@ +# Project: zlib_1_03 +# Patched for zlib 1.1.2 rw@shadow.org.uk 19980430 +# test works out-of-the-box, installs `somewhere' on demand + +# Toolflags: +CCflags = -c -depend !Depend -IC: -g -throwback -DRISCOS -fah +C++flags = -c -depend !Depend -IC: -throwback +Linkflags = -aif -c++ -o $@ +ObjAsmflags = -throwback -NoCache -depend !Depend +CMHGflags = +LibFileflags = -c -l -o $@ +Squeezeflags = -o $@ + +# change the line below to where _you_ want the library installed. +libdest = lib:zlib + +# Final targets: +@.lib: @.o.adler32 @.o.compress @.o.crc32 @.o.deflate @.o.gzio \ + @.o.infblock @.o.infcodes @.o.inffast @.o.inflate @.o.inftrees @.o.infutil @.o.trees \ + @.o.uncompr @.o.zutil + LibFile $(LibFileflags) @.o.adler32 @.o.compress @.o.crc32 @.o.deflate \ + @.o.gzio @.o.infblock @.o.infcodes @.o.inffast @.o.inflate @.o.inftrees @.o.infutil \ + @.o.trees @.o.uncompr @.o.zutil +test: @.minigzip @.example @.lib + @copy @.lib @.libc A~C~DF~L~N~P~Q~RS~TV + @echo running tests: hang on. + @/@.minigzip -f -9 libc + @/@.minigzip -d libc-gz + @/@.minigzip -f -1 libc + @/@.minigzip -d libc-gz + @/@.minigzip -h -9 libc + @/@.minigzip -d libc-gz + @/@.minigzip -h -1 libc + @/@.minigzip -d libc-gz + @/@.minigzip -9 libc + @/@.minigzip -d libc-gz + @/@.minigzip -1 libc + @/@.minigzip -d libc-gz + @diff @.lib @.libc + @echo that should have reported '@.lib and @.libc identical' if you have diff. + @/@.example @.fred @.fred + @echo that will have given lots of hello!'s. + +@.minigzip: @.o.minigzip @.lib C:o.Stubs + Link $(Linkflags) @.o.minigzip @.lib C:o.Stubs +@.example: @.o.example @.lib C:o.Stubs + Link $(Linkflags) @.o.example @.lib C:o.Stubs + +install: @.lib + cdir $(libdest) + cdir $(libdest).h + @copy @.h.zlib $(libdest).h.zlib A~C~DF~L~N~P~Q~RS~TV + @copy @.h.zconf $(libdest).h.zconf A~C~DF~L~N~P~Q~RS~TV + @copy @.lib $(libdest).lib A~C~DF~L~N~P~Q~RS~TV + @echo okay, installed zlib in $(libdest) + +clean:; remove @.minigzip + remove @.example + remove @.libc + -wipe @.o.* F~r~cV + remove @.fred + +# User-editable dependencies: +.c.o: + cc $(ccflags) -o $@ $< + +# Static dependencies: + +# Dynamic dependencies: +o.example: c.example +o.example: h.zlib +o.example: h.zconf +o.minigzip: c.minigzip +o.minigzip: h.zlib +o.minigzip: h.zconf +o.adler32: c.adler32 +o.adler32: h.zlib +o.adler32: h.zconf +o.compress: c.compress +o.compress: h.zlib +o.compress: h.zconf +o.crc32: c.crc32 +o.crc32: h.zlib +o.crc32: h.zconf +o.deflate: c.deflate +o.deflate: h.deflate +o.deflate: h.zutil +o.deflate: h.zlib +o.deflate: h.zconf +o.gzio: c.gzio +o.gzio: h.zutil +o.gzio: h.zlib +o.gzio: h.zconf +o.infblock: c.infblock +o.infblock: h.zutil +o.infblock: h.zlib +o.infblock: h.zconf +o.infblock: h.infblock +o.infblock: h.inftrees +o.infblock: h.infcodes +o.infblock: h.infutil +o.infcodes: c.infcodes +o.infcodes: h.zutil +o.infcodes: h.zlib +o.infcodes: h.zconf +o.infcodes: h.inftrees +o.infcodes: h.infblock +o.infcodes: h.infcodes +o.infcodes: h.infutil +o.infcodes: h.inffast +o.inffast: c.inffast +o.inffast: h.zutil +o.inffast: h.zlib +o.inffast: h.zconf +o.inffast: h.inftrees +o.inffast: h.infblock +o.inffast: h.infcodes +o.inffast: h.infutil +o.inffast: h.inffast +o.inflate: c.inflate +o.inflate: h.zutil +o.inflate: h.zlib +o.inflate: h.zconf +o.inflate: h.infblock +o.inftrees: c.inftrees +o.inftrees: h.zutil +o.inftrees: h.zlib +o.inftrees: h.zconf +o.inftrees: h.inftrees +o.inftrees: h.inffixed +o.infutil: c.infutil +o.infutil: h.zutil +o.infutil: h.zlib +o.infutil: h.zconf +o.infutil: h.infblock +o.infutil: h.inftrees +o.infutil: h.infcodes +o.infutil: h.infutil +o.trees: c.trees +o.trees: h.deflate +o.trees: h.zutil +o.trees: h.zlib +o.trees: h.zconf +o.trees: h.trees +o.uncompr: c.uncompr +o.uncompr: h.zlib +o.uncompr: h.zconf +o.zutil: c.zutil +o.zutil: h.zutil +o.zutil: h.zlib +o.zutil: h.zconf diff --git a/contrib/zlib/old/README b/contrib/zlib/old/README new file mode 100644 index 00000000..800bf079 --- /dev/null +++ b/contrib/zlib/old/README @@ -0,0 +1,3 @@ +This directory contains files that have not been updated for zlib 1.2.x + +(Volunteers are encouraged to help clean this up. Thanks.) diff --git a/contrib/zlib/old/descrip.mms b/contrib/zlib/old/descrip.mms new file mode 100644 index 00000000..7066da5b --- /dev/null +++ b/contrib/zlib/old/descrip.mms @@ -0,0 +1,48 @@ +# descrip.mms: MMS description file for building zlib on VMS +# written by Martin P.J. Zinser + +cc_defs = +c_deb = + +.ifdef __DECC__ +pref = /prefix=all +.endif + +OBJS = adler32.obj, compress.obj, crc32.obj, gzio.obj, uncompr.obj,\ + deflate.obj, trees.obj, zutil.obj, inflate.obj, infblock.obj,\ + inftrees.obj, infcodes.obj, infutil.obj, inffast.obj + +CFLAGS= $(C_DEB) $(CC_DEFS) $(PREF) + +all : example.exe minigzip.exe + @ write sys$output " Example applications available" +libz.olb : libz.olb($(OBJS)) + @ write sys$output " libz available" + +example.exe : example.obj libz.olb + link example,libz.olb/lib + +minigzip.exe : minigzip.obj libz.olb + link minigzip,libz.olb/lib,x11vms:xvmsutils.olb/lib + +clean : + delete *.obj;*,libz.olb;* + + +# Other dependencies. +adler32.obj : zutil.h zlib.h zconf.h +compress.obj : zlib.h zconf.h +crc32.obj : zutil.h zlib.h zconf.h +deflate.obj : deflate.h zutil.h zlib.h zconf.h +example.obj : zlib.h zconf.h +gzio.obj : zutil.h zlib.h zconf.h +infblock.obj : zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h +infcodes.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h infcodes.h inffast.h +inffast.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h +inflate.obj : zutil.h zlib.h zconf.h infblock.h +inftrees.obj : zutil.h zlib.h zconf.h inftrees.h +infutil.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h +minigzip.obj : zlib.h zconf.h +trees.obj : deflate.h zutil.h zlib.h zconf.h +uncompr.obj : zlib.h zconf.h +zutil.obj : zutil.h zlib.h zconf.h diff --git a/contrib/zlib/old/os2/Makefile.os2 b/contrib/zlib/old/os2/Makefile.os2 new file mode 100644 index 00000000..bb426c0d --- /dev/null +++ b/contrib/zlib/old/os2/Makefile.os2 @@ -0,0 +1,136 @@ +# Makefile for zlib under OS/2 using GCC (PGCC) +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile and test, type: +# cp Makefile.os2 .. +# cd .. +# make -f Makefile.os2 test + +# This makefile will build a static library z.lib, a shared library +# z.dll and a import library zdll.lib. You can use either z.lib or +# zdll.lib by specifying either -lz or -lzdll on gcc's command line + +CC=gcc -Zomf -s + +CFLAGS=-O6 -Wall +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-g -DZLIB_DEBUG +#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ +# -Wstrict-prototypes -Wmissing-prototypes + +#################### BUG WARNING: ##################### +## infcodes.c hits a bug in pgcc-1.0, so you have to use either +## -O# where # <= 4 or one of (-fno-ommit-frame-pointer or -fno-force-mem) +## This bug is reportedly fixed in pgcc >1.0, but this was not tested +CFLAGS+=-fno-force-mem + +LDFLAGS=-s -L. -lzdll -Zcrtdll +LDSHARED=$(CC) -s -Zomf -Zdll -Zcrtdll + +VER=1.1.0 +ZLIB=z.lib +SHAREDLIB=z.dll +SHAREDLIBIMP=zdll.lib +LIBS=$(ZLIB) $(SHAREDLIB) $(SHAREDLIBIMP) + +AR=emxomfar cr +IMPLIB=emximp +RANLIB=echo +TAR=tar +SHELL=bash + +prefix=/usr/local +exec_prefix = $(prefix) + +OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \ + zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o + +TEST_OBJS = example.o minigzip.o + +DISTFILES = README INDEX ChangeLog configure Make*[a-z0-9] *.[ch] descrip.mms \ + algorithm.txt zlib.3 msdos/Make*[a-z0-9] msdos/zlib.def msdos/zlib.rc \ + nt/Makefile.nt nt/zlib.dnt contrib/README.contrib contrib/*.txt \ + contrib/asm386/*.asm contrib/asm386/*.c \ + contrib/asm386/*.bat contrib/asm386/zlibvc.d?? contrib/iostream/*.cpp \ + contrib/iostream/*.h contrib/iostream2/*.h contrib/iostream2/*.cpp \ + contrib/untgz/Makefile contrib/untgz/*.c contrib/untgz/*.w32 + +all: example.exe minigzip.exe + +test: all + @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \ + echo hello world | ./minigzip | ./minigzip -d || \ + echo ' *** minigzip test FAILED ***' ; \ + if ./example; then \ + echo ' *** zlib test OK ***'; \ + else \ + echo ' *** zlib test FAILED ***'; \ + fi + +$(ZLIB): $(OBJS) + $(AR) $@ $(OBJS) + -@ ($(RANLIB) $@ || true) >/dev/null 2>&1 + +$(SHAREDLIB): $(OBJS) os2/z.def + $(LDSHARED) -o $@ $^ + +$(SHAREDLIBIMP): os2/z.def + $(IMPLIB) -o $@ $^ + +example.exe: example.o $(LIBS) + $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS) + +minigzip.exe: minigzip.o $(LIBS) + $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS) + +clean: + rm -f *.o *~ example minigzip libz.a libz.so* foo.gz + +distclean: clean + +zip: + mv Makefile Makefile~; cp -p Makefile.in Makefile + rm -f test.c ztest*.c + v=`sed -n -e 's/\.//g' -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\ + zip -ul9 zlib$$v $(DISTFILES) + mv Makefile~ Makefile + +dist: + mv Makefile Makefile~; cp -p Makefile.in Makefile + rm -f test.c ztest*.c + d=zlib-`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\ + rm -f $$d.tar.gz; \ + if test ! -d ../$$d; then rm -f ../$$d; ln -s `pwd` ../$$d; fi; \ + files=""; \ + for f in $(DISTFILES); do files="$$files $$d/$$f"; done; \ + cd ..; \ + GZIP=-9 $(TAR) chofz $$d/$$d.tar.gz $$files; \ + if test ! -d $$d; then rm -f $$d; fi + mv Makefile~ Makefile + +tags: + etags *.[ch] + +depend: + makedepend -- $(CFLAGS) -- *.[ch] + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +adler32.o: zlib.h zconf.h +compress.o: zlib.h zconf.h +crc32.o: zlib.h zconf.h +deflate.o: deflate.h zutil.h zlib.h zconf.h +example.o: zlib.h zconf.h +gzio.o: zutil.h zlib.h zconf.h +infblock.o: infblock.h inftrees.h infcodes.h infutil.h zutil.h zlib.h zconf.h +infcodes.o: zutil.h zlib.h zconf.h +infcodes.o: inftrees.h infblock.h infcodes.h infutil.h inffast.h +inffast.o: zutil.h zlib.h zconf.h inftrees.h +inffast.o: infblock.h infcodes.h infutil.h inffast.h +inflate.o: zutil.h zlib.h zconf.h infblock.h +inftrees.o: zutil.h zlib.h zconf.h inftrees.h +infutil.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h +minigzip.o: zlib.h zconf.h +trees.o: deflate.h zutil.h zlib.h zconf.h trees.h +uncompr.o: zlib.h zconf.h +zutil.o: zutil.h zlib.h zconf.h diff --git a/contrib/zlib/old/os2/zlib.def b/contrib/zlib/old/os2/zlib.def new file mode 100644 index 00000000..4c753f1a --- /dev/null +++ b/contrib/zlib/old/os2/zlib.def @@ -0,0 +1,51 @@ +; +; Slightly modified version of ../nt/zlib.dnt :-) +; + +LIBRARY Z +DESCRIPTION "Zlib compression library for OS/2" +CODE PRELOAD MOVEABLE DISCARDABLE +DATA PRELOAD MOVEABLE MULTIPLE + +EXPORTS + adler32 + compress + crc32 + deflate + deflateCopy + deflateEnd + deflateInit2_ + deflateInit_ + deflateParams + deflateReset + deflateSetDictionary + gzclose + gzdopen + gzerror + gzflush + gzopen + gzread + gzwrite + inflate + inflateEnd + inflateInit2_ + inflateInit_ + inflateReset + inflateSetDictionary + inflateSync + uncompress + zlibVersion + gzprintf + gzputc + gzgetc + gzseek + gzrewind + gztell + gzeof + gzsetparams + zError + inflateSyncPoint + get_crc_table + compress2 + gzputs + gzgets diff --git a/contrib/zlib/old/visual-basic.txt b/contrib/zlib/old/visual-basic.txt new file mode 100644 index 00000000..57efe581 --- /dev/null +++ b/contrib/zlib/old/visual-basic.txt @@ -0,0 +1,160 @@ +See below some functions declarations for Visual Basic. + +Frequently Asked Question: + +Q: Each time I use the compress function I get the -5 error (not enough + room in the output buffer). + +A: Make sure that the length of the compressed buffer is passed by + reference ("as any"), not by value ("as long"). Also check that + before the call of compress this length is equal to the total size of + the compressed buffer and not zero. + + +From: "Jon Caruana" +Subject: Re: How to port zlib declares to vb? +Date: Mon, 28 Oct 1996 18:33:03 -0600 + +Got the answer! (I haven't had time to check this but it's what I got, and +looks correct): + +He has the following routines working: + compress + uncompress + gzopen + gzwrite + gzread + gzclose + +Declares follow: (Quoted from Carlos Rios , in Vb4 form) + +#If Win16 Then 'Use Win16 calls. +Declare Function compress Lib "ZLIB.DLL" (ByVal compr As + String, comprLen As Any, ByVal buf As String, ByVal buflen + As Long) As Integer +Declare Function uncompress Lib "ZLIB.DLL" (ByVal uncompr + As String, uncomprLen As Any, ByVal compr As String, ByVal + lcompr As Long) As Integer +Declare Function gzopen Lib "ZLIB.DLL" (ByVal filePath As + String, ByVal mode As String) As Long +Declare Function gzread Lib "ZLIB.DLL" (ByVal file As + Long, ByVal uncompr As String, ByVal uncomprLen As Integer) + As Integer +Declare Function gzwrite Lib "ZLIB.DLL" (ByVal file As + Long, ByVal uncompr As String, ByVal uncomprLen As Integer) + As Integer +Declare Function gzclose Lib "ZLIB.DLL" (ByVal file As + Long) As Integer +#Else +Declare Function compress Lib "ZLIB32.DLL" + (ByVal compr As String, comprLen As Any, ByVal buf As + String, ByVal buflen As Long) As Integer +Declare Function uncompress Lib "ZLIB32.DLL" + (ByVal uncompr As String, uncomprLen As Any, ByVal compr As + String, ByVal lcompr As Long) As Long +Declare Function gzopen Lib "ZLIB32.DLL" + (ByVal file As String, ByVal mode As String) As Long +Declare Function gzread Lib "ZLIB32.DLL" + (ByVal file As Long, ByVal uncompr As String, ByVal + uncomprLen As Long) As Long +Declare Function gzwrite Lib "ZLIB32.DLL" + (ByVal file As Long, ByVal uncompr As String, ByVal + uncomprLen As Long) As Long +Declare Function gzclose Lib "ZLIB32.DLL" + (ByVal file As Long) As Long +#End If + +-Jon Caruana +jon-net@usa.net +Microsoft Sitebuilder Network Level 1 Member - HTML Writer's Guild Member + + +Here is another example from Michael that he +says conforms to the VB guidelines, and that solves the problem of not +knowing the uncompressed size by storing it at the end of the file: + +'Calling the functions: +'bracket meaning: [optional] {Range of possible values} +'Call subCompressFile( [, , [level of compression {1..9}]]) +'Call subUncompressFile() + +Option Explicit +Private lngpvtPcnSml As Long 'Stores value for 'lngPercentSmaller' +Private Const SUCCESS As Long = 0 +Private Const strFilExt As String = ".cpr" +Private Declare Function lngfncCpr Lib "zlib.dll" Alias "compress2" (ByRef +dest As Any, ByRef destLen As Any, ByRef src As Any, ByVal srcLen As Long, +ByVal level As Integer) As Long +Private Declare Function lngfncUcp Lib "zlib.dll" Alias "uncompress" (ByRef +dest As Any, ByRef destLen As Any, ByRef src As Any, ByVal srcLen As Long) +As Long + +Public Sub subCompressFile(ByVal strargOriFilPth As String, Optional ByVal +strargCprFilPth As String, Optional ByVal intLvl As Integer = 9) + Dim strCprPth As String + Dim lngOriSiz As Long + Dim lngCprSiz As Long + Dim bytaryOri() As Byte + Dim bytaryCpr() As Byte + lngOriSiz = FileLen(strargOriFilPth) + ReDim bytaryOri(lngOriSiz - 1) + Open strargOriFilPth For Binary Access Read As #1 + Get #1, , bytaryOri() + Close #1 + strCprPth = IIf(strargCprFilPth = "", strargOriFilPth, strargCprFilPth) +'Select file path and name + strCprPth = strCprPth & IIf(Right(strCprPth, Len(strFilExt)) = +strFilExt, "", strFilExt) 'Add file extension if not exists + lngCprSiz = (lngOriSiz * 1.01) + 12 'Compression needs temporary a bit +more space then original file size + ReDim bytaryCpr(lngCprSiz - 1) + If lngfncCpr(bytaryCpr(0), lngCprSiz, bytaryOri(0), lngOriSiz, intLvl) = +SUCCESS Then + lngpvtPcnSml = (1# - (lngCprSiz / lngOriSiz)) * 100 + ReDim Preserve bytaryCpr(lngCprSiz - 1) + Open strCprPth For Binary Access Write As #1 + Put #1, , bytaryCpr() + Put #1, , lngOriSiz 'Add the the original size value to the end +(last 4 bytes) + Close #1 + Else + MsgBox "Compression error" + End If + Erase bytaryCpr + Erase bytaryOri +End Sub + +Public Sub subUncompressFile(ByVal strargFilPth As String) + Dim bytaryCpr() As Byte + Dim bytaryOri() As Byte + Dim lngOriSiz As Long + Dim lngCprSiz As Long + Dim strOriPth As String + lngCprSiz = FileLen(strargFilPth) + ReDim bytaryCpr(lngCprSiz - 1) + Open strargFilPth For Binary Access Read As #1 + Get #1, , bytaryCpr() + Close #1 + 'Read the original file size value: + lngOriSiz = bytaryCpr(lngCprSiz - 1) * (2 ^ 24) _ + + bytaryCpr(lngCprSiz - 2) * (2 ^ 16) _ + + bytaryCpr(lngCprSiz - 3) * (2 ^ 8) _ + + bytaryCpr(lngCprSiz - 4) + ReDim Preserve bytaryCpr(lngCprSiz - 5) 'Cut of the original size value + ReDim bytaryOri(lngOriSiz - 1) + If lngfncUcp(bytaryOri(0), lngOriSiz, bytaryCpr(0), lngCprSiz) = SUCCESS +Then + strOriPth = Left(strargFilPth, Len(strargFilPth) - Len(strFilExt)) + Open strOriPth For Binary Access Write As #1 + Put #1, , bytaryOri() + Close #1 + Else + MsgBox "Uncompression error" + End If + Erase bytaryCpr + Erase bytaryOri +End Sub +Public Property Get lngPercentSmaller() As Long + lngPercentSmaller = lngpvtPcnSml +End Property diff --git a/contrib/zlib/os400/README400 b/contrib/zlib/os400/README400 new file mode 100644 index 00000000..4f98334f --- /dev/null +++ b/contrib/zlib/os400/README400 @@ -0,0 +1,48 @@ + ZLIB version 1.2.11 for OS/400 installation instructions + +1) Download and unpack the zlib tarball to some IFS directory. + (i.e.: /path/to/the/zlib/ifs/source/directory) + + If the installed IFS command suppors gzip format, this is straightforward, +else you have to unpack first to some directory on a system supporting it, +then move the whole directory to the IFS via the network (via SMB or FTP). + +2) Edit the configuration parameters in the compilation script. + + EDTF STMF('/path/to/the/zlib/ifs/source/directory/os400/make.sh') + +Tune the parameters according to your needs if not matching the defaults. +Save the file and exit after edition. + +3) Enter qshell, then work in the zlib OS/400 specific directory. + + QSH + cd /path/to/the/zlib/ifs/source/directory/os400 + +4) Compile and install + + sh make.sh + +The script will: +- create the libraries, objects and IFS directories for the zlib environment, +- compile all modules, +- create a service program, +- create a static and a dynamic binding directory, +- install header files for C/C++ and for ILE/RPG, both for compilation in + DB2 and IFS environments. + +That's all. + + +Notes: For OS/400 ILE RPG programmers, a /copy member defining the ZLIB + API prototypes for ILE RPG can be found in ZLIB/H(ZLIB.INC). + In the ILE environment, the same definitions are available from + file zlib.inc located in the same IFS include directory as the + C/C++ header files. + Please read comments in this member for more information. + + Remember that most foreign textual data are ASCII coded: this + implementation does not handle conversion from/to ASCII, so + text data code conversions must be done explicitely. + + Mainly for the reason above, always open zipped files in binary mode. diff --git a/contrib/zlib/os400/bndsrc b/contrib/zlib/os400/bndsrc new file mode 100644 index 00000000..5e6e0a2f --- /dev/null +++ b/contrib/zlib/os400/bndsrc @@ -0,0 +1,119 @@ +STRPGMEXP PGMLVL(*CURRENT) SIGNATURE('ZLIB') + +/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ +/* Version 1.1.3 entry points. */ +/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ + + EXPORT SYMBOL("adler32") + EXPORT SYMBOL("compress") + EXPORT SYMBOL("compress2") + EXPORT SYMBOL("crc32") + EXPORT SYMBOL("get_crc_table") + EXPORT SYMBOL("deflate") + EXPORT SYMBOL("deflateEnd") + EXPORT SYMBOL("deflateSetDictionary") + EXPORT SYMBOL("deflateCopy") + EXPORT SYMBOL("deflateReset") + EXPORT SYMBOL("deflateParams") + EXPORT SYMBOL("deflatePrime") + EXPORT SYMBOL("deflateInit_") + EXPORT SYMBOL("deflateInit2_") + EXPORT SYMBOL("gzopen") + EXPORT SYMBOL("gzdopen") + EXPORT SYMBOL("gzsetparams") + EXPORT SYMBOL("gzread") + EXPORT SYMBOL("gzwrite") + EXPORT SYMBOL("gzprintf") + EXPORT SYMBOL("gzputs") + EXPORT SYMBOL("gzgets") + EXPORT SYMBOL("gzputc") + EXPORT SYMBOL("gzgetc") + EXPORT SYMBOL("gzflush") + EXPORT SYMBOL("gzseek") + EXPORT SYMBOL("gzrewind") + EXPORT SYMBOL("gztell") + EXPORT SYMBOL("gzeof") + EXPORT SYMBOL("gzclose") + EXPORT SYMBOL("gzerror") + EXPORT SYMBOL("inflate") + EXPORT SYMBOL("inflateEnd") + EXPORT SYMBOL("inflateSetDictionary") + EXPORT SYMBOL("inflateSync") + EXPORT SYMBOL("inflateReset") + EXPORT SYMBOL("inflateInit_") + EXPORT SYMBOL("inflateInit2_") + EXPORT SYMBOL("inflateSyncPoint") + EXPORT SYMBOL("uncompress") + EXPORT SYMBOL("zlibVersion") + EXPORT SYMBOL("zError") + EXPORT SYMBOL("z_errmsg") + +/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ +/* Version 1.2.1 additional entry points. */ +/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ + + EXPORT SYMBOL("compressBound") + EXPORT SYMBOL("deflateBound") + EXPORT SYMBOL("deflatePending") + EXPORT SYMBOL("gzungetc") + EXPORT SYMBOL("gzclearerr") + EXPORT SYMBOL("inflateBack") + EXPORT SYMBOL("inflateBackEnd") + EXPORT SYMBOL("inflateBackInit_") + EXPORT SYMBOL("inflateCopy") + EXPORT SYMBOL("zlibCompileFlags") + +/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ +/* Version 1.2.4 additional entry points. */ +/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ + + EXPORT SYMBOL("adler32_combine") + EXPORT SYMBOL("adler32_combine64") + EXPORT SYMBOL("crc32_combine") + EXPORT SYMBOL("crc32_combine64") + EXPORT SYMBOL("deflateSetHeader") + EXPORT SYMBOL("deflateTune") + EXPORT SYMBOL("gzbuffer") + EXPORT SYMBOL("gzclose_r") + EXPORT SYMBOL("gzclose_w") + EXPORT SYMBOL("gzdirect") + EXPORT SYMBOL("gzoffset") + EXPORT SYMBOL("gzoffset64") + EXPORT SYMBOL("gzopen64") + EXPORT SYMBOL("gzseek64") + EXPORT SYMBOL("gztell64") + EXPORT SYMBOL("inflateGetHeader") + EXPORT SYMBOL("inflateMark") + EXPORT SYMBOL("inflatePrime") + EXPORT SYMBOL("inflateReset2") + EXPORT SYMBOL("inflateUndermine") + +/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ +/* Version 1.2.6 additional entry points. */ +/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ + + EXPORT SYMBOL("deflateResetKeep") + EXPORT SYMBOL("gzgetc_") + EXPORT SYMBOL("inflateResetKeep") + +/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ +/* Version 1.2.8 additional entry points. */ +/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ + + EXPORT SYMBOL("gzvprintf") + EXPORT SYMBOL("inflateGetDictionary") + +/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ +/* Version 1.2.9 additional entry points. */ +/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ + + EXPORT SYMBOL("adler32_z") + EXPORT SYMBOL("crc32_z") + EXPORT SYMBOL("deflateGetDictionary") + EXPORT SYMBOL("gzfread") + EXPORT SYMBOL("gzfwrite") + EXPORT SYMBOL("inflateCodesUsed") + EXPORT SYMBOL("inflateValidate") + EXPORT SYMBOL("uncompress2") + +ENDPGMEXP diff --git a/contrib/zlib/os400/make.sh b/contrib/zlib/os400/make.sh new file mode 100644 index 00000000..19eec117 --- /dev/null +++ b/contrib/zlib/os400/make.sh @@ -0,0 +1,366 @@ +#!/bin/sh +# +# ZLIB compilation script for the OS/400. +# +# +# This is a shell script since make is not a standard component of OS/400. + + +################################################################################ +# +# Tunable configuration parameters. +# +################################################################################ + +TARGETLIB='ZLIB' # Target OS/400 program library +STATBNDDIR='ZLIB_A' # Static binding directory. +DYNBNDDIR='ZLIB' # Dynamic binding directory. +SRVPGM="ZLIB" # Service program. +IFSDIR='/zlib' # IFS support base directory. +TGTCCSID='500' # Target CCSID of objects +DEBUG='*NONE' # Debug level +OPTIMIZE='40' # Optimisation level +OUTPUT='*NONE' # Compilation output option. +TGTRLS='V6R1M0' # Target OS release + +export TARGETLIB STATBNDDIR DYNBNDDIR SRVPGM IFSDIR +export TGTCCSID DEBUG OPTIMIZE OUTPUT TGTRLS + + +################################################################################ +# +# OS/400 specific definitions. +# +################################################################################ + +LIBIFSNAME="/QSYS.LIB/${TARGETLIB}.LIB" + + +################################################################################ +# +# Procedures. +# +################################################################################ + +# action_needed dest [src] +# +# dest is an object to build +# if specified, src is an object on which dest depends. +# +# exit 0 (succeeds) if some action has to be taken, else 1. + +action_needed() + +{ + [ ! -e "${1}" ] && return 0 + [ "${2}" ] || return 1 + [ "${1}" -ot "${2}" ] && return 0 + return 1 +} + + +# make_module module_name source_name [additional_definitions] +# +# Compile source name into module if needed. +# As side effect, append the module name to variable MODULES. +# Set LINK to "YES" if the module has been compiled. + +make_module() + +{ + MODULES="${MODULES} ${1}" + MODIFSNAME="${LIBIFSNAME}/${1}.MODULE" + CSRC="`basename \"${2}\"`" + + if action_needed "${MODIFSNAME}" "${2}" + then : + elif [ ! "`sed -e \"//,/<\\\\/source>/!d\" \ + -e '/ tmphdrfile + + # Need to translate to target CCSID. + + CMD="CPY OBJ('`pwd`/tmphdrfile') TOOBJ('${DEST}')" + CMD="${CMD} TOCCSID(${TGTCCSID}) DTAFMT(*TEXT) REPLACE(*YES)" + system "${CMD}" + # touch -r "${HFILE}" "${DEST}" + rm -f tmphdrfile + fi + + IFSFILE="${IFSDIR}/include/`basename \"${HFILE}\"`" + + if action_needed "${IFSFILE}" "${DEST}" + then rm -f "${IFSFILE}" + ln -s "${DEST}" "${IFSFILE}" + fi +done + + +# Install the ILE/RPG header file. + + +HFILE="${SCRIPTDIR}/zlib.inc" +DEST="${SRCPF}/ZLIB.INC.MBR" + +if action_needed "${DEST}" "${HFILE}" +then CMD="CPY OBJ('${HFILE}') TOOBJ('${DEST}')" + CMD="${CMD} TOCCSID(${TGTCCSID}) DTAFMT(*TEXT) REPLACE(*YES)" + system "${CMD}" + # touch -r "${HFILE}" "${DEST}" +fi + +IFSFILE="${IFSDIR}/include/`basename \"${HFILE}\"`" + +if action_needed "${IFSFILE}" "${DEST}" +then rm -f "${IFSFILE}" + ln -s "${DEST}" "${IFSFILE}" +fi + + +# Create and compile the identification source file. + +echo '#pragma comment(user, "ZLIB version '"${VERSION}"'")' > os400.c +echo '#pragma comment(user, __DATE__)' >> os400.c +echo '#pragma comment(user, __TIME__)' >> os400.c +echo '#pragma comment(copyright, "Copyright (C) 1995-2017 Jean-Loup Gailly, Mark Adler. OS/400 version by P. Monnerat.")' >> os400.c +make_module OS400 os400.c +LINK= # No need to rebuild service program yet. +MODULES= + + +# Get source list. + +CSOURCES=`sed -e '/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Library + + Medium + + 2.0 + + + + zlib + zlib + alain.bonnefoy@icbt.com + Public + public + www.gzip.org/zlib + + + Jean-Loup Gailly,Mark Adler + www.gzip.org/zlib + + zlib@gzip.org + + + A massively spiffy yet delicately unobtrusive compression library. + zlib is designed to be a free, general-purpose, legally unencumbered, lossless data compression library for use on virtually any computer hardware and operating system. + http://www.gzip.org/zlib + + + + + 1.2.11 + Medium + Stable + + + + + + + No License + + + + Software Development/Libraries and Extensions/C Libraries + zlib,compression + qnx6 + qnx6 + None + Developer + + + + + + + + + + + + + + Install + Post + No + Ignore + + No + Optional + + + + + + + + + + + + + InstallOver + zlib + + + + + + + + + + + + + InstallOver + zlib-dev + + + + + + + + + diff --git a/contrib/zlib/test/example.c b/contrib/zlib/test/example.c new file mode 100644 index 00000000..3090dbad --- /dev/null +++ b/contrib/zlib/test/example.c @@ -0,0 +1,602 @@ +/* example.c -- usage example of the zlib compression library + * Copyright (C) 1995-2006, 2011, 2016 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "../zlib.h" +#include + +#ifdef STDC +# include +# include +#endif + +#if defined(VMS) || defined(RISCOS) +# define TESTFILE "foo-gz" +#else +# define TESTFILE "foo.gz" +#endif + +#define CHECK_ERR(err, msg) { \ + if (err != Z_OK) { \ + fprintf(stderr, "%s error: %d\n", msg, err); \ + exit(1); \ + } \ +} + +static z_const char hello[] = "hello, hello!"; +/* "hello world" would be more standard, but the repeated "hello" + * stresses the compression code better, sorry... + */ + +static const char dictionary[] = "hello"; +static uLong dictId; /* Adler32 value of the dictionary */ + +void test_deflate OF((Byte *compr, uLong comprLen)); +void test_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_deflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_flush OF((Byte *compr, uLong *comprLen)); +void test_sync OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_dict_deflate OF((Byte *compr, uLong comprLen)); +void test_dict_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +int main OF((int argc, char *argv[])); + + +#ifdef Z_SOLO + +void *myalloc OF((void *, unsigned, unsigned)); +void myfree OF((void *, void *)); + +void *myalloc(q, n, m) + void *q; + unsigned n, m; +{ + (void)q; + return calloc(n, m); +} + +void myfree(void *q, void *p) +{ + (void)q; + free(p); +} + +static alloc_func zalloc = myalloc; +static free_func zfree = myfree; + +#else /* !Z_SOLO */ + +static alloc_func zalloc = (alloc_func)0; +static free_func zfree = (free_func)0; + +void test_compress OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_gzio OF((const char *fname, + Byte *uncompr, uLong uncomprLen)); + +/* =========================================================================== + * Test compress() and uncompress() + */ +void test_compress(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + uLong len = (uLong)strlen(hello)+1; + + err = compress(compr, &comprLen, (const Bytef*)hello, len); + CHECK_ERR(err, "compress"); + + strcpy((char*)uncompr, "garbage"); + + err = uncompress(uncompr, &uncomprLen, compr, comprLen); + CHECK_ERR(err, "uncompress"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad uncompress\n"); + exit(1); + } else { + printf("uncompress(): %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Test read/write of .gz files + */ +void test_gzio(fname, uncompr, uncomprLen) + const char *fname; /* compressed file name */ + Byte *uncompr; + uLong uncomprLen; +{ +#ifdef NO_GZCOMPRESS + fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n"); +#else + int err; + int len = (int)strlen(hello)+1; + gzFile file; + z_off_t pos; + + file = gzopen(fname, "wb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + exit(1); + } + gzputc(file, 'h'); + if (gzputs(file, "ello") != 4) { + fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err)); + exit(1); + } + if (gzprintf(file, ", %s!", "hello") != 8) { + fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err)); + exit(1); + } + gzseek(file, 1L, SEEK_CUR); /* add one zero byte */ + gzclose(file); + + file = gzopen(fname, "rb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + exit(1); + } + strcpy((char*)uncompr, "garbage"); + + if (gzread(file, uncompr, (unsigned)uncomprLen) != len) { + fprintf(stderr, "gzread err: %s\n", gzerror(file, &err)); + exit(1); + } + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad gzread: %s\n", (char*)uncompr); + exit(1); + } else { + printf("gzread(): %s\n", (char*)uncompr); + } + + pos = gzseek(file, -8L, SEEK_CUR); + if (pos != 6 || gztell(file) != pos) { + fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n", + (long)pos, (long)gztell(file)); + exit(1); + } + + if (gzgetc(file) != ' ') { + fprintf(stderr, "gzgetc error\n"); + exit(1); + } + + if (gzungetc(' ', file) != ' ') { + fprintf(stderr, "gzungetc error\n"); + exit(1); + } + + gzgets(file, (char*)uncompr, (int)uncomprLen); + if (strlen((char*)uncompr) != 7) { /* " hello!" */ + fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err)); + exit(1); + } + if (strcmp((char*)uncompr, hello + 6)) { + fprintf(stderr, "bad gzgets after gzseek\n"); + exit(1); + } else { + printf("gzgets() after gzseek: %s\n", (char*)uncompr); + } + + gzclose(file); +#endif +} + +#endif /* Z_SOLO */ + +/* =========================================================================== + * Test deflate() with small buffers + */ +void test_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + uLong len = (uLong)strlen(hello)+1; + + c_stream.zalloc = zalloc; + c_stream.zfree = zfree; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (z_const unsigned char *)hello; + c_stream.next_out = compr; + + while (c_stream.total_in != len && c_stream.total_out < comprLen) { + c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + } + /* Finish the stream, still forcing small buffers: */ + for (;;) { + c_stream.avail_out = 1; + err = deflate(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "deflate"); + } + + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with small buffers + */ +void test_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = zalloc; + d_stream.zfree = zfree; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = 0; + d_stream.next_out = uncompr; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) { + d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate\n"); + exit(1); + } else { + printf("inflate(): %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Test deflate() with large buffers and dynamic change of compression level + */ +void test_large_deflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = zalloc; + c_stream.zfree = zfree; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_SPEED); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + /* At this point, uncompr is still mostly zeroes, so it should compress + * very well: + */ + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + if (c_stream.avail_in != 0) { + fprintf(stderr, "deflate not greedy\n"); + exit(1); + } + + /* Feed in already compressed data and switch to no compression: */ + deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); + c_stream.next_in = compr; + c_stream.avail_in = (uInt)comprLen/2; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + /* Switch back to compressing mode: */ + deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED); + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + exit(1); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with large buffers + */ +void test_large_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = zalloc; + d_stream.zfree = zfree; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + for (;;) { + d_stream.next_out = uncompr; /* discard the output */ + d_stream.avail_out = (uInt)uncomprLen; + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "large inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (d_stream.total_out != 2*uncomprLen + comprLen/2) { + fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out); + exit(1); + } else { + printf("large_inflate(): OK\n"); + } +} + +/* =========================================================================== + * Test deflate() with full flush + */ +void test_flush(compr, comprLen) + Byte *compr; + uLong *comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + uInt len = (uInt)strlen(hello)+1; + + c_stream.zalloc = zalloc; + c_stream.zfree = zfree; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (z_const unsigned char *)hello; + c_stream.next_out = compr; + c_stream.avail_in = 3; + c_stream.avail_out = (uInt)*comprLen; + err = deflate(&c_stream, Z_FULL_FLUSH); + CHECK_ERR(err, "deflate"); + + compr[3]++; /* force an error in first compressed block */ + c_stream.avail_in = len - 3; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + CHECK_ERR(err, "deflate"); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); + + *comprLen = c_stream.total_out; +} + +/* =========================================================================== + * Test inflateSync() + */ +void test_sync(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = zalloc; + d_stream.zfree = zfree; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = 2; /* just read the zlib header */ + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + err = inflate(&d_stream, Z_NO_FLUSH); + CHECK_ERR(err, "inflate"); + + d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */ + err = inflateSync(&d_stream); /* but skip the damaged part */ + CHECK_ERR(err, "inflateSync"); + + err = inflate(&d_stream, Z_FINISH); + if (err != Z_DATA_ERROR) { + fprintf(stderr, "inflate should report DATA_ERROR\n"); + /* Because of incorrect adler32 */ + exit(1); + } + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + printf("after inflateSync(): hel%s\n", (char *)uncompr); +} + +/* =========================================================================== + * Test deflate() with preset dictionary + */ +void test_dict_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = zalloc; + c_stream.zfree = zfree; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + err = deflateSetDictionary(&c_stream, + (const Bytef*)dictionary, (int)sizeof(dictionary)); + CHECK_ERR(err, "deflateSetDictionary"); + + dictId = c_stream.adler; + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + c_stream.next_in = (z_const unsigned char *)hello; + c_stream.avail_in = (uInt)strlen(hello)+1; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + exit(1); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with a preset dictionary + */ +void test_dict_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = zalloc; + d_stream.zfree = zfree; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + for (;;) { + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + if (err == Z_NEED_DICT) { + if (d_stream.adler != dictId) { + fprintf(stderr, "unexpected dictionary"); + exit(1); + } + err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary, + (int)sizeof(dictionary)); + } + CHECK_ERR(err, "inflate with dict"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate with dict\n"); + exit(1); + } else { + printf("inflate with dictionary: %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Usage: example [output.gz [input.gz]] + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + Byte *compr, *uncompr; + uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */ + uLong uncomprLen = comprLen; + static const char* myVersion = ZLIB_VERSION; + + if (zlibVersion()[0] != myVersion[0]) { + fprintf(stderr, "incompatible zlib version\n"); + exit(1); + + } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) { + fprintf(stderr, "warning: different zlib version\n"); + } + + printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n", + ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags()); + + compr = (Byte*)calloc((uInt)comprLen, 1); + uncompr = (Byte*)calloc((uInt)uncomprLen, 1); + /* compr and uncompr are cleared to avoid reading uninitialized + * data and to ensure that uncompr compresses well. + */ + if (compr == Z_NULL || uncompr == Z_NULL) { + printf("out of memory\n"); + exit(1); + } + +#ifdef Z_SOLO + (void)argc; + (void)argv; +#else + test_compress(compr, comprLen, uncompr, uncomprLen); + + test_gzio((argc > 1 ? argv[1] : TESTFILE), + uncompr, uncomprLen); +#endif + + test_deflate(compr, comprLen); + test_inflate(compr, comprLen, uncompr, uncomprLen); + + test_large_deflate(compr, comprLen, uncompr, uncomprLen); + test_large_inflate(compr, comprLen, uncompr, uncomprLen); + + test_flush(compr, &comprLen); + test_sync(compr, comprLen, uncompr, uncomprLen); + comprLen = uncomprLen; + + test_dict_deflate(compr, comprLen); + test_dict_inflate(compr, comprLen, uncompr, uncomprLen); + + free(compr); + free(uncompr); + + return 0; +} diff --git a/contrib/zlib/test/infcover.c b/contrib/zlib/test/infcover.c new file mode 100644 index 00000000..2be01646 --- /dev/null +++ b/contrib/zlib/test/infcover.c @@ -0,0 +1,671 @@ +/* infcover.c -- test zlib's inflate routines with full code coverage + * Copyright (C) 2011, 2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* to use, do: ./configure --cover && make cover */ + +#include +#include +#include +#include +#include "zlib.h" + +/* get definition of internal structure so we can mess with it (see pull()), + and so we can call inflate_trees() (see cover5()) */ +#define ZLIB_INTERNAL +#include "inftrees.h" +#include "inflate.h" + +#define local static + +/* -- memory tracking routines -- */ + +/* + These memory tracking routines are provided to zlib and track all of zlib's + allocations and deallocations, check for LIFO operations, keep a current + and high water mark of total bytes requested, optionally set a limit on the + total memory that can be allocated, and when done check for memory leaks. + + They are used as follows: + + z_stream strm; + mem_setup(&strm) initializes the memory tracking and sets the + zalloc, zfree, and opaque members of strm to use + memory tracking for all zlib operations on strm + mem_limit(&strm, limit) sets a limit on the total bytes requested -- a + request that exceeds this limit will result in an + allocation failure (returns NULL) -- setting the + limit to zero means no limit, which is the default + after mem_setup() + mem_used(&strm, "msg") prints to stderr "msg" and the total bytes used + mem_high(&strm, "msg") prints to stderr "msg" and the high water mark + mem_done(&strm, "msg") ends memory tracking, releases all allocations + for the tracking as well as leaked zlib blocks, if + any. If there was anything unusual, such as leaked + blocks, non-FIFO frees, or frees of addresses not + allocated, then "msg" and information about the + problem is printed to stderr. If everything is + normal, nothing is printed. mem_done resets the + strm members to Z_NULL to use the default memory + allocation routines on the next zlib initialization + using strm. + */ + +/* these items are strung together in a linked list, one for each allocation */ +struct mem_item { + void *ptr; /* pointer to allocated memory */ + size_t size; /* requested size of allocation */ + struct mem_item *next; /* pointer to next item in list, or NULL */ +}; + +/* this structure is at the root of the linked list, and tracks statistics */ +struct mem_zone { + struct mem_item *first; /* pointer to first item in list, or NULL */ + size_t total, highwater; /* total allocations, and largest total */ + size_t limit; /* memory allocation limit, or 0 if no limit */ + int notlifo, rogue; /* counts of non-LIFO frees and rogue frees */ +}; + +/* memory allocation routine to pass to zlib */ +local void *mem_alloc(void *mem, unsigned count, unsigned size) +{ + void *ptr; + struct mem_item *item; + struct mem_zone *zone = mem; + size_t len = count * (size_t)size; + + /* induced allocation failure */ + if (zone == NULL || (zone->limit && zone->total + len > zone->limit)) + return NULL; + + /* perform allocation using the standard library, fill memory with a + non-zero value to make sure that the code isn't depending on zeros */ + ptr = malloc(len); + if (ptr == NULL) + return NULL; + memset(ptr, 0xa5, len); + + /* create a new item for the list */ + item = malloc(sizeof(struct mem_item)); + if (item == NULL) { + free(ptr); + return NULL; + } + item->ptr = ptr; + item->size = len; + + /* insert item at the beginning of the list */ + item->next = zone->first; + zone->first = item; + + /* update the statistics */ + zone->total += item->size; + if (zone->total > zone->highwater) + zone->highwater = zone->total; + + /* return the allocated memory */ + return ptr; +} + +/* memory free routine to pass to zlib */ +local void mem_free(void *mem, void *ptr) +{ + struct mem_item *item, *next; + struct mem_zone *zone = mem; + + /* if no zone, just do a free */ + if (zone == NULL) { + free(ptr); + return; + } + + /* point next to the item that matches ptr, or NULL if not found -- remove + the item from the linked list if found */ + next = zone->first; + if (next) { + if (next->ptr == ptr) + zone->first = next->next; /* first one is it, remove from list */ + else { + do { /* search the linked list */ + item = next; + next = item->next; + } while (next != NULL && next->ptr != ptr); + if (next) { /* if found, remove from linked list */ + item->next = next->next; + zone->notlifo++; /* not a LIFO free */ + } + + } + } + + /* if found, update the statistics and free the item */ + if (next) { + zone->total -= next->size; + free(next); + } + + /* if not found, update the rogue count */ + else + zone->rogue++; + + /* in any case, do the requested free with the standard library function */ + free(ptr); +} + +/* set up a controlled memory allocation space for monitoring, set the stream + parameters to the controlled routines, with opaque pointing to the space */ +local void mem_setup(z_stream *strm) +{ + struct mem_zone *zone; + + zone = malloc(sizeof(struct mem_zone)); + assert(zone != NULL); + zone->first = NULL; + zone->total = 0; + zone->highwater = 0; + zone->limit = 0; + zone->notlifo = 0; + zone->rogue = 0; + strm->opaque = zone; + strm->zalloc = mem_alloc; + strm->zfree = mem_free; +} + +/* set a limit on the total memory allocation, or 0 to remove the limit */ +local void mem_limit(z_stream *strm, size_t limit) +{ + struct mem_zone *zone = strm->opaque; + + zone->limit = limit; +} + +/* show the current total requested allocations in bytes */ +local void mem_used(z_stream *strm, char *prefix) +{ + struct mem_zone *zone = strm->opaque; + + fprintf(stderr, "%s: %lu allocated\n", prefix, zone->total); +} + +/* show the high water allocation in bytes */ +local void mem_high(z_stream *strm, char *prefix) +{ + struct mem_zone *zone = strm->opaque; + + fprintf(stderr, "%s: %lu high water mark\n", prefix, zone->highwater); +} + +/* release the memory allocation zone -- if there are any surprises, notify */ +local void mem_done(z_stream *strm, char *prefix) +{ + int count = 0; + struct mem_item *item, *next; + struct mem_zone *zone = strm->opaque; + + /* show high water mark */ + mem_high(strm, prefix); + + /* free leftover allocations and item structures, if any */ + item = zone->first; + while (item != NULL) { + free(item->ptr); + next = item->next; + free(item); + item = next; + count++; + } + + /* issue alerts about anything unexpected */ + if (count || zone->total) + fprintf(stderr, "** %s: %lu bytes in %d blocks not freed\n", + prefix, zone->total, count); + if (zone->notlifo) + fprintf(stderr, "** %s: %d frees not LIFO\n", prefix, zone->notlifo); + if (zone->rogue) + fprintf(stderr, "** %s: %d frees not recognized\n", + prefix, zone->rogue); + + /* free the zone and delete from the stream */ + free(zone); + strm->opaque = Z_NULL; + strm->zalloc = Z_NULL; + strm->zfree = Z_NULL; +} + +/* -- inflate test routines -- */ + +/* Decode a hexadecimal string, set *len to length, in[] to the bytes. This + decodes liberally, in that hex digits can be adjacent, in which case two in + a row writes a byte. Or they can be delimited by any non-hex character, + where the delimiters are ignored except when a single hex digit is followed + by a delimiter, where that single digit writes a byte. The returned data is + allocated and must eventually be freed. NULL is returned if out of memory. + If the length is not needed, then len can be NULL. */ +local unsigned char *h2b(const char *hex, unsigned *len) +{ + unsigned char *in, *re; + unsigned next, val; + + in = malloc((strlen(hex) + 1) >> 1); + if (in == NULL) + return NULL; + next = 0; + val = 1; + do { + if (*hex >= '0' && *hex <= '9') + val = (val << 4) + *hex - '0'; + else if (*hex >= 'A' && *hex <= 'F') + val = (val << 4) + *hex - 'A' + 10; + else if (*hex >= 'a' && *hex <= 'f') + val = (val << 4) + *hex - 'a' + 10; + else if (val != 1 && val < 32) /* one digit followed by delimiter */ + val += 240; /* make it look like two digits */ + if (val > 255) { /* have two digits */ + in[next++] = val & 0xff; /* save the decoded byte */ + val = 1; /* start over */ + } + } while (*hex++); /* go through the loop with the terminating null */ + if (len != NULL) + *len = next; + re = realloc(in, next); + return re == NULL ? in : re; +} + +/* generic inflate() run, where hex is the hexadecimal input data, what is the + text to include in an error message, step is how much input data to feed + inflate() on each call, or zero to feed it all, win is the window bits + parameter to inflateInit2(), len is the size of the output buffer, and err + is the error code expected from the first inflate() call (the second + inflate() call is expected to return Z_STREAM_END). If win is 47, then + header information is collected with inflateGetHeader(). If a zlib stream + is looking for a dictionary, then an empty dictionary is provided. + inflate() is run until all of the input data is consumed. */ +local void inf(char *hex, char *what, unsigned step, int win, unsigned len, + int err) +{ + int ret; + unsigned have; + unsigned char *in, *out; + z_stream strm, copy; + gz_header head; + + mem_setup(&strm); + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit2(&strm, win); + if (ret != Z_OK) { + mem_done(&strm, what); + return; + } + out = malloc(len); assert(out != NULL); + if (win == 47) { + head.extra = out; + head.extra_max = len; + head.name = out; + head.name_max = len; + head.comment = out; + head.comm_max = len; + ret = inflateGetHeader(&strm, &head); assert(ret == Z_OK); + } + in = h2b(hex, &have); assert(in != NULL); + if (step == 0 || step > have) + step = have; + strm.avail_in = step; + have -= step; + strm.next_in = in; + do { + strm.avail_out = len; + strm.next_out = out; + ret = inflate(&strm, Z_NO_FLUSH); assert(err == 9 || ret == err); + if (ret != Z_OK && ret != Z_BUF_ERROR && ret != Z_NEED_DICT) + break; + if (ret == Z_NEED_DICT) { + ret = inflateSetDictionary(&strm, in, 1); + assert(ret == Z_DATA_ERROR); + mem_limit(&strm, 1); + ret = inflateSetDictionary(&strm, out, 0); + assert(ret == Z_MEM_ERROR); + mem_limit(&strm, 0); + ((struct inflate_state *)strm.state)->mode = DICT; + ret = inflateSetDictionary(&strm, out, 0); + assert(ret == Z_OK); + ret = inflate(&strm, Z_NO_FLUSH); assert(ret == Z_BUF_ERROR); + } + ret = inflateCopy(©, &strm); assert(ret == Z_OK); + ret = inflateEnd(©); assert(ret == Z_OK); + err = 9; /* don't care next time around */ + have += strm.avail_in; + strm.avail_in = step > have ? have : step; + have -= strm.avail_in; + } while (strm.avail_in); + free(in); + free(out); + ret = inflateReset2(&strm, -8); assert(ret == Z_OK); + ret = inflateEnd(&strm); assert(ret == Z_OK); + mem_done(&strm, what); +} + +/* cover all of the lines in inflate.c up to inflate() */ +local void cover_support(void) +{ + int ret; + z_stream strm; + + mem_setup(&strm); + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit(&strm); assert(ret == Z_OK); + mem_used(&strm, "inflate init"); + ret = inflatePrime(&strm, 5, 31); assert(ret == Z_OK); + ret = inflatePrime(&strm, -1, 0); assert(ret == Z_OK); + ret = inflateSetDictionary(&strm, Z_NULL, 0); + assert(ret == Z_STREAM_ERROR); + ret = inflateEnd(&strm); assert(ret == Z_OK); + mem_done(&strm, "prime"); + + inf("63 0", "force window allocation", 0, -15, 1, Z_OK); + inf("63 18 5", "force window replacement", 0, -8, 259, Z_OK); + inf("63 18 68 30 d0 0 0", "force split window update", 4, -8, 259, Z_OK); + inf("3 0", "use fixed blocks", 0, -15, 1, Z_STREAM_END); + inf("", "bad window size", 0, 1, 0, Z_STREAM_ERROR); + + mem_setup(&strm); + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit_(&strm, ZLIB_VERSION - 1, (int)sizeof(z_stream)); + assert(ret == Z_VERSION_ERROR); + mem_done(&strm, "wrong version"); + + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit(&strm); assert(ret == Z_OK); + ret = inflateEnd(&strm); assert(ret == Z_OK); + fputs("inflate built-in memory routines\n", stderr); +} + +/* cover all inflate() header and trailer cases and code after inflate() */ +local void cover_wrap(void) +{ + int ret; + z_stream strm, copy; + unsigned char dict[257]; + + ret = inflate(Z_NULL, 0); assert(ret == Z_STREAM_ERROR); + ret = inflateEnd(Z_NULL); assert(ret == Z_STREAM_ERROR); + ret = inflateCopy(Z_NULL, Z_NULL); assert(ret == Z_STREAM_ERROR); + fputs("inflate bad parameters\n", stderr); + + inf("1f 8b 0 0", "bad gzip method", 0, 31, 0, Z_DATA_ERROR); + inf("1f 8b 8 80", "bad gzip flags", 0, 31, 0, Z_DATA_ERROR); + inf("77 85", "bad zlib method", 0, 15, 0, Z_DATA_ERROR); + inf("8 99", "set window size from header", 0, 0, 0, Z_OK); + inf("78 9c", "bad zlib window size", 0, 8, 0, Z_DATA_ERROR); + inf("78 9c 63 0 0 0 1 0 1", "check adler32", 0, 15, 1, Z_STREAM_END); + inf("1f 8b 8 1e 0 0 0 0 0 0 1 0 0 0 0 0 0", "bad header crc", 0, 47, 1, + Z_DATA_ERROR); + inf("1f 8b 8 2 0 0 0 0 0 0 1d 26 3 0 0 0 0 0 0 0 0 0", "check gzip length", + 0, 47, 0, Z_STREAM_END); + inf("78 90", "bad zlib header check", 0, 47, 0, Z_DATA_ERROR); + inf("8 b8 0 0 0 1", "need dictionary", 0, 8, 0, Z_NEED_DICT); + inf("78 9c 63 0", "compute adler32", 0, 15, 1, Z_OK); + + mem_setup(&strm); + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit2(&strm, -8); + strm.avail_in = 2; + strm.next_in = (void *)"\x63"; + strm.avail_out = 1; + strm.next_out = (void *)&ret; + mem_limit(&strm, 1); + ret = inflate(&strm, Z_NO_FLUSH); assert(ret == Z_MEM_ERROR); + ret = inflate(&strm, Z_NO_FLUSH); assert(ret == Z_MEM_ERROR); + mem_limit(&strm, 0); + memset(dict, 0, 257); + ret = inflateSetDictionary(&strm, dict, 257); + assert(ret == Z_OK); + mem_limit(&strm, (sizeof(struct inflate_state) << 1) + 256); + ret = inflatePrime(&strm, 16, 0); assert(ret == Z_OK); + strm.avail_in = 2; + strm.next_in = (void *)"\x80"; + ret = inflateSync(&strm); assert(ret == Z_DATA_ERROR); + ret = inflate(&strm, Z_NO_FLUSH); assert(ret == Z_STREAM_ERROR); + strm.avail_in = 4; + strm.next_in = (void *)"\0\0\xff\xff"; + ret = inflateSync(&strm); assert(ret == Z_OK); + (void)inflateSyncPoint(&strm); + ret = inflateCopy(©, &strm); assert(ret == Z_MEM_ERROR); + mem_limit(&strm, 0); + ret = inflateUndermine(&strm, 1); assert(ret == Z_DATA_ERROR); + (void)inflateMark(&strm); + ret = inflateEnd(&strm); assert(ret == Z_OK); + mem_done(&strm, "miscellaneous, force memory errors"); +} + +/* input and output functions for inflateBack() */ +local unsigned pull(void *desc, unsigned char **buf) +{ + static unsigned int next = 0; + static unsigned char dat[] = {0x63, 0, 2, 0}; + struct inflate_state *state; + + if (desc == Z_NULL) { + next = 0; + return 0; /* no input (already provided at next_in) */ + } + state = (void *)((z_stream *)desc)->state; + if (state != Z_NULL) + state->mode = SYNC; /* force an otherwise impossible situation */ + return next < sizeof(dat) ? (*buf = dat + next++, 1) : 0; +} + +local int push(void *desc, unsigned char *buf, unsigned len) +{ + buf += len; + return desc != Z_NULL; /* force error if desc not null */ +} + +/* cover inflateBack() up to common deflate data cases and after those */ +local void cover_back(void) +{ + int ret; + z_stream strm; + unsigned char win[32768]; + + ret = inflateBackInit_(Z_NULL, 0, win, 0, 0); + assert(ret == Z_VERSION_ERROR); + ret = inflateBackInit(Z_NULL, 0, win); assert(ret == Z_STREAM_ERROR); + ret = inflateBack(Z_NULL, Z_NULL, Z_NULL, Z_NULL, Z_NULL); + assert(ret == Z_STREAM_ERROR); + ret = inflateBackEnd(Z_NULL); assert(ret == Z_STREAM_ERROR); + fputs("inflateBack bad parameters\n", stderr); + + mem_setup(&strm); + ret = inflateBackInit(&strm, 15, win); assert(ret == Z_OK); + strm.avail_in = 2; + strm.next_in = (void *)"\x03"; + ret = inflateBack(&strm, pull, Z_NULL, push, Z_NULL); + assert(ret == Z_STREAM_END); + /* force output error */ + strm.avail_in = 3; + strm.next_in = (void *)"\x63\x00"; + ret = inflateBack(&strm, pull, Z_NULL, push, &strm); + assert(ret == Z_BUF_ERROR); + /* force mode error by mucking with state */ + ret = inflateBack(&strm, pull, &strm, push, Z_NULL); + assert(ret == Z_STREAM_ERROR); + ret = inflateBackEnd(&strm); assert(ret == Z_OK); + mem_done(&strm, "inflateBack bad state"); + + ret = inflateBackInit(&strm, 15, win); assert(ret == Z_OK); + ret = inflateBackEnd(&strm); assert(ret == Z_OK); + fputs("inflateBack built-in memory routines\n", stderr); +} + +/* do a raw inflate of data in hexadecimal with both inflate and inflateBack */ +local int try(char *hex, char *id, int err) +{ + int ret; + unsigned len, size; + unsigned char *in, *out, *win; + char *prefix; + z_stream strm; + + /* convert to hex */ + in = h2b(hex, &len); + assert(in != NULL); + + /* allocate work areas */ + size = len << 3; + out = malloc(size); + assert(out != NULL); + win = malloc(32768); + assert(win != NULL); + prefix = malloc(strlen(id) + 6); + assert(prefix != NULL); + + /* first with inflate */ + strcpy(prefix, id); + strcat(prefix, "-late"); + mem_setup(&strm); + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit2(&strm, err < 0 ? 47 : -15); + assert(ret == Z_OK); + strm.avail_in = len; + strm.next_in = in; + do { + strm.avail_out = size; + strm.next_out = out; + ret = inflate(&strm, Z_TREES); + assert(ret != Z_STREAM_ERROR && ret != Z_MEM_ERROR); + if (ret == Z_DATA_ERROR || ret == Z_NEED_DICT) + break; + } while (strm.avail_in || strm.avail_out == 0); + if (err) { + assert(ret == Z_DATA_ERROR); + assert(strcmp(id, strm.msg) == 0); + } + inflateEnd(&strm); + mem_done(&strm, prefix); + + /* then with inflateBack */ + if (err >= 0) { + strcpy(prefix, id); + strcat(prefix, "-back"); + mem_setup(&strm); + ret = inflateBackInit(&strm, 15, win); + assert(ret == Z_OK); + strm.avail_in = len; + strm.next_in = in; + ret = inflateBack(&strm, pull, Z_NULL, push, Z_NULL); + assert(ret != Z_STREAM_ERROR); + if (err) { + assert(ret == Z_DATA_ERROR); + assert(strcmp(id, strm.msg) == 0); + } + inflateBackEnd(&strm); + mem_done(&strm, prefix); + } + + /* clean up */ + free(prefix); + free(win); + free(out); + free(in); + return ret; +} + +/* cover deflate data cases in both inflate() and inflateBack() */ +local void cover_inflate(void) +{ + try("0 0 0 0 0", "invalid stored block lengths", 1); + try("3 0", "fixed", 0); + try("6", "invalid block type", 1); + try("1 1 0 fe ff 0", "stored", 0); + try("fc 0 0", "too many length or distance symbols", 1); + try("4 0 fe ff", "invalid code lengths set", 1); + try("4 0 24 49 0", "invalid bit length repeat", 1); + try("4 0 24 e9 ff ff", "invalid bit length repeat", 1); + try("4 0 24 e9 ff 6d", "invalid code -- missing end-of-block", 1); + try("4 80 49 92 24 49 92 24 71 ff ff 93 11 0", + "invalid literal/lengths set", 1); + try("4 80 49 92 24 49 92 24 f b4 ff ff c3 84", "invalid distances set", 1); + try("4 c0 81 8 0 0 0 0 20 7f eb b 0 0", "invalid literal/length code", 1); + try("2 7e ff ff", "invalid distance code", 1); + try("c c0 81 0 0 0 0 0 90 ff 6b 4 0", "invalid distance too far back", 1); + + /* also trailer mismatch just in inflate() */ + try("1f 8b 8 0 0 0 0 0 0 0 3 0 0 0 0 1", "incorrect data check", -1); + try("1f 8b 8 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 1", + "incorrect length check", -1); + try("5 c0 21 d 0 0 0 80 b0 fe 6d 2f 91 6c", "pull 17", 0); + try("5 e0 81 91 24 cb b2 2c 49 e2 f 2e 8b 9a 47 56 9f fb fe ec d2 ff 1f", + "long code", 0); + try("ed c0 1 1 0 0 0 40 20 ff 57 1b 42 2c 4f", "length extra", 0); + try("ed cf c1 b1 2c 47 10 c4 30 fa 6f 35 1d 1 82 59 3d fb be 2e 2a fc f c", + "long distance and extra", 0); + try("ed c0 81 0 0 0 0 80 a0 fd a9 17 a9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 " + "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6", "window end", 0); + inf("2 8 20 80 0 3 0", "inflate_fast TYPE return", 0, -15, 258, + Z_STREAM_END); + inf("63 18 5 40 c 0", "window wrap", 3, -8, 300, Z_OK); +} + +/* cover remaining lines in inftrees.c */ +local void cover_trees(void) +{ + int ret; + unsigned bits; + unsigned short lens[16], work[16]; + code *next, table[ENOUGH_DISTS]; + + /* we need to call inflate_table() directly in order to manifest not- + enough errors, since zlib insures that enough is always enough */ + for (bits = 0; bits < 15; bits++) + lens[bits] = (unsigned short)(bits + 1); + lens[15] = 15; + next = table; + bits = 15; + ret = inflate_table(DISTS, lens, 16, &next, &bits, work); + assert(ret == 1); + next = table; + bits = 1; + ret = inflate_table(DISTS, lens, 16, &next, &bits, work); + assert(ret == 1); + fputs("inflate_table not enough errors\n", stderr); +} + +/* cover remaining inffast.c decoding and window copying */ +local void cover_fast(void) +{ + inf("e5 e0 81 ad 6d cb b2 2c c9 01 1e 59 63 ae 7d ee fb 4d fd b5 35 41 68" + " ff 7f 0f 0 0 0", "fast length extra bits", 0, -8, 258, Z_DATA_ERROR); + inf("25 fd 81 b5 6d 59 b6 6a 49 ea af 35 6 34 eb 8c b9 f6 b9 1e ef 67 49" + " 50 fe ff ff 3f 0 0", "fast distance extra bits", 0, -8, 258, + Z_DATA_ERROR); + inf("3 7e 0 0 0 0 0", "fast invalid distance code", 0, -8, 258, + Z_DATA_ERROR); + inf("1b 7 0 0 0 0 0", "fast invalid literal/length code", 0, -8, 258, + Z_DATA_ERROR); + inf("d c7 1 ae eb 38 c 4 41 a0 87 72 de df fb 1f b8 36 b1 38 5d ff ff 0", + "fast 2nd level codes and too far back", 0, -8, 258, Z_DATA_ERROR); + inf("63 18 5 8c 10 8 0 0 0 0", "very common case", 0, -8, 259, Z_OK); + inf("63 60 60 18 c9 0 8 18 18 18 26 c0 28 0 29 0 0 0", + "contiguous and wrap around window", 6, -8, 259, Z_OK); + inf("63 0 3 0 0 0 0 0", "copy direct from output", 0, -8, 259, + Z_STREAM_END); +} + +int main(void) +{ + fprintf(stderr, "%s\n", zlibVersion()); + cover_support(); + cover_wrap(); + cover_back(); + cover_inflate(); + cover_trees(); + cover_fast(); + return 0; +} diff --git a/contrib/zlib/test/minigzip.c b/contrib/zlib/test/minigzip.c new file mode 100644 index 00000000..e22fb08c --- /dev/null +++ b/contrib/zlib/test/minigzip.c @@ -0,0 +1,651 @@ +/* minigzip.c -- simulate gzip using the zlib compression library + * Copyright (C) 1995-2006, 2010, 2011, 2016 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * minigzip is a minimal implementation of the gzip utility. This is + * only an example of using zlib and isn't meant to replace the + * full-featured gzip. No attempt is made to deal with file systems + * limiting names to 14 or 8+3 characters, etc... Error checking is + * very limited. So use minigzip only for testing; use gzip for the + * real thing. On MSDOS, use only on file names without extension + * or in pipe mode. + */ + +/* @(#) $Id$ */ + +#include "zlib.h" +#include + +#ifdef STDC +# include +# include +#endif + +#ifdef USE_MMAP +# include +# include +# include +#endif + +#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) +# include +# include +# ifdef UNDER_CE +# include +# endif +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1900 +# define snprintf _snprintf +#endif + +#ifdef VMS +# define unlink delete +# define GZ_SUFFIX "-gz" +#endif +#ifdef RISCOS +# define unlink remove +# define GZ_SUFFIX "-gz" +# define fileno(file) file->__file +#endif +#if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fileno */ +#endif + +#if !defined(Z_HAVE_UNISTD_H) && !defined(_LARGEFILE64_SOURCE) +#ifndef WIN32 /* unlink already in stdio.h for WIN32 */ + extern int unlink OF((const char *)); +#endif +#endif + +#if defined(UNDER_CE) +# include +# define perror(s) pwinerror(s) + +/* Map the Windows error number in ERROR to a locale-dependent error + message string and return a pointer to it. Typically, the values + for ERROR come from GetLastError. + + The string pointed to shall not be modified by the application, + but may be overwritten by a subsequent call to strwinerror + + The strwinerror function does not change the current setting + of GetLastError. */ + +static char *strwinerror (error) + DWORD error; +{ + static char buf[1024]; + + wchar_t *msgbuf; + DWORD lasterr = GetLastError(); + DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + error, + 0, /* Default language */ + (LPVOID)&msgbuf, + 0, + NULL); + if (chars != 0) { + /* If there is an \r\n appended, zap it. */ + if (chars >= 2 + && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { + chars -= 2; + msgbuf[chars] = 0; + } + + if (chars > sizeof (buf) - 1) { + chars = sizeof (buf) - 1; + msgbuf[chars] = 0; + } + + wcstombs(buf, msgbuf, chars + 1); + LocalFree(msgbuf); + } + else { + sprintf(buf, "unknown win32 error (%ld)", error); + } + + SetLastError(lasterr); + return buf; +} + +static void pwinerror (s) + const char *s; +{ + if (s && *s) + fprintf(stderr, "%s: %s\n", s, strwinerror(GetLastError ())); + else + fprintf(stderr, "%s\n", strwinerror(GetLastError ())); +} + +#endif /* UNDER_CE */ + +#ifndef GZ_SUFFIX +# define GZ_SUFFIX ".gz" +#endif +#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1) + +#define BUFLEN 16384 +#define MAX_NAME_LEN 1024 + +#ifdef MAXSEG_64K +# define local static + /* Needed for systems with limitation on stack size. */ +#else +# define local +#endif + +#ifdef Z_SOLO +/* for Z_SOLO, create simplified gz* functions using deflate and inflate */ + +#if defined(Z_HAVE_UNISTD_H) || defined(Z_LARGE) +# include /* for unlink() */ +#endif + +void *myalloc OF((void *, unsigned, unsigned)); +void myfree OF((void *, void *)); + +void *myalloc(q, n, m) + void *q; + unsigned n, m; +{ + (void)q; + return calloc(n, m); +} + +void myfree(q, p) + void *q, *p; +{ + (void)q; + free(p); +} + +typedef struct gzFile_s { + FILE *file; + int write; + int err; + char *msg; + z_stream strm; +} *gzFile; + +gzFile gzopen OF((const char *, const char *)); +gzFile gzdopen OF((int, const char *)); +gzFile gz_open OF((const char *, int, const char *)); + +gzFile gzopen(path, mode) +const char *path; +const char *mode; +{ + return gz_open(path, -1, mode); +} + +gzFile gzdopen(fd, mode) +int fd; +const char *mode; +{ + return gz_open(NULL, fd, mode); +} + +gzFile gz_open(path, fd, mode) + const char *path; + int fd; + const char *mode; +{ + gzFile gz; + int ret; + + gz = malloc(sizeof(struct gzFile_s)); + if (gz == NULL) + return NULL; + gz->write = strchr(mode, 'w') != NULL; + gz->strm.zalloc = myalloc; + gz->strm.zfree = myfree; + gz->strm.opaque = Z_NULL; + if (gz->write) + ret = deflateInit2(&(gz->strm), -1, 8, 15 + 16, 8, 0); + else { + gz->strm.next_in = 0; + gz->strm.avail_in = Z_NULL; + ret = inflateInit2(&(gz->strm), 15 + 16); + } + if (ret != Z_OK) { + free(gz); + return NULL; + } + gz->file = path == NULL ? fdopen(fd, gz->write ? "wb" : "rb") : + fopen(path, gz->write ? "wb" : "rb"); + if (gz->file == NULL) { + gz->write ? deflateEnd(&(gz->strm)) : inflateEnd(&(gz->strm)); + free(gz); + return NULL; + } + gz->err = 0; + gz->msg = ""; + return gz; +} + +int gzwrite OF((gzFile, const void *, unsigned)); + +int gzwrite(gz, buf, len) + gzFile gz; + const void *buf; + unsigned len; +{ + z_stream *strm; + unsigned char out[BUFLEN]; + + if (gz == NULL || !gz->write) + return 0; + strm = &(gz->strm); + strm->next_in = (void *)buf; + strm->avail_in = len; + do { + strm->next_out = out; + strm->avail_out = BUFLEN; + (void)deflate(strm, Z_NO_FLUSH); + fwrite(out, 1, BUFLEN - strm->avail_out, gz->file); + } while (strm->avail_out == 0); + return len; +} + +int gzread OF((gzFile, void *, unsigned)); + +int gzread(gz, buf, len) + gzFile gz; + void *buf; + unsigned len; +{ + int ret; + unsigned got; + unsigned char in[1]; + z_stream *strm; + + if (gz == NULL || gz->write) + return 0; + if (gz->err) + return 0; + strm = &(gz->strm); + strm->next_out = (void *)buf; + strm->avail_out = len; + do { + got = fread(in, 1, 1, gz->file); + if (got == 0) + break; + strm->next_in = in; + strm->avail_in = 1; + ret = inflate(strm, Z_NO_FLUSH); + if (ret == Z_DATA_ERROR) { + gz->err = Z_DATA_ERROR; + gz->msg = strm->msg; + return 0; + } + if (ret == Z_STREAM_END) + inflateReset(strm); + } while (strm->avail_out); + return len - strm->avail_out; +} + +int gzclose OF((gzFile)); + +int gzclose(gz) + gzFile gz; +{ + z_stream *strm; + unsigned char out[BUFLEN]; + + if (gz == NULL) + return Z_STREAM_ERROR; + strm = &(gz->strm); + if (gz->write) { + strm->next_in = Z_NULL; + strm->avail_in = 0; + do { + strm->next_out = out; + strm->avail_out = BUFLEN; + (void)deflate(strm, Z_FINISH); + fwrite(out, 1, BUFLEN - strm->avail_out, gz->file); + } while (strm->avail_out == 0); + deflateEnd(strm); + } + else + inflateEnd(strm); + fclose(gz->file); + free(gz); + return Z_OK; +} + +const char *gzerror OF((gzFile, int *)); + +const char *gzerror(gz, err) + gzFile gz; + int *err; +{ + *err = gz->err; + return gz->msg; +} + +#endif + +static char *prog; + +void error OF((const char *msg)); +void gz_compress OF((FILE *in, gzFile out)); +#ifdef USE_MMAP +int gz_compress_mmap OF((FILE *in, gzFile out)); +#endif +void gz_uncompress OF((gzFile in, FILE *out)); +void file_compress OF((char *file, char *mode)); +void file_uncompress OF((char *file)); +int main OF((int argc, char *argv[])); + +/* =========================================================================== + * Display error message and exit + */ +void error(msg) + const char *msg; +{ + fprintf(stderr, "%s: %s\n", prog, msg); + exit(1); +} + +/* =========================================================================== + * Compress input to output then close both files. + */ + +void gz_compress(in, out) + FILE *in; + gzFile out; +{ + local char buf[BUFLEN]; + int len; + int err; + +#ifdef USE_MMAP + /* Try first compressing with mmap. If mmap fails (minigzip used in a + * pipe), use the normal fread loop. + */ + if (gz_compress_mmap(in, out) == Z_OK) return; +#endif + for (;;) { + len = (int)fread(buf, 1, sizeof(buf), in); + if (ferror(in)) { + perror("fread"); + exit(1); + } + if (len == 0) break; + + if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err)); + } + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); +} + +#ifdef USE_MMAP /* MMAP version, Miguel Albrecht */ + +/* Try compressing the input file at once using mmap. Return Z_OK if + * if success, Z_ERRNO otherwise. + */ +int gz_compress_mmap(in, out) + FILE *in; + gzFile out; +{ + int len; + int err; + int ifd = fileno(in); + caddr_t buf; /* mmap'ed buffer for the entire input file */ + off_t buf_len; /* length of the input file */ + struct stat sb; + + /* Determine the size of the file, needed for mmap: */ + if (fstat(ifd, &sb) < 0) return Z_ERRNO; + buf_len = sb.st_size; + if (buf_len <= 0) return Z_ERRNO; + + /* Now do the actual mmap: */ + buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0); + if (buf == (caddr_t)(-1)) return Z_ERRNO; + + /* Compress the whole file at once: */ + len = gzwrite(out, (char *)buf, (unsigned)buf_len); + + if (len != (int)buf_len) error(gzerror(out, &err)); + + munmap(buf, buf_len); + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); + return Z_OK; +} +#endif /* USE_MMAP */ + +/* =========================================================================== + * Uncompress input to output then close both files. + */ +void gz_uncompress(in, out) + gzFile in; + FILE *out; +{ + local char buf[BUFLEN]; + int len; + int err; + + for (;;) { + len = gzread(in, buf, sizeof(buf)); + if (len < 0) error (gzerror(in, &err)); + if (len == 0) break; + + if ((int)fwrite(buf, 1, (unsigned)len, out) != len) { + error("failed fwrite"); + } + } + if (fclose(out)) error("failed fclose"); + + if (gzclose(in) != Z_OK) error("failed gzclose"); +} + + +/* =========================================================================== + * Compress the given file: create a corresponding .gz file and remove the + * original. + */ +void file_compress(file, mode) + char *file; + char *mode; +{ + local char outfile[MAX_NAME_LEN]; + FILE *in; + gzFile out; + + if (strlen(file) + strlen(GZ_SUFFIX) >= sizeof(outfile)) { + fprintf(stderr, "%s: filename too long\n", prog); + exit(1); + } + +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + snprintf(outfile, sizeof(outfile), "%s%s", file, GZ_SUFFIX); +#else + strcpy(outfile, file); + strcat(outfile, GZ_SUFFIX); +#endif + + in = fopen(file, "rb"); + if (in == NULL) { + perror(file); + exit(1); + } + out = gzopen(outfile, mode); + if (out == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile); + exit(1); + } + gz_compress(in, out); + + unlink(file); +} + + +/* =========================================================================== + * Uncompress the given file and remove the original. + */ +void file_uncompress(file) + char *file; +{ + local char buf[MAX_NAME_LEN]; + char *infile, *outfile; + FILE *out; + gzFile in; + unsigned len = strlen(file); + + if (len + strlen(GZ_SUFFIX) >= sizeof(buf)) { + fprintf(stderr, "%s: filename too long\n", prog); + exit(1); + } + +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + snprintf(buf, sizeof(buf), "%s", file); +#else + strcpy(buf, file); +#endif + + if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) { + infile = file; + outfile = buf; + outfile[len-3] = '\0'; + } else { + outfile = file; + infile = buf; +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + snprintf(buf + len, sizeof(buf) - len, "%s", GZ_SUFFIX); +#else + strcat(infile, GZ_SUFFIX); +#endif + } + in = gzopen(infile, "rb"); + if (in == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, infile); + exit(1); + } + out = fopen(outfile, "wb"); + if (out == NULL) { + perror(file); + exit(1); + } + + gz_uncompress(in, out); + + unlink(infile); +} + + +/* =========================================================================== + * Usage: minigzip [-c] [-d] [-f] [-h] [-r] [-1 to -9] [files...] + * -c : write to standard output + * -d : decompress + * -f : compress with Z_FILTERED + * -h : compress with Z_HUFFMAN_ONLY + * -r : compress with Z_RLE + * -1 to -9 : compression level + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + int copyout = 0; + int uncompr = 0; + gzFile file; + char *bname, outmode[20]; + +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + snprintf(outmode, sizeof(outmode), "%s", "wb6 "); +#else + strcpy(outmode, "wb6 "); +#endif + + prog = argv[0]; + bname = strrchr(argv[0], '/'); + if (bname) + bname++; + else + bname = argv[0]; + argc--, argv++; + + if (!strcmp(bname, "gunzip")) + uncompr = 1; + else if (!strcmp(bname, "zcat")) + copyout = uncompr = 1; + + while (argc > 0) { + if (strcmp(*argv, "-c") == 0) + copyout = 1; + else if (strcmp(*argv, "-d") == 0) + uncompr = 1; + else if (strcmp(*argv, "-f") == 0) + outmode[3] = 'f'; + else if (strcmp(*argv, "-h") == 0) + outmode[3] = 'h'; + else if (strcmp(*argv, "-r") == 0) + outmode[3] = 'R'; + else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' && + (*argv)[2] == 0) + outmode[2] = (*argv)[1]; + else + break; + argc--, argv++; + } + if (outmode[3] == ' ') + outmode[3] = 0; + if (argc == 0) { + SET_BINARY_MODE(stdin); + SET_BINARY_MODE(stdout); + if (uncompr) { + file = gzdopen(fileno(stdin), "rb"); + if (file == NULL) error("can't gzdopen stdin"); + gz_uncompress(file, stdout); + } else { + file = gzdopen(fileno(stdout), outmode); + if (file == NULL) error("can't gzdopen stdout"); + gz_compress(stdin, file); + } + } else { + if (copyout) { + SET_BINARY_MODE(stdout); + } + do { + if (uncompr) { + if (copyout) { + file = gzopen(*argv, "rb"); + if (file == NULL) + fprintf(stderr, "%s: can't gzopen %s\n", prog, *argv); + else + gz_uncompress(file, stdout); + } else { + file_uncompress(*argv); + } + } else { + if (copyout) { + FILE * in = fopen(*argv, "rb"); + + if (in == NULL) { + perror(*argv); + } else { + file = gzdopen(fileno(stdout), outmode); + if (file == NULL) error("can't gzdopen stdout"); + + gz_compress(in, file); + } + + } else { + file_compress(*argv, outmode); + } + } + } while (argv++, --argc); + } + return 0; +} diff --git a/contrib/zlib/treebuild.xml b/contrib/zlib/treebuild.xml new file mode 100644 index 00000000..fd75525f --- /dev/null +++ b/contrib/zlib/treebuild.xml @@ -0,0 +1,116 @@ + + + + zip compression library + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/contrib/zlib/trees.c b/contrib/zlib/trees.c new file mode 100644 index 00000000..50cf4b45 --- /dev/null +++ b/contrib/zlib/trees.c @@ -0,0 +1,1203 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2017 Jean-loup Gailly + * detect_data_type() function provided freely by Cosmin Truta, 2006 + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id$ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef ZLIB_DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local const static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local const static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local const static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, const ct_data *ltree, + const ct_data *dtree)); +local int detect_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef ZLIB_DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* !ZLIB_DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef ZLIB_DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (ush)value << s->bi_valid; + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= (ush)value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !ZLIB_DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = (int)value;\ + s->bi_buf |= (ush)val << s->bi_valid;\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (ush)(value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* ZLIB_DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ +#ifdef NO_INIT_GLOBAL_POINTERS + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; +#endif + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef ZLIB_DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, + "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void ZLIB_INTERNAL _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef ZLIB_DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (unsigned)(bits + xbits); + if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits); + } + if (overflow == 0) return; + + Tracev((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if ((unsigned) tree[m].Len != (unsigned) bits) { + Tracev((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((ulg)bits - tree[m].Len) * tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + unsigned code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + code = (code + bl_count[bits-1]) << 1; + next_code[bits] = (ush)code; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*((ulg)max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int last; /* one if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ + bi_windup(s); /* align on byte boundary */ + put_short(s, (ush)stored_len); + put_short(s, (ush)~stored_len); + zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len); + s->pending += stored_len; +#ifdef ZLIB_DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; + s->bits_sent += 2*16; + s->bits_sent += stored_len<<3; +#endif +} + +/* =========================================================================== + * Flush the bits in the bit buffer to pending output (leaves at most 7 bits) + */ +void ZLIB_INTERNAL _tr_flush_bits(s) + deflate_state *s; +{ + bi_flush(s); +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + */ +void ZLIB_INTERNAL _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef ZLIB_DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and write out the encoded block. + */ +void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int last; /* one if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is binary or text */ + if (s->strm->data_type == Z_UNKNOWN) + s->strm->data_type = detect_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, last); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+last, 3); + compress_block(s, (const ct_data *)static_ltree, + (const ct_data *)static_dtree); +#ifdef ZLIB_DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+last, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (const ct_data *)s->dyn_ltree, + (const ct_data *)s->dyn_dtree); +#ifdef ZLIB_DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (last) { + bi_windup(s); +#ifdef ZLIB_DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*last)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int ZLIB_INTERNAL _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + const ct_data *ltree; /* literal tree */ + const ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= (unsigned)base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); +} + +/* =========================================================================== + * Check if the data type is TEXT or BINARY, using the following algorithm: + * - TEXT if the two conditions below are satisfied: + * a) There are no non-portable control characters belonging to the + * "black list" (0..6, 14..25, 28..31). + * b) There is at least one printable character belonging to the + * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). + * - BINARY otherwise. + * - The following partially-portable control characters form a + * "gray list" that is ignored in this detection algorithm: + * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local int detect_data_type(s) + deflate_state *s; +{ + /* black_mask is the bit mask of black-listed bytes + * set bits 0..6, 14..25, and 28..31 + * 0xf3ffc07f = binary 11110011111111111100000001111111 + */ + unsigned long black_mask = 0xf3ffc07fUL; + int n; + + /* Check for non-textual ("black-listed") bytes. */ + for (n = 0; n <= 31; n++, black_mask >>= 1) + if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0)) + return Z_BINARY; + + /* Check for textual ("white-listed") bytes. */ + if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 + || s->dyn_ltree[13].Freq != 0) + return Z_TEXT; + for (n = 32; n < LITERALS; n++) + if (s->dyn_ltree[n].Freq != 0) + return Z_TEXT; + + /* There are no "black-listed" or "white-listed" bytes: + * this stream either is empty or has tolerated ("gray-listed") bytes only. + */ + return Z_BINARY; +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef ZLIB_DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} diff --git a/contrib/zlib/trees.h b/contrib/zlib/trees.h new file mode 100644 index 00000000..d35639d8 --- /dev/null +++ b/contrib/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/contrib/zlib/uncompr.c b/contrib/zlib/uncompr.c new file mode 100644 index 00000000..f03a1a86 --- /dev/null +++ b/contrib/zlib/uncompr.c @@ -0,0 +1,93 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003, 2010, 2014, 2016 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. *sourceLen is + the byte length of the source buffer. Upon entry, *destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, + *destLen is the size of the decompressed data and *sourceLen is the number + of source bytes consumed. Upon return, source + *sourceLen points to the + first unused input byte. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, or + Z_DATA_ERROR if the input data was corrupted, including if the input data is + an incomplete zlib stream. +*/ +int ZEXPORT uncompress2 (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong *sourceLen; +{ + z_stream stream; + int err; + const uInt max = (uInt)-1; + uLong len, left; + Byte buf[1]; /* for detection of incomplete stream when *destLen == 0 */ + + len = *sourceLen; + if (*destLen) { + left = *destLen; + *destLen = 0; + } + else { + left = 1; + dest = buf; + } + + stream.next_in = (z_const Bytef *)source; + stream.avail_in = 0; + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + stream.next_out = dest; + stream.avail_out = 0; + + do { + if (stream.avail_out == 0) { + stream.avail_out = left > (uLong)max ? max : (uInt)left; + left -= stream.avail_out; + } + if (stream.avail_in == 0) { + stream.avail_in = len > (uLong)max ? max : (uInt)len; + len -= stream.avail_in; + } + err = inflate(&stream, Z_NO_FLUSH); + } while (err == Z_OK); + + *sourceLen -= len + stream.avail_in; + if (dest != buf) + *destLen = stream.total_out; + else if (stream.total_out && err == Z_BUF_ERROR) + left = 1; + + inflateEnd(&stream); + return err == Z_STREAM_END ? Z_OK : + err == Z_NEED_DICT ? Z_DATA_ERROR : + err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR : + err; +} + +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return uncompress2(dest, destLen, source, &sourceLen); +} diff --git a/contrib/zlib/watcom/watcom_f.mak b/contrib/zlib/watcom/watcom_f.mak new file mode 100644 index 00000000..37f4d74c --- /dev/null +++ b/contrib/zlib/watcom/watcom_f.mak @@ -0,0 +1,43 @@ +# Makefile for zlib +# OpenWatcom flat model +# Last updated: 28-Dec-2005 + +# To use, do "wmake -f watcom_f.mak" + +C_SOURCE = adler32.c compress.c crc32.c deflate.c & + gzclose.c gzlib.c gzread.c gzwrite.c & + infback.c inffast.c inflate.c inftrees.c & + trees.c uncompr.c zutil.c + +OBJS = adler32.obj compress.obj crc32.obj deflate.obj & + gzclose.obj gzlib.obj gzread.obj gzwrite.obj & + infback.obj inffast.obj inflate.obj inftrees.obj & + trees.obj uncompr.obj zutil.obj + +CC = wcc386 +LINKER = wcl386 +CFLAGS = -zq -mf -3r -fp3 -s -bt=dos -oilrtfm -fr=nul -wx +ZLIB_LIB = zlib_f.lib + +.C.OBJ: + $(CC) $(CFLAGS) $[@ + +all: $(ZLIB_LIB) example.exe minigzip.exe + +$(ZLIB_LIB): $(OBJS) + wlib -b -c $(ZLIB_LIB) -+adler32.obj -+compress.obj -+crc32.obj + wlib -b -c $(ZLIB_LIB) -+gzclose.obj -+gzlib.obj -+gzread.obj -+gzwrite.obj + wlib -b -c $(ZLIB_LIB) -+deflate.obj -+infback.obj + wlib -b -c $(ZLIB_LIB) -+inffast.obj -+inflate.obj -+inftrees.obj + wlib -b -c $(ZLIB_LIB) -+trees.obj -+uncompr.obj -+zutil.obj + +example.exe: $(ZLIB_LIB) example.obj + $(LINKER) -ldos32a -fe=example.exe example.obj $(ZLIB_LIB) + +minigzip.exe: $(ZLIB_LIB) minigzip.obj + $(LINKER) -ldos32a -fe=minigzip.exe minigzip.obj $(ZLIB_LIB) + +clean: .SYMBOLIC + del *.obj + del $(ZLIB_LIB) + @echo Cleaning done diff --git a/contrib/zlib/watcom/watcom_l.mak b/contrib/zlib/watcom/watcom_l.mak new file mode 100644 index 00000000..193eed7b --- /dev/null +++ b/contrib/zlib/watcom/watcom_l.mak @@ -0,0 +1,43 @@ +# Makefile for zlib +# OpenWatcom large model +# Last updated: 28-Dec-2005 + +# To use, do "wmake -f watcom_l.mak" + +C_SOURCE = adler32.c compress.c crc32.c deflate.c & + gzclose.c gzlib.c gzread.c gzwrite.c & + infback.c inffast.c inflate.c inftrees.c & + trees.c uncompr.c zutil.c + +OBJS = adler32.obj compress.obj crc32.obj deflate.obj & + gzclose.obj gzlib.obj gzread.obj gzwrite.obj & + infback.obj inffast.obj inflate.obj inftrees.obj & + trees.obj uncompr.obj zutil.obj + +CC = wcc +LINKER = wcl +CFLAGS = -zq -ml -s -bt=dos -oilrtfm -fr=nul -wx +ZLIB_LIB = zlib_l.lib + +.C.OBJ: + $(CC) $(CFLAGS) $[@ + +all: $(ZLIB_LIB) example.exe minigzip.exe + +$(ZLIB_LIB): $(OBJS) + wlib -b -c $(ZLIB_LIB) -+adler32.obj -+compress.obj -+crc32.obj + wlib -b -c $(ZLIB_LIB) -+gzclose.obj -+gzlib.obj -+gzread.obj -+gzwrite.obj + wlib -b -c $(ZLIB_LIB) -+deflate.obj -+infback.obj + wlib -b -c $(ZLIB_LIB) -+inffast.obj -+inflate.obj -+inftrees.obj + wlib -b -c $(ZLIB_LIB) -+trees.obj -+uncompr.obj -+zutil.obj + +example.exe: $(ZLIB_LIB) example.obj + $(LINKER) -fe=example.exe example.obj $(ZLIB_LIB) + +minigzip.exe: $(ZLIB_LIB) minigzip.obj + $(LINKER) -fe=minigzip.exe minigzip.obj $(ZLIB_LIB) + +clean: .SYMBOLIC + del *.obj + del $(ZLIB_LIB) + @echo Cleaning done diff --git a/contrib/zlib/win32/DLL_FAQ.txt b/contrib/zlib/win32/DLL_FAQ.txt new file mode 100644 index 00000000..12c00901 --- /dev/null +++ b/contrib/zlib/win32/DLL_FAQ.txt @@ -0,0 +1,397 @@ + + Frequently Asked Questions about ZLIB1.DLL + + +This document describes the design, the rationale, and the usage +of the official DLL build of zlib, named ZLIB1.DLL. If you have +general questions about zlib, you should see the file "FAQ" found +in the zlib distribution, or at the following location: + http://www.gzip.org/zlib/zlib_faq.html + + + 1. What is ZLIB1.DLL, and how can I get it? + + - ZLIB1.DLL is the official build of zlib as a DLL. + (Please remark the character '1' in the name.) + + Pointers to a precompiled ZLIB1.DLL can be found in the zlib + web site at: + http://www.zlib.net/ + + Applications that link to ZLIB1.DLL can rely on the following + specification: + + * The exported symbols are exclusively defined in the source + files "zlib.h" and "zlib.def", found in an official zlib + source distribution. + * The symbols are exported by name, not by ordinal. + * The exported names are undecorated. + * The calling convention of functions is "C" (CDECL). + * The ZLIB1.DLL binary is linked to MSVCRT.DLL. + + The archive in which ZLIB1.DLL is bundled contains compiled + test programs that must run with a valid build of ZLIB1.DLL. + It is recommended to download the prebuilt DLL from the zlib + web site, instead of building it yourself, to avoid potential + incompatibilities that could be introduced by your compiler + and build settings. If you do build the DLL yourself, please + make sure that it complies with all the above requirements, + and it runs with the precompiled test programs, bundled with + the original ZLIB1.DLL distribution. + + If, for any reason, you need to build an incompatible DLL, + please use a different file name. + + + 2. Why did you change the name of the DLL to ZLIB1.DLL? + What happened to the old ZLIB.DLL? + + - The old ZLIB.DLL, built from zlib-1.1.4 or earlier, required + compilation settings that were incompatible to those used by + a static build. The DLL settings were supposed to be enabled + by defining the macro ZLIB_DLL, before including "zlib.h". + Incorrect handling of this macro was silently accepted at + build time, resulting in two major problems: + + * ZLIB_DLL was missing from the old makefile. When building + the DLL, not all people added it to the build options. In + consequence, incompatible incarnations of ZLIB.DLL started + to circulate around the net. + + * When switching from using the static library to using the + DLL, applications had to define the ZLIB_DLL macro and + to recompile all the sources that contained calls to zlib + functions. Failure to do so resulted in creating binaries + that were unable to run with the official ZLIB.DLL build. + + The only possible solution that we could foresee was to make + a binary-incompatible change in the DLL interface, in order to + remove the dependency on the ZLIB_DLL macro, and to release + the new DLL under a different name. + + We chose the name ZLIB1.DLL, where '1' indicates the major + zlib version number. We hope that we will not have to break + the binary compatibility again, at least not as long as the + zlib-1.x series will last. + + There is still a ZLIB_DLL macro, that can trigger a more + efficient build and use of the DLL, but compatibility no + longer dependents on it. + + + 3. Can I build ZLIB.DLL from the new zlib sources, and replace + an old ZLIB.DLL, that was built from zlib-1.1.4 or earlier? + + - In principle, you can do it by assigning calling convention + keywords to the macros ZEXPORT and ZEXPORTVA. In practice, + it depends on what you mean by "an old ZLIB.DLL", because the + old DLL exists in several mutually-incompatible versions. + You have to find out first what kind of calling convention is + being used in your particular ZLIB.DLL build, and to use the + same one in the new build. If you don't know what this is all + about, you might be better off if you would just leave the old + DLL intact. + + + 4. Can I compile my application using the new zlib interface, and + link it to an old ZLIB.DLL, that was built from zlib-1.1.4 or + earlier? + + - The official answer is "no"; the real answer depends again on + what kind of ZLIB.DLL you have. Even if you are lucky, this + course of action is unreliable. + + If you rebuild your application and you intend to use a newer + version of zlib (post- 1.1.4), it is strongly recommended to + link it to the new ZLIB1.DLL. + + + 5. Why are the zlib symbols exported by name, and not by ordinal? + + - Although exporting symbols by ordinal is a little faster, it + is risky. Any single glitch in the maintenance or use of the + DEF file that contains the ordinals can result in incompatible + builds and frustrating crashes. Simply put, the benefits of + exporting symbols by ordinal do not justify the risks. + + Technically, it should be possible to maintain ordinals in + the DEF file, and still export the symbols by name. Ordinals + exist in every DLL, and even if the dynamic linking performed + at the DLL startup is searching for names, ordinals serve as + hints, for a faster name lookup. However, if the DEF file + contains ordinals, the Microsoft linker automatically builds + an implib that will cause the executables linked to it to use + those ordinals, and not the names. It is interesting to + notice that the GNU linker for Win32 does not suffer from this + problem. + + It is possible to avoid the DEF file if the exported symbols + are accompanied by a "__declspec(dllexport)" attribute in the + source files. You can do this in zlib by predefining the + ZLIB_DLL macro. + + + 6. I see that the ZLIB1.DLL functions use the "C" (CDECL) calling + convention. Why not use the STDCALL convention? + STDCALL is the standard convention in Win32, and I need it in + my Visual Basic project! + + (For readability, we use CDECL to refer to the convention + triggered by the "__cdecl" keyword, STDCALL to refer to + the convention triggered by "__stdcall", and FASTCALL to + refer to the convention triggered by "__fastcall".) + + - Most of the native Windows API functions (without varargs) use + indeed the WINAPI convention (which translates to STDCALL in + Win32), but the standard C functions use CDECL. If a user + application is intrinsically tied to the Windows API (e.g. + it calls native Windows API functions such as CreateFile()), + sometimes it makes sense to decorate its own functions with + WINAPI. But if ANSI C or POSIX portability is a goal (e.g. + it calls standard C functions such as fopen()), it is not a + sound decision to request the inclusion of , or to + use non-ANSI constructs, for the sole purpose to make the user + functions STDCALL-able. + + The functionality offered by zlib is not in the category of + "Windows functionality", but is more like "C functionality". + + Technically, STDCALL is not bad; in fact, it is slightly + faster than CDECL, and it works with variable-argument + functions, just like CDECL. It is unfortunate that, in spite + of using STDCALL in the Windows API, it is not the default + convention used by the C compilers that run under Windows. + The roots of the problem reside deep inside the unsafety of + the K&R-style function prototypes, where the argument types + are not specified; but that is another story for another day. + + The remaining fact is that CDECL is the default convention. + Even if an explicit convention is hard-coded into the function + prototypes inside C headers, problems may appear. The + necessity to expose the convention in users' callbacks is one + of these problems. + + The calling convention issues are also important when using + zlib in other programming languages. Some of them, like Ada + (GNAT) and Fortran (GNU G77), have C bindings implemented + initially on Unix, and relying on the C calling convention. + On the other hand, the pre- .NET versions of Microsoft Visual + Basic require STDCALL, while Borland Delphi prefers, although + it does not require, FASTCALL. + + In fairness to all possible uses of zlib outside the C + programming language, we choose the default "C" convention. + Anyone interested in different bindings or conventions is + encouraged to maintain specialized projects. The "contrib/" + directory from the zlib distribution already holds a couple + of foreign bindings, such as Ada, C++, and Delphi. + + + 7. I need a DLL for my Visual Basic project. What can I do? + + - Define the ZLIB_WINAPI macro before including "zlib.h", when + building both the DLL and the user application (except that + you don't need to define anything when using the DLL in Visual + Basic). The ZLIB_WINAPI macro will switch on the WINAPI + (STDCALL) convention. The name of this DLL must be different + than the official ZLIB1.DLL. + + Gilles Vollant has contributed a build named ZLIBWAPI.DLL, + with the ZLIB_WINAPI macro turned on, and with the minizip + functionality built in. For more information, please read + the notes inside "contrib/vstudio/readme.txt", found in the + zlib distribution. + + + 8. I need to use zlib in my Microsoft .NET project. What can I + do? + + - Henrik Ravn has contributed a .NET wrapper around zlib. Look + into contrib/dotzlib/, inside the zlib distribution. + + + 9. If my application uses ZLIB1.DLL, should I link it to + MSVCRT.DLL? Why? + + - It is not required, but it is recommended to link your + application to MSVCRT.DLL, if it uses ZLIB1.DLL. + + The executables (.EXE, .DLL, etc.) that are involved in the + same process and are using the C run-time library (i.e. they + are calling standard C functions), must link to the same + library. There are several libraries in the Win32 system: + CRTDLL.DLL, MSVCRT.DLL, the static C libraries, etc. + Since ZLIB1.DLL is linked to MSVCRT.DLL, the executables that + depend on it should also be linked to MSVCRT.DLL. + + +10. Why are you saying that ZLIB1.DLL and my application should + be linked to the same C run-time (CRT) library? I linked my + application and my DLLs to different C libraries (e.g. my + application to a static library, and my DLLs to MSVCRT.DLL), + and everything works fine. + + - If a user library invokes only pure Win32 API (accessible via + and the related headers), its DLL build will work + in any context. But if this library invokes standard C API, + things get more complicated. + + There is a single Win32 library in a Win32 system. Every + function in this library resides in a single DLL module, that + is safe to call from anywhere. On the other hand, there are + multiple versions of the C library, and each of them has its + own separate internal state. Standalone executables and user + DLLs that call standard C functions must link to a C run-time + (CRT) library, be it static or shared (DLL). Intermixing + occurs when an executable (not necessarily standalone) and a + DLL are linked to different CRTs, and both are running in the + same process. + + Intermixing multiple CRTs is possible, as long as their + internal states are kept intact. The Microsoft Knowledge Base + articles KB94248 "HOWTO: Use the C Run-Time" and KB140584 + "HOWTO: Link with the Correct C Run-Time (CRT) Library" + mention the potential problems raised by intermixing. + + If intermixing works for you, it's because your application + and DLLs are avoiding the corruption of each of the CRTs' + internal states, maybe by careful design, or maybe by fortune. + + Also note that linking ZLIB1.DLL to non-Microsoft CRTs, such + as those provided by Borland, raises similar problems. + + +11. Why are you linking ZLIB1.DLL to MSVCRT.DLL? + + - MSVCRT.DLL exists on every Windows 95 with a new service pack + installed, or with Microsoft Internet Explorer 4 or later, and + on all other Windows 4.x or later (Windows 98, Windows NT 4, + or later). It is freely distributable; if not present in the + system, it can be downloaded from Microsoft or from other + software provider for free. + + The fact that MSVCRT.DLL does not exist on a virgin Windows 95 + is not so problematic. Windows 95 is scarcely found nowadays, + Microsoft ended its support a long time ago, and many recent + applications from various vendors, including Microsoft, do not + even run on it. Furthermore, no serious user should run + Windows 95 without a proper update installed. + + +12. Why are you not linking ZLIB1.DLL to + <> ? + + - We considered and abandoned the following alternatives: + + * Linking ZLIB1.DLL to a static C library (LIBC.LIB, or + LIBCMT.LIB) is not a good option. People are using the DLL + mainly to save disk space. If you are linking your program + to a static C library, you may as well consider linking zlib + in statically, too. + + * Linking ZLIB1.DLL to CRTDLL.DLL looks appealing, because + CRTDLL.DLL is present on every Win32 installation. + Unfortunately, it has a series of problems: it does not + work properly with Microsoft's C++ libraries, it does not + provide support for 64-bit file offsets, (and so on...), + and Microsoft discontinued its support a long time ago. + + * Linking ZLIB1.DLL to MSVCR70.DLL or MSVCR71.DLL, supplied + with the Microsoft .NET platform, and Visual C++ 7.0/7.1, + raises problems related to the status of ZLIB1.DLL as a + system component. According to the Microsoft Knowledge Base + article KB326922 "INFO: Redistribution of the Shared C + Runtime Component in Visual C++ .NET", MSVCR70.DLL and + MSVCR71.DLL are not supposed to function as system DLLs, + because they may clash with MSVCRT.DLL. Instead, the + application's installer is supposed to put these DLLs + (if needed) in the application's private directory. + If ZLIB1.DLL depends on a non-system runtime, it cannot + function as a redistributable system component. + + * Linking ZLIB1.DLL to non-Microsoft runtimes, such as + Borland's, or Cygwin's, raises problems related to the + reliable presence of these runtimes on Win32 systems. + It's easier to let the DLL build of zlib up to the people + who distribute these runtimes, and who may proceed as + explained in the answer to Question 14. + + +13. If ZLIB1.DLL cannot be linked to MSVCR70.DLL or MSVCR71.DLL, + how can I build/use ZLIB1.DLL in Microsoft Visual C++ 7.0 + (Visual Studio .NET) or newer? + + - Due to the problems explained in the Microsoft Knowledge Base + article KB326922 (see the previous answer), the C runtime that + comes with the VC7 environment is no longer considered a + system component. That is, it should not be assumed that this + runtime exists, or may be installed in a system directory. + Since ZLIB1.DLL is supposed to be a system component, it may + not depend on a non-system component. + + In order to link ZLIB1.DLL and your application to MSVCRT.DLL + in VC7, you need the library of Visual C++ 6.0 or older. If + you don't have this library at hand, it's probably best not to + use ZLIB1.DLL. + + We are hoping that, in the future, Microsoft will provide a + way to build applications linked to a proper system runtime, + from the Visual C++ environment. Until then, you have a + couple of alternatives, such as linking zlib in statically. + If your application requires dynamic linking, you may proceed + as explained in the answer to Question 14. + + +14. I need to link my own DLL build to a CRT different than + MSVCRT.DLL. What can I do? + + - Feel free to rebuild the DLL from the zlib sources, and link + it the way you want. You should, however, clearly state that + your build is unofficial. You should give it a different file + name, and/or install it in a private directory that can be + accessed by your application only, and is not visible to the + others (i.e. it's neither in the PATH, nor in the SYSTEM or + SYSTEM32 directories). Otherwise, your build may clash with + applications that link to the official build. + + For example, in Cygwin, zlib is linked to the Cygwin runtime + CYGWIN1.DLL, and it is distributed under the name CYGZ.DLL. + + +15. May I include additional pieces of code that I find useful, + link them in ZLIB1.DLL, and export them? + + - No. A legitimate build of ZLIB1.DLL must not include code + that does not originate from the official zlib source code. + But you can make your own private DLL build, under a different + file name, as suggested in the previous answer. + + For example, zlib is a part of the VCL library, distributed + with Borland Delphi and C++ Builder. The DLL build of VCL + is a redistributable file, named VCLxx.DLL. + + +16. May I remove some functionality out of ZLIB1.DLL, by enabling + macros like NO_GZCOMPRESS or NO_GZIP at compile time? + + - No. A legitimate build of ZLIB1.DLL must provide the complete + zlib functionality, as implemented in the official zlib source + code. But you can make your own private DLL build, under a + different file name, as suggested in the previous answer. + + +17. I made my own ZLIB1.DLL build. Can I test it for compliance? + + - We prefer that you download the official DLL from the zlib + web site. If you need something peculiar from this DLL, you + can send your suggestion to the zlib mailing list. + + However, in case you do rebuild the DLL yourself, you can run + it with the test programs found in the DLL distribution. + Running these test programs is not a guarantee of compliance, + but a failure can imply a detected problem. + +** + +This document is written and maintained by +Cosmin Truta diff --git a/contrib/zlib/win32/Makefile.bor b/contrib/zlib/win32/Makefile.bor new file mode 100644 index 00000000..d152bbb7 --- /dev/null +++ b/contrib/zlib/win32/Makefile.bor @@ -0,0 +1,110 @@ +# Makefile for zlib +# Borland C++ for Win32 +# +# Usage: +# make -f win32/Makefile.bor +# make -f win32/Makefile.bor LOCAL_ZLIB=-DASMV OBJA=match.obj OBJPA=+match.obj + +# ------------ Borland C++ ------------ + +# Optional nonstandard preprocessor flags (e.g. -DMAX_MEM_LEVEL=7) +# should be added to the environment via "set LOCAL_ZLIB=-DFOO" or +# added to the declaration of LOC here: +LOC = $(LOCAL_ZLIB) + +CC = bcc32 +AS = bcc32 +LD = bcc32 +AR = tlib +CFLAGS = -a -d -k- -O2 $(LOC) +ASFLAGS = $(LOC) +LDFLAGS = $(LOC) + + +# variables +ZLIB_LIB = zlib.lib + +OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzclose.obj gzlib.obj gzread.obj +OBJ2 = gzwrite.obj infback.obj inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj +#OBJA = +OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzclose.obj+gzlib.obj+gzread.obj +OBJP2 = +gzwrite.obj+infback.obj+inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj +#OBJPA= + + +# targets +all: $(ZLIB_LIB) example.exe minigzip.exe + +.c.obj: + $(CC) -c $(CFLAGS) $< + +.asm.obj: + $(AS) -c $(ASFLAGS) $< + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzclose.obj: gzclose.c zlib.h zconf.h gzguts.h + +gzlib.obj: gzlib.c zlib.h zconf.h gzguts.h + +gzread.obj: gzread.c zlib.h zconf.h gzguts.h + +gzwrite.obj: gzwrite.c zlib.h zconf.h gzguts.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: test/example.c zlib.h zconf.h + +minigzip.obj: test/minigzip.c zlib.h zconf.h + + +# For the sake of the old Borland make, +# the command line is cut to fit in the MS-DOS 128 byte limit: +$(ZLIB_LIB): $(OBJ1) $(OBJ2) $(OBJA) + -del $(ZLIB_LIB) + $(AR) $(ZLIB_LIB) $(OBJP1) + $(AR) $(ZLIB_LIB) $(OBJP2) + $(AR) $(ZLIB_LIB) $(OBJPA) + + +# testing +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +example.exe: example.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB) + +minigzip.exe: minigzip.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB) + + +# cleanup +clean: + -del $(ZLIB_LIB) + -del *.obj + -del *.exe + -del *.tds + -del zlib.bak + -del foo.gz diff --git a/contrib/zlib/win32/Makefile.gcc b/contrib/zlib/win32/Makefile.gcc new file mode 100644 index 00000000..305be50a --- /dev/null +++ b/contrib/zlib/win32/Makefile.gcc @@ -0,0 +1,182 @@ +# Makefile for zlib, derived from Makefile.dj2. +# Modified for mingw32 by C. Spieler, 6/16/98. +# Updated for zlib 1.2.x by Christian Spieler and Cosmin Truta, Mar-2003. +# Last updated: Mar 2012. +# Tested under Cygwin and MinGW. + +# Copyright (C) 1995-2003 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile, or to compile and test, type from the top level zlib directory: +# +# make -fwin32/Makefile.gcc; make test testdll -fwin32/Makefile.gcc +# +# To use the asm code, type: +# cp contrib/asm?86/match.S ./match.S +# make LOC=-DASMV OBJA=match.o -fwin32/Makefile.gcc +# +# To install libz.a, zconf.h and zlib.h in the system directories, type: +# +# make install -fwin32/Makefile.gcc +# +# BINARY_PATH, INCLUDE_PATH and LIBRARY_PATH must be set. +# +# To install the shared lib, append SHARED_MODE=1 to the make command : +# +# make install -fwin32/Makefile.gcc SHARED_MODE=1 + +# Note: +# If the platform is *not* MinGW (e.g. it is Cygwin or UWIN), +# the DLL name should be changed from "zlib1.dll". + +STATICLIB = libz.a +SHAREDLIB = zlib1.dll +IMPLIB = libz.dll.a + +# +# Set to 1 if shared object needs to be installed +# +SHARED_MODE=0 + +#LOC = -DASMV +#LOC = -DZLIB_DEBUG -g + +PREFIX = +CC = $(PREFIX)gcc +CFLAGS = $(LOC) -O3 -Wall + +AS = $(CC) +ASFLAGS = $(LOC) -Wall + +LD = $(CC) +LDFLAGS = $(LOC) + +AR = $(PREFIX)ar +ARFLAGS = rcs + +RC = $(PREFIX)windres +RCFLAGS = --define GCC_WINDRES + +STRIP = $(PREFIX)strip + +CP = cp -fp +# If GNU install is available, replace $(CP) with install. +INSTALL = $(CP) +RM = rm -f + +prefix ?= /usr/local +exec_prefix = $(prefix) + +OBJS = adler32.o compress.o crc32.o deflate.o gzclose.o gzlib.o gzread.o \ + gzwrite.o infback.o inffast.o inflate.o inftrees.o trees.o uncompr.o zutil.o +OBJA = + +all: $(STATICLIB) $(SHAREDLIB) $(IMPLIB) example.exe minigzip.exe example_d.exe minigzip_d.exe + +test: example.exe minigzip.exe + ./example + echo hello world | ./minigzip | ./minigzip -d + +testdll: example_d.exe minigzip_d.exe + ./example_d + echo hello world | ./minigzip_d | ./minigzip_d -d + +.c.o: + $(CC) $(CFLAGS) -c -o $@ $< + +.S.o: + $(AS) $(ASFLAGS) -c -o $@ $< + +$(STATICLIB): $(OBJS) $(OBJA) + $(AR) $(ARFLAGS) $@ $(OBJS) $(OBJA) + +$(IMPLIB): $(SHAREDLIB) + +$(SHAREDLIB): win32/zlib.def $(OBJS) $(OBJA) zlibrc.o + $(CC) -shared -Wl,--out-implib,$(IMPLIB) $(LDFLAGS) \ + -o $@ win32/zlib.def $(OBJS) $(OBJA) zlibrc.o + $(STRIP) $@ + +example.exe: example.o $(STATICLIB) + $(LD) $(LDFLAGS) -o $@ example.o $(STATICLIB) + $(STRIP) $@ + +minigzip.exe: minigzip.o $(STATICLIB) + $(LD) $(LDFLAGS) -o $@ minigzip.o $(STATICLIB) + $(STRIP) $@ + +example_d.exe: example.o $(IMPLIB) + $(LD) $(LDFLAGS) -o $@ example.o $(IMPLIB) + $(STRIP) $@ + +minigzip_d.exe: minigzip.o $(IMPLIB) + $(LD) $(LDFLAGS) -o $@ minigzip.o $(IMPLIB) + $(STRIP) $@ + +example.o: test/example.c zlib.h zconf.h + $(CC) $(CFLAGS) -I. -c -o $@ test/example.c + +minigzip.o: test/minigzip.c zlib.h zconf.h + $(CC) $(CFLAGS) -I. -c -o $@ test/minigzip.c + +zlibrc.o: win32/zlib1.rc + $(RC) $(RCFLAGS) -o $@ win32/zlib1.rc + +.PHONY: install uninstall clean + +install: zlib.h zconf.h $(STATICLIB) $(IMPLIB) + @if test -z "$(DESTDIR)$(INCLUDE_PATH)" -o -z "$(DESTDIR)$(LIBRARY_PATH)" -o -z "$(DESTDIR)$(BINARY_PATH)"; then \ + echo INCLUDE_PATH, LIBRARY_PATH, and BINARY_PATH must be specified; \ + exit 1; \ + fi + -@mkdir -p '$(DESTDIR)$(INCLUDE_PATH)' + -@mkdir -p '$(DESTDIR)$(LIBRARY_PATH)' '$(DESTDIR)$(LIBRARY_PATH)'/pkgconfig + -if [ "$(SHARED_MODE)" = "1" ]; then \ + mkdir -p '$(DESTDIR)$(BINARY_PATH)'; \ + $(INSTALL) $(SHAREDLIB) '$(DESTDIR)$(BINARY_PATH)'; \ + $(INSTALL) $(IMPLIB) '$(DESTDIR)$(LIBRARY_PATH)'; \ + fi + -$(INSTALL) zlib.h '$(DESTDIR)$(INCLUDE_PATH)' + -$(INSTALL) zconf.h '$(DESTDIR)$(INCLUDE_PATH)' + -$(INSTALL) $(STATICLIB) '$(DESTDIR)$(LIBRARY_PATH)' + sed \ + -e 's|@prefix@|${prefix}|g' \ + -e 's|@exec_prefix@|${exec_prefix}|g' \ + -e 's|@libdir@|$(LIBRARY_PATH)|g' \ + -e 's|@sharedlibdir@|$(LIBRARY_PATH)|g' \ + -e 's|@includedir@|$(INCLUDE_PATH)|g' \ + -e 's|@VERSION@|'`sed -n -e '/VERSION "/s/.*"\(.*\)".*/\1/p' zlib.h`'|g' \ + zlib.pc.in > '$(DESTDIR)$(LIBRARY_PATH)'/pkgconfig/zlib.pc + +uninstall: + -if [ "$(SHARED_MODE)" = "1" ]; then \ + $(RM) '$(DESTDIR)$(BINARY_PATH)'/$(SHAREDLIB); \ + $(RM) '$(DESTDIR)$(LIBRARY_PATH)'/$(IMPLIB); \ + fi + -$(RM) '$(DESTDIR)$(INCLUDE_PATH)'/zlib.h + -$(RM) '$(DESTDIR)$(INCLUDE_PATH)'/zconf.h + -$(RM) '$(DESTDIR)$(LIBRARY_PATH)'/$(STATICLIB) + +clean: + -$(RM) $(STATICLIB) + -$(RM) $(SHAREDLIB) + -$(RM) $(IMPLIB) + -$(RM) *.o + -$(RM) *.exe + -$(RM) foo.gz + +adler32.o: zlib.h zconf.h +compress.o: zlib.h zconf.h +crc32.o: crc32.h zlib.h zconf.h +deflate.o: deflate.h zutil.h zlib.h zconf.h +gzclose.o: zlib.h zconf.h gzguts.h +gzlib.o: zlib.h zconf.h gzguts.h +gzread.o: zlib.h zconf.h gzguts.h +gzwrite.o: zlib.h zconf.h gzguts.h +inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inftrees.o: zutil.h zlib.h zconf.h inftrees.h +trees.o: deflate.h zutil.h zlib.h zconf.h trees.h +uncompr.o: zlib.h zconf.h +zutil.o: zutil.h zlib.h zconf.h diff --git a/contrib/zlib/win32/Makefile.msc b/contrib/zlib/win32/Makefile.msc new file mode 100644 index 00000000..6831882d --- /dev/null +++ b/contrib/zlib/win32/Makefile.msc @@ -0,0 +1,163 @@ +# Makefile for zlib using Microsoft (Visual) C +# zlib is copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler +# +# Usage: +# nmake -f win32/Makefile.msc (standard build) +# nmake -f win32/Makefile.msc LOC=-DFOO (nonstandard build) +# nmake -f win32/Makefile.msc LOC="-DASMV -DASMINF" \ +# OBJA="inffas32.obj match686.obj" (use ASM code, x86) +# nmake -f win32/Makefile.msc AS=ml64 LOC="-DASMV -DASMINF -I." \ +# OBJA="inffasx64.obj gvmat64.obj inffas8664.obj" (use ASM code, x64) + +# The toplevel directory of the source tree. +# +TOP = . + +# optional build flags +LOC = + +# variables +STATICLIB = zlib.lib +SHAREDLIB = zlib1.dll +IMPLIB = zdll.lib + +CC = cl +AS = ml +LD = link +AR = lib +RC = rc +CFLAGS = -nologo -MD -W3 -O2 -Oy- -Zi -Fd"zlib" $(LOC) +WFLAGS = -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE +ASFLAGS = -coff -Zi $(LOC) +LDFLAGS = -nologo -debug -incremental:no -opt:ref +ARFLAGS = -nologo +RCFLAGS = /dWIN32 /r + +OBJS = adler32.obj compress.obj crc32.obj deflate.obj gzclose.obj gzlib.obj gzread.obj \ + gzwrite.obj infback.obj inflate.obj inftrees.obj inffast.obj trees.obj uncompr.obj zutil.obj +OBJA = + + +# targets +all: $(STATICLIB) $(SHAREDLIB) $(IMPLIB) \ + example.exe minigzip.exe example_d.exe minigzip_d.exe + +$(STATICLIB): $(OBJS) $(OBJA) + $(AR) $(ARFLAGS) -out:$@ $(OBJS) $(OBJA) + +$(IMPLIB): $(SHAREDLIB) + +$(SHAREDLIB): $(TOP)/win32/zlib.def $(OBJS) $(OBJA) zlib1.res + $(LD) $(LDFLAGS) -def:$(TOP)/win32/zlib.def -dll -implib:$(IMPLIB) \ + -out:$@ -base:0x5A4C0000 $(OBJS) $(OBJA) zlib1.res + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;2 + +example.exe: example.obj $(STATICLIB) + $(LD) $(LDFLAGS) example.obj $(STATICLIB) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +minigzip.exe: minigzip.obj $(STATICLIB) + $(LD) $(LDFLAGS) minigzip.obj $(STATICLIB) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +example_d.exe: example.obj $(IMPLIB) + $(LD) $(LDFLAGS) -out:$@ example.obj $(IMPLIB) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +minigzip_d.exe: minigzip.obj $(IMPLIB) + $(LD) $(LDFLAGS) -out:$@ minigzip.obj $(IMPLIB) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +{$(TOP)}.c.obj: + $(CC) -c $(WFLAGS) $(CFLAGS) $< + +{$(TOP)/test}.c.obj: + $(CC) -c -I$(TOP) $(WFLAGS) $(CFLAGS) $< + +{$(TOP)/contrib/masmx64}.c.obj: + $(CC) -c $(WFLAGS) $(CFLAGS) $< + +{$(TOP)/contrib/masmx64}.asm.obj: + $(AS) -c $(ASFLAGS) $< + +{$(TOP)/contrib/masmx86}.asm.obj: + $(AS) -c $(ASFLAGS) $< + +adler32.obj: $(TOP)/adler32.c $(TOP)/zlib.h $(TOP)/zconf.h + +compress.obj: $(TOP)/compress.c $(TOP)/zlib.h $(TOP)/zconf.h + +crc32.obj: $(TOP)/crc32.c $(TOP)/zlib.h $(TOP)/zconf.h $(TOP)/crc32.h + +deflate.obj: $(TOP)/deflate.c $(TOP)/deflate.h $(TOP)/zutil.h $(TOP)/zlib.h $(TOP)/zconf.h + +gzclose.obj: $(TOP)/gzclose.c $(TOP)/zlib.h $(TOP)/zconf.h $(TOP)/gzguts.h + +gzlib.obj: $(TOP)/gzlib.c $(TOP)/zlib.h $(TOP)/zconf.h $(TOP)/gzguts.h + +gzread.obj: $(TOP)/gzread.c $(TOP)/zlib.h $(TOP)/zconf.h $(TOP)/gzguts.h + +gzwrite.obj: $(TOP)/gzwrite.c $(TOP)/zlib.h $(TOP)/zconf.h $(TOP)/gzguts.h + +infback.obj: $(TOP)/infback.c $(TOP)/zutil.h $(TOP)/zlib.h $(TOP)/zconf.h $(TOP)/inftrees.h $(TOP)/inflate.h \ + $(TOP)/inffast.h $(TOP)/inffixed.h + +inffast.obj: $(TOP)/inffast.c $(TOP)/zutil.h $(TOP)/zlib.h $(TOP)/zconf.h $(TOP)/inftrees.h $(TOP)/inflate.h \ + $(TOP)/inffast.h + +inflate.obj: $(TOP)/inflate.c $(TOP)/zutil.h $(TOP)/zlib.h $(TOP)/zconf.h $(TOP)/inftrees.h $(TOP)/inflate.h \ + $(TOP)/inffast.h $(TOP)/inffixed.h + +inftrees.obj: $(TOP)/inftrees.c $(TOP)/zutil.h $(TOP)/zlib.h $(TOP)/zconf.h $(TOP)/inftrees.h + +trees.obj: $(TOP)/trees.c $(TOP)/zutil.h $(TOP)/zlib.h $(TOP)/zconf.h $(TOP)/deflate.h $(TOP)/trees.h + +uncompr.obj: $(TOP)/uncompr.c $(TOP)/zlib.h $(TOP)/zconf.h + +zutil.obj: $(TOP)/zutil.c $(TOP)/zutil.h $(TOP)/zlib.h $(TOP)/zconf.h + +gvmat64.obj: $(TOP)/contrib\masmx64\gvmat64.asm + +inffasx64.obj: $(TOP)/contrib\masmx64\inffasx64.asm + +inffas8664.obj: $(TOP)/contrib\masmx64\inffas8664.c $(TOP)/zutil.h $(TOP)/zlib.h $(TOP)/zconf.h \ + $(TOP)/inftrees.h $(TOP)/inflate.h $(TOP)/inffast.h + +inffas32.obj: $(TOP)/contrib\masmx86\inffas32.asm + +match686.obj: $(TOP)/contrib\masmx86\match686.asm + +example.obj: $(TOP)/test/example.c $(TOP)/zlib.h $(TOP)/zconf.h + +minigzip.obj: $(TOP)/test/minigzip.c $(TOP)/zlib.h $(TOP)/zconf.h + +zlib1.res: $(TOP)/win32/zlib1.rc + $(RC) $(RCFLAGS) /fo$@ $(TOP)/win32/zlib1.rc + +# testing +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +testdll: example_d.exe minigzip_d.exe + example_d + echo hello world | minigzip_d | minigzip_d -d + + +# cleanup +clean: + -del $(STATICLIB) + -del $(SHAREDLIB) + -del $(IMPLIB) + -del *.obj + -del *.res + -del *.exp + -del *.exe + -del *.pdb + -del *.manifest + -del foo.gz diff --git a/contrib/zlib/win32/README-WIN32.txt b/contrib/zlib/win32/README-WIN32.txt new file mode 100644 index 00000000..df7ab7f4 --- /dev/null +++ b/contrib/zlib/win32/README-WIN32.txt @@ -0,0 +1,103 @@ +ZLIB DATA COMPRESSION LIBRARY + +zlib 1.2.11 is a general purpose data compression library. All the code is +thread safe. The data format used by the zlib library is described by RFCs +(Request for Comments) 1950 to 1952 in the files +http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) +and rfc1952.txt (gzip format). + +All functions of the compression library are documented in the file zlib.h +(volunteer to write man pages welcome, contact zlib@gzip.org). Two compiled +examples are distributed in this package, example and minigzip. The example_d +and minigzip_d flavors validate that the zlib1.dll file is working correctly. + +Questions about zlib should be sent to . The zlib home page +is http://zlib.net/ . Before reporting a problem, please check this site to +verify that you have the latest version of zlib; otherwise get the latest +version and check whether the problem still exists or not. + +PLEASE read DLL_FAQ.txt, and the the zlib FAQ http://zlib.net/zlib_faq.html +before asking for help. + + +Manifest: + +The package zlib-1.2.11-win32-x86.zip will contain the following files: + + README-WIN32.txt This document + ChangeLog Changes since previous zlib packages + DLL_FAQ.txt Frequently asked questions about zlib1.dll + zlib.3.pdf Documentation of this library in Adobe Acrobat format + + example.exe A statically-bound example (using zlib.lib, not the dll) + example.pdb Symbolic information for debugging example.exe + + example_d.exe A zlib1.dll bound example (using zdll.lib) + example_d.pdb Symbolic information for debugging example_d.exe + + minigzip.exe A statically-bound test program (using zlib.lib, not the dll) + minigzip.pdb Symbolic information for debugging minigzip.exe + + minigzip_d.exe A zlib1.dll bound test program (using zdll.lib) + minigzip_d.pdb Symbolic information for debugging minigzip_d.exe + + zlib.h Install these files into the compilers' INCLUDE path to + zconf.h compile programs which use zlib.lib or zdll.lib + + zdll.lib Install these files into the compilers' LIB path if linking + zdll.exp a compiled program to the zlib1.dll binary + + zlib.lib Install these files into the compilers' LIB path to link zlib + zlib.pdb into compiled programs, without zlib1.dll runtime dependency + (zlib.pdb provides debugging info to the compile time linker) + + zlib1.dll Install this binary shared library into the system PATH, or + the program's runtime directory (where the .exe resides) + zlib1.pdb Install in the same directory as zlib1.dll, in order to debug + an application crash using WinDbg or similar tools. + +All .pdb files above are entirely optional, but are very useful to a developer +attempting to diagnose program misbehavior or a crash. Many additional +important files for developers can be found in the zlib127.zip source package +available from http://zlib.net/ - review that package's README file for details. + + +Acknowledgments: + +The deflate format used by zlib was defined by Phil Katz. The deflate and +zlib specifications were written by L. Peter Deutsch. Thanks to all the +people who reported problems and suggested various improvements in zlib; they +are too numerous to cite here. + + +Copyright notice: + + (C) 1995-2017 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* receiving +lengthy legal documents to sign. The sources are provided for free but without +warranty of any kind. The library has been entirely written by Jean-loup +Gailly and Mark Adler; it does not include third-party code. + +If you redistribute modified sources, we would appreciate that you include in +the file ChangeLog history information documenting your changes. Please read +the FAQ for more information on the distribution of modified source versions. diff --git a/contrib/zlib/win32/VisualC.txt b/contrib/zlib/win32/VisualC.txt new file mode 100644 index 00000000..1005b219 --- /dev/null +++ b/contrib/zlib/win32/VisualC.txt @@ -0,0 +1,3 @@ + +To build zlib using the Microsoft Visual C++ environment, +use the appropriate project from the contrib/vstudio/ directory. diff --git a/contrib/zlib/win32/zlib.def b/contrib/zlib/win32/zlib.def new file mode 100644 index 00000000..a2188b00 --- /dev/null +++ b/contrib/zlib/win32/zlib.def @@ -0,0 +1,94 @@ +; zlib data compression library +EXPORTS +; basic functions + zlibVersion + deflate + deflateEnd + inflate + inflateEnd +; advanced functions + deflateSetDictionary + deflateGetDictionary + deflateCopy + deflateReset + deflateParams + deflateTune + deflateBound + deflatePending + deflatePrime + deflateSetHeader + inflateSetDictionary + inflateGetDictionary + inflateSync + inflateCopy + inflateReset + inflateReset2 + inflatePrime + inflateMark + inflateGetHeader + inflateBack + inflateBackEnd + zlibCompileFlags +; utility functions + compress + compress2 + compressBound + uncompress + uncompress2 + gzopen + gzdopen + gzbuffer + gzsetparams + gzread + gzfread + gzwrite + gzfwrite + gzprintf + gzvprintf + gzputs + gzgets + gzputc + gzgetc + gzungetc + gzflush + gzseek + gzrewind + gztell + gzoffset + gzeof + gzdirect + gzclose + gzclose_r + gzclose_w + gzerror + gzclearerr +; large file functions + gzopen64 + gzseek64 + gztell64 + gzoffset64 + adler32_combine64 + crc32_combine64 +; checksum functions + adler32 + adler32_z + crc32 + crc32_z + adler32_combine + crc32_combine +; various hacks, don't look :) + deflateInit_ + deflateInit2_ + inflateInit_ + inflateInit2_ + inflateBackInit_ + gzgetc_ + zError + inflateSyncPoint + get_crc_table + inflateUndermine + inflateValidate + inflateCodesUsed + inflateResetKeep + deflateResetKeep + gzopen_w diff --git a/contrib/zlib/win32/zlib1.rc b/contrib/zlib/win32/zlib1.rc new file mode 100644 index 00000000..234e641c --- /dev/null +++ b/contrib/zlib/win32/zlib1.rc @@ -0,0 +1,40 @@ +#include +#include "../zlib.h" + +#ifdef GCC_WINDRES +VS_VERSION_INFO VERSIONINFO +#else +VS_VERSION_INFO VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE +#endif + FILEVERSION ZLIB_VER_MAJOR,ZLIB_VER_MINOR,ZLIB_VER_REVISION,0 + PRODUCTVERSION ZLIB_VER_MAJOR,ZLIB_VER_MINOR,ZLIB_VER_REVISION,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS 1 +#else + FILEFLAGS 0 +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0 // not used +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + //language ID = U.S. English, char set = Windows, Multilingual + BEGIN + VALUE "FileDescription", "zlib data compression library\0" + VALUE "FileVersion", ZLIB_VERSION "\0" + VALUE "InternalName", "zlib1.dll\0" + VALUE "LegalCopyright", "(C) 1995-2017 Jean-loup Gailly & Mark Adler\0" + VALUE "OriginalFilename", "zlib1.dll\0" + VALUE "ProductName", "zlib\0" + VALUE "ProductVersion", ZLIB_VERSION "\0" + VALUE "Comments", "For more information visit http://www.zlib.net/\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1252 + END +END diff --git a/contrib/zlib/zconf.h.cmakein b/contrib/zlib/zconf.h.cmakein new file mode 100644 index 00000000..a7f24cce --- /dev/null +++ b/contrib/zlib/zconf.h.cmakein @@ -0,0 +1,536 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H +#cmakedefine Z_PREFIX +#cmakedefine Z_HAVE_UNISTD_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ +# define Z_PREFIX_SET + +/* all linked symbols and init macros */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_bits z__tr_flush_bits +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# define adler32_z z_adler32_z +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define crc32_z z_crc32_z +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateGetDictionary z_deflateGetDictionary +# define deflateInit z_deflateInit +# define deflateInit2 z_deflateInit2 +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePending z_deflatePending +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# ifndef Z_SOLO +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzfread z_gzfread +# define gzfwrite z_gzfwrite +# define gzgetc z_gzgetc +# define gzgetc_ z_gzgetc_ +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# ifdef _WIN32 +# define gzopen_w z_gzopen_w +# endif +# define gzprintf z_gzprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzvprintf z_gzvprintf +# define gzwrite z_gzwrite +# endif +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit z_inflateBackInit +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCodesUsed z_inflateCodesUsed +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetDictionary z_inflateGetDictionary +# define inflateGetHeader z_inflateGetHeader +# define inflateInit z_inflateInit +# define inflateInit2 z_inflateInit2 +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateResetKeep z_inflateResetKeep +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflateValidate z_inflateValidate +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# ifndef Z_SOLO +# define uncompress z_uncompress +# define uncompress2 z_uncompress2 +# endif +# define zError z_zError +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# ifndef Z_SOLO +# define gzFile z_gzFile +# endif +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + +#ifdef Z_SOLO + typedef unsigned long z_size_t; +#else +# define z_longlong long long +# if defined(NO_SIZE_T) + typedef unsigned NO_SIZE_T z_size_t; +# elif defined(STDC) +# include + typedef size_t z_size_t; +# else + typedef unsigned long z_size_t; +# endif +# undef z_longlong +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus about 7 kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +#ifndef Z_ARG /* function prototypes for stdarg */ +# if defined(STDC) || defined(Z_HAVE_STDARG_H) +# define Z_ARG(args) args +# else +# define Z_ARG(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# elif (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# elif (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short +# endif +#endif + +#ifdef Z_U4 + typedef Z_U4 z_crc_t; +#else + typedef unsigned long z_crc_t; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + +#ifdef STDC +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#endif + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +# include /* for va_list */ +# endif +#endif + +#ifdef _WIN32 +# ifndef Z_SOLO +# include /* for wchar_t */ +# endif +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) +# define Z_HAVE_UNISTD_H +#endif +#ifndef Z_SOLO +# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && !defined(Z_SOLO) +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/contrib/zlib/zconf.h.in b/contrib/zlib/zconf.h.in new file mode 100644 index 00000000..5e1d68a0 --- /dev/null +++ b/contrib/zlib/zconf.h.in @@ -0,0 +1,534 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ +# define Z_PREFIX_SET + +/* all linked symbols and init macros */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_bits z__tr_flush_bits +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# define adler32_z z_adler32_z +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define crc32_z z_crc32_z +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateGetDictionary z_deflateGetDictionary +# define deflateInit z_deflateInit +# define deflateInit2 z_deflateInit2 +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePending z_deflatePending +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# ifndef Z_SOLO +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzfread z_gzfread +# define gzfwrite z_gzfwrite +# define gzgetc z_gzgetc +# define gzgetc_ z_gzgetc_ +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# ifdef _WIN32 +# define gzopen_w z_gzopen_w +# endif +# define gzprintf z_gzprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzvprintf z_gzvprintf +# define gzwrite z_gzwrite +# endif +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit z_inflateBackInit +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCodesUsed z_inflateCodesUsed +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetDictionary z_inflateGetDictionary +# define inflateGetHeader z_inflateGetHeader +# define inflateInit z_inflateInit +# define inflateInit2 z_inflateInit2 +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateResetKeep z_inflateResetKeep +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflateValidate z_inflateValidate +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# ifndef Z_SOLO +# define uncompress z_uncompress +# define uncompress2 z_uncompress2 +# endif +# define zError z_zError +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# ifndef Z_SOLO +# define gzFile z_gzFile +# endif +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + +#ifdef Z_SOLO + typedef unsigned long z_size_t; +#else +# define z_longlong long long +# if defined(NO_SIZE_T) + typedef unsigned NO_SIZE_T z_size_t; +# elif defined(STDC) +# include + typedef size_t z_size_t; +# else + typedef unsigned long z_size_t; +# endif +# undef z_longlong +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus about 7 kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +#ifndef Z_ARG /* function prototypes for stdarg */ +# if defined(STDC) || defined(Z_HAVE_STDARG_H) +# define Z_ARG(args) args +# else +# define Z_ARG(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# elif (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# elif (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short +# endif +#endif + +#ifdef Z_U4 + typedef Z_U4 z_crc_t; +#else + typedef unsigned long z_crc_t; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + +#ifdef STDC +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#endif + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +# include /* for va_list */ +# endif +#endif + +#ifdef _WIN32 +# ifndef Z_SOLO +# include /* for wchar_t */ +# endif +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) +# define Z_HAVE_UNISTD_H +#endif +#ifndef Z_SOLO +# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && !defined(Z_SOLO) +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/contrib/zlib/zlib.3 b/contrib/zlib/zlib.3 new file mode 100644 index 00000000..bda4eb07 --- /dev/null +++ b/contrib/zlib/zlib.3 @@ -0,0 +1,149 @@ +.TH ZLIB 3 "15 Jan 2017" +.SH NAME +zlib \- compression/decompression library +.SH SYNOPSIS +[see +.I zlib.h +for full description] +.SH DESCRIPTION +The +.I zlib +library is a general purpose data compression library. +The code is thread safe, assuming that the standard library functions +used are thread safe, such as memory allocation routines. +It provides in-memory compression and decompression functions, +including integrity checks of the uncompressed data. +This version of the library supports only one compression method (deflation) +but other algorithms may be added later +with the same stream interface. +.LP +Compression can be done in a single step if the buffers are large enough +or can be done by repeated calls of the compression function. +In the latter case, +the application must provide more input and/or consume the output +(providing more output space) before each call. +.LP +The library also supports reading and writing files in +.IR gzip (1) +(.gz) format +with an interface similar to that of stdio. +.LP +The library does not install any signal handler. +The decoder checks the consistency of the compressed data, +so the library should never crash even in the case of corrupted input. +.LP +All functions of the compression library are documented in the file +.IR zlib.h . +The distribution source includes examples of use of the library +in the files +.I test/example.c +and +.IR test/minigzip.c, +as well as other examples in the +.IR examples/ +directory. +.LP +Changes to this version are documented in the file +.I ChangeLog +that accompanies the source. +.LP +.I zlib +is built in to many languages and operating systems, including but not limited to +Java, Python, .NET, PHP, Perl, Ruby, Swift, and Go. +.LP +An experimental package to read and write files in the .zip format, +written on top of +.I zlib +by Gilles Vollant (info@winimage.com), +is available at: +.IP +http://www.winimage.com/zLibDll/minizip.html +and also in the +.I contrib/minizip +directory of the main +.I zlib +source distribution. +.SH "SEE ALSO" +The +.I zlib +web site can be found at: +.IP +http://zlib.net/ +.LP +The data format used by the +.I zlib +library is described by RFC +(Request for Comments) 1950 to 1952 in the files: +.IP +http://tools.ietf.org/html/rfc1950 (for the zlib header and trailer format) +.br +http://tools.ietf.org/html/rfc1951 (for the deflate compressed data format) +.br +http://tools.ietf.org/html/rfc1952 (for the gzip header and trailer format) +.LP +Mark Nelson wrote an article about +.I zlib +for the Jan. 1997 issue of Dr. Dobb's Journal; +a copy of the article is available at: +.IP +http://marknelson.us/1997/01/01/zlib-engine/ +.SH "REPORTING PROBLEMS" +Before reporting a problem, +please check the +.I zlib +web site to verify that you have the latest version of +.IR zlib ; +otherwise, +obtain the latest version and see if the problem still exists. +Please read the +.I zlib +FAQ at: +.IP +http://zlib.net/zlib_faq.html +.LP +before asking for help. +Send questions and/or comments to zlib@gzip.org, +or (for the Windows DLL version) to Gilles Vollant (info@winimage.com). +.SH AUTHORS AND LICENSE +Version 1.2.11 +.LP +Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler +.LP +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. +.LP +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: +.LP +.nr step 1 1 +.IP \n[step]. 3 +The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. +.IP \n+[step]. +Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. +.IP \n+[step]. +This notice may not be removed or altered from any source distribution. +.LP +Jean-loup Gailly Mark Adler +.br +jloup@gzip.org madler@alumni.caltech.edu +.LP +The deflate format used by +.I zlib +was defined by Phil Katz. +The deflate and +.I zlib +specifications were written by L. Peter Deutsch. +Thanks to all the people who reported problems and suggested various +improvements in +.IR zlib ; +who are too numerous to cite here. +.LP +UNIX manual page by R. P. C. Rodgers, +U.S. National Library of Medicine (rodgers@nlm.nih.gov). +.\" end of man page diff --git a/contrib/zlib/zlib.3.pdf b/contrib/zlib/zlib.3.pdf new file mode 100644 index 00000000..6fa519c5 Binary files /dev/null and b/contrib/zlib/zlib.3.pdf differ diff --git a/contrib/zlib/zlib.h b/contrib/zlib/zlib.h new file mode 100644 index 00000000..f09cdaf1 --- /dev/null +++ b/contrib/zlib/zlib.h @@ -0,0 +1,1912 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.11, January 15th, 2017 + + Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.11" +#define ZLIB_VERNUM 0x12b0 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 2 +#define ZLIB_VER_REVISION 11 +#define ZLIB_VER_SUBREVISION 0 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed data. + This version of the library supports only one compression method (deflation) + but other algorithms will be added later and will have the same stream + interface. + + Compression can be done in a single step if the buffers are large enough, + or can be done by repeated calls of the compression function. In the latter + case, the application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip and raw deflate streams in + memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never crash + even in the case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + z_const Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total number of input bytes read so far */ + + Bytef *next_out; /* next output byte will go here */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total number of bytes output so far */ + + z_const char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text + for deflate, or the decoding state for inflate */ + uLong adler; /* Adler-32 or CRC-32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. In that case, zlib is thread-safe. When zalloc and zfree are + Z_NULL on entry to the initialization function, they are set to internal + routines that use the standard library functions malloc() and free(). + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this if + the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers + returned by zalloc for objects of exactly 65536 bytes *must* have their + offset normalized to zero. The default allocation function provided by this + library ensures this (see zutil.c). To reduce memory requirements and avoid + any allocation of 64K objects, at the expense of compression ratio, compile + the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use by the decompressor (particularly + if the decompressor wants to decompress everything in a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field for deflate() */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is not + compatible with the zlib.h header file used by the application. This check + is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at all + (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION + requests a default compromise between speed and compression (currently + equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if level is not a valid compression level, or + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). msg is set to null + if there is no error message. deflateInit does not perform any compression: + this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Generate more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary. Some output may be provided even if + flush is zero. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating avail_in or avail_out accordingly; avail_out should + never be zero before the call. The application can consume the compressed + output when it wants, for example when the output buffer is full (avail_out + == 0), or after each call of deflate(). If deflate returns Z_OK and with + zero avail_out, it must be called again after making room in the output + buffer because there might be more output pending. See deflatePending(), + which can be used if desired to determine whether or not there is more ouput + in that case. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumulate before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In + particular avail_in is zero after the call if enough output space has been + provided before the call.) Flushing may degrade compression for some + compression algorithms and so it should be used only when necessary. This + completes the current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed by four bytes + (00 00 ff ff). + + If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the + output buffer, but the output is not aligned to a byte boundary. All of the + input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + This completes the current deflate block and follows it with an empty fixed + codes block that is 10 bits long. This assures that enough bytes are output + in order for the decompressor to finish the block before the empty fixed + codes block. + + If flush is set to Z_BLOCK, a deflate block is completed and emitted, as + for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to + seven bits of the current block are held to be written as the next byte after + the next deflate block is completed. In this case, the decompressor may not + be provided enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait for the next + block to be emitted. This is for advanced applications that need to control + the emission of deflate blocks. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there was + enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this + function must be called again with Z_FINISH and more output space (updated + avail_out) but no more input data, until it returns with Z_STREAM_END or an + error. After deflate has returned Z_STREAM_END, the only possible operations + on the stream are deflateReset or deflateEnd. + + Z_FINISH can be used in the first deflate call after deflateInit if all the + compression is to be done in a single step. In order to complete in one + call, avail_out must be at least the value returned by deflateBound (see + below). Then deflate is guaranteed to return Z_STREAM_END. If not enough + output space is provided, deflate will not return Z_STREAM_END, and it must + be called again as described above. + + deflate() sets strm->adler to the Adler-32 checksum of all input read + so far (that is, total_in bytes). If a gzip stream is being generated, then + strm->adler will be the CRC-32 checksum of the input read so far. (See + deflateInit2 below.) + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). If in doubt, the data is + considered binary. This field is only for information purposes and does not + affect the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was Z_NULL or the state was inadvertently written over + by the application), or Z_BUF_ERROR if no progress is possible (for example + avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and + deflate() can be called again with more input and more output space to + continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, msg + may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. In the current version of inflate, the provided input is not + read or consumed. The allocation of a sliding window will be deferred to + the first call of inflate (if the decompression does not complete on the + first call). If zalloc and zfree are set to Z_NULL, inflateInit updates + them to use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit does not perform any decompression. + Actual decompression will be done by inflate(). So next_in, and avail_in, + next_out, and avail_out are unused and unchanged. The current + implementation of inflateInit() does not process any header information -- + that is deferred until inflate() is called. +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), then next_in and avail_in are updated + accordingly, and processing will resume at this point for the next call of + inflate(). + + - Generate more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there is + no more input data or no more space in the output buffer (see below about + the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating the next_* and avail_* values accordingly. If the + caller of inflate() does not provide both available input and available + output space, it is possible that there will be no progress made. The + application can consume the uncompressed output when it wants, for example + when the output buffer is full (avail_out == 0), or after each call of + inflate(). If inflate returns Z_OK and with zero avail_out, it must be + called again after making room in the output buffer because there might be + more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, + Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() + stop if and when it gets to the next deflate block boundary. When decoding + the zlib or gzip format, this will cause inflate() to return immediately + after the header and before the first block. When doing a raw inflate, + inflate() will go ahead and process the first block, and will return when it + gets to the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + To assist in this, on return inflate() always sets strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 if + inflate() is currently decoding the last block in the deflate stream, plus + 128 if inflate() returned immediately after decoding an end-of-block code or + decoding the complete header up to just before the first byte of the deflate + stream. The end-of-block will not be indicated until all of the uncompressed + data from that block has been written to strm->next_out. The number of + unused bits may in general be greater than seven, except when bit 7 of + data_type is set, in which case the number of unused bits will be less than + eight. data_type is set as noted here every time inflate() returns for all + flush options, and so can be used to determine the amount of currently + consumed input in bits. + + The Z_TREES option behaves as Z_BLOCK does, but it also returns when the + end of each deflate block header is reached, before any actual data in that + block is decoded. This allows the caller to determine the length of the + deflate block header for later use in random access within a deflate block. + 256 is added to the value of strm->data_type when inflate() returns + immediately after reaching the end of the deflate block header. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step (a + single call of inflate), the parameter flush should be set to Z_FINISH. In + this case all pending input is processed and all pending output is flushed; + avail_out must be large enough to hold all of the uncompressed data for the + operation to complete. (The size of the uncompressed data may have been + saved by the compressor for this purpose.) The use of Z_FINISH is not + required to perform an inflation in one step. However it may be used to + inform inflate that a faster approach can be used for the single inflate() + call. Z_FINISH also informs inflate to not maintain a sliding window if the + stream completes, which reduces inflate's memory footprint. If the stream + does not complete, either because not all of the stream is provided or not + enough output space is provided, then a sliding window will be allocated and + inflate() can be called again to continue the operation as if Z_NO_FLUSH had + been used. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the effects of the flush parameter in this implementation are + on the return value of inflate() as noted below, when inflate() returns early + when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of + memory for a sliding window when Z_FINISH is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the Adler-32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the Adler-32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed Adler-32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() can decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically, if requested when + initializing with inflateInit2(). Any information contained in the gzip + header is not retained unless inflateGetHeader() is used. When processing + gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output + produced so far. The CRC-32 is checked against the gzip trailer, as is the + uncompressed length, modulo 2^32. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value, in which case strm->msg points to a string with a more specific + error), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was Z_NULL, or the state was inadvertently written over + by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR + if no progress was possible or if there was not enough room in the output + buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may + then call inflateSync() to look for a good compression block if a partial + recovery of the data is to be attempted. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state + was inconsistent. +*/ + + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by the + caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + For the current implementation of deflate(), a windowBits value of 8 (a + window size of 256 bytes) is not supported. As a result, a request for 8 + will result in 9 (a 512-byte window). In that case, providing 8 to + inflateInit2() will result in an error when the zlib header with 9 is + checked against the initialization of inflate(). The remedy is to not use 8 + with deflateInit2() with this initialization, or at least in that case use 9 + with inflateInit2(). + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute a check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), no + header crc, and the operating system will be set to the appropriate value, + if the operating system was determined at compile time. If a gzip stream is + being written, strm->adler is a CRC-32 instead of an Adler-32. + + For raw deflate or gzip encoding, a request for a 256-byte window is + rejected as invalid, since only the zlib header provides a means of + transmitting the window size to the decompressor. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. The default value is 8. See zconf.h for total memory usage + as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as + fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The + strategy parameter only affects the compression ratio but not the + correctness of the compressed output even if it is not set appropriately. + Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler + decoder for special applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid + method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is + incompatible with the version assumed by the caller (ZLIB_VERSION). msg is + set to null if there is no error message. deflateInit2 does not perform any + compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. When using the zlib format, this + function must be called immediately after deflateInit, deflateInit2 or + deflateReset, and before any call of deflate. When doing raw deflate, this + function must be called either before any call of deflate, or immediately + after the completion of a deflate block, i.e. after all input has been + consumed and all output has been delivered when using any of the flush + options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The + compressor and decompressor must use exactly the same dictionary (see + inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size + provided in deflateInit or deflateInit2. Thus the strings most likely to be + useful should be put at the end of the dictionary, not at the front. In + addition, the current implementation of deflate will use at most the window + size minus 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the Adler-32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler-32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + Adler-32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if not at a block boundary for raw deflate). deflateSetDictionary does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm, + Bytef *dictionary, + uInt *dictLength)); +/* + Returns the sliding dictionary being maintained by deflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If deflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similary, if dictLength is Z_NULL, then it is not set. + + deflateGetDictionary() may return a length less than the window size, even + when more than the window size in input has been provided. It may return up + to 258 bytes less in that case, due to how zlib's implementation of deflate + manages the sliding window and lookahead for matches, where matches can be + up to 258 bytes long. If the application needs the last window-size bytes of + input, then that would need to be saved by the application outside of zlib. + + deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and can + consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, but + does not free and reallocate the internal compression state. The stream + will leave the compression level and any other attributes that may have been + set unchanged. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2(). This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different strategy. + If the compression approach (which is a function of the level) or the + strategy is changed, and if any input has been consumed in a previous + deflate() call, then the input available so far is compressed with the old + level and strategy using deflate(strm, Z_BLOCK). There are three approaches + for the compression levels 0, 1..3, and 4..9 respectively. The new level + and strategy will take effect at the next call of deflate(). + + If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does + not have enough output space to complete, then the parameter change will not + take effect. In this case, deflateParams() can be called again with the + same parameters and more output space to try again. + + In order to assure a change in the parameters on the first try, the + deflate stream should be flushed using deflate() with Z_BLOCK or other flush + request until strm.avail_out is not zero, before calling deflateParams(). + Then no more input data should be provided before the deflateParams() call. + If this is done, the old level and strategy will be applied to the data + compressed before deflateParams(), and the new level and strategy will be + applied to the the data compressed after deflateParams(). + + deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream + state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if + there was not enough output space to complete the compression of the + available input data before a change in the strategy or approach. Note that + in the case of a Z_BUF_ERROR, the parameters are not changed. A return + value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be + retried with more output space. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() or + deflateInit2(), and after deflateSetHeader(), if used. This would be used + to allocate an output buffer for deflation in a single pass, and so would be + called before deflate(). If that first deflate() call is provided the + sourceLen input bytes, an output buffer allocated to the size returned by + deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed + to return Z_STREAM_END. Note that it is possible for the compressed size to + be larger than the value returned by deflateBound() if flush options other + than Z_FINISH or Z_NO_FLUSH are used. +*/ + +ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, + unsigned *pending, + int *bits)); +/* + deflatePending() returns the number of bytes and bits of output that have + been generated, but not yet provided in the available output. The bytes not + provided would be due to the available output space having being consumed. + The number of bits of output not provided are between 0 and 7, where they + await more bits to join them in order to fill out a full byte. If pending + or bits are Z_NULL, then those values are not set. + + deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. + */ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the bits + leftover from a previous deflate stream when appending to it. As such, this + function can only be used for raw deflate, and must be used before the first + deflate() call after a deflateInit2() or deflateReset(). bits must be less + than or equal to 16, and that many of the least significant bits of value + will be inserted in the output. + + deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough + room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be zero to request that inflate use the window size in + the zlib header of the compressed stream. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an Adler-32 or a CRC-32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a + CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see + below), inflate() will not automatically decode concatenated gzip streams. + inflate() will return Z_STREAM_END at the end of the gzip stream. The state + would need to be reset to continue decoding a subsequent gzip stream. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit2 does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit2() does not process any header information -- that is + deferred until inflate() is called. +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler-32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called at any + time to set the dictionary. If the provided dictionary is smaller than the + window and there is already data in the window, then the provided dictionary + will amend what's there. The application must insure that the dictionary + that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler-32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, + Bytef *dictionary, + uInt *dictLength)); +/* + Returns the sliding dictionary being maintained by inflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If inflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similary, if dictLength is Z_NULL, then it is not set. + + inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a possible full flush point (see above + for the description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync searches for a 00 00 FF FF pattern in the compressed data. + All full flush points have this pattern, but not all occurrences of this + pattern are full flush points. + + inflateSync returns Z_OK if a possible full flush point has been found, + Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point + has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. + In the success case, the application may save the current current value of + total_in which indicates where valid compressed data was found. In the + error case, the application may repeatedly call inflateSync, providing more + input each time, until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate the internal decompression state. The + stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, + int windowBits)); +/* + This function is the same as inflateReset, but it also permits changing + the wrap and window size requests. The windowBits parameter is interpreted + the same as it is for inflateInit2. If the window size is changed, then the + memory allocated for the window is freed, and the window will be reallocated + by inflate() if needed. + + inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL), or if + the windowBits parameter is invalid. +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + If bits is negative, then the input stream bit buffer is emptied. Then + inflatePrime() can be called again to put bits in the buffer. This is used + to clear out bits leftover after feeding inflate a block description prior + to feeding inflate codes. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); +/* + This function returns two values, one in the lower 16 bits of the return + value, and the other in the remaining upper bits, obtained by shifting the + return value down 16 bits. If the upper value is -1 and the lower value is + zero, then inflate() is currently decoding information outside of a block. + If the upper value is -1 and the lower value is non-zero, then inflate is in + the middle of a stored block, with the lower value equaling the number of + bytes from the input remaining to copy. If the upper value is not -1, then + it is the number of bits back from the current bit position in the input of + the code (literal or length/distance pair) currently being processed. In + that case the lower value is the number of bytes already emitted for that + code. + + A code is being processed if inflate is waiting for more input to complete + decoding of the code, or if it has completed decoding but is waiting for + more output space to write the literal or match data. + + inflateMark() is used to mark locations in the input data for random + access, which may be at bit positions, and to note those cases where the + output of a code may span boundaries of random access blocks. The current + location in the input stream can be determined from avail_in and data_type + as noted in the description for the Z_BLOCK flush parameter for inflate. + + inflateMark returns the value noted above, or -65536 if the provided + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be + used to force inflate() to return immediately after header processing is + complete and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When any + of extra, name, or comment are not Z_NULL and the respective field is not + present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the parameters are invalid, Z_MEM_ERROR if the internal state could not be + allocated, or Z_VERSION_ERROR if the version of the library does not match + the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, + z_const unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is potentially more efficient than + inflate() for file i/o applications, in that it avoids copying between the + output and the sliding window by simply making the window itself the output + buffer. inflate() can be faster on modern CPUs when used with large + buffers. inflateBack() trusts the application to not change the output + buffer passed by the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free the + allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects only + the raw deflate stream to decompress. This is different from the default + behavior of inflate(), which expects a zlib header and trailer around the + deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero -- buf is ignored in that + case -- and inflateBack() will return a buffer error. inflateBack() will + call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. + out() should return zero on success, or non-zero on failure. If out() + returns non-zero, inflateBack() will return with an error. Neither in() nor + out() are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format error + in the deflate stream (in which case strm->msg is set to indicate the nature + of the error), or Z_STREAM_ERROR if the stream was not properly initialized. + In the case of Z_BUF_ERROR, an input or output error can be distinguished + using strm->next_in which will be Z_NULL only if in() returned an error. If + strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning + non-zero. (in() will always be called before out(), so strm->next_in is + assured to be defined if out() returns non-zero.) Note that inflateBack() + cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: ZLIB_DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + +#ifndef Z_SOLO + + /* utility functions */ + +/* + The following utility functions are implemented on top of the basic + stream-oriented functions. To simplify the interface, some default options + are assumed (compression level and memory usage, standard memory allocation + functions). The source code of these utility functions can be modified if + you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed data. compress() is equivalent to compress2() with a level + parameter of Z_DEFAULT_COMPRESSION. + + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed data. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before a + compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, destLen + is the actual size of the uncompressed data. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In + the case where there is not enough room, uncompress() will fill the output + buffer with the uncompressed data up to that point. +*/ + +ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong *sourceLen)); +/* + Same as uncompress, except that sourceLen is a pointer, where the + length of the source is *sourceLen. On return, *sourceLen is the number of + source bytes consumed. +*/ + + /* gzip file access functions */ + +/* + This library supports reading and writing files in gzip (.gz) format with + an interface similar to that of stdio, using the functions that start with + "gz". The gzip format is different from the zlib format. gzip is a gzip + wrapper, documented in RFC 1952, wrapped around a deflate stream. +*/ + +typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ + +/* +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); + + Opens a gzip (.gz) file for reading or writing. The mode parameter is as + in fopen ("rb" or "wb") but can also include a compression level ("wb9") or + a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only + compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' + for fixed code compression as in "wb9F". (See the description of + deflateInit2 for more information about the strategy parameter.) 'T' will + request transparent writing or appending with no compression and not using + the gzip format. + + "a" can be used instead of "w" to request that the gzip stream that will + be written be appended to the file. "+" will result in an error, since + reading and writing to the same gzip file is not supported. The addition of + "x" when writing will create the file exclusively, which fails if the file + already exists. On systems that support it, the addition of "e" when + reading or writing will set the flag to close the file on an execve() call. + + These functions, as well as gzip, will read and decode a sequence of gzip + streams in a file. The append function of gzopen() can be used to create + such a file. (Also see gzflush() for another way to do this.) When + appending, gzopen does not test whether the file begins with a gzip stream, + nor does it look for the end of the gzip streams to begin appending. gzopen + will simply append a gzip stream to the existing file. + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. When + reading, this will be detected automatically by looking for the magic two- + byte gzip header. + + gzopen returns NULL if the file could not be opened, if there was + insufficient memory to allocate the gzFile state, or if an invalid mode was + specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). + errno can be checked to determine if the reason gzopen failed was that the + file could not be opened. +*/ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen associates a gzFile with the file descriptor fd. File descriptors + are obtained from calls like open, dup, creat, pipe or fileno (if the file + has been previously opened with fopen). The mode parameter is as in gzopen. + + The next call of gzclose on the returned gzFile will also close the file + descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor + fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, + mode);. The duplicated descriptor should be saved to avoid a leak, since + gzdopen does not close fd if it fails. If you are using fileno() to get the + file descriptor from a FILE *, then you will have to use dup() to avoid + double-close()ing the file descriptor. Both gzclose() and fclose() will + close the associated file descriptor, so they need to have different file + descriptors. + + gzdopen returns NULL if there was insufficient memory to allocate the + gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not + provided, or '+' was provided), or if fd is -1. The file descriptor is not + used until the next gz* read, write, seek, or close operation, so gzdopen + will not detect if fd is invalid (unless fd is -1). +*/ + +ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); +/* + Set the internal buffer size used by this library's functions. The + default buffer size is 8192 bytes. This function must be called after + gzopen() or gzdopen(), and before any other calls that read or write the + file. The buffer memory allocation is always deferred to the first read or + write. Three times that size in buffer space is allocated. A larger buffer + size of, for example, 64K or 128K bytes will noticeably increase the speed + of decompression (reading). + + The new buffer size also affects the maximum length for gzprintf(). + + gzbuffer() returns 0 on success, or -1 on failure, such as being called + too late. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. Previously provided + data is flushed before the parameter change. + + gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not + opened for writing, Z_ERRNO if there is an error writing the flushed data, + or Z_MEM_ERROR if there is a memory allocation error. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. If + the input file is not in gzip format, gzread copies the given number of + bytes into the buffer directly from the file. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream. Any number of gzip streams may be + concatenated in the input file, and will all be decompressed by gzread(). + If something other than a gzip stream is encountered after a gzip stream, + that remaining trailing garbage is ignored (and no error is returned). + + gzread can be used to read a gzip file that is being concurrently written. + Upon reaching the end of the input, gzread will return with the available + data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then + gzclearerr can be used to clear the end of file indicator in order to permit + gzread to be tried again. Z_OK indicates that a gzip stream was completed + on the last gzread. Z_BUF_ERROR indicates that the input file ended in the + middle of a gzip stream. Note that gzread does not return -1 in the event + of an incomplete gzip stream. This error is deferred until gzclose(), which + will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip + stream. Alternatively, gzerror can be used before gzclose to detect this + case. + + gzread returns the number of uncompressed bytes actually read, less than + len for end of file, or -1 for error. If len is too large to fit in an int, + then nothing is read, -1 is returned, and the error state is set to + Z_STREAM_ERROR. +*/ + +ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, + gzFile file)); +/* + Read up to nitems items of size size from file to buf, otherwise operating + as gzread() does. This duplicates the interface of stdio's fread(), with + size_t request and return types. If the library defines size_t, then + z_size_t is identical to size_t. If not, then z_size_t is an unsigned + integer type that can contain a pointer. + + gzfread() returns the number of full items read of size size, or zero if + the end of the file was reached and a full item could not be read, or if + there was an error. gzerror() must be consulted if zero is returned in + order to determine if there was an error. If the multiplication of size and + nitems overflows, i.e. the product does not fit in a z_size_t, then nothing + is read, zero is returned, and the error state is set to Z_STREAM_ERROR. + + In the event that the end of file is reached and only a partial item is + available at the end, i.e. the remaining uncompressed data length is not a + multiple of size, then the final partial item is nevetheless read into buf + and the end-of-file flag is set. The length of the partial item read is not + provided, but could be inferred from the result of gztell(). This behavior + is the same as the behavior of fread() implementations in common libraries, + but it prevents the direct use of gzfread() to read a concurrently written + file, reseting and retrying on end-of-file, when size is not 1. +*/ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes written or 0 in case of + error. +*/ + +ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size, + z_size_t nitems, gzFile file)); +/* + gzfwrite() writes nitems items of size size from buf to file, duplicating + the interface of stdio's fwrite(), with size_t request and return types. If + the library defines size_t, then z_size_t is identical to size_t. If not, + then z_size_t is an unsigned integer type that can contain a pointer. + + gzfwrite() returns the number of full items written of size size, or zero + if there was an error. If the multiplication of size and nitems overflows, + i.e. the product does not fit in a z_size_t, then nothing is written, zero + is returned, and the error state is set to Z_STREAM_ERROR. +*/ + +ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the arguments to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written, or a negative zlib error code in case + of error. The number of uncompressed bytes written is limited to 8191, or + one less than the buffer size given to gzbuffer(). The caller should assure + that this limit is not exceeded. If it is exceeded, then gzprintf() will + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. + This can be determined using zlibCompileFlags(). +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or a + newline character is read and transferred to buf, or an end-of-file + condition is encountered. If any characters are read or if len == 1, the + string is terminated with a null character. If no characters are read due + to an end-of-file or len < 1, then the buffer is left untouched. + + gzgets returns buf which is a null-terminated string, or it returns NULL + for end-of-file or in case of error. If there was an error, the contents at + buf are indeterminate. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. gzputc + returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte or -1 + in case of end of file or error. This is implemented as a macro for speed. + As such, it does not do all of the checking the other functions do. I.e. + it does not check to see if file is NULL, nor whether the structure file + points to has been clobbered or not. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read as the first character + on the next read. At least one character of push-back is allowed. + gzungetc() returns the character pushed, or -1 on failure. gzungetc() will + fail if c is -1, and may fail if a character has been pushed but not read + yet. If gzungetc is used immediately after gzopen or gzdopen, at least the + output buffer size of pushed characters is allowed. (See gzbuffer above.) + The pushed character will be discarded if the stream is repositioned with + gzseek() or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter flush + is as in the deflate() function. The return value is the zlib error number + (see function gzerror below). gzflush is only permitted when writing. + + If the flush parameter is Z_FINISH, the remaining data is written and the + gzip stream is completed in the output. If gzwrite() is called again, a new + gzip stream will be started in the output. gzread() is able to read such + concatenated gzip streams. + + gzflush should be called only when strictly necessary because it will + degrade compression if called too often. +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); + + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); + + Returns the starting position for the next gzread or gzwrite on the given + compressed file. This position represents a number of bytes in the + uncompressed data stream, and is zero when starting, even if appending or + reading a gzip stream from the middle of a file using gzdopen(). + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); + + Returns the current offset in the file being read or written. This offset + includes the count of bytes that precede the gzip stream, for example when + appending or when using gzdopen() for reading. When reading, the offset + does not include as yet unused buffered input. This information can be used + for a progress indicator. On error, gzoffset() returns -1. +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns true (1) if the end-of-file indicator has been set while reading, + false (0) otherwise. Note that the end-of-file indicator is set only if the + read tried to go past the end of the input, but came up short. Therefore, + just like feof(), gzeof() may return false even if there is no more data to + read, in the event that the last read request was for the exact number of + bytes remaining in the input file. This will happen if the input file size + is an exact multiple of the buffer size. + + If gzeof() returns true, then the read functions will return no more data, + unless the end-of-file indicator is reset by gzclearerr() and the input file + has grown since the previous end of file was detected. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns true (1) if file is being copied directly while reading, or false + (0) if file is a gzip stream being decompressed. + + If the input file is empty, gzdirect() will return true, since the input + does not contain a gzip stream. + + If gzdirect() is used immediately after gzopen() or gzdopen() it will + cause buffers to be allocated to allow reading the file to determine if it + is a gzip file. Therefore if gzbuffer() is used, it should be called before + gzdirect(). + + When writing, gzdirect() returns true (1) if transparent writing was + requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: + gzdirect() is not needed when writing. Transparent writing must be + explicitly requested, so the application already knows the answer. When + linking statically, using gzdirect() will include all of the zlib code for + gzip file reading and decompression, which may not be desired.) +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file and + deallocates the (de)compression state. Note that once file is closed, you + cannot call gzerror with file, since its structures have been deallocated. + gzclose must not be called more than once on the same file, just as free + must not be called more than once on the same allocation. + + gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a + file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the + last read ended in the middle of a gzip stream, or Z_OK on success. +*/ + +ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); +ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); +/* + Same as gzclose(), but gzclose_r() is only for use when reading, and + gzclose_w() is only for use when writing or appending. The advantage to + using these instead of gzclose() is that they avoid linking in zlib + compression or decompression code that is not used when only reading or only + writing respectively. If gzclose() is used, then both compression and + decompression code will be included the application when linking to a static + zlib library. +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the given + compressed file. errnum is set to zlib error number. If an error occurred + in the file system and not in the compression library, errnum is set to + Z_ERRNO and the application may consult errno to get the exact error code. + + The application must not modify the returned string. Future calls to + this function may invalidate the previously returned string. If file is + closed, then the string previously returned by gzerror will no longer be + available. + + gzerror() should be used to distinguish errors from end-of-file for those + functions above that do not distinguish those cases in their return values. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + +#endif /* !Z_SOLO */ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the compression + library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is Z_NULL, this function returns the + required initial value for the checksum. + + An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed + much faster. + + Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf, + z_size_t len)); +/* + Same as adler32(), but with a size_t length. +*/ + +/* +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); + + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note + that the z_off_t type (like off_t) is a signed integer. If len2 is + negative, the result has no meaning or utility. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is Z_NULL, this function returns the required + initial value for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_z OF((uLong adler, const Bytef *buf, + z_size_t len)); +/* + Same as crc32(), but with a size_t length. +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#ifdef Z_PREFIX_SET +# define z_deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +# define z_inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) +#else +# define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +# define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +# define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +# define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +# define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) +#endif + +#ifndef Z_SOLO + +/* gzgetc() macro and its supporting function and exposed data structure. Note + * that the real internal state is much larger than the exposed structure. + * This abbreviated structure exposes just enough for the gzgetc() macro. The + * user should not mess with these exposed elements, since their names or + * behavior could change in the future, perhaps even capriciously. They can + * only be used by the gzgetc() macro. You have been warned. + */ +struct gzFile_s { + unsigned have; + unsigned char *next; + z_off64_t pos; +}; +ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +# define z_gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) +#else +# define gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) +#endif + +/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or + * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if + * both are true, the application gets the *64 functions, and the regular + * functions are changed to 64 bits) -- in case these are set on systems + * without large file support, _LFS64_LARGEFILE must also be true + */ +#ifdef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); +#endif + +#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) +# ifdef Z_PREFIX_SET +# define z_gzopen z_gzopen64 +# define z_gzseek z_gzseek64 +# define z_gztell z_gztell64 +# define z_gzoffset z_gzoffset64 +# define z_adler32_combine z_adler32_combine64 +# define z_crc32_combine z_crc32_combine64 +# else +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# endif +# ifndef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +# endif +#else + ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); +#endif + +#else /* Z_SOLO */ + + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); + +#endif /* !Z_SOLO */ + +/* undocumented functions */ +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); +ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); +ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); +ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int)); +ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF ((z_streamp)); +ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); +ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); +#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(Z_SOLO) +ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, + const char *mode)); +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, + const char *format, + va_list va)); +# endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/contrib/zlib/zlib.map b/contrib/zlib/zlib.map new file mode 100644 index 00000000..82ce98cf --- /dev/null +++ b/contrib/zlib/zlib.map @@ -0,0 +1,94 @@ +ZLIB_1.2.0 { + global: + compressBound; + deflateBound; + inflateBack; + inflateBackEnd; + inflateBackInit_; + inflateCopy; + local: + deflate_copyright; + inflate_copyright; + inflate_fast; + inflate_table; + zcalloc; + zcfree; + z_errmsg; + gz_error; + gz_intmax; + _*; +}; + +ZLIB_1.2.0.2 { + gzclearerr; + gzungetc; + zlibCompileFlags; +} ZLIB_1.2.0; + +ZLIB_1.2.0.8 { + deflatePrime; +} ZLIB_1.2.0.2; + +ZLIB_1.2.2 { + adler32_combine; + crc32_combine; + deflateSetHeader; + inflateGetHeader; +} ZLIB_1.2.0.8; + +ZLIB_1.2.2.3 { + deflateTune; + gzdirect; +} ZLIB_1.2.2; + +ZLIB_1.2.2.4 { + inflatePrime; +} ZLIB_1.2.2.3; + +ZLIB_1.2.3.3 { + adler32_combine64; + crc32_combine64; + gzopen64; + gzseek64; + gztell64; + inflateUndermine; +} ZLIB_1.2.2.4; + +ZLIB_1.2.3.4 { + inflateReset2; + inflateMark; +} ZLIB_1.2.3.3; + +ZLIB_1.2.3.5 { + gzbuffer; + gzoffset; + gzoffset64; + gzclose_r; + gzclose_w; +} ZLIB_1.2.3.4; + +ZLIB_1.2.5.1 { + deflatePending; +} ZLIB_1.2.3.5; + +ZLIB_1.2.5.2 { + deflateResetKeep; + gzgetc_; + inflateResetKeep; +} ZLIB_1.2.5.1; + +ZLIB_1.2.7.1 { + inflateGetDictionary; + gzvprintf; +} ZLIB_1.2.5.2; + +ZLIB_1.2.9 { + inflateCodesUsed; + inflateValidate; + uncompress2; + gzfread; + gzfwrite; + deflateGetDictionary; + adler32_z; + crc32_z; +} ZLIB_1.2.7.1; diff --git a/contrib/zlib/zlib.pc.cmakein b/contrib/zlib/zlib.pc.cmakein new file mode 100644 index 00000000..a5e64293 --- /dev/null +++ b/contrib/zlib/zlib.pc.cmakein @@ -0,0 +1,13 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=@CMAKE_INSTALL_PREFIX@ +libdir=@INSTALL_LIB_DIR@ +sharedlibdir=@INSTALL_LIB_DIR@ +includedir=@INSTALL_INC_DIR@ + +Name: zlib +Description: zlib compression library +Version: @VERSION@ + +Requires: +Libs: -L${libdir} -L${sharedlibdir} -lz +Cflags: -I${includedir} diff --git a/contrib/zlib/zlib.pc.in b/contrib/zlib/zlib.pc.in new file mode 100644 index 00000000..7e5acf9c --- /dev/null +++ b/contrib/zlib/zlib.pc.in @@ -0,0 +1,13 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +sharedlibdir=@sharedlibdir@ +includedir=@includedir@ + +Name: zlib +Description: zlib compression library +Version: @VERSION@ + +Requires: +Libs: -L${libdir} -L${sharedlibdir} -lz +Cflags: -I${includedir} diff --git a/contrib/zlib/zlib2ansi b/contrib/zlib/zlib2ansi new file mode 100644 index 00000000..15e3e165 --- /dev/null +++ b/contrib/zlib/zlib2ansi @@ -0,0 +1,152 @@ +#!/usr/bin/perl + +# Transform K&R C function definitions into ANSI equivalent. +# +# Author: Paul Marquess +# Version: 1.0 +# Date: 3 October 2006 + +# TODO +# +# Asumes no function pointer parameters. unless they are typedefed. +# Assumes no literal strings that look like function definitions +# Assumes functions start at the beginning of a line + +use strict; +use warnings; + +local $/; +$_ = <>; + +my $sp = qr{ \s* (?: /\* .*? \*/ )? \s* }x; # assume no nested comments + +my $d1 = qr{ $sp (?: [\w\*\s]+ $sp)* $sp \w+ $sp [\[\]\s]* $sp }x ; +my $decl = qr{ $sp (?: \w+ $sp )+ $d1 }xo ; +my $dList = qr{ $sp $decl (?: $sp , $d1 )* $sp ; $sp }xo ; + + +while (s/^ + ( # Start $1 + ( # Start $2 + .*? # Minimal eat content + ( ^ \w [\w\s\*]+ ) # $3 -- function name + \s* # optional whitespace + ) # $2 - Matched up to before parameter list + + \( \s* # Literal "(" + optional whitespace + ( [^\)]+ ) # $4 - one or more anythings except ")" + \s* \) # optional whitespace surrounding a Literal ")" + + ( (?: $dList )+ ) # $5 + + $sp ^ { # literal "{" at start of line + ) # Remember to $1 + //xsom + ) +{ + my $all = $1 ; + my $prefix = $2; + my $param_list = $4 ; + my $params = $5; + + StripComments($params); + StripComments($param_list); + $param_list =~ s/^\s+//; + $param_list =~ s/\s+$//; + + my $i = 0 ; + my %pList = map { $_ => $i++ } + split /\s*,\s*/, $param_list; + my $pMatch = '(\b' . join('|', keys %pList) . '\b)\W*$' ; + + my @params = split /\s*;\s*/, $params; + my @outParams = (); + foreach my $p (@params) + { + if ($p =~ /,/) + { + my @bits = split /\s*,\s*/, $p; + my $first = shift @bits; + $first =~ s/^\s*//; + push @outParams, $first; + $first =~ /^(\w+\s*)/; + my $type = $1 ; + push @outParams, map { $type . $_ } @bits; + } + else + { + $p =~ s/^\s+//; + push @outParams, $p; + } + } + + + my %tmp = map { /$pMatch/; $_ => $pList{$1} } + @outParams ; + + @outParams = map { " $_" } + sort { $tmp{$a} <=> $tmp{$b} } + @outParams ; + + print $prefix ; + print "(\n" . join(",\n", @outParams) . ")\n"; + print "{" ; + +} + +# Output any trailing code. +print ; +exit 0; + + +sub StripComments +{ + + no warnings; + + # Strip C & C++ coments + # From the perlfaq + $_[0] =~ + + s{ + /\* ## Start of /* ... */ comment + [^*]*\*+ ## Non-* followed by 1-or-more *'s + ( + [^/*][^*]*\*+ + )* ## 0-or-more things which don't start with / + ## but do end with '*' + / ## End of /* ... */ comment + + | ## OR C++ Comment + // ## Start of C++ comment // + [^\n]* ## followed by 0-or-more non end of line characters + + | ## OR various things which aren't comments: + + ( + " ## Start of " ... " string + ( + \\. ## Escaped char + | ## OR + [^"\\] ## Non "\ + )* + " ## End of " ... " string + + | ## OR + + ' ## Start of ' ... ' string + ( + \\. ## Escaped char + | ## OR + [^'\\] ## Non '\ + )* + ' ## End of ' ... ' string + + | ## OR + + . ## Anything other char + [^/"'\\]* ## Chars which doesn't start a comment, string or escape + ) + }{$2}gxs; + +} diff --git a/contrib/zlib/zutil.c b/contrib/zlib/zutil.c new file mode 100644 index 00000000..a76c6b0c --- /dev/null +++ b/contrib/zlib/zutil.c @@ -0,0 +1,325 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2017 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" +#ifndef Z_SOLO +# include "gzguts.h" +#endif + +z_const char * const z_errmsg[10] = { + (z_const char *)"need dictionary", /* Z_NEED_DICT 2 */ + (z_const char *)"stream end", /* Z_STREAM_END 1 */ + (z_const char *)"", /* Z_OK 0 */ + (z_const char *)"file error", /* Z_ERRNO (-1) */ + (z_const char *)"stream error", /* Z_STREAM_ERROR (-2) */ + (z_const char *)"data error", /* Z_DATA_ERROR (-3) */ + (z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */ + (z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */ + (z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */ + (z_const char *)"" +}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch ((int)(sizeof(uInt))) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch ((int)(sizeof(uLong))) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch ((int)(sizeof(voidpf))) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch ((int)(sizeof(z_off_t))) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef ZLIB_DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef ZLIB_DEBUG +#include +# ifndef verbose +# define verbose 0 +# endif +int ZLIB_INTERNAL z_verbose = verbose; + +void ZLIB_INTERNAL z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void ZLIB_INTERNAL zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int ZLIB_INTERNAL zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void ZLIB_INTERNAL zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + +#ifndef Z_SOLO + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf; + ulg bsize = (ulg)items*size; + + (void)opaque; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) +{ + int n; + + (void)opaque; + + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) +{ + (void)opaque; + return _halloc((long)items, size); +} + +void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) +{ + (void)opaque; + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + (void)opaque; + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void ZLIB_INTERNAL zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + (void)opaque; + free(ptr); +} + +#endif /* MY_ZCALLOC */ + +#endif /* !Z_SOLO */ diff --git a/contrib/zlib/zutil.h b/contrib/zlib/zutil.h new file mode 100644 index 00000000..b079ea6a --- /dev/null +++ b/contrib/zlib/zutil.h @@ -0,0 +1,271 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include "zlib.h" + +#if defined(STDC) && !defined(Z_SOLO) +# if !(defined(_WIN32_WCE) && defined(_MSC_VER)) +# include +# endif +# include +# include +#endif + +#ifdef Z_SOLO + typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */ +#endif + +#ifndef local +# define local static +#endif +/* since "static" is used to mean two completely different things in C, we + define "local" for the non-static meaning of "static", for readability + (compile with -Dlocal if your debugger can't find static symbols) */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# ifndef Z_SOLO +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 1 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 2 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#ifdef __370__ +# if __TARGET_LIB__ < 0x20000000 +# define OS_CODE 4 +# elif __TARGET_LIB__ < 0x40000000 +# define OS_CODE 11 +# else +# define OS_CODE 8 +# endif +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 5 +#endif + +#ifdef OS2 +# define OS_CODE 6 +# if defined(M_I86) && !defined(Z_SOLO) +# include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 7 +# ifndef Z_SOLO +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +# endif +#endif + +#ifdef __acorn +# define OS_CODE 13 +#endif + +#if defined(WIN32) && !defined(__CYGWIN__) +# define OS_CODE 10 +#endif + +#ifdef _BEOS_ +# define OS_CODE 16 +#endif + +#ifdef __TOS_OS400__ +# define OS_CODE 18 +#endif + +#ifdef __APPLE__ +# define OS_CODE 19 +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + +#if defined(__BORLANDC__) && !defined(MSDOS) + #pragma warn -8004 + #pragma warn -8008 + #pragma warn -8066 +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_WIN32) && \ + (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 3 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(pyr) || defined(Z_SOLO) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef ZLIB_DEBUG +# include + extern int ZLIB_INTERNAL z_verbose; + extern void ZLIB_INTERNAL z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +#ifndef Z_SOLO + voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, + unsigned size)); + void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); +#endif + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +/* Reverse the bytes in a 32-bit value */ +#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +#endif /* ZUTIL_H */ diff --git a/resources/Zano WP.pdf b/resources/Zano WP.pdf new file mode 100644 index 00000000..b62e0164 Binary files /dev/null and b/resources/Zano WP.pdf differ diff --git a/resources/dmg_installer_bg.png b/resources/dmg_installer_bg.png new file mode 100644 index 00000000..9c88ecb6 Binary files /dev/null and b/resources/dmg_installer_bg.png differ diff --git a/resources/installer_bg_164x313.bmp b/resources/installer_bg_164x313.bmp new file mode 100644 index 00000000..abc47621 Binary files /dev/null and b/resources/installer_bg_164x313.bmp differ diff --git a/resources/installer_bg_191x385.bmp b/resources/installer_bg_191x385.bmp new file mode 100644 index 00000000..48feb48d Binary files /dev/null and b/resources/installer_bg_191x385.bmp differ diff --git a/resources/installer_bg_246x457.bmp b/resources/installer_bg_246x457.bmp new file mode 100644 index 00000000..865b3de3 Binary files /dev/null and b/resources/installer_bg_246x457.bmp differ diff --git a/resources/installer_bg_328x628.bmp b/resources/installer_bg_328x628.bmp new file mode 100644 index 00000000..280b1a73 Binary files /dev/null and b/resources/installer_bg_328x628.bmp differ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 00000000..44941fc2 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,187 @@ + +if(POLICY CMP0043) + cmake_policy(SET CMP0043 OLD) +endif() + + +########### +# using shared PCH -- this is unusual case for MSVC... so mystery, such hack, many wow. See also: https://stackoverflow.com/questions/645747/sharing-precompiled-headers-between-projects-in-visual-studio/4170902#4170902 +# define USE_PCH to YES for using precomiled headers + +MACRO(INIT_SHARED_PCH pch_cpp_file) + IF(MSVC AND USE_PCH) + set_property(SOURCE ${pch_cpp_file} APPEND_STRING PROPERTY COMPILE_FLAGS " /Fo$(OutDir) /Z7 /Fd$(OutDir)vc$(PlatformToolsetVersion).pdb /Ycstdafx.h /Fp$(TargetDir)pch.pch") + ENDIF(MSVC AND USE_PCH) +ENDMACRO(INIT_SHARED_PCH) + +MACRO(ENABLE_SHARED_PCH sources_var) + IF(MSVC AND USE_PCH) + MESSAGE( STATUS " ...... enabling precompiled headers for: " ${sources_var} ) + SET(precompiled_binary "$(TargetDir)pch.pch") + SET(precompiled_header "${CMAKE_CURRENT_SOURCE_DIR}/pch/stdafx.h") + SET(sources ${${sources_var}}) + foreach(src ${sources}) + if(NOT ${src} MATCHES "\\.rc$") # skip *.rc files + SET_SOURCE_FILES_PROPERTIES(${src} + PROPERTIES COMPILE_FLAGS "/Z7 /Fd$(OutDir)vc$(PlatformToolsetVersion).pdb /Yu\"${precompiled_header}\" /FI\"${precompiled_header}\" /Fp\"${precompiled_binary}\"" + OBJECT_DEPENDS "${precompiled_binary}") + endif() + endforeach() + ENDIF(MSVC AND USE_PCH) +ENDMACRO(ENABLE_SHARED_PCH) + +MACRO(ENABLE_SHARED_PCH_EXECUTABLE target) + IF(MSVC AND USE_PCH) + SET_TARGET_PROPERTIES(${target} PROPERTIES LINK_FLAGS "$(OutDir)stdafx.obj") + ENDIF(MSVC AND USE_PCH) +ENDMACRO(ENABLE_SHARED_PCH_EXECUTABLE) +########### + + + + +file(GLOB_RECURSE PCH pch/*) +file(GLOB_RECURSE COMMON common/*) +file(GLOB CRYPTO crypto/*.*) +file(GLOB_RECURSE CURRENCY_CORE currency_core/*) +file(GLOB_RECURSE CURRENCY_PROTOCOL currency_protocol/*) +file(GLOB_RECURSE DAEMON daemon/*) + +file(GLOB_RECURSE P2P p2p/*) +file(GLOB_RECURSE RPC rpc/*) +file(GLOB_RECURSE SIMPLEWALLET simplewallet/*) +file(GLOB_RECURSE CONN_TOOL connectivity_tool/*) +file(GLOB_RECURSE WALLET wallet/*) +file(GLOB_RECURSE MINER miner/*) + +if(BUILD_GUI) + if(MSVC) + file(GLOB_RECURSE QTDAEMON gui/qt-daemon/*.cpp gui/qt-daemon/*.h gui/qt-daemon/app.rc) + elseif(APPLE) + file(GLOB_RECURSE QTDAEMON gui/qt-daemon/*.cpp gui/qt-daemon/*.h gui/qt-daemon/*.mm) + else() + file(GLOB_RECURSE QTDAEMON gui/qt-daemon/*.cpp gui/qt-daemon/*.h) + endif() +endif() + + +source_group(pch FILES ${PCH}) +source_group(common FILES ${COMMON}) +source_group(crypto FILES ${CRYPTO}) +source_group(currency_core FILES ${CURRENCY_CORE}) +source_group(currency_protocol FILES ${CURRENCY_PROTOCOL}) +source_group(daemon FILES ${DAEMON}) +source_group(p2p FILES ${P2P}) +source_group(rpc FILES ${RPC}) +source_group(simplewallet FILES ${SIMPLEWALLET}) +source_group(connectivity-tool FILES ${CONN_TOOL}) +source_group(wallet FILES ${WALLET}) + +if(BUILD_GUI) + source_group(qtdaemon FILES ${QTDAEMON}) +endif() + + +if (USE_PCH) + add_library(pch ${PCH}) + set(PCH_LIB_NAME pch) +endif() +INIT_SHARED_PCH("pch/stdafx.cpp") + +add_library(common ${COMMON}) +add_dependencies(common version ${PCH_LIB_NAME}) +ENABLE_SHARED_PCH(COMMON) + +if(NOT MSVC AND NOT APPLE) + target_compile_options(common PRIVATE -fno-var-tracking-assignments) +endif() + +add_library(crypto ${CRYPTO}) + +MESSAGE( STATUS "INCLUDING OpenCL_INCLUDE_DIRS: " ${OpenCL_INCLUDE_DIRS} ) +include_directories( ${OpenCL_INCLUDE_DIRS} ) + +add_library(currency_core ${CURRENCY_CORE}) +add_dependencies(currency_core version rpc ${PCH_LIB_NAME}) +ENABLE_SHARED_PCH(CURRENCY_CORE) + +add_library(rpc ${RPC}) +add_dependencies(rpc version ${PCH_LIB_NAME}) +ENABLE_SHARED_PCH(RPC) + +add_library(wallet ${WALLET}) +add_dependencies(wallet version ${PCH_LIB_NAME}) +ENABLE_SHARED_PCH(WALLET) + +target_link_libraries(currency_core lmdb) + +add_executable(daemon ${DAEMON} ${P2P} ${CURRENCY_PROTOCOL}) +add_dependencies(daemon version) +target_link_libraries(daemon rpc currency_core crypto common upnpc-static zlibstatic ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +ENABLE_SHARED_PCH(DAEMON) +ENABLE_SHARED_PCH_EXECUTABLE(daemon) + +add_executable(connectivity_tool ${CONN_TOOL}) +add_dependencies(connectivity_tool version) +target_link_libraries(connectivity_tool currency_core crypto common zlibstatic ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +ENABLE_SHARED_PCH(CONN_TOOL) +ENABLE_SHARED_PCH_EXECUTABLE(connectivity_tool) + +add_executable(simplewallet ${SIMPLEWALLET}) +add_dependencies(simplewallet version) +target_link_libraries(simplewallet wallet rpc currency_core crypto common zlibstatic ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +ENABLE_SHARED_PCH(SIMPLEWALLET) +ENABLE_SHARED_PCH_EXECUTABLE(simplewallet) + +set_property(TARGET common crypto currency_core rpc wallet PROPERTY FOLDER "libs") +set_property(TARGET daemon simplewallet connectivity_tool PROPERTY FOLDER "prog") +set_property(TARGET daemon PROPERTY OUTPUT_NAME "zanod") + +if(BUILD_GUI) + + if(APPLE) + FIND_LIBRARY(COCOA_LIBRARY Cocoa) + endif() + + set(CMAKE_AUTOMOC ON) + set(CMAKE_INCLUDE_CURRENT_DIR ON) + SET(MACOSX_BUNDLE_ICON_FILE app.icns) + add_executable(Zano WIN32 MACOSX_BUNDLE ${QTDAEMON} ) + ENABLE_SHARED_PCH(QTDAEMON) + ENABLE_SHARED_PCH_EXECUTABLE(Zano) + + QT5_USE_MODULES(Zano WebEngineWidgets WebChannel) + find_package(Qt5PrintSupport REQUIRED) + + target_link_libraries(Zano wallet rpc currency_core crypto common zlibstatic Qt5::WebEngineWidgets Qt5::PrintSupport ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) + + if(APPLE) + target_link_libraries(Zano ${COCOA_LIBRARY}) + endif() + if(MSVC) + target_link_libraries(Zano shlwapi.lib) + endif() + + set_property(TARGET Zano PROPERTY FOLDER "prog") + set_target_properties(Zano PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/gui/qt-daemon/Info.plist.in) + + set(CMAKE_AUTOMOC OFF) +endif() + +if(APPLE) + set(SIMPLE_BUNDLE 1) +endif() + +if(SIMPLE_BUNDLE) + set(INSTALL_DIR "${CMAKE_BINARY_DIR}/hp-${VERSION}") + install(TARGETS daemon simplewallet connectivity_tool + RUNTIME DESTINATION "${INSTALL_DIR}" COMPONENT Runtime + ) + + install(FILES ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} DESTINATION "${INSTALL_DIR}/lib") + + if(APPLE) + set(FIXUP_COMMAND ${CMAKE_SOURCE_DIR}/utils/macosx_fixup.sh " " ${INSTALL_DIR}) + install(CODE "execute_process(COMMAND ${FIXUP_COMMAND})") + endif() +endif() diff --git a/src/common/base58.cpp b/src/common/base58.cpp new file mode 100644 index 00000000..76e277c3 --- /dev/null +++ b/src/common/base58.cpp @@ -0,0 +1,248 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include + +#include "base58.h" +#include "crypto/hash.h" +#include "int-util.h" +#include "util.h" +#include "varint.h" + +namespace tools +{ + namespace base58 + { + namespace + { + const char alphabet[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + const size_t alphabet_size = sizeof(alphabet) - 1; + const size_t encoded_block_sizes[] = {0, 2, 3, 5, 6, 7, 9, 10, 11}; + const size_t full_block_size = sizeof(encoded_block_sizes) / sizeof(encoded_block_sizes[0]) - 1; + const size_t full_encoded_block_size = encoded_block_sizes[full_block_size]; + const size_t addr_checksum_size = 4; + + struct reverse_alphabet + { + reverse_alphabet() + { + m_data.resize(alphabet[alphabet_size - 1] - alphabet[0] + 1, -1); + + for (size_t i = 0; i < alphabet_size; ++i) + { + size_t idx = static_cast(alphabet[i] - alphabet[0]); + m_data[idx] = static_cast(i); + } + } + + int operator()(char letter) const + { + size_t idx = static_cast(letter - alphabet[0]); + return idx < m_data.size() ? m_data[idx] : -1; + } + + static reverse_alphabet instance; + + private: + std::vector m_data; + }; + + reverse_alphabet reverse_alphabet::instance; + + struct decoded_block_sizes + { + decoded_block_sizes() + { + m_data.resize(encoded_block_sizes[full_block_size] + 1, -1); + for (size_t i = 0; i <= full_block_size; ++i) + { + m_data[encoded_block_sizes[i]] = static_cast(i); + } + } + + int operator()(size_t encoded_block_size) const + { + assert(encoded_block_size <= full_encoded_block_size); + return m_data[encoded_block_size]; + } + + static decoded_block_sizes instance; + + private: + std::vector m_data; + }; + + decoded_block_sizes decoded_block_sizes::instance; + + uint64_t uint_8be_to_64(const uint8_t* data, size_t size) + { + assert(1 <= size && size <= sizeof(uint64_t)); + + uint64_t res = 0; + switch (9 - size) + { + case 1: res |= *data++; BOOST_FALLTHROUGH; + case 2: res <<= 8; res |= *data++; BOOST_FALLTHROUGH; + case 3: res <<= 8; res |= *data++; BOOST_FALLTHROUGH; + case 4: res <<= 8; res |= *data++; BOOST_FALLTHROUGH; + case 5: res <<= 8; res |= *data++; BOOST_FALLTHROUGH; + case 6: res <<= 8; res |= *data++; BOOST_FALLTHROUGH; + case 7: res <<= 8; res |= *data++; BOOST_FALLTHROUGH; + case 8: res <<= 8; res |= *data; break; + default: assert(false); + } + + return res; + } + + void uint_64_to_8be(uint64_t num, size_t size, uint8_t* data) + { + assert(1 <= size && size <= sizeof(uint64_t)); + + uint64_t num_be = SWAP64BE(num); + memcpy(data, reinterpret_cast(&num_be) + sizeof(uint64_t) - size, size); + } + + void encode_block(const char* block, size_t size, char* res) + { + assert(1 <= size && size <= full_block_size); + + uint64_t num = uint_8be_to_64(reinterpret_cast(block), size); + int i = static_cast(encoded_block_sizes[size]) - 1; + while (0 < num) + { + uint64_t remainder = num % alphabet_size; + num /= alphabet_size; + res[i] = alphabet[remainder]; + --i; + } + } + + bool decode_block(const char* block, size_t size, char* res) + { + assert(1 <= size && size <= full_encoded_block_size); + + int res_size = decoded_block_sizes::instance(size); + if (res_size <= 0) + return false; // Invalid block size + + uint64_t res_num = 0; + uint64_t order = 1; + for (size_t i = size - 1; i < size; --i) + { + int digit = reverse_alphabet::instance(block[i]); + if (digit < 0) + return false; // Invalid symbol + + //uint64_t product_hi; + boost::multiprecision::uint128_t tmp = res_num; + tmp += boost::multiprecision::uint128_t(order) * digit; + + if (tmp < res_num || tmp > std::numeric_limits::max() ) + return false; // Overflow + + res_num = tmp.convert_to(); + order *= alphabet_size; // Never overflows, 58^10 < 2^64 + } + + if (static_cast(res_size) < full_block_size && (UINT64_C(1) << (8 * res_size)) <= res_num) + return false; // Overflow + + uint_64_to_8be(res_num, res_size, reinterpret_cast(res)); + + return true; + } + } + + std::string encode(const std::string& data) + { + if (data.empty()) + return std::string(); + + size_t full_block_count = data.size() / full_block_size; + size_t last_block_size = data.size() % full_block_size; + size_t res_size = full_block_count * full_encoded_block_size + encoded_block_sizes[last_block_size]; + + std::string res(res_size, alphabet[0]); + for (size_t i = 0; i < full_block_count; ++i) + { + encode_block(data.data() + i * full_block_size, full_block_size, &res[i * full_encoded_block_size]); + } + + if (0 < last_block_size) + { + encode_block(data.data() + full_block_count * full_block_size, last_block_size, &res[full_block_count * full_encoded_block_size]); + } + + return res; + } + + bool decode(const std::string& enc, std::string& data) + { + if (enc.empty()) + { + data.clear(); + return true; + } + + size_t full_block_count = enc.size() / full_encoded_block_size; + size_t last_block_size = enc.size() % full_encoded_block_size; + int last_block_decoded_size = decoded_block_sizes::instance(last_block_size); + if (last_block_decoded_size < 0) + return false; // Invalid enc length + size_t data_size = full_block_count * full_block_size + last_block_decoded_size; + + data.resize(data_size, 0); + for (size_t i = 0; i < full_block_count; ++i) + { + if (!decode_block(enc.data() + i * full_encoded_block_size, full_encoded_block_size, &data[i * full_block_size])) + return false; + } + + if (0 < last_block_size) + { + if (!decode_block(enc.data() + full_block_count * full_encoded_block_size, last_block_size, + &data[full_block_count * full_block_size])) + return false; + } + + return true; + } + + std::string encode_addr(uint64_t tag, const std::string& data) + { + std::string buf = get_varint_data(tag); + buf += data; + crypto::hash hash = crypto::cn_fast_hash(buf.data(), buf.size()); + const char* hash_data = reinterpret_cast(&hash); + buf.append(hash_data, addr_checksum_size); + return encode(buf); + } + + bool decode_addr(std::string addr, uint64_t& tag, std::string& data) + { + std::string addr_data; + bool r = decode(addr, addr_data); + if (!r) return false; + if (addr_data.size() <= addr_checksum_size) return false; + + std::string checksum(addr_checksum_size, '\0'); + checksum = addr_data.substr(addr_data.size() - addr_checksum_size); + + addr_data.resize(addr_data.size() - addr_checksum_size); + crypto::hash hash = crypto::cn_fast_hash(addr_data.data(), addr_data.size()); + std::string expected_checksum(reinterpret_cast(&hash), addr_checksum_size); + if (expected_checksum != checksum) return false; + + int read = tools::read_varint(addr_data.begin(), addr_data.end(), tag); + if (read <= 0) return false; + + data = addr_data.substr(read); + return true; + } + } +} diff --git a/src/common/base58.h b/src/common/base58.h new file mode 100644 index 00000000..be09658d --- /dev/null +++ b/src/common/base58.h @@ -0,0 +1,22 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include + +namespace tools +{ + namespace base58 + { + std::string encode(const std::string& data); + bool decode(const std::string& enc, std::string& data); + + std::string encode_addr(uint64_t tag, const std::string& data); + bool decode_addr(std::string addr, uint64_t& tag, std::string& data); + } +} diff --git a/src/common/boost_serialization_helper.h b/src/common/boost_serialization_helper.h new file mode 100644 index 00000000..8ca8989d --- /dev/null +++ b/src/common/boost_serialization_helper.h @@ -0,0 +1,103 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include +#include + + + +#define CHECK_PROJECT_NAME() std::string project_name = CURRENCY_NAME; ar & project_name; if(!(project_name == CURRENCY_NAME) ) {throw std::runtime_error(std::string("wrong storage file: project name in file: ") + project_name + ", expected: " + CURRENCY_NAME );} + + +namespace tools +{ + template + bool serialize_obj_to_file(t_object& obj, const std::string& file_path) + { + TRY_ENTRY(); + std::ofstream data_file; + data_file.open( file_path , std::ios_base::binary | std::ios_base::out| std::ios::trunc); + if(data_file.fail()) + return false; + + boost::archive::binary_oarchive a(data_file); + a << obj; + + return !data_file.fail(); + CATCH_ENTRY_L0("serialize_obj_to_file", false); + } + + + template + bool serialize_obj_to_buff(t_object& obj, std::string& buff) + { + TRY_ENTRY(); + std::stringstream data_buff; + + boost::archive::binary_oarchive a(data_buff); + a << obj; + buff = data_buff.str(); + return !data_buff.fail(); + CATCH_ENTRY_L0("serialize_obj_to_buff", false); + } + + template + bool portble_serialize_obj_to_stream(t_object& obj, t_stream& stream) + { + TRY_ENTRY(); + + eos::portable_oarchive a(stream); + a << obj; + + return !stream.fail(); + CATCH_ENTRY_L0("serialize_obj_to_file", false); + } + + template + bool unserialize_obj_from_file(t_object& obj, const std::string& file_path) + { + TRY_ENTRY(); + + std::ifstream data_file; + data_file.open( file_path, std::ios_base::binary | std::ios_base::in); + if(data_file.fail()) + return false; + boost::archive::binary_iarchive a(data_file); + + a >> obj; + return !data_file.fail(); + CATCH_ENTRY_L0("unserialize_obj_from_file", false); + } + + template + bool unserialize_obj_from_buff(t_object& obj, const std::string& buff) + { + TRY_ENTRY(); + + std::stringstream ss(buff); + boost::archive::binary_iarchive a(ss); + + a >> obj; + return !ss.fail(); + CATCH_ENTRY_L0("unserialize_obj_from_obj", false); + } + + + template + bool portable_unserialize_obj_from_stream(t_object& obj, t_stream& stream) + { + TRY_ENTRY(); + + eos::portable_iarchive a(stream); + + a >> obj; + return !stream.fail(); + CATCH_ENTRY_L0("unserialize_obj_from_file", false); + } +} diff --git a/src/common/command_line.cpp b/src/common/command_line.cpp new file mode 100644 index 00000000..c1b90b7b --- /dev/null +++ b/src/common/command_line.cpp @@ -0,0 +1,25 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + + +#include "command_line.h" +#include "currency_core/currency_config.h" + +namespace command_line +{ + const arg_descriptor arg_help = {"help", "Produce help message"}; + const arg_descriptor arg_version = {"version", "Output version information"}; + const arg_descriptor arg_data_dir = {"data-dir", "Specify data directory"}; + + const arg_descriptor arg_config_file = { "config-file", "Specify configuration file", std::string(CURRENCY_NAME_SHORT ".conf") }; + const arg_descriptor arg_os_version = { "os-version", "" }; + const arg_descriptor arg_log_dir = { "log-dir", "", "", true}; + const arg_descriptor arg_log_level = { "log-level", "", LOG_LEVEL_0, true}; + const arg_descriptor arg_console = { "no-console", "Disable daemon console commands" }; + const arg_descriptor arg_show_details = { "currency-details", "Display currency details" }; + const arg_descriptor arg_show_rpc_autodoc = { "show_rpc_autodoc", "Display rpc auto-generated documentation template" }; + +} diff --git a/src/common/command_line.h b/src/common/command_line.h new file mode 100644 index 00000000..152c923f --- /dev/null +++ b/src/common/command_line.h @@ -0,0 +1,186 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include + +#include +#include +#include +#include "include_base_utils.h" + +namespace command_line +{ + template + struct arg_descriptor; + + template + struct arg_descriptor + { + typedef T value_type; + + const char* name; + const char* description; + T default_value; + bool not_use_default; + }; + + template + struct arg_descriptor, false> + { + typedef std::vector value_type; + + const char* name; + const char* description; + }; + + template + struct arg_descriptor + { + static_assert(!std::is_same::value, "Boolean switch can't be required"); + + typedef T value_type; + + const char* name; + const char* description; + }; + + template + boost::program_options::typed_value* make_semantic(const arg_descriptor& /*arg*/) + { + return boost::program_options::value()->required(); + } + + template + boost::program_options::typed_value* make_semantic(const arg_descriptor& arg) + { + auto semantic = boost::program_options::value(); + if (!arg.not_use_default) + semantic->default_value(arg.default_value); + return semantic; + } + + template + boost::program_options::typed_value* make_semantic(const arg_descriptor& arg, const T& def) + { + auto semantic = boost::program_options::value(); + if (!arg.not_use_default) + semantic->default_value(def); + return semantic; + } + + template + boost::program_options::typed_value, char>* make_semantic(const arg_descriptor, false>& /*arg*/) + { + auto semantic = boost::program_options::value< std::vector >(); + semantic->default_value(std::vector(), ""); + return semantic; + } + + template + void add_arg(boost::program_options::options_description& description, const arg_descriptor& arg, bool unique = true) + { + if (0 != description.find_nothrow(arg.name, false)) + { + CHECK_AND_ASSERT_MES(!unique, void(), "Argument already exists: " << arg.name); + return; + } + + description.add_options()(arg.name, make_semantic(arg), arg.description); + } + + template + void add_arg(boost::program_options::options_description& description, const arg_descriptor& arg, const T& def, bool unique = true) + { + if (0 != description.find_nothrow(arg.name, false)) + { + CHECK_AND_ASSERT_MES(!unique, void(), "Argument already exists: " << arg.name); + return; + } + + description.add_options()(arg.name, make_semantic(arg, def), arg.description); + } + + template<> + inline void add_arg(boost::program_options::options_description& description, const arg_descriptor& arg, bool unique) + { + if (0 != description.find_nothrow(arg.name, false)) + { + CHECK_AND_ASSERT_MES(!unique, void(), "Argument already exists: " << arg.name); + return; + } + + description.add_options()(arg.name, boost::program_options::bool_switch(), arg.description); + } + + template + boost::program_options::basic_parsed_options parse_command_line(int argc, const charT* const argv[], + const boost::program_options::options_description& desc, bool allow_unregistered = false) + { + auto parser = boost::program_options::command_line_parser(argc, argv); + parser.options(desc); + if (allow_unregistered) + { + parser.allow_unregistered(); + } + return parser.run(); + } + + template + bool handle_error_helper(const boost::program_options::options_description& desc, F parser) + { + try + { + return parser(); + } + catch (std::exception& e) + { + std::cerr << "Failed to parse arguments: " << e.what() << std::endl; + std::cerr << desc << std::endl; + return false; + } + catch (...) + { + std::cerr << "Failed to parse arguments: unknown exception" << std::endl; + std::cerr << desc << std::endl; + return false; + } + } + + template + bool has_arg(const boost::program_options::variables_map& vm, const arg_descriptor& arg) + { + auto value = vm[arg.name]; + return !value.empty(); + } + + + template + T get_arg(const boost::program_options::variables_map& vm, const arg_descriptor& arg) + { + return vm[arg.name].template as(); + } + + template<> + inline bool has_arg(const boost::program_options::variables_map& vm, const arg_descriptor& arg) + { + return get_arg(vm, arg); + } + + + extern const arg_descriptor arg_help; + extern const arg_descriptor arg_version; + extern const arg_descriptor arg_data_dir; + extern const arg_descriptor arg_config_file; + extern const arg_descriptor arg_os_version; + extern const arg_descriptor arg_log_dir; + extern const arg_descriptor arg_log_level; + extern const arg_descriptor arg_console; + extern const arg_descriptor arg_show_details; + extern const arg_descriptor arg_show_rpc_autodoc; +} diff --git a/src/common/crypto_boost_serialization.h b/src/common/crypto_boost_serialization.h new file mode 100644 index 00000000..310c8e92 --- /dev/null +++ b/src/common/crypto_boost_serialization.h @@ -0,0 +1,57 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include "crypto/crypto.h" + +namespace boost +{ + namespace serialization + { + //--------------------------------------------------- + template + inline void serialize(Archive &a, crypto::public_key &x, const boost::serialization::version_type ver) + { + a & reinterpret_cast(x); + } + template + inline void serialize(Archive &a, crypto::secret_key &x, const boost::serialization::version_type ver) + { + a & reinterpret_cast(x); + } + template + inline void serialize(Archive &a, crypto::key_derivation &x, const boost::serialization::version_type ver) + { + a & reinterpret_cast(x); + } + template + inline void serialize(Archive &a, crypto::key_image &x, const boost::serialization::version_type ver) + { + a & reinterpret_cast(x); + } + + template + inline void serialize(Archive &a, crypto::signature &x, const boost::serialization::version_type ver) + { + a & reinterpret_cast(x); + } + template + inline void serialize(Archive &a, crypto::hash &x, const boost::serialization::version_type ver) + { + a & reinterpret_cast(x); + } + } +} + +//} diff --git a/src/common/db_abstract_accessor.h b/src/common/db_abstract_accessor.h new file mode 100644 index 00000000..2f20dd34 --- /dev/null +++ b/src/common/db_abstract_accessor.h @@ -0,0 +1,1028 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include +#include +#include +#include "include_base_utils.h" + +#include "db_backend_base.h" +#include "misc_language.h" +#include "cache_helper.h" +#include "profile_tools.h" +#include "../serialization/serialization.h" +#include "epee/include/readwrite_lock.h" +#include "epee/include/math_helper.h" + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL "db" +// 'db' channel is disabled by default + +namespace tools +{ + namespace db + { + template + const char* key_to_ptr(const t_pod_key& k, size_t& s) + { + static_assert(std::is_pod::value, "t_pod_key must be a POD type."); + s = sizeof(k); + return reinterpret_cast(&k); + } + inline + const char* key_to_ptr(const std::string& k, size_t& s) + { + s = k.size(); + return k.data(); + } + template + void key_from_ptr(t_pod_key& k, const void* pkey, uint64_t ks) + { + static_assert(std::is_pod::value, "t_pod_key must be a POD type."); + CHECK_AND_ASSERT_THROW_MES(sizeof(t_pod_key) == ks, "size missmatch"); + CHECK_AND_ASSERT_THROW_MES(pkey, "wrog ptr(null)"); + k = *(t_pod_key*)pkey; + } + inline + void key_from_ptr(std::string& k, const void* pkey, uint64_t ks) + { + CHECK_AND_ASSERT_THROW_MES(pkey, "wrog ptr(null)"); + k.assign((const char*)pkey, static_cast(ks)); + } + + struct i_db_parent_to_container_callabck + { + virtual bool on_write_transaction_begin(){ return true; } + virtual bool on_write_transaction_commit(){ return true; } + virtual bool on_write_transaction_abort(){ return true; } + }; + + + /************************************************************************/ + /* */ + /************************************************************************/ + class basic_db_accessor + { + std::shared_ptr m_backend; + epee::critical_section m_binded_containers_lock; + std::set m_binded_containers; + + epee::critical_section m_transactions_stack_lock; + std::map > m_transactions_stack; + std::atomic m_is_open; + epee::shared_recursive_mutex& m_rwlock; + + public: + struct performance_data + { + epee::math_helper::average backend_set_pod_time; + epee::math_helper::average backend_set_t_time; + epee::math_helper::average set_serialize_t_time; + }; + private: + mutable std::unordered_map m_performance_data_map; + public: + basic_db_accessor(std::shared_ptr backend, epee::shared_recursive_mutex& rwlock) :m_backend(backend), m_rwlock(rwlock), m_is_open(false) + {} + ~basic_db_accessor() + { + close(); + } + + const performance_data& get_performance_data_for_handle(container_handle h) const { return m_performance_data_map[h]; } + + + bool bind_parent_container(i_db_parent_to_container_callabck* pcontainer) + { + CRITICAL_REGION_LOCAL(m_binded_containers_lock); + m_binded_containers.insert(pcontainer); + return true; + } + + bool unbind_parent_container(i_db_parent_to_container_callabck* pcontainer) + { + CRITICAL_REGION_LOCAL(m_binded_containers_lock); + auto it = m_binded_containers.find(pcontainer); + CHECK_AND_ASSERT_THROW_MES(it != m_binded_containers.end(), "Unable to unbind pointer"); + m_binded_containers.erase(it); + return true; + } + bool has_writer_tx_in_stack(const std::vector& ve) + { + for (auto v : ve) + { + if (!v) + return true; + } + return false; + } + bool begin_transaction(bool readonly = false) + { + bool r = m_backend->begin_transaction(readonly); + CRITICAL_REGION_LOCAL(m_transactions_stack_lock); + std::vector& this_thread_tx_stack = m_transactions_stack[std::this_thread::get_id()]; + + if (r) + { + bool need_to_brodcst_writer_tx = !has_writer_tx_in_stack(this_thread_tx_stack); + this_thread_tx_stack.push_back(readonly); + if (need_to_brodcst_writer_tx && !readonly) + { + LOG_PRINT_CYAN("[WRITE_TX_BEGIN]", LOG_LEVEL_2); + for (auto cnt_ptr : m_binded_containers) + { + cnt_ptr->on_write_transaction_begin(); + } + } + } + return r; + } + + bool begin_readonly_transaction()const + { + return const_cast(*this).begin_transaction(true); + } + + void commit_transaction()const + { + return const_cast(*this).commit_transaction(); + } + void commit_transaction() + { + bool r = false; + bool is_writer_tx = false; + { + CRITICAL_REGION_LOCAL(m_transactions_stack_lock); + std::vector& this_thread_tx_stack = m_transactions_stack[std::this_thread::get_id()]; + CHECK_AND_ASSERT_THROW_MES(this_thread_tx_stack.size(), "Internal error: this_thread_tx_stack.size = 0 at commit tx"); + is_writer_tx = !this_thread_tx_stack.back(); + } + + if (is_writer_tx) + m_rwlock.lock(); // wait all readers and writers to get exclusive access + + { + CRITICAL_REGION_LOCAL(m_transactions_stack_lock); + r = m_backend->commit_transaction(); //commit first and then switch cache isolation off (via on_write_transaction_commit() below) + + std::vector& this_thread_tx_stack = m_transactions_stack[std::this_thread::get_id()]; + CHECK_AND_ASSERT_THROW_MES(this_thread_tx_stack.size(), "Internal error: this_thread_tx_stack.size = 0 at commit tx"); + CHECK_AND_ASSERT_THROW_MES(!this_thread_tx_stack.back() == is_writer_tx, "Internal error: !this_thread_tx_stack.back() != is_writer_tx at commit tx"); + this_thread_tx_stack.pop_back(); + bool has_other_writers_on_stack = has_writer_tx_in_stack(this_thread_tx_stack); + if (is_writer_tx && !has_other_writers_on_stack) + { + LOG_PRINT_CYAN("[WRITE_TX_COMMIT]", LOG_LEVEL_2); + for (auto cnt_ptr : m_binded_containers) + { + cnt_ptr->on_write_transaction_commit(); // will cause cache isolation to be switched off + } + } + } + + if (is_writer_tx) + m_rwlock.unlock();//manual unlock + + CHECK_AND_ASSERT_THROW_MES(r, "failed to commit tx"); + } + void abort_transaction() + { + bool is_writer_tx = false; + { + CRITICAL_REGION_LOCAL(m_transactions_stack_lock); + std::vector& this_thread_tx_stack = m_transactions_stack[std::this_thread::get_id()]; + CHECK_AND_ASSERT_THROW_MES(this_thread_tx_stack.size(), "Internal error: this_thread_tx_stack.size = 0 at abort tx"); + CHECK_AND_ASSERT_THROW_MES(!this_thread_tx_stack.back(), "Internal error: abort on readonly tx"); + is_writer_tx = !this_thread_tx_stack.back(); + } + if (is_writer_tx) + m_rwlock.lock(); // wait all readers and writers to get exclusive access + + { + CRITICAL_REGION_LOCAL(m_transactions_stack_lock); + m_backend->abort_transaction(); // abort first and then switch cache isolation off (via on_write_transaction_abort() below) + + std::vector& this_thread_tx_stack = m_transactions_stack[std::this_thread::get_id()]; + CHECK_AND_ASSERT_THROW_MES(this_thread_tx_stack.size(), "Internal error: this_thread_tx_stack.size = 0 at abort tx"); + CHECK_AND_ASSERT_THROW_MES(!this_thread_tx_stack.back(), "Internal error: abort on readonly tx"); + this_thread_tx_stack.pop_back(); + bool has_other_writers_on_stack = has_writer_tx_in_stack(this_thread_tx_stack); + if (!has_other_writers_on_stack) + { + LOG_PRINT_CYAN("[WRITE_TX_ABORT]", LOG_LEVEL_2); + for (auto cnt_ptr : m_binded_containers) + { + cnt_ptr->on_write_transaction_abort(); // will cause cache isolation to be switched off + } + } + } + + if (is_writer_tx) + m_rwlock.unlock();//manual unlock + + } + + + std::shared_ptr get_backend() const + { + return m_backend; + } + + bool close() + { + m_is_open = false; + return m_backend->close(); + } + bool open(const std::string& path, uint64_t cache_sz = CACHE_SIZE) + { + bool r = m_backend->open(path, cache_sz); + if(r) + m_is_open = true; + + return r; + } + + bool is_open() + { + return m_is_open; + } + + uint64_t size(container_handle h) const + { + return m_backend->size(h); + } + + template + bool erase(container_handle h, const t_pod_key& k) + { + //TRY_ENTRY(); + size_t sk = 0; + const char* pk = key_to_ptr(k, sk); + + return m_backend->erase(h, pk, sk); + //CATCH_ENTRY_L0("get_t_object_from_db", false); + } + + template + bool get_t_object(container_handle h, const t_pod_key& k, t_object& obj) const + { + //TRY_ENTRY(); + std::string res_buff; + size_t sk = 0; + const char* pk = key_to_ptr(k, sk); + + if (!m_backend->get(h, pk, sk, res_buff)) + return false; + + return t_unserializable_object_from_blob(obj, res_buff); + //CATCH_ENTRY_L0("get_t_object_from_db", false); + } + + bool clear(container_handle h) + { + return m_backend->clear(h); + } + + template + bool set_t_object(container_handle h, const t_pod_key& k, t_object& obj) + { + performance_data& m_performance_data = m_performance_data_map[h]; + //TRY_ENTRY(); + std::string obj_buff; + TIME_MEASURE_START_PD(set_serialize_t_time); + ::t_serializable_object_to_blob(obj, obj_buff); + TIME_MEASURE_FINISH_PD(set_serialize_t_time); + + size_t sk = 0; + const char* pk = key_to_ptr(k, sk); + TIME_MEASURE_START_PD(backend_set_t_time); + bool r = m_backend->set(h, pk, sk, obj_buff.data(), obj_buff.size()); + TIME_MEASURE_FINISH_PD(backend_set_t_time); + return r; + //CATCH_ENTRY_L0("set_t_object_to_db", false); + } + + template + bool get_pod_object(container_handle h, const t_pod_key& k, t_pod_object& obj) const + { + static_assert(std::is_pod::value, "t_pod_object must be a POD type."); + + + //TRY_ENTRY(); + std::string res_buff; + size_t sk = 0; + const char* pk = key_to_ptr(k, sk); + + if (!m_backend->get(h, pk, sk, res_buff)) + return false; + + CHECK_AND_ASSERT_MES(sizeof(t_pod_object) == res_buff.size(), false, "sizes missmath at get_pod_object_from_db(). returned size = " + << res_buff.size() << "expected: " << sizeof(t_pod_object)); + + obj = *(t_pod_object*)res_buff.data(); + return true; + //CATCH_ENTRY_L0("get_t_object_from_db", false); + } + + template + bool set_pod_object(container_handle h, const t_pod_key& k, const t_pod_object& obj) + { + performance_data& m_performance_data = m_performance_data_map[h]; + static_assert(std::is_pod::value, "t_pod_object must be a POD type."); + size_t sk = 0; + const char* pk = key_to_ptr(k, sk); + + TIME_MEASURE_START_PD(backend_set_pod_time); + bool r = m_backend->set(h, pk, sk, (const char*)&obj, sizeof(obj)); + TIME_MEASURE_FINISH_PD(backend_set_pod_time); + if (!r) + return false; + + return true; + //CATCH_ENTRY_L0("get_t_object_from_db", false); + } + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + class key_value_pod_access_strategy + { + public: + template + static bool from_buff_to_obj(const void* pv, uint64_t vs, t_value& v) + { + CHECK_AND_ASSERT_THROW_MES(sizeof(t_value) == vs, "sizes missmath at get_pod_object_from_db(). returned size = " + << vs << "expected: " << sizeof(t_value)); + + v = *(t_value*)pv; + + return true; + } + + template + static void set(container_handle h, basic_db_accessor& bdb, const t_key& k, const t_value& v) + { + static_assert(std::is_pod::value, "t_value must be a POD type."); + bdb.set_pod_object(h, k, v); + } + template + static std::shared_ptr get(container_handle h, basic_db_accessor& bdb, const t_key& k) + { + static_assert(std::is_pod::value, "t_value must be a POD type."); + std::shared_ptr res(nullptr); + t_value v = AUTO_VAL_INIT(v); + if (bdb.get_pod_object(h, k, v)) + { + //TODO: remove one extra copy + res.reset(new t_value(v)); + } + return res; + } + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + class key_value_t_access_strategy + { + public: + template + static bool from_buff_to_obj(const void* pv, uint64_t vs, t_value& v) + { + std::string src_blob((const char*)pv, static_cast(vs)); + return t_unserializable_object_from_blob(v, src_blob);//::t_serializable_object_to_blob(v, res_buff); + } + + + + template + static void set(container_handle h, basic_db_accessor& bdb, const t_key& k, const t_value& v) + { + bdb.set_t_object(h, k, v); + } + template + static std::shared_ptr get(container_handle h, basic_db_accessor& bdb, const t_key& k) + { + std::shared_ptr res(nullptr); + t_value v = AUTO_VAL_INIT(v); + if (bdb.get_t_object(h, k, v)) + { + //TODO: remove one extra copy + res.reset(new t_value(v)); + } + return res; + } + }; + + /****************************************************************************************/ + /* to make easier selecting of strategy by true/false instead of long type definition */ + /****************************************************************************************/ + template + class access_strategy_selector; + + template<> + class access_strategy_selector: public key_value_t_access_strategy + {}; + + template<> + class access_strategy_selector: public key_value_pod_access_strategy + {}; + + /************************************************************************/ + /* */ + /************************************************************************/ + template + struct keys_accessor_cb : i_db_callback + { + t_cb m_cb; + keys_accessor_cb(t_cb cb) :m_cb(cb){} + bool on_enum_item(uint64_t i, const void* pkey, uint64_t ks, const void* pval, uint64_t vs) + { + t_key k = AUTO_VAL_INIT(k); + key_from_ptr(k, pkey, ks); + return m_cb(i, k); + } + }; + + template + struct items_accessor_cb : i_db_callback + { + t_cb m_cb; + items_accessor_cb(t_cb cb) :m_cb(cb){} + bool on_enum_item(uint64_t i, const void* pkey, uint64_t ks, const void* pval, uint64_t vs) + { + t_key k = AUTO_VAL_INIT(k); + t_value v = AUTO_VAL_INIT(v); + key_from_ptr(k, pkey, ks); + t_value_read_strategy::from_buff_to_obj(pval, vs, v); + return m_cb(i, k, v); + } + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + + template + class basic_key_value_accessor : public i_db_parent_to_container_callabck + { +#ifdef ENABLE_PROFILING + mutable epee::profile_tools::local_call_account m_get_profiler; + mutable epee::profile_tools::local_call_account m_set_profiler; + mutable epee::profile_tools::local_call_account m_explicit_get_profiler; + mutable epee::profile_tools::local_call_account m_explicit_set_profiler; + mutable epee::profile_tools::local_call_account m_commit_profiler; +#endif + mutable uint64_t size_cache; + mutable bool size_cache_valid; + protected: + container_handle m_h; + basic_db_accessor& bdb; + epee::misc_utils::isolation_lock m_isolation; + public: + typedef t_value t_value_type; + + basic_key_value_accessor(basic_db_accessor& db) : + bdb(db), + m_h(AUTO_VAL_INIT(m_h)), + size_cache(0), + size_cache_valid(false) + { + db.bind_parent_container(this); + } + + ~basic_key_value_accessor() + { + bdb.unbind_parent_container(this); + } + + virtual bool on_write_transaction_begin() + { + m_isolation.set_isolation_mode(); + return true; + } + virtual bool on_write_transaction_commit() + { + m_isolation.reset_isolation_mode(); + return true; + } + virtual bool on_write_transaction_abort() + { + m_isolation.reset_isolation_mode(); + return true; + } + + bool begin_transaction(bool read_only = false) + { + return bdb.begin_transaction(read_only); + } + void commit_transaction() + { + try + { + PROFILE_FUNC_ACC(m_commit_profiler); + bdb.commit_transaction(); + } + catch (...) + { + size_cache_valid = false; + throw; + } + } + void abort_transaction() + { + size_cache_valid = false; + bdb.abort_transaction(); + } + + bool init(const std::string& container_name) + { +#ifdef ENABLE_PROFILING + m_get_profiler.m_name = container_name +":get"; + m_set_profiler.m_name = container_name + ":set"; + m_explicit_get_profiler.m_name = container_name + ":explicit_get"; + m_explicit_set_profiler.m_name = container_name + ":explicit_set"; + m_commit_profiler.m_name = container_name + ":commit";; +#endif + return bdb.get_backend()->open_container(container_name, m_h); + } + + template + void enumerate_keys(t_cb cb) const + { + keys_accessor_cb local_enum_handler(cb); + bdb.get_backend()->enumerate(m_h, &local_enum_handler); + } + + template + void enumerate_items(t_cb cb)const + { + items_accessor_cb > local_enum_handler(cb); + bdb.get_backend()->enumerate(m_h, &local_enum_handler); + } + + template + void explicit_set(const t_explicit_key& k, const t_explicit_value& v) + { + PROFILE_FUNC_ACC(m_explicit_set_profiler); + size_cache_valid = false; + t_strategy::set(m_h, bdb, k, v); + } + + template + std::shared_ptr explicit_get(const t_explicit_key& k) + { + PROFILE_FUNC_ACC(m_explicit_get_profiler); + return t_strategy::template get(m_h, bdb, k); + } + + void set(const t_key& k, const t_value& v) + { + PROFILE_FUNC_ACC(m_set_profiler); + size_cache_valid = false; + access_strategy_selector::set(m_h, bdb, k, v); + } + + std::shared_ptr get(const t_key& k) const + { + PROFILE_FUNC_ACC(m_get_profiler); + return access_strategy_selector::template get(m_h, bdb, k); + } + + //find() and end() aliases for make easier porting std stuff + std::shared_ptr find(const t_key& k) const + { + return get(k); + } + + std::shared_ptr end() const + { + return std::shared_ptr(nullptr); + } + + uint64_t size() const + { + return m_isolation.isolated_access([&](bool allowed_cache) + { + if (allowed_cache && size_cache_valid) + { + return size_cache; + } + else + { + uint64_t res = bdb.size(m_h); + if (allowed_cache) + { + size_cache = res; + size_cache_valid = true; + } + return res; + } + }); + } + uint64_t size_no_cache() const + { + return bdb.size(m_h); + } + size_t clear() + { + bdb.clear(m_h); + m_isolation.isolated_write_access([&](){ + size_cache_valid = false; + return true; + }); + return true; + } + + bool erase_validate(const t_key& k) + { + auto res_ptr = this->get(k); + bdb.erase(m_h, k); + m_isolation.isolated_write_access([&](){ + size_cache_valid = false; + return true; + }); + return static_cast(res_ptr); + } + + + void erase(const t_key& k) + { + bdb.erase(m_h, k); + m_isolation.isolated_write_access([&](){ + size_cache_valid = false; + return true; + }); + } + + std::shared_ptr operator[] (const t_key& k) const + { + auto r = this->get(k); + CHECK_AND_ASSERT_THROW(r.get(), std::out_of_range("Out of range in basic_key_value_accessor")); + return r; + } + }; + + + + + /************************************************************************/ + /* */ + /************************************************************************/ + template + class cached_key_value_accessor : public basic_key_value_accessor + { + typedef basic_key_value_accessor base_class; + + + typedef epee::misc_utils::cache_with_write_isolation, 10000> cache_container_type; + //typedef epee::misc_utils::cache_dummy, 100000> cache_container_type; + mutable cache_container_type m_cache; + + + virtual bool on_write_transaction_abort() + { + clear_cache(); + return base_class::on_write_transaction_abort(); + } + + public: + struct performance_data + { + epee::math_helper::average hit_percent; + epee::math_helper::average read_cache_microsec; + epee::math_helper::average read_db_microsec; + epee::math_helper::average update_cache_microsec; + epee::math_helper::average write_to_cache_microsec; + epee::math_helper::average write_to_db_microsec; + }; + + cached_key_value_accessor(basic_db_accessor& db) : + basic_key_value_accessor(db), + m_cache(base_class::m_isolation) + { + + } + ~cached_key_value_accessor() + { + m_cache.clear(); //will clear cache isolated + } + + void clear_cache() const + { + m_cache.clear(); + } + + void set_cache_size(uint64_t max_cache_size) + { + m_cache.set_max_elements(max_cache_size); + } + + void set(const t_key& k, const t_value& v) + { + TIME_MEASURE_START_PD(write_to_db_microsec); + base_class::set(k, v); + TIME_MEASURE_FINISH_PD(write_to_db_microsec); + + TIME_MEASURE_START_PD(write_to_cache_microsec); + m_cache.set(k, std::shared_ptr(new t_value(v))); + TIME_MEASURE_FINISH_PD(write_to_cache_microsec); + } + + std::shared_ptr get(const t_key& k) const + { + std::shared_ptr res; + TIME_MEASURE_START_PD(read_cache_microsec); + bool r = m_cache.get(k, res); + TIME_MEASURE_FINISH_PD(read_cache_microsec); + if (r) + { + m_performance_data.hit_percent.push(100); + return res; + } + m_performance_data.hit_percent.push(0); + + TIME_MEASURE_START_PD(read_db_microsec); + res = base_class::get(k); + TIME_MEASURE_FINISH_PD(read_db_microsec); + if (res) + { + TIME_MEASURE_START_PD(update_cache_microsec); + m_cache.set(k, res); + TIME_MEASURE_FINISH_PD(update_cache_microsec); + } + return res; + } + + size_t clear() + { + m_cache.clear(); + return base_class::clear(); + } + + bool erase_validate(const t_key& k) + { + + auto res_ptr = base_class::erase_validate(k); + m_cache.erase(k); + return static_cast(res_ptr); + } + + std::shared_ptr operator[] (const t_key& k) const + { + return get(k); + } + + void erase(const t_key& k) + { + base_class::erase(k); + m_cache.erase(k); + } + + const performance_data& get_performance_data() const + { + return m_performance_data; + } + const typename basic_db_accessor::performance_data& get_performance_data_native() const + { + return base_class::bdb.get_performance_data_for_handle(base_class::m_h); + } + private: + mutable performance_data m_performance_data; + }; + + + /************************************************************************/ + /* */ + /************************************************************************/ + template + class solo_db_value + { + t_key m_key; + t_accessor& m_accessor; + public: + solo_db_value(const t_key& k, t_accessor& accessor) :m_accessor(accessor), m_key(k) + {} + + solo_db_value(const solo_db_value& v) :m_accessor(v.m_accessor), m_key(v.m_key) + {} + solo_db_value& operator=(const solo_db_value&) = delete; + + + t_value operator=(t_value v) + { + m_accessor.template explicit_set >(m_key, v); + return v; + } + + operator t_value() const + { + static_assert(std::is_pod::value, "t_value must be a POD type."); + + std::shared_ptr vptr = m_accessor.template explicit_get >(m_key); + if (vptr.get()) + { + return *vptr.get(); + } + return AUTO_VAL_INIT(t_value()); + } + }; + + +#pragma pack(push, 1) + struct guid_key + { + uint64_t a; + uint64_t b; + }; +#pragma pack(pop) + + //we use this suffix to keep elements count of sub-container, guid_key collision supposed to be impossible (almost) + // {E005D3C8-C9E9-4C2E-B94C-A40EC25505AD} + static const guid_key const_counter_suffix = + { 0xe005d3c8c9e94c2e, 0xb94ca40ec25550ad}; + + +#pragma pack(push, 1) + template + struct composite_key + { + t_key_a container_id; + t_key_b sufix; + }; + +// template +// struct container_counter_key_holder : public composite_key +// {}; +#pragma pack(pop) + + /************************************************************************/ + /* */ + /************************************************************************/ + + template + class basic_key_to_array_accessor : public basic_key_value_accessor, t_value, is_t_access_strategy> + { + typedef basic_key_value_accessor, t_value, is_t_access_strategy> basic_accessor_type; + +// template + solo_db_value, uint64_t, basic_accessor_type> + get_counter_accessor(const t_key& container_id) + { + + static_assert(std::is_pod::value, "t_pod_key must be a POD type."); + composite_key cc = { container_id, const_counter_suffix}; + + return solo_db_value, uint64_t, basic_accessor_type >(cc, *this); + } + +// template + const solo_db_value, uint64_t, basic_accessor_type > + get_counter_accessor(const t_key& container_id) const + { + + static_assert(std::is_pod::value, "t_pod_key must be a POD type."); + composite_key cc = { container_id, const_counter_suffix }; + + return solo_db_value, uint64_t, basic_accessor_type >(cc, const_cast(static_cast(*this))); + } + + public: + basic_key_to_array_accessor(basic_db_accessor& db) : basic_key_value_accessor, t_value, is_t_access_strategy>(db) + {} + + uint64_t get_item_size(const t_key& k) const + { + return get_counter_accessor(k); + } + + std::shared_ptr get_subitem(const t_key& k, uint64_t i) const + { + if (i >= get_item_size(k)) + { + LOG_ERROR("Out of bound access: itmes_count = " << get_item_size(k) << ", i = " << i); + throw std::out_of_range("In basic_key_to_array_accessor"); + } + composite_key ck{ k, i }; + return this->get(ck); + } + + void push_back_item(const t_key& k, const t_value& v) + { + auto counter = get_counter_accessor(k); + uint64_t new_index = counter; + counter = new_index+1; + composite_key ck{ k, new_index }; + this->set(ck, v); + } + + void pop_back_item(const t_key& k) + { + auto counter = get_counter_accessor(k); + uint64_t sz = static_cast(counter); + + CHECK_AND_ASSERT_MES(sz != 0, void(), "pop_back_item called on empty subitem"); + + composite_key ck{ k, sz - 1 }; + this->erase(ck); + counter = --sz; + } + + // removes all items by key k + void erase_items(const t_key& k) + { + auto counter = get_counter_accessor(k); + uint64_t sz = static_cast(counter); + + while (sz != 0) + { + composite_key ck{ k, sz - 1 }; + this->erase(ck); + --sz; + } + + counter = 0; + } + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + template + class array_accessor : public cached_key_value_accessor + { + public: + array_accessor(basic_db_accessor& db) : cached_key_value_accessor(db) + {} + void push_back(const t_value& v) + { + this->set(this->size(), v); + + } + void pop_back() + { + this->erase(this->size()-1); + } + std::shared_ptr back() const + { + auto res = this->get(this->size()-1); + CHECK_AND_ASSERT_THROW(res.get(), std::out_of_range(std::string("Out of range in array_accessor in call back(): size()=") + + std::to_string(this->size()) + + ", size_no_cache()=" + std::to_string(this->size_no_cache()) )); + return res; + } + + std::shared_ptr operator[] (const uint64_t& k) const + { + auto res = this->get(k); + CHECK_AND_ASSERT_THROW(res.get(), std::out_of_range(std::string("Out of range in array_accessor in call []: key = ") + + std::to_string(k) + + ", size_no_cache()=" + std::to_string(this->size_no_cache()))); + + return res; + } + + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + template + class reader_access + { + t_db& m_db; + bool got_transaction; + public: + reader_access(t_db& db) :m_db(db), got_transaction(false) + {} + + void lock() + { + //start read only transaction + if (m_db.is_open()) + { + m_db.begin_transaction(true); + got_transaction = true; + } + + } + void unlock() + { + if (got_transaction) + m_db.commit_transaction(); + + got_transaction = false; + } + + }; + + } +} + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL NULL diff --git a/src/common/db_backend_base.h b/src/common/db_backend_base.h new file mode 100644 index 00000000..db566d86 --- /dev/null +++ b/src/common/db_backend_base.h @@ -0,0 +1,51 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#ifndef ENV32BIT +#define CACHE_SIZE uint64_t(uint64_t(1UL * 128UL) * 1024UL * 1024UL * 1024UL) +#else +#define CACHE_SIZE (1 * 1024UL * 1024UL * 1024UL) +#endif + + +namespace tools +{ + namespace db + { + typedef size_t container_handle; + const uint64_t invalid_tx_id = 0; + struct i_db_callback + { + virtual bool on_enum_item(uint64_t i, const void* pkey, uint64_t ks, const void* pval, uint64_t vs) = 0; + }; + + struct stat_info + { + uint64_t tx_count; + uint64_t write_tx_count; + uint64_t map_size; + }; + + struct i_db_backend + { + virtual bool close()=0; + virtual bool begin_transaction(bool read_only = false) = 0; + virtual bool commit_transaction()=0; + virtual void abort_transaction()=0; + virtual bool open(const std::string& path, uint64_t cache_sz = CACHE_SIZE) = 0; + virtual bool open_container(const std::string& name, container_handle& h)=0; + virtual bool erase(container_handle h, const char* k, size_t s) = 0; + virtual uint64_t size(container_handle h) = 0; + virtual bool get(container_handle h, const char* k, size_t s, std::string& res_buff) = 0; + virtual bool set(container_handle h, const char* k, size_t s, const char* v, size_t vs) = 0; + virtual bool clear(container_handle h) = 0; + virtual bool enumerate(container_handle h, i_db_callback* pcb)=0; + virtual bool get_stat_info(stat_info& si) = 0; + virtual ~i_db_backend(){}; + }; + } +} \ No newline at end of file diff --git a/src/common/db_backend_leveldb.cpp b/src/common/db_backend_leveldb.cpp new file mode 100644 index 00000000..c408c43a --- /dev/null +++ b/src/common/db_backend_leveldb.cpp @@ -0,0 +1,109 @@ + +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// +// #pragma once +// #include "db_backend_leveldb.h" +// +// namespace tools +// { +// namespace db +// { +// level_db_backend : public i_db_backend +// { +// std::string m_path; +// db_handle m_pdb; +// public: +// basic_db() :m_pdb(nullptr) +// {} +// ~basic_db(){ close(); } +// bool close() +// { +// if (m_pdb) +// delete m_pdb; +// m_pdb = nullptr; +// +// return true; +// } +// +// void begin_transaction() +// { +// //leveldb is not supporting transactions yet +// } +// +// void commit_transaction() +// { +// //leveldb is not supporting transactions yet +// } +// +// +// bool open(const std::string& path) +// { +// m_path = path; +// close(); +// leveldb::Options options; +// options.create_if_missing = true; +// leveldb::Status status = leveldb::DB::Open(options, path, &m_pdb); +// if (!status.ok()) +// { +// LOG_ERROR("Unable to open/create database " << path << ", error: " << status.ToString()); +// return err_handle; +// } +// return true; +// } +// +// bool erase(const char* k, size s) +// { +// TRY_ENTRY(); +// leveldb::WriteOptions wo; +// wo.sync = true; +// leveldb::Status s = m_pdb->Delete(wo, leveldb::Slice(k, s)); +// if (!s.ok()) +// return false; +// +// return true; +// CATCH_ENTRY_L0("get_t_object_from_db", false); +// } +// +// +// bool get(const char* k, size s, std::string& res_buff) +// { +// TRY_ENTRY(); +// leveldb::ReadOptions ro; +// leveldb::Status s = m_pdb->Get(ro, leveldb::Slice(k, s), &res_buff); +// if (!s.ok()) +// return false; +// +// CATCH_ENTRY_L0("get_t_object_from_db", false); +// } +// +// bool clear() +// { +// close(); +// boost::system::error_code ec; +// bool res = boost::filesystem::remove_all(m_path, ec); +// if (!res) +// { +// LOG_ERROR("Failed to remove db file " << m_path << ", why: " << ec); +// return false; +// } +// return open(m_path); +// } +// +// bool set(const char* k, size s, const char* v, size vs) +// { +// TRY_ENTRY(); +// leveldb::WriteOptions wo; +// wo.sync = true; +// leveldb::Status s = m_pdb->Put(wo, leveldb::Slice(k, s), leveldb::Slice(v, vs)); +// if (!s.ok()) +// return false; +// +// return true; +// CATCH_ENTRY_L0("set_t_object_to_db", false); +// } +// }; +// } +// } diff --git a/src/common/db_backend_leveldb.h b/src/common/db_backend_leveldb.h new file mode 100644 index 00000000..541f3d64 --- /dev/null +++ b/src/common/db_backend_leveldb.h @@ -0,0 +1,46 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include "include_base_utils.h" + +// #include "db_backend_base.h" +// +// #include "currency_db_base.h" +// #include "leveldb/db.h" +// #include "common/boost_serialization_helper.h" +// #include "common/difficulty_boost_serialization.h" +// #include "currency_format_utils.h" +// +// +// namespace tools +// { +// namespace db +// { +// typedef leveldb::DB* db_handle; +// +// static const db_handle err_handle = nullptr; +// +// class level_db_backend : public i_db_backend +// { +// std::string m_path; +// db_handle m_pdb; +// public: +// level_db_backend() :m_pdb(nullptr) +// {} +// ~level_db_backend(){ close(); } +// bool close(); +// void begin_transaction(); +// void commit_transaction(); +// bool open(const std::string& path); +// bool erase(const char* k, size s); +// bool get(const char* k, size s, std::string& res_buff); +// bool clear(); +// bool set(const char* k, size s, const char* v, size vs); +// }; +// } +// } + + diff --git a/src/common/db_backend_lmdb.cpp b/src/common/db_backend_lmdb.cpp new file mode 100644 index 00000000..204c1a9b --- /dev/null +++ b/src/common/db_backend_lmdb.cpp @@ -0,0 +1,366 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "db_backend_lmdb.h" +#include "misc_language.h" +#include "string_coding.h" +#include "profile_tools.h" + +#define BUF_SIZE 1024 + +#define CHECK_AND_ASSERT_MESS_LMDB_DB(rc, ret, mess) CHECK_AND_ASSERT_MES(res == MDB_SUCCESS, ret, "[DB ERROR]:(" << rc << ")" << mdb_strerror(rc) << ", [message]: " << mess); + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL "lmdb" +// 'lmdb' channel is disabled by default + +namespace tools +{ + namespace db + { + lmdb_db_backend::lmdb_db_backend() : m_penv(AUTO_VAL_INIT(m_penv)) + { + + } + lmdb_db_backend::~lmdb_db_backend() + { + close(); + } + + bool lmdb_db_backend::open(const std::string& path_, uint64_t cache_sz) + { + int res = 0; + res = mdb_env_create(&m_penv); + CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_env_create"); + + res = mdb_env_set_maxdbs(m_penv, 15); + CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_env_set_maxdbs"); + + res = mdb_env_set_mapsize(m_penv, cache_sz); + CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_env_set_mapsize"); + + m_path = path_; +#ifdef WIN32 + m_path = epee::string_encoding::convert_ansii_to_utf8(m_path); +#endif + + res = mdb_env_open(m_penv, m_path.c_str(), MDB_NORDAHEAD , 0644); + CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_env_open, m_path=" << m_path); + + return true; + } + + bool lmdb_db_backend::open_container(const std::string& name, container_handle& h) + { + + MDB_dbi dbi = AUTO_VAL_INIT(dbi); + begin_transaction(); + int res = mdb_dbi_open(get_current_tx(), name.c_str(), MDB_CREATE, &dbi); + CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_dbi_open with container name: " << name); + commit_transaction(); + h = static_cast(dbi); + return true; + } + + bool lmdb_db_backend::close() + { + { + std::lock_guard lock(m_cs); + for (auto& tx_thread : m_txs) + { + for (auto txe : tx_thread.second) + { + int res = mdb_txn_commit(txe.ptx); + if (res != MDB_SUCCESS) + { + LOG_ERROR("[DB ERROR]: On close tranactions: " << mdb_strerror(res)); + } + } + } + + m_txs.clear(); + } + if (m_penv) + { + mdb_env_close(m_penv); + m_penv = nullptr; + } + return true; + } + + bool lmdb_db_backend::begin_transaction(bool read_only) + { + if (!read_only) + { + LOG_PRINT_CYAN("[DB " << m_path << "] WRITE LOCKED", LOG_LEVEL_3); + CRITICAL_SECTION_LOCK(m_write_exclusive_lock); + } + PROFILE_FUNC("lmdb_db_backend::begin_transaction"); + { + std::lock_guard lock(m_cs); + CHECK_AND_ASSERT_THROW_MES(m_penv, "m_penv==null, db closed"); + transactions_list& rtxlist = m_txs[std::this_thread::get_id()]; + MDB_txn* pparent_tx = nullptr; + MDB_txn* p_new_tx = nullptr; + if (rtxlist.size()) + pparent_tx = rtxlist.back().ptx; + + + if (pparent_tx && read_only) + { + ++rtxlist.back().count; + } + else + { + int res = 0; + unsigned int flags = 0; + if (read_only) + flags += MDB_RDONLY; + + CHECK_AND_ASSERT_THROW_MES(m_penv, "m_penv==null, db closed"); + res = mdb_txn_begin(m_penv, pparent_tx, flags, &p_new_tx); + CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_txn_begin"); + + rtxlist.push_back(tx_entry()); + rtxlist.back().count = read_only ? 1 : 0; + rtxlist.back().ptx = p_new_tx; + rtxlist.back().read_only = read_only; + } + } + + + LOG_PRINT_L4("[DB] Transaction started"); + return true; + } + + MDB_txn* lmdb_db_backend::get_current_tx() + { + std::lock_guard lock(m_cs); + auto& rtxlist = m_txs[std::this_thread::get_id()]; + CHECK_AND_ASSERT_MES(rtxlist.size(), nullptr, "Unable to find active tx for thread " << std::this_thread::get_id()); + return rtxlist.back().ptx; + } + + bool lmdb_db_backend::pop_tx_entry(tx_entry& txe) + { + std::lock_guard lock(m_cs); + auto it = m_txs.find(std::this_thread::get_id()); + CHECK_AND_ASSERT_MES(it != m_txs.end(), false, "[DB] Unable to find id cor current thread"); + CHECK_AND_ASSERT_MES(it->second.size(), false, "[DB] No active tx for current thread"); + + txe = it->second.back(); + + if (it->second.back().read_only && it->second.back().count == 0) + { + LOG_ERROR("Internal db tx state error: read_only and count readers == 0"); + } + + if ((it->second.back().read_only && it->second.back().count < 2) || (!it->second.back().read_only && it->second.back().count < 1)) + { + it->second.pop_back(); + if (!it->second.size()) + m_txs.erase(it); + } + else + { + --it->second.back().count; + } + return true; + } + + bool lmdb_db_backend::commit_transaction() + { + PROFILE_FUNC("lmdb_db_backend::commit_transaction"); + { + tx_entry txe = AUTO_VAL_INIT(txe); + bool r = pop_tx_entry(txe); + CHECK_AND_ASSERT_MES(r, false, "Unable to pop_tx_entry"); + + if (txe.count == 0 || (txe.read_only && txe.count == 1)) + { + int res = 0; + res = mdb_txn_commit(txe.ptx); + CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_txn_commit (error " << res << ")"); + if (!txe.read_only && !txe.count) + { + CRITICAL_SECTION_UNLOCK(m_write_exclusive_lock); + LOG_PRINT_CYAN("[DB " << m_path << "] WRITE UNLOCKED", LOG_LEVEL_3); + } + } + } + LOG_PRINT_L4("[DB] Transaction committed"); + return true; + } + + void lmdb_db_backend::abort_transaction() + { + { + tx_entry txe = AUTO_VAL_INIT(txe); + bool r = pop_tx_entry(txe); + CHECK_AND_ASSERT_MES(r, void(), "Unable to pop_tx_entry"); + if (txe.count == 0 || (txe.read_only && txe.count == 1)) + { + mdb_txn_abort(txe.ptx); + if (!txe.read_only && txe.count) + { + CRITICAL_SECTION_UNLOCK(m_write_exclusive_lock); + LOG_PRINT_CYAN("[DB " << m_path << "] WRITE UNLOCKED(ABORTED)", LOG_LEVEL_3); + } + } + + + } + LOG_PRINT_L4("[DB] Transaction aborted"); + } + + bool lmdb_db_backend::erase(container_handle h, const char* k, size_t ks) + { + int res = 0; + MDB_val key = AUTO_VAL_INIT(key); + key.mv_data = (void*)k; + key.mv_size = ks; + + res = mdb_del(get_current_tx(), static_cast(h), &key, nullptr); + if (res == MDB_NOTFOUND) + return false; + CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_del"); + return true; + } + + bool lmdb_db_backend::have_tx() + { + std::lock_guard lock(m_cs); + auto it = m_txs.find(std::this_thread::get_id()); + if (it == m_txs.end()) + return false; + return it->second.size() ? true : false; + } + + bool lmdb_db_backend::get(container_handle h, const char* k, size_t ks, std::string& res_buff) + { + PROFILE_FUNC("lmdb_db_backend::get"); + int res = 0; + MDB_val key = AUTO_VAL_INIT(key); + MDB_val data = AUTO_VAL_INIT(data); + key.mv_data = (void*)k; + key.mv_size = ks; + bool need_to_commit = false; + if (!have_tx()) + { + need_to_commit = true; + begin_transaction(true); + } + + res = mdb_get(get_current_tx(), static_cast(h), &key, &data); + + if (need_to_commit) + commit_transaction(); + + if (res == MDB_NOTFOUND) + return false; + + CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_get, h: " << h << ", ks: " << ks); + res_buff.assign((const char*)data.mv_data, data.mv_size); + return true; + } + + bool lmdb_db_backend::clear(container_handle h) + { + int res = mdb_drop(get_current_tx(), static_cast(h), 0); + CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_drop"); + return true; + } + + uint64_t lmdb_db_backend::size(container_handle h) + { + PROFILE_FUNC("lmdb_db_backend::size"); + MDB_stat container_stat = AUTO_VAL_INIT(container_stat); + bool need_to_commit = false; + if (!have_tx()) + { + need_to_commit = true; + begin_transaction(true); + } + int res = mdb_stat(get_current_tx(), static_cast(h), &container_stat); + if (need_to_commit) + commit_transaction(); + CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_stat"); + return container_stat.ms_entries; + } + + bool lmdb_db_backend::set(container_handle h, const char* k, size_t ks, const char* v, size_t vs) + { + PROFILE_FUNC("lmdb_db_backend::set"); + int res = 0; + MDB_val key = AUTO_VAL_INIT(key); + MDB_val data = AUTO_VAL_INIT(data); + key.mv_data = (void*)k; + key.mv_size = ks; + data.mv_data = (void*)v; + data.mv_size = vs; + + res = mdb_put(get_current_tx(), static_cast(h), &key, &data, 0); + CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_put"); + return true; + } + bool lmdb_db_backend::enumerate(container_handle h, i_db_callback* pcb) + { + CHECK_AND_ASSERT_MES(pcb, false, "null capback ptr passed to enumerate"); + MDB_val key = AUTO_VAL_INIT(key); + MDB_val data = AUTO_VAL_INIT(data); + + bool need_to_commit = false; + if (!have_tx()) + { + need_to_commit = true; + begin_transaction(true); + } + MDB_cursor* cursor_ptr = nullptr; + int res = mdb_cursor_open(get_current_tx(), static_cast(h), &cursor_ptr); + CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_cursor_open"); + CHECK_AND_ASSERT_MES(cursor_ptr, false, "cursor_ptr is null after mdb_cursor_open"); + + uint64_t count = 0; + do + { + int res = mdb_cursor_get(cursor_ptr, &key, &data, MDB_NEXT); + if (res == MDB_NOTFOUND) + break; + if (!pcb->on_enum_item(count, key.mv_data, key.mv_size, data.mv_data, data.mv_size)) + break; + count++; + } while (cursor_ptr); + + mdb_cursor_close(cursor_ptr); + if (need_to_commit) + commit_transaction(); + return true; + } + + bool lmdb_db_backend::get_stat_info(tools::db::stat_info& si) + { + si = AUTO_VAL_INIT_T(tools::db::stat_info); + + MDB_envinfo ei = AUTO_VAL_INIT(ei); + mdb_env_info(m_penv, &ei); + si.map_size = ei.me_mapsize; + + std::lock_guard lock(m_cs); + for (auto& e : m_txs) + { + for (auto& pr : e.second) + { + ++si.tx_count; + if(!pr.read_only) + ++si.write_tx_count; + } + } + return true; + } + } +} + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL NULL \ No newline at end of file diff --git a/src/common/db_backend_lmdb.h b/src/common/db_backend_lmdb.h new file mode 100644 index 00000000..f41f3e35 --- /dev/null +++ b/src/common/db_backend_lmdb.h @@ -0,0 +1,66 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include + + +#include "include_base_utils.h" + +#include "db_backend_base.h" +#include "db/liblmdb/lmdb.h" + + +namespace tools +{ + namespace db + { + + + + class lmdb_db_backend : public i_db_backend + { + + struct tx_entry + { + MDB_txn* ptx; + bool read_only; // needed for thread-top transaction, for figure out if we need to unlock exclusive access + size_t count; //count of read-only nested emulated transactions + }; + typedef std::list transactions_list; + + + std::string m_path; + MDB_env *m_penv; + + boost::recursive_mutex m_cs; + boost::recursive_mutex m_write_exclusive_lock; + std::map m_txs; // size_t -> count of nested read_only transactions + bool pop_tx_entry(tx_entry& txe); + public: + lmdb_db_backend(); + ~lmdb_db_backend(); + + //----------------- i_db_backend ----------------------------------------------------- + bool close(); + bool begin_transaction(bool read_only = false); + bool commit_transaction(); + void abort_transaction(); + bool open(const std::string& path, uint64_t cache_sz = CACHE_SIZE); + bool open_container(const std::string& name, container_handle& h); + bool erase(container_handle h, const char* k, size_t s); + bool get(container_handle h, const char* k, size_t s, std::string& res_buff); + bool clear(container_handle h); + uint64_t size(container_handle h); + bool set(container_handle h, const char* k, size_t s, const char* v, size_t vs); + bool enumerate(container_handle h, i_db_callback* pcb); + bool get_stat_info(tools::db::stat_info& si); + //------------------------------------------------------------------------------------- + bool have_tx(); + MDB_txn* get_current_tx(); + + }; + } +} \ No newline at end of file diff --git a/src/common/difficulty_boost_serialization.h b/src/common/difficulty_boost_serialization.h new file mode 100644 index 00000000..3630423f --- /dev/null +++ b/src/common/difficulty_boost_serialization.h @@ -0,0 +1,69 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include + +namespace boost +{ + namespace serialization + { + //--------------------------------------------------- + template + inline void serialize(archive_t &a, currency::wide_difficulty_type &x, const boost::serialization::version_type ver) + { + if(archive_t::is_loading::value) + { + //load high part + uint64_t v = 0; +#ifdef DEBUG_DIFFICULTY_SERIALIZATION + std::cout << "loading" << ENDL; +#endif + a & v; + x = v; +#ifdef DEBUG_DIFFICULTY_SERIALIZATION + std::cout << "hight part: " << std::hex << v << ENDL; +#endif + //load low part + x = x << 64; + a & v; +#ifdef DEBUG_DIFFICULTY_SERIALIZATION + std::cout << "low part: " << std::hex << v << ENDL; +#endif + x += v; +#ifdef DEBUG_DIFFICULTY_SERIALIZATION + std::cout << "loaded value: " << std::hex << x << ENDL; +#endif + }else + { +#ifdef DEBUG_DIFFICULTY_SERIALIZATION + std::cout << "storing" << ENDL; +#endif + //store high part + currency::wide_difficulty_type x_ = x; +#ifdef DEBUG_DIFFICULTY_SERIALIZATION + std::cout << "original: " << std::hex << x_ << ENDL; +#endif + x_ = x_ >> 64; + uint64_t v = x_.convert_to(); +#ifdef DEBUG_DIFFICULTY_SERIALIZATION + std::cout << "hight part: " << std::hex << v << ENDL; +#endif + a & v; + //store low part + x_ = x; + x_ = x_ << 64; + x_ = x_ >> 64; + v = x_.convert_to(); +#ifdef DEBUG_DIFFICULTY_SERIALIZATION + std::cout << "low part: " << std::hex << v << ENDL; +#endif + a & v; + } + } + } +} diff --git a/src/common/int-util.h b/src/common/int-util.h new file mode 100644 index 00000000..9eff50be --- /dev/null +++ b/src/common/int-util.h @@ -0,0 +1,237 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +#include +#include + + +static inline uint32_t rol32(uint32_t x, int r) { + static_assert(sizeof(uint32_t) == sizeof(unsigned int), "this code assumes 32-bit integers"); + return _rotl(x, r); +} + +static inline uint64_t rol64(uint64_t x, int r) { + return _rotl64(x, r); +} + +#else + +static inline uint32_t rol32(uint32_t x, int r) { + return (x << (r & 31)) | (x >> (-r & 31)); +} + +static inline uint64_t rol64(uint64_t x, int r) { + return (x << (r & 63)) | (x >> (-r & 63)); +} + +#endif + +static inline uint64_t hi_dword(uint64_t val) { + return val >> 32; +} + +static inline uint64_t lo_dword(uint64_t val) { + return val & 0xFFFFFFFF; +} + +static inline uint64_t mul128_manually(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi) { + // multiplier = ab = a * 2^32 + b + // multiplicand = cd = c * 2^32 + d + // ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d + uint64_t a = hi_dword(multiplier); + uint64_t b = lo_dword(multiplier); + uint64_t c = hi_dword(multiplicand); + uint64_t d = lo_dword(multiplicand); + + uint64_t ac = a * c; + uint64_t ad = a * d; + uint64_t bc = b * c; + uint64_t bd = b * d; + + uint64_t adbc = ad + bc; + uint64_t adbc_carry = adbc < ad ? 1 : 0; + + // multiplier * multiplicand = product_hi * 2^64 + product_lo + uint64_t product_lo = bd + (adbc << 32); + uint64_t product_lo_carry = product_lo < bd ? 1 : 0; + *product_hi = ac + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry; + assert(ac <= *product_hi); + + return product_lo; +} + +static inline uint64_t div_with_reminder(uint64_t dividend, uint32_t divisor, uint32_t* remainder) { + dividend |= ((uint64_t)*remainder) << 32; + *remainder = dividend % divisor; + return dividend / divisor; +} + +// Long division with 2^32 base +static inline uint32_t div128_32_manually(uint64_t dividend_hi, uint64_t dividend_lo, uint32_t divisor, uint64_t* quotient_hi, uint64_t* quotient_lo) { + uint64_t dividend_dwords[4]; + uint32_t remainder = 0; + + dividend_dwords[3] = hi_dword(dividend_hi); + dividend_dwords[2] = lo_dword(dividend_hi); + dividend_dwords[1] = hi_dword(dividend_lo); + dividend_dwords[0] = lo_dword(dividend_lo); + + *quotient_hi = div_with_reminder(dividend_dwords[3], divisor, &remainder) << 32; + *quotient_hi |= div_with_reminder(dividend_dwords[2], divisor, &remainder); + *quotient_lo = div_with_reminder(dividend_dwords[1], divisor, &remainder) << 32; + *quotient_lo |= div_with_reminder(dividend_dwords[0], divisor, &remainder); + + return remainder; +} + +static inline uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi) +{ +// #if defined(_MSC_VER) +// return _umul128(multiplier, multiplicand, product_hi); +// #elif defined(__GNUC__) +// __uint128_t product = ((__uint128_t)multiplier) * multiplicand; +// *product_hi = (uint64_t)(product >> 64); +// return ((uint64_t)product) & ~(UINT64_C(0)); +// #else + return mul128_manually(multiplier, multiplicand, product_hi); +//#endif*/ +} +//*/ + +static inline uint32_t div128_32(uint64_t dividend_hi, uint64_t dividend_lo, uint32_t divisor, uint64_t* quotient_hi, uint64_t* quotient_lo) +{ +// #if defined(__GNUC__) +// __uint128_t dividend = (((__uint128_t)dividend_hi) << 64) | dividend_lo; +// __uint128_t quotient = dividend / divisor; +// __uint128_t reminder = dividend % divisor; +// *quotient_hi = (uint64_t)(quotient >> 64); +// *quotient_lo = ((uint64_t)quotient) & ~(UINT64_C(0)); +// return (uint32_t)reminder; +// #else + return div128_32_manually(dividend_hi, dividend_lo, divisor, quotient_hi, quotient_lo); +//#endif +} +//*/ +#define IDENT32(x) ((uint32_t) (x)) +#define IDENT64(x) ((uint64_t) (x)) + +#define SWAP32(x) ((((uint32_t) (x) & 0x000000ff) << 24) | \ + (((uint32_t) (x) & 0x0000ff00) << 8) | \ + (((uint32_t) (x) & 0x00ff0000) >> 8) | \ + (((uint32_t) (x) & 0xff000000) >> 24)) +#define SWAP64(x) ((((uint64_t) (x) & 0x00000000000000ff) << 56) | \ + (((uint64_t) (x) & 0x000000000000ff00) << 40) | \ + (((uint64_t) (x) & 0x0000000000ff0000) << 24) | \ + (((uint64_t) (x) & 0x00000000ff000000) << 8) | \ + (((uint64_t) (x) & 0x000000ff00000000) >> 8) | \ + (((uint64_t) (x) & 0x0000ff0000000000) >> 24) | \ + (((uint64_t) (x) & 0x00ff000000000000) >> 40) | \ + (((uint64_t) (x) & 0xff00000000000000) >> 56)) + +static inline uint32_t ident32(uint32_t x) { return x; } +static inline uint64_t ident64(uint64_t x) { return x; } + +static inline uint32_t swap32(uint32_t x) { + x = ((x & 0x00ff00ff) << 8) | ((x & 0xff00ff00) >> 8); + return (x << 16) | (x >> 16); +} +static inline uint64_t swap64(uint64_t x) { + x = ((x & 0x00ff00ff00ff00ff) << 8) | ((x & 0xff00ff00ff00ff00) >> 8); + x = ((x & 0x0000ffff0000ffff) << 16) | ((x & 0xffff0000ffff0000) >> 16); + return (x << 32) | (x >> 32); +} + +#if defined(__GNUC__) +#define UNUSED __attribute__((unused)) +#else +#define UNUSED +#endif +static inline void mem_inplace_ident(void *mem UNUSED, size_t n UNUSED) { } +#undef UNUSED + +static inline void mem_inplace_swap32(void *mem, size_t n) { + size_t i; + for (i = 0; i < n; i++) { + ((uint32_t *) mem)[i] = swap32(((const uint32_t *) mem)[i]); + } +} +static inline void mem_inplace_swap64(void *mem, size_t n) { + size_t i; + for (i = 0; i < n; i++) { + ((uint64_t *) mem)[i] = swap64(((const uint64_t *) mem)[i]); + } +} + +static inline void memcpy_ident32(void *dst, const void *src, size_t n) { + memcpy(dst, src, 4 * n); +} +static inline void memcpy_ident64(void *dst, const void *src, size_t n) { + memcpy(dst, src, 8 * n); +} + +static inline void memcpy_swap32(void *dst, const void *src, size_t n) { + size_t i; + for (i = 0; i < n; i++) { + ((uint32_t *) dst)[i] = swap32(((const uint32_t *) src)[i]); + } +} +static inline void memcpy_swap64(void *dst, const void *src, size_t n) { + size_t i; + for (i = 0; i < n; i++) { + ((uint64_t *) dst)[i] = swap64(((const uint64_t *) src)[i]); + } +} + +#if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN) +static_assert(false, "BYTE_ORDER is undefined. Perhaps, GNU extensions are not enabled"); +#endif + +#if BYTE_ORDER == LITTLE_ENDIAN +#define SWAP32LE IDENT32 +#define SWAP32BE SWAP32 +#define swap32le ident32 +#define swap32be swap32 +#define mem_inplace_swap32le mem_inplace_ident +#define mem_inplace_swap32be mem_inplace_swap32 +#define memcpy_swap32le memcpy_ident32 +#define memcpy_swap32be memcpy_swap32 +#define SWAP64LE IDENT64 +#define SWAP64BE SWAP64 +#define swap64le ident64 +#define swap64be swap64 +#define mem_inplace_swap64le mem_inplace_ident +#define mem_inplace_swap64be mem_inplace_swap64 +#define memcpy_swap64le memcpy_ident64 +#define memcpy_swap64be memcpy_swap64 +#endif + +#if BYTE_ORDER == BIG_ENDIAN +#define SWAP32BE IDENT32 +#define SWAP32LE SWAP32 +#define swap32be ident32 +#define swap32le swap32 +#define mem_inplace_swap32be mem_inplace_ident +#define mem_inplace_swap32le mem_inplace_swap32 +#define memcpy_swap32be memcpy_ident32 +#define memcpy_swap32le memcpy_swap32 +#define SWAP64BE IDENT64 +#define SWAP64LE SWAP64 +#define swap64be ident64 +#define swap64le swap64 +#define mem_inplace_swap64be mem_inplace_ident +#define mem_inplace_swap64le mem_inplace_swap64 +#define memcpy_swap64be memcpy_ident64 +#define memcpy_swap64le memcpy_swap64 +#endif diff --git a/src/common/make_hashable.h b/src/common/make_hashable.h new file mode 100644 index 00000000..af18f478 --- /dev/null +++ b/src/common/make_hashable.h @@ -0,0 +1,39 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include +#include + +#define POD_MAKE_COMPARABLE(space, type) \ +namespace space { \ + inline bool operator==(const type &_v1, const type &_v2) { \ + return std::memcmp(&_v1, &_v2, sizeof(type)) == 0; \ + } \ + inline bool operator!=(const type &_v1, const type &_v2) { \ + return std::memcmp(&_v1, &_v2, sizeof(type)) != 0; \ + } \ +} + +#define POD_MAKE_HASHABLE(space, type) \ + POD_MAKE_COMPARABLE(space, type) \ +namespace space { \ + static_assert(sizeof(std::size_t) <= sizeof(type), "Size of " #type " must be at least that of size_t"); \ + inline std::size_t hash_value(const type &_v) { \ + return reinterpret_cast(_v); \ + } \ +} \ +namespace std { \ + template<> \ + struct hash { \ + std::size_t operator()(const space::type &_v) const { \ + return reinterpret_cast(_v); \ + } \ + }; \ +} diff --git a/src/common/median_db_cache.h b/src/common/median_db_cache.h new file mode 100644 index 00000000..2e2dea50 --- /dev/null +++ b/src/common/median_db_cache.h @@ -0,0 +1,133 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include "misc_language.h" + +namespace tools +{ +#define LOC_INT_ERR(cond, msg) CHECK_AND_ASSERT_THROW_MES(cond, "internal error in median_db_cache: " << msg << ENDL << *this) + template + class median_db_cache : public epee::misc_utils::median_helper + { + typedef epee::misc_utils::median_helper super_t; + struct db_entry_type + { + key k; + associated_data d; + }; + + //m_tx_median_helper; + typedef tools::db::cached_key_value_accessor median_db_container; + median_db_container m_median_container; + uint64_t m_counter_hi; + uint64_t m_counter_lo; + bool m_is_loading_from_db; + + bool load_items_from_db() + { + std::map loaded_entries; + LOG_PRINT_L0("Loading median from db cache..."); + m_median_container.enumerate_items([&](uint64_t i, uint64_t index, const db_entry_type& entry) + { + //adjust counters + if (index > m_counter_hi) + m_counter_hi = index; + if (index < m_counter_lo) + m_counter_lo = index; + loaded_entries[index] = entry; + return true; + }); + LOG_PRINT_L0("Loaded " << loaded_entries.size() << " items, building median cache..."); + + m_is_loading_from_db = true; + for (auto i : loaded_entries) + { + this->push_item(i.second.k, i.second.d); + } + m_is_loading_from_db = false; + LOG_PRINT_L0("Median cache build OK"); + return true; + } + virtual void handle_add_front_item(const key& k, const associated_data& ad) + { + if (m_is_loading_from_db) + return; + db_entry_type det = AUTO_VAL_INIT(det); + det.k = k; + det.d = ad; + m_median_container.set(++m_counter_hi, det); + + //in case if it was totally empty at init(which is very doubtful) + if (m_counter_lo == std::numeric_limits::max()) + m_counter_lo = m_counter_hi; + + } + virtual void handle_remove_front_item(const key& k) + { + LOC_INT_ERR(!m_is_loading_from_db, "m_is_loading_from_db is true"); + LOC_INT_ERR(m_median_container.erase_validate(m_counter_hi), "erase_validate failed"); + --m_counter_hi; + //TODO: check coretests and make a decision on what to do with the following check + //LOC_INT_ERR(m_counter_lo <= m_counter_hi, "handle_remove_front_item: m_counter_lo(" << m_counter_lo << ") > m_counter_hi(" << m_counter_hi << ")"); + } + virtual void handle_purge_back_item() + { + LOC_INT_ERR(m_counter_lo < m_counter_hi, "handle_purge_back_item: m_counter_lo(" << m_counter_lo << ") >= m_counter_hi(" << m_counter_hi << ")"); + m_median_container.erase(m_counter_lo++); + } + + + + public: + median_db_cache(db::basic_db_accessor& db) : + m_median_container(db), + m_counter_hi(0), + m_counter_lo(std::numeric_limits::max()), + m_is_loading_from_db(false) + { + + } + bool init(const std::string& name) + { + bool r = m_median_container.init(name); + CHECK_AND_ASSERT_MES(r, false, "Failed to init m_median_container"); + return load_items_from_db(); + } + + ~median_db_cache() + { + } + + void clear() + { + super_t::clear(); + m_median_container.clear(); + m_counter_hi = 0; + m_counter_lo = std::numeric_limits::max(); + } + + template + friend std::ostream& operator<<(std::ostream& ss, const median_db_cache &mdbc); + }; // class median_db_cache +#undef LOC_INT_ERR + + template + inline std::ostream& operator<<(std::ostream& s, const median_db_cache &mdbc) + { + s << "median_db_cache<" << typeid(key_t).name() << ", " << typeid(associated_data_t).name() << "> instance 0x" << &mdbc << ENDL + << " m_counter_lo: " << mdbc.m_counter_lo << ENDL + << " m_counter_hi: " << mdbc.m_counter_hi << ENDL + << " m_is_loading_from_db: " << mdbc.m_is_loading_from_db << ENDL + << " m_median_container.size: " << mdbc.m_median_container.size() << ENDL + << " m_median_container.size_no_cache(): " << mdbc.m_median_container.size_no_cache() << ENDL + << "parent " << static_cast>(mdbc); + return s; + } + + +} \ No newline at end of file diff --git a/src/common/miniupnp_helper.h b/src/common/miniupnp_helper.h new file mode 100644 index 00000000..2b2fd090 --- /dev/null +++ b/src/common/miniupnp_helper.h @@ -0,0 +1,159 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include +#include +#include "include_base_utils.h" +extern "C" { +#include "miniupnpc/miniupnpc.h" +#include "miniupnpc/upnpcommands.h" +#include "miniupnpc/upnperrors.h" +} + +#include "misc_language.h" +#include "currency_core/currency_config.h" +#include "version.h" + +namespace tools +{ + class miniupnp_helper + { + UPNPDev *m_devlist; + UPNPUrls m_urls; + IGDdatas m_data; + char m_lanaddr[64]; + int m_IGD; + boost::thread m_mapper_thread; + uint32_t m_external_port; + public: + miniupnp_helper():m_devlist(nullptr), + m_urls(AUTO_VAL_INIT(m_urls)), + m_data(AUTO_VAL_INIT(m_data)), + m_IGD(0) + { + m_lanaddr[0] = 0; + } + ~miniupnp_helper() + { + deinit(); + } + + bool start_regular_mapping(uint32_t internal_port, uint32_t external_port, uint32_t period_ms) + { + m_external_port = external_port; + if(!init()) + return false; + m_mapper_thread = boost::thread([=](){run_port_mapping_loop(internal_port, external_port, period_ms);}); + return true; + } + + bool stop_mapping() + { + if(m_mapper_thread.joinable()) + { + m_mapper_thread.interrupt(); + m_mapper_thread.join(); + } + + if(m_IGD == 1) + { + do_port_unmapping(); + } + return true; + } + + private: + + bool init() + { + deinit(); + + int error = 0; + m_devlist = upnpDiscover(2000, nullptr, nullptr, 0, 0, &error); + if(error) + { + LOG_PRINT_L0("Failed to call upnpDiscover"); + return false; + } + + m_IGD = UPNP_GetValidIGD(m_devlist, &m_urls, &m_data, m_lanaddr, sizeof(m_lanaddr)); + if(m_IGD != 1) + { + LOG_PRINT_L2("IGD not found"); + return false; + } + return true; + } + + bool deinit() + { + stop_mapping(); + + if(m_devlist) + { + freeUPNPDevlist(m_devlist); + m_devlist = nullptr; + } + + if(m_IGD > 0) + { + FreeUPNPUrls(&m_urls); + m_IGD = 0; + } + return true; + } + + bool run_port_mapping_loop(uint32_t internal_port, uint32_t external_port, uint32_t period_ms) + { + while(true) + { + do_port_mapping(external_port, internal_port); + boost::this_thread::sleep_for(boost::chrono::milliseconds( period_ms )); + } + return true; + } + + bool do_port_mapping(uint32_t external_port, uint32_t internal_port) + { + std::string internal_port_str = std::to_string(internal_port); + std::string external_port_str = std::to_string(external_port); + std::string str_desc = CURRENCY_NAME " v" PROJECT_VERSION_LONG; + + int r = UPNP_AddPortMapping(m_urls.controlURL, m_data.first.servicetype, + external_port_str.c_str(), internal_port_str.c_str(), m_lanaddr, str_desc.c_str(), "TCP", nullptr, "0"); + + if(r!=UPNPCOMMAND_SUCCESS) + { + LOG_PRINT_L1("AddPortMapping with external_port_str= " << external_port_str << + ", internal_port_str=" << internal_port_str << + ", failed with code=" << r << "(" << strupnperror(r) << ")"); + }else + { + LOG_PRINT_L0("[upnp] port mapped successful (ext: " << external_port_str << ", int:" << internal_port_str << ")"); + } + return true; + } + + void do_port_unmapping() + { + std::string external_port_str = std::to_string(m_external_port); + + int r = UPNP_DeletePortMapping(m_urls.controlURL, m_data.first.servicetype, external_port_str.c_str(), "TCP", nullptr); + if(r!=UPNPCOMMAND_SUCCESS) + { + LOG_PRINT_L1("DeletePortMapping with external_port_str= " << external_port_str << + ", failed with code=" << r << "(" << strupnperror(r) << ")"); + }else + { + LOG_PRINT_L0("[upnp] port unmapped successful (ext: " << external_port_str << ")"); + } + } + }; +} + diff --git a/src/common/mnemonic-encoding.cpp b/src/common/mnemonic-encoding.cpp new file mode 100644 index 00000000..3b769860 --- /dev/null +++ b/src/common/mnemonic-encoding.cpp @@ -0,0 +1,3375 @@ +// Copyright (c) 2014, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/* + * This file and its cpp file are for translating Electrum-style word lists + * into their equivalent byte representations for cross-compatibility with + * that method of "backing up" one's wallet keys. + */ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project + +#include +#include +#include +#include +#include "mnemonic-encoding.h" + +namespace tools +{ + namespace mnemonic_encoding + { + using namespace std; + + const int NUMWORDS = 1626; + + const map wordsMap = { + {"like", 0}, + {"just", 1}, + {"love", 2}, + {"know", 3}, + {"never", 4}, + {"want", 5}, + {"time", 6}, + {"out", 7}, + {"there", 8}, + {"make", 9}, + {"look", 10}, + {"eye", 11}, + {"down", 12}, + {"only", 13}, + {"think", 14}, + {"heart", 15}, + {"back", 16}, + {"then", 17}, + {"into", 18}, + {"about", 19}, + {"more", 20}, + {"away", 21}, + {"still", 22}, + {"them", 23}, + {"take", 24}, + {"thing", 25}, + {"even", 26}, + {"through", 27}, + {"long", 28}, + {"always", 29}, + {"world", 30}, + {"too", 31}, + {"friend", 32}, + {"tell", 33}, + {"try", 34}, + {"hand", 35}, + {"thought", 36}, + {"over", 37}, + {"here", 38}, + {"other", 39}, + {"need", 40}, + {"smile", 41}, + {"again", 42}, + {"much", 43}, + {"cry", 44}, + {"been", 45}, + {"night", 46}, + {"ever", 47}, + {"little", 48}, + {"said", 49}, + {"end", 50}, + {"some", 51}, + {"those", 52}, + {"around", 53}, + {"mind", 54}, + {"people", 55}, + {"girl", 56}, + {"leave", 57}, + {"dream", 58}, + {"left", 59}, + {"turn", 60}, + {"myself", 61}, + {"give", 62}, + {"nothing", 63}, + {"really", 64}, + {"off", 65}, + {"before", 66}, + {"something", 67}, + {"find", 68}, + {"walk", 69}, + {"wish", 70}, + {"good", 71}, + {"once", 72}, + {"place", 73}, + {"ask", 74}, + {"stop", 75}, + {"keep", 76}, + {"watch", 77}, + {"seem", 78}, + {"everything", 79}, + {"wait", 80}, + {"got", 81}, + {"yet", 82}, + {"made", 83}, + {"remember", 84}, + {"start", 85}, + {"alone", 86}, + {"run", 87}, + {"hope", 88}, + {"maybe", 89}, + {"believe", 90}, + {"body", 91}, + {"hate", 92}, + {"after", 93}, + {"close", 94}, + {"talk", 95}, + {"stand", 96}, + {"own", 97}, + {"each", 98}, + {"hurt", 99}, + {"help", 100}, + {"home", 101}, + {"god", 102}, + {"soul", 103}, + {"new", 104}, + {"many", 105}, + {"two", 106}, + {"inside", 107}, + {"should", 108}, + {"true", 109}, + {"first", 110}, + {"fear", 111}, + {"mean", 112}, + {"better", 113}, + {"play", 114}, + {"another", 115}, + {"gone", 116}, + {"change", 117}, + {"use", 118}, + {"wonder", 119}, + {"someone", 120}, + {"hair", 121}, + {"cold", 122}, + {"open", 123}, + {"best", 124}, + {"any", 125}, + {"behind", 126}, + {"happen", 127}, + {"water", 128}, + {"dark", 129}, + {"laugh", 130}, + {"stay", 131}, + {"forever", 132}, + {"name", 133}, + {"work", 134}, + {"show", 135}, + {"sky", 136}, + {"break", 137}, + {"came", 138}, + {"deep", 139}, + {"door", 140}, + {"put", 141}, + {"black", 142}, + {"together", 143}, + {"upon", 144}, + {"happy", 145}, + {"such", 146}, + {"great", 147}, + {"white", 148}, + {"matter", 149}, + {"fill", 150}, + {"past", 151}, + {"please", 152}, + {"burn", 153}, + {"cause", 154}, + {"enough", 155}, + {"touch", 156}, + {"moment", 157}, + {"soon", 158}, + {"voice", 159}, + {"scream", 160}, + {"anything", 161}, + {"stare", 162}, + {"sound", 163}, + {"red", 164}, + {"everyone", 165}, + {"hide", 166}, + {"kiss", 167}, + {"truth", 168}, + {"death", 169}, + {"beautiful", 170}, + {"mine", 171}, + {"blood", 172}, + {"broken", 173}, + {"very", 174}, + {"pass", 175}, + {"next", 176}, + {"forget", 177}, + {"tree", 178}, + {"wrong", 179}, + {"air", 180}, + {"mother", 181}, + {"understand", 182}, + {"lip", 183}, + {"hit", 184}, + {"wall", 185}, + {"memory", 186}, + {"sleep", 187}, + {"free", 188}, + {"high", 189}, + {"realize", 190}, + {"school", 191}, + {"might", 192}, + {"skin", 193}, + {"sweet", 194}, + {"perfect", 195}, + {"blue", 196}, + {"kill", 197}, + {"breath", 198}, + {"dance", 199}, + {"against", 200}, + {"fly", 201}, + {"between", 202}, + {"grow", 203}, + {"strong", 204}, + {"under", 205}, + {"listen", 206}, + {"bring", 207}, + {"sometimes", 208}, + {"speak", 209}, + {"pull", 210}, + {"person", 211}, + {"become", 212}, + {"family", 213}, + {"begin", 214}, + {"ground", 215}, + {"real", 216}, + {"small", 217}, + {"father", 218}, + {"sure", 219}, + {"feet", 220}, + {"rest", 221}, + {"young", 222}, + {"finally", 223}, + {"land", 224}, + {"across", 225}, + {"today", 226}, + {"different", 227}, + {"guy", 228}, + {"line", 229}, + {"fire", 230}, + {"reason", 231}, + {"reach", 232}, + {"second", 233}, + {"slowly", 234}, + {"write", 235}, + {"eat", 236}, + {"smell", 237}, + {"mouth", 238}, + {"step", 239}, + {"learn", 240}, + {"three", 241}, + {"floor", 242}, + {"promise", 243}, + {"breathe", 244}, + {"darkness", 245}, + {"push", 246}, + {"earth", 247}, + {"guess", 248}, + {"save", 249}, + {"song", 250}, + {"above", 251}, + {"along", 252}, + {"both", 253}, + {"color", 254}, + {"house", 255}, + {"almost", 256}, + {"sorry", 257}, + {"anymore", 258}, + {"brother", 259}, + {"okay", 260}, + {"dear", 261}, + {"game", 262}, + {"fade", 263}, + {"already", 264}, + {"apart", 265}, + {"warm", 266}, + {"beauty", 267}, + {"heard", 268}, + {"notice", 269}, + {"question", 270}, + {"shine", 271}, + {"began", 272}, + {"piece", 273}, + {"whole", 274}, + {"shadow", 275}, + {"secret", 276}, + {"street", 277}, + {"within", 278}, + {"finger", 279}, + {"point", 280}, + {"morning", 281}, + {"whisper", 282}, + {"child", 283}, + {"moon", 284}, + {"green", 285}, + {"story", 286}, + {"glass", 287}, + {"kid", 288}, + {"silence", 289}, + {"since", 290}, + {"soft", 291}, + {"yourself", 292}, + {"empty", 293}, + {"shall", 294}, + {"angel", 295}, + {"answer", 296}, + {"baby", 297}, + {"bright", 298}, + {"dad", 299}, + {"path", 300}, + {"worry", 301}, + {"hour", 302}, + {"drop", 303}, + {"follow", 304}, + {"power", 305}, + {"war", 306}, + {"half", 307}, + {"flow", 308}, + {"heaven", 309}, + {"act", 310}, + {"chance", 311}, + {"fact", 312}, + {"least", 313}, + {"tired", 314}, + {"children", 315}, + {"near", 316}, + {"quite", 317}, + {"afraid", 318}, + {"rise", 319}, + {"sea", 320}, + {"taste", 321}, + {"window", 322}, + {"cover", 323}, + {"nice", 324}, + {"trust", 325}, + {"lot", 326}, + {"sad", 327}, + {"cool", 328}, + {"force", 329}, + {"peace", 330}, + {"return", 331}, + {"blind", 332}, + {"easy", 333}, + {"ready", 334}, + {"roll", 335}, + {"rose", 336}, + {"drive", 337}, + {"held", 338}, + {"music", 339}, + {"beneath", 340}, + {"hang", 341}, + {"mom", 342}, + {"paint", 343}, + {"emotion", 344}, + {"quiet", 345}, + {"clear", 346}, + {"cloud", 347}, + {"few", 348}, + {"pretty", 349}, + {"bird", 350}, + {"outside", 351}, + {"paper", 352}, + {"picture", 353}, + {"front", 354}, + {"rock", 355}, + {"simple", 356}, + {"anyone", 357}, + {"meant", 358}, + {"reality", 359}, + {"road", 360}, + {"sense", 361}, + {"waste", 362}, + {"bit", 363}, + {"leaf", 364}, + {"thank", 365}, + {"happiness", 366}, + {"meet", 367}, + {"men", 368}, + {"smoke", 369}, + {"truly", 370}, + {"decide", 371}, + {"self", 372}, + {"age", 373}, + {"book", 374}, + {"form", 375}, + {"alive", 376}, + {"carry", 377}, + {"escape", 378}, + {"damn", 379}, + {"instead", 380}, + {"able", 381}, + {"ice", 382}, + {"minute", 383}, + {"throw", 384}, + {"catch", 385}, + {"leg", 386}, + {"ring", 387}, + {"course", 388}, + {"goodbye", 389}, + {"lead", 390}, + {"poem", 391}, + {"sick", 392}, + {"corner", 393}, + {"desire", 394}, + {"known", 395}, + {"problem", 396}, + {"remind", 397}, + {"shoulder", 398}, + {"suppose", 399}, + {"toward", 400}, + {"wave", 401}, + {"drink", 402}, + {"jump", 403}, + {"woman", 404}, + {"pretend", 405}, + {"sister", 406}, + {"week", 407}, + {"human", 408}, + {"joy", 409}, + {"crack", 410}, + {"grey", 411}, + {"pray", 412}, + {"surprise", 413}, + {"dry", 414}, + {"knee", 415}, + {"less", 416}, + {"search", 417}, + {"bleed", 418}, + {"caught", 419}, + {"clean", 420}, + {"embrace", 421}, + {"future", 422}, + {"king", 423}, + {"son", 424}, + {"sorrow", 425}, + {"chest", 426}, + {"hug", 427}, + {"remain", 428}, + {"sat", 429}, + {"worth", 430}, + {"blow", 431}, + {"daddy", 432}, + {"final", 433}, + {"parent", 434}, + {"tight", 435}, + {"also", 436}, + {"create", 437}, + {"lonely", 438}, + {"safe", 439}, + {"cross", 440}, + {"dress", 441}, + {"evil", 442}, + {"silent", 443}, + {"bone", 444}, + {"fate", 445}, + {"perhaps", 446}, + {"anger", 447}, + {"class", 448}, + {"scar", 449}, + {"snow", 450}, + {"tiny", 451}, + {"tonight", 452}, + {"continue", 453}, + {"control", 454}, + {"dog", 455}, + {"edge", 456}, + {"mirror", 457}, + {"month", 458}, + {"suddenly", 459}, + {"comfort", 460}, + {"given", 461}, + {"loud", 462}, + {"quickly", 463}, + {"gaze", 464}, + {"plan", 465}, + {"rush", 466}, + {"stone", 467}, + {"town", 468}, + {"battle", 469}, + {"ignore", 470}, + {"spirit", 471}, + {"stood", 472}, + {"stupid", 473}, + {"yours", 474}, + {"brown", 475}, + {"build", 476}, + {"dust", 477}, + {"hey", 478}, + {"kept", 479}, + {"pay", 480}, + {"phone", 481}, + {"twist", 482}, + {"although", 483}, + {"ball", 484}, + {"beyond", 485}, + {"hidden", 486}, + {"nose", 487}, + {"taken", 488}, + {"fail", 489}, + {"float", 490}, + {"pure", 491}, + {"somehow", 492}, + {"wash", 493}, + {"wrap", 494}, + {"angry", 495}, + {"cheek", 496}, + {"creature", 497}, + {"forgotten", 498}, + {"heat", 499}, + {"rip", 500}, + {"single", 501}, + {"space", 502}, + {"special", 503}, + {"weak", 504}, + {"whatever", 505}, + {"yell", 506}, + {"anyway", 507}, + {"blame", 508}, + {"job", 509}, + {"choose", 510}, + {"country", 511}, + {"curse", 512}, + {"drift", 513}, + {"echo", 514}, + {"figure", 515}, + {"grew", 516}, + {"laughter", 517}, + {"neck", 518}, + {"suffer", 519}, + {"worse", 520}, + {"yeah", 521}, + {"disappear", 522}, + {"foot", 523}, + {"forward", 524}, + {"knife", 525}, + {"mess", 526}, + {"somewhere", 527}, + {"stomach", 528}, + {"storm", 529}, + {"beg", 530}, + {"idea", 531}, + {"lift", 532}, + {"offer", 533}, + {"breeze", 534}, + {"field", 535}, + {"five", 536}, + {"often", 537}, + {"simply", 538}, + {"stuck", 539}, + {"win", 540}, + {"allow", 541}, + {"confuse", 542}, + {"enjoy", 543}, + {"except", 544}, + {"flower", 545}, + {"seek", 546}, + {"strength", 547}, + {"calm", 548}, + {"grin", 549}, + {"gun", 550}, + {"heavy", 551}, + {"hill", 552}, + {"large", 553}, + {"ocean", 554}, + {"shoe", 555}, + {"sigh", 556}, + {"straight", 557}, + {"summer", 558}, + {"tongue", 559}, + {"accept", 560}, + {"crazy", 561}, + {"everyday", 562}, + {"exist", 563}, + {"grass", 564}, + {"mistake", 565}, + {"sent", 566}, + {"shut", 567}, + {"surround", 568}, + {"table", 569}, + {"ache", 570}, + {"brain", 571}, + {"destroy", 572}, + {"heal", 573}, + {"nature", 574}, + {"shout", 575}, + {"sign", 576}, + {"stain", 577}, + {"choice", 578}, + {"doubt", 579}, + {"glance", 580}, + {"glow", 581}, + {"mountain", 582}, + {"queen", 583}, + {"stranger", 584}, + {"throat", 585}, + {"tomorrow", 586}, + {"city", 587}, + {"either", 588}, + {"fish", 589}, + {"flame", 590}, + {"rather", 591}, + {"shape", 592}, + {"spin", 593}, + {"spread", 594}, + {"ash", 595}, + {"distance", 596}, + {"finish", 597}, + {"image", 598}, + {"imagine", 599}, + {"important", 600}, + {"nobody", 601}, + {"shatter", 602}, + {"warmth", 603}, + {"became", 604}, + {"feed", 605}, + {"flesh", 606}, + {"funny", 607}, + {"lust", 608}, + {"shirt", 609}, + {"trouble", 610}, + {"yellow", 611}, + {"attention", 612}, + {"bare", 613}, + {"bite", 614}, + {"money", 615}, + {"protect", 616}, + {"amaze", 617}, + {"appear", 618}, + {"born", 619}, + {"choke", 620}, + {"completely", 621}, + {"daughter", 622}, + {"fresh", 623}, + {"friendship", 624}, + {"gentle", 625}, + {"probably", 626}, + {"six", 627}, + {"deserve", 628}, + {"expect", 629}, + {"grab", 630}, + {"middle", 631}, + {"nightmare", 632}, + {"river", 633}, + {"thousand", 634}, + {"weight", 635}, + {"worst", 636}, + {"wound", 637}, + {"barely", 638}, + {"bottle", 639}, + {"cream", 640}, + {"regret", 641}, + {"relationship", 642}, + {"stick", 643}, + {"test", 644}, + {"crush", 645}, + {"endless", 646}, + {"fault", 647}, + {"itself", 648}, + {"rule", 649}, + {"spill", 650}, + {"art", 651}, + {"circle", 652}, + {"join", 653}, + {"kick", 654}, + {"mask", 655}, + {"master", 656}, + {"passion", 657}, + {"quick", 658}, + {"raise", 659}, + {"smooth", 660}, + {"unless", 661}, + {"wander", 662}, + {"actually", 663}, + {"broke", 664}, + {"chair", 665}, + {"deal", 666}, + {"favorite", 667}, + {"gift", 668}, + {"note", 669}, + {"number", 670}, + {"sweat", 671}, + {"box", 672}, + {"chill", 673}, + {"clothes", 674}, + {"lady", 675}, + {"mark", 676}, + {"park", 677}, + {"poor", 678}, + {"sadness", 679}, + {"tie", 680}, + {"animal", 681}, + {"belong", 682}, + {"brush", 683}, + {"consume", 684}, + {"dawn", 685}, + {"forest", 686}, + {"innocent", 687}, + {"pen", 688}, + {"pride", 689}, + {"stream", 690}, + {"thick", 691}, + {"clay", 692}, + {"complete", 693}, + {"count", 694}, + {"draw", 695}, + {"faith", 696}, + {"press", 697}, + {"silver", 698}, + {"struggle", 699}, + {"surface", 700}, + {"taught", 701}, + {"teach", 702}, + {"wet", 703}, + {"bless", 704}, + {"chase", 705}, + {"climb", 706}, + {"enter", 707}, + {"letter", 708}, + {"melt", 709}, + {"metal", 710}, + {"movie", 711}, + {"stretch", 712}, + {"swing", 713}, + {"vision", 714}, + {"wife", 715}, + {"beside", 716}, + {"crash", 717}, + {"forgot", 718}, + {"guide", 719}, + {"haunt", 720}, + {"joke", 721}, + {"knock", 722}, + {"plant", 723}, + {"pour", 724}, + {"prove", 725}, + {"reveal", 726}, + {"steal", 727}, + {"stuff", 728}, + {"trip", 729}, + {"wood", 730}, + {"wrist", 731}, + {"bother", 732}, + {"bottom", 733}, + {"crawl", 734}, + {"crowd", 735}, + {"fix", 736}, + {"forgive", 737}, + {"frown", 738}, + {"grace", 739}, + {"loose", 740}, + {"lucky", 741}, + {"party", 742}, + {"release", 743}, + {"surely", 744}, + {"survive", 745}, + {"teacher", 746}, + {"gently", 747}, + {"grip", 748}, + {"speed", 749}, + {"suicide", 750}, + {"travel", 751}, + {"treat", 752}, + {"vein", 753}, + {"written", 754}, + {"cage", 755}, + {"chain", 756}, + {"conversation", 757}, + {"date", 758}, + {"enemy", 759}, + {"however", 760}, + {"interest", 761}, + {"million", 762}, + {"page", 763}, + {"pink", 764}, + {"proud", 765}, + {"sway", 766}, + {"themselves", 767}, + {"winter", 768}, + {"church", 769}, + {"cruel", 770}, + {"cup", 771}, + {"demon", 772}, + {"experience", 773}, + {"freedom", 774}, + {"pair", 775}, + {"pop", 776}, + {"purpose", 777}, + {"respect", 778}, + {"shoot", 779}, + {"softly", 780}, + {"state", 781}, + {"strange", 782}, + {"bar", 783}, + {"birth", 784}, + {"curl", 785}, + {"dirt", 786}, + {"excuse", 787}, + {"lord", 788}, + {"lovely", 789}, + {"monster", 790}, + {"order", 791}, + {"pack", 792}, + {"pants", 793}, + {"pool", 794}, + {"scene", 795}, + {"seven", 796}, + {"shame", 797}, + {"slide", 798}, + {"ugly", 799}, + {"among", 800}, + {"blade", 801}, + {"blonde", 802}, + {"closet", 803}, + {"creek", 804}, + {"deny", 805}, + {"drug", 806}, + {"eternity", 807}, + {"gain", 808}, + {"grade", 809}, + {"handle", 810}, + {"key", 811}, + {"linger", 812}, + {"pale", 813}, + {"prepare", 814}, + {"swallow", 815}, + {"swim", 816}, + {"tremble", 817}, + {"wheel", 818}, + {"won", 819}, + {"cast", 820}, + {"cigarette", 821}, + {"claim", 822}, + {"college", 823}, + {"direction", 824}, + {"dirty", 825}, + {"gather", 826}, + {"ghost", 827}, + {"hundred", 828}, + {"loss", 829}, + {"lung", 830}, + {"orange", 831}, + {"present", 832}, + {"swear", 833}, + {"swirl", 834}, + {"twice", 835}, + {"wild", 836}, + {"bitter", 837}, + {"blanket", 838}, + {"doctor", 839}, + {"everywhere", 840}, + {"flash", 841}, + {"grown", 842}, + {"knowledge", 843}, + {"numb", 844}, + {"pressure", 845}, + {"radio", 846}, + {"repeat", 847}, + {"ruin", 848}, + {"spend", 849}, + {"unknown", 850}, + {"buy", 851}, + {"clock", 852}, + {"devil", 853}, + {"early", 854}, + {"false", 855}, + {"fantasy", 856}, + {"pound", 857}, + {"precious", 858}, + {"refuse", 859}, + {"sheet", 860}, + {"teeth", 861}, + {"welcome", 862}, + {"add", 863}, + {"ahead", 864}, + {"block", 865}, + {"bury", 866}, + {"caress", 867}, + {"content", 868}, + {"depth", 869}, + {"despite", 870}, + {"distant", 871}, + {"marry", 872}, + {"purple", 873}, + {"threw", 874}, + {"whenever", 875}, + {"bomb", 876}, + {"dull", 877}, + {"easily", 878}, + {"grasp", 879}, + {"hospital", 880}, + {"innocence", 881}, + {"normal", 882}, + {"receive", 883}, + {"reply", 884}, + {"rhyme", 885}, + {"shade", 886}, + {"someday", 887}, + {"sword", 888}, + {"toe", 889}, + {"visit", 890}, + {"asleep", 891}, + {"bought", 892}, + {"center", 893}, + {"consider", 894}, + {"flat", 895}, + {"hero", 896}, + {"history", 897}, + {"ink", 898}, + {"insane", 899}, + {"muscle", 900}, + {"mystery", 901}, + {"pocket", 902}, + {"reflection", 903}, + {"shove", 904}, + {"silently", 905}, + {"smart", 906}, + {"soldier", 907}, + {"spot", 908}, + {"stress", 909}, + {"train", 910}, + {"type", 911}, + {"view", 912}, + {"whether", 913}, + {"bus", 914}, + {"energy", 915}, + {"explain", 916}, + {"holy", 917}, + {"hunger", 918}, + {"inch", 919}, + {"magic", 920}, + {"mix", 921}, + {"noise", 922}, + {"nowhere", 923}, + {"prayer", 924}, + {"presence", 925}, + {"shock", 926}, + {"snap", 927}, + {"spider", 928}, + {"study", 929}, + {"thunder", 930}, + {"trail", 931}, + {"admit", 932}, + {"agree", 933}, + {"bag", 934}, + {"bang", 935}, + {"bound", 936}, + {"butterfly", 937}, + {"cute", 938}, + {"exactly", 939}, + {"explode", 940}, + {"familiar", 941}, + {"fold", 942}, + {"further", 943}, + {"pierce", 944}, + {"reflect", 945}, + {"scent", 946}, + {"selfish", 947}, + {"sharp", 948}, + {"sink", 949}, + {"spring", 950}, + {"stumble", 951}, + {"universe", 952}, + {"weep", 953}, + {"women", 954}, + {"wonderful", 955}, + {"action", 956}, + {"ancient", 957}, + {"attempt", 958}, + {"avoid", 959}, + {"birthday", 960}, + {"branch", 961}, + {"chocolate", 962}, + {"core", 963}, + {"depress", 964}, + {"drunk", 965}, + {"especially", 966}, + {"focus", 967}, + {"fruit", 968}, + {"honest", 969}, + {"match", 970}, + {"palm", 971}, + {"perfectly", 972}, + {"pillow", 973}, + {"pity", 974}, + {"poison", 975}, + {"roar", 976}, + {"shift", 977}, + {"slightly", 978}, + {"thump", 979}, + {"truck", 980}, + {"tune", 981}, + {"twenty", 982}, + {"unable", 983}, + {"wipe", 984}, + {"wrote", 985}, + {"coat", 986}, + {"constant", 987}, + {"dinner", 988}, + {"drove", 989}, + {"egg", 990}, + {"eternal", 991}, + {"flight", 992}, + {"flood", 993}, + {"frame", 994}, + {"freak", 995}, + {"gasp", 996}, + {"glad", 997}, + {"hollow", 998}, + {"motion", 999}, + {"peer", 1000}, + {"plastic", 1001}, + {"root", 1002}, + {"screen", 1003}, + {"season", 1004}, + {"sting", 1005}, + {"strike", 1006}, + {"team", 1007}, + {"unlike", 1008}, + {"victim", 1009}, + {"volume", 1010}, + {"warn", 1011}, + {"weird", 1012}, + {"attack", 1013}, + {"await", 1014}, + {"awake", 1015}, + {"built", 1016}, + {"charm", 1017}, + {"crave", 1018}, + {"despair", 1019}, + {"fought", 1020}, + {"grant", 1021}, + {"grief", 1022}, + {"horse", 1023}, + {"limit", 1024}, + {"message", 1025}, + {"ripple", 1026}, + {"sanity", 1027}, + {"scatter", 1028}, + {"serve", 1029}, + {"split", 1030}, + {"string", 1031}, + {"trick", 1032}, + {"annoy", 1033}, + {"blur", 1034}, + {"boat", 1035}, + {"brave", 1036}, + {"clearly", 1037}, + {"cling", 1038}, + {"connect", 1039}, + {"fist", 1040}, + {"forth", 1041}, + {"imagination", 1042}, + {"iron", 1043}, + {"jock", 1044}, + {"judge", 1045}, + {"lesson", 1046}, + {"milk", 1047}, + {"misery", 1048}, + {"nail", 1049}, + {"naked", 1050}, + {"ourselves", 1051}, + {"poet", 1052}, + {"possible", 1053}, + {"princess", 1054}, + {"sail", 1055}, + {"size", 1056}, + {"snake", 1057}, + {"society", 1058}, + {"stroke", 1059}, + {"torture", 1060}, + {"toss", 1061}, + {"trace", 1062}, + {"wise", 1063}, + {"bloom", 1064}, + {"bullet", 1065}, + {"cell", 1066}, + {"check", 1067}, + {"cost", 1068}, + {"darling", 1069}, + {"during", 1070}, + {"footstep", 1071}, + {"fragile", 1072}, + {"hallway", 1073}, + {"hardly", 1074}, + {"horizon", 1075}, + {"invisible", 1076}, + {"journey", 1077}, + {"midnight", 1078}, + {"mud", 1079}, + {"nod", 1080}, + {"pause", 1081}, + {"relax", 1082}, + {"shiver", 1083}, + {"sudden", 1084}, + {"value", 1085}, + {"youth", 1086}, + {"abuse", 1087}, + {"admire", 1088}, + {"blink", 1089}, + {"breast", 1090}, + {"bruise", 1091}, + {"constantly", 1092}, + {"couple", 1093}, + {"creep", 1094}, + {"curve", 1095}, + {"difference", 1096}, + {"dumb", 1097}, + {"emptiness", 1098}, + {"gotta", 1099}, + {"honor", 1100}, + {"plain", 1101}, + {"planet", 1102}, + {"recall", 1103}, + {"rub", 1104}, + {"ship", 1105}, + {"slam", 1106}, + {"soar", 1107}, + {"somebody", 1108}, + {"tightly", 1109}, + {"weather", 1110}, + {"adore", 1111}, + {"approach", 1112}, + {"bond", 1113}, + {"bread", 1114}, + {"burst", 1115}, + {"candle", 1116}, + {"coffee", 1117}, + {"cousin", 1118}, + {"crime", 1119}, + {"desert", 1120}, + {"flutter", 1121}, + {"frozen", 1122}, + {"grand", 1123}, + {"heel", 1124}, + {"hello", 1125}, + {"language", 1126}, + {"level", 1127}, + {"movement", 1128}, + {"pleasure", 1129}, + {"powerful", 1130}, + {"random", 1131}, + {"rhythm", 1132}, + {"settle", 1133}, + {"silly", 1134}, + {"slap", 1135}, + {"sort", 1136}, + {"spoken", 1137}, + {"steel", 1138}, + {"threaten", 1139}, + {"tumble", 1140}, + {"upset", 1141}, + {"aside", 1142}, + {"awkward", 1143}, + {"bee", 1144}, + {"blank", 1145}, + {"board", 1146}, + {"button", 1147}, + {"card", 1148}, + {"carefully", 1149}, + {"complain", 1150}, + {"crap", 1151}, + {"deeply", 1152}, + {"discover", 1153}, + {"drag", 1154}, + {"dread", 1155}, + {"effort", 1156}, + {"entire", 1157}, + {"fairy", 1158}, + {"giant", 1159}, + {"gotten", 1160}, + {"greet", 1161}, + {"illusion", 1162}, + {"jeans", 1163}, + {"leap", 1164}, + {"liquid", 1165}, + {"march", 1166}, + {"mend", 1167}, + {"nervous", 1168}, + {"nine", 1169}, + {"replace", 1170}, + {"rope", 1171}, + {"spine", 1172}, + {"stole", 1173}, + {"terror", 1174}, + {"accident", 1175}, + {"apple", 1176}, + {"balance", 1177}, + {"boom", 1178}, + {"childhood", 1179}, + {"collect", 1180}, + {"demand", 1181}, + {"depression", 1182}, + {"eventually", 1183}, + {"faint", 1184}, + {"glare", 1185}, + {"goal", 1186}, + {"group", 1187}, + {"honey", 1188}, + {"kitchen", 1189}, + {"laid", 1190}, + {"limb", 1191}, + {"machine", 1192}, + {"mere", 1193}, + {"mold", 1194}, + {"murder", 1195}, + {"nerve", 1196}, + {"painful", 1197}, + {"poetry", 1198}, + {"prince", 1199}, + {"rabbit", 1200}, + {"shelter", 1201}, + {"shore", 1202}, + {"shower", 1203}, + {"soothe", 1204}, + {"stair", 1205}, + {"steady", 1206}, + {"sunlight", 1207}, + {"tangle", 1208}, + {"tease", 1209}, + {"treasure", 1210}, + {"uncle", 1211}, + {"begun", 1212}, + {"bliss", 1213}, + {"canvas", 1214}, + {"cheer", 1215}, + {"claw", 1216}, + {"clutch", 1217}, + {"commit", 1218}, + {"crimson", 1219}, + {"crystal", 1220}, + {"delight", 1221}, + {"doll", 1222}, + {"existence", 1223}, + {"express", 1224}, + {"fog", 1225}, + {"football", 1226}, + {"gay", 1227}, + {"goose", 1228}, + {"guard", 1229}, + {"hatred", 1230}, + {"illuminate", 1231}, + {"mass", 1232}, + {"math", 1233}, + {"mourn", 1234}, + {"rich", 1235}, + {"rough", 1236}, + {"skip", 1237}, + {"stir", 1238}, + {"student", 1239}, + {"style", 1240}, + {"support", 1241}, + {"thorn", 1242}, + {"tough", 1243}, + {"yard", 1244}, + {"yearn", 1245}, + {"yesterday", 1246}, + {"advice", 1247}, + {"appreciate", 1248}, + {"autumn", 1249}, + {"bank", 1250}, + {"beam", 1251}, + {"bowl", 1252}, + {"capture", 1253}, + {"carve", 1254}, + {"collapse", 1255}, + {"confusion", 1256}, + {"creation", 1257}, + {"dove", 1258}, + {"feather", 1259}, + {"girlfriend", 1260}, + {"glory", 1261}, + {"government", 1262}, + {"harsh", 1263}, + {"hop", 1264}, + {"inner", 1265}, + {"loser", 1266}, + {"moonlight", 1267}, + {"neighbor", 1268}, + {"neither", 1269}, + {"peach", 1270}, + {"pig", 1271}, + {"praise", 1272}, + {"screw", 1273}, + {"shield", 1274}, + {"shimmer", 1275}, + {"sneak", 1276}, + {"stab", 1277}, + {"subject", 1278}, + {"throughout", 1279}, + {"thrown", 1280}, + {"tower", 1281}, + {"twirl", 1282}, + {"wow", 1283}, + {"army", 1284}, + {"arrive", 1285}, + {"bathroom", 1286}, + {"bump", 1287}, + {"cease", 1288}, + {"cookie", 1289}, + {"couch", 1290}, + {"courage", 1291}, + {"dim", 1292}, + {"guilt", 1293}, + {"howl", 1294}, + {"hum", 1295}, + {"husband", 1296}, + {"insult", 1297}, + {"led", 1298}, + {"lunch", 1299}, + {"mock", 1300}, + {"mostly", 1301}, + {"natural", 1302}, + {"nearly", 1303}, + {"needle", 1304}, + {"nerd", 1305}, + {"peaceful", 1306}, + {"perfection", 1307}, + {"pile", 1308}, + {"price", 1309}, + {"remove", 1310}, + {"roam", 1311}, + {"sanctuary", 1312}, + {"serious", 1313}, + {"shiny", 1314}, + {"shook", 1315}, + {"sob", 1316}, + {"stolen", 1317}, + {"tap", 1318}, + {"vain", 1319}, + {"void", 1320}, + {"warrior", 1321}, + {"wrinkle", 1322}, + {"affection", 1323}, + {"apologize", 1324}, + {"blossom", 1325}, + {"bounce", 1326}, + {"bridge", 1327}, + {"cheap", 1328}, + {"crumble", 1329}, + {"decision", 1330}, + {"descend", 1331}, + {"desperately", 1332}, + {"dig", 1333}, + {"dot", 1334}, + {"flip", 1335}, + {"frighten", 1336}, + {"heartbeat", 1337}, + {"huge", 1338}, + {"lazy", 1339}, + {"lick", 1340}, + {"odd", 1341}, + {"opinion", 1342}, + {"process", 1343}, + {"puzzle", 1344}, + {"quietly", 1345}, + {"retreat", 1346}, + {"score", 1347}, + {"sentence", 1348}, + {"separate", 1349}, + {"situation", 1350}, + {"skill", 1351}, + {"soak", 1352}, + {"square", 1353}, + {"stray", 1354}, + {"taint", 1355}, + {"task", 1356}, + {"tide", 1357}, + {"underneath", 1358}, + {"veil", 1359}, + {"whistle", 1360}, + {"anywhere", 1361}, + {"bedroom", 1362}, + {"bid", 1363}, + {"bloody", 1364}, + {"burden", 1365}, + {"careful", 1366}, + {"compare", 1367}, + {"concern", 1368}, + {"curtain", 1369}, + {"decay", 1370}, + {"defeat", 1371}, + {"describe", 1372}, + {"double", 1373}, + {"dreamer", 1374}, + {"driver", 1375}, + {"dwell", 1376}, + {"evening", 1377}, + {"flare", 1378}, + {"flicker", 1379}, + {"grandma", 1380}, + {"guitar", 1381}, + {"harm", 1382}, + {"horrible", 1383}, + {"hungry", 1384}, + {"indeed", 1385}, + {"lace", 1386}, + {"melody", 1387}, + {"monkey", 1388}, + {"nation", 1389}, + {"object", 1390}, + {"obviously", 1391}, + {"rainbow", 1392}, + {"salt", 1393}, + {"scratch", 1394}, + {"shown", 1395}, + {"shy", 1396}, + {"stage", 1397}, + {"stun", 1398}, + {"third", 1399}, + {"tickle", 1400}, + {"useless", 1401}, + {"weakness", 1402}, + {"worship", 1403}, + {"worthless", 1404}, + {"afternoon", 1405}, + {"beard", 1406}, + {"boyfriend", 1407}, + {"bubble", 1408}, + {"busy", 1409}, + {"certain", 1410}, + {"chin", 1411}, + {"concrete", 1412}, + {"desk", 1413}, + {"diamond", 1414}, + {"doom", 1415}, + {"drawn", 1416}, + {"due", 1417}, + {"felicity", 1418}, + {"freeze", 1419}, + {"frost", 1420}, + {"garden", 1421}, + {"glide", 1422}, + {"harmony", 1423}, + {"hopefully", 1424}, + {"hunt", 1425}, + {"jealous", 1426}, + {"lightning", 1427}, + {"mama", 1428}, + {"mercy", 1429}, + {"peel", 1430}, + {"physical", 1431}, + {"position", 1432}, + {"pulse", 1433}, + {"punch", 1434}, + {"quit", 1435}, + {"rant", 1436}, + {"respond", 1437}, + {"salty", 1438}, + {"sane", 1439}, + {"satisfy", 1440}, + {"savior", 1441}, + {"sheep", 1442}, + {"slept", 1443}, + {"social", 1444}, + {"sport", 1445}, + {"tuck", 1446}, + {"utter", 1447}, + {"valley", 1448}, + {"wolf", 1449}, + {"aim", 1450}, + {"alas", 1451}, + {"alter", 1452}, + {"arrow", 1453}, + {"awaken", 1454}, + {"beaten", 1455}, + {"belief", 1456}, + {"brand", 1457}, + {"ceiling", 1458}, + {"cheese", 1459}, + {"clue", 1460}, + {"confidence", 1461}, + {"connection", 1462}, + {"daily", 1463}, + {"disguise", 1464}, + {"eager", 1465}, + {"erase", 1466}, + {"essence", 1467}, + {"everytime", 1468}, + {"expression", 1469}, + {"fan", 1470}, + {"flag", 1471}, + {"flirt", 1472}, + {"foul", 1473}, + {"fur", 1474}, + {"giggle", 1475}, + {"glorious", 1476}, + {"ignorance", 1477}, + {"law", 1478}, + {"lifeless", 1479}, + {"measure", 1480}, + {"mighty", 1481}, + {"muse", 1482}, + {"north", 1483}, + {"opposite", 1484}, + {"paradise", 1485}, + {"patience", 1486}, + {"patient", 1487}, + {"pencil", 1488}, + {"petal", 1489}, + {"plate", 1490}, + {"ponder", 1491}, + {"possibly", 1492}, + {"practice", 1493}, + {"slice", 1494}, + {"spell", 1495}, + {"stock", 1496}, + {"strife", 1497}, + {"strip", 1498}, + {"suffocate", 1499}, + {"suit", 1500}, + {"tender", 1501}, + {"tool", 1502}, + {"trade", 1503}, + {"velvet", 1504}, + {"verse", 1505}, + {"waist", 1506}, + {"witch", 1507}, + {"aunt", 1508}, + {"bench", 1509}, + {"bold", 1510}, + {"cap", 1511}, + {"certainly", 1512}, + {"click", 1513}, + {"companion", 1514}, + {"creator", 1515}, + {"dart", 1516}, + {"delicate", 1517}, + {"determine", 1518}, + {"dish", 1519}, + {"dragon", 1520}, + {"drama", 1521}, + {"drum", 1522}, + {"dude", 1523}, + {"everybody", 1524}, + {"feast", 1525}, + {"forehead", 1526}, + {"former", 1527}, + {"fright", 1528}, + {"fully", 1529}, + {"gas", 1530}, + {"hook", 1531}, + {"hurl", 1532}, + {"invite", 1533}, + {"juice", 1534}, + {"manage", 1535}, + {"moral", 1536}, + {"possess", 1537}, + {"raw", 1538}, + {"rebel", 1539}, + {"royal", 1540}, + {"scale", 1541}, + {"scary", 1542}, + {"several", 1543}, + {"slight", 1544}, + {"stubborn", 1545}, + {"swell", 1546}, + {"talent", 1547}, + {"tea", 1548}, + {"terrible", 1549}, + {"thread", 1550}, + {"torment", 1551}, + {"trickle", 1552}, + {"usually", 1553}, + {"vast", 1554}, + {"violence", 1555}, + {"weave", 1556}, + {"acid", 1557}, + {"agony", 1558}, + {"ashamed", 1559}, + {"awe", 1560}, + {"belly", 1561}, + {"blend", 1562}, + {"blush", 1563}, + {"character", 1564}, + {"cheat", 1565}, + {"common", 1566}, + {"company", 1567}, + {"coward", 1568}, + {"creak", 1569}, + {"danger", 1570}, + {"deadly", 1571}, + {"defense", 1572}, + {"define", 1573}, + {"depend", 1574}, + {"desperate", 1575}, + {"destination", 1576}, + {"dew", 1577}, + {"duck", 1578}, + {"dusty", 1579}, + {"embarrass", 1580}, + {"engine", 1581}, + {"example", 1582}, + {"explore", 1583}, + {"foe", 1584}, + {"freely", 1585}, + {"frustrate", 1586}, + {"generation", 1587}, + {"glove", 1588}, + {"guilty", 1589}, + {"health", 1590}, + {"hurry", 1591}, + {"idiot", 1592}, + {"impossible", 1593}, + {"inhale", 1594}, + {"jaw", 1595}, + {"kingdom", 1596}, + {"mention", 1597}, + {"mist", 1598}, + {"moan", 1599}, + {"mumble", 1600}, + {"mutter", 1601}, + {"observe", 1602}, + {"ode", 1603}, + {"pathetic", 1604}, + {"pattern", 1605}, + {"pie", 1606}, + {"prefer", 1607}, + {"puff", 1608}, + {"rape", 1609}, + {"rare", 1610}, + {"revenge", 1611}, + {"rude", 1612}, + {"scrape", 1613}, + {"spiral", 1614}, + {"squeeze", 1615}, + {"strain", 1616}, + {"sunset", 1617}, + {"suspend", 1618}, + {"sympathy", 1619}, + {"thigh", 1620}, + {"throne", 1621}, + {"total", 1622}, + {"unseen", 1623}, + {"weapon", 1624}, + {"weary", 1625} + }; + + const std::string wordsArray[] = { + "like", + "just", + "love", + "know", + "never", + "want", + "time", + "out", + "there", + "make", + "look", + "eye", + "down", + "only", + "think", + "heart", + "back", + "then", + "into", + "about", + "more", + "away", + "still", + "them", + "take", + "thing", + "even", + "through", + "long", + "always", + "world", + "too", + "friend", + "tell", + "try", + "hand", + "thought", + "over", + "here", + "other", + "need", + "smile", + "again", + "much", + "cry", + "been", + "night", + "ever", + "little", + "said", + "end", + "some", + "those", + "around", + "mind", + "people", + "girl", + "leave", + "dream", + "left", + "turn", + "myself", + "give", + "nothing", + "really", + "off", + "before", + "something", + "find", + "walk", + "wish", + "good", + "once", + "place", + "ask", + "stop", + "keep", + "watch", + "seem", + "everything", + "wait", + "got", + "yet", + "made", + "remember", + "start", + "alone", + "run", + "hope", + "maybe", + "believe", + "body", + "hate", + "after", + "close", + "talk", + "stand", + "own", + "each", + "hurt", + "help", + "home", + "god", + "soul", + "new", + "many", + "two", + "inside", + "should", + "true", + "first", + "fear", + "mean", + "better", + "play", + "another", + "gone", + "change", + "use", + "wonder", + "someone", + "hair", + "cold", + "open", + "best", + "any", + "behind", + "happen", + "water", + "dark", + "laugh", + "stay", + "forever", + "name", + "work", + "show", + "sky", + "break", + "came", + "deep", + "door", + "put", + "black", + "together", + "upon", + "happy", + "such", + "great", + "white", + "matter", + "fill", + "past", + "please", + "burn", + "cause", + "enough", + "touch", + "moment", + "soon", + "voice", + "scream", + "anything", + "stare", + "sound", + "red", + "everyone", + "hide", + "kiss", + "truth", + "death", + "beautiful", + "mine", + "blood", + "broken", + "very", + "pass", + "next", + "forget", + "tree", + "wrong", + "air", + "mother", + "understand", + "lip", + "hit", + "wall", + "memory", + "sleep", + "free", + "high", + "realize", + "school", + "might", + "skin", + "sweet", + "perfect", + "blue", + "kill", + "breath", + "dance", + "against", + "fly", + "between", + "grow", + "strong", + "under", + "listen", + "bring", + "sometimes", + "speak", + "pull", + "person", + "become", + "family", + "begin", + "ground", + "real", + "small", + "father", + "sure", + "feet", + "rest", + "young", + "finally", + "land", + "across", + "today", + "different", + "guy", + "line", + "fire", + "reason", + "reach", + "second", + "slowly", + "write", + "eat", + "smell", + "mouth", + "step", + "learn", + "three", + "floor", + "promise", + "breathe", + "darkness", + "push", + "earth", + "guess", + "save", + "song", + "above", + "along", + "both", + "color", + "house", + "almost", + "sorry", + "anymore", + "brother", + "okay", + "dear", + "game", + "fade", + "already", + "apart", + "warm", + "beauty", + "heard", + "notice", + "question", + "shine", + "began", + "piece", + "whole", + "shadow", + "secret", + "street", + "within", + "finger", + "point", + "morning", + "whisper", + "child", + "moon", + "green", + "story", + "glass", + "kid", + "silence", + "since", + "soft", + "yourself", + "empty", + "shall", + "angel", + "answer", + "baby", + "bright", + "dad", + "path", + "worry", + "hour", + "drop", + "follow", + "power", + "war", + "half", + "flow", + "heaven", + "act", + "chance", + "fact", + "least", + "tired", + "children", + "near", + "quite", + "afraid", + "rise", + "sea", + "taste", + "window", + "cover", + "nice", + "trust", + "lot", + "sad", + "cool", + "force", + "peace", + "return", + "blind", + "easy", + "ready", + "roll", + "rose", + "drive", + "held", + "music", + "beneath", + "hang", + "mom", + "paint", + "emotion", + "quiet", + "clear", + "cloud", + "few", + "pretty", + "bird", + "outside", + "paper", + "picture", + "front", + "rock", + "simple", + "anyone", + "meant", + "reality", + "road", + "sense", + "waste", + "bit", + "leaf", + "thank", + "happiness", + "meet", + "men", + "smoke", + "truly", + "decide", + "self", + "age", + "book", + "form", + "alive", + "carry", + "escape", + "damn", + "instead", + "able", + "ice", + "minute", + "throw", + "catch", + "leg", + "ring", + "course", + "goodbye", + "lead", + "poem", + "sick", + "corner", + "desire", + "known", + "problem", + "remind", + "shoulder", + "suppose", + "toward", + "wave", + "drink", + "jump", + "woman", + "pretend", + "sister", + "week", + "human", + "joy", + "crack", + "grey", + "pray", + "surprise", + "dry", + "knee", + "less", + "search", + "bleed", + "caught", + "clean", + "embrace", + "future", + "king", + "son", + "sorrow", + "chest", + "hug", + "remain", + "sat", + "worth", + "blow", + "daddy", + "final", + "parent", + "tight", + "also", + "create", + "lonely", + "safe", + "cross", + "dress", + "evil", + "silent", + "bone", + "fate", + "perhaps", + "anger", + "class", + "scar", + "snow", + "tiny", + "tonight", + "continue", + "control", + "dog", + "edge", + "mirror", + "month", + "suddenly", + "comfort", + "given", + "loud", + "quickly", + "gaze", + "plan", + "rush", + "stone", + "town", + "battle", + "ignore", + "spirit", + "stood", + "stupid", + "yours", + "brown", + "build", + "dust", + "hey", + "kept", + "pay", + "phone", + "twist", + "although", + "ball", + "beyond", + "hidden", + "nose", + "taken", + "fail", + "float", + "pure", + "somehow", + "wash", + "wrap", + "angry", + "cheek", + "creature", + "forgotten", + "heat", + "rip", + "single", + "space", + "special", + "weak", + "whatever", + "yell", + "anyway", + "blame", + "job", + "choose", + "country", + "curse", + "drift", + "echo", + "figure", + "grew", + "laughter", + "neck", + "suffer", + "worse", + "yeah", + "disappear", + "foot", + "forward", + "knife", + "mess", + "somewhere", + "stomach", + "storm", + "beg", + "idea", + "lift", + "offer", + "breeze", + "field", + "five", + "often", + "simply", + "stuck", + "win", + "allow", + "confuse", + "enjoy", + "except", + "flower", + "seek", + "strength", + "calm", + "grin", + "gun", + "heavy", + "hill", + "large", + "ocean", + "shoe", + "sigh", + "straight", + "summer", + "tongue", + "accept", + "crazy", + "everyday", + "exist", + "grass", + "mistake", + "sent", + "shut", + "surround", + "table", + "ache", + "brain", + "destroy", + "heal", + "nature", + "shout", + "sign", + "stain", + "choice", + "doubt", + "glance", + "glow", + "mountain", + "queen", + "stranger", + "throat", + "tomorrow", + "city", + "either", + "fish", + "flame", + "rather", + "shape", + "spin", + "spread", + "ash", + "distance", + "finish", + "image", + "imagine", + "important", + "nobody", + "shatter", + "warmth", + "became", + "feed", + "flesh", + "funny", + "lust", + "shirt", + "trouble", + "yellow", + "attention", + "bare", + "bite", + "money", + "protect", + "amaze", + "appear", + "born", + "choke", + "completely", + "daughter", + "fresh", + "friendship", + "gentle", + "probably", + "six", + "deserve", + "expect", + "grab", + "middle", + "nightmare", + "river", + "thousand", + "weight", + "worst", + "wound", + "barely", + "bottle", + "cream", + "regret", + "relationship", + "stick", + "test", + "crush", + "endless", + "fault", + "itself", + "rule", + "spill", + "art", + "circle", + "join", + "kick", + "mask", + "master", + "passion", + "quick", + "raise", + "smooth", + "unless", + "wander", + "actually", + "broke", + "chair", + "deal", + "favorite", + "gift", + "note", + "number", + "sweat", + "box", + "chill", + "clothes", + "lady", + "mark", + "park", + "poor", + "sadness", + "tie", + "animal", + "belong", + "brush", + "consume", + "dawn", + "forest", + "innocent", + "pen", + "pride", + "stream", + "thick", + "clay", + "complete", + "count", + "draw", + "faith", + "press", + "silver", + "struggle", + "surface", + "taught", + "teach", + "wet", + "bless", + "chase", + "climb", + "enter", + "letter", + "melt", + "metal", + "movie", + "stretch", + "swing", + "vision", + "wife", + "beside", + "crash", + "forgot", + "guide", + "haunt", + "joke", + "knock", + "plant", + "pour", + "prove", + "reveal", + "steal", + "stuff", + "trip", + "wood", + "wrist", + "bother", + "bottom", + "crawl", + "crowd", + "fix", + "forgive", + "frown", + "grace", + "loose", + "lucky", + "party", + "release", + "surely", + "survive", + "teacher", + "gently", + "grip", + "speed", + "suicide", + "travel", + "treat", + "vein", + "written", + "cage", + "chain", + "conversation", + "date", + "enemy", + "however", + "interest", + "million", + "page", + "pink", + "proud", + "sway", + "themselves", + "winter", + "church", + "cruel", + "cup", + "demon", + "experience", + "freedom", + "pair", + "pop", + "purpose", + "respect", + "shoot", + "softly", + "state", + "strange", + "bar", + "birth", + "curl", + "dirt", + "excuse", + "lord", + "lovely", + "monster", + "order", + "pack", + "pants", + "pool", + "scene", + "seven", + "shame", + "slide", + "ugly", + "among", + "blade", + "blonde", + "closet", + "creek", + "deny", + "drug", + "eternity", + "gain", + "grade", + "handle", + "key", + "linger", + "pale", + "prepare", + "swallow", + "swim", + "tremble", + "wheel", + "won", + "cast", + "cigarette", + "claim", + "college", + "direction", + "dirty", + "gather", + "ghost", + "hundred", + "loss", + "lung", + "orange", + "present", + "swear", + "swirl", + "twice", + "wild", + "bitter", + "blanket", + "doctor", + "everywhere", + "flash", + "grown", + "knowledge", + "numb", + "pressure", + "radio", + "repeat", + "ruin", + "spend", + "unknown", + "buy", + "clock", + "devil", + "early", + "false", + "fantasy", + "pound", + "precious", + "refuse", + "sheet", + "teeth", + "welcome", + "add", + "ahead", + "block", + "bury", + "caress", + "content", + "depth", + "despite", + "distant", + "marry", + "purple", + "threw", + "whenever", + "bomb", + "dull", + "easily", + "grasp", + "hospital", + "innocence", + "normal", + "receive", + "reply", + "rhyme", + "shade", + "someday", + "sword", + "toe", + "visit", + "asleep", + "bought", + "center", + "consider", + "flat", + "hero", + "history", + "ink", + "insane", + "muscle", + "mystery", + "pocket", + "reflection", + "shove", + "silently", + "smart", + "soldier", + "spot", + "stress", + "train", + "type", + "view", + "whether", + "bus", + "energy", + "explain", + "holy", + "hunger", + "inch", + "magic", + "mix", + "noise", + "nowhere", + "prayer", + "presence", + "shock", + "snap", + "spider", + "study", + "thunder", + "trail", + "admit", + "agree", + "bag", + "bang", + "bound", + "butterfly", + "cute", + "exactly", + "explode", + "familiar", + "fold", + "further", + "pierce", + "reflect", + "scent", + "selfish", + "sharp", + "sink", + "spring", + "stumble", + "universe", + "weep", + "women", + "wonderful", + "action", + "ancient", + "attempt", + "avoid", + "birthday", + "branch", + "chocolate", + "core", + "depress", + "drunk", + "especially", + "focus", + "fruit", + "honest", + "match", + "palm", + "perfectly", + "pillow", + "pity", + "poison", + "roar", + "shift", + "slightly", + "thump", + "truck", + "tune", + "twenty", + "unable", + "wipe", + "wrote", + "coat", + "constant", + "dinner", + "drove", + "egg", + "eternal", + "flight", + "flood", + "frame", + "freak", + "gasp", + "glad", + "hollow", + "motion", + "peer", + "plastic", + "root", + "screen", + "season", + "sting", + "strike", + "team", + "unlike", + "victim", + "volume", + "warn", + "weird", + "attack", + "await", + "awake", + "built", + "charm", + "crave", + "despair", + "fought", + "grant", + "grief", + "horse", + "limit", + "message", + "ripple", + "sanity", + "scatter", + "serve", + "split", + "string", + "trick", + "annoy", + "blur", + "boat", + "brave", + "clearly", + "cling", + "connect", + "fist", + "forth", + "imagination", + "iron", + "jock", + "judge", + "lesson", + "milk", + "misery", + "nail", + "naked", + "ourselves", + "poet", + "possible", + "princess", + "sail", + "size", + "snake", + "society", + "stroke", + "torture", + "toss", + "trace", + "wise", + "bloom", + "bullet", + "cell", + "check", + "cost", + "darling", + "during", + "footstep", + "fragile", + "hallway", + "hardly", + "horizon", + "invisible", + "journey", + "midnight", + "mud", + "nod", + "pause", + "relax", + "shiver", + "sudden", + "value", + "youth", + "abuse", + "admire", + "blink", + "breast", + "bruise", + "constantly", + "couple", + "creep", + "curve", + "difference", + "dumb", + "emptiness", + "gotta", + "honor", + "plain", + "planet", + "recall", + "rub", + "ship", + "slam", + "soar", + "somebody", + "tightly", + "weather", + "adore", + "approach", + "bond", + "bread", + "burst", + "candle", + "coffee", + "cousin", + "crime", + "desert", + "flutter", + "frozen", + "grand", + "heel", + "hello", + "language", + "level", + "movement", + "pleasure", + "powerful", + "random", + "rhythm", + "settle", + "silly", + "slap", + "sort", + "spoken", + "steel", + "threaten", + "tumble", + "upset", + "aside", + "awkward", + "bee", + "blank", + "board", + "button", + "card", + "carefully", + "complain", + "crap", + "deeply", + "discover", + "drag", + "dread", + "effort", + "entire", + "fairy", + "giant", + "gotten", + "greet", + "illusion", + "jeans", + "leap", + "liquid", + "march", + "mend", + "nervous", + "nine", + "replace", + "rope", + "spine", + "stole", + "terror", + "accident", + "apple", + "balance", + "boom", + "childhood", + "collect", + "demand", + "depression", + "eventually", + "faint", + "glare", + "goal", + "group", + "honey", + "kitchen", + "laid", + "limb", + "machine", + "mere", + "mold", + "murder", + "nerve", + "painful", + "poetry", + "prince", + "rabbit", + "shelter", + "shore", + "shower", + "soothe", + "stair", + "steady", + "sunlight", + "tangle", + "tease", + "treasure", + "uncle", + "begun", + "bliss", + "canvas", + "cheer", + "claw", + "clutch", + "commit", + "crimson", + "crystal", + "delight", + "doll", + "existence", + "express", + "fog", + "football", + "gay", + "goose", + "guard", + "hatred", + "illuminate", + "mass", + "math", + "mourn", + "rich", + "rough", + "skip", + "stir", + "student", + "style", + "support", + "thorn", + "tough", + "yard", + "yearn", + "yesterday", + "advice", + "appreciate", + "autumn", + "bank", + "beam", + "bowl", + "capture", + "carve", + "collapse", + "confusion", + "creation", + "dove", + "feather", + "girlfriend", + "glory", + "government", + "harsh", + "hop", + "inner", + "loser", + "moonlight", + "neighbor", + "neither", + "peach", + "pig", + "praise", + "screw", + "shield", + "shimmer", + "sneak", + "stab", + "subject", + "throughout", + "thrown", + "tower", + "twirl", + "wow", + "army", + "arrive", + "bathroom", + "bump", + "cease", + "cookie", + "couch", + "courage", + "dim", + "guilt", + "howl", + "hum", + "husband", + "insult", + "led", + "lunch", + "mock", + "mostly", + "natural", + "nearly", + "needle", + "nerd", + "peaceful", + "perfection", + "pile", + "price", + "remove", + "roam", + "sanctuary", + "serious", + "shiny", + "shook", + "sob", + "stolen", + "tap", + "vain", + "void", + "warrior", + "wrinkle", + "affection", + "apologize", + "blossom", + "bounce", + "bridge", + "cheap", + "crumble", + "decision", + "descend", + "desperately", + "dig", + "dot", + "flip", + "frighten", + "heartbeat", + "huge", + "lazy", + "lick", + "odd", + "opinion", + "process", + "puzzle", + "quietly", + "retreat", + "score", + "sentence", + "separate", + "situation", + "skill", + "soak", + "square", + "stray", + "taint", + "task", + "tide", + "underneath", + "veil", + "whistle", + "anywhere", + "bedroom", + "bid", + "bloody", + "burden", + "careful", + "compare", + "concern", + "curtain", + "decay", + "defeat", + "describe", + "double", + "dreamer", + "driver", + "dwell", + "evening", + "flare", + "flicker", + "grandma", + "guitar", + "harm", + "horrible", + "hungry", + "indeed", + "lace", + "melody", + "monkey", + "nation", + "object", + "obviously", + "rainbow", + "salt", + "scratch", + "shown", + "shy", + "stage", + "stun", + "third", + "tickle", + "useless", + "weakness", + "worship", + "worthless", + "afternoon", + "beard", + "boyfriend", + "bubble", + "busy", + "certain", + "chin", + "concrete", + "desk", + "diamond", + "doom", + "drawn", + "due", + "felicity", + "freeze", + "frost", + "garden", + "glide", + "harmony", + "hopefully", + "hunt", + "jealous", + "lightning", + "mama", + "mercy", + "peel", + "physical", + "position", + "pulse", + "punch", + "quit", + "rant", + "respond", + "salty", + "sane", + "satisfy", + "savior", + "sheep", + "slept", + "social", + "sport", + "tuck", + "utter", + "valley", + "wolf", + "aim", + "alas", + "alter", + "arrow", + "awaken", + "beaten", + "belief", + "brand", + "ceiling", + "cheese", + "clue", + "confidence", + "connection", + "daily", + "disguise", + "eager", + "erase", + "essence", + "everytime", + "expression", + "fan", + "flag", + "flirt", + "foul", + "fur", + "giggle", + "glorious", + "ignorance", + "law", + "lifeless", + "measure", + "mighty", + "muse", + "north", + "opposite", + "paradise", + "patience", + "patient", + "pencil", + "petal", + "plate", + "ponder", + "possibly", + "practice", + "slice", + "spell", + "stock", + "strife", + "strip", + "suffocate", + "suit", + "tender", + "tool", + "trade", + "velvet", + "verse", + "waist", + "witch", + "aunt", + "bench", + "bold", + "cap", + "certainly", + "click", + "companion", + "creator", + "dart", + "delicate", + "determine", + "dish", + "dragon", + "drama", + "drum", + "dude", + "everybody", + "feast", + "forehead", + "former", + "fright", + "fully", + "gas", + "hook", + "hurl", + "invite", + "juice", + "manage", + "moral", + "possess", + "raw", + "rebel", + "royal", + "scale", + "scary", + "several", + "slight", + "stubborn", + "swell", + "talent", + "tea", + "terrible", + "thread", + "torment", + "trickle", + "usually", + "vast", + "violence", + "weave", + "acid", + "agony", + "ashamed", + "awe", + "belly", + "blend", + "blush", + "character", + "cheat", + "common", + "company", + "coward", + "creak", + "danger", + "deadly", + "defense", + "define", + "depend", + "desperate", + "destination", + "dew", + "duck", + "dusty", + "embarrass", + "engine", + "example", + "explore", + "foe", + "freely", + "frustrate", + "generation", + "glove", + "guilty", + "health", + "hurry", + "idiot", + "impossible", + "inhale", + "jaw", + "kingdom", + "mention", + "mist", + "moan", + "mumble", + "mutter", + "observe", + "ode", + "pathetic", + "pattern", + "pie", + "prefer", + "puff", + "rape", + "rare", + "revenge", + "rude", + "scrape", + "spiral", + "squeeze", + "strain", + "sunset", + "suspend", + "sympathy", + "thigh", + "throne", + "total", + "unseen", + "weapon", + "weary" + }; + + + // convert text to binary data, 3 words -> 4 bytes + vector text2binary_throw(const string& text) + { + int n = NUMWORDS; + vector tokens; + string trimmed_copy(boost::trim_copy(text)); + boost::split(tokens, trimmed_copy, + boost::is_any_of(" ")); + if(tokens.size() % 3 != 0) + throw runtime_error("Invalid word count in mnemonic text"); + + vector res(tokens.size() / 3 * 4); // 3 tokens => 4 bytes + for (unsigned int i=0; i < tokens.size() / 3; i++) + { + if (wordsMap.count(tokens[i*3]) == 0 || + wordsMap.count(tokens[i*3 + 1]) == 0 || + wordsMap.count(tokens[i*3 + 2]) == 0) + throw runtime_error("Invalid word in mnemonic text"); + + uint32_t w1 = wordsMap.at(tokens[i*3]); + uint32_t w2 = wordsMap.at(tokens[i*3 + 1]); + uint32_t w3 = wordsMap.at(tokens[i*3 + 2]); + + uint32_t* val = reinterpret_cast(&res[i * 4]); + *val = w1 + n * (((n - w1) + w2) % n) + n * n * (((n - w2) + w3) % n); + } + return res; + } + + vector text2binary(const string& text) + { + try + { + return text2binary_throw(text); + } + catch (...) + { + return vector(); + } + } + // convert binary data to text, 4 bytes => 3 words + string binary2text(const vector& binary) + { + int n = NUMWORDS; // hardcoded because this is what electrum uses + + if (binary.size() % 4 != 0) + throw runtime_error("Invalid binary data size for mnemonic encoding"); + // 4 bytes -> 3 words. 8 digits base 16 -> 3 digits base 1626 + string res; + for (unsigned int i=0; i < binary.size() / 4; i++, res += ' ') + { + const uint32_t* val = + reinterpret_cast(&binary[i * 4]); + + uint32_t w1 = *val % n; + uint32_t w2 = ((*val / n) + w1) % n; + uint32_t w3 = (((*val / n) / n) + w2) % n; + + res += wordsArray[w1] + " "; + res += wordsArray[w2] + " "; + res += wordsArray[w3]; + } + return res; + } + } +} diff --git a/src/common/mnemonic-encoding.h b/src/common/mnemonic-encoding.h new file mode 100644 index 00000000..443da308 --- /dev/null +++ b/src/common/mnemonic-encoding.h @@ -0,0 +1,46 @@ +// Copyright (c) 2014, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/* + * This file and its cpp file are for translating Electrum-style word lists + * into their equivalent byte representations for cross-compatibility with + * that method of "backing up" one's wallet keys. + */ + + +#include +#include + +namespace tools +{ + namespace mnemonic_encoding + { + std::vector text2binary(const std::string& text); + std::string binary2text(const std::vector& binary); + } +} diff --git a/src/common/pod-class.h b/src/common/pod-class.h new file mode 100644 index 00000000..84c89994 --- /dev/null +++ b/src/common/pod-class.h @@ -0,0 +1,9 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +// in C++ no difference 'class' vs 'struct' except the default members access. +// maybe be better to erase the 'POD_CLASS' macro completely? +#define POD_CLASS struct diff --git a/src/common/unordered_containers_boost_serialization.h b/src/common/unordered_containers_boost_serialization.h new file mode 100644 index 00000000..644133f4 --- /dev/null +++ b/src/common/unordered_containers_boost_serialization.h @@ -0,0 +1,119 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include +#include + +namespace boost +{ + namespace serialization + { + template + inline void save(Archive &a, const std::unordered_map &x, const boost::serialization::version_type ver) + { + size_t s = x.size(); + a << s; + BOOST_FOREACH(auto& v, x) + { + a << v.first; + a << v.second; + } + } + + template + inline void load(Archive &a, std::unordered_map &x, const boost::serialization::version_type ver) + { + x.clear(); + size_t s = 0; + a >> s; + for(size_t i = 0; i != s; i++) + { + h_key k; + hval v; + a >> k; + a >> v; + x.insert(std::pair(k, v)); + } + } + + + template + inline void save(Archive &a, const std::unordered_multimap &x, const boost::serialization::version_type ver) + { + size_t s = x.size(); + a << s; + BOOST_FOREACH(auto& v, x) + { + a << v.first; + a << v.second; + } + } + + template + inline void load(Archive &a, std::unordered_multimap &x, const boost::serialization::version_type ver) + { + x.clear(); + size_t s = 0; + a >> s; + for(size_t i = 0; i != s; i++) + { + h_key k; + hval v; + a >> k; + a >> v; + x.emplace(k, v); + } + } + + + template + inline void save(Archive &a, const std::unordered_set &x, const boost::serialization::version_type ver) + { + size_t s = x.size(); + a << s; + BOOST_FOREACH(auto& v, x) + { + a << v; + } + } + + template + inline void load(Archive &a, std::unordered_set &x, const boost::serialization::version_type ver) + { + x.clear(); + size_t s = 0; + a >> s; + for(size_t i = 0; i != s; i++) + { + hval v; + a >> v; + x.insert(v); + } + } + + + template + inline void serialize(Archive &a, std::unordered_map &x, const boost::serialization::version_type ver) + { + split_free(a, x, ver); + } + + template + inline void serialize(Archive &a, std::unordered_multimap &x, const boost::serialization::version_type ver) + { + split_free(a, x, ver); + } + + template + inline void serialize(Archive &a, std::unordered_set &x, const boost::serialization::version_type ver) + { + split_free(a, x, ver); + } + } +} diff --git a/src/common/util.cpp b/src/common/util.cpp new file mode 100644 index 00000000..338e07dc --- /dev/null +++ b/src/common/util.cpp @@ -0,0 +1,529 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "include_base_utils.h" +using namespace epee; + +#include "util.h" +#include "currency_core/currency_config.h" + +#ifdef WIN32 +#include +#include +#include +#include +#pragma comment(lib, "netapi32.lib") +#else +#include +#endif + + +namespace tools +{ + std::function signal_handler::m_handler; + std::function signal_handler::m_fatal_handler; + +#ifdef WIN32 + + bool GetWinMajorMinorVersion(DWORD& major, DWORD& minor) + { + bool bRetCode = false; + LPBYTE pinfoRawData = 0; + if (NERR_Success == NetWkstaGetInfo(NULL, 100, &pinfoRawData)) + { + WKSTA_INFO_100* pworkstationInfo = (WKSTA_INFO_100*)pinfoRawData; + major = pworkstationInfo->wki100_ver_major; + minor = pworkstationInfo->wki100_ver_minor; + ::NetApiBufferFree(pinfoRawData); + bRetCode = true; + } + return bRetCode; + } + + + std::string get_windows_version_display_string() + { + std::string winver; + OSVERSIONINFOEX osver; + SYSTEM_INFO sysInfo; + typedef void(__stdcall *GETSYSTEMINFO) (LPSYSTEM_INFO); + +#pragma warning (push) +#pragma warning (disable:4996) + memset(&osver, 0, sizeof(osver)); + osver.dwOSVersionInfoSize = sizeof(osver); + GetVersionEx((LPOSVERSIONINFO)&osver); +#pragma warning (pop) + DWORD major = 0; + DWORD minor = 0; + if (GetWinMajorMinorVersion(major, minor)) + { + osver.dwMajorVersion = major; + osver.dwMinorVersion = minor; + } + else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 2) + { + OSVERSIONINFOEXW osvi; + ULONGLONG cm = 0; + cm = VerSetConditionMask(cm, VER_MINORVERSION, VER_EQUAL); + ZeroMemory(&osvi, sizeof(osvi)); + osvi.dwOSVersionInfoSize = sizeof(osvi); + osvi.dwMinorVersion = 3; + if (VerifyVersionInfoW(&osvi, VER_MINORVERSION, cm)) + { + osver.dwMinorVersion = 3; + } + } + + GETSYSTEMINFO getSysInfo = (GETSYSTEMINFO)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetNativeSystemInfo"); + if (getSysInfo == NULL) getSysInfo = ::GetSystemInfo; + getSysInfo(&sysInfo); + + if (osver.dwMajorVersion == 10 && osver.dwMinorVersion >= 0 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows 10 Server"; + else if (osver.dwMajorVersion == 10 && osver.dwMinorVersion >= 0 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows 10"; + else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 3 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows Server 2012 R2"; + else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 3 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows 8.1"; + else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 2 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows Server 2012"; + else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 2 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows 8"; + else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 1 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows Server 2008 R2"; + else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 1 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows 7"; + else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 0 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows Server 2008"; + else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 0 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows Vista"; + else if (osver.dwMajorVersion == 5 && osver.dwMinorVersion == 2 && osver.wProductType == VER_NT_WORKSTATION + && sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) + winver = "Windows XP x64"; + else if (osver.dwMajorVersion == 5 && osver.dwMinorVersion == 2) winver = "Windows Server 2003"; + else if (osver.dwMajorVersion == 5 && osver.dwMinorVersion == 1) winver = "Windows XP"; + else if (osver.dwMajorVersion == 5 && osver.dwMinorVersion == 0) winver = "Windows 2000"; + else winver = "unknown"; + + if (osver.wServicePackMajor != 0) + { + std::string sp; + char buf[128] = { 0 }; + sp = " Service Pack "; + sprintf_s(buf, sizeof(buf), "%hd", osver.wServicePackMajor); + sp.append(buf); + winver += sp; + } + + if (osver.dwMajorVersion >= 6) + { + if (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) + winver += ", 64-bit"; + else if (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) + winver += ", 32-bit"; + } + + + winver += "(" + + std::to_string(osver.dwMajorVersion) + ":" + + std::to_string(osver.dwMinorVersion) + ":" + + std::to_string(osver.dwBuildNumber) + ":" + + std::to_string(osver.dwPlatformId) + ":" + + std::to_string(osver.wServicePackMajor) + ":" + + std::to_string(osver.wServicePackMinor) + ":" + + std::to_string(osver.wSuiteMask) + ":" + + std::to_string(osver.wProductType) + ")"; + + return winver; + } + + + + + + std::string get_windows_version_display_string_() + { + typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); + typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD); +#define BUFSIZE 10000 + + char pszOS[BUFSIZE] = {0}; + OSVERSIONINFOEX osvi; + SYSTEM_INFO si; + PGNSI pGNSI; + PGPI pGPI; + BOOL bOsVersionInfoEx; + DWORD dwType; + + ZeroMemory(&si, sizeof(SYSTEM_INFO)); + ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); + + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO*) &osvi); + + if(!bOsVersionInfoEx) return pszOS; + + // Call GetNativeSystemInfo if supported or GetSystemInfo otherwise. + + pGNSI = (PGNSI) GetProcAddress( + GetModuleHandle(TEXT("kernel32.dll")), + "GetNativeSystemInfo"); + if(NULL != pGNSI) + pGNSI(&si); + else GetSystemInfo(&si); + + if ( VER_PLATFORM_WIN32_NT==osvi.dwPlatformId && + osvi.dwMajorVersion > 4 ) + { + StringCchCopy(pszOS, BUFSIZE, TEXT("Microsoft ")); + + // Test for the specific product. + + if ( osvi.dwMajorVersion == 6 ) + { + if( osvi.dwMinorVersion == 0 ) + { + if( osvi.wProductType == VER_NT_WORKSTATION ) + StringCchCat(pszOS, BUFSIZE, TEXT("Windows Vista ")); + else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2008 " )); + } + + if ( osvi.dwMinorVersion == 1 ) + { + if( osvi.wProductType == VER_NT_WORKSTATION ) + StringCchCat(pszOS, BUFSIZE, TEXT("Windows 7 ")); + else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2008 R2 " )); + } + + pGPI = (PGPI) GetProcAddress( + GetModuleHandle(TEXT("kernel32.dll")), + "GetProductInfo"); + + pGPI( osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &dwType); + + switch( dwType ) + { + case PRODUCT_ULTIMATE: + StringCchCat(pszOS, BUFSIZE, TEXT("Ultimate Edition" )); + break; + case PRODUCT_PROFESSIONAL: + StringCchCat(pszOS, BUFSIZE, TEXT("Professional" )); + break; + case PRODUCT_HOME_PREMIUM: + StringCchCat(pszOS, BUFSIZE, TEXT("Home Premium Edition" )); + break; + case PRODUCT_HOME_BASIC: + StringCchCat(pszOS, BUFSIZE, TEXT("Home Basic Edition" )); + break; + case PRODUCT_ENTERPRISE: + StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition" )); + break; + case PRODUCT_BUSINESS: + StringCchCat(pszOS, BUFSIZE, TEXT("Business Edition" )); + break; + case PRODUCT_STARTER: + StringCchCat(pszOS, BUFSIZE, TEXT("Starter Edition" )); + break; + case PRODUCT_CLUSTER_SERVER: + StringCchCat(pszOS, BUFSIZE, TEXT("Cluster Server Edition" )); + break; + case PRODUCT_DATACENTER_SERVER: + StringCchCat(pszOS, BUFSIZE, TEXT("Datacenter Edition" )); + break; + case PRODUCT_DATACENTER_SERVER_CORE: + StringCchCat(pszOS, BUFSIZE, TEXT("Datacenter Edition (core installation)" )); + break; + case PRODUCT_ENTERPRISE_SERVER: + StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition" )); + break; + case PRODUCT_ENTERPRISE_SERVER_CORE: + StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition (core installation)" )); + break; + case PRODUCT_ENTERPRISE_SERVER_IA64: + StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition for Itanium-based Systems" )); + break; + case PRODUCT_SMALLBUSINESS_SERVER: + StringCchCat(pszOS, BUFSIZE, TEXT("Small Business Server" )); + break; + case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM: + StringCchCat(pszOS, BUFSIZE, TEXT("Small Business Server Premium Edition" )); + break; + case PRODUCT_STANDARD_SERVER: + StringCchCat(pszOS, BUFSIZE, TEXT("Standard Edition" )); + break; + case PRODUCT_STANDARD_SERVER_CORE: + StringCchCat(pszOS, BUFSIZE, TEXT("Standard Edition (core installation)" )); + break; + case PRODUCT_WEB_SERVER: + StringCchCat(pszOS, BUFSIZE, TEXT("Web Server Edition" )); + break; + } + } + + if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 ) + { + if( GetSystemMetrics(SM_SERVERR2) ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Server 2003 R2, ")); + else if ( osvi.wSuiteMask & VER_SUITE_STORAGE_SERVER ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Storage Server 2003")); + else if ( osvi.wSuiteMask & VER_SUITE_WH_SERVER ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Home Server")); + else if( osvi.wProductType == VER_NT_WORKSTATION && + si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64) + { + StringCchCat(pszOS, BUFSIZE, TEXT( "Windows XP Professional x64 Edition")); + } + else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2003, ")); + + // Test for the server type. + if ( osvi.wProductType != VER_NT_WORKSTATION ) + { + if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_IA64 ) + { + if( osvi.wSuiteMask & VER_SUITE_DATACENTER ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Edition for Itanium-based Systems" )); + else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise Edition for Itanium-based Systems" )); + } + + else if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 ) + { + if( osvi.wSuiteMask & VER_SUITE_DATACENTER ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter x64 Edition" )); + else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise x64 Edition" )); + else StringCchCat(pszOS, BUFSIZE, TEXT( "Standard x64 Edition" )); + } + + else + { + if ( osvi.wSuiteMask & VER_SUITE_COMPUTE_SERVER ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Compute Cluster Edition" )); + else if( osvi.wSuiteMask & VER_SUITE_DATACENTER ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Edition" )); + else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise Edition" )); + else if ( osvi.wSuiteMask & VER_SUITE_BLADE ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Web Edition" )); + else StringCchCat(pszOS, BUFSIZE, TEXT( "Standard Edition" )); + } + } + } + + if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 ) + { + StringCchCat(pszOS, BUFSIZE, TEXT("Windows XP ")); + if( osvi.wSuiteMask & VER_SUITE_PERSONAL ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Home Edition" )); + else StringCchCat(pszOS, BUFSIZE, TEXT( "Professional" )); + } + + if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 ) + { + StringCchCat(pszOS, BUFSIZE, TEXT("Windows 2000 ")); + + if ( osvi.wProductType == VER_NT_WORKSTATION ) + { + StringCchCat(pszOS, BUFSIZE, TEXT( "Professional" )); + } + else + { + if( osvi.wSuiteMask & VER_SUITE_DATACENTER ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Server" )); + else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) + StringCchCat(pszOS, BUFSIZE, TEXT( "Advanced Server" )); + else StringCchCat(pszOS, BUFSIZE, TEXT( "Server" )); + } + } + + // Include service pack (if any) and build number. + + if( strlen(osvi.szCSDVersion) > 0 ) + { + StringCchCat(pszOS, BUFSIZE, TEXT(" ") ); + StringCchCat(pszOS, BUFSIZE, osvi.szCSDVersion); + } + + TCHAR buf[80]; + + StringCchPrintf( buf, 80, TEXT(" (build %d)"), osvi.dwBuildNumber); + StringCchCat(pszOS, BUFSIZE, buf); + + if ( osvi.dwMajorVersion >= 6 ) + { + if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 ) + StringCchCat(pszOS, BUFSIZE, TEXT( ", 64-bit" )); + else if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_INTEL ) + StringCchCat(pszOS, BUFSIZE, TEXT(", 32-bit")); + } + + return pszOS; + } + else + { + printf( "This sample does not support this version of Windows.\n"); + return pszOS; + } + } +#else +std::string get_nix_version_display_string() +{ + utsname un; + + if(uname(&un) < 0) + return std::string("*nix: failed to get os version"); + return std::string() + un.sysname + " " + un.version + " " + un.release; +} +#endif + + + + std::string get_os_version_string() + { +#ifdef WIN32 + return get_windows_version_display_string(); +#else + return get_nix_version_display_string(); +#endif + } + + + +#ifdef WIN32 + std::string get_special_folder_path(int nfolder, bool iscreate) + { + namespace fs = boost::filesystem; + char psz_path[MAX_PATH] = ""; + + if(SHGetSpecialFolderPathA(NULL, psz_path, nfolder, iscreate)) + { + return psz_path; + } + + LOG_ERROR("SHGetSpecialFolderPathA() failed, could not obtain requested path."); + return ""; + } +#endif + + std::string get_default_data_dir() + { + //namespace fs = boost::filesystem; + // Windows < Vista: C:\Documents and Settings\Username\Application Data\CURRENCY_NAME_SHORT + // Windows >= Vista: C:\Users\Username\AppData\Roaming\CURRENCY_NAME_SHORT + // Mac: ~/Library/Application Support/CURRENCY_NAME_SHORT + // Unix: ~/.CURRENCY_NAME_SHORT + std::string config_folder; +#ifdef WIN32 + // Windows +#ifdef _M_X64 + config_folder = get_special_folder_path(CSIDL_APPDATA, true) + "/" + CURRENCY_NAME_SHORT; +#else + config_folder = get_special_folder_path(CSIDL_APPDATA, true) + "/" + CURRENCY_NAME_SHORT + "-x86"; +#endif +#else + std::string pathRet; + char* pszHome = getenv("HOME"); + if (pszHome == NULL || strlen(pszHome) == 0) + pathRet = "/"; + else + pathRet = pszHome; +#ifdef __APPLE__ + // Mac + pathRet += "/Library/Application Support"; + config_folder = (pathRet + "/" + CURRENCY_NAME_SHORT); +#else + // Unix + config_folder = (pathRet + "/." + CURRENCY_NAME_SHORT); +#endif +#endif + + return config_folder; + } + std::string get_host_computer_name() + { + char szname[1024] = ""; + gethostname(szname, sizeof(szname)); + szname[sizeof(szname)-1] = 0; //just to be sure + return szname; + } + + + std::string get_default_user_dir() + { + //namespace fs = boost::filesystem; + // Windows < Vista: C:\Documents and Settings\Username + // Windows >= Vista: C:\Users\Username\AppData\Roaming\CURRENCY_NAME_SHORT + // Mac: ~/Library/Application Support/CURRENCY_NAME_SHORT + // Unix: ~/.CURRENCY_NAME_SHORT + std::string wallets_dir; +#ifdef WIN32 + // Windows + wallets_dir = get_special_folder_path(CSIDL_PERSONAL, true) + "/" + CURRENCY_NAME_BASE; +#else + std::string pathRet; + char* pszHome = getenv("HOME"); + if (pszHome == NULL || strlen(pszHome) == 0) + pathRet = "/"; + else + pathRet = pszHome; + + wallets_dir = (pathRet + "/" + CURRENCY_NAME_BASE); + +#endif + return wallets_dir; + } + + std::string get_current_username() + { +#ifdef WIN32 + // Windows + const char* psz_username = getenv("USERNAME"); +#else + const char* psz_username = getenv("USER"); +#endif + if (psz_username == NULL || strlen(psz_username) == 0) + psz_username = "unknown_user"; + + return std::string(psz_username); + } + + + + bool create_directories_if_necessary(const std::string& path) + { + namespace fs = boost::filesystem; + boost::system::error_code ec; + fs::path fs_path(path); + if (fs::is_directory(fs_path, ec)) + { + return true; + } + + bool res = fs::create_directories(fs_path, ec); + if (res) + { + LOG_PRINT_L2("Created directory: " << path); + } + else + { + LOG_PRINT_L2("Can't create directory: " << path << ", err: "<< ec.message()); + } + + return res; + } + + std::error_code replace_file(const std::string& replacement_name, const std::string& replaced_name) + { + int code; +#if defined(WIN32) + // Maximizing chances for success + DWORD attributes = ::GetFileAttributes(replaced_name.c_str()); + if (INVALID_FILE_ATTRIBUTES != attributes) + { + ::SetFileAttributes(replaced_name.c_str(), attributes & (~FILE_ATTRIBUTE_READONLY)); + } + + bool ok = 0 != ::MoveFileEx(replacement_name.c_str(), replaced_name.c_str(), MOVEFILE_REPLACE_EXISTING); + code = ok ? 0 : static_cast(::GetLastError()); +#else + bool ok = 0 == std::rename(replacement_name.c_str(), replaced_name.c_str()); + code = ok ? 0 : errno; +#endif + return std::error_code(code, std::system_category()); + } +} diff --git a/src/common/util.h b/src/common/util.h new file mode 100644 index 00000000..2166b6ca --- /dev/null +++ b/src/common/util.h @@ -0,0 +1,334 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#define BOOST_FILESYSTEM_VERSION 3 +#define BOOST_NO_CXX11_SCOPED_ENUMS + +#include +#include +#include + +#include "crypto/crypto.h" +#include "crypto/hash.h" +#include "misc_language.h" +#include "p2p/p2p_protocol_defs.h" + +#if defined(WIN32) +#include +#endif + +namespace tools +{ + std::string get_host_computer_name(); + std::string get_default_data_dir(); + std::string get_default_user_dir(); + std::string get_current_username(); + std::string get_os_version_string(); + bool create_directories_if_necessary(const std::string& path); + std::error_code replace_file(const std::string& replacement_name, const std::string& replaced_name); + + inline crypto::hash get_proof_of_trust_hash(const nodetool::proof_of_trust& pot) + { + std::string s; + s.append(reinterpret_cast(&pot.peer_id), sizeof(pot.peer_id)); + s.append(reinterpret_cast(&pot.time), sizeof(pot.time)); + return crypto::cn_fast_hash(s.data(), s.size()); + } + + inline + crypto::public_key get_public_key_from_string(const std::string& str_key) + { + crypto::public_key k = AUTO_VAL_INIT(k); + epee::string_tools::hex_to_pod(str_key, k); + return k; + } + + + class signal_handler + { + public: + template + static bool install(T t) + { +#if defined(WIN32) + bool r = TRUE == ::SetConsoleCtrlHandler(&win_handler, TRUE); + if (r) + { + m_handler = t; + } + return r; +#else + signal(SIGINT, posix_handler); + signal(SIGTERM, posix_handler); + m_handler = t; + return true; +#endif + } + + template + static void install_fatal(T t) + { +#if defined(WIN32) + // NOTE: Unfortunately, there's no way to handle heap corruption signals/exceptions. More info: https://connect.microsoft.com/VisualStudio/feedback/details/664497/cant-catch-0xc0000374-exception-status-heap-corruption + ::SetUnhandledExceptionFilter(win_unhandled_exception_handler); +#else + signal(SIGABRT, posix_fatal_handler); + signal(SIGSEGV, posix_fatal_handler); + signal(SIGILL, posix_fatal_handler); +#endif + + m_fatal_handler = t; + } + + static void uninstall_fatal() + { +#if defined(WIN32) + ::SetUnhandledExceptionFilter(NULL); +#endif + signal(SIGABRT, SIG_DFL); + signal(SIGSEGV, SIG_DFL); + signal(SIGILL, SIG_DFL); + m_fatal_handler = &noop_fatal_handler; + } + + private: +#if defined(WIN32) + static BOOL WINAPI win_handler(DWORD type) + { + if (CTRL_C_EVENT == type || CTRL_BREAK_EVENT == type) + { + handle_signal(); + return TRUE; + } + else + { + LOG_PRINT_RED_L0("Got control signal " << type << ". Exiting without saving..."); + return FALSE; + } + return TRUE; + } + + /************************************************************************/ + // This code borrowed from http://www.debuginfo.com/articles/effminidumps2.html + /************************************************************************/ + + /////////////////////////////////////////////////////////////////////////////// + // This function determines whether we need data sections of the given module + // + + static bool IsDataSectionNeeded(const WCHAR* pModuleName) + { + // Check parameters + if (pModuleName == 0) + { + return false; + } + + // Extract the module name + + WCHAR szFileName[_MAX_FNAME] = L""; + + _wsplitpath(pModuleName, NULL, NULL, szFileName, NULL); + // Compare the name with the list of known names and decide + // Note: For this to work, the executable name must be "mididump.exe" + if (wcsicmp(szFileName, L"mididump") == 0) + { + return true; + } + else if (wcsicmp(szFileName, L"ntdll") == 0) + { + return true; + } + // Complete + return false; + } + + /////////////////////////////////////////////////////////////////////////////// + // Custom minidump callback + // + + static BOOL CALLBACK MyMiniDumpCallback(PVOID pParam, const PMINIDUMP_CALLBACK_INPUT pInput, + PMINIDUMP_CALLBACK_OUTPUT pOutput) + { + BOOL bRet = FALSE; + // Check parameters + if (pInput == 0) + return FALSE; + + if (pOutput == 0) + return FALSE; + + // Process the callbacks + switch (pInput->CallbackType) + { + case IncludeModuleCallback: + { + // Include the module into the dump + bRet = TRUE; + } + break; + + case IncludeThreadCallback: + { + // Include the thread into the dump + bRet = TRUE; + } + break; + + case ModuleCallback: + { + // Are data sections available for this module ? + + if (pOutput->ModuleWriteFlags & ModuleWriteDataSeg) + { + // Yes, they are, but do we need them? + + if (!IsDataSectionNeeded(pInput->Module.FullPath)) + { + wprintf(L"Excluding module data sections: %s \n", pInput->Module.FullPath); + + pOutput->ModuleWriteFlags &= (~ModuleWriteDataSeg); + } + } + + bRet = TRUE; + } + break; + + case ThreadCallback: + { + // Include all thread information into the minidump + bRet = TRUE; + } + break; + + case ThreadExCallback: + { + // Include this information + bRet = TRUE; + } + break; + + case MemoryCallback: + { + // We do not include any information here -> return FALSE + bRet = FALSE; + } + break; + + case CancelCallback: + break; + } + + return bRet; + + } + + static void GenerateCrashDump(EXCEPTION_POINTERS *pep = NULL) + + { + SYSTEMTIME sysTime = { 0 }; + GetSystemTime(&sysTime); + // get the computer name + char compName[MAX_COMPUTERNAME_LENGTH + 1] = { 0 }; + DWORD compNameLen = ARRAYSIZE(compName); + GetComputerNameA(compName, &compNameLen); + // build the filename: APPNAME_COMPUTERNAME_DATE_TIME.DMP + char path[MAX_PATH*10] = { 0 }; + std::string folder = epee::log_space::log_singletone::get_default_log_folder(); + sprintf_s(path, ARRAYSIZE(path),"%s\\crashdump_%s_%04u-%02u-%02u_%02u-%02u-%02u.dmp", + folder.c_str(), compName, sysTime.wYear, sysTime.wMonth, sysTime.wDay, + sysTime.wHour, sysTime.wMinute, sysTime.wSecond); + + HANDLE hFile = CreateFileA(path, GENERIC_READ | GENERIC_WRITE, + 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE)) + { + // Create the minidump + MINIDUMP_EXCEPTION_INFORMATION mdei; + + mdei.ThreadId = GetCurrentThreadId(); + mdei.ExceptionPointers = pep; + mdei.ClientPointers = FALSE; + + MINIDUMP_CALLBACK_INFORMATION mci; + + mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MyMiniDumpCallback; + mci.CallbackParam = 0; + + MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)(MiniDumpWithPrivateReadWriteMemory | + MiniDumpWithDataSegs | + MiniDumpWithHandleData | + MiniDumpWithFullMemoryInfo | + MiniDumpWithThreadInfo | + MiniDumpWithUnloadedModules); + + BOOL rv = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), + hFile, mdt, (pep != 0) ? &mdei : 0, 0, &mci); + + if (!rv) + { + LOG_ERROR("Minidump file create FAILED(error " << GetLastError() << ") on path: " << path); + } + else + { + LOG_PRINT_L0("Minidump file created on path: " << path); + } + // Close the file + CloseHandle(hFile); + } + else + { + LOG_ERROR("Minidump FAILED to create file (error " << GetLastError() << ") on path: " << path); + } + } + + + + static LONG WINAPI win_unhandled_exception_handler(_In_ struct _EXCEPTION_POINTERS *ep) + { + GenerateCrashDump(ep); + handle_fatal_signal(ep->ExceptionRecord->ExceptionCode, ep->ExceptionRecord->ExceptionAddress); + return EXCEPTION_EXECUTE_HANDLER; + } + +#else + static void posix_handler(int /*type*/) + { + handle_signal(); + } +#endif + + static void posix_fatal_handler(int sig_number) + { + handle_fatal_signal(sig_number, 0); + } + + static void noop_fatal_handler(int, void*) {} + + static void handle_signal() + { + static std::mutex m_mutex; + std::unique_lock lock(m_mutex); + m_handler(); + } + + static void handle_fatal_signal(int sig_number, void* address) + { + static std::mutex m_mutex_fatal; + std::unique_lock lock(m_mutex_fatal); + m_fatal_handler(sig_number, address); + uninstall_fatal(); + } + + private: + static std::function m_handler; + static std::function m_fatal_handler; + }; +} diff --git a/src/common/varint.h b/src/common/varint.h new file mode 100644 index 00000000..249fce23 --- /dev/null +++ b/src/common/varint.h @@ -0,0 +1,86 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include +#include +#include +#include + +namespace tools { + + + //--------------------------------------------------------------- + template + size_t get_varint_packed_size(T v) + { + if(v <= 127) + return 1; + else if(v <= 16383) + return 2; + else if(v <= 2097151) + return 3; + else if(v <= 268435455) + return 4; + else if(v <= 34359738367) + return 5; + else if(v <= 4398046511103) + return 6; + else if(v <= 562949953421311) + return 7; + else + return 8; + } + template + typename std::enable_if::value && std::is_unsigned::value, void>::type + write_varint(OutputIt &&dest, T i) { + while (i >= 0x80) { + *dest++ = (static_cast(i) & 0x7f) | 0x80; + i >>= 7; + } + *dest++ = static_cast(i); + } + + template + std::string get_varint_data(const t_type& v) + { + std::stringstream ss; + write_varint(std::ostreambuf_iterator(ss), v); + return ss.str(); + } + + template + typename std::enable_if::value && std::is_unsigned::value && 0 <= bits && bits <= std::numeric_limits::digits, int>::type + read_varint(InputIt &&first, InputIt &&last, T &i) { + int read = 0; + i = 0; + for (int shift = 0;; shift += 7) { + if (first == last) { + return read; // End of input. + } + unsigned char byte = *first++; + ++read; + if (shift + 7 >= bits && byte >= 1 << (bits - shift)) { + return -1; // Overflow. + } + if (byte == 0 && shift != 0) { + return -2; // Non-canonical representation. + } + i |= static_cast(byte & 0x7f) << shift; + if ((byte & 0x80) == 0) { + break; + } + } + return read; + } + + template + int read_varint(InputIt &&first, InputIt &&last, T &i) { + return read_varint::digits, InputIt, T>(std::move(first), std::move(last), i); + } +} diff --git a/src/connectivity_tool/conn_tool.cpp b/src/connectivity_tool/conn_tool.cpp new file mode 100644 index 00000000..031b248d --- /dev/null +++ b/src/connectivity_tool/conn_tool.cpp @@ -0,0 +1,940 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + + + +#include "include_base_utils.h" +#include "version.h" + +using namespace epee; +#include +#include "p2p/p2p_protocol_defs.h" +#include "common/command_line.h" +#include "currency_core/currency_core.h" +#include "currency_protocol/currency_protocol_handler.h" +#include "net/levin_client.h" +#include "storages/levin_abstract_invoke2.h" +#include "currency_core/currency_core.h" +#include "storages/portable_storage_template_helper.h" +#include "crypto/crypto.h" +#include "storages/http_abstract_invoke.h" +#include "net/http_client.h" +#include "currency_core/genesis_acc.h" + + +namespace po = boost::program_options; +using namespace currency; +using namespace nodetool; + + + + + + +namespace +{ + const command_line::arg_descriptor arg_ip = {"ip", "set ip"}; + const command_line::arg_descriptor arg_port = {"port", "set port"}; + const command_line::arg_descriptor arg_rpc_port = {"rpc-port", "set rpc port", RPC_DEFAULT_PORT}; + const command_line::arg_descriptor arg_timeout = {"timeout", "set timeout", 5000}; + const command_line::arg_descriptor arg_priv_key = {"private-key", "private key to subscribe debug command", "", true}; + const command_line::arg_descriptor arg_peer_id = {"peer-id", "peerid if known(if not - will be requested)", 0}; + const command_line::arg_descriptor arg_generate_keys = {"generate-keys-pair", "generate private and public keys pair"}; + const command_line::arg_descriptor arg_request_stat_info = {"request-stat-info", "request statistics information"}; + const command_line::arg_descriptor arg_log_journal_len = { "log-journal-len", "Specify length of list of last error messages in log", 0, true }; + const command_line::arg_descriptor arg_request_net_state = {"request-net-state", "request network state information (peer list, connections count)"}; + const command_line::arg_descriptor arg_get_daemon_info = {"rpc-get-daemon-info", "request daemon state info vie rpc (--rpc-port option should be set ).", "", true}; + const command_line::arg_descriptor arg_get_aliases = {"rpc-get-aliases", "request daemon aliases all list", "", true}; + const command_line::arg_descriptor arg_increment_build_no = { "increment-build-no", "Increment build nimber", "", true }; + const command_line::arg_descriptor arg_upate_maintainers_info = {"update-maintainers-info", "Push maintainers info into the network, update-maintainers-info=file-with-info.json", "", true}; + const command_line::arg_descriptor arg_update_build_no = {"update-build-no", "Updated version number in version template file", "", true}; + const command_line::arg_descriptor arg_generate_genesis = {"generate-genesis", "Generate genesis coinbase based on config file", "", true }; + const command_line::arg_descriptor arg_genesis_split_amount = { "genesis-split-amount", "Set split amount for generating genesis block", 0, true }; + const command_line::arg_descriptor arg_get_info_flags = { "getinfo-flags-hex", "Set of bits for rpc-get-daemon-info", "", true }; +} + +typedef COMMAND_REQUEST_STAT_INFO_T::stat_info> COMMAND_REQUEST_STAT_INFO; + +struct response_schema +{ + std::string status; + std::string COMMAND_REQUEST_STAT_INFO_status; + std::string COMMAND_REQUEST_NETWORK_STATE_status; + enableable si_rsp; + enableable ns_rsp; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(COMMAND_REQUEST_STAT_INFO_status) + KV_SERIALIZE(COMMAND_REQUEST_NETWORK_STATE_status) + KV_SERIALIZE(si_rsp) + KV_SERIALIZE(ns_rsp) + END_KV_SERIALIZE_MAP() +}; + + std::string get_response_schema_as_json(response_schema& rs) + { + std::stringstream ss; + ss << "{" << ENDL + << " \"status\": \"" << rs.status << "\"," << ENDL + << " \"COMMAND_REQUEST_NETWORK_STATE_status\": \"" << rs.COMMAND_REQUEST_NETWORK_STATE_status << "\"," << ENDL + << " \"COMMAND_REQUEST_STAT_INFO_status\": \"" << rs.COMMAND_REQUEST_STAT_INFO_status << "\""; + if(rs.si_rsp.enabled) + { + ss << "," << ENDL << " \"si_rsp\": " << epee::serialization::store_t_to_json(rs.si_rsp.v, 1); + } + if(rs.ns_rsp.enabled) + { + ss << "," << ENDL << " \"ns_rsp\": {" << ENDL + << " \"local_time\": " << rs.ns_rsp.v.local_time << "," << ENDL + << " \"my_id\": \"" << rs.ns_rsp.v.my_id << "\"," << ENDL + << " \"up_time\": \"" << rs.ns_rsp.v.up_time << "\"," << ENDL + << " \"connections_list\": [" << ENDL; + + size_t i = 0; + for(const connection_entry& ce : rs.ns_rsp.v.connections_list) + { + ss << " {" + "\"peer_id\": \"" << ce.id << "\", " + "\"ip\": \"" << string_tools::get_ip_string_from_int32(ce.adr.ip) << "\", " + "\"port\": " << ce.adr.port << ", " + "\"time_started\": " << ce.time_started << ", " + "\"last_recv\": " << ce.last_recv << ", " + "\"last_send\": " << ce.last_send << ", " + "\"is_income\": " << ce.is_income << "}"; + if(rs.ns_rsp.v.connections_list.size()-1 != i) + ss << ","; + ss << ENDL; + i++; + } + ss << " ]," << ENDL; + ss << " \"local_peerlist_white\": [" << ENDL; + i = 0; + for(const peerlist_entry& pe : rs.ns_rsp.v.local_peerlist_white) + { + ss << " {\"peer_id\": \"" << pe.id << "\", \"ip\": \"" << string_tools::get_ip_string_from_int32(pe.adr.ip) << "\", \"port\": " << pe.adr.port << ", \"last_seen\": "<< rs.ns_rsp.v.local_time - pe.last_seen << "}"; + if(rs.ns_rsp.v.local_peerlist_white.size()-1 != i) + ss << ","; + ss << ENDL; + i++; + } + ss << " ]," << ENDL; + + ss << " \"local_peerlist_gray\": [" << ENDL; + i = 0; + for(const peerlist_entry& pe : rs.ns_rsp.v.local_peerlist_gray) + { + ss << " {\"peer_id\": \"" << pe.id << "\", \"ip\": \"" << string_tools::get_ip_string_from_int32(pe.adr.ip) << "\", \"port\": " << pe.adr.port << ", \"last_seen\": "<< rs.ns_rsp.v.local_time - pe.last_seen << "}"; + if(rs.ns_rsp.v.local_peerlist_gray.size()-1 != i) + ss << ","; + ss << ENDL; + i++; + } + ss << " ]" << ENDL << " }" << ENDL; + } + ss << "}" << ENDL; + return ss.str(); + } +//--------------------------------------------------------------------------------------------------------------- +bool print_COMMAND_REQUEST_STAT_INFO(const COMMAND_REQUEST_STAT_INFO::response& si) +{ + std::cout << " ------ COMMAND_REQUEST_STAT_INFO ------ " << ENDL; + std::cout << "Version: " << si.version << ENDL; + std::cout << "Connections: " << si.connections_count << ENDL; + std::cout << "INC Connections: " << si.incoming_connections_count << ENDL; + + + std::cout << "Tx pool size: " << si.payload_info.tx_pool_size << ENDL; + std::cout << "BC height: " << si.payload_info.blockchain_height << ENDL; + std::cout << "Mining speed: " << si.payload_info.mining_speed << ENDL; + std::cout << "Alternative blocks: " << si.payload_info.alternative_blocks << ENDL; + std::cout << "Top block id: " << si.payload_info.top_block_id_str << ENDL; + return true; +} +//--------------------------------------------------------------------------------------------------------------- +bool print_COMMAND_REQUEST_NETWORK_STATE(const COMMAND_REQUEST_NETWORK_STATE::response& ns) +{ + std::cout << " ------ COMMAND_REQUEST_NETWORK_STATE ------ " << ENDL; + std::cout << "Peer id: " << ns.my_id << ENDL; + std::cout << "Active connections:" << ENDL; + BOOST_FOREACH(const connection_entry& ce, ns.connections_list) + { + std::cout << ce.id << "\t" << string_tools::get_ip_string_from_int32(ce.adr.ip) << ":" << ce.adr.port << (ce.is_income ? "(INC)":"(OUT)") << ENDL; + } + + std::cout << "Peer list white:" << ns.my_id << ENDL; + BOOST_FOREACH(const peerlist_entry& pe, ns.local_peerlist_white) + { + std::cout << pe.id << "\t" << string_tools::get_ip_string_from_int32(pe.adr.ip) << ":" << pe.adr.port << "\t" << misc_utils::get_time_interval_string(ns.local_time - pe.last_seen) << ENDL; + } + + std::cout << "Peer list gray:" << ns.my_id << ENDL; + BOOST_FOREACH(const peerlist_entry& pe, ns.local_peerlist_gray) + { + std::cout << pe.id << "\t" << string_tools::get_ip_string_from_int32(pe.adr.ip) << ":" << pe.adr.port << "\t" << misc_utils::get_time_interval_string(ns.local_time - pe.last_seen) << ENDL; + } + + + return true; +} + + + +std::string split_to_c_literal_lines(const std::string& str, size_t line_len) +{ + std::stringstream res; + size_t current_offset = 0; + while (current_offset < str.size()) + { + if (current_offset + line_len > str.size()) + line_len = str.size() - current_offset; + + res << "\"" << str.substr(current_offset, line_len) << "\"" << ENDL ; + current_offset += line_len; + } + return res.str(); +} + +template +std::string pod_to_uint8_array(const t_pod& v) +{ + using namespace std; + uint8_t* parray = (uint8_t*)&v; + size_t count = sizeof(t_pod); + std::stringstream ss; + for (size_t i = 0; i != count; i++) + { + ss << (i == 0 ? "0x" : ",0x") << hex << setw(2) << setfill('0') << +parray[i]; + } + return ss.str(); +} + + +template +std::basic_string buff_to_uint64_array(const std::basic_string& s) +{ + using namespace std; + + + uint64_t* parray = (uint64_t*)s.data(); + size_t count = s.size() / sizeof(uint64_t); + size_t rest_bytes = s.size() - count * sizeof(uint64_t); + + + basic_stringstream hexStream; + hexStream << "--------- genesis.h---------" << ENDL + << "#pragma pack(push, 1)" << ENDL + << "struct genesis_tx_raw_data" << ENDL + << "{" << ENDL + << " uint64_t const v[" << count << "];" << ENDL + << " uint8_t const r[" << rest_bytes << "];" << ENDL + << "};" << ENDL + << "#pragma pack(pop)" << ENDL + << "extern const genesis_tx_raw_data ggenesis_tx_raw;" << ENDL + << ENDL + << "--------- genesis.cpp---------" << ENDL + << "const genesis_tx_raw_data ggenesis_tx_raw = {{" << ENDL; + ; + + //hexStream << hex << ; //<< noshowbase; + + for (size_t i = 0; i != count; i++) + { + hexStream << (i == 0 ? "0x":",0x")<< hex << setw(16) << setfill('0') << parray[i]; + } + hexStream << "}," << ENDL << "{"; + uint8_t* ptail_array = (uint8_t*)&parray[count]; + for (size_t i = 0; i != rest_bytes; i++) + { + hexStream << (i == 0 ? "0x":",0x") << hex << setw(2) << setfill('0') << +ptail_array[i]; + } + hexStream << "}};" << ENDL; + return hexStream.str(); +} + +struct payment_method_summary +{ + double amount_total; + uint64_t amount_paid_this; + double amount_usd_eq; +}; + +void process_payment_entrie(payment_method_summary& pms, const std::string& amount_in_coin, uint64_t amount_in_this, const std::string& to_usd_rate) +{ + double d_amount_in_coin = std::stod(amount_in_coin); + double d_to_usd_rate = std::stod(to_usd_rate); + //CHECK_AND_ASSERT_THROW_MES(d_amount_in_coin, "unable to parse amount_in_coin: " << amount_in_coin); + CHECK_AND_ASSERT_THROW_MES(amount_in_this, "unable to parse amount_this"); + //CHECK_AND_ASSERT_THROW_MES(d_to_usd_rate, "unable to parse to_usd_rate: " << to_usd_rate); + pms.amount_total += d_amount_in_coin; + pms.amount_paid_this += amount_in_this; + pms.amount_usd_eq += d_amount_in_coin * d_amount_in_coin; +} + +uint64_t get_total_from_payments_stat(const std::map& payments_stat) +{ + uint64_t total_this = 0; + for (const auto& se : payments_stat) + { + total_this += se.second.amount_paid_this; + } + return total_this; +} + +bool generate_genesis(const std::string& path_config, uint64_t premine_split_amount) +{ + TIME_MEASURE_START_MS(load_json_time); + currency::genesis_config_json_struct gcp = AUTO_VAL_INIT(gcp); + if (!epee::serialization::load_t_from_json_file(gcp, path_config)) + { + LOG_ERROR("Failed to open JSON file from " << path_config); + return false; + } + TIME_MEASURE_FINISH_MS(load_json_time); + + TIME_MEASURE_START_MS(loading_to_map); + std::map amounts_map; + for (auto& p : gcp.payments) + { + p.amount_this_coin_int = std::round(p.amount_this_coin_fl * COIN); + amounts_map[p.address_this] = p.amount_this_coin_int; + } + TIME_MEASURE_FINISH_MS(loading_to_map); + TIME_MEASURE_START_MS(loading_to_map2); + std::map amounts_map2; + auto hint_it = amounts_map2.insert(*amounts_map.begin()).first; + for (auto it = ++amounts_map.begin(); it != amounts_map.end(); it++) + { + hint_it = amounts_map2.insert(hint_it, *it); + } + TIME_MEASURE_FINISH_MS(loading_to_map2); + + std::cout << "path: " << path_config << ENDL << "items " << amounts_map.size() + << ", load_json_time:" << load_json_time + << ", loading_to_map: " << loading_to_map + << ", loading_to_map2: " << loading_to_map2 << ENDL; + + + currency::block bl = boost::value_initialized(); + + std::vector destinations; + tx_destination_entry de = AUTO_VAL_INIT(de); + de.addr.resize(1); + + + std::map payments_stat; + + //make sure it initialized with zeros + payments_stat["qtum"] = payments_stat["bch"] + = payments_stat["rep"] = payments_stat["dash"] + = payments_stat["ltc"] = payments_stat["eos"] + = payments_stat["eth"] = payments_stat["btc"] + = payments_stat["prm"] + = AUTO_VAL_INIT_T(payment_method_summary); + + uint64_t summary_premine_coins = 0; + for (auto& p: gcp.payments) + { + + bool r = get_account_address_from_str(de.addr.back(), p.address_this); + CHECK_AND_ASSERT_MES(r, false, "wrong address string: " << p.address_this); + + de.amount = p.amount_this_coin_int; //std::cout << de.amount << ENDL; + summary_premine_coins += de.amount; + destinations.push_back(de); + + +#define PROCESS_XXX_COIN_ENTRIE(ticker) else if (!p.paid_ ## ticker.empty()) \ + { \ + process_payment_entrie(payments_stat[#ticker], p.paid_ ## ticker, p.amount_this_coin_int, p. ticker ## _usd_price); \ + } + + if (false) {} + PROCESS_XXX_COIN_ENTRIE(qtum) + PROCESS_XXX_COIN_ENTRIE(bch) + PROCESS_XXX_COIN_ENTRIE(rep) + PROCESS_XXX_COIN_ENTRIE(dash) + PROCESS_XXX_COIN_ENTRIE(ltc) + PROCESS_XXX_COIN_ENTRIE(eos) + PROCESS_XXX_COIN_ENTRIE(eth) + PROCESS_XXX_COIN_ENTRIE(btc) + PROCESS_XXX_COIN_ENTRIE(prm) + PROCESS_XXX_COIN_ENTRIE(xmr) + + // self check + if (summary_premine_coins != get_total_from_payments_stat(payments_stat)) + { + LOG_ERROR("Internal error: missmatch of balances"); + } + } + + uint64_t total_this = 0; + double total_usd_eq = 0; + + std::stringstream ss; + ss.precision(10); + ss << std::setw(15) << std::left << "NAME" << std::setw(15) << std::left << "AMOUNT" << std::setw(15) << std::left << "AMOUNT THIS" << std::setw(15) << std::left << "USD EQ" << ENDL; + for (auto& se : payments_stat) + { + ss << std::setw(15) << std::left << se.first << std::setw(15) << std::fixed << std::left << se.second.amount_total << std::setw(15) << std::fixed << std::left << print_money(se.second.amount_paid_this) << std::setw(15) << std::fixed << std::left << se.second.amount_usd_eq << ENDL; + total_this += se.second.amount_paid_this; + total_usd_eq += se.second.amount_usd_eq; + } + ss << ENDL << std::setw(15) << std::left << "TOTAL" << std::setw(15) << std::fixed << std::left << " " << std::setw(15) << std::fixed << std::left << print_money(total_this) << std::setw(15) << std::fixed << std::left << total_usd_eq << ENDL; + + ss << ENDL << std::setw(15) << std::left << "PREMINE_AMOUNT" << std::setw(15) << std::fixed << std::left << " " << std::setw(15) << std::fixed << std::left << total_this << "(" << print_money(total_this) <<"THIS)" << ENDL; + + epee::log_space::set_console_color(epee::log_space::console_colors::console_color_magenta, true); + std::cout << "GENESIS STAT: " << ENDL << ss.str(); + epee::log_space::set_console_color(epee::log_space::console_colors::console_color_default, false); + + bool r = file_io_utils::save_string_to_file(path_config + ".premine_stat.txt", ss.str()); + + + ss.str(""); + ss.clear(); + construct_miner_tx(0, 0, 0, 0, 0, destinations, bl.miner_tx, gcp.proof_string, CURRENCY_MINER_TX_MAX_OUTS); + currency::blobdata txb = tx_to_blob(bl.miner_tx); + + //self validate block + + if (currency::get_outs_money_amount(bl.miner_tx) != total_this || summary_premine_coins != total_this) + { + LOG_ERROR("Internal error: total_this = " << total_this << " didn't match with miner_tx total = " << currency::get_outs_money_amount(bl.miner_tx)); + } + + + + std::string hex_tx_represent = string_tools::buff_to_hex_nodelimer(txb); + std::string uint64_t_array_represent = /*string_tools::*/buff_to_uint64_array(txb); + + r = file_io_utils::save_string_to_file(path_config + ".genesis.txt", hex_tx_represent); + CHECK_AND_ASSERT_MES_NO_RET(r, "failed to create " << path_config << ".genesis.txt"); + r = file_io_utils::save_string_to_file(path_config + ".genesis.uint64.array.txt", uint64_t_array_represent); + CHECK_AND_ASSERT_MES_NO_RET(r, "failed to create " << path_config << ".genesis.uint64.array.txt"); + + //generate address dictionary + std::map ordered_keys; + uint64_t i = 0; + for (auto& p : gcp.payments) + { + uint64_t key = currency::get_string_uint64_hash(p.address_this); + auto it = ordered_keys.find(key); + if (it != ordered_keys.end()) + { + LOG_ERROR("Collision found on address " << p.address_this << " key: " << key << " offset_associated: " << it->second); + return false; + } + ordered_keys[key] = i; + i++; + } + //dump it to file + + ss << "-------------genesis_acc.cpp-------------" << ENDL + << "const std::string ggenesis_tx_pub_key_str = \"" << string_tools::pod_to_hex(get_tx_pub_key_from_extra(bl.miner_tx)) << "\";" << ENDL; + ss << "const crypto::public_key ggenesis_tx_pub_key = epee::string_tools::parse_tpod_from_hex_string(ggenesis_tx_pub_key_str);" << ENDL + << "extern const genesis_tx_dictionary_entry ggenesis_dict[" << ordered_keys.size() << "];" << ENDL + << "const genesis_tx_dictionary_entry ggenesis_dict[" << ordered_keys.size() << "] = {"; + + for (auto it = ordered_keys.begin(); it != ordered_keys.end(); it++) + { + ss << (it == ordered_keys.begin() ? "":",") << ENDL << "{" << it->first << "ULL," << it->second << "}"; + } + ss << ENDL << "};" << ENDL; + + r = file_io_utils::save_string_to_file(path_config + ".genesis.dictionary.txt", ss.str()); + CHECK_AND_ASSERT_MES_NO_RET(r, "failed to create " << path_config << ".genesis.dictionary.txt"); + + return true; +} +//--------------------------------------------------------------------------------------------------------------- +bool handle_get_aliases(po::variables_map& vm) +{ + if(!command_line::has_arg(vm, arg_rpc_port)) + { + std::cout << "{" << ENDL << " \"status\": \"ERROR: " << "RPC port not set \"" << ENDL << "}" << ENDL; + return false; + } + + epee::net_utils::http::http_simple_client http_client; + + currency::COMMAND_RPC_GET_ALL_ALIASES::request req = AUTO_VAL_INIT(req); + currency::COMMAND_RPC_GET_ALL_ALIASES::response res = AUTO_VAL_INIT(res); + std::string daemon_addr = command_line::get_arg(vm, arg_ip) + ":" + std::to_string(command_line::get_arg(vm, arg_rpc_port)); + bool r = epee::net_utils::invoke_http_json_rpc(daemon_addr + "/json_rpc", "get_all_alias_details", req, res, http_client, command_line::get_arg(vm, arg_timeout)); + if(!r) + { + std::cout << "{" << ENDL << " \"status\": \"ERROR: " << "Failed to invoke request \"" << ENDL << "}" << ENDL; + return false; + } + std::cout << epee::serialization::store_t_to_json(res); + + return true; +} +//--------------------------------------------------------------------------------------------------------------- +bool handle_get_daemon_info(po::variables_map& vm) +{ + if(!command_line::has_arg(vm, arg_rpc_port)) + { + std::cout << "ERROR: rpc port not set" << ENDL; + return false; + } + + currency::COMMAND_RPC_GET_INFO::request req = AUTO_VAL_INIT(req); + currency::COMMAND_RPC_GET_INFO::response res = AUTO_VAL_INIT(res); + + if (command_line::has_arg(vm, arg_get_info_flags)) + { + std::string flags_str = command_line::get_arg(vm, arg_get_info_flags); + if (!epee::string_tools::get_xnum_from_hex_string(flags_str, req.flags)) + { + LOG_ERROR("Wrong flags specified, reset to all flags"); + req.flags = COMMAND_RPC_GET_INFO_FLAG_ALL_FLAGS; + } + } + else + { + //very slow case + req.flags = COMMAND_RPC_GET_INFO_FLAG_ALL_FLAGS; + } + + epee::net_utils::http::http_simple_client http_client; + + std::string daemon_addr = command_line::get_arg(vm, arg_ip) + ":" + std::to_string(command_line::get_arg(vm, arg_rpc_port)); + std::string url = daemon_addr + "/getinfo"; + bool r = net_utils::invoke_http_json_remote_command2(url, req, res, http_client, command_line::get_arg(vm, arg_timeout)); + if(!r) + { + std::cout << "ERROR: failed to invoke request to " << url << ENDL; + return false; + } + +#define PRINT_FIELD_NAME(owner_object, prefix, field_name) << prefix #field_name ": " << owner_object.field_name << ENDL + + std::cout << "OK" << ENDL + << "height: " << res.height << ENDL + << "pos_difficulty: " << res.pos_difficulty << ENDL + << "pow_difficulty: " << res.pow_difficulty << ENDL + << "tx_count: " << res.tx_count << ENDL + << "tx_pool_size: " << res.tx_pool_size << ENDL + << "alt_blocks_count: " << res.alt_blocks_count << ENDL + << "outgoing_connections_count: " << res.outgoing_connections_count << ENDL + << "incoming_connections_count: " << res.incoming_connections_count << ENDL + << "white_peerlist_size: " << res.white_peerlist_size << ENDL + << "grey_peerlist_size: " << res.grey_peerlist_size << ENDL + << "current_network_hashrate_50: " << res.current_network_hashrate_50 << ENDL + << "current_network_hashrate_350: " << res.current_network_hashrate_350 << ENDL + << "seconds_between_10_blocks: " << res.seconds_for_10_blocks << ENDL + << "seconds_between_30_blocks: " << res.seconds_for_30_blocks << ENDL + << "alias_count: " << res.alias_count << ENDL + << "transactions_cnt_per_day: " << res.transactions_cnt_per_day << ENDL + << "transactions_volume_per_day: " << res.transactions_volume_per_day << ENDL + << "pos_sequence_factor: " << res.pos_sequence_factor << ENDL + << "pow_sequence_factor: " << res.pow_sequence_factor << ENDL + << "last_pos_timestamp: " << res.last_pos_timestamp << ENDL + << "last_pow_timestamp: " << res.last_pow_timestamp << ENDL + << "total_coins: " << res.total_coins / COIN << ENDL + << "pos_difficulty_in_coins: " << currency::wide_difficulty_type(res.pos_difficulty) / COIN << ENDL + << "block_reward: " << res.block_reward << ENDL + << "last_block_total_reward: " << res.last_block_total_reward << ENDL + << "outs_stat_amount1_0_001: " << res.outs_stat.amount_0_001 << ENDL + << "outs_stat_amount2_0_01: " << res.outs_stat.amount_0_01 << ENDL + << "outs_stat_amount3_0_1: " << res.outs_stat.amount_0_1 << ENDL + << "outs_stat_amount4_1: " << res.outs_stat.amount_10 << ENDL + << "outs_stat_amount5_10: " << res.outs_stat.amount_10 << ENDL + << "outs_stat_amount6_100: " << res.outs_stat.amount_100 << ENDL + << "outs_stat_amount7_1000: " << res.outs_stat.amount_1000 << ENDL + << "outs_stat_amount8_10000: " << res.outs_stat.amount_10000 << ENDL + << "outs_stat_amount9_100000: " << res.outs_stat.amount_100000 << ENDL + << "outs_stat_amount10_1000000: " << res.outs_stat.amount_1000000 << ENDL + << "current_max_allowed_block_size: " << res.current_max_allowed_block_size << ENDL + << "last_block_size: " << res.last_block_size << ENDL + << "tx_count_in_last_block: " << res.tx_count_in_last_block << ENDL + << "pos_diff_total_coins_rate: " << res.pos_diff_total_coins_rate << ENDL + << "pos_block_ts_shift_vs_actual: " << res.pos_block_ts_shift_vs_actual << ENDL + << "block_processing_time_0: " << res.performance_data.block_processing_time_0 << ENDL + << "block_processing_time_1: " << res.performance_data.block_processing_time_1 << ENDL + << "etc_stuff_6: " << res.performance_data.etc_stuff_6 << ENDL + << "insert_time_4: " << res.performance_data.insert_time_4 << ENDL + << "longhash_calculating_time_3: " << res.performance_data.longhash_calculating_time_3 << ENDL + << "raise_block_core_event: " << res.performance_data.raise_block_core_event << ENDL + << "target_calculating_time_2: " << res.performance_data.target_calculating_time_2 << ENDL + << "all_txs_insert_time_5: " << res.performance_data.all_txs_insert_time_5 << ENDL + << "tx_add_one_tx_time: " << res.performance_data.tx_add_one_tx_time << ENDL + << "tx_check_inputs_time: " << res.performance_data.tx_check_inputs_time << ENDL + << "tx_process_attachment: " << res.performance_data.tx_process_attachment << ENDL + << "tx_process_extra: " << res.performance_data.tx_process_extra << ENDL + << "tx_process_inputs: " << res.performance_data.tx_process_inputs << ENDL + << "tx_push_global_index: " << res.performance_data.tx_push_global_index << ENDL + << "tx_check_exist: " << res.performance_data.tx_check_exist << ENDL + << "tx_store_db: " << res.performance_data.tx_store_db << ENDL + << "db_tx_count: " << res.performance_data.tx_count << ENDL + << "db_writer_tx_count: " << res.performance_data.writer_tx_count << ENDL + << "db_map_size: " << res.performance_data.map_size << ENDL + << "market_size: " << res.offers_count << ENDL + PRINT_FIELD_NAME(res.performance_data, "", tx_print_log) + PRINT_FIELD_NAME(res.performance_data, "", tx_prapare_append) + PRINT_FIELD_NAME(res.performance_data, "", tx_append_time) + PRINT_FIELD_NAME(res.performance_data, "", tx_append_rl_wait) + PRINT_FIELD_NAME(res.performance_data, "", tx_append_is_expired) + PRINT_FIELD_NAME(res.performance_data, "", tx_check_inputs_prefix_hash) + PRINT_FIELD_NAME(res.performance_data, "", tx_check_inputs_attachment_check) + PRINT_FIELD_NAME(res.performance_data, "", tx_check_inputs_loop) + PRINT_FIELD_NAME(res.performance_data, "", tx_check_inputs_loop_kimage_check) + PRINT_FIELD_NAME(res.performance_data, "", tx_check_inputs_loop_ch_in_val_sig) + PRINT_FIELD_NAME(res.performance_data, "", tx_check_inputs_loop_scan_outputkeys_get_item_size) + PRINT_FIELD_NAME(res.performance_data, "", tx_check_inputs_loop_scan_outputkeys_relative_to_absolute) + PRINT_FIELD_NAME(res.performance_data, "", tx_check_inputs_loop_scan_outputkeys_loop) + PRINT_FIELD_NAME(res.performance_data, "", tx_check_inputs_loop_scan_outputkeys_loop_get_subitem) + PRINT_FIELD_NAME(res.performance_data, "", tx_check_inputs_loop_scan_outputkeys_loop_find_tx) + PRINT_FIELD_NAME(res.performance_data, "", tx_check_inputs_loop_scan_outputkeys_loop_handle_output) + PRINT_FIELD_NAME(res.tx_pool_performance_data, "pool_", tx_processing_time) + PRINT_FIELD_NAME(res.tx_pool_performance_data, "pool_", check_inputs_types_supported_time) + PRINT_FIELD_NAME(res.tx_pool_performance_data, "pool_", expiration_validate_time) + PRINT_FIELD_NAME(res.tx_pool_performance_data, "pool_", validate_amount_time) + PRINT_FIELD_NAME(res.tx_pool_performance_data, "pool_", validate_alias_time) + PRINT_FIELD_NAME(res.tx_pool_performance_data, "pool_", check_keyimages_ws_ms_time) + PRINT_FIELD_NAME(res.tx_pool_performance_data, "pool_", check_inputs_time) + PRINT_FIELD_NAME(res.tx_pool_performance_data, "pool_", begin_tx_time) + PRINT_FIELD_NAME(res.tx_pool_performance_data, "pool_", update_db_time) + PRINT_FIELD_NAME(res.tx_pool_performance_data, "pool_", db_commit_time); + + + return true; +} +//--------------------------------------------------------------------------------------------------------------- +bool handle_request_stat(po::variables_map& vm, peerid_type peer_id) +{ + + if(!command_line::has_arg(vm, arg_priv_key)) + { + std::cout << "{" << ENDL << " \"status\": \"ERROR: " << "secret key not set \"" << ENDL << "}" << ENDL; + return false; + } + crypto::secret_key prvk = AUTO_VAL_INIT(prvk); + if(!string_tools::hex_to_pod(command_line::get_arg(vm, arg_priv_key) , prvk)) + { + std::cout << "{" << ENDL << " \"status\": \"ERROR: " << "wrong secret key set \"" << ENDL << "}" << ENDL; + return false; + } + + + response_schema rs = AUTO_VAL_INIT(rs); + + levin::levin_client_impl2 transport; + if(!transport.connect(command_line::get_arg(vm, arg_ip), static_cast(command_line::get_arg(vm, arg_port)), static_cast(command_line::get_arg(vm, arg_timeout)))) + { + std::cout << "{" << ENDL << " \"status\": \"ERROR: " << "Failed to connect to " << command_line::get_arg(vm, arg_ip) << ":" << command_line::get_arg(vm, arg_port) << "\"" << ENDL << "}" << ENDL; + return false; + }else + rs.status = "OK"; + + if(!peer_id) + { + COMMAND_REQUEST_PEER_ID::request req = AUTO_VAL_INIT(req); + COMMAND_REQUEST_PEER_ID::response rsp = AUTO_VAL_INIT(rsp); + if(!net_utils::invoke_remote_command2(COMMAND_REQUEST_PEER_ID::ID, req, rsp, transport)) + { + std::cout << "{" << ENDL << " \"status\": \"ERROR: " << "Failed to connect to " << command_line::get_arg(vm, arg_ip) << ":" << command_line::get_arg(vm, arg_port) << "\"" << ENDL << "}" << ENDL; + return false; + }else + { + peer_id = rsp.my_id; + } + } + + + nodetool::proof_of_trust pot = AUTO_VAL_INIT(pot); + pot.peer_id = peer_id; + pot.time = time(NULL); + crypto::public_key pubk = AUTO_VAL_INIT(pubk); + string_tools::hex_to_pod(P2P_MAINTAINERS_PUB_KEY, pubk); + crypto::hash h = tools::get_proof_of_trust_hash(pot); + crypto::generate_signature(h, pubk, prvk, pot.sign); + + if(command_line::get_arg(vm, arg_request_stat_info)) + { + uint64_t log_journal_len = 10; + if (command_line::has_arg(vm, arg_log_journal_len)) + log_journal_len = command_line::get_arg(vm, arg_log_journal_len); + + COMMAND_REQUEST_STAT_INFO::request req = AUTO_VAL_INIT(req); + req.pr.chain_len = 3; + req.pr.logs_journal_len = log_journal_len; + req.tr = pot; + if(!net_utils::invoke_remote_command2(COMMAND_REQUEST_STAT_INFO::ID, req, rs.si_rsp.v, transport)) + { + std::stringstream ss; + ss << "ERROR: " << "Failed to invoke remote command COMMAND_REQUEST_STAT_INFO to " << command_line::get_arg(vm, arg_ip) << ":" << command_line::get_arg(vm, arg_port); + rs.COMMAND_REQUEST_STAT_INFO_status = ss.str(); + }else + { + rs.si_rsp.enabled = true; + rs.COMMAND_REQUEST_STAT_INFO_status = "OK"; + } + } + + + if(command_line::get_arg(vm, arg_request_net_state)) + { + ++pot.time; + h = tools::get_proof_of_trust_hash(pot); + crypto::generate_signature(h, pubk, prvk, pot.sign); + COMMAND_REQUEST_NETWORK_STATE::request req = AUTO_VAL_INIT(req); + req.tr = pot; + if(!net_utils::invoke_remote_command2(COMMAND_REQUEST_NETWORK_STATE::ID, req, rs.ns_rsp.v, transport)) + { + std::stringstream ss; + ss << "ERROR: " << "Failed to invoke remote command COMMAND_REQUEST_NETWORK_STATE to " << command_line::get_arg(vm, arg_ip) << ":" << command_line::get_arg(vm, arg_port); + rs.COMMAND_REQUEST_NETWORK_STATE_status = ss.str(); + }else + { + rs.ns_rsp.enabled = true; + rs.COMMAND_REQUEST_NETWORK_STATE_status = "OK"; + } + } + std::cout << get_response_schema_as_json(rs); + return true; + } +//--------------------------------------------------------------------------------------------------------------- +bool get_private_key(crypto::secret_key& pk, po::variables_map& vm) +{ + if(!command_line::has_arg(vm, arg_priv_key)) + { + std::cout << "ERROR: secret key not set" << ENDL; + return false; + } + + if(!string_tools::hex_to_pod(command_line::get_arg(vm, arg_priv_key) , pk)) + { + std::cout << "ERROR: wrong secret key set" << ENDL; + return false; + } + crypto::public_key pubkey = AUTO_VAL_INIT(pubkey); + if(!crypto::secret_key_to_public_key(pk, pubkey)) + { + std::cout << "ERROR: wrong secret key set(secret_key_to_public_key failed)" << ENDL; + return false; + } + if( pubkey != tools::get_public_key_from_string(P2P_MAINTAINERS_PUB_KEY)) + { + std::cout << "ERROR: wrong secret key set(public keys not match)" << ENDL; + return false; + } + return true; +} +//--------------------------------------------------------------------------------------------------------------- +bool handle_increment_build_no(po::variables_map& vm) +{ + std::string path = command_line::get_arg(vm, arg_increment_build_no); + if (!path.size()) + { + std::cout << "no argument for increment_build_no" << ENDL; + return false; + } + std::string target_buff; + if (!file_io_utils::load_file_to_string(path, target_buff)) + { + std::cout << "noFailed to read file " << path << ENDL; + return false; + } + std::string pattern = "#define PROJECT_VERSION_BUILD_NO "; + std::string::size_type templ_offet = target_buff.find(pattern); + if (templ_offet == std::string::npos) + { + std::cout << "Filed to find pattern in " << path << ENDL; + return false; + } + + + std::string::size_type p = target_buff.find('\n', templ_offet + pattern.size()); + if (p == std::string::npos) + { + std::cout << "Filed to find pattern in " << path << ENDL; + return false; + } + //for windows-like line endings + if (target_buff[p - 1] == '\r') + --p; + + std::string build_no_str = target_buff.substr(templ_offet + pattern.size(), p - (templ_offet + pattern.size())); + build_no_str = string_tools::trim(build_no_str); + uint64_t build_num = 0; + if (!string_tools::get_xtype_from_string(build_num, build_no_str)) + { + std::cout << "Filed to find pattern in " << path << ENDL; + return false; + } + + ++build_num; + target_buff.erase(templ_offet + pattern.size(), p - (templ_offet + pattern.size())); + target_buff.insert(templ_offet + pattern.size(), std::to_string(build_num)); + + if (!file_io_utils::save_string_to_file(path, target_buff)) + { + std::cout << "Filed to save file " << path << ENDL; + return false; + } + std::cout << "SUCCESSFULLY INCREMENTED: " << build_num << ENDL; + + return true; +} +//--------------------------------------------------------------------------------------------------------------- +bool handle_update_maintainers_info(po::variables_map& vm) +{ + if(!command_line::has_arg(vm, arg_rpc_port)) + { + std::cout << "ERROR: rpc port not set" << ENDL; + return false; + } + crypto::secret_key prvk = AUTO_VAL_INIT(prvk); + if(!get_private_key(prvk, vm)) + { + std::cout << "ERROR: secret key error" << ENDL; + return false; + } + std::string path = command_line::get_arg(vm, arg_upate_maintainers_info); + + epee::net_utils::http::http_simple_client http_client; + + currency::COMMAND_RPC_SET_MAINTAINERS_INFO::request req = AUTO_VAL_INIT(req); + currency::COMMAND_RPC_SET_MAINTAINERS_INFO::response res = AUTO_VAL_INIT(res); + + maintainers_info mi = AUTO_VAL_INIT(mi); + bool r = epee::serialization::load_t_from_json_file(mi, path); + CHECK_AND_ASSERT_MES(r, false, "Failed to load maintainers_info from json file: " << path); + mi.timestamp = time(NULL); + std::cout << "timestamp: " << mi.timestamp << ENDL; + epee::serialization::store_t_to_binary(mi, req.maintainers_info_buff); + crypto::generate_signature(currency::get_blob_hash(req.maintainers_info_buff), tools::get_public_key_from_string(P2P_MAINTAINERS_PUB_KEY), prvk, req.sign); + + std::string daemon_addr = command_line::get_arg(vm, arg_ip) + ":" + std::to_string(command_line::get_arg(vm, arg_rpc_port)); + r = net_utils::invoke_http_bin_remote_command2(daemon_addr + "/set_maintainers_info.bin", req, res, http_client, command_line::get_arg(vm, arg_timeout)); + if(!r) + { + std::cout << "ERROR: failed to invoke request" << ENDL; + return false; + } + if(res.status != CORE_RPC_STATUS_OK) + { + std::cout << "ERROR: failed to update maintainers info: " << res.status << ENDL; + return false; + } + + std::cout << "OK" << ENDL; + return true; +} +//--------------------------------------------------------------------------------------------------------------- +bool generate_and_print_keys() +{ + crypto::public_key pk = AUTO_VAL_INIT(pk); + crypto::secret_key sk = AUTO_VAL_INIT(sk); + generate_keys(pk, sk); + std::cout << "PUBLIC KEY: " << epee::string_tools::pod_to_hex(pk) << ENDL + << "PRIVATE KEY: " << epee::string_tools::pod_to_hex(sk); + return true; +} + +int main(int argc, char* argv[]) +{ + + string_tools::set_module_name_and_folder(argv[0]); + log_space::get_set_log_detalisation_level(true, LOG_LEVEL_4); + + tools::signal_handler::install_fatal([](int sig_number, void* address) { + LOG_ERROR("\n\nFATAL ERROR\nsig: " << sig_number << ", address: " << address); + std::fflush(nullptr); // all open output streams are flushed + }); + + // Declare the supported options. + po::options_description desc_general("General options"); + command_line::add_arg(desc_general, command_line::arg_help); + + po::options_description desc_params("Connectivity options"); + command_line::add_arg(desc_params, arg_ip); + command_line::add_arg(desc_params, arg_port); + command_line::add_arg(desc_params, arg_rpc_port); + command_line::add_arg(desc_params, arg_timeout); + command_line::add_arg(desc_params, arg_request_stat_info); + command_line::add_arg(desc_params, arg_request_net_state); + command_line::add_arg(desc_params, arg_generate_keys); + command_line::add_arg(desc_params, arg_peer_id); + command_line::add_arg(desc_params, arg_priv_key); + command_line::add_arg(desc_params, arg_get_daemon_info); + command_line::add_arg(desc_params, arg_get_aliases); + command_line::add_arg(desc_params, arg_upate_maintainers_info); + command_line::add_arg(desc_params, arg_increment_build_no); + command_line::add_arg(desc_params, command_line::arg_version); + command_line::add_arg(desc_params, arg_generate_genesis); + command_line::add_arg(desc_params, arg_genesis_split_amount); + command_line::add_arg(desc_params, arg_get_info_flags); + command_line::add_arg(desc_params, arg_log_journal_len); + + + + po::options_description desc_all; + desc_all.add(desc_general).add(desc_params); + + po::variables_map vm; + bool r = command_line::handle_error_helper(desc_all, [&]() + { + po::store(command_line::parse_command_line(argc, argv, desc_general, true), vm); + if (command_line::get_arg(vm, command_line::arg_help)) + { + std::cout << desc_all << ENDL; + return false; + } + + po::store(command_line::parse_command_line(argc, argv, desc_params, false), vm); + po::notify(vm); + + return true; + }); + if (!r) + return 1; + + if (command_line::get_arg(vm, command_line::arg_version)) + { + std::cout << CURRENCY_NAME << " v" << PROJECT_VERSION_LONG << ENDL; + return 0; + } + if(command_line::has_arg(vm, arg_request_stat_info) || command_line::has_arg(vm, arg_request_net_state)) + { + return handle_request_stat(vm, command_line::get_arg(vm, arg_peer_id)) ? 0:1; + } + if(command_line::has_arg(vm, arg_get_daemon_info)) + { + return handle_get_daemon_info(vm) ? 0:1; + } + else if(command_line::has_arg(vm, arg_generate_keys)) + { + return generate_and_print_keys() ? 0:1; + } + else if(command_line::has_arg(vm, arg_get_aliases)) + { + return handle_get_aliases(vm) ? 0:1; + } + else if(command_line::has_arg(vm, arg_upate_maintainers_info)) + { + return handle_update_maintainers_info(vm) ? 0:1; + } + else if (command_line::has_arg(vm, arg_increment_build_no)) + { + return handle_increment_build_no(vm) ? 0 : 1; + } + else if (command_line::has_arg(vm, arg_generate_genesis)) + { + return generate_genesis(command_line::get_arg(vm, arg_generate_genesis), 10000000000000000) ? 0 : 1; + } + else + { + std::cerr << "Not enough arguments." << ENDL; + std::cerr << desc_all << ENDL; + } + + return 1; +} + diff --git a/src/crypto/chacha8.c b/src/crypto/chacha8.c new file mode 100644 index 00000000..df135af5 --- /dev/null +++ b/src/crypto/chacha8.c @@ -0,0 +1,170 @@ +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ + +#include +#include +#include + +#include "chacha8.h" +#include "common/int-util.h" +#include "warnings.h" + +/* + * The following macros are used to obtain exact-width results. + */ +#define U8V(v) ((uint8_t)(v) & UINT8_C(0xFF)) +#define U32V(v) ((uint32_t)(v) & UINT32_C(0xFFFFFFFF)) + +/* + * The following macros load words from an array of bytes with + * different types of endianness, and vice versa. + */ +#define U8TO32_LITTLE(p) SWAP32LE(((uint32_t*)(p))[0]) +#define U32TO8_LITTLE(p, v) (((uint32_t*)(p))[0] = SWAP32LE(v)) + +#define ROTATE(v,c) (rol32(v,c)) +#define XOR(v,w) ((v) ^ (w)) +#define PLUS(v,w) (U32V((v) + (w))) +#define PLUSONE(v) (PLUS((v),1)) + +#define QUARTERROUND(a,b,c,d) \ + a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ + a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); + +static const char sigma[] = "expand 32-byte k"; + +DISABLE_GCC_AND_CLANG_WARNING(strict-aliasing) + +void chacha8(const void* data, size_t length, const uint8_t* key, const uint8_t* iv, char* cipher) { + uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + char* ctarget = 0; + char tmp[64]; + int i; + + if (!length) return; + + j0 = U8TO32_LITTLE(sigma + 0); + j1 = U8TO32_LITTLE(sigma + 4); + j2 = U8TO32_LITTLE(sigma + 8); + j3 = U8TO32_LITTLE(sigma + 12); + j4 = U8TO32_LITTLE(key + 0); + j5 = U8TO32_LITTLE(key + 4); + j6 = U8TO32_LITTLE(key + 8); + j7 = U8TO32_LITTLE(key + 12); + j8 = U8TO32_LITTLE(key + 16); + j9 = U8TO32_LITTLE(key + 20); + j10 = U8TO32_LITTLE(key + 24); + j11 = U8TO32_LITTLE(key + 28); + j12 = 0; + j13 = 0; + j14 = U8TO32_LITTLE(iv + 0); + j15 = U8TO32_LITTLE(iv + 4); + + for (;;) { + if (length < 64) { + memcpy(tmp, data, length); + data = tmp; + ctarget = cipher; + cipher = tmp; + } + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + for (i = 8;i > 0;i -= 2) { + QUARTERROUND( x0, x4, x8,x12) + QUARTERROUND( x1, x5, x9,x13) + QUARTERROUND( x2, x6,x10,x14) + QUARTERROUND( x3, x7,x11,x15) + QUARTERROUND( x0, x5,x10,x15) + QUARTERROUND( x1, x6,x11,x12) + QUARTERROUND( x2, x7, x8,x13) + QUARTERROUND( x3, x4, x9,x14) + } + x0 = PLUS( x0, j0); + x1 = PLUS( x1, j1); + x2 = PLUS( x2, j2); + x3 = PLUS( x3, j3); + x4 = PLUS( x4, j4); + x5 = PLUS( x5, j5); + x6 = PLUS( x6, j6); + x7 = PLUS( x7, j7); + x8 = PLUS( x8, j8); + x9 = PLUS( x9, j9); + x10 = PLUS(x10,j10); + x11 = PLUS(x11,j11); + x12 = PLUS(x12,j12); + x13 = PLUS(x13,j13); + x14 = PLUS(x14,j14); + x15 = PLUS(x15,j15); + + x0 = XOR( x0,U8TO32_LITTLE((uint8_t*)data + 0)); + x1 = XOR( x1,U8TO32_LITTLE((uint8_t*)data + 4)); + x2 = XOR( x2,U8TO32_LITTLE((uint8_t*)data + 8)); + x3 = XOR( x3,U8TO32_LITTLE((uint8_t*)data + 12)); + x4 = XOR( x4,U8TO32_LITTLE((uint8_t*)data + 16)); + x5 = XOR( x5,U8TO32_LITTLE((uint8_t*)data + 20)); + x6 = XOR( x6,U8TO32_LITTLE((uint8_t*)data + 24)); + x7 = XOR( x7,U8TO32_LITTLE((uint8_t*)data + 28)); + x8 = XOR( x8,U8TO32_LITTLE((uint8_t*)data + 32)); + x9 = XOR( x9,U8TO32_LITTLE((uint8_t*)data + 36)); + x10 = XOR(x10,U8TO32_LITTLE((uint8_t*)data + 40)); + x11 = XOR(x11,U8TO32_LITTLE((uint8_t*)data + 44)); + x12 = XOR(x12,U8TO32_LITTLE((uint8_t*)data + 48)); + x13 = XOR(x13,U8TO32_LITTLE((uint8_t*)data + 52)); + x14 = XOR(x14,U8TO32_LITTLE((uint8_t*)data + 56)); + x15 = XOR(x15,U8TO32_LITTLE((uint8_t*)data + 60)); + + j12 = PLUSONE(j12); + if (!j12) + { + j13 = PLUSONE(j13); + /* stopping at 2^70 bytes per iv is user's responsibility */ + } + + U32TO8_LITTLE(cipher + 0,x0); + U32TO8_LITTLE(cipher + 4,x1); + U32TO8_LITTLE(cipher + 8,x2); + U32TO8_LITTLE(cipher + 12,x3); + U32TO8_LITTLE(cipher + 16,x4); + U32TO8_LITTLE(cipher + 20,x5); + U32TO8_LITTLE(cipher + 24,x6); + U32TO8_LITTLE(cipher + 28,x7); + U32TO8_LITTLE(cipher + 32,x8); + U32TO8_LITTLE(cipher + 36,x9); + U32TO8_LITTLE(cipher + 40,x10); + U32TO8_LITTLE(cipher + 44,x11); + U32TO8_LITTLE(cipher + 48,x12); + U32TO8_LITTLE(cipher + 52,x13); + U32TO8_LITTLE(cipher + 56,x14); + U32TO8_LITTLE(cipher + 60,x15); + + if (length <= 64) { + if (length < 64) { + memcpy(ctarget, cipher, length); + } + return; + } + length -= 64; + cipher += 64; + data = (uint8_t*)data + 64; + } +} diff --git a/src/crypto/chacha8.h b/src/crypto/chacha8.h new file mode 100644 index 00000000..98e14280 --- /dev/null +++ b/src/crypto/chacha8.h @@ -0,0 +1,107 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include + +#define CHACHA8_KEY_SIZE 32 +#define CHACHA8_IV_SIZE 8 + +#if defined(__cplusplus) +#include + +#include "hash.h" + +namespace crypto { + extern "C" { +#endif + void chacha8(const void* data, size_t length, const uint8_t* key, const uint8_t* iv, char* cipher); +#if defined(__cplusplus) + } + +#pragma pack(push, 1) + struct chacha8_key { + uint8_t data[CHACHA8_KEY_SIZE]; + + ~chacha8_key() + { + memset(data, 0, sizeof(data)); + } + }; + + // MS VC 2012 doesn't interpret `class chacha8_iv` as POD in spite of [9.0.10], so it is a struct + struct chacha8_iv { + uint8_t data[CHACHA8_IV_SIZE]; + }; +#pragma pack(pop) + + static_assert(sizeof(chacha8_key) == CHACHA8_KEY_SIZE && sizeof(chacha8_iv) == CHACHA8_IV_SIZE, "Invalid structure size"); + + inline void chacha8(const void* data, std::size_t length, const chacha8_key& key, const chacha8_iv& iv, char* cipher) { + chacha8(data, length, reinterpret_cast(&key), reinterpret_cast(&iv), cipher); + } + + inline void generate_chacha8_key(const void* pass, size_t sz, chacha8_key& key) { + static_assert(sizeof(chacha8_key) <= sizeof(hash), "Size of hash must be at least that of chacha8_key"); + char pwd_hash[HASH_SIZE]; + //TODO: change wallet encryption algo + crypto::cn_fast_hash(pass, sz, pwd_hash); + memcpy(&key.data, pwd_hash, sizeof(key.data)); + memset(pwd_hash, 0, sizeof(pwd_hash)); + } + + inline void generate_chacha8_key(std::string password, chacha8_key& key) + { + generate_chacha8_key(password.data(), password.size(), key); + } + + + inline bool chacha_crypt(const void* src_buff, size_t sz, void* target_buff, const void* key_buff, size_t key_buff_size) + { + crypto::chacha8_key key; + crypto::chacha8_iv iv; + memset(&iv, 0, sizeof(iv)); + crypto::generate_chacha8_key(key_buff, key_buff_size, key); + crypto::chacha8(src_buff, sz, key, iv, (char*)target_buff); + return true; + } + + inline bool chacha_crypt(std::string& buff, const std::string& pass) + { + + std::string decrypted_buff; + decrypted_buff.resize(buff.size()); + chacha_crypt(buff.data(), buff.size(), (void*)decrypted_buff.data(), pass.data(), pass.size()); + buff = decrypted_buff; + return true; + } +// inline bool chacha_decrypt(std::string& buff, const std::string& pass) +// { +// return chacha_crypt(buff, pass); +// } + template + inline bool chacha_crypt(pod_to_encrypt& crypt, const pod_pass& pass) + { + std::string buff; + buff.resize(sizeof(pod_to_encrypt)); + chacha_crypt(&crypt, sizeof(crypt), (void*)buff.data(), &pass, sizeof(pass)); + memcpy(&crypt, buff.data(), sizeof(crypt)); + return true; + } + template + inline bool chacha_crypt(std::string& buff, const pod_pass& pass) + { + std::string buff_target; + buff_target.resize(buff.size()); + chacha_crypt(buff.data(), buff.size(), (void*)buff_target.data(), &pass, sizeof(pass)); + buff = buff_target; + return true; + } + + +} + +#endif diff --git a/src/crypto/crypto-ops-data.c b/src/crypto/crypto-ops-data.c new file mode 100644 index 00000000..48bfe21a --- /dev/null +++ b/src/crypto/crypto-ops-data.c @@ -0,0 +1,846 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include "crypto-ops.h" + +/* sqrt(x) is such an integer y that 0 <= y <= p - 1, y % 2 = 0, and y^2 = x (mod p). */ +/* d = -121665 / 121666 */ +const fe fe_d = {-10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116}; /* d */ +const fe fe_sqrtm1 = {-32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482}; /* sqrt(-1) */ +const fe fe_d2 = {-21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199}; /* 2 * d */ + +/* base[i][j] = (j+1)*256^i*B */ +const ge_precomp ge_base[32][8] = { + { + {{25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605}, + {-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378}, + {-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546}}, + {{-12815894, -12976347, -21581243, 11784320, -25355658, -2750717, -11717903, -3814571, -358445, -10211303}, + {-21703237, 6903825, 27185491, 6451973, -29577724, -9554005, -15616551, 11189268, -26829678, -5319081}, + {26966642, 11152617, 32442495, 15396054, 14353839, -12752335, -3128826, -9541118, -15472047, -4166697}}, + {{15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024}, + {16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574}, + {30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357}}, + {{-17036878, 13921892, 10945806, -6033431, 27105052, -16084379, -28926210, 15006023, 3284568, -6276540}, + {23599295, -8306047, -11193664, -7687416, 13236774, 10506355, 7464579, 9656445, 13059162, 10374397}, + {7798556, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664, -3839045, -641708, -101325}}, + {{10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380}, + {4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306}, + {19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942}}, + {{-15371964, -12862754, 32573250, 4720197, -26436522, 5875511, -19188627, -15224819, -9818940, -12085777}, + {-8549212, 109983, 15149363, 2178705, 22900618, 4543417, 3044240, -15689887, 1762328, 14866737}, + {-18199695, -15951423, -10473290, 1707278, -17185920, 3916101, -28236412, 3959421, 27914454, 4383652}}, + {{5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766}, + {-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701}, + {28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300}}, + {{14499471, -2729599, -33191113, -4254652, 28494862, 14271267, 30290735, 10876454, -33154098, 2381726}, + {-7195431, -2655363, -14730155, 462251, -27724326, 3941372, -6236617, 3696005, -32300832, 15351955}, + {27431194, 8222322, 16448760, -3907995, -18707002, 11938355, -32961401, -2970515, 29551813, 10109425}} + }, { + {{-13657040, -13155431, -31283750, 11777098, 21447386, 6519384, -2378284, -1627556, 10092783, -4764171}, + {27939166, 14210322, 4677035, 16277044, -22964462, -12398139, -32508754, 12005538, -17810127, 12803510}, + {17228999, -15661624, -1233527, 300140, -1224870, -11714777, 30364213, -9038194, 18016357, 4397660}}, + {{-10958843, -7690207, 4776341, -14954238, 27850028, -15602212, -26619106, 14544525, -17477504, 982639}, + {29253598, 15796703, -2863982, -9908884, 10057023, 3163536, 7332899, -4120128, -21047696, 9934963}, + {5793303, 16271923, -24131614, -10116404, 29188560, 1206517, -14747930, 4559895, -30123922, -10897950}}, + {{-27643952, -11493006, 16282657, -11036493, 28414021, -15012264, 24191034, 4541697, -13338309, 5500568}, + {12650548, -1497113, 9052871, 11355358, -17680037, -8400164, -17430592, 12264343, 10874051, 13524335}, + {25556948, -3045990, 714651, 2510400, 23394682, -10415330, 33119038, 5080568, -22528059, 5376628}}, + {{-26088264, -4011052, -17013699, -3537628, -6726793, 1920897, -22321305, -9447443, 4535768, 1569007}, + {-2255422, 14606630, -21692440, -8039818, 28430649, 8775819, -30494562, 3044290, 31848280, 12543772}, + {-22028579, 2943893, -31857513, 6777306, 13784462, -4292203, -27377195, -2062731, 7718482, 14474653}}, + {{2385315, 2454213, -22631320, 46603, -4437935, -15680415, 656965, -7236665, 24316168, -5253567}, + {13741529, 10911568, -33233417, -8603737, -20177830, -1033297, 33040651, -13424532, -20729456, 8321686}, + {21060490, -2212744, 15712757, -4336099, 1639040, 10656336, 23845965, -11874838, -9984458, 608372}}, + {{-13672732, -15087586, -10889693, -7557059, -6036909, 11305547, 1123968, -6780577, 27229399, 23887}, + {-23244140, -294205, -11744728, 14712571, -29465699, -2029617, 12797024, -6440308, -1633405, 16678954}, + {-29500620, 4770662, -16054387, 14001338, 7830047, 9564805, -1508144, -4795045, -17169265, 4904953}}, + {{24059557, 14617003, 19037157, -15039908, 19766093, -14906429, 5169211, 16191880, 2128236, -4326833}, + {-16981152, 4124966, -8540610, -10653797, 30336522, -14105247, -29806336, 916033, -6882542, -2986532}, + {-22630907, 12419372, -7134229, -7473371, -16478904, 16739175, 285431, 2763829, 15736322, 4143876}}, + {{2379352, 11839345, -4110402, -5988665, 11274298, 794957, 212801, -14594663, 23527084, -16458268}, + {33431127, -11130478, -17838966, -15626900, 8909499, 8376530, -32625340, 4087881, -15188911, -14416214}, + {1767683, 7197987, -13205226, -2022635, -13091350, 448826, 5799055, 4357868, -4774191, -16323038}} + }, { + {{6721966, 13833823, -23523388, -1551314, 26354293, -11863321, 23365147, -3949732, 7390890, 2759800}, + {4409041, 2052381, 23373853, 10530217, 7676779, -12885954, 21302353, -4264057, 1244380, -12919645}, + {-4421239, 7169619, 4982368, -2957590, 30256825, -2777540, 14086413, 9208236, 15886429, 16489664}}, + {{1996075, 10375649, 14346367, 13311202, -6874135, -16438411, -13693198, 398369, -30606455, -712933}, + {-25307465, 9795880, -2777414, 14878809, -33531835, 14780363, 13348553, 12076947, -30836462, 5113182}, + {-17770784, 11797796, 31950843, 13929123, -25888302, 12288344, -30341101, -7336386, 13847711, 5387222}}, + {{-18582163, -3416217, 17824843, -2340966, 22744343, -10442611, 8763061, 3617786, -19600662, 10370991}, + {20246567, -14369378, 22358229, -543712, 18507283, -10413996, 14554437, -8746092, 32232924, 16763880}, + {9648505, 10094563, 26416693, 14745928, -30374318, -6472621, 11094161, 15689506, 3140038, -16510092}}, + {{-16160072, 5472695, 31895588, 4744994, 8823515, 10365685, -27224800, 9448613, -28774454, 366295}, + {19153450, 11523972, -11096490, -6503142, -24647631, 5420647, 28344573, 8041113, 719605, 11671788}, + {8678025, 2694440, -6808014, 2517372, 4964326, 11152271, -15432916, -15266516, 27000813, -10195553}}, + {{-15157904, 7134312, 8639287, -2814877, -7235688, 10421742, 564065, 5336097, 6750977, -14521026}, + {11836410, -3979488, 26297894, 16080799, 23455045, 15735944, 1695823, -8819122, 8169720, 16220347}, + {-18115838, 8653647, 17578566, -6092619, -8025777, -16012763, -11144307, -2627664, -5990708, -14166033}}, + {{-23308498, -10968312, 15213228, -10081214, -30853605, -11050004, 27884329, 2847284, 2655861, 1738395}, + {-27537433, -14253021, -25336301, -8002780, -9370762, 8129821, 21651608, -3239336, -19087449, -11005278}, + {1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, 10478196, 8544890}}, + {{32173121, -16129311, 24896207, 3921497, 22579056, -3410854, 19270449, 12217473, 17789017, -3395995}, + {-30552961, -2228401, -15578829, -10147201, 13243889, 517024, 15479401, -3853233, 30460520, 1052596}, + {-11614875, 13323618, 32618793, 8175907, -15230173, 12596687, 27491595, -4612359, 3179268, -9478891}}, + {{31947069, -14366651, -4640583, -15339921, -15125977, -6039709, -14756777, -16411740, 19072640, -9511060}, + {11685058, 11822410, 3158003, -13952594, 33402194, -4165066, 5977896, -5215017, 473099, 5040608}, + {-20290863, 8198642, -27410132, 11602123, 1290375, -2799760, 28326862, 1721092, -19558642, -3131606}} + }, { + {{7881532, 10687937, 7578723, 7738378, -18951012, -2553952, 21820786, 8076149, -27868496, 11538389}, + {-19935666, 3899861, 18283497, -6801568, -15728660, -11249211, 8754525, 7446702, -5676054, 5797016}, + {-11295600, -3793569, -15782110, -7964573, 12708869, -8456199, 2014099, -9050574, -2369172, -5877341}}, + {{-22472376, -11568741, -27682020, 1146375, 18956691, 16640559, 1192730, -3714199, 15123619, 10811505}, + {14352098, -3419715, -18942044, 10822655, 32750596, 4699007, -70363, 15776356, -28886779, -11974553}, + {-28241164, -8072475, -4978962, -5315317, 29416931, 1847569, -20654173, -16484855, 4714547, -9600655}}, + {{15200332, 8368572, 19679101, 15970074, -31872674, 1959451, 24611599, -4543832, -11745876, 12340220}, + {12876937, -10480056, 33134381, 6590940, -6307776, 14872440, 9613953, 8241152, 15370987, 9608631}, + {-4143277, -12014408, 8446281, -391603, 4407738, 13629032, -7724868, 15866074, -28210621, -8814099}}, + {{26660628, -15677655, 8393734, 358047, -7401291, 992988, -23904233, 858697, 20571223, 8420556}, + {14620715, 13067227, -15447274, 8264467, 14106269, 15080814, 33531827, 12516406, -21574435, -12476749}, + {236881, 10476226, 57258, -14677024, 6472998, 2466984, 17258519, 7256740, 8791136, 15069930}}, + {{1276410, -9371918, 22949635, -16322807, -23493039, -5702186, 14711875, 4874229, -30663140, -2331391}, + {5855666, 4990204, -13711848, 7294284, -7804282, 1924647, -1423175, -7912378, -33069337, 9234253}, + {20590503, -9018988, 31529744, -7352666, -2706834, 10650548, 31559055, -11609587, 18979186, 13396066}}, + {{24474287, 4968103, 22267082, 4407354, 24063882, -8325180, -18816887, 13594782, 33514650, 7021958}, + {-11566906, -6565505, -21365085, 15928892, -26158305, 4315421, -25948728, -3916677, -21480480, 12868082}, + {-28635013, 13504661, 19988037, -2132761, 21078225, 6443208, -21446107, 2244500, -12455797, -8089383}}, + {{-30595528, 13793479, -5852820, 319136, -25723172, -6263899, 33086546, 8957937, -15233648, 5540521}, + {-11630176, -11503902, -8119500, -7643073, 2620056, 1022908, -23710744, -1568984, -16128528, -14962807}, + {23152971, 775386, 27395463, 14006635, -9701118, 4649512, 1689819, 892185, -11513277, -15205948}}, + {{9770129, 9586738, 26496094, 4324120, 1556511, -3550024, 27453819, 4763127, -19179614, 5867134}, + {-32765025, 1927590, 31726409, -4753295, 23962434, -16019500, 27846559, 5931263, -29749703, -16108455}, + {27461885, -2977536, 22380810, 1815854, -23033753, -3031938, 7283490, -15148073, -19526700, 7734629}} + }, { + {{-8010264, -9590817, -11120403, 6196038, 29344158, -13430885, 7585295, -3176626, 18549497, 15302069}, + {-32658337, -6171222, -7672793, -11051681, 6258878, 13504381, 10458790, -6418461, -8872242, 8424746}, + {24687205, 8613276, -30667046, -3233545, 1863892, -1830544, 19206234, 7134917, -11284482, -828919}}, + {{11334899, -9218022, 8025293, 12707519, 17523892, -10476071, 10243738, -14685461, -5066034, 16498837}, + {8911542, 6887158, -9584260, -6958590, 11145641, -9543680, 17303925, -14124238, 6536641, 10543906}, + {-28946384, 15479763, -17466835, 568876, -1497683, 11223454, -2669190, -16625574, -27235709, 8876771}}, + {{-25742899, -12566864, -15649966, -846607, -33026686, -796288, -33481822, 15824474, -604426, -9039817}, + {10330056, 70051, 7957388, -9002667, 9764902, 15609756, 27698697, -4890037, 1657394, 3084098}, + {10477963, -7470260, 12119566, -13250805, 29016247, -5365589, 31280319, 14396151, -30233575, 15272409}}, + {{-12288309, 3169463, 28813183, 16658753, 25116432, -5630466, -25173957, -12636138, -25014757, 1950504}, + {-26180358, 9489187, 11053416, -14746161, -31053720, 5825630, -8384306, -8767532, 15341279, 8373727}, + {28685821, 7759505, -14378516, -12002860, -31971820, 4079242, 298136, -10232602, -2878207, 15190420}}, + {{-32932876, 13806336, -14337485, -15794431, -24004620, 10940928, 8669718, 2742393, -26033313, -6875003}, + {-1580388, -11729417, -25979658, -11445023, -17411874, -10912854, 9291594, -16247779, -12154742, 6048605}, + {-30305315, 14843444, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, 11213262, 9168384}}, + {{-26280513, 11007847, 19408960, -940758, -18592965, -4328580, -5088060, -11105150, 20470157, -16398701}, + {-23136053, 9282192, 14855179, -15390078, -7362815, -14408560, -22783952, 14461608, 14042978, 5230683}, + {29969567, -2741594, -16711867, -8552442, 9175486, -2468974, 21556951, 3506042, -5933891, -12449708}}, + {{-3144746, 8744661, 19704003, 4581278, -20430686, 6830683, -21284170, 8971513, -28539189, 15326563}, + {-19464629, 10110288, -17262528, -3503892, -23500387, 1355669, -15523050, 15300988, -20514118, 9168260}, + {-5353335, 4488613, -23803248, 16314347, 7780487, -15638939, -28948358, 9601605, 33087103, -9011387}}, + {{-19443170, -15512900, -20797467, -12445323, -29824447, 10229461, -27444329, -15000531, -5996870, 15664672}, + {23294591, -16632613, -22650781, -8470978, 27844204, 11461195, 13099750, -2460356, 18151676, 13417686}, + {-24722913, -4176517, -31150679, 5988919, -26858785, 6685065, 1661597, -12551441, 15271676, -15452665}} + }, { + {{11433042, -13228665, 8239631, -5279517, -1985436, -725718, -18698764, 2167544, -6921301, -13440182}, + {-31436171, 15575146, 30436815, 12192228, -22463353, 9395379, -9917708, -8638997, 12215110, 12028277}, + {14098400, 6555944, 23007258, 5757252, -15427832, -12950502, 30123440, 4617780, -16900089, -655628}}, + {{-4026201, -15240835, 11893168, 13718664, -14809462, 1847385, -15819999, 10154009, 23973261, -12684474}, + {-26531820, -3695990, -1908898, 2534301, -31870557, -16550355, 18341390, -11419951, 32013174, -10103539}, + {-25479301, 10876443, -11771086, -14625140, -12369567, 1838104, 21911214, 6354752, 4425632, -837822}}, + {{-10433389, -14612966, 22229858, -3091047, -13191166, 776729, -17415375, -12020462, 4725005, 14044970}, + {19268650, -7304421, 1555349, 8692754, -21474059, -9910664, 6347390, -1411784, -19522291, -16109756}, + {-24864089, 12986008, -10898878, -5558584, -11312371, -148526, 19541418, 8180106, 9282262, 10282508}}, + {{-26205082, 4428547, -8661196, -13194263, 4098402, -14165257, 15522535, 8372215, 5542595, -10702683}, + {-10562541, 14895633, 26814552, -16673850, -17480754, -2489360, -2781891, 6993761, -18093885, 10114655}, + {-20107055, -929418, 31422704, 10427861, -7110749, 6150669, -29091755, -11529146, 25953725, -106158}}, + {{-4234397, -8039292, -9119125, 3046000, 2101609, -12607294, 19390020, 6094296, -3315279, 12831125}, + {-15998678, 7578152, 5310217, 14408357, -33548620, -224739, 31575954, 6326196, 7381791, -2421839}, + {-20902779, 3296811, 24736065, -16328389, 18374254, 7318640, 6295303, 8082724, -15362489, 12339664}}, + {{27724736, 2291157, 6088201, -14184798, 1792727, 5857634, 13848414, 15768922, 25091167, 14856294}, + {-18866652, 8331043, 24373479, 8541013, -701998, -9269457, 12927300, -12695493, -22182473, -9012899}, + {-11423429, -5421590, 11632845, 3405020, 30536730, -11674039, -27260765, 13866390, 30146206, 9142070}}, + {{3924129, -15307516, -13817122, -10054960, 12291820, -668366, -27702774, 9326384, -8237858, 4171294}, + {-15921940, 16037937, 6713787, 16606682, -21612135, 2790944, 26396185, 3731949, 345228, -5462949}, + {-21327538, 13448259, 25284571, 1143661, 20614966, -8849387, 2031539, -12391231, -16253183, -13582083}}, + {{31016211, -16722429, 26371392, -14451233, -5027349, 14854137, 17477601, 3842657, 28012650, -16405420}, + {-5075835, 9368966, -8562079, -4600902, -15249953, 6970560, -9189873, 16292057, -8867157, 3507940}, + {29439664, 3537914, 23333589, 6997794, -17555561, -11018068, -15209202, -15051267, -9164929, 6580396}} + }, { + {{-12185861, -7679788, 16438269, 10826160, -8696817, -6235611, 17860444, -9273846, -2095802, 9304567}, + {20714564, -4336911, 29088195, 7406487, 11426967, -5095705, 14792667, -14608617, 5289421, -477127}, + {-16665533, -10650790, -6160345, -13305760, 9192020, -1802462, 17271490, 12349094, 26939669, -3752294}}, + {{-12889898, 9373458, 31595848, 16374215, 21471720, 13221525, -27283495, -12348559, -3698806, 117887}, + {22263325, -6560050, 3984570, -11174646, -15114008, -566785, 28311253, 5358056, -23319780, 541964}, + {16259219, 3261970, 2309254, -15534474, -16885711, -4581916, 24134070, -16705829, -13337066, -13552195}}, + {{9378160, -13140186, -22845982, -12745264, 28198281, -7244098, -2399684, -717351, 690426, 14876244}, + {24977353, -314384, -8223969, -13465086, 28432343, -1176353, -13068804, -12297348, -22380984, 6618999}, + {-1538174, 11685646, 12944378, 13682314, -24389511, -14413193, 8044829, -13817328, 32239829, -5652762}}, + {{-18603066, 4762990, -926250, 8885304, -28412480, -3187315, 9781647, -10350059, 32779359, 5095274}, + {-33008130, -5214506, -32264887, -3685216, 9460461, -9327423, -24601656, 14506724, 21639561, -2630236}, + {-16400943, -13112215, 25239338, 15531969, 3987758, -4499318, -1289502, -6863535, 17874574, 558605}}, + {{-13600129, 10240081, 9171883, 16131053, -20869254, 9599700, 33499487, 5080151, 2085892, 5119761}, + {-22205145, -2519528, -16381601, 414691, -25019550, 2170430, 30634760, -8363614, -31999993, -5759884}, + {-6845704, 15791202, 8550074, -1312654, 29928809, -12092256, 27534430, -7192145, -22351378, 12961482}}, + {{-24492060, -9570771, 10368194, 11582341, -23397293, -2245287, 16533930, 8206996, -30194652, -5159638}, + {-11121496, -3382234, 2307366, 6362031, -135455, 8868177, -16835630, 7031275, 7589640, 8945490}, + {-32152748, 8917967, 6661220, -11677616, -1192060, -15793393, 7251489, -11182180, 24099109, -14456170}}, + {{5019558, -7907470, 4244127, -14714356, -26933272, 6453165, -19118182, -13289025, -6231896, -10280736}, + {10853594, 10721687, 26480089, 5861829, -22995819, 1972175, -1866647, -10557898, -3363451, -6441124}, + {-17002408, 5906790, 221599, -6563147, 7828208, -13248918, 24362661, -2008168, -13866408, 7421392}}, + {{8139927, -6546497, 32257646, -5890546, 30375719, 1886181, -21175108, 15441252, 28826358, -4123029}, + {6267086, 9695052, 7709135, -16603597, -32869068, -1886135, 14795160, -7840124, 13746021, -1742048}, + {28584902, 7787108, -6732942, -15050729, 22846041, -7571236, -3181936, -363524, 4771362, -8419958}} + }, { + {{24949256, 6376279, -27466481, -8174608, -18646154, -9930606, 33543569, -12141695, 3569627, 11342593}, + {26514989, 4740088, 27912651, 3697550, 19331575, -11472339, 6809886, 4608608, 7325975, -14801071}, + {-11618399, -14554430, -24321212, 7655128, -1369274, 5214312, -27400540, 10258390, -17646694, -8186692}}, + {{11431204, 15823007, 26570245, 14329124, 18029990, 4796082, -31446179, 15580664, 9280358, -3973687}, + {-160783, -10326257, -22855316, -4304997, -20861367, -13621002, -32810901, -11181622, -15545091, 4387441}, + {-20799378, 12194512, 3937617, -5805892, -27154820, 9340370, -24513992, 8548137, 20617071, -7482001}}, + {{-938825, -3930586, -8714311, 16124718, 24603125, -6225393, -13775352, -11875822, 24345683, 10325460}, + {-19855277, -1568885, -22202708, 8714034, 14007766, 6928528, 16318175, -1010689, 4766743, 3552007}, + {-21751364, -16730916, 1351763, -803421, -4009670, 3950935, 3217514, 14481909, 10988822, -3994762}}, + {{15564307, -14311570, 3101243, 5684148, 30446780, -8051356, 12677127, -6505343, -8295852, 13296005}, + {-9442290, 6624296, -30298964, -11913677, -4670981, -2057379, 31521204, 9614054, -30000824, 12074674}, + {4771191, -135239, 14290749, -13089852, 27992298, 14998318, -1413936, -1556716, 29832613, -16391035}}, + {{7064884, -7541174, -19161962, -5067537, -18891269, -2912736, 25825242, 5293297, -27122660, 13101590}, + {-2298563, 2439670, -7466610, 1719965, -27267541, -16328445, 32512469, -5317593, -30356070, -4190957}, + {-30006540, 10162316, -33180176, 3981723, -16482138, -13070044, 14413974, 9515896, 19568978, 9628812}}, + {{33053803, 199357, 15894591, 1583059, 27380243, -4580435, -17838894, -6106839, -6291786, 3437740}, + {-18978877, 3884493, 19469877, 12726490, 15913552, 13614290, -22961733, 70104, 7463304, 4176122}, + {-27124001, 10659917, 11482427, -16070381, 12771467, -6635117, -32719404, -5322751, 24216882, 5944158}}, + {{8894125, 7450974, -2664149, -9765752, -28080517, -12389115, 19345746, 14680796, 11632993, 5847885}, + {26942781, -2315317, 9129564, -4906607, 26024105, 11769399, -11518837, 6367194, -9727230, 4782140}, + {19916461, -4828410, -22910704, -11414391, 25606324, -5972441, 33253853, 8220911, 6358847, -1873857}}, + {{801428, -2081702, 16569428, 11065167, 29875704, 96627, 7908388, -4480480, -13538503, 1387155}, + {19646058, 5720633, -11416706, 12814209, 11607948, 12749789, 14147075, 15156355, -21866831, 11835260}, + {19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, -26560550, 5052483}} + }, { + {{-3017432, 10058206, 1980837, 3964243, 22160966, 12322533, -6431123, -12618185, 12228557, -7003677}, + {32944382, 14922211, -22844894, 5188528, 21913450, -8719943, 4001465, 13238564, -6114803, 8653815}, + {22865569, -4652735, 27603668, -12545395, 14348958, 8234005, 24808405, 5719875, 28483275, 2841751}}, + {{-16420968, -1113305, -327719, -12107856, 21886282, -15552774, -1887966, -315658, 19932058, -12739203}, + {-11656086, 10087521, -8864888, -5536143, -19278573, -3055912, 3999228, 13239134, -4777469, -13910208}, + {1382174, -11694719, 17266790, 9194690, -13324356, 9720081, 20403944, 11284705, -14013818, 3093230}}, + {{16650921, -11037932, -1064178, 1570629, -8329746, 7352753, -302424, 16271225, -24049421, -6691850}, + {-21911077, -5927941, -4611316, -5560156, -31744103, -10785293, 24123614, 15193618, -21652117, -16739389}, + {-9935934, -4289447, -25279823, 4372842, 2087473, 10399484, 31870908, 14690798, 17361620, 11864968}}, + {{-11307610, 6210372, 13206574, 5806320, -29017692, -13967200, -12331205, -7486601, -25578460, -16240689}, + {14668462, -12270235, 26039039, 15305210, 25515617, 4542480, 10453892, 6577524, 9145645, -6443880}, + {5974874, 3053895, -9433049, -10385191, -31865124, 3225009, -7972642, 3936128, -5652273, -3050304}}, + {{30625386, -4729400, -25555961, -12792866, -20484575, 7695099, 17097188, -16303496, -27999779, 1803632}, + {-3553091, 9865099, -5228566, 4272701, -5673832, -16689700, 14911344, 12196514, -21405489, 7047412}, + {20093277, 9920966, -11138194, -5343857, 13161587, 12044805, -32856851, 4124601, -32343828, -10257566}}, + {{-20788824, 14084654, -13531713, 7842147, 19119038, -13822605, 4752377, -8714640, -21679658, 2288038}, + {-26819236, -3283715, 29965059, 3039786, -14473765, 2540457, 29457502, 14625692, -24819617, 12570232}, + {-1063558, -11551823, 16920318, 12494842, 1278292, -5869109, -21159943, -3498680, -11974704, 4724943}}, + {{17960970, -11775534, -4140968, -9702530, -8876562, -1410617, -12907383, -8659932, -29576300, 1903856}, + {23134274, -14279132, -10681997, -1611936, 20684485, 15770816, -12989750, 3190296, 26955097, 14109738}, + {15308788, 5320727, -30113809, -14318877, 22902008, 7767164, 29425325, -11277562, 31960942, 11934971}}, + {{-27395711, 8435796, 4109644, 12222639, -24627868, 14818669, 20638173, 4875028, 10491392, 1379718}, + {-13159415, 9197841, 3875503, -8936108, -1383712, -5879801, 33518459, 16176658, 21432314, 12180697}, + {-11787308, 11500838, 13787581, -13832590, -22430679, 10140205, 1465425, 12689540, -10301319, -13872883}} + }, { + {{5414091, -15386041, -21007664, 9643570, 12834970, 1186149, -2622916, -1342231, 26128231, 6032912}, + {-26337395, -13766162, 32496025, -13653919, 17847801, -12669156, 3604025, 8316894, -25875034, -10437358}, + {3296484, 6223048, 24680646, -12246460, -23052020, 5903205, -8862297, -4639164, 12376617, 3188849}}, + {{29190488, -14659046, 27549113, -1183516, 3520066, -10697301, 32049515, -7309113, -16109234, -9852307}, + {-14744486, -9309156, 735818, -598978, -20407687, -5057904, 25246078, -15795669, 18640741, -960977}, + {-6928835, -16430795, 10361374, 5642961, 4910474, 12345252, -31638386, -494430, 10530747, 1053335}}, + {{-29265967, -14186805, -13538216, -12117373, -19457059, -10655384, -31462369, -2948985, 24018831, 15026644}, + {-22592535, -3145277, -2289276, 5953843, -13440189, 9425631, 25310643, 13003497, -2314791, -15145616}, + {-27419985, -603321, -8043984, -1669117, -26092265, 13987819, -27297622, 187899, -23166419, -2531735}}, + {{-21744398, -13810475, 1844840, 5021428, -10434399, -15911473, 9716667, 16266922, -5070217, 726099}, + {29370922, -6053998, 7334071, -15342259, 9385287, 2247707, -13661962, -4839461, 30007388, -15823341}, + {-936379, 16086691, 23751945, -543318, -1167538, -5189036, 9137109, 730663, 9835848, 4555336}}, + {{-23376435, 1410446, -22253753, -12899614, 30867635, 15826977, 17693930, 544696, -11985298, 12422646}, + {31117226, -12215734, -13502838, 6561947, -9876867, -12757670, -5118685, -4096706, 29120153, 13924425}, + {-17400879, -14233209, 19675799, -2734756, -11006962, -5858820, -9383939, -11317700, 7240931, -237388}}, + {{-31361739, -11346780, -15007447, -5856218, -22453340, -12152771, 1222336, 4389483, 3293637, -15551743}, + {-16684801, -14444245, 11038544, 11054958, -13801175, -3338533, -24319580, 7733547, 12796905, -6335822}, + {-8759414, -10817836, -25418864, 10783769, -30615557, -9746811, -28253339, 3647836, 3222231, -11160462}}, + {{18606113, 1693100, -25448386, -15170272, 4112353, 10045021, 23603893, -2048234, -7550776, 2484985}, + {9255317, -3131197, -12156162, -1004256, 13098013, -9214866, 16377220, -2102812, -19802075, -3034702}, + {-22729289, 7496160, -5742199, 11329249, 19991973, -3347502, -31718148, 9936966, -30097688, -10618797}}, + {{21878590, -5001297, 4338336, 13643897, -3036865, 13160960, 19708896, 5415497, -7360503, -4109293}, + {27736861, 10103576, 12500508, 8502413, -3413016, -9633558, 10436918, -1550276, -23659143, -8132100}, + {19492550, -12104365, -29681976, -852630, -3208171, 12403437, 30066266, 8367329, 13243957, 8709688}} + }, { + {{12015105, 2801261, 28198131, 10151021, 24818120, -4743133, -11194191, -5645734, 5150968, 7274186}, + {2831366, -12492146, 1478975, 6122054, 23825128, -12733586, 31097299, 6083058, 31021603, -9793610}, + {-2529932, -2229646, 445613, 10720828, -13849527, -11505937, -23507731, 16354465, 15067285, -14147707}}, + {{7840942, 14037873, -33364863, 15934016, -728213, -3642706, 21403988, 1057586, -19379462, -12403220}, + {915865, -16469274, 15608285, -8789130, -24357026, 6060030, -17371319, 8410997, -7220461, 16527025}, + {32922597, -556987, 20336074, -16184568, 10903705, -5384487, 16957574, 52992, 23834301, 6588044}}, + {{32752030, 11232950, 3381995, -8714866, 22652988, -10744103, 17159699, 16689107, -20314580, -1305992}, + {-4689649, 9166776, -25710296, -10847306, 11576752, 12733943, 7924251, -2752281, 1976123, -7249027}, + {21251222, 16309901, -2983015, -6783122, 30810597, 12967303, 156041, -3371252, 12331345, -8237197}}, + {{8651614, -4477032, -16085636, -4996994, 13002507, 2950805, 29054427, -5106970, 10008136, -4667901}, + {31486080, 15114593, -14261250, 12951354, 14369431, -7387845, 16347321, -13662089, 8684155, -10532952}, + {19443825, 11385320, 24468943, -9659068, -23919258, 2187569, -26263207, -6086921, 31316348, 14219878}}, + {{-28594490, 1193785, 32245219, 11392485, 31092169, 15722801, 27146014, 6992409, 29126555, 9207390}, + {32382935, 1110093, 18477781, 11028262, -27411763, -7548111, -4980517, 10843782, -7957600, -14435730}, + {2814918, 7836403, 27519878, -7868156, -20894015, -11553689, -21494559, 8550130, 28346258, 1994730}}, + {{-19578299, 8085545, -14000519, -3948622, 2785838, -16231307, -19516951, 7174894, 22628102, 8115180}, + {-30405132, 955511, -11133838, -15078069, -32447087, -13278079, -25651578, 3317160, -9943017, 930272}, + {-15303681, -6833769, 28856490, 1357446, 23421993, 1057177, 24091212, -1388970, -22765376, -10650715}}, + {{-22751231, -5303997, -12907607, -12768866, -15811511, -7797053, -14839018, -16554220, -1867018, 8398970}, + {-31969310, 2106403, -4736360, 1362501, 12813763, 16200670, 22981545, -6291273, 18009408, -15772772}, + {-17220923, -9545221, -27784654, 14166835, 29815394, 7444469, 29551787, -3727419, 19288549, 1325865}}, + {{15100157, -15835752, -23923978, -1005098, -26450192, 15509408, 12376730, -3479146, 33166107, -8042750}, + {20909231, 13023121, -9209752, 16251778, -5778415, -8094914, 12412151, 10018715, 2213263, -13878373}, + {32529814, -11074689, 30361439, -16689753, -9135940, 1513226, 22922121, 6382134, -5766928, 8371348}} + }, { + {{9923462, 11271500, 12616794, 3544722, -29998368, -1721626, 12891687, -8193132, -26442943, 10486144}, + {-22597207, -7012665, 8587003, -8257861, 4084309, -12970062, 361726, 2610596, -23921530, -11455195}, + {5408411, -1136691, -4969122, 10561668, 24145918, 14240566, 31319731, -4235541, 19985175, -3436086}}, + {{-13994457, 16616821, 14549246, 3341099, 32155958, 13648976, -17577068, 8849297, 65030, 8370684}, + {-8320926, -12049626, 31204563, 5839400, -20627288, -1057277, -19442942, 6922164, 12743482, -9800518}, + {-2361371, 12678785, 28815050, 4759974, -23893047, 4884717, 23783145, 11038569, 18800704, 255233}}, + {{-5269658, -1773886, 13957886, 7990715, 23132995, 728773, 13393847, 9066957, 19258688, -14753793}, + {-2936654, -10827535, -10432089, 14516793, -3640786, 4372541, -31934921, 2209390, -1524053, 2055794}, + {580882, 16705327, 5468415, -2683018, -30926419, -14696000, -7203346, -8994389, -30021019, 7394435}}, + {{23838809, 1822728, -15738443, 15242727, 8318092, -3733104, -21672180, -3492205, -4821741, 14799921}, + {13345610, 9759151, 3371034, -16137791, 16353039, 8577942, 31129804, 13496856, -9056018, 7402518}, + {2286874, -4435931, -20042458, -2008336, -13696227, 5038122, 11006906, -15760352, 8205061, 1607563}}, + {{14414086, -8002132, 3331830, -3208217, 22249151, -5594188, 18364661, -2906958, 30019587, -9029278}, + {-27688051, 1585953, -10775053, 931069, -29120221, -11002319, -14410829, 12029093, 9944378, 8024}, + {4368715, -3709630, 29874200, -15022983, -20230386, -11410704, -16114594, -999085, -8142388, 5640030}}, + {{10299610, 13746483, 11661824, 16234854, 7630238, 5998374, 9809887, -16694564, 15219798, -14327783}, + {27425505, -5719081, 3055006, 10660664, 23458024, 595578, -15398605, -1173195, -18342183, 9742717}, + {6744077, 2427284, 26042789, 2720740, -847906, 1118974, 32324614, 7406442, 12420155, 1994844}}, + {{14012521, -5024720, -18384453, -9578469, -26485342, -3936439, -13033478, -10909803, 24319929, -6446333}, + {16412690, -4507367, 10772641, 15929391, -17068788, -4658621, 10555945, -10484049, -30102368, -4739048}, + {22397382, -7767684, -9293161, -12792868, 17166287, -9755136, -27333065, 6199366, 21880021, -12250760}}, + {{-4283307, 5368523, -31117018, 8163389, -30323063, 3209128, 16557151, 8890729, 8840445, 4957760}, + {-15447727, 709327, -6919446, -10870178, -29777922, 6522332, -21720181, 12130072, -14796503, 5005757}, + {-2114751, -14308128, 23019042, 15765735, -25269683, 6002752, 10183197, -13239326, -16395286, -2176112}} + }, { + {{-19025756, 1632005, 13466291, -7995100, -23640451, 16573537, -32013908, -3057104, 22208662, 2000468}, + {3065073, -1412761, -25598674, -361432, -17683065, -5703415, -8164212, 11248527, -3691214, -7414184}, + {10379208, -6045554, 8877319, 1473647, -29291284, -12507580, 16690915, 2553332, -3132688, 16400289}}, + {{15716668, 1254266, -18472690, 7446274, -8448918, 6344164, -22097271, -7285580, 26894937, 9132066}, + {24158887, 12938817, 11085297, -8177598, -28063478, -4457083, -30576463, 64452, -6817084, -2692882}, + {13488534, 7794716, 22236231, 5989356, 25426474, -12578208, 2350710, -3418511, -4688006, 2364226}}, + {{16335052, 9132434, 25640582, 6678888, 1725628, 8517937, -11807024, -11697457, 15445875, -7798101}, + {29004207, -7867081, 28661402, -640412, -12794003, -7943086, 31863255, -4135540, -278050, -15759279}, + {-6122061, -14866665, -28614905, 14569919, -10857999, -3591829, 10343412, -6976290, -29828287, -10815811}}, + {{27081650, 3463984, 14099042, -4517604, 1616303, -6205604, 29542636, 15372179, 17293797, 960709}, + {20263915, 11434237, -5765435, 11236810, 13505955, -10857102, -16111345, 6493122, -19384511, 7639714}, + {-2830798, -14839232, 25403038, -8215196, -8317012, -16173699, 18006287, -16043750, 29994677, -15808121}}, + {{9769828, 5202651, -24157398, -13631392, -28051003, -11561624, -24613141, -13860782, -31184575, 709464}, + {12286395, 13076066, -21775189, -1176622, -25003198, 4057652, -32018128, -8890874, 16102007, 13205847}, + {13733362, 5599946, 10557076, 3195751, -5557991, 8536970, -25540170, 8525972, 10151379, 10394400}}, + {{4024660, -16137551, 22436262, 12276534, -9099015, -2686099, 19698229, 11743039, -33302334, 8934414}, + {-15879800, -4525240, -8580747, -2934061, 14634845, -698278, -9449077, 3137094, -11536886, 11721158}, + {17555939, -5013938, 8268606, 2331751, -22738815, 9761013, 9319229, 8835153, -9205489, -1280045}}, + {{-461409, -7830014, 20614118, 16688288, -7514766, -4807119, 22300304, 505429, 6108462, -6183415}, + {-5070281, 12367917, -30663534, 3234473, 32617080, -8422642, 29880583, -13483331, -26898490, -7867459}, + {-31975283, 5726539, 26934134, 10237677, -3173717, -605053, 24199304, 3795095, 7592688, -14992079}}, + {{21594432, -14964228, 17466408, -4077222, 32537084, 2739898, 6407723, 12018833, -28256052, 4298412}, + {-20650503, -11961496, -27236275, 570498, 3767144, -1717540, 13891942, -1569194, 13717174, 10805743}, + {-14676630, -15644296, 15287174, 11927123, 24177847, -8175568, -796431, 14860609, -26938930, -5863836}} + }, { + {{12962541, 5311799, -10060768, 11658280, 18855286, -7954201, 13286263, -12808704, -4381056, 9882022}, + {18512079, 11319350, -20123124, 15090309, 18818594, 5271736, -22727904, 3666879, -23967430, -3299429}, + {-6789020, -3146043, 16192429, 13241070, 15898607, -14206114, -10084880, -6661110, -2403099, 5276065}}, + {{30169808, -5317648, 26306206, -11750859, 27814964, 7069267, 7152851, 3684982, 1449224, 13082861}, + {10342826, 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, -21016438, -8202000}, + {-33150110, 3261608, 22745853, 7948688, 19370557, -15177665, -26171976, 6482814, -10300080, -11060101}}, + {{32869458, -5408545, 25609743, 15678670, -10687769, -15471071, 26112421, 2521008, -22664288, 6904815}, + {29506923, 4457497, 3377935, -9796444, -30510046, 12935080, 1561737, 3841096, -29003639, -6657642}, + {10340844, -6630377, -18656632, -2278430, 12621151, -13339055, 30878497, -11824370, -25584551, 5181966}}, + {{25940115, -12658025, 17324188, -10307374, -8671468, 15029094, 24396252, -16450922, -2322852, -12388574}, + {-21765684, 9916823, -1300409, 4079498, -1028346, 11909559, 1782390, 12641087, 20603771, -6561742}, + {-18882287, -11673380, 24849422, 11501709, 13161720, -4768874, 1925523, 11914390, 4662781, 7820689}}, + {{12241050, -425982, 8132691, 9393934, 32846760, -1599620, 29749456, 12172924, 16136752, 15264020}, + {-10349955, -14680563, -8211979, 2330220, -17662549, -14545780, 10658213, 6671822, 19012087, 3772772}, + {3753511, -3421066, 10617074, 2028709, 14841030, -6721664, 28718732, -15762884, 20527771, 12988982}}, + {{-14822485, -5797269, -3707987, 12689773, -898983, -10914866, -24183046, -10564943, 3299665, -12424953}, + {-16777703, -15253301, -9642417, 4978983, 3308785, 8755439, 6943197, 6461331, -25583147, 8991218}, + {-17226263, 1816362, -1673288, -6086439, 31783888, -8175991, -32948145, 7417950, -30242287, 1507265}}, + {{29692663, 6829891, -10498800, 4334896, 20945975, -11906496, -28887608, 8209391, 14606362, -10647073}, + {-3481570, 8707081, 32188102, 5672294, 22096700, 1711240, -33020695, 9761487, 4170404, -2085325}, + {-11587470, 14855945, -4127778, -1531857, -26649089, 15084046, 22186522, 16002000, -14276837, -8400798}}, + {{-4811456, 13761029, -31703877, -2483919, -3312471, 7869047, -7113572, -9620092, 13240845, 10965870}, + {-7742563, -8256762, -14768334, -13656260, -23232383, 12387166, 4498947, 14147411, 29514390, 4302863}, + {-13413405, -12407859, 20757302, -13801832, 14785143, 8976368, -5061276, -2144373, 17846988, -13971927}} + }, { + {{-2244452, -754728, -4597030, -1066309, -6247172, 1455299, -21647728, -9214789, -5222701, 12650267}, + {-9906797, -16070310, 21134160, 12198166, -27064575, 708126, 387813, 13770293, -19134326, 10958663}, + {22470984, 12369526, 23446014, -5441109, -21520802, -9698723, -11772496, -11574455, -25083830, 4271862}}, + {{-25169565, -10053642, -19909332, 15361595, -5984358, 2159192, 75375, -4278529, -32526221, 8469673}, + {15854970, 4148314, -8893890, 7259002, 11666551, 13824734, -30531198, 2697372, 24154791, -9460943}, + {15446137, -15806644, 29759747, 14019369, 30811221, -9610191, -31582008, 12840104, 24913809, 9815020}}, + {{-4709286, -5614269, -31841498, -12288893, -14443537, 10799414, -9103676, 13438769, 18735128, 9466238}, + {11933045, 9281483, 5081055, -5183824, -2628162, -4905629, -7727821, -10896103, -22728655, 16199064}, + {14576810, 379472, -26786533, -8317236, -29426508, -10812974, -102766, 1876699, 30801119, 2164795}}, + {{15995086, 3199873, 13672555, 13712240, -19378835, -4647646, -13081610, -15496269, -13492807, 1268052}, + {-10290614, -3659039, -3286592, 10948818, 23037027, 3794475, -3470338, -12600221, -17055369, 3565904}, + {29210088, -9419337, -5919792, -4952785, 10834811, -13327726, -16512102, -10820713, -27162222, -14030531}}, + {{-13161890, 15508588, 16663704, -8156150, -28349942, 9019123, -29183421, -3769423, 2244111, -14001979}, + {-5152875, -3800936, -9306475, -6071583, 16243069, 14684434, -25673088, -16180800, 13491506, 4641841}, + {10813417, 643330, -19188515, -728916, 30292062, -16600078, 27548447, -7721242, 14476989, -12767431}}, + {{10292079, 9984945, 6481436, 8279905, -7251514, 7032743, 27282937, -1644259, -27912810, 12651324}, + {-31185513, -813383, 22271204, 11835308, 10201545, 15351028, 17099662, 3988035, 21721536, -3148940}, + {10202177, -6545839, -31373232, -9574638, -32150642, -8119683, -12906320, 3852694, 13216206, 14842320}}, + {{-15815640, -10601066, -6538952, -7258995, -6984659, -6581778, -31500847, 13765824, -27434397, 9900184}, + {14465505, -13833331, -32133984, -14738873, -27443187, 12990492, 33046193, 15796406, -7051866, -8040114}, + {30924417, -8279620, 6359016, -12816335, 16508377, 9071735, -25488601, 15413635, 9524356, -7018878}}, + {{12274201, -13175547, 32627641, -1785326, 6736625, 13267305, 5237659, -5109483, 15663516, 4035784}, + {-2951309, 8903985, 17349946, 601635, -16432815, -4612556, -13732739, -15889334, -22258478, 4659091}, + {-16916263, -4952973, -30393711, -15158821, 20774812, 15897498, 5736189, 15026997, -2178256, -13455585}} + }, { + {{-8858980, -2219056, 28571666, -10155518, -474467, -10105698, -3801496, 278095, 23440562, -290208}, + {10226241, -5928702, 15139956, 120818, -14867693, 5218603, 32937275, 11551483, -16571960, -7442864}, + {17932739, -12437276, -24039557, 10749060, 11316803, 7535897, 22503767, 5561594, -3646624, 3898661}}, + {{7749907, -969567, -16339731, -16464, -25018111, 15122143, -1573531, 7152530, 21831162, 1245233}, + {26958459, -14658026, 4314586, 8346991, -5677764, 11960072, -32589295, -620035, -30402091, -16716212}, + {-12165896, 9166947, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, -22338025, 13987525}}, + {{-24349909, 7778775, 21116000, 15572597, -4833266, -5357778, -4300898, -5124639, -7469781, -2858068}, + {9681908, -6737123, -31951644, 13591838, -6883821, 386950, 31622781, 6439245, -14581012, 4091397}, + {-8426427, 1470727, -28109679, -1596990, 3978627, -5123623, -19622683, 12092163, 29077877, -14741988}}, + {{5269168, -6859726, -13230211, -8020715, 25932563, 1763552, -5606110, -5505881, -20017847, 2357889}, + {32264008, -15407652, -5387735, -1160093, -2091322, -3946900, 23104804, -12869908, 5727338, 189038}, + {14609123, -8954470, -6000566, -16622781, -14577387, -7743898, -26745169, 10942115, -25888931, -14884697}}, + {{20513500, 5557931, -15604613, 7829531, 26413943, -2019404, -21378968, 7471781, 13913677, -5137875}, + {-25574376, 11967826, 29233242, 12948236, -6754465, 4713227, -8940970, 14059180, 12878652, 8511905}, + {-25656801, 3393631, -2955415, -7075526, -2250709, 9366908, -30223418, 6812974, 5568676, -3127656}}, + {{11630004, 12144454, 2116339, 13606037, 27378885, 15676917, -17408753, -13504373, -14395196, 8070818}, + {27117696, -10007378, -31282771, -5570088, 1127282, 12772488, -29845906, 10483306, -11552749, -1028714}, + {10637467, -5688064, 5674781, 1072708, -26343588, -6982302, -1683975, 9177853, -27493162, 15431203}}, + {{20525145, 10892566, -12742472, 12779443, -29493034, 16150075, -28240519, 14943142, -15056790, -7935931}, + {-30024462, 5626926, -551567, -9981087, 753598, 11981191, 25244767, -3239766, -3356550, 9594024}, + {-23752644, 2636870, -5163910, -10103818, 585134, 7877383, 11345683, -6492290, 13352335, -10977084}}, + {{-1931799, -5407458, 3304649, -12884869, 17015806, -4877091, -29783850, -7752482, -13215537, -319204}, + {20239939, 6607058, 6203985, 3483793, -18386976, -779229, -20723742, 15077870, -22750759, 14523817}, + {27406042, -6041657, 27423596, -4497394, 4996214, 10002360, -28842031, -4545494, -30172742, -4805667}} + }, { + {{11374242, 12660715, 17861383, -12540833, 10935568, 1099227, -13886076, -9091740, -27727044, 11358504}, + {-12730809, 10311867, 1510375, 10778093, -2119455, -9145702, 32676003, 11149336, -26123651, 4985768}, + {-19096303, 341147, -6197485, -239033, 15756973, -8796662, -983043, 13794114, -19414307, -15621255}}, + {{6490081, 11940286, 25495923, -7726360, 8668373, -8751316, 3367603, 6970005, -1691065, -9004790}, + {1656497, 13457317, 15370807, 6364910, 13605745, 8362338, -19174622, -5475723, -16796596, -5031438}, + {-22273315, -13524424, -64685, -4334223, -18605636, -10921968, -20571065, -7007978, -99853, -10237333}}, + {{17747465, 10039260, 19368299, -4050591, -20630635, -16041286, 31992683, -15857976, -29260363, -5511971}, + {31932027, -4986141, -19612382, 16366580, 22023614, 88450, 11371999, -3744247, 4882242, -10626905}, + {29796507, 37186, 19818052, 10115756, -11829032, 3352736, 18551198, 3272828, -5190932, -4162409}}, + {{12501286, 4044383, -8612957, -13392385, -32430052, 5136599, -19230378, -3529697, 330070, -3659409}, + {6384877, 2899513, 17807477, 7663917, -2358888, 12363165, 25366522, -8573892, -271295, 12071499}, + {-8365515, -4042521, 25133448, -4517355, -6211027, 2265927, -32769618, 1936675, -5159697, 3829363}}, + {{28425966, -5835433, -577090, -4697198, -14217555, 6870930, 7921550, -6567787, 26333140, 14267664}, + {-11067219, 11871231, 27385719, -10559544, -4585914, -11189312, 10004786, -8709488, -21761224, 8930324}, + {-21197785, -16396035, 25654216, -1725397, 12282012, 11008919, 1541940, 4757911, -26491501, -16408940}}, + {{13537262, -7759490, -20604840, 10961927, -5922820, -13218065, -13156584, 6217254, -15943699, 13814990}, + {-17422573, 15157790, 18705543, 29619, 24409717, -260476, 27361681, 9257833, -1956526, -1776914}, + {-25045300, -10191966, 15366585, 15166509, -13105086, 8423556, -29171540, 12361135, -18685978, 4578290}}, + {{24579768, 3711570, 1342322, -11180126, -27005135, 14124956, -22544529, 14074919, 21964432, 8235257}, + {-6528613, -2411497, 9442966, -5925588, 12025640, -1487420, -2981514, -1669206, 13006806, 2355433}, + {-16304899, -13605259, -6632427, -5142349, 16974359, -10911083, 27202044, 1719366, 1141648, -12796236}}, + {{-12863944, -13219986, -8318266, -11018091, -6810145, -4843894, 13475066, -3133972, 32674895, 13715045}, + {11423335, -5468059, 32344216, 8962751, 24989809, 9241752, -13265253, 16086212, -28740881, -15642093}, + {-1409668, 12530728, -6368726, 10847387, 19531186, -14132160, -11709148, 7791794, -27245943, 4383347}} + }, { + {{-28970898, 5271447, -1266009, -9736989, -12455236, 16732599, -4862407, -4906449, 27193557, 6245191}, + {-15193956, 5362278, -1783893, 2695834, 4960227, 12840725, 23061898, 3260492, 22510453, 8577507}, + {-12632451, 11257346, -32692994, 13548177, -721004, 10879011, 31168030, 13952092, -29571492, -3635906}}, + {{3877321, -9572739, 32416692, 5405324, -11004407, -13656635, 3759769, 11935320, 5611860, 8164018}, + {-16275802, 14667797, 15906460, 12155291, -22111149, -9039718, 32003002, -8832289, 5773085, -8422109}, + {-23788118, -8254300, 1950875, 8937633, 18686727, 16459170, -905725, 12376320, 31632953, 190926}}, + {{-24593607, -16138885, -8423991, 13378746, 14162407, 6901328, -8288749, 4508564, -25341555, -3627528}, + {8884438, -5884009, 6023974, 10104341, -6881569, -4941533, 18722941, -14786005, -1672488, 827625}, + {-32720583, -16289296, -32503547, 7101210, 13354605, 2659080, -1800575, -14108036, -24878478, 1541286}}, + {{2901347, -1117687, 3880376, -10059388, -17620940, -3612781, -21802117, -3567481, 20456845, -1885033}, + {27019610, 12299467, -13658288, -1603234, -12861660, -4861471, -19540150, -5016058, 29439641, 15138866}, + {21536104, -6626420, -32447818, -10690208, -22408077, 5175814, -5420040, -16361163, 7779328, 109896}}, + {{30279744, 14648750, -8044871, 6425558, 13639621, -743509, 28698390, 12180118, 23177719, -554075}, + {26572847, 3405927, -31701700, 12890905, -19265668, 5335866, -6493768, 2378492, 4439158, -13279347}, + {-22716706, 3489070, -9225266, -332753, 18875722, -1140095, 14819434, -12731527, -17717757, -5461437}}, + {{-5056483, 16566551, 15953661, 3767752, -10436499, 15627060, -820954, 2177225, 8550082, -15114165}, + {-18473302, 16596775, -381660, 15663611, 22860960, 15585581, -27844109, -3582739, -23260460, -8428588}, + {-32480551, 15707275, -8205912, -5652081, 29464558, 2713815, -22725137, 15860482, -21902570, 1494193}}, + {{-19562091, -14087393, -25583872, -9299552, 13127842, 759709, 21923482, 16529112, 8742704, 12967017}, + {-28464899, 1553205, 32536856, -10473729, -24691605, -406174, -8914625, -2933896, -29903758, 15553883}, + {21877909, 3230008, 9881174, 10539357, -4797115, 2841332, 11543572, 14513274, 19375923, -12647961}}, + {{8832269, -14495485, 13253511, 5137575, 5037871, 4078777, 24880818, -6222716, 2862653, 9455043}, + {29306751, 5123106, 20245049, -14149889, 9592566, 8447059, -2077124, -2990080, 15511449, 4789663}, + {-20679756, 7004547, 8824831, -9434977, -4045704, -3750736, -5754762, 108893, 23513200, 16652362}} + }, { + {{-33256173, 4144782, -4476029, -6579123, 10770039, -7155542, -6650416, -12936300, -18319198, 10212860}, + {2756081, 8598110, 7383731, -6859892, 22312759, -1105012, 21179801, 2600940, -9988298, -12506466}, + {-24645692, 13317462, -30449259, -15653928, 21365574, -10869657, 11344424, 864440, -2499677, -16710063}}, + {{-26432803, 6148329, -17184412, -14474154, 18782929, -275997, -22561534, 211300, 2719757, 4940997}, + {-1323882, 3911313, -6948744, 14759765, -30027150, 7851207, 21690126, 8518463, 26699843, 5276295}, + {-13149873, -6429067, 9396249, 365013, 24703301, -10488939, 1321586, 149635, -15452774, 7159369}}, + {{9987780, -3404759, 17507962, 9505530, 9731535, -2165514, 22356009, 8312176, 22477218, -8403385}, + {18155857, -16504990, 19744716, 9006923, 15154154, -10538976, 24256460, -4864995, -22548173, 9334109}, + {2986088, -4911893, 10776628, -3473844, 10620590, -7083203, -21413845, 14253545, -22587149, 536906}}, + {{4377756, 8115836, 24567078, 15495314, 11625074, 13064599, 7390551, 10589625, 10838060, -15420424}, + {-19342404, 867880, 9277171, -3218459, -14431572, -1986443, 19295826, -15796950, 6378260, 699185}, + {7895026, 4057113, -7081772, -13077756, -17886831, -323126, -716039, 15693155, -5045064, -13373962}}, + {{-7737563, -5869402, -14566319, -7406919, 11385654, 13201616, 31730678, -10962840, -3918636, -9669325}, + {10188286, -15770834, -7336361, 13427543, 22223443, 14896287, 30743455, 7116568, -21786507, 5427593}, + {696102, 13206899, 27047647, -10632082, 15285305, -9853179, 10798490, -4578720, 19236243, 12477404}}, + {{-11229439, 11243796, -17054270, -8040865, -788228, -8167967, -3897669, 11180504, -23169516, 7733644}, + {17800790, -14036179, -27000429, -11766671, 23887827, 3149671, 23466177, -10538171, 10322027, 15313801}, + {26246234, 11968874, 32263343, -5468728, 6830755, -13323031, -15794704, -101982, -24449242, 10890804}}, + {{-31365647, 10271363, -12660625, -6267268, 16690207, -13062544, -14982212, 16484931, 25180797, -5334884}, + {-586574, 10376444, -32586414, -11286356, 19801893, 10997610, 2276632, 9482883, 316878, 13820577}, + {-9882808, -4510367, -2115506, 16457136, -11100081, 11674996, 30756178, -7515054, 30696930, -3712849}}, + {{32988917, -9603412, 12499366, 7910787, -10617257, -11931514, -7342816, -9985397, -32349517, 7392473}, + {-8855661, 15927861, 9866406, -3649411, -2396914, -16655781, -30409476, -9134995, 25112947, -2926644}, + {-2504044, -436966, 25621774, -5678772, 15085042, -5479877, -24884878, -13526194, 5537438, -13914319}} + }, { + {{-11225584, 2320285, -9584280, 10149187, -33444663, 5808648, -14876251, -1729667, 31234590, 6090599}, + {-9633316, 116426, 26083934, 2897444, -6364437, -2688086, 609721, 15878753, -6970405, -9034768}, + {-27757857, 247744, -15194774, -9002551, 23288161, -10011936, -23869595, 6503646, 20650474, 1804084}}, + {{-27589786, 15456424, 8972517, 8469608, 15640622, 4439847, 3121995, -10329713, 27842616, -202328}, + {-15306973, 2839644, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, -11375082, 12714369}, + {20807691, -7270825, 29286141, 11421711, -27876523, -13868230, -21227475, 1035546, -19733229, 12796920}}, + {{12076899, -14301286, -8785001, -11848922, -25012791, 16400684, -17591495, -12899438, 3480665, -15182815}, + {-32361549, 5457597, 28548107, 7833186, 7303070, -11953545, -24363064, -15921875, -33374054, 2771025}, + {-21389266, 421932, 26597266, 6860826, 22486084, -6737172, -17137485, -4210226, -24552282, 15673397}}, + {{-20184622, 2338216, 19788685, -9620956, -4001265, -8740893, -20271184, 4733254, 3727144, -12934448}, + {6120119, 814863, -11794402, -622716, 6812205, -15747771, 2019594, 7975683, 31123697, -10958981}, + {30069250, -11435332, 30434654, 2958439, 18399564, -976289, 12296869, 9204260, -16432438, 9648165}}, + {{32705432, -1550977, 30705658, 7451065, -11805606, 9631813, 3305266, 5248604, -26008332, -11377501}, + {17219865, 2375039, -31570947, -5575615, -19459679, 9219903, 294711, 15298639, 2662509, -16297073}, + {-1172927, -7558695, -4366770, -4287744, -21346413, -8434326, 32087529, -1222777, 32247248, -14389861}}, + {{14312628, 1221556, 17395390, -8700143, -4945741, -8684635, -28197744, -9637817, -16027623, -13378845}, + {-1428825, -9678990, -9235681, 6549687, -7383069, -468664, 23046502, 9803137, 17597934, 2346211}, + {18510800, 15337574, 26171504, 981392, -22241552, 7827556, -23491134, -11323352, 3059833, -11782870}}, + {{10141598, 6082907, 17829293, -1947643, 9830092, 13613136, -25556636, -5544586, -33502212, 3592096}, + {33114168, -15889352, -26525686, -13343397, 33076705, 8716171, 1151462, 1521897, -982665, -6837803}, + {-32939165, -4255815, 23947181, -324178, -33072974, -12305637, -16637686, 3891704, 26353178, 693168}}, + {{30374239, 1595580, -16884039, 13186931, 4600344, 406904, 9585294, -400668, 31375464, 14369965}, + {-14370654, -7772529, 1510301, 6434173, -18784789, -6262728, 32732230, -13108839, 17901441, 16011505}, + {18171223, -11934626, -12500402, 15197122, -11038147, -15230035, -19172240, -16046376, 8764035, 12309598}} + }, { + {{5975908, -5243188, -19459362, -9681747, -11541277, 14015782, -23665757, 1228319, 17544096, -10593782}, + {5811932, -1715293, 3442887, -2269310, -18367348, -8359541, -18044043, -15410127, -5565381, 12348900}, + {-31399660, 11407555, 25755363, 6891399, -3256938, 14872274, -24849353, 8141295, -10632534, -585479}}, + {{-12675304, 694026, -5076145, 13300344, 14015258, -14451394, -9698672, -11329050, 30944593, 1130208}, + {8247766, -6710942, -26562381, -7709309, -14401939, -14648910, 4652152, 2488540, 23550156, -271232}, + {17294316, -3788438, 7026748, 15626851, 22990044, 113481, 2267737, -5908146, -408818, -137719}}, + {{16091085, -16253926, 18599252, 7340678, 2137637, -1221657, -3364161, 14550936, 3260525, -7166271}, + {-4910104, -13332887, 18550887, 10864893, -16459325, -7291596, -23028869, -13204905, -12748722, 2701326}, + {-8574695, 16099415, 4629974, -16340524, -20786213, -6005432, -10018363, 9276971, 11329923, 1862132}}, + {{14763076, -15903608, -30918270, 3689867, 3511892, 10313526, -21951088, 12219231, -9037963, -940300}, + {8894987, -3446094, 6150753, 3013931, 301220, 15693451, -31981216, -2909717, -15438168, 11595570}, + {15214962, 3537601, -26238722, -14058872, 4418657, -15230761, 13947276, 10730794, -13489462, -4363670}}, + {{-2538306, 7682793, 32759013, 263109, -29984731, -7955452, -22332124, -10188635, 977108, 699994}, + {-12466472, 4195084, -9211532, 550904, -15565337, 12917920, 19118110, -439841, -30534533, -14337913}, + {31788461, -14507657, 4799989, 7372237, 8808585, -14747943, 9408237, -10051775, 12493932, -5409317}}, + {{-25680606, 5260744, -19235809, -6284470, -3695942, 16566087, 27218280, 2607121, 29375955, 6024730}, + {842132, -2794693, -4763381, -8722815, 26332018, -12405641, 11831880, 6985184, -9940361, 2854096}, + {-4847262, -7969331, 2516242, -5847713, 9695691, -7221186, 16512645, 960770, 12121869, 16648078}}, + {{-15218652, 14667096, -13336229, 2013717, 30598287, -464137, -31504922, -7882064, 20237806, 2838411}, + {-19288047, 4453152, 15298546, -16178388, 22115043, -15972604, 12544294, -13470457, 1068881, -12499905}, + {-9558883, -16518835, 33238498, 13506958, 30505848, -1114596, -8486907, -2630053, 12521378, 4845654}}, + {{-28198521, 10744108, -2958380, 10199664, 7759311, -13088600, 3409348, -873400, -6482306, -12885870}, + {-23561822, 6230156, -20382013, 10655314, -24040585, -11621172, 10477734, -1240216, -3113227, 13974498}, + {12966261, 15550616, -32038948, -1615346, 21025980, -629444, 5642325, 7188737, 18895762, 12629579}} + }, { + {{14741879, -14946887, 22177208, -11721237, 1279741, 8058600, 11758140, 789443, 32195181, 3895677}, + {10758205, 15755439, -4509950, 9243698, -4879422, 6879879, -2204575, -3566119, -8982069, 4429647}, + {-2453894, 15725973, -20436342, -10410672, -5803908, -11040220, -7135870, -11642895, 18047436, -15281743}}, + {{-25173001, -11307165, 29759956, 11776784, -22262383, -15820455, 10993114, -12850837, -17620701, -9408468}, + {21987233, 700364, -24505048, 14972008, -7774265, -5718395, 32155026, 2581431, -29958985, 8773375}, + {-25568350, 454463, -13211935, 16126715, 25240068, 8594567, 20656846, 12017935, -7874389, -13920155}}, + {{6028182, 6263078, -31011806, -11301710, -818919, 2461772, -31841174, -5468042, -1721788, -2776725}, + {-12278994, 16624277, 987579, -5922598, 32908203, 1248608, 7719845, -4166698, 28408820, 6816612}, + {-10358094, -8237829, 19549651, -12169222, 22082623, 16147817, 20613181, 13982702, -10339570, 5067943}}, + {{-30505967, -3821767, 12074681, 13582412, -19877972, 2443951, -19719286, 12746132, 5331210, -10105944}, + {30528811, 3601899, -1957090, 4619785, -27361822, -15436388, 24180793, -12570394, 27679908, -1648928}, + {9402404, -13957065, 32834043, 10838634, -26580150, -13237195, 26653274, -8685565, 22611444, -12715406}}, + {{22190590, 1118029, 22736441, 15130463, -30460692, -5991321, 19189625, -4648942, 4854859, 6622139}, + {-8310738, -2953450, -8262579, -3388049, -10401731, -271929, 13424426, -3567227, 26404409, 13001963}, + {-31241838, -15415700, -2994250, 8939346, 11562230, -12840670, -26064365, -11621720, -15405155, 11020693}}, + {{1866042, -7949489, -7898649, -10301010, 12483315, 13477547, 3175636, -12424163, 28761762, 1406734}, + {-448555, -1777666, 13018551, 3194501, -9580420, -11161737, 24760585, -4347088, 25577411, -13378680}, + {-24290378, 4759345, -690653, -1852816, 2066747, 10693769, -29595790, 9884936, -9368926, 4745410}}, + {{-9141284, 6049714, -19531061, -4341411, -31260798, 9944276, -15462008, -11311852, 10931924, -11931931}, + {-16561513, 14112680, -8012645, 4817318, -8040464, -11414606, -22853429, 10856641, -20470770, 13434654}, + {22759489, -10073434, -16766264, -1871422, 13637442, -10168091, 1765144, -12654326, 28445307, -5364710}}, + {{29875063, 12493613, 2795536, -3786330, 1710620, 15181182, -10195717, -8788675, 9074234, 1167180}, + {-26205683, 11014233, -9842651, -2635485, -26908120, 7532294, -18716888, -9535498, 3843903, 9367684}, + {-10969595, -6403711, 9591134, 9582310, 11349256, 108879, 16235123, 8601684, -139197, 4242895}} + }, { + {{22092954, -13191123, -2042793, -11968512, 32186753, -11517388, -6574341, 2470660, -27417366, 16625501}, + {-11057722, 3042016, 13770083, -9257922, 584236, -544855, -7770857, 2602725, -27351616, 14247413}, + {6314175, -10264892, -32772502, 15957557, -10157730, 168750, -8618807, 14290061, 27108877, -1180880}}, + {{-8586597, -7170966, 13241782, 10960156, -32991015, -13794596, 33547976, -11058889, -27148451, 981874}, + {22833440, 9293594, -32649448, -13618667, -9136966, 14756819, -22928859, -13970780, -10479804, -16197962}, + {-7768587, 3326786, -28111797, 10783824, 19178761, 14905060, 22680049, 13906969, -15933690, 3797899}}, + {{21721356, -4212746, -12206123, 9310182, -3882239, -13653110, 23740224, -2709232, 20491983, -8042152}, + {9209270, -15135055, -13256557, -6167798, -731016, 15289673, 25947805, 15286587, 30997318, -6703063}, + {7392032, 16618386, 23946583, -8039892, -13265164, -1533858, -14197445, -2321576, 17649998, -250080}}, + {{-9301088, -14193827, 30609526, -3049543, -25175069, -1283752, -15241566, -9525724, -2233253, 7662146}, + {-17558673, 1763594, -33114336, 15908610, -30040870, -12174295, 7335080, -8472199, -3174674, 3440183}, + {-19889700, -5977008, -24111293, -9688870, 10799743, -16571957, 40450, -4431835, 4862400, 1133}}, + {{-32856209, -7873957, -5422389, 14860950, -16319031, 7956142, 7258061, 311861, -30594991, -7379421}, + {-3773428, -1565936, 28985340, 7499440, 24445838, 9325937, 29727763, 16527196, 18278453, 15405622}, + {-4381906, 8508652, -19898366, -3674424, -5984453, 15149970, -13313598, 843523, -21875062, 13626197}}, + {{2281448, -13487055, -10915418, -2609910, 1879358, 16164207, -10783882, 3953792, 13340839, 15928663}, + {31727126, -7179855, -18437503, -8283652, 2875793, -16390330, -25269894, -7014826, -23452306, 5964753}, + {4100420, -5959452, -17179337, 6017714, -18705837, 12227141, -26684835, 11344144, 2538215, -7570755}}, + {{-9433605, 6123113, 11159803, -2156608, 30016280, 14966241, -20474983, 1485421, -629256, -15958862}, + {-26804558, 4260919, 11851389, 9658551, -32017107, 16367492, -20205425, -13191288, 11659922, -11115118}, + {26180396, 10015009, -30844224, -8581293, 5418197, 9480663, 2231568, -10170080, 33100372, -1306171}}, + {{15121113, -5201871, -10389905, 15427821, -27509937, -15992507, 21670947, 4486675, -5931810, -14466380}, + {16166486, -9483733, -11104130, 6023908, -31926798, -1364923, 2340060, -16254968, -10735770, -10039824}, + {28042865, -3557089, -12126526, 12259706, -3717498, -6945899, 6766453, -8689599, 18036436, 5803270}} + }, { + {{-817581, 6763912, 11803561, 1585585, 10958447, -2671165, 23855391, 4598332, -6159431, -14117438}, + {-31031306, -14256194, 17332029, -2383520, 31312682, -5967183, 696309, 50292, -20095739, 11763584}, + {-594563, -2514283, -32234153, 12643980, 12650761, 14811489, 665117, -12613632, -19773211, -10713562}}, + {{30464590, -11262872, -4127476, -12734478, 19835327, -7105613, -24396175, 2075773, -17020157, 992471}, + {18357185, -6994433, 7766382, 16342475, -29324918, 411174, 14578841, 8080033, -11574335, -10601610}, + {19598397, 10334610, 12555054, 2555664, 18821899, -10339780, 21873263, 16014234, 26224780, 16452269}}, + {{-30223925, 5145196, 5944548, 16385966, 3976735, 2009897, -11377804, -7618186, -20533829, 3698650}, + {14187449, 3448569, -10636236, -10810935, -22663880, -3433596, 7268410, -10890444, 27394301, 12015369}, + {19695761, 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, -1312777, -13259127, -3402461}}, + {{30860103, 12735208, -1888245, -4699734, -16974906, 2256940, -8166013, 12298312, -8550524, -10393462}, + {-5719826, -11245325, -1910649, 15569035, 26642876, -7587760, -5789354, -15118654, -4976164, 12651793}, + {-2848395, 9953421, 11531313, -5282879, 26895123, -12697089, -13118820, -16517902, 9768698, -2533218}}, + {{-24719459, 1894651, -287698, -4704085, 15348719, -8156530, 32767513, 12765450, 4940095, 10678226}, + {18860224, 15980149, -18987240, -1562570, -26233012, -11071856, -7843882, 13944024, -24372348, 16582019}, + {-15504260, 4970268, -29893044, 4175593, -20993212, -2199756, -11704054, 15444560, -11003761, 7989037}}, + {{31490452, 5568061, -2412803, 2182383, -32336847, 4531686, -32078269, 6200206, -19686113, -14800171}, + {-17308668, -15879940, -31522777, -2831, -32887382, 16375549, 8680158, -16371713, 28550068, -6857132}, + {-28126887, -5688091, 16837845, -1820458, -6850681, 12700016, -30039981, 4364038, 1155602, 5988841}}, + {{21890435, -13272907, -12624011, 12154349, -7831873, 15300496, 23148983, -4470481, 24618407, 8283181}, + {-33136107, -10512751, 9975416, 6841041, -31559793, 16356536, 3070187, -7025928, 1466169, 10740210}, + {-1509399, -15488185, -13503385, -10655916, 32799044, 909394, -13938903, -5779719, -32164649, -15327040}}, + {{3960823, -14267803, -28026090, -15918051, -19404858, 13146868, 15567327, 951507, -3260321, -573935}, + {24740841, 5052253, -30094131, 8961361, 25877428, 6165135, -24368180, 14397372, -7380369, -6144105}, + {-28888365, 3510803, -28103278, -1158478, -11238128, -10631454, -15441463, -14453128, -1625486, -6494814}} + }, { + {{793299, -9230478, 8836302, -6235707, -27360908, -2369593, 33152843, -4885251, -9906200, -621852}, + {5666233, 525582, 20782575, -8038419, -24538499, 14657740, 16099374, 1468826, -6171428, -15186581}, + {-4859255, -3779343, -2917758, -6748019, 7778750, 11688288, -30404353, -9871238, -1558923, -9863646}}, + {{10896332, -7719704, 824275, 472601, -19460308, 3009587, 25248958, 14783338, -30581476, -15757844}, + {10566929, 12612572, -31944212, 11118703, -12633376, 12362879, 21752402, 8822496, 24003793, 14264025}, + {27713862, -7355973, -11008240, 9227530, 27050101, 2504721, 23886875, -13117525, 13958495, -5732453}}, + {{-23481610, 4867226, -27247128, 3900521, 29838369, -8212291, -31889399, -10041781, 7340521, -15410068}, + {4646514, -8011124, -22766023, -11532654, 23184553, 8566613, 31366726, -1381061, -15066784, -10375192}, + {-17270517, 12723032, -16993061, 14878794, 21619651, -6197576, 27584817, 3093888, -8843694, 3849921}}, + {{-9064912, 2103172, 25561640, -15125738, -5239824, 9582958, 32477045, -9017955, 5002294, -15550259}, + {-12057553, -11177906, 21115585, -13365155, 8808712, -12030708, 16489530, 13378448, -25845716, 12741426}, + {-5946367, 10645103, -30911586, 15390284, -3286982, -7118677, 24306472, 15852464, 28834118, -7646072}}, + {{-17335748, -9107057, -24531279, 9434953, -8472084, -583362, -13090771, 455841, 20461858, 5491305}, + {13669248, -16095482, -12481974, -10203039, -14569770, -11893198, -24995986, 11293807, -28588204, -9421832}, + {28497928, 6272777, -33022994, 14470570, 8906179, -1225630, 18504674, -14165166, 29867745, -8795943}}, + {{-16207023, 13517196, -27799630, -13697798, 24009064, -6373891, -6367600, -13175392, 22853429, -4012011}, + {24191378, 16712145, -13931797, 15217831, 14542237, 1646131, 18603514, -11037887, 12876623, -2112447}, + {17902668, 4518229, -411702, -2829247, 26878217, 5258055, -12860753, 608397, 16031844, 3723494}}, + {{-28632773, 12763728, -20446446, 7577504, 33001348, -13017745, 17558842, -7872890, 23896954, -4314245}, + {-20005381, -12011952, 31520464, 605201, 2543521, 5991821, -2945064, 7229064, -9919646, -8826859}, + {28816045, 298879, -28165016, -15920938, 19000928, -1665890, -12680833, -2949325, -18051778, -2082915}}, + {{16000882, -344896, 3493092, -11447198, -29504595, -13159789, 12577740, 16041268, -19715240, 7847707}, + {10151868, 10572098, 27312476, 7922682, 14825339, 4723128, -32855931, -6519018, -10020567, 3852848}, + {-11430470, 15697596, -21121557, -4420647, 5386314, 15063598, 16514493, -15932110, 29330899, -15076224}} + }, { + {{-25499735, -4378794, -15222908, -6901211, 16615731, 2051784, 3303702, 15490, -27548796, 12314391}, + {15683520, -6003043, 18109120, -9980648, 15337968, -5997823, -16717435, 15921866, 16103996, -3731215}, + {-23169824, -10781249, 13588192, -1628807, -3798557, -1074929, -19273607, 5402699, -29815713, -9841101}}, + {{23190676, 2384583, -32714340, 3462154, -29903655, -1529132, -11266856, 8911517, -25205859, 2739713}, + {21374101, -3554250, -33524649, 9874411, 15377179, 11831242, -33529904, 6134907, 4931255, 11987849}, + {-7732, -2978858, -16223486, 7277597, 105524, -322051, -31480539, 13861388, -30076310, 10117930}}, + {{-29501170, -10744872, -26163768, 13051539, -25625564, 5089643, -6325503, 6704079, 12890019, 15728940}, + {-21972360, -11771379, -951059, -4418840, 14704840, 2695116, 903376, -10428139, 12885167, 8311031}, + {-17516482, 5352194, 10384213, -13811658, 7506451, 13453191, 26423267, 4384730, 1888765, -5435404}}, + {{-25817338, -3107312, -13494599, -3182506, 30896459, -13921729, -32251644, -12707869, -19464434, -3340243}, + {-23607977, -2665774, -526091, 4651136, 5765089, 4618330, 6092245, 14845197, 17151279, -9854116}, + {-24830458, -12733720, -15165978, 10367250, -29530908, -265356, 22825805, -7087279, -16866484, 16176525}}, + {{-23583256, 6564961, 20063689, 3798228, -4740178, 7359225, 2006182, -10363426, -28746253, -10197509}, + {-10626600, -4486402, -13320562, -5125317, 3432136, -6393229, 23632037, -1940610, 32808310, 1099883}, + {15030977, 5768825, -27451236, -2887299, -6427378, -15361371, -15277896, -6809350, 2051441, -15225865}}, + {{-3362323, -7239372, 7517890, 9824992, 23555850, 295369, 5148398, -14154188, -22686354, 16633660}, + {4577086, -16752288, 13249841, -15304328, 19958763, -14537274, 18559670, -10759549, 8402478, -9864273}, + {-28406330, -1051581, -26790155, -907698, -17212414, -11030789, 9453451, -14980072, 17983010, 9967138}}, + {{-25762494, 6524722, 26585488, 9969270, 24709298, 1220360, -1677990, 7806337, 17507396, 3651560}, + {-10420457, -4118111, 14584639, 15971087, -15768321, 8861010, 26556809, -5574557, -18553322, -11357135}, + {2839101, 14284142, 4029895, 3472686, 14402957, 12689363, -26642121, 8459447, -5605463, -7621941}}, + {{-4839289, -3535444, 9744961, 2871048, 25113978, 3187018, -25110813, -849066, 17258084, -7977739}, + {18164541, -10595176, -17154882, -1542417, 19237078, -9745295, 23357533, -15217008, 26908270, 12150756}, + {-30264870, -7647865, 5112249, -7036672, -1499807, -6974257, 43168, -5537701, -32302074, 16215819}} + }, { + {{-6898905, 9824394, -12304779, -4401089, -31397141, -6276835, 32574489, 12532905, -7503072, -8675347}, + {-27343522, -16515468, -27151524, -10722951, 946346, 16291093, 254968, 7168080, 21676107, -1943028}, + {21260961, -8424752, -16831886, -11920822, -23677961, 3968121, -3651949, -6215466, -3556191, -7913075}}, + {{16544754, 13250366, -16804428, 15546242, -4583003, 12757258, -2462308, -8680336, -18907032, -9662799}, + {-2415239, -15577728, 18312303, 4964443, -15272530, -12653564, 26820651, 16690659, 25459437, -4564609}, + {-25144690, 11425020, 28423002, -11020557, -6144921, -15826224, 9142795, -2391602, -6432418, -1644817}}, + {{-23104652, 6253476, 16964147, -3768872, -25113972, -12296437, -27457225, -16344658, 6335692, 7249989}, + {-30333227, 13979675, 7503222, -12368314, -11956721, -4621693, -30272269, 2682242, 25993170, -12478523}, + {4364628, 5930691, 32304656, -10044554, -8054781, 15091131, 22857016, -10598955, 31820368, 15075278}}, + {{31879134, -8918693, 17258761, 90626, -8041836, -4917709, 24162788, -9650886, -17970238, 12833045}, + {19073683, 14851414, -24403169, -11860168, 7625278, 11091125, -19619190, 2074449, -9413939, 14905377}, + {24483667, -11935567, -2518866, -11547418, -1553130, 15355506, -25282080, 9253129, 27628530, -7555480}}, + {{17597607, 8340603, 19355617, 552187, 26198470, -3176583, 4593324, -9157582, -14110875, 15297016}, + {510886, 14337390, -31785257, 16638632, 6328095, 2713355, -20217417, -11864220, 8683221, 2921426}, + {18606791, 11874196, 27155355, -5281482, -24031742, 6265446, -25178240, -1278924, 4674690, 13890525}}, + {{13609624, 13069022, -27372361, -13055908, 24360586, 9592974, 14977157, 9835105, 4389687, 288396}, + {9922506, -519394, 13613107, 5883594, -18758345, -434263, -12304062, 8317628, 23388070, 16052080}, + {12720016, 11937594, -31970060, -5028689, 26900120, 8561328, -20155687, -11632979, -14754271, -10812892}}, + {{15961858, 14150409, 26716931, -665832, -22794328, 13603569, 11829573, 7467844, -28822128, 929275}, + {11038231, -11582396, -27310482, -7316562, -10498527, -16307831, -23479533, -9371869, -21393143, 2465074}, + {20017163, -4323226, 27915242, 1529148, 12396362, 15675764, 13817261, -9658066, 2463391, -4622140}}, + {{-16358878, -12663911, -12065183, 4996454, -1256422, 1073572, 9583558, 12851107, 4003896, 12673717}, + {-1731589, -15155870, -3262930, 16143082, 19294135, 13385325, 14741514, -9103726, 7903886, 2348101}, + {24536016, -16515207, 12715592, -3862155, 1511293, 10047386, -3842346, -7129159, -28377538, 10048127}} + }, { + {{-12622226, -6204820, 30718825, 2591312, -10617028, 12192840, 18873298, -7297090, -32297756, 15221632}, + {-26478122, -11103864, 11546244, -1852483, 9180880, 7656409, -21343950, 2095755, 29769758, 6593415}, + {-31994208, -2907461, 4176912, 3264766, 12538965, -868111, 26312345, -6118678, 30958054, 8292160}}, + {{31429822, -13959116, 29173532, 15632448, 12174511, -2760094, 32808831, 3977186, 26143136, -3148876}, + {22648901, 1402143, -22799984, 13746059, 7936347, 365344, -8668633, -1674433, -3758243, -2304625}, + {-15491917, 8012313, -2514730, -12702462, -23965846, -10254029, -1612713, -1535569, -16664475, 8194478}}, + {{27338066, -7507420, -7414224, 10140405, -19026427, -6589889, 27277191, 8855376, 28572286, 3005164}, + {26287124, 4821776, 25476601, -4145903, -3764513, -15788984, -18008582, 1182479, -26094821, -13079595}, + {-7171154, 3178080, 23970071, 6201893, -17195577, -4489192, -21876275, -13982627, 32208683, -1198248}}, + {{-16657702, 2817643, -10286362, 14811298, 6024667, 13349505, -27315504, -10497842, -27672585, -11539858}, + {15941029, -9405932, -21367050, 8062055, 31876073, -238629, -15278393, -1444429, 15397331, -4130193}, + {8934485, -13485467, -23286397, -13423241, -32446090, 14047986, 31170398, -1441021, -27505566, 15087184}}, + {{-18357243, -2156491, 24524913, -16677868, 15520427, -6360776, -15502406, 11461896, 16788528, -5868942}, + {-1947386, 16013773, 21750665, 3714552, -17401782, -16055433, -3770287, -10323320, 31322514, -11615635}, + {21426655, -5650218, -13648287, -5347537, -28812189, -4920970, -18275391, -14621414, 13040862, -12112948}}, + {{11293895, 12478086, -27136401, 15083750, -29307421, 14748872, 14555558, -13417103, 1613711, 4896935}, + {-25894883, 15323294, -8489791, -8057900, 25967126, -13425460, 2825960, -4897045, -23971776, -11267415}, + {-15924766, -5229880, -17443532, 6410664, 3622847, 10243618, 20615400, 12405433, -23753030, -8436416}}, + {{-7091295, 12556208, -20191352, 9025187, -17072479, 4333801, 4378436, 2432030, 23097949, -566018}, + {4565804, -16025654, 20084412, -7842817, 1724999, 189254, 24767264, 10103221, -18512313, 2424778}, + {366633, -11976806, 8173090, -6890119, 30788634, 5745705, -7168678, 1344109, -3642553, 12412659}}, + {{-24001791, 7690286, 14929416, -168257, -32210835, -13412986, 24162697, -15326504, -3141501, 11179385}, + {18289522, -14724954, 8056945, 16430056, -21729724, 7842514, -6001441, -1486897, -18684645, -11443503}, + {476239, 6601091, -6152790, -9723375, 17503545, -4863900, 27672959, 13403813, 11052904, 5219329}} + }, { + {{20678546, -8375738, -32671898, 8849123, -5009758, 14574752, 31186971, -3973730, 9014762, -8579056}, + {-13644050, -10350239, -15962508, 5075808, -1514661, -11534600, -33102500, 9160280, 8473550, -3256838}, + {24900749, 14435722, 17209120, -15292541, -22592275, 9878983, -7689309, -16335821, -24568481, 11788948}}, + {{-3118155, -11395194, -13802089, 14797441, 9652448, -6845904, -20037437, 10410733, -24568470, -1458691}, + {-15659161, 16736706, -22467150, 10215878, -9097177, 7563911, 11871841, -12505194, -18513325, 8464118}, + {-23400612, 8348507, -14585951, -861714, -3950205, -6373419, 14325289, 8628612, 33313881, -8370517}}, + {{-20186973, -4967935, 22367356, 5271547, -1097117, -4788838, -24805667, -10236854, -8940735, -5818269}, + {-6948785, -1795212, -32625683, -16021179, 32635414, -7374245, 15989197, -12838188, 28358192, -4253904}, + {-23561781, -2799059, -32351682, -1661963, -9147719, 10429267, -16637684, 4072016, -5351664, 5596589}}, + {{-28236598, -3390048, 12312896, 6213178, 3117142, 16078565, 29266239, 2557221, 1768301, 15373193}, + {-7243358, -3246960, -4593467, -7553353, -127927, -912245, -1090902, -4504991, -24660491, 3442910}, + {-30210571, 5124043, 14181784, 8197961, 18964734, -11939093, 22597931, 7176455, -18585478, 13365930}}, + {{-7877390, -1499958, 8324673, 4690079, 6261860, 890446, 24538107, -8570186, -9689599, -3031667}, + {25008904, -10771599, -4305031, -9638010, 16265036, 15721635, 683793, -11823784, 15723479, -15163481}, + {-9660625, 12374379, -27006999, -7026148, -7724114, -12314514, 11879682, 5400171, 519526, -1235876}}, + {{22258397, -16332233, -7869817, 14613016, -22520255, -2950923, -20353881, 7315967, 16648397, 7605640}, + {-8081308, -8464597, -8223311, 9719710, 19259459, -15348212, 23994942, -5281555, -9468848, 4763278}, + {-21699244, 9220969, -15730624, 1084137, -25476107, -2852390, 31088447, -7764523, -11356529, 728112}}, + {{26047220, -11751471, -6900323, -16521798, 24092068, 9158119, -4273545, -12555558, -29365436, -5498272}, + {17510331, -322857, 5854289, 8403524, 17133918, -3112612, -28111007, 12327945, 10750447, 10014012}, + {-10312768, 3936952, 9156313, -8897683, 16498692, -994647, -27481051, -666732, 3424691, 7540221}}, + {{30322361, -6964110, 11361005, -4143317, 7433304, 4989748, -7071422, -16317219, -9244265, 15258046}, + {13054562, -2779497, 19155474, 469045, -12482797, 4566042, 5631406, 2711395, 1062915, -5136345}, + {-19240248, -11254599, -29509029, -7499965, -5835763, 13005411, -6066489, 12194497, 32960380, 1459310}} + }, { + {{19852034, 7027924, 23669353, 10020366, 8586503, -6657907, 394197, -6101885, 18638003, -11174937}, + {31395534, 15098109, 26581030, 8030562, -16527914, -5007134, 9012486, -7584354, -6643087, -5442636}, + {-9192165, -2347377, -1997099, 4529534, 25766844, 607986, -13222, 9677543, -32294889, -6456008}}, + {{-2444496, -149937, 29348902, 8186665, 1873760, 12489863, -30934579, -7839692, -7852844, -8138429}, + {-15236356, -15433509, 7766470, 746860, 26346930, -10221762, -27333451, 10754588, -9431476, 5203576}, + {31834314, 14135496, -770007, 5159118, 20917671, -16768096, -7467973, -7337524, 31809243, 7347066}}, + {{-9606723, -11874240, 20414459, 13033986, 13716524, -11691881, 19797970, -12211255, 15192876, -2087490}, + {-12663563, -2181719, 1168162, -3804809, 26747877, -14138091, 10609330, 12694420, 33473243, -13382104}, + {33184999, 11180355, 15832085, -11385430, -1633671, 225884, 15089336, -11023903, -6135662, 14480053}}, + {{31308717, -5619998, 31030840, -1897099, 15674547, -6582883, 5496208, 13685227, 27595050, 8737275}, + {-20318852, -15150239, 10933843, -16178022, 8335352, -7546022, -31008351, -12610604, 26498114, 66511}, + {22644454, -8761729, -16671776, 4884562, -3105614, -13559366, 30540766, -4286747, -13327787, -7515095}}, + {{-28017847, 9834845, 18617207, -2681312, -3401956, -13307506, 8205540, 13585437, -17127465, 15115439}, + {23711543, -672915, 31206561, -8362711, 6164647, -9709987, -33535882, -1426096, 8236921, 16492939}, + {-23910559, -13515526, -26299483, -4503841, 25005590, -7687270, 19574902, 10071562, 6708380, -6222424}}, + {{2101391, -4930054, 19702731, 2367575, -15427167, 1047675, 5301017, 9328700, 29955601, -11678310}, + {3096359, 9271816, -21620864, -15521844, -14847996, -7592937, -25892142, -12635595, -9917575, 6216608}, + {-32615849, 338663, -25195611, 2510422, -29213566, -13820213, 24822830, -6146567, -26767480, 7525079}}, + {{-23066649, -13985623, 16133487, -7896178, -3389565, 778788, -910336, -2782495, -19386633, 11994101}, + {21691500, -13624626, -641331, -14367021, 3285881, -3483596, -25064666, 9718258, -7477437, 13381418}, + {18445390, -4202236, 14979846, 11622458, -1727110, -3582980, 23111648, -6375247, 28535282, 15779576}}, + {{30098053, 3089662, -9234387, 16662135, -21306940, 11308411, -14068454, 12021730, 9955285, -16303356}, + {9734894, -14576830, -7473633, -9138735, 2060392, 11313496, -18426029, 9924399, 20194861, 13380996}, + {-26378102, -7965207, -22167821, 15789297, -18055342, -6168792, -1984914, 15707771, 26342023, 10146099}} + }, { + {{-26016874, -219943, 21339191, -41388, 19745256, -2878700, -29637280, 2227040, 21612326, -545728}, + {-13077387, 1184228, 23562814, -5970442, -20351244, -6348714, 25764461, 12243797, -20856566, 11649658}, + {-10031494, 11262626, 27384172, 2271902, 26947504, -15997771, 39944, 6114064, 33514190, 2333242}}, + {{-21433588, -12421821, 8119782, 7219913, -21830522, -9016134, -6679750, -12670638, 24350578, -13450001}, + {-4116307, -11271533, -23886186, 4843615, -30088339, 690623, -31536088, -10406836, 8317860, 12352766}, + {18200138, -14475911, -33087759, -2696619, -23702521, -9102511, -23552096, -2287550, 20712163, 6719373}}, + {{26656208, 6075253, -7858556, 1886072, -28344043, 4262326, 11117530, -3763210, 26224235, -3297458}, + {-17168938, -14854097, -3395676, -16369877, -19954045, 14050420, 21728352, 9493610, 18620611, -16428628}, + {-13323321, 13325349, 11432106, 5964811, 18609221, 6062965, -5269471, -9725556, -30701573, -16479657}}, + {{-23860538, -11233159, 26961357, 1640861, -32413112, -16737940, 12248509, -5240639, 13735342, 1934062}, + {25089769, 6742589, 17081145, -13406266, 21909293, -16067981, -15136294, -3765346, -21277997, 5473616}, + {31883677, -7961101, 1083432, -11572403, 22828471, 13290673, -7125085, 12469656, 29111212, -5451014}}, + {{24244947, -15050407, -26262976, 2791540, -14997599, 16666678, 24367466, 6388839, -10295587, 452383}, + {-25640782, -3417841, 5217916, 16224624, 19987036, -4082269, -24236251, -5915248, 15766062, 8407814}, + {-20406999, 13990231, 15495425, 16395525, 5377168, 15166495, -8917023, -4388953, -8067909, 2276718}}, + {{30157918, 12924066, -17712050, 9245753, 19895028, 3368142, -23827587, 5096219, 22740376, -7303417}, + {2041139, -14256350, 7783687, 13876377, -25946985, -13352459, 24051124, 13742383, -15637599, 13295222}, + {33338237, -8505733, 12532113, 7977527, 9106186, -1715251, -17720195, -4612972, -4451357, -14669444}}, + {{-20045281, 5454097, -14346548, 6447146, 28862071, 1883651, -2469266, -4141880, 7770569, 9620597}, + {23208068, 7979712, 33071466, 8149229, 1758231, -10834995, 30945528, -1694323, -33502340, -14767970}, + {1439958, -16270480, -1079989, -793782, 4625402, 10647766, -5043801, 1220118, 30494170, -11440799}}, + {{-5037580, -13028295, -2970559, -3061767, 15640974, -6701666, -26739026, 926050, -1684339, -13333647}, + {13908495, -3549272, 30919928, -6273825, -21521863, 7989039, 9021034, 9078865, 3353509, 4033511}, + {-29663431, -15113610, 32259991, -344482, 24295849, -12912123, 23161163, 8839127, 27485041, 7356032}} + }, { + {{9661027, 705443, 11980065, -5370154, -1628543, 14661173, -6346142, 2625015, 28431036, -16771834}, + {-23839233, -8311415, -25945511, 7480958, -17681669, -8354183, -22545972, 14150565, 15970762, 4099461}, + {29262576, 16756590, 26350592, -8793563, 8529671, -11208050, 13617293, -9937143, 11465739, 8317062}}, + {{-25493081, -6962928, 32500200, -9419051, -23038724, -2302222, 14898637, 3848455, 20969334, -5157516}, + {-20384450, -14347713, -18336405, 13884722, -33039454, 2842114, -21610826, -3649888, 11177095, 14989547}, + {-24496721, -11716016, 16959896, 2278463, 12066309, 10137771, 13515641, 2581286, -28487508, 9930240}}, + {{-17751622, -2097826, 16544300, -13009300, -15914807, -14949081, 18345767, -13403753, 16291481, -5314038}, + {-33229194, 2553288, 32678213, 9875984, 8534129, 6889387, -9676774, 6957617, 4368891, 9788741}, + {16660756, 7281060, -10830758, 12911820, 20108584, -8101676, -21722536, -8613148, 16250552, -11111103}}, + {{-19765507, 2390526, -16551031, 14161980, 1905286, 6414907, 4689584, 10604807, -30190403, 4782747}, + {-1354539, 14736941, -7367442, -13292886, 7710542, -14155590, -9981571, 4383045, 22546403, 437323}, + {31665577, -12180464, -16186830, 1491339, -18368625, 3294682, 27343084, 2786261, -30633590, -14097016}}, + {{-14467279, -683715, -33374107, 7448552, 19294360, 14334329, -19690631, 2355319, -19284671, -6114373}, + {15121312, -15796162, 6377020, -6031361, -10798111, -12957845, 18952177, 15496498, -29380133, 11754228}, + {-2637277, -13483075, 8488727, -14303896, 12728761, -1622493, 7141596, 11724556, 22761615, -10134141}}, + {{16918416, 11729663, -18083579, 3022987, -31015732, -13339659, -28741185, -12227393, 32851222, 11717399}, + {11166634, 7338049, -6722523, 4531520, -29468672, -7302055, 31474879, 3483633, -1193175, -4030831}, + {-185635, 9921305, 31456609, -13536438, -12013818, 13348923, 33142652, 6546660, -19985279, -3948376}}, + {{-32460596, 11266712, -11197107, -7899103, 31703694, 3855903, -8537131, -12833048, -30772034, -15486313}, + {-18006477, 12709068, 3991746, -6479188, -21491523, -10550425, -31135347, -16049879, 10928917, 3011958}, + {-6957757, -15594337, 31696059, 334240, 29576716, 14796075, -30831056, -12805180, 18008031, 10258577}}, + {{-22448644, 15655569, 7018479, -4410003, -30314266, -1201591, -1853465, 1367120, 25127874, 6671743}, + {29701166, -14373934, -10878120, 9279288, -17568, 13127210, 21382910, 11042292, 25838796, 4642684}, + {-20430234, 14955537, -24126347, 8124619, -5369288, -5990470, 30468147, -13900640, 18423289, 4177476}} + } +}; + +const ge_precomp ge_Bi[8] = { + {{25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605}, + {-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378}, + {-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546}}, {{15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024}, + {16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574}, + {30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357}}, {{10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380}, + {4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306}, + {19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942}}, {{5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766}, + {-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701}, + {28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300}}, {{-22518993, -6692182, 14201702, -8745502, -23510406, 8844726, 18474211, -1361450, -13062696, 13821877}, + {-6455177, -7839871, 3374702, -4740862, -27098617, -10571707, 31655028, -7212327, 18853322, -14220951}, + {4566830, -12963868, -28974889, -12240689, -7602672, -2830569, -8514358, -10431137, 2207753, -3209784}}, {{-25154831, -4185821, 29681144, 7868801, -6854661, -9423865, -12437364, -663000, -31111463, -16132436}, + {25576264, -2703214, 7349804, -11814844, 16472782, 9300885, 3844789, 15725684, 171356, 6466918}, + {23103977, 13316479, 9739013, -16149481, 817875, -15038942, 8965339, -14088058, -30714912, 16193877}}, {{-33521811, 3180713, -2394130, 14003687, -16903474, -16270840, 17238398, 4729455, -18074513, 9256800}, + {-25182317, -4174131, 32336398, 5036987, -21236817, 11360617, 22616405, 9761698, -19827198, 630305}, + {-13720693, 2639453, -24237460, -7406481, 9494427, -5774029, -6554551, -15960994, -2449256, -14291300}}, {{-3151181, -5046075, 9282714, 6866145, -31907062, -863023, -18940575, 15033784, 25105118, -7894876}, + {-24326370, 15950226, -31801215, -14592823, -11662737, -5090925, 1573892, -2625887, 2198790, -15804619}, + {-3099351, 10324967, -2241613, 7453183, -5446979, -2735503, -13812022, -16236442, -32461234, -12290683}} +}; + +/* A = 2 * (1 - d) / (1 + d) = 486662 */ +const fe fe_ma2 = {-12721188, -3529, 0, 0, 0, 0, 0, 0, 0, 0}; /* -A^2 */ +const fe fe_ma = {-486662, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* -A */ +const fe fe_fffb1 = {-31702527, -2466483, -26106795, -12203692, -12169197, -321052, 14850977, -10296299, -16929438, -407568}; /* sqrt(-2 * A * (A + 2)) */ +const fe fe_fffb2 = {8166131, -6741800, -17040804, 3154616, 21461005, 1466302, -30876704, -6368709, 10503587, -13363080}; /* sqrt(2 * A * (A + 2)) */ +const fe fe_fffb3 = {-13620103, 14639558, 4532995, 7679154, 16815101, -15883539, -22863840, -14813421, 13716513, -6477756}; /* sqrt(-sqrt(-1) * A * (A + 2)) */ +const fe fe_fffb4 = {-21786234, -12173074, 21573800, 4524538, -4645904, 16204591, 8012863, -8444712, 3212926, 6885324}; /* sqrt(sqrt(-1) * A * (A + 2)) */ diff --git a/src/crypto/crypto-ops.c b/src/crypto/crypto-ops.c new file mode 100644 index 00000000..97e7df50 --- /dev/null +++ b/src/crypto/crypto-ops.c @@ -0,0 +1,2899 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include + +#include "warnings.h" +#include "crypto-ops.h" + +DISABLE_VS_WARNINGS(4146 4244) + +/* Predeclarations */ + +static void fe_mul(fe, const fe, const fe); +static void fe_sq(fe, const fe); +static void fe_tobytes(unsigned char *, const fe); +static void ge_madd(ge_p1p1 *, const ge_p3 *, const ge_precomp *); +static void ge_msub(ge_p1p1 *, const ge_p3 *, const ge_precomp *); +static void ge_p2_0(ge_p2 *); +static void ge_p3_dbl(ge_p1p1 *, const ge_p3 *); +static void ge_sub(ge_p1p1 *, const ge_p3 *, const ge_cached *); +static void fe_divpowm1(fe, const fe, const fe); + +/* Common functions */ + +static uint64_t load_3(const unsigned char *in) { + uint64_t result; + result = (uint64_t) in[0]; + result |= ((uint64_t) in[1]) << 8; + result |= ((uint64_t) in[2]) << 16; + return result; +} + +static uint64_t load_4(const unsigned char *in) +{ + uint64_t result; + result = (uint64_t) in[0]; + result |= ((uint64_t) in[1]) << 8; + result |= ((uint64_t) in[2]) << 16; + result |= ((uint64_t) in[3]) << 24; + return result; +} + +/* From fe_0.c */ + +/* +h = 0 +*/ + +static void fe_0(fe h) { + h[0] = 0; + h[1] = 0; + h[2] = 0; + h[3] = 0; + h[4] = 0; + h[5] = 0; + h[6] = 0; + h[7] = 0; + h[8] = 0; + h[9] = 0; +} + +/* From fe_1.c */ + +/* +h = 1 +*/ + +static void fe_1(fe h) { + h[0] = 1; + h[1] = 0; + h[2] = 0; + h[3] = 0; + h[4] = 0; + h[5] = 0; + h[6] = 0; + h[7] = 0; + h[8] = 0; + h[9] = 0; +} + +/* From fe_add.c */ + +/* +h = f + g +Can overlap h with f or g. + +Preconditions: + |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + +Postconditions: + |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +*/ + +static void fe_add(fe h, const fe f, const fe g) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int32_t g0 = g[0]; + int32_t g1 = g[1]; + int32_t g2 = g[2]; + int32_t g3 = g[3]; + int32_t g4 = g[4]; + int32_t g5 = g[5]; + int32_t g6 = g[6]; + int32_t g7 = g[7]; + int32_t g8 = g[8]; + int32_t g9 = g[9]; + int32_t h0 = f0 + g0; + int32_t h1 = f1 + g1; + int32_t h2 = f2 + g2; + int32_t h3 = f3 + g3; + int32_t h4 = f4 + g4; + int32_t h5 = f5 + g5; + int32_t h6 = f6 + g6; + int32_t h7 = f7 + g7; + int32_t h8 = f8 + g8; + int32_t h9 = f9 + g9; + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +/* From fe_cmov.c */ + +/* +Replace (f,g) with (g,g) if b == 1; +replace (f,g) with (f,g) if b == 0. + +Preconditions: b in {0,1}. +*/ + +static void fe_cmov(fe f, const fe g, unsigned int b) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int32_t g0 = g[0]; + int32_t g1 = g[1]; + int32_t g2 = g[2]; + int32_t g3 = g[3]; + int32_t g4 = g[4]; + int32_t g5 = g[5]; + int32_t g6 = g[6]; + int32_t g7 = g[7]; + int32_t g8 = g[8]; + int32_t g9 = g[9]; + int32_t x0 = f0 ^ g0; + int32_t x1 = f1 ^ g1; + int32_t x2 = f2 ^ g2; + int32_t x3 = f3 ^ g3; + int32_t x4 = f4 ^ g4; + int32_t x5 = f5 ^ g5; + int32_t x6 = f6 ^ g6; + int32_t x7 = f7 ^ g7; + int32_t x8 = f8 ^ g8; + int32_t x9 = f9 ^ g9; + assert((((b - 1) & ~b) | ((b - 2) & ~(b - 1))) == (unsigned int) -1); + b = -b; + x0 &= b; + x1 &= b; + x2 &= b; + x3 &= b; + x4 &= b; + x5 &= b; + x6 &= b; + x7 &= b; + x8 &= b; + x9 &= b; + f[0] = f0 ^ x0; + f[1] = f1 ^ x1; + f[2] = f2 ^ x2; + f[3] = f3 ^ x3; + f[4] = f4 ^ x4; + f[5] = f5 ^ x5; + f[6] = f6 ^ x6; + f[7] = f7 ^ x7; + f[8] = f8 ^ x8; + f[9] = f9 ^ x9; +} + +/* From fe_copy.c */ + +/* +h = f +*/ + +static void fe_copy(fe h, const fe f) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + h[0] = f0; + h[1] = f1; + h[2] = f2; + h[3] = f3; + h[4] = f4; + h[5] = f5; + h[6] = f6; + h[7] = f7; + h[8] = f8; + h[9] = f9; +} + +/* From fe_invert.c */ + +static void fe_invert(fe out, const fe z) { + fe t0; + fe t1; + fe t2; + fe t3; + int i; + + fe_sq(t0, z); + fe_sq(t1, t0); + fe_sq(t1, t1); + fe_mul(t1, z, t1); + fe_mul(t0, t0, t1); + fe_sq(t2, t0); + fe_mul(t1, t1, t2); + fe_sq(t2, t1); + for (i = 0; i < 4; ++i) { + fe_sq(t2, t2); + } + fe_mul(t1, t2, t1); + fe_sq(t2, t1); + for (i = 0; i < 9; ++i) { + fe_sq(t2, t2); + } + fe_mul(t2, t2, t1); + fe_sq(t3, t2); + for (i = 0; i < 19; ++i) { + fe_sq(t3, t3); + } + fe_mul(t2, t3, t2); + fe_sq(t2, t2); + for (i = 0; i < 9; ++i) { + fe_sq(t2, t2); + } + fe_mul(t1, t2, t1); + fe_sq(t2, t1); + for (i = 0; i < 49; ++i) { + fe_sq(t2, t2); + } + fe_mul(t2, t2, t1); + fe_sq(t3, t2); + for (i = 0; i < 99; ++i) { + fe_sq(t3, t3); + } + fe_mul(t2, t3, t2); + fe_sq(t2, t2); + for (i = 0; i < 49; ++i) { + fe_sq(t2, t2); + } + fe_mul(t1, t2, t1); + fe_sq(t1, t1); + for (i = 0; i < 4; ++i) { + fe_sq(t1, t1); + } + fe_mul(out, t1, t0); + + return; +} + +/* From fe_isnegative.c */ + +/* +return 1 if f is in {1,3,5,...,q-2} +return 0 if f is in {0,2,4,...,q-1} + +Preconditions: + |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +*/ + +static int fe_isnegative(const fe f) { + unsigned char s[32]; + fe_tobytes(s, f); + return s[0] & 1; +} + +/* From fe_isnonzero.c, modified */ + +static int fe_isnonzero(const fe f) { + unsigned char s[32]; + fe_tobytes(s, f); + return (((int) (s[0] | s[1] | s[2] | s[3] | s[4] | s[5] | s[6] | s[7] | s[8] | + s[9] | s[10] | s[11] | s[12] | s[13] | s[14] | s[15] | s[16] | s[17] | + s[18] | s[19] | s[20] | s[21] | s[22] | s[23] | s[24] | s[25] | s[26] | + s[27] | s[28] | s[29] | s[30] | s[31]) - 1) >> 8) + 1; +} + +/* From fe_mul.c */ + +/* +h = f * g +Can overlap h with f or g. + +Preconditions: + |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + |g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + +Postconditions: + |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. +*/ + +/* +Notes on implementation strategy: + +Using schoolbook multiplication. +Karatsuba would save a little in some cost models. + +Most multiplications by 2 and 19 are 32-bit precomputations; +cheaper than 64-bit postcomputations. + +There is one remaining multiplication by 19 in the carry chain; +one *19 precomputation can be merged into this, +but the resulting data flow is considerably less clean. + +There are 12 carries below. +10 of them are 2-way parallelizable and vectorizable. +Can get away with 11 carries, but then data flow is much deeper. + +With tighter constraints on inputs can squeeze carries into int32. +*/ + +static void fe_mul(fe h, const fe f, const fe g) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int32_t g0 = g[0]; + int32_t g1 = g[1]; + int32_t g2 = g[2]; + int32_t g3 = g[3]; + int32_t g4 = g[4]; + int32_t g5 = g[5]; + int32_t g6 = g[6]; + int32_t g7 = g[7]; + int32_t g8 = g[8]; + int32_t g9 = g[9]; + int32_t g1_19 = 19 * g1; /* 1.959375*2^29 */ + int32_t g2_19 = 19 * g2; /* 1.959375*2^30; still ok */ + int32_t g3_19 = 19 * g3; + int32_t g4_19 = 19 * g4; + int32_t g5_19 = 19 * g5; + int32_t g6_19 = 19 * g6; + int32_t g7_19 = 19 * g7; + int32_t g8_19 = 19 * g8; + int32_t g9_19 = 19 * g9; + int32_t f1_2 = 2 * f1; + int32_t f3_2 = 2 * f3; + int32_t f5_2 = 2 * f5; + int32_t f7_2 = 2 * f7; + int32_t f9_2 = 2 * f9; + int64_t f0g0 = f0 * (int64_t) g0; + int64_t f0g1 = f0 * (int64_t) g1; + int64_t f0g2 = f0 * (int64_t) g2; + int64_t f0g3 = f0 * (int64_t) g3; + int64_t f0g4 = f0 * (int64_t) g4; + int64_t f0g5 = f0 * (int64_t) g5; + int64_t f0g6 = f0 * (int64_t) g6; + int64_t f0g7 = f0 * (int64_t) g7; + int64_t f0g8 = f0 * (int64_t) g8; + int64_t f0g9 = f0 * (int64_t) g9; + int64_t f1g0 = f1 * (int64_t) g0; + int64_t f1g1_2 = f1_2 * (int64_t) g1; + int64_t f1g2 = f1 * (int64_t) g2; + int64_t f1g3_2 = f1_2 * (int64_t) g3; + int64_t f1g4 = f1 * (int64_t) g4; + int64_t f1g5_2 = f1_2 * (int64_t) g5; + int64_t f1g6 = f1 * (int64_t) g6; + int64_t f1g7_2 = f1_2 * (int64_t) g7; + int64_t f1g8 = f1 * (int64_t) g8; + int64_t f1g9_38 = f1_2 * (int64_t) g9_19; + int64_t f2g0 = f2 * (int64_t) g0; + int64_t f2g1 = f2 * (int64_t) g1; + int64_t f2g2 = f2 * (int64_t) g2; + int64_t f2g3 = f2 * (int64_t) g3; + int64_t f2g4 = f2 * (int64_t) g4; + int64_t f2g5 = f2 * (int64_t) g5; + int64_t f2g6 = f2 * (int64_t) g6; + int64_t f2g7 = f2 * (int64_t) g7; + int64_t f2g8_19 = f2 * (int64_t) g8_19; + int64_t f2g9_19 = f2 * (int64_t) g9_19; + int64_t f3g0 = f3 * (int64_t) g0; + int64_t f3g1_2 = f3_2 * (int64_t) g1; + int64_t f3g2 = f3 * (int64_t) g2; + int64_t f3g3_2 = f3_2 * (int64_t) g3; + int64_t f3g4 = f3 * (int64_t) g4; + int64_t f3g5_2 = f3_2 * (int64_t) g5; + int64_t f3g6 = f3 * (int64_t) g6; + int64_t f3g7_38 = f3_2 * (int64_t) g7_19; + int64_t f3g8_19 = f3 * (int64_t) g8_19; + int64_t f3g9_38 = f3_2 * (int64_t) g9_19; + int64_t f4g0 = f4 * (int64_t) g0; + int64_t f4g1 = f4 * (int64_t) g1; + int64_t f4g2 = f4 * (int64_t) g2; + int64_t f4g3 = f4 * (int64_t) g3; + int64_t f4g4 = f4 * (int64_t) g4; + int64_t f4g5 = f4 * (int64_t) g5; + int64_t f4g6_19 = f4 * (int64_t) g6_19; + int64_t f4g7_19 = f4 * (int64_t) g7_19; + int64_t f4g8_19 = f4 * (int64_t) g8_19; + int64_t f4g9_19 = f4 * (int64_t) g9_19; + int64_t f5g0 = f5 * (int64_t) g0; + int64_t f5g1_2 = f5_2 * (int64_t) g1; + int64_t f5g2 = f5 * (int64_t) g2; + int64_t f5g3_2 = f5_2 * (int64_t) g3; + int64_t f5g4 = f5 * (int64_t) g4; + int64_t f5g5_38 = f5_2 * (int64_t) g5_19; + int64_t f5g6_19 = f5 * (int64_t) g6_19; + int64_t f5g7_38 = f5_2 * (int64_t) g7_19; + int64_t f5g8_19 = f5 * (int64_t) g8_19; + int64_t f5g9_38 = f5_2 * (int64_t) g9_19; + int64_t f6g0 = f6 * (int64_t) g0; + int64_t f6g1 = f6 * (int64_t) g1; + int64_t f6g2 = f6 * (int64_t) g2; + int64_t f6g3 = f6 * (int64_t) g3; + int64_t f6g4_19 = f6 * (int64_t) g4_19; + int64_t f6g5_19 = f6 * (int64_t) g5_19; + int64_t f6g6_19 = f6 * (int64_t) g6_19; + int64_t f6g7_19 = f6 * (int64_t) g7_19; + int64_t f6g8_19 = f6 * (int64_t) g8_19; + int64_t f6g9_19 = f6 * (int64_t) g9_19; + int64_t f7g0 = f7 * (int64_t) g0; + int64_t f7g1_2 = f7_2 * (int64_t) g1; + int64_t f7g2 = f7 * (int64_t) g2; + int64_t f7g3_38 = f7_2 * (int64_t) g3_19; + int64_t f7g4_19 = f7 * (int64_t) g4_19; + int64_t f7g5_38 = f7_2 * (int64_t) g5_19; + int64_t f7g6_19 = f7 * (int64_t) g6_19; + int64_t f7g7_38 = f7_2 * (int64_t) g7_19; + int64_t f7g8_19 = f7 * (int64_t) g8_19; + int64_t f7g9_38 = f7_2 * (int64_t) g9_19; + int64_t f8g0 = f8 * (int64_t) g0; + int64_t f8g1 = f8 * (int64_t) g1; + int64_t f8g2_19 = f8 * (int64_t) g2_19; + int64_t f8g3_19 = f8 * (int64_t) g3_19; + int64_t f8g4_19 = f8 * (int64_t) g4_19; + int64_t f8g5_19 = f8 * (int64_t) g5_19; + int64_t f8g6_19 = f8 * (int64_t) g6_19; + int64_t f8g7_19 = f8 * (int64_t) g7_19; + int64_t f8g8_19 = f8 * (int64_t) g8_19; + int64_t f8g9_19 = f8 * (int64_t) g9_19; + int64_t f9g0 = f9 * (int64_t) g0; + int64_t f9g1_38 = f9_2 * (int64_t) g1_19; + int64_t f9g2_19 = f9 * (int64_t) g2_19; + int64_t f9g3_38 = f9_2 * (int64_t) g3_19; + int64_t f9g4_19 = f9 * (int64_t) g4_19; + int64_t f9g5_38 = f9_2 * (int64_t) g5_19; + int64_t f9g6_19 = f9 * (int64_t) g6_19; + int64_t f9g7_38 = f9_2 * (int64_t) g7_19; + int64_t f9g8_19 = f9 * (int64_t) g8_19; + int64_t f9g9_38 = f9_2 * (int64_t) g9_19; + int64_t h0 = f0g0+f1g9_38+f2g8_19+f3g7_38+f4g6_19+f5g5_38+f6g4_19+f7g3_38+f8g2_19+f9g1_38; + int64_t h1 = f0g1+f1g0 +f2g9_19+f3g8_19+f4g7_19+f5g6_19+f6g5_19+f7g4_19+f8g3_19+f9g2_19; + int64_t h2 = f0g2+f1g1_2 +f2g0 +f3g9_38+f4g8_19+f5g7_38+f6g6_19+f7g5_38+f8g4_19+f9g3_38; + int64_t h3 = f0g3+f1g2 +f2g1 +f3g0 +f4g9_19+f5g8_19+f6g7_19+f7g6_19+f8g5_19+f9g4_19; + int64_t h4 = f0g4+f1g3_2 +f2g2 +f3g1_2 +f4g0 +f5g9_38+f6g8_19+f7g7_38+f8g6_19+f9g5_38; + int64_t h5 = f0g5+f1g4 +f2g3 +f3g2 +f4g1 +f5g0 +f6g9_19+f7g8_19+f8g7_19+f9g6_19; + int64_t h6 = f0g6+f1g5_2 +f2g4 +f3g3_2 +f4g2 +f5g1_2 +f6g0 +f7g9_38+f8g8_19+f9g7_38; + int64_t h7 = f0g7+f1g6 +f2g5 +f3g4 +f4g3 +f5g2 +f6g1 +f7g0 +f8g9_19+f9g8_19; + int64_t h8 = f0g8+f1g7_2 +f2g6 +f3g5_2 +f4g4 +f5g3_2 +f6g2 +f7g1_2 +f8g0 +f9g9_38; + int64_t h9 = f0g9+f1g8 +f2g7 +f3g6 +f4g5 +f5g4 +f6g3 +f7g2 +f8g1 +f9g0 ; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + + /* + |h0| <= (1.65*1.65*2^52*(1+19+19+19+19)+1.65*1.65*2^50*(38+38+38+38+38)) + i.e. |h0| <= 1.4*2^60; narrower ranges for h2, h4, h6, h8 + |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19)) + i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9 + */ + + carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + /* |h0| <= 2^25 */ + /* |h4| <= 2^25 */ + /* |h1| <= 1.71*2^59 */ + /* |h5| <= 1.71*2^59 */ + + carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + /* |h1| <= 2^24; from now on fits into int32 */ + /* |h5| <= 2^24; from now on fits into int32 */ + /* |h2| <= 1.41*2^60 */ + /* |h6| <= 1.41*2^60 */ + + carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + /* |h2| <= 2^25; from now on fits into int32 unchanged */ + /* |h6| <= 2^25; from now on fits into int32 unchanged */ + /* |h3| <= 1.71*2^59 */ + /* |h7| <= 1.71*2^59 */ + + carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + /* |h3| <= 2^24; from now on fits into int32 unchanged */ + /* |h7| <= 2^24; from now on fits into int32 unchanged */ + /* |h4| <= 1.72*2^34 */ + /* |h8| <= 1.41*2^60 */ + + carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + /* |h4| <= 2^25; from now on fits into int32 unchanged */ + /* |h8| <= 2^25; from now on fits into int32 unchanged */ + /* |h5| <= 1.01*2^24 */ + /* |h9| <= 1.71*2^59 */ + + carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + /* |h9| <= 2^24; from now on fits into int32 unchanged */ + /* |h0| <= 1.1*2^39 */ + + carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + /* |h0| <= 2^25; from now on fits into int32 unchanged */ + /* |h1| <= 1.01*2^24 */ + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +/* From fe_neg.c */ + +/* +h = -f + +Preconditions: + |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + +Postconditions: + |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +*/ + +static void fe_neg(fe h, const fe f) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int32_t h0 = -f0; + int32_t h1 = -f1; + int32_t h2 = -f2; + int32_t h3 = -f3; + int32_t h4 = -f4; + int32_t h5 = -f5; + int32_t h6 = -f6; + int32_t h7 = -f7; + int32_t h8 = -f8; + int32_t h9 = -f9; + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +/* From fe_sq.c */ + +/* +h = f * f +Can overlap h with f. + +Preconditions: + |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + +Postconditions: + |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. +*/ + +/* +See fe_mul.c for discussion of implementation strategy. +*/ + +static void fe_sq(fe h, const fe f) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int32_t f0_2 = 2 * f0; + int32_t f1_2 = 2 * f1; + int32_t f2_2 = 2 * f2; + int32_t f3_2 = 2 * f3; + int32_t f4_2 = 2 * f4; + int32_t f5_2 = 2 * f5; + int32_t f6_2 = 2 * f6; + int32_t f7_2 = 2 * f7; + int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */ + int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */ + int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */ + int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */ + int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */ + int64_t f0f0 = f0 * (int64_t) f0; + int64_t f0f1_2 = f0_2 * (int64_t) f1; + int64_t f0f2_2 = f0_2 * (int64_t) f2; + int64_t f0f3_2 = f0_2 * (int64_t) f3; + int64_t f0f4_2 = f0_2 * (int64_t) f4; + int64_t f0f5_2 = f0_2 * (int64_t) f5; + int64_t f0f6_2 = f0_2 * (int64_t) f6; + int64_t f0f7_2 = f0_2 * (int64_t) f7; + int64_t f0f8_2 = f0_2 * (int64_t) f8; + int64_t f0f9_2 = f0_2 * (int64_t) f9; + int64_t f1f1_2 = f1_2 * (int64_t) f1; + int64_t f1f2_2 = f1_2 * (int64_t) f2; + int64_t f1f3_4 = f1_2 * (int64_t) f3_2; + int64_t f1f4_2 = f1_2 * (int64_t) f4; + int64_t f1f5_4 = f1_2 * (int64_t) f5_2; + int64_t f1f6_2 = f1_2 * (int64_t) f6; + int64_t f1f7_4 = f1_2 * (int64_t) f7_2; + int64_t f1f8_2 = f1_2 * (int64_t) f8; + int64_t f1f9_76 = f1_2 * (int64_t) f9_38; + int64_t f2f2 = f2 * (int64_t) f2; + int64_t f2f3_2 = f2_2 * (int64_t) f3; + int64_t f2f4_2 = f2_2 * (int64_t) f4; + int64_t f2f5_2 = f2_2 * (int64_t) f5; + int64_t f2f6_2 = f2_2 * (int64_t) f6; + int64_t f2f7_2 = f2_2 * (int64_t) f7; + int64_t f2f8_38 = f2_2 * (int64_t) f8_19; + int64_t f2f9_38 = f2 * (int64_t) f9_38; + int64_t f3f3_2 = f3_2 * (int64_t) f3; + int64_t f3f4_2 = f3_2 * (int64_t) f4; + int64_t f3f5_4 = f3_2 * (int64_t) f5_2; + int64_t f3f6_2 = f3_2 * (int64_t) f6; + int64_t f3f7_76 = f3_2 * (int64_t) f7_38; + int64_t f3f8_38 = f3_2 * (int64_t) f8_19; + int64_t f3f9_76 = f3_2 * (int64_t) f9_38; + int64_t f4f4 = f4 * (int64_t) f4; + int64_t f4f5_2 = f4_2 * (int64_t) f5; + int64_t f4f6_38 = f4_2 * (int64_t) f6_19; + int64_t f4f7_38 = f4 * (int64_t) f7_38; + int64_t f4f8_38 = f4_2 * (int64_t) f8_19; + int64_t f4f9_38 = f4 * (int64_t) f9_38; + int64_t f5f5_38 = f5 * (int64_t) f5_38; + int64_t f5f6_38 = f5_2 * (int64_t) f6_19; + int64_t f5f7_76 = f5_2 * (int64_t) f7_38; + int64_t f5f8_38 = f5_2 * (int64_t) f8_19; + int64_t f5f9_76 = f5_2 * (int64_t) f9_38; + int64_t f6f6_19 = f6 * (int64_t) f6_19; + int64_t f6f7_38 = f6 * (int64_t) f7_38; + int64_t f6f8_38 = f6_2 * (int64_t) f8_19; + int64_t f6f9_38 = f6 * (int64_t) f9_38; + int64_t f7f7_38 = f7 * (int64_t) f7_38; + int64_t f7f8_38 = f7_2 * (int64_t) f8_19; + int64_t f7f9_76 = f7_2 * (int64_t) f9_38; + int64_t f8f8_19 = f8 * (int64_t) f8_19; + int64_t f8f9_38 = f8 * (int64_t) f9_38; + int64_t f9f9_38 = f9 * (int64_t) f9_38; + int64_t h0 = f0f0 +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38; + int64_t h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38; + int64_t h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19; + int64_t h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38; + int64_t h4 = f0f4_2+f1f3_4 +f2f2 +f5f9_76+f6f8_38+f7f7_38; + int64_t h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38; + int64_t h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19; + int64_t h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38; + int64_t h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4 +f9f9_38; + int64_t h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + + carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + + carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + + carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + + carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + + carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + + carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + + carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +/* From fe_sq2.c */ + +/* +h = 2 * f * f +Can overlap h with f. + +Preconditions: + |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + +Postconditions: + |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. +*/ + +/* +See fe_mul.c for discussion of implementation strategy. +*/ + +static void fe_sq2(fe h, const fe f) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int32_t f0_2 = 2 * f0; + int32_t f1_2 = 2 * f1; + int32_t f2_2 = 2 * f2; + int32_t f3_2 = 2 * f3; + int32_t f4_2 = 2 * f4; + int32_t f5_2 = 2 * f5; + int32_t f6_2 = 2 * f6; + int32_t f7_2 = 2 * f7; + int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */ + int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */ + int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */ + int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */ + int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */ + int64_t f0f0 = f0 * (int64_t) f0; + int64_t f0f1_2 = f0_2 * (int64_t) f1; + int64_t f0f2_2 = f0_2 * (int64_t) f2; + int64_t f0f3_2 = f0_2 * (int64_t) f3; + int64_t f0f4_2 = f0_2 * (int64_t) f4; + int64_t f0f5_2 = f0_2 * (int64_t) f5; + int64_t f0f6_2 = f0_2 * (int64_t) f6; + int64_t f0f7_2 = f0_2 * (int64_t) f7; + int64_t f0f8_2 = f0_2 * (int64_t) f8; + int64_t f0f9_2 = f0_2 * (int64_t) f9; + int64_t f1f1_2 = f1_2 * (int64_t) f1; + int64_t f1f2_2 = f1_2 * (int64_t) f2; + int64_t f1f3_4 = f1_2 * (int64_t) f3_2; + int64_t f1f4_2 = f1_2 * (int64_t) f4; + int64_t f1f5_4 = f1_2 * (int64_t) f5_2; + int64_t f1f6_2 = f1_2 * (int64_t) f6; + int64_t f1f7_4 = f1_2 * (int64_t) f7_2; + int64_t f1f8_2 = f1_2 * (int64_t) f8; + int64_t f1f9_76 = f1_2 * (int64_t) f9_38; + int64_t f2f2 = f2 * (int64_t) f2; + int64_t f2f3_2 = f2_2 * (int64_t) f3; + int64_t f2f4_2 = f2_2 * (int64_t) f4; + int64_t f2f5_2 = f2_2 * (int64_t) f5; + int64_t f2f6_2 = f2_2 * (int64_t) f6; + int64_t f2f7_2 = f2_2 * (int64_t) f7; + int64_t f2f8_38 = f2_2 * (int64_t) f8_19; + int64_t f2f9_38 = f2 * (int64_t) f9_38; + int64_t f3f3_2 = f3_2 * (int64_t) f3; + int64_t f3f4_2 = f3_2 * (int64_t) f4; + int64_t f3f5_4 = f3_2 * (int64_t) f5_2; + int64_t f3f6_2 = f3_2 * (int64_t) f6; + int64_t f3f7_76 = f3_2 * (int64_t) f7_38; + int64_t f3f8_38 = f3_2 * (int64_t) f8_19; + int64_t f3f9_76 = f3_2 * (int64_t) f9_38; + int64_t f4f4 = f4 * (int64_t) f4; + int64_t f4f5_2 = f4_2 * (int64_t) f5; + int64_t f4f6_38 = f4_2 * (int64_t) f6_19; + int64_t f4f7_38 = f4 * (int64_t) f7_38; + int64_t f4f8_38 = f4_2 * (int64_t) f8_19; + int64_t f4f9_38 = f4 * (int64_t) f9_38; + int64_t f5f5_38 = f5 * (int64_t) f5_38; + int64_t f5f6_38 = f5_2 * (int64_t) f6_19; + int64_t f5f7_76 = f5_2 * (int64_t) f7_38; + int64_t f5f8_38 = f5_2 * (int64_t) f8_19; + int64_t f5f9_76 = f5_2 * (int64_t) f9_38; + int64_t f6f6_19 = f6 * (int64_t) f6_19; + int64_t f6f7_38 = f6 * (int64_t) f7_38; + int64_t f6f8_38 = f6_2 * (int64_t) f8_19; + int64_t f6f9_38 = f6 * (int64_t) f9_38; + int64_t f7f7_38 = f7 * (int64_t) f7_38; + int64_t f7f8_38 = f7_2 * (int64_t) f8_19; + int64_t f7f9_76 = f7_2 * (int64_t) f9_38; + int64_t f8f8_19 = f8 * (int64_t) f8_19; + int64_t f8f9_38 = f8 * (int64_t) f9_38; + int64_t f9f9_38 = f9 * (int64_t) f9_38; + int64_t h0 = f0f0 +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38; + int64_t h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38; + int64_t h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19; + int64_t h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38; + int64_t h4 = f0f4_2+f1f3_4 +f2f2 +f5f9_76+f6f8_38+f7f7_38; + int64_t h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38; + int64_t h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19; + int64_t h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38; + int64_t h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4 +f9f9_38; + int64_t h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + + h0 += h0; + h1 += h1; + h2 += h2; + h3 += h3; + h4 += h4; + h5 += h5; + h6 += h6; + h7 += h7; + h8 += h8; + h9 += h9; + + carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + + carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + + carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + + carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + + carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + + carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + + carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +/* From fe_sub.c */ + +/* +h = f - g +Can overlap h with f or g. + +Preconditions: + |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + +Postconditions: + |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +*/ + +static void fe_sub(fe h, const fe f, const fe g) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int32_t g0 = g[0]; + int32_t g1 = g[1]; + int32_t g2 = g[2]; + int32_t g3 = g[3]; + int32_t g4 = g[4]; + int32_t g5 = g[5]; + int32_t g6 = g[6]; + int32_t g7 = g[7]; + int32_t g8 = g[8]; + int32_t g9 = g[9]; + int32_t h0 = f0 - g0; + int32_t h1 = f1 - g1; + int32_t h2 = f2 - g2; + int32_t h3 = f3 - g3; + int32_t h4 = f4 - g4; + int32_t h5 = f5 - g5; + int32_t h6 = f6 - g6; + int32_t h7 = f7 - g7; + int32_t h8 = f8 - g8; + int32_t h9 = f9 - g9; + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +/* From fe_tobytes.c */ + +/* +Preconditions: + |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + +Write p=2^255-19; q=floor(h/p). +Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). + +Proof: + Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. + Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4. + + Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). + Then 0> 25; + q = (h0 + q) >> 26; + q = (h1 + q) >> 25; + q = (h2 + q) >> 26; + q = (h3 + q) >> 25; + q = (h4 + q) >> 26; + q = (h5 + q) >> 25; + q = (h6 + q) >> 26; + q = (h7 + q) >> 25; + q = (h8 + q) >> 26; + q = (h9 + q) >> 25; + + /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */ + h0 += 19 * q; + /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */ + + carry0 = h0 >> 26; h1 += carry0; h0 -= carry0 << 26; + carry1 = h1 >> 25; h2 += carry1; h1 -= carry1 << 25; + carry2 = h2 >> 26; h3 += carry2; h2 -= carry2 << 26; + carry3 = h3 >> 25; h4 += carry3; h3 -= carry3 << 25; + carry4 = h4 >> 26; h5 += carry4; h4 -= carry4 << 26; + carry5 = h5 >> 25; h6 += carry5; h5 -= carry5 << 25; + carry6 = h6 >> 26; h7 += carry6; h6 -= carry6 << 26; + carry7 = h7 >> 25; h8 += carry7; h7 -= carry7 << 25; + carry8 = h8 >> 26; h9 += carry8; h8 -= carry8 << 26; + carry9 = h9 >> 25; h9 -= carry9 << 25; + /* h10 = carry9 */ + + /* + Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20. + Have h0+...+2^230 h9 between 0 and 2^255-1; + evidently 2^255 h10-2^255 q = 0. + Goal: Output h0+...+2^230 h9. + */ + + s[0] = h0 >> 0; + s[1] = h0 >> 8; + s[2] = h0 >> 16; + s[3] = (h0 >> 24) | (h1 << 2); + s[4] = h1 >> 6; + s[5] = h1 >> 14; + s[6] = (h1 >> 22) | (h2 << 3); + s[7] = h2 >> 5; + s[8] = h2 >> 13; + s[9] = (h2 >> 21) | (h3 << 5); + s[10] = h3 >> 3; + s[11] = h3 >> 11; + s[12] = (h3 >> 19) | (h4 << 6); + s[13] = h4 >> 2; + s[14] = h4 >> 10; + s[15] = h4 >> 18; + s[16] = h5 >> 0; + s[17] = h5 >> 8; + s[18] = h5 >> 16; + s[19] = (h5 >> 24) | (h6 << 1); + s[20] = h6 >> 7; + s[21] = h6 >> 15; + s[22] = (h6 >> 23) | (h7 << 3); + s[23] = h7 >> 5; + s[24] = h7 >> 13; + s[25] = (h7 >> 21) | (h8 << 4); + s[26] = h8 >> 4; + s[27] = h8 >> 12; + s[28] = (h8 >> 20) | (h9 << 6); + s[29] = h9 >> 2; + s[30] = h9 >> 10; + s[31] = h9 >> 18; +} + +/* From ge_add.c */ + +void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) { + fe t0; + fe_add(r->X, p->Y, p->X); + fe_sub(r->Y, p->Y, p->X); + fe_mul(r->Z, r->X, q->YplusX); + fe_mul(r->Y, r->Y, q->YminusX); + fe_mul(r->T, q->T2d, p->T); + fe_mul(r->X, p->Z, q->Z); + fe_add(t0, r->X, r->X); + fe_sub(r->X, r->Z, r->Y); + fe_add(r->Y, r->Z, r->Y); + fe_add(r->Z, t0, r->T); + fe_sub(r->T, t0, r->T); +} + +/* From ge_double_scalarmult.c, modified */ + +static void slide(signed char *r, const unsigned char *a) { + int i; + int b; + int k; + + for (i = 0; i < 256; ++i) { + r[i] = 1 & (a[i >> 3] >> (i & 7)); + } + + for (i = 0; i < 256; ++i) { + if (r[i]) { + for (b = 1; b <= 6 && i + b < 256; ++b) { + if (r[i + b]) { + if (r[i] + (r[i + b] << b) <= 15) { + r[i] += r[i + b] << b; r[i + b] = 0; + } else if (r[i] - (r[i + b] << b) >= -15) { + r[i] -= r[i + b] << b; + for (k = i + b; k < 256; ++k) { + if (!r[k]) { + r[k] = 1; + break; + } + r[k] = 0; + } + } else + break; + } + } + } + } +} + +void ge_dsm_precomp(ge_dsmp r, const ge_p3 *s) { + ge_p1p1 t; + ge_p3 s2, u; + ge_p3_to_cached(&r[0], s); + ge_p3_dbl(&t, s); ge_p1p1_to_p3(&s2, &t); + ge_add(&t, &s2, &r[0]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[1], &u); + ge_add(&t, &s2, &r[1]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[2], &u); + ge_add(&t, &s2, &r[2]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[3], &u); + ge_add(&t, &s2, &r[3]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[4], &u); + ge_add(&t, &s2, &r[4]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[5], &u); + ge_add(&t, &s2, &r[5]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[6], &u); + ge_add(&t, &s2, &r[6]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[7], &u); +} + +/* +r = a * A + b * B +where a = a[0]+256*a[1]+...+256^31 a[31]. +and b = b[0]+256*b[1]+...+256^31 b[31]. +B is the Ed25519 base point (x,4/5) with x positive. +*/ + +void ge_double_scalarmult_base_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b) { + signed char aslide[256]; + signed char bslide[256]; + ge_dsmp Ai; /* A, 3A, 5A, 7A, 9A, 11A, 13A, 15A */ + ge_p1p1 t; + ge_p3 u; + int i; + + slide(aslide, a); + slide(bslide, b); + ge_dsm_precomp(Ai, A); + + ge_p2_0(r); + + for (i = 255; i >= 0; --i) { + if (aslide[i] || bslide[i]) break; + } + + for (; i >= 0; --i) { + ge_p2_dbl(&t, r); + + if (aslide[i] > 0) { + ge_p1p1_to_p3(&u, &t); + ge_add(&t, &u, &Ai[aslide[i]/2]); + } else if (aslide[i] < 0) { + ge_p1p1_to_p3(&u, &t); + ge_sub(&t, &u, &Ai[(-aslide[i])/2]); + } + + if (bslide[i] > 0) { + ge_p1p1_to_p3(&u, &t); + ge_madd(&t, &u, &ge_Bi[bslide[i]/2]); + } else if (bslide[i] < 0) { + ge_p1p1_to_p3(&u, &t); + ge_msub(&t, &u, &ge_Bi[(-bslide[i])/2]); + } + + ge_p1p1_to_p2(r, &t); + } +} + +/* From ge_frombytes.c, modified */ + +int ge_frombytes_vartime(ge_p3 *h, const unsigned char *s) { + fe u; + fe v; + fe vxx; + fe check; + + /* From fe_frombytes.c */ + + int64_t h0 = load_4(s); + int64_t h1 = load_3(s + 4) << 6; + int64_t h2 = load_3(s + 7) << 5; + int64_t h3 = load_3(s + 10) << 3; + int64_t h4 = load_3(s + 13) << 2; + int64_t h5 = load_4(s + 16); + int64_t h6 = load_3(s + 20) << 7; + int64_t h7 = load_3(s + 23) << 5; + int64_t h8 = load_3(s + 26) << 4; + int64_t h9 = (load_3(s + 29) & 8388607) << 2; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + + /* Validate the number to be canonical */ + if (h9 == 33554428 && h8 == 268435440 && h7 == 536870880 && h6 == 2147483520 && + h5 == 4294967295 && h4 == 67108860 && h3 == 134217720 && h2 == 536870880 && + h1 == 1073741760 && h0 >= 4294967277) { + return -1; + } + + carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + + carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + + h->Y[0] = h0; + h->Y[1] = h1; + h->Y[2] = h2; + h->Y[3] = h3; + h->Y[4] = h4; + h->Y[5] = h5; + h->Y[6] = h6; + h->Y[7] = h7; + h->Y[8] = h8; + h->Y[9] = h9; + + /* End fe_frombytes.c */ + + fe_1(h->Z); + fe_sq(u, h->Y); + fe_mul(v, u, fe_d); + fe_sub(u, u, h->Z); /* u = y^2-1 */ + fe_add(v, v, h->Z); /* v = dy^2+1 */ + + fe_divpowm1(h->X, u, v); /* x = uv^3(uv^7)^((q-5)/8) */ + + fe_sq(vxx, h->X); + fe_mul(vxx, vxx, v); + fe_sub(check, vxx, u); /* vx^2-u */ + if (fe_isnonzero(check)) { + fe_add(check, vxx, u); /* vx^2+u */ + if (fe_isnonzero(check)) { + return -1; + } + fe_mul(h->X, h->X, fe_sqrtm1); + } + + if (fe_isnegative(h->X) != (s[31] >> 7)) { + /* If x = 0, the sign must be positive */ + if (!fe_isnonzero(h->X)) { + return -1; + } + fe_neg(h->X, h->X); + } + + fe_mul(h->T, h->X, h->Y); + return 0; +} + +/* From ge_madd.c */ + +/* +r = p + q +*/ + +static void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) { + fe t0; + fe_add(r->X, p->Y, p->X); + fe_sub(r->Y, p->Y, p->X); + fe_mul(r->Z, r->X, q->yplusx); + fe_mul(r->Y, r->Y, q->yminusx); + fe_mul(r->T, q->xy2d, p->T); + fe_add(t0, p->Z, p->Z); + fe_sub(r->X, r->Z, r->Y); + fe_add(r->Y, r->Z, r->Y); + fe_add(r->Z, t0, r->T); + fe_sub(r->T, t0, r->T); +} + +/* From ge_msub.c */ + +/* +r = p - q +*/ + +static void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) { + fe t0; + fe_add(r->X, p->Y, p->X); + fe_sub(r->Y, p->Y, p->X); + fe_mul(r->Z, r->X, q->yminusx); + fe_mul(r->Y, r->Y, q->yplusx); + fe_mul(r->T, q->xy2d, p->T); + fe_add(t0, p->Z, p->Z); + fe_sub(r->X, r->Z, r->Y); + fe_add(r->Y, r->Z, r->Y); + fe_sub(r->Z, t0, r->T); + fe_add(r->T, t0, r->T); +} + +/* From ge_p1p1_to_p2.c */ + +/* +r = p +*/ + +void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p) { + fe_mul(r->X, p->X, p->T); + fe_mul(r->Y, p->Y, p->Z); + fe_mul(r->Z, p->Z, p->T); +} + +/* From ge_p1p1_to_p3.c */ + +/* +r = p +*/ + +void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p) { + fe_mul(r->X, p->X, p->T); + fe_mul(r->Y, p->Y, p->Z); + fe_mul(r->Z, p->Z, p->T); + fe_mul(r->T, p->X, p->Y); +} + +/* From ge_p2_0.c */ + +static void ge_p2_0(ge_p2 *h) { + fe_0(h->X); + fe_1(h->Y); + fe_1(h->Z); +} + +/* From ge_p2_dbl.c */ + +/* +r = 2 * p +*/ + +void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p) { + fe t0; + fe_sq(r->X, p->X); + fe_sq(r->Z, p->Y); + fe_sq2(r->T, p->Z); + fe_add(r->Y, p->X, p->Y); + fe_sq(t0, r->Y); + fe_add(r->Y, r->Z, r->X); + fe_sub(r->Z, r->Z, r->X); + fe_sub(r->X, t0, r->Y); + fe_sub(r->T, r->T, r->Z); +} + +/* From ge_p3_0.c */ + +static void ge_p3_0(ge_p3 *h) { + fe_0(h->X); + fe_1(h->Y); + fe_1(h->Z); + fe_0(h->T); +} + +/* From ge_p3_dbl.c */ + +/* +r = 2 * p +*/ + +static void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p) { + ge_p2 q; + ge_p3_to_p2(&q, p); + ge_p2_dbl(r, &q); +} + +/* From ge_p3_to_cached.c */ + +/* +r = p +*/ + +void ge_p3_to_cached(ge_cached *r, const ge_p3 *p) { + fe_add(r->YplusX, p->Y, p->X); + fe_sub(r->YminusX, p->Y, p->X); + fe_copy(r->Z, p->Z); + fe_mul(r->T2d, p->T, fe_d2); +} + +/* From ge_p3_to_p2.c */ + +/* +r = p +*/ + +void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p) { + fe_copy(r->X, p->X); + fe_copy(r->Y, p->Y); + fe_copy(r->Z, p->Z); +} + +/* From ge_p3_tobytes.c */ + +void ge_p3_tobytes(unsigned char *s, const ge_p3 *h) { + fe recip; + fe x; + fe y; + + fe_invert(recip, h->Z); + fe_mul(x, h->X, recip); + fe_mul(y, h->Y, recip); + fe_tobytes(s, y); + s[31] ^= fe_isnegative(x) << 7; +} + +/* From ge_precomp_0.c */ + +static void ge_precomp_0(ge_precomp *h) { + fe_1(h->yplusx); + fe_1(h->yminusx); + fe_0(h->xy2d); +} + +/* From ge_scalarmult_base.c */ + +static unsigned char equal(signed char b, signed char c) { + unsigned char ub = b; + unsigned char uc = c; + unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */ + uint32_t y = x; /* 0: yes; 1..255: no */ + y -= 1; /* 4294967295: yes; 0..254: no */ + y >>= 31; /* 1: yes; 0: no */ + return y; +} + +static unsigned char negative(signed char b) { + unsigned long long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */ + x >>= 63; /* 1: yes; 0: no */ + return x; +} + +static void ge_precomp_cmov(ge_precomp *t, const ge_precomp *u, unsigned char b) { + fe_cmov(t->yplusx, u->yplusx, b); + fe_cmov(t->yminusx, u->yminusx, b); + fe_cmov(t->xy2d, u->xy2d, b); +} + +static void select(ge_precomp *t, int pos, signed char b) { + ge_precomp minust; + unsigned char bnegative = negative(b); + unsigned char babs = b - (((-bnegative) & b) << 1); + + ge_precomp_0(t); + ge_precomp_cmov(t, &ge_base[pos][0], equal(babs, 1)); + ge_precomp_cmov(t, &ge_base[pos][1], equal(babs, 2)); + ge_precomp_cmov(t, &ge_base[pos][2], equal(babs, 3)); + ge_precomp_cmov(t, &ge_base[pos][3], equal(babs, 4)); + ge_precomp_cmov(t, &ge_base[pos][4], equal(babs, 5)); + ge_precomp_cmov(t, &ge_base[pos][5], equal(babs, 6)); + ge_precomp_cmov(t, &ge_base[pos][6], equal(babs, 7)); + ge_precomp_cmov(t, &ge_base[pos][7], equal(babs, 8)); + fe_copy(minust.yplusx, t->yminusx); + fe_copy(minust.yminusx, t->yplusx); + fe_neg(minust.xy2d, t->xy2d); + ge_precomp_cmov(t, &minust, bnegative); +} + +/* +h = a * B +where a = a[0]+256*a[1]+...+256^31 a[31] +B is the Ed25519 base point (x,4/5) with x positive. + +Preconditions: + a[31] <= 127 +*/ + +void ge_scalarmult_base(ge_p3 *h, const unsigned char *a) { + signed char e[64]; + signed char carry; + ge_p1p1 r; + ge_p2 s; + ge_precomp t; + int i; + + for (i = 0; i < 32; ++i) { + e[2 * i + 0] = (a[i] >> 0) & 15; + e[2 * i + 1] = (a[i] >> 4) & 15; + } + /* each e[i] is between 0 and 15 */ + /* e[63] is between 0 and 7 */ + + carry = 0; + for (i = 0; i < 63; ++i) { + e[i] += carry; + carry = e[i] + 8; + carry >>= 4; + e[i] -= carry << 4; + } + e[63] += carry; + /* each e[i] is between -8 and 8 */ + + ge_p3_0(h); + for (i = 1; i < 64; i += 2) { + select(&t, i / 2, e[i]); + ge_madd(&r, h, &t); ge_p1p1_to_p3(h, &r); + } + + ge_p3_dbl(&r, h); ge_p1p1_to_p2(&s, &r); + ge_p2_dbl(&r, &s); ge_p1p1_to_p2(&s, &r); + ge_p2_dbl(&r, &s); ge_p1p1_to_p2(&s, &r); + ge_p2_dbl(&r, &s); ge_p1p1_to_p3(h, &r); + + for (i = 0; i < 64; i += 2) { + select(&t, i / 2, e[i]); + ge_madd(&r, h, &t); ge_p1p1_to_p3(h, &r); + } +} + +/* From ge_sub.c */ + +/* +r = p - q +*/ + +static void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) { + fe t0; + fe_add(r->X, p->Y, p->X); + fe_sub(r->Y, p->Y, p->X); + fe_mul(r->Z, r->X, q->YminusX); + fe_mul(r->Y, r->Y, q->YplusX); + fe_mul(r->T, q->T2d, p->T); + fe_mul(r->X, p->Z, q->Z); + fe_add(t0, r->X, r->X); + fe_sub(r->X, r->Z, r->Y); + fe_add(r->Y, r->Z, r->Y); + fe_sub(r->Z, t0, r->T); + fe_add(r->T, t0, r->T); +} + +/* From ge_tobytes.c */ + +void ge_tobytes(unsigned char *s, const ge_p2 *h) { + fe recip; + fe x; + fe y; + + fe_invert(recip, h->Z); + fe_mul(x, h->X, recip); + fe_mul(y, h->Y, recip); + fe_tobytes(s, y); + s[31] ^= fe_isnegative(x) << 7; +} + +/* From sc_reduce.c */ + +/* +Input: + s[0]+256*s[1]+...+256^63*s[63] = s + +Output: + s[0]+256*s[1]+...+256^31*s[31] = s mod l + where l = 2^252 + 27742317777372353535851937790883648493. + Overwrites s in place. +*/ + +void sc_reduce(unsigned char *s) { + int64_t s0 = 2097151 & load_3(s); + int64_t s1 = 2097151 & (load_4(s + 2) >> 5); + int64_t s2 = 2097151 & (load_3(s + 5) >> 2); + int64_t s3 = 2097151 & (load_4(s + 7) >> 7); + int64_t s4 = 2097151 & (load_4(s + 10) >> 4); + int64_t s5 = 2097151 & (load_3(s + 13) >> 1); + int64_t s6 = 2097151 & (load_4(s + 15) >> 6); + int64_t s7 = 2097151 & (load_3(s + 18) >> 3); + int64_t s8 = 2097151 & load_3(s + 21); + int64_t s9 = 2097151 & (load_4(s + 23) >> 5); + int64_t s10 = 2097151 & (load_3(s + 26) >> 2); + int64_t s11 = 2097151 & (load_4(s + 28) >> 7); + int64_t s12 = 2097151 & (load_4(s + 31) >> 4); + int64_t s13 = 2097151 & (load_3(s + 34) >> 1); + int64_t s14 = 2097151 & (load_4(s + 36) >> 6); + int64_t s15 = 2097151 & (load_3(s + 39) >> 3); + int64_t s16 = 2097151 & load_3(s + 42); + int64_t s17 = 2097151 & (load_4(s + 44) >> 5); + int64_t s18 = 2097151 & (load_3(s + 47) >> 2); + int64_t s19 = 2097151 & (load_4(s + 49) >> 7); + int64_t s20 = 2097151 & (load_4(s + 52) >> 4); + int64_t s21 = 2097151 & (load_3(s + 55) >> 1); + int64_t s22 = 2097151 & (load_4(s + 57) >> 6); + int64_t s23 = (load_4(s + 60) >> 3); + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + int64_t carry10; + int64_t carry11; + int64_t carry12; + int64_t carry13; + int64_t carry14; + int64_t carry15; + int64_t carry16; + + s11 += s23 * 666643; + s12 += s23 * 470296; + s13 += s23 * 654183; + s14 -= s23 * 997805; + s15 += s23 * 136657; + s16 -= s23 * 683901; + + s10 += s22 * 666643; + s11 += s22 * 470296; + s12 += s22 * 654183; + s13 -= s22 * 997805; + s14 += s22 * 136657; + s15 -= s22 * 683901; + + s9 += s21 * 666643; + s10 += s21 * 470296; + s11 += s21 * 654183; + s12 -= s21 * 997805; + s13 += s21 * 136657; + s14 -= s21 * 683901; + + s8 += s20 * 666643; + s9 += s20 * 470296; + s10 += s20 * 654183; + s11 -= s20 * 997805; + s12 += s20 * 136657; + s13 -= s20 * 683901; + + s7 += s19 * 666643; + s8 += s19 * 470296; + s9 += s19 * 654183; + s10 -= s19 * 997805; + s11 += s19 * 136657; + s12 -= s19 * 683901; + + s6 += s18 * 666643; + s7 += s18 * 470296; + s8 += s18 * 654183; + s9 -= s18 * 997805; + s10 += s18 * 136657; + s11 -= s18 * 683901; + + carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; + carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; + carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; + carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21; + carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21; + carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21; + + carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; + carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; + carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; + carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21; + carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21; + + s5 += s17 * 666643; + s6 += s17 * 470296; + s7 += s17 * 654183; + s8 -= s17 * 997805; + s9 += s17 * 136657; + s10 -= s17 * 683901; + + s4 += s16 * 666643; + s5 += s16 * 470296; + s6 += s16 * 654183; + s7 -= s16 * 997805; + s8 += s16 * 136657; + s9 -= s16 * 683901; + + s3 += s15 * 666643; + s4 += s15 * 470296; + s5 += s15 * 654183; + s6 -= s15 * 997805; + s7 += s15 * 136657; + s8 -= s15 * 683901; + + s2 += s14 * 666643; + s3 += s14 * 470296; + s4 += s14 * 654183; + s5 -= s14 * 997805; + s6 += s14 * 136657; + s7 -= s14 * 683901; + + s1 += s13 * 666643; + s2 += s13 * 470296; + s3 += s13 * 654183; + s4 -= s13 * 997805; + s5 += s13 * 136657; + s6 -= s13 * 683901; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21; + carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21; + carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21; + carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; + carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; + carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; + + carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21; + carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21; + carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21; + carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; + carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; + carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; + carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; + carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; + carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; + carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; + carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; + carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; + carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; + carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; + carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; + carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; + carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + + carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; + carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; + carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; + carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; + carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; + carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; + carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; + carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; + carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; + carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; + carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; + + s[0] = s0 >> 0; + s[1] = s0 >> 8; + s[2] = (s0 >> 16) | (s1 << 5); + s[3] = s1 >> 3; + s[4] = s1 >> 11; + s[5] = (s1 >> 19) | (s2 << 2); + s[6] = s2 >> 6; + s[7] = (s2 >> 14) | (s3 << 7); + s[8] = s3 >> 1; + s[9] = s3 >> 9; + s[10] = (s3 >> 17) | (s4 << 4); + s[11] = s4 >> 4; + s[12] = s4 >> 12; + s[13] = (s4 >> 20) | (s5 << 1); + s[14] = s5 >> 7; + s[15] = (s5 >> 15) | (s6 << 6); + s[16] = s6 >> 2; + s[17] = s6 >> 10; + s[18] = (s6 >> 18) | (s7 << 3); + s[19] = s7 >> 5; + s[20] = s7 >> 13; + s[21] = s8 >> 0; + s[22] = s8 >> 8; + s[23] = (s8 >> 16) | (s9 << 5); + s[24] = s9 >> 3; + s[25] = s9 >> 11; + s[26] = (s9 >> 19) | (s10 << 2); + s[27] = s10 >> 6; + s[28] = (s10 >> 14) | (s11 << 7); + s[29] = s11 >> 1; + s[30] = s11 >> 9; + s[31] = s11 >> 17; +} + +/* New code */ + +static void fe_divpowm1(fe r, const fe u, const fe v) { + fe v3, uv7, t0, t1, t2; + int i; + + fe_sq(v3, v); + fe_mul(v3, v3, v); /* v3 = v^3 */ + fe_sq(uv7, v3); + fe_mul(uv7, uv7, v); + fe_mul(uv7, uv7, u); /* uv7 = uv^7 */ + + /*fe_pow22523(uv7, uv7);*/ + + /* From fe_pow22523.c */ + + fe_sq(t0, uv7); + fe_sq(t1, t0); + fe_sq(t1, t1); + fe_mul(t1, uv7, t1); + fe_mul(t0, t0, t1); + fe_sq(t0, t0); + fe_mul(t0, t1, t0); + fe_sq(t1, t0); + for (i = 0; i < 4; ++i) { + fe_sq(t1, t1); + } + fe_mul(t0, t1, t0); + fe_sq(t1, t0); + for (i = 0; i < 9; ++i) { + fe_sq(t1, t1); + } + fe_mul(t1, t1, t0); + fe_sq(t2, t1); + for (i = 0; i < 19; ++i) { + fe_sq(t2, t2); + } + fe_mul(t1, t2, t1); + for (i = 0; i < 10; ++i) { + fe_sq(t1, t1); + } + fe_mul(t0, t1, t0); + fe_sq(t1, t0); + for (i = 0; i < 49; ++i) { + fe_sq(t1, t1); + } + fe_mul(t1, t1, t0); + fe_sq(t2, t1); + for (i = 0; i < 99; ++i) { + fe_sq(t2, t2); + } + fe_mul(t1, t2, t1); + for (i = 0; i < 50; ++i) { + fe_sq(t1, t1); + } + fe_mul(t0, t1, t0); + fe_sq(t0, t0); + fe_sq(t0, t0); + fe_mul(t0, t0, uv7); + + /* End fe_pow22523.c */ + /* t0 = (uv^7)^((q-5)/8) */ + fe_mul(t0, t0, v3); + fe_mul(r, t0, u); /* u^(m+1)v^(-(m+1)) */ +} + +static void ge_cached_0(ge_cached *r) { + fe_1(r->YplusX); + fe_1(r->YminusX); + fe_1(r->Z); + fe_0(r->T2d); +} + +static void ge_cached_cmov(ge_cached *t, const ge_cached *u, unsigned char b) { + fe_cmov(t->YplusX, u->YplusX, b); + fe_cmov(t->YminusX, u->YminusX, b); + fe_cmov(t->Z, u->Z, b); + fe_cmov(t->T2d, u->T2d, b); +} + +/* Assumes that a[31] <= 127 */ +void ge_scalarmult(ge_p2 *r, const unsigned char *a, const ge_p3 *A) { + signed char e[64]; + int carry, carry2, i; + ge_cached Ai[8]; /* 1 * A, 2 * A, ..., 8 * A */ + ge_p1p1 t; + ge_p3 u; + + carry = 0; /* 0..1 */ + for (i = 0; i < 31; i++) { + carry += a[i]; /* 0..256 */ + carry2 = (carry + 8) >> 4; /* 0..16 */ + e[2 * i] = carry - (carry2 << 4); /* -8..7 */ + carry = (carry2 + 8) >> 4; /* 0..1 */ + e[2 * i + 1] = carry2 - (carry << 4); /* -8..7 */ + } + carry += a[31]; /* 0..128 */ + carry2 = (carry + 8) >> 4; /* 0..8 */ + e[62] = carry - (carry2 << 4); /* -8..7 */ + e[63] = carry2; /* 0..8 */ + + ge_p3_to_cached(&Ai[0], A); + for (i = 0; i < 7; i++) { + ge_add(&t, A, &Ai[i]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[i + 1], &u); + } + + ge_p2_0(r); + for (i = 63; i >= 0; i--) { + signed char b = e[i]; + unsigned char bnegative = negative(b); + unsigned char babs = b - (((-bnegative) & b) << 1); + ge_cached cur, minuscur; + ge_p2_dbl(&t, r); + ge_p1p1_to_p2(r, &t); + ge_p2_dbl(&t, r); + ge_p1p1_to_p2(r, &t); + ge_p2_dbl(&t, r); + ge_p1p1_to_p2(r, &t); + ge_p2_dbl(&t, r); + ge_p1p1_to_p3(&u, &t); + ge_cached_0(&cur); + ge_cached_cmov(&cur, &Ai[0], equal(babs, 1)); + ge_cached_cmov(&cur, &Ai[1], equal(babs, 2)); + ge_cached_cmov(&cur, &Ai[2], equal(babs, 3)); + ge_cached_cmov(&cur, &Ai[3], equal(babs, 4)); + ge_cached_cmov(&cur, &Ai[4], equal(babs, 5)); + ge_cached_cmov(&cur, &Ai[5], equal(babs, 6)); + ge_cached_cmov(&cur, &Ai[6], equal(babs, 7)); + ge_cached_cmov(&cur, &Ai[7], equal(babs, 8)); + fe_copy(minuscur.YplusX, cur.YminusX); + fe_copy(minuscur.YminusX, cur.YplusX); + fe_copy(minuscur.Z, cur.Z); + fe_neg(minuscur.T2d, cur.T2d); + ge_cached_cmov(&cur, &minuscur, bnegative); + ge_add(&t, &u, &cur); + ge_p1p1_to_p2(r, &t); + } +} + +void ge_double_scalarmult_precomp_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b, const ge_dsmp Bi) { + signed char aslide[256]; + signed char bslide[256]; + ge_dsmp Ai; /* A, 3A, 5A, 7A, 9A, 11A, 13A, 15A */ + ge_p1p1 t; + ge_p3 u; + int i; + + slide(aslide, a); + slide(bslide, b); + ge_dsm_precomp(Ai, A); + + ge_p2_0(r); + + for (i = 255; i >= 0; --i) { + if (aslide[i] || bslide[i]) break; + } + + for (; i >= 0; --i) { + ge_p2_dbl(&t, r); + + if (aslide[i] > 0) { + ge_p1p1_to_p3(&u, &t); + ge_add(&t, &u, &Ai[aslide[i]/2]); + } else if (aslide[i] < 0) { + ge_p1p1_to_p3(&u, &t); + ge_sub(&t, &u, &Ai[(-aslide[i])/2]); + } + + if (bslide[i] > 0) { + ge_p1p1_to_p3(&u, &t); + ge_add(&t, &u, &Bi[bslide[i]/2]); + } else if (bslide[i] < 0) { + ge_p1p1_to_p3(&u, &t); + ge_sub(&t, &u, &Bi[(-bslide[i])/2]); + } + + ge_p1p1_to_p2(r, &t); + } +} + +void ge_mul8(ge_p1p1 *r, const ge_p2 *t) { + ge_p2 u; + ge_p2_dbl(r, t); + ge_p1p1_to_p2(&u, r); + ge_p2_dbl(r, &u); + ge_p1p1_to_p2(&u, r); + ge_p2_dbl(r, &u); +} + +void ge_fromfe_frombytes_vartime(ge_p2 *r, const unsigned char *s) { + fe u, v, w, x, y, z; + unsigned char sign; + + /* From fe_frombytes.c */ + + int64_t h0 = load_4(s); + int64_t h1 = load_3(s + 4) << 6; + int64_t h2 = load_3(s + 7) << 5; + int64_t h3 = load_3(s + 10) << 3; + int64_t h4 = load_3(s + 13) << 2; + int64_t h5 = load_4(s + 16); + int64_t h6 = load_3(s + 20) << 7; + int64_t h7 = load_3(s + 23) << 5; + int64_t h8 = load_3(s + 26) << 4; + int64_t h9 = load_3(s + 29) << 2; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + + carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + + carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + + u[0] = h0; + u[1] = h1; + u[2] = h2; + u[3] = h3; + u[4] = h4; + u[5] = h5; + u[6] = h6; + u[7] = h7; + u[8] = h8; + u[9] = h9; + + /* End fe_frombytes.c */ + + fe_sq2(v, u); /* 2 * u^2 */ + fe_1(w); + fe_add(w, v, w); /* w = 2 * u^2 + 1 */ + fe_sq(x, w); /* w^2 */ + fe_mul(y, fe_ma2, v); /* -2 * A^2 * u^2 */ + fe_add(x, x, y); /* x = w^2 - 2 * A^2 * u^2 */ + fe_divpowm1(r->X, w, x); /* (w / x)^(m + 1) */ + fe_sq(y, r->X); + fe_mul(x, y, x); + fe_sub(y, w, x); + fe_copy(z, fe_ma); + if (fe_isnonzero(y)) { + fe_add(y, w, x); + if (fe_isnonzero(y)) { + goto negative; + } else { + fe_mul(r->X, r->X, fe_fffb1); + } + } else { + fe_mul(r->X, r->X, fe_fffb2); + } + fe_mul(r->X, r->X, u); /* u * sqrt(2 * A * (A + 2) * w / x) */ + fe_mul(z, z, v); /* -2 * A * u^2 */ + sign = 0; + goto setsign; +negative: + fe_mul(x, x, fe_sqrtm1); + fe_sub(y, w, x); + if (fe_isnonzero(y)) { + assert((fe_add(y, w, x), !fe_isnonzero(y))); + fe_mul(r->X, r->X, fe_fffb3); + } else { + fe_mul(r->X, r->X, fe_fffb4); + } + /* r->X = sqrt(A * (A + 2) * w / x) */ + /* z = -A */ + sign = 1; +setsign: + if (fe_isnegative(r->X) != sign) { + assert(fe_isnonzero(r->X)); + fe_neg(r->X, r->X); + } + fe_add(r->Z, z, w); + fe_sub(r->Y, z, w); + fe_mul(r->X, r->X, r->Z); +#if !defined(NDEBUG) + { + fe check_x, check_y, check_iz, check_v; + fe_invert(check_iz, r->Z); + fe_mul(check_x, r->X, check_iz); + fe_mul(check_y, r->Y, check_iz); + fe_sq(check_x, check_x); + fe_sq(check_y, check_y); + fe_mul(check_v, check_x, check_y); + fe_mul(check_v, fe_d, check_v); + fe_add(check_v, check_v, check_x); + fe_sub(check_v, check_v, check_y); + fe_1(check_x); + fe_add(check_v, check_v, check_x); + assert(!fe_isnonzero(check_v)); + } +#endif +} + +void sc_0(unsigned char *s) { + int i; + for (i = 0; i < 32; i++) { + s[i] = 0; + } +} + +void sc_reduce32(unsigned char *s) { + int64_t s0 = 2097151 & load_3(s); + int64_t s1 = 2097151 & (load_4(s + 2) >> 5); + int64_t s2 = 2097151 & (load_3(s + 5) >> 2); + int64_t s3 = 2097151 & (load_4(s + 7) >> 7); + int64_t s4 = 2097151 & (load_4(s + 10) >> 4); + int64_t s5 = 2097151 & (load_3(s + 13) >> 1); + int64_t s6 = 2097151 & (load_4(s + 15) >> 6); + int64_t s7 = 2097151 & (load_3(s + 18) >> 3); + int64_t s8 = 2097151 & load_3(s + 21); + int64_t s9 = 2097151 & (load_4(s + 23) >> 5); + int64_t s10 = 2097151 & (load_3(s + 26) >> 2); + int64_t s11 = (load_4(s + 28) >> 7); + int64_t s12 = 0; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + int64_t carry10; + int64_t carry11; + + carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21; + carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21; + carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21; + carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; + carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; + carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; + + carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21; + carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21; + carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21; + carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; + carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; + carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; + carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; + carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; + carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; + carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; + carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; + carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; + carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; + carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; + carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; + carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; + carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + + carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; + carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; + carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; + carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; + carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; + carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; + carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; + carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; + carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; + carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; + carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; + + s[0] = s0 >> 0; + s[1] = s0 >> 8; + s[2] = (s0 >> 16) | (s1 << 5); + s[3] = s1 >> 3; + s[4] = s1 >> 11; + s[5] = (s1 >> 19) | (s2 << 2); + s[6] = s2 >> 6; + s[7] = (s2 >> 14) | (s3 << 7); + s[8] = s3 >> 1; + s[9] = s3 >> 9; + s[10] = (s3 >> 17) | (s4 << 4); + s[11] = s4 >> 4; + s[12] = s4 >> 12; + s[13] = (s4 >> 20) | (s5 << 1); + s[14] = s5 >> 7; + s[15] = (s5 >> 15) | (s6 << 6); + s[16] = s6 >> 2; + s[17] = s6 >> 10; + s[18] = (s6 >> 18) | (s7 << 3); + s[19] = s7 >> 5; + s[20] = s7 >> 13; + s[21] = s8 >> 0; + s[22] = s8 >> 8; + s[23] = (s8 >> 16) | (s9 << 5); + s[24] = s9 >> 3; + s[25] = s9 >> 11; + s[26] = (s9 >> 19) | (s10 << 2); + s[27] = s10 >> 6; + s[28] = (s10 >> 14) | (s11 << 7); + s[29] = s11 >> 1; + s[30] = s11 >> 9; + s[31] = s11 >> 17; +} + +void sc_add(unsigned char *s, const unsigned char *a, const unsigned char *b) { + int64_t a0 = 2097151 & load_3(a); + int64_t a1 = 2097151 & (load_4(a + 2) >> 5); + int64_t a2 = 2097151 & (load_3(a + 5) >> 2); + int64_t a3 = 2097151 & (load_4(a + 7) >> 7); + int64_t a4 = 2097151 & (load_4(a + 10) >> 4); + int64_t a5 = 2097151 & (load_3(a + 13) >> 1); + int64_t a6 = 2097151 & (load_4(a + 15) >> 6); + int64_t a7 = 2097151 & (load_3(a + 18) >> 3); + int64_t a8 = 2097151 & load_3(a + 21); + int64_t a9 = 2097151 & (load_4(a + 23) >> 5); + int64_t a10 = 2097151 & (load_3(a + 26) >> 2); + int64_t a11 = (load_4(a + 28) >> 7); + int64_t b0 = 2097151 & load_3(b); + int64_t b1 = 2097151 & (load_4(b + 2) >> 5); + int64_t b2 = 2097151 & (load_3(b + 5) >> 2); + int64_t b3 = 2097151 & (load_4(b + 7) >> 7); + int64_t b4 = 2097151 & (load_4(b + 10) >> 4); + int64_t b5 = 2097151 & (load_3(b + 13) >> 1); + int64_t b6 = 2097151 & (load_4(b + 15) >> 6); + int64_t b7 = 2097151 & (load_3(b + 18) >> 3); + int64_t b8 = 2097151 & load_3(b + 21); + int64_t b9 = 2097151 & (load_4(b + 23) >> 5); + int64_t b10 = 2097151 & (load_3(b + 26) >> 2); + int64_t b11 = (load_4(b + 28) >> 7); + int64_t s0 = a0 + b0; + int64_t s1 = a1 + b1; + int64_t s2 = a2 + b2; + int64_t s3 = a3 + b3; + int64_t s4 = a4 + b4; + int64_t s5 = a5 + b5; + int64_t s6 = a6 + b6; + int64_t s7 = a7 + b7; + int64_t s8 = a8 + b8; + int64_t s9 = a9 + b9; + int64_t s10 = a10 + b10; + int64_t s11 = a11 + b11; + int64_t s12 = 0; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + int64_t carry10; + int64_t carry11; + + carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21; + carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21; + carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21; + carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; + carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; + carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; + + carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21; + carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21; + carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21; + carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; + carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; + carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; + carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; + carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; + carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; + carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; + carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; + carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; + carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; + carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; + carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; + carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; + carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + + carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; + carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; + carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; + carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; + carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; + carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; + carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; + carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; + carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; + carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; + carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; + + s[0] = s0 >> 0; + s[1] = s0 >> 8; + s[2] = (s0 >> 16) | (s1 << 5); + s[3] = s1 >> 3; + s[4] = s1 >> 11; + s[5] = (s1 >> 19) | (s2 << 2); + s[6] = s2 >> 6; + s[7] = (s2 >> 14) | (s3 << 7); + s[8] = s3 >> 1; + s[9] = s3 >> 9; + s[10] = (s3 >> 17) | (s4 << 4); + s[11] = s4 >> 4; + s[12] = s4 >> 12; + s[13] = (s4 >> 20) | (s5 << 1); + s[14] = s5 >> 7; + s[15] = (s5 >> 15) | (s6 << 6); + s[16] = s6 >> 2; + s[17] = s6 >> 10; + s[18] = (s6 >> 18) | (s7 << 3); + s[19] = s7 >> 5; + s[20] = s7 >> 13; + s[21] = s8 >> 0; + s[22] = s8 >> 8; + s[23] = (s8 >> 16) | (s9 << 5); + s[24] = s9 >> 3; + s[25] = s9 >> 11; + s[26] = (s9 >> 19) | (s10 << 2); + s[27] = s10 >> 6; + s[28] = (s10 >> 14) | (s11 << 7); + s[29] = s11 >> 1; + s[30] = s11 >> 9; + s[31] = s11 >> 17; +} + +void sc_sub(unsigned char *s, const unsigned char *a, const unsigned char *b) { + int64_t a0 = 2097151 & load_3(a); + int64_t a1 = 2097151 & (load_4(a + 2) >> 5); + int64_t a2 = 2097151 & (load_3(a + 5) >> 2); + int64_t a3 = 2097151 & (load_4(a + 7) >> 7); + int64_t a4 = 2097151 & (load_4(a + 10) >> 4); + int64_t a5 = 2097151 & (load_3(a + 13) >> 1); + int64_t a6 = 2097151 & (load_4(a + 15) >> 6); + int64_t a7 = 2097151 & (load_3(a + 18) >> 3); + int64_t a8 = 2097151 & load_3(a + 21); + int64_t a9 = 2097151 & (load_4(a + 23) >> 5); + int64_t a10 = 2097151 & (load_3(a + 26) >> 2); + int64_t a11 = (load_4(a + 28) >> 7); + int64_t b0 = 2097151 & load_3(b); + int64_t b1 = 2097151 & (load_4(b + 2) >> 5); + int64_t b2 = 2097151 & (load_3(b + 5) >> 2); + int64_t b3 = 2097151 & (load_4(b + 7) >> 7); + int64_t b4 = 2097151 & (load_4(b + 10) >> 4); + int64_t b5 = 2097151 & (load_3(b + 13) >> 1); + int64_t b6 = 2097151 & (load_4(b + 15) >> 6); + int64_t b7 = 2097151 & (load_3(b + 18) >> 3); + int64_t b8 = 2097151 & load_3(b + 21); + int64_t b9 = 2097151 & (load_4(b + 23) >> 5); + int64_t b10 = 2097151 & (load_3(b + 26) >> 2); + int64_t b11 = (load_4(b + 28) >> 7); + int64_t s0 = a0 - b0; + int64_t s1 = a1 - b1; + int64_t s2 = a2 - b2; + int64_t s3 = a3 - b3; + int64_t s4 = a4 - b4; + int64_t s5 = a5 - b5; + int64_t s6 = a6 - b6; + int64_t s7 = a7 - b7; + int64_t s8 = a8 - b8; + int64_t s9 = a9 - b9; + int64_t s10 = a10 - b10; + int64_t s11 = a11 - b11; + int64_t s12 = 0; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + int64_t carry10; + int64_t carry11; + + carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21; + carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21; + carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21; + carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; + carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; + carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; + + carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21; + carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21; + carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21; + carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; + carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; + carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; + carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; + carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; + carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; + carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; + carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; + carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; + carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; + carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; + carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; + carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; + carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + + carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; + carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; + carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; + carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; + carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; + carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; + carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; + carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; + carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; + carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; + carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; + + s[0] = s0 >> 0; + s[1] = s0 >> 8; + s[2] = (s0 >> 16) | (s1 << 5); + s[3] = s1 >> 3; + s[4] = s1 >> 11; + s[5] = (s1 >> 19) | (s2 << 2); + s[6] = s2 >> 6; + s[7] = (s2 >> 14) | (s3 << 7); + s[8] = s3 >> 1; + s[9] = s3 >> 9; + s[10] = (s3 >> 17) | (s4 << 4); + s[11] = s4 >> 4; + s[12] = s4 >> 12; + s[13] = (s4 >> 20) | (s5 << 1); + s[14] = s5 >> 7; + s[15] = (s5 >> 15) | (s6 << 6); + s[16] = s6 >> 2; + s[17] = s6 >> 10; + s[18] = (s6 >> 18) | (s7 << 3); + s[19] = s7 >> 5; + s[20] = s7 >> 13; + s[21] = s8 >> 0; + s[22] = s8 >> 8; + s[23] = (s8 >> 16) | (s9 << 5); + s[24] = s9 >> 3; + s[25] = s9 >> 11; + s[26] = (s9 >> 19) | (s10 << 2); + s[27] = s10 >> 6; + s[28] = (s10 >> 14) | (s11 << 7); + s[29] = s11 >> 1; + s[30] = s11 >> 9; + s[31] = s11 >> 17; +} + +/* +Input: + a[0]+256*a[1]+...+256^31*a[31] = a + b[0]+256*b[1]+...+256^31*b[31] = b + c[0]+256*c[1]+...+256^31*c[31] = c + +Output: + s[0]+256*s[1]+...+256^31*s[31] = (c-ab) mod l + where l = 2^252 + 27742317777372353535851937790883648493. +*/ + +void sc_mulsub(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c) { + int64_t a0 = 2097151 & load_3(a); + int64_t a1 = 2097151 & (load_4(a + 2) >> 5); + int64_t a2 = 2097151 & (load_3(a + 5) >> 2); + int64_t a3 = 2097151 & (load_4(a + 7) >> 7); + int64_t a4 = 2097151 & (load_4(a + 10) >> 4); + int64_t a5 = 2097151 & (load_3(a + 13) >> 1); + int64_t a6 = 2097151 & (load_4(a + 15) >> 6); + int64_t a7 = 2097151 & (load_3(a + 18) >> 3); + int64_t a8 = 2097151 & load_3(a + 21); + int64_t a9 = 2097151 & (load_4(a + 23) >> 5); + int64_t a10 = 2097151 & (load_3(a + 26) >> 2); + int64_t a11 = (load_4(a + 28) >> 7); + int64_t b0 = 2097151 & load_3(b); + int64_t b1 = 2097151 & (load_4(b + 2) >> 5); + int64_t b2 = 2097151 & (load_3(b + 5) >> 2); + int64_t b3 = 2097151 & (load_4(b + 7) >> 7); + int64_t b4 = 2097151 & (load_4(b + 10) >> 4); + int64_t b5 = 2097151 & (load_3(b + 13) >> 1); + int64_t b6 = 2097151 & (load_4(b + 15) >> 6); + int64_t b7 = 2097151 & (load_3(b + 18) >> 3); + int64_t b8 = 2097151 & load_3(b + 21); + int64_t b9 = 2097151 & (load_4(b + 23) >> 5); + int64_t b10 = 2097151 & (load_3(b + 26) >> 2); + int64_t b11 = (load_4(b + 28) >> 7); + int64_t c0 = 2097151 & load_3(c); + int64_t c1 = 2097151 & (load_4(c + 2) >> 5); + int64_t c2 = 2097151 & (load_3(c + 5) >> 2); + int64_t c3 = 2097151 & (load_4(c + 7) >> 7); + int64_t c4 = 2097151 & (load_4(c + 10) >> 4); + int64_t c5 = 2097151 & (load_3(c + 13) >> 1); + int64_t c6 = 2097151 & (load_4(c + 15) >> 6); + int64_t c7 = 2097151 & (load_3(c + 18) >> 3); + int64_t c8 = 2097151 & load_3(c + 21); + int64_t c9 = 2097151 & (load_4(c + 23) >> 5); + int64_t c10 = 2097151 & (load_3(c + 26) >> 2); + int64_t c11 = (load_4(c + 28) >> 7); + int64_t s0; + int64_t s1; + int64_t s2; + int64_t s3; + int64_t s4; + int64_t s5; + int64_t s6; + int64_t s7; + int64_t s8; + int64_t s9; + int64_t s10; + int64_t s11; + int64_t s12; + int64_t s13; + int64_t s14; + int64_t s15; + int64_t s16; + int64_t s17; + int64_t s18; + int64_t s19; + int64_t s20; + int64_t s21; + int64_t s22; + int64_t s23; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + int64_t carry10; + int64_t carry11; + int64_t carry12; + int64_t carry13; + int64_t carry14; + int64_t carry15; + int64_t carry16; + int64_t carry17; + int64_t carry18; + int64_t carry19; + int64_t carry20; + int64_t carry21; + int64_t carry22; + + s0 = c0 - a0*b0; + s1 = c1 - (a0*b1 + a1*b0); + s2 = c2 - (a0*b2 + a1*b1 + a2*b0); + s3 = c3 - (a0*b3 + a1*b2 + a2*b1 + a3*b0); + s4 = c4 - (a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0); + s5 = c5 - (a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0); + s6 = c6 - (a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0); + s7 = c7 - (a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0); + s8 = c8 - (a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0); + s9 = c9 - (a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0); + s10 = c10 - (a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0); + s11 = c11 - (a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0); + s12 = -(a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1); + s13 = -(a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2); + s14 = -(a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3); + s15 = -(a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4); + s16 = -(a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5); + s17 = -(a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6); + s18 = -(a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7); + s19 = -(a8*b11 + a9*b10 + a10*b9 + a11*b8); + s20 = -(a9*b11 + a10*b10 + a11*b9); + s21 = -(a10*b11 + a11*b10); + s22 = -a11*b11; + s23 = 0; + + carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21; + carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21; + carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21; + carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; + carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; + carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; + carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21; + carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21; + carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21; + carry18 = (s18 + (1<<20)) >> 21; s19 += carry18; s18 -= carry18 << 21; + carry20 = (s20 + (1<<20)) >> 21; s21 += carry20; s20 -= carry20 << 21; + carry22 = (s22 + (1<<20)) >> 21; s23 += carry22; s22 -= carry22 << 21; + + carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21; + carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21; + carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21; + carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; + carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; + carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; + carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21; + carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21; + carry17 = (s17 + (1<<20)) >> 21; s18 += carry17; s17 -= carry17 << 21; + carry19 = (s19 + (1<<20)) >> 21; s20 += carry19; s19 -= carry19 << 21; + carry21 = (s21 + (1<<20)) >> 21; s22 += carry21; s21 -= carry21 << 21; + + s11 += s23 * 666643; + s12 += s23 * 470296; + s13 += s23 * 654183; + s14 -= s23 * 997805; + s15 += s23 * 136657; + s16 -= s23 * 683901; + + s10 += s22 * 666643; + s11 += s22 * 470296; + s12 += s22 * 654183; + s13 -= s22 * 997805; + s14 += s22 * 136657; + s15 -= s22 * 683901; + + s9 += s21 * 666643; + s10 += s21 * 470296; + s11 += s21 * 654183; + s12 -= s21 * 997805; + s13 += s21 * 136657; + s14 -= s21 * 683901; + + s8 += s20 * 666643; + s9 += s20 * 470296; + s10 += s20 * 654183; + s11 -= s20 * 997805; + s12 += s20 * 136657; + s13 -= s20 * 683901; + + s7 += s19 * 666643; + s8 += s19 * 470296; + s9 += s19 * 654183; + s10 -= s19 * 997805; + s11 += s19 * 136657; + s12 -= s19 * 683901; + + s6 += s18 * 666643; + s7 += s18 * 470296; + s8 += s18 * 654183; + s9 -= s18 * 997805; + s10 += s18 * 136657; + s11 -= s18 * 683901; + + carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; + carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; + carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; + carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21; + carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21; + carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21; + + carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; + carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; + carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; + carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21; + carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21; + + s5 += s17 * 666643; + s6 += s17 * 470296; + s7 += s17 * 654183; + s8 -= s17 * 997805; + s9 += s17 * 136657; + s10 -= s17 * 683901; + + s4 += s16 * 666643; + s5 += s16 * 470296; + s6 += s16 * 654183; + s7 -= s16 * 997805; + s8 += s16 * 136657; + s9 -= s16 * 683901; + + s3 += s15 * 666643; + s4 += s15 * 470296; + s5 += s15 * 654183; + s6 -= s15 * 997805; + s7 += s15 * 136657; + s8 -= s15 * 683901; + + s2 += s14 * 666643; + s3 += s14 * 470296; + s4 += s14 * 654183; + s5 -= s14 * 997805; + s6 += s14 * 136657; + s7 -= s14 * 683901; + + s1 += s13 * 666643; + s2 += s13 * 470296; + s3 += s13 * 654183; + s4 -= s13 * 997805; + s5 += s13 * 136657; + s6 -= s13 * 683901; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21; + carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21; + carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21; + carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; + carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; + carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; + + carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21; + carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21; + carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21; + carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; + carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; + carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; + carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; + carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; + carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; + carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; + carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; + carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; + carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; + carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; + carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; + carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; + carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + + carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; + carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; + carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; + carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; + carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; + carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; + carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; + carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; + carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; + carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; + carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; + + s[0] = s0 >> 0; + s[1] = s0 >> 8; + s[2] = (s0 >> 16) | (s1 << 5); + s[3] = s1 >> 3; + s[4] = s1 >> 11; + s[5] = (s1 >> 19) | (s2 << 2); + s[6] = s2 >> 6; + s[7] = (s2 >> 14) | (s3 << 7); + s[8] = s3 >> 1; + s[9] = s3 >> 9; + s[10] = (s3 >> 17) | (s4 << 4); + s[11] = s4 >> 4; + s[12] = s4 >> 12; + s[13] = (s4 >> 20) | (s5 << 1); + s[14] = s5 >> 7; + s[15] = (s5 >> 15) | (s6 << 6); + s[16] = s6 >> 2; + s[17] = s6 >> 10; + s[18] = (s6 >> 18) | (s7 << 3); + s[19] = s7 >> 5; + s[20] = s7 >> 13; + s[21] = s8 >> 0; + s[22] = s8 >> 8; + s[23] = (s8 >> 16) | (s9 << 5); + s[24] = s9 >> 3; + s[25] = s9 >> 11; + s[26] = (s9 >> 19) | (s10 << 2); + s[27] = s10 >> 6; + s[28] = (s10 >> 14) | (s11 << 7); + s[29] = s11 >> 1; + s[30] = s11 >> 9; + s[31] = s11 >> 17; +} + +/* Assumes that a != INT64_MIN */ +static int64_t signum(int64_t a) { + return (a >> 63) - ((-a) >> 63); +} + +int sc_check(const unsigned char *s) { + int64_t s0 = load_4(s); + int64_t s1 = load_4(s + 4); + int64_t s2 = load_4(s + 8); + int64_t s3 = load_4(s + 12); + int64_t s4 = load_4(s + 16); + int64_t s5 = load_4(s + 20); + int64_t s6 = load_4(s + 24); + int64_t s7 = load_4(s + 28); + return (signum(1559614444 - s0) + (signum(1477600026 - s1) << 1) + (signum(2734136534 - s2) << 2) + (signum(350157278 - s3) << 3) + (signum(-s4) << 4) + (signum(-s5) << 5) + (signum(-s6) << 6) + (signum(268435456 - s7) << 7)) >> 8; +} + +int sc_isnonzero(const unsigned char *s) { + return (((int) (s[0] | s[1] | s[2] | s[3] | s[4] | s[5] | s[6] | s[7] | s[8] | + s[9] | s[10] | s[11] | s[12] | s[13] | s[14] | s[15] | s[16] | s[17] | + s[18] | s[19] | s[20] | s[21] | s[22] | s[23] | s[24] | s[25] | s[26] | + s[27] | s[28] | s[29] | s[30] | s[31]) - 1) >> 8) + 1; +} diff --git a/src/crypto/crypto-ops.h b/src/crypto/crypto-ops.h new file mode 100644 index 00000000..9d07fc8b --- /dev/null +++ b/src/crypto/crypto-ops.h @@ -0,0 +1,119 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +/* From fe.h */ + +typedef int32_t fe[10]; + +/* From ge.h */ + +typedef struct { + fe X; + fe Y; + fe Z; +} ge_p2; + +typedef struct { + fe X; + fe Y; + fe Z; + fe T; +} ge_p3; + +typedef struct { + fe X; + fe Y; + fe Z; + fe T; +} ge_p1p1; + +typedef struct { + fe yplusx; + fe yminusx; + fe xy2d; +} ge_precomp; + +typedef struct { + fe YplusX; + fe YminusX; + fe Z; + fe T2d; +} ge_cached; + +/* From ge_add.c */ + +void ge_add(ge_p1p1 *, const ge_p3 *, const ge_cached *); + +/* From ge_double_scalarmult.c, modified */ + +typedef ge_cached ge_dsmp[8]; +extern const ge_precomp ge_Bi[8]; +void ge_dsm_precomp(ge_dsmp r, const ge_p3 *s); +void ge_double_scalarmult_base_vartime(ge_p2 *, const unsigned char *, const ge_p3 *, const unsigned char *); + +/* From ge_frombytes.c, modified */ + +extern const fe fe_sqrtm1; +extern const fe fe_d; +int ge_frombytes_vartime(ge_p3 *, const unsigned char *); + +/* From ge_p1p1_to_p2.c */ + +void ge_p1p1_to_p2(ge_p2 *, const ge_p1p1 *); + +/* From ge_p1p1_to_p3.c */ + +void ge_p1p1_to_p3(ge_p3 *, const ge_p1p1 *); + +/* From ge_p2_dbl.c */ + +void ge_p2_dbl(ge_p1p1 *, const ge_p2 *); + +/* From ge_p3_to_cached.c */ + +extern const fe fe_d2; +void ge_p3_to_cached(ge_cached *, const ge_p3 *); + +/* From ge_p3_to_p2.c */ + +void ge_p3_to_p2(ge_p2 *, const ge_p3 *); + +/* From ge_p3_tobytes.c */ + +void ge_p3_tobytes(unsigned char *, const ge_p3 *); + +/* From ge_scalarmult_base.c */ + +extern const ge_precomp ge_base[32][8]; +void ge_scalarmult_base(ge_p3 *, const unsigned char *); + +/* From ge_tobytes.c */ + +void ge_tobytes(unsigned char *, const ge_p2 *); + +/* From sc_reduce.c */ + +void sc_reduce(unsigned char *); + +/* New code */ + +void ge_scalarmult(ge_p2 *, const unsigned char *, const ge_p3 *); +void ge_double_scalarmult_precomp_vartime(ge_p2 *, const unsigned char *, const ge_p3 *, const unsigned char *, const ge_dsmp); +void ge_mul8(ge_p1p1 *, const ge_p2 *); +extern const fe fe_ma2; +extern const fe fe_ma; +extern const fe fe_fffb1; +extern const fe fe_fffb2; +extern const fe fe_fffb3; +extern const fe fe_fffb4; +void ge_fromfe_frombytes_vartime(ge_p2 *, const unsigned char *); +void sc_0(unsigned char *); +void sc_reduce32(unsigned char *); +void sc_add(unsigned char *, const unsigned char *, const unsigned char *); +void sc_sub(unsigned char *, const unsigned char *, const unsigned char *); +void sc_mulsub(unsigned char *, const unsigned char *, const unsigned char *, const unsigned char *); +int sc_check(const unsigned char *); +int sc_isnonzero(const unsigned char *); /* Doesn't normalize */ diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp new file mode 100644 index 00000000..fab703cf --- /dev/null +++ b/src/crypto/crypto.cpp @@ -0,0 +1,422 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common/varint.h" +#include "warnings.h" +#include "crypto.h" +#include "hash.h" + +namespace crypto { + + DISABLE_GCC_AND_CLANG_WARNING(strict-aliasing) + const unsigned char I_[32] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const unsigned char L_[32] = { 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 }; + + const key_image I = *reinterpret_cast(&I_); + const key_image L = *reinterpret_cast(&L_); + + struct random_init_singleton + { + random_init_singleton() + { + grant_random_initialize(); + } + }; + + random_init_singleton init_rand; //place initializer here to avoid grant_random_initialize first call after threads will be possible(local static variables init is not thread-safe) + + using std::abort; + using std::int32_t; + using std::int64_t; + using std::lock_guard; + using std::mutex; + using std::size_t; + using std::uint32_t; + using std::uint64_t; + + extern "C" { +#include "crypto-ops.h" +#include "random.h" + } + + + mutex random_lock; + + static inline unsigned char *operator &(ec_point &point) { + return &reinterpret_cast(point); + } + + static inline const unsigned char *operator &(const ec_point &point) { + return &reinterpret_cast(point); + } + + static inline unsigned char *operator &(ec_scalar &scalar) { + return &reinterpret_cast(scalar); + } + + static inline const unsigned char *operator &(const ec_scalar &scalar) { + return &reinterpret_cast(scalar); + } + + static inline void random_scalar(ec_scalar &res) { + unsigned char tmp[64]; + generate_random_bytes(64, tmp); + sc_reduce(tmp); + memcpy(&res, tmp, 32); + } + + void crypto_ops::keys_from_short(unsigned char* a_part, public_key &pub, secret_key &sec) + { + unsigned char tmp[64] = { 0 }; + static_assert(sizeof tmp >= BRAINWALLET_SHORT_SEED_SIZE, "size mismatch"); + memcpy(tmp, a_part, BRAINWALLET_SHORT_SEED_SIZE); + + cn_fast_hash(tmp, 16, (char*)&tmp[16]); + cn_fast_hash(tmp, 32, (char*)&tmp[32]); + + sc_reduce(tmp); + memcpy(&sec, tmp, 32); + ge_p3 point; + ge_scalarmult_base(&point, &sec); + ge_p3_tobytes(&pub, &point); + } + + void crypto_ops::keys_from_default(unsigned char* a_part, public_key &pub, secret_key &sec) + { + unsigned char tmp[64] = { 0 }; + static_assert(sizeof tmp >= BRAINWALLET_DEFAULT_SEED_SIZE, "size mismatch"); + memcpy(tmp, a_part, BRAINWALLET_DEFAULT_SEED_SIZE); + + cn_fast_hash(tmp, 32, (char*)&tmp[32]); + + sc_reduce(tmp); + memcpy(&sec, tmp, 32); + ge_p3 point; + ge_scalarmult_base(&point, &sec); + ge_p3_tobytes(&pub, &point); + } + + void crypto_ops::generate_brain_keys(public_key &pub, secret_key &sec, std::string& seed) + { + unsigned char tmp[BRAINWALLET_DEFAULT_SEED_SIZE]; + generate_random_bytes(BRAINWALLET_DEFAULT_SEED_SIZE, tmp); + seed.assign((const char*)tmp, BRAINWALLET_DEFAULT_SEED_SIZE); + keys_from_default(tmp, pub, sec); + } + + static inline void hash_to_scalar(const void *data, size_t length, ec_scalar &res) + { + cn_fast_hash(data, length, reinterpret_cast(res)); + sc_reduce32(&res); + } + + void crypto_ops::generate_keys(public_key &pub, secret_key &sec) { + lock_guard lock(random_lock); + ge_p3 point; + random_scalar(sec); + ge_scalarmult_base(&point, &sec); + ge_p3_tobytes(&pub, &point); + } + + void crypto_ops::dependent_key(const secret_key& first, secret_key& second) + { + hash_to_scalar(&first, 32, second); + if (sc_check((unsigned char*)&second) != 0) + throw std::runtime_error("Failed to derive key"); + } + + + bool crypto_ops::check_key(const public_key &key) { + ge_p3 point; + return ge_frombytes_vartime(&point, &key) == 0; + } + + /* + Fix discovered by Monero Lab and suggested by "fluffypony" (bitcointalk.org) + */ + key_image scalarmult_key(const key_image & P, const key_image & a) + { + ge_p3 A = ge_p3(); + ge_p2 R = ge_p2(); + // maybe use assert instead? + ge_frombytes_vartime(&A, reinterpret_cast(&P)); + ge_scalarmult(&R, reinterpret_cast(&a), &A); + key_image a_p = key_image(); + ge_tobytes(reinterpret_cast(&a_p), &R); + return a_p; + } + + bool crypto_ops::validate_key_image(const key_image& ki) + { + if (!(scalarmult_key(ki, L) == I)) + { + return false; + } + return true; + } + + bool crypto_ops::secret_key_to_public_key(const secret_key &sec, public_key &pub) { + ge_p3 point; + if (sc_check(&sec) != 0) { + return false; + } + ge_scalarmult_base(&point, &sec); + ge_p3_tobytes(&pub, &point); + return true; + } + + bool crypto_ops::generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation) { + ge_p3 point; + ge_p2 point2; + ge_p1p1 point3; + assert(sc_check(&key2) == 0); + if (ge_frombytes_vartime(&point, &key1) != 0) { + return false; + } + ge_scalarmult(&point2, &key2, &point); + ge_mul8(&point3, &point2); + ge_p1p1_to_p2(&point2, &point3); + ge_tobytes(&derivation, &point2); + return true; + } + + static void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res) { + struct { + key_derivation derivation; + char output_index[(sizeof(size_t) * 8 + 6) / 7]; + } buf; + char *end = buf.output_index; + buf.derivation = derivation; + tools::write_varint(end, output_index); + assert(end <= buf.output_index + sizeof buf.output_index); + hash_to_scalar(&buf, end - reinterpret_cast(&buf), res); + } + + bool crypto_ops::derive_public_key(const key_derivation &derivation, size_t output_index, + const public_key &base, public_key &derived_key) { + ec_scalar scalar; + ge_p3 point1; + ge_p3 point2; + ge_cached point3; + ge_p1p1 point4; + ge_p2 point5; + if (ge_frombytes_vartime(&point1, &base) != 0) { + return false; + } + derivation_to_scalar(derivation, output_index, scalar); + ge_scalarmult_base(&point2, &scalar); + ge_p3_to_cached(&point3, &point2); + ge_add(&point4, &point1, &point3); + ge_p1p1_to_p2(&point5, &point4); + ge_tobytes(&derived_key, &point5); + return true; + } + + void crypto_ops::derive_secret_key(const key_derivation &derivation, size_t output_index, + const secret_key &base, secret_key &derived_key) { + ec_scalar scalar; + assert(sc_check(&base) == 0); + derivation_to_scalar(derivation, output_index, scalar); + sc_add(&derived_key, &base, &scalar); + } + + struct s_comm { + hash h; + ec_point key; + ec_point comm; + }; + + void crypto_ops::generate_signature(const hash &prefix_hash, const public_key &pub, const secret_key &sec, signature &sig) { + lock_guard lock(random_lock); + ge_p3 tmp3; + ec_scalar k; + s_comm buf; +#if !defined(NDEBUG) + { + ge_p3 t; + public_key t2; + assert(sc_check(&sec) == 0); + ge_scalarmult_base(&t, &sec); + ge_p3_tobytes(&t2, &t); + assert(pub == t2); + } +#endif + buf.h = prefix_hash; + buf.key = pub; + random_scalar(k); + ge_scalarmult_base(&tmp3, &k); + ge_p3_tobytes(&buf.comm, &tmp3); + hash_to_scalar(&buf, sizeof(s_comm), sig.c); + sc_mulsub(&sig.r, &sig.c, &sec, &k); + } + + bool crypto_ops::check_signature(const hash &prefix_hash, const public_key &pub, const signature &sig) { + ge_p2 tmp2; + ge_p3 tmp3; + ec_scalar c; + s_comm buf; + assert(check_key(pub)); + buf.h = prefix_hash; + buf.key = pub; + if (ge_frombytes_vartime(&tmp3, &pub) != 0) { + return false; + } + if (sc_check(&sig.c) != 0 || sc_check(&sig.r) != 0) { + return false; + } + ge_double_scalarmult_base_vartime(&tmp2, &sig.c, &tmp3, &sig.r); + ge_tobytes(&buf.comm, &tmp2); + hash_to_scalar(&buf, sizeof(s_comm), c); + sc_sub(&c, &c, &sig.c); + return sc_isnonzero(&c) == 0; + } + + static void hash_to_ec(const public_key &key, ge_p3 &res) { + hash h; + ge_p2 point; + ge_p1p1 point2; + cn_fast_hash(std::addressof(key), sizeof(public_key), h); + ge_fromfe_frombytes_vartime(&point, reinterpret_cast(&h)); + ge_mul8(&point2, &point); + ge_p1p1_to_p3(&res, &point2); + } + + void crypto_ops::generate_key_image(const public_key &pub, const secret_key &sec, key_image &image) { + ge_p3 point; + ge_p2 point2; + assert(sc_check(&sec) == 0); + hash_to_ec(pub, point); + ge_scalarmult(&point2, &sec, &point); + ge_tobytes(&image, &point2); + } + +PUSH_WARNINGS +DISABLE_VS_WARNINGS(4200) +struct rs_comm_entry +{ + ec_point a, b; +}; + struct rs_comm { + hash h; + struct rs_comm_entry ab[]; + }; +POP_WARNINGS + + static inline size_t rs_comm_size(size_t pubs_count) { + return sizeof(rs_comm)+pubs_count * sizeof(rs_comm_entry); + } + + void crypto_ops::generate_ring_signature(const hash &prefix_hash, const key_image &image, + const public_key *const *pubs, size_t pubs_count, + const secret_key &sec, size_t sec_index, + signature *sig) { + lock_guard lock(random_lock); + size_t i; + ge_p3 image_unp; + ge_dsmp image_pre; + ec_scalar sum, k, h; + rs_comm *const buf = reinterpret_cast(alloca(rs_comm_size(pubs_count))); + assert(sec_index < pubs_count); +#if !defined(NDEBUG) + { + ge_p3 t; + public_key t2; + key_image t3; + assert(sc_check(&sec) == 0); + ge_scalarmult_base(&t, &sec); + ge_p3_tobytes(&t2, &t); + assert(*pubs[sec_index] == t2); + generate_key_image(*pubs[sec_index], sec, t3); + assert(image == t3); + for (i = 0; i < pubs_count; i++) { + assert(check_key(*pubs[i])); + } + } +#endif + if (ge_frombytes_vartime(&image_unp, &image) != 0) { + abort(); + } + ge_dsm_precomp(image_pre, &image_unp); + sc_0(&sum); + buf->h = prefix_hash; + for (i = 0; i < pubs_count; i++) { + ge_p2 tmp2; + ge_p3 tmp3; + if (i == sec_index) { + random_scalar(k); + ge_scalarmult_base(&tmp3, &k); + ge_p3_tobytes(&buf->ab[i].a, &tmp3); + hash_to_ec(*pubs[i], tmp3); + ge_scalarmult(&tmp2, &k, &tmp3); + ge_tobytes(&buf->ab[i].b, &tmp2); + } else { + random_scalar(sig[i].c); + random_scalar(sig[i].r); + if (ge_frombytes_vartime(&tmp3, &*pubs[i]) != 0) { + abort(); + } + ge_double_scalarmult_base_vartime(&tmp2, &sig[i].c, &tmp3, &sig[i].r); + ge_tobytes(&buf->ab[i].a, &tmp2); + hash_to_ec(*pubs[i], tmp3); + ge_double_scalarmult_precomp_vartime(&tmp2, &sig[i].r, &tmp3, &sig[i].c, image_pre); + ge_tobytes(&buf->ab[i].b, &tmp2); + sc_add(&sum, &sum, &sig[i].c); + } + } + hash_to_scalar(buf, rs_comm_size(pubs_count), h); + sc_sub(&sig[sec_index].c, &h, &sum); + sc_mulsub(&sig[sec_index].r, &sig[sec_index].c, &sec, &k); + } + + bool crypto_ops::check_ring_signature(const hash &prefix_hash, const key_image &image, + const public_key *const *pubs, size_t pubs_count, + const signature *sig) { + size_t i; + ge_p3 image_unp; + ge_dsmp image_pre; + ec_scalar sum, h; + rs_comm *const buf = reinterpret_cast(alloca(rs_comm_size(pubs_count))); +#if !defined(NDEBUG) + for (i = 0; i < pubs_count; i++) { + assert(check_key(*pubs[i])); + } +#endif + if (ge_frombytes_vartime(&image_unp, &image) != 0) { + return false; + } + ge_dsm_precomp(image_pre, &image_unp); + sc_0(&sum); + buf->h = prefix_hash; + for (i = 0; i < pubs_count; i++) { + ge_p2 tmp2; + ge_p3 tmp3; + if (sc_check(&sig[i].c) != 0 || sc_check(&sig[i].r) != 0) { + return false; + } + if (ge_frombytes_vartime(&tmp3, &*pubs[i]) != 0) { + return false; + } + ge_double_scalarmult_base_vartime(&tmp2, &sig[i].c, &tmp3, &sig[i].r); + ge_tobytes(&buf->ab[i].a, &tmp2); + hash_to_ec(*pubs[i], tmp3); + ge_double_scalarmult_precomp_vartime(&tmp2, &sig[i].r, &tmp3, &sig[i].c, image_pre); + ge_tobytes(&buf->ab[i].b, &tmp2); + sc_add(&sum, &sum, &sig[i].c); + } + hash_to_scalar(buf, rs_comm_size(pubs_count), h); + sc_sub(&h, &h, &sum); + return sc_isnonzero(&h) == 0; + } +} diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h new file mode 100644 index 00000000..0019c48e --- /dev/null +++ b/src/crypto/crypto.h @@ -0,0 +1,247 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include +#include +#include + +#include "common/pod-class.h" +#include "generic-ops.h" +#include "hash.h" +#include "warnings.h" + + +PUSH_WARNINGS +DISABLE_CLANG_WARNING(unused-private-field) + +#define BRAINWALLET_DEFAULT_SEED_SIZE 32 +#define BRAINWALLET_SHORT_SEED_SIZE 16 + +namespace crypto { + + extern "C" { +#include "random.h" + } + + extern std::mutex random_lock; + +#pragma pack(push, 1) + POD_CLASS ec_point { + char data[32]; + }; + + POD_CLASS ec_scalar { + char data[32]; + }; + + POD_CLASS public_key: ec_point { + friend class crypto_ops; + }; + + POD_CLASS secret_key: ec_scalar { + friend class crypto_ops; + }; + + POD_CLASS key_derivation: ec_point { + friend class crypto_ops; + }; + + POD_CLASS key_image: public ec_point { + friend class crypto_ops; + }; + + POD_CLASS signature { + ec_scalar c, r; + friend class crypto_ops; + }; +#pragma pack(pop) + + static_assert(sizeof(ec_point) == 32 && sizeof(ec_scalar) == 32 && + sizeof(public_key) == 32 && sizeof(secret_key) == 32 && + sizeof(key_derivation) == 32 && sizeof(key_image) == 32 && + sizeof(signature) == 64, "Invalid structure size"); + + class crypto_ops { + crypto_ops(); + crypto_ops(const crypto_ops &); + void operator=(const crypto_ops &); + ~crypto_ops(); + + static void generate_keys(public_key &, secret_key &); + friend void generate_keys(public_key &, secret_key &); + static void generate_brain_keys(public_key &, secret_key &, std::string& seed); + friend void generate_brain_keys(public_key &, secret_key &, std::string& seed); + static void keys_from_short(unsigned char* a_part, public_key &pub, secret_key &sec); + friend void keys_from_short(unsigned char* a_part, public_key &pub, secret_key &sec); + static void keys_from_default(unsigned char* a_part, public_key &pub, secret_key &sec); + friend void keys_from_default(unsigned char* a_part, public_key &pub, secret_key &sec); + static void dependent_key(const secret_key& first, secret_key& second); + friend void dependent_key(const secret_key& first, secret_key& second); + static bool check_key(const public_key &); + friend bool check_key(const public_key &); + static bool secret_key_to_public_key(const secret_key &, public_key &); + friend bool secret_key_to_public_key(const secret_key &, public_key &); + static bool generate_key_derivation(const public_key &, const secret_key &, key_derivation &); + friend bool generate_key_derivation(const public_key &, const secret_key &, key_derivation &); + static bool derive_public_key(const key_derivation &, std::size_t, const public_key &, public_key &); + friend bool derive_public_key(const key_derivation &, std::size_t, const public_key &, public_key &); + static void derive_secret_key(const key_derivation &, std::size_t, const secret_key &, secret_key &); + friend void derive_secret_key(const key_derivation &, std::size_t, const secret_key &, secret_key &); + static void generate_signature(const hash &, const public_key &, const secret_key &, signature &); + friend void generate_signature(const hash &, const public_key &, const secret_key &, signature &); + static bool check_signature(const hash &, const public_key &, const signature &); + friend bool check_signature(const hash &, const public_key &, const signature &); + static void generate_key_image(const public_key &, const secret_key &, key_image &); + friend void generate_key_image(const public_key &, const secret_key &, key_image &); + static void generate_ring_signature(const hash &, const key_image &, + const public_key *const *, std::size_t, const secret_key &, std::size_t, signature *); + friend void generate_ring_signature(const hash &, const key_image &, + const public_key *const *, std::size_t, const secret_key &, std::size_t, signature *); + static bool check_ring_signature(const hash &, const key_image &, + const public_key *const *, std::size_t, const signature *); + friend bool check_ring_signature(const hash &, const key_image &, + const public_key *const *, std::size_t, const signature *); + friend bool validate_key_image(const key_image& ki); + static bool validate_key_image(const key_image& ki); + + }; + + /* Generate a value filled with random bytes. + */ + template + typename std::enable_if::value, T>::type rand() { + typename std::remove_cv::type res; + std::lock_guard lock(random_lock); + generate_random_bytes(sizeof(T), &res); + return res; + } + + /* An adapter, to be used with std::shuffle, etc. + */ + struct uniform_random_bit_generator + { + typedef uint64_t result_type; + static CONSTEXPR uint64_t min() { return 0; } + static CONSTEXPR uint64_t max() { return UINT64_MAX; } + uint64_t operator()() { return rand(); } + }; + + + /* Generate a new key pair + */ + inline void generate_keys(public_key &pub, secret_key &sec) { + crypto_ops::generate_keys(pub, sec); + } + + inline void generate_brain_keys(public_key &pub, secret_key &sec, std::string& seed) { + crypto_ops::generate_brain_keys(pub, sec, seed); + } + + inline void keys_from_short(unsigned char* a_part, public_key &pub, secret_key &sec) + { + crypto_ops::keys_from_short(a_part, pub, sec); + } + + + inline void keys_from_default(unsigned char* a_part, public_key &pub, secret_key &sec) + { + crypto_ops::keys_from_default(a_part, pub, sec); + } + + inline void dependent_key(const secret_key& first, secret_key& second){ + return crypto_ops::dependent_key(first, second); + } + + /* Check a public key. Returns true if it is valid, false otherwise. + */ + inline bool check_key(const public_key &key) { + return crypto_ops::check_key(key); + } + + inline bool validate_key_image(const key_image& ki){ + return crypto_ops::validate_key_image(ki); + } + /* Checks a private key and computes the corresponding public key. + */ + inline bool secret_key_to_public_key(const secret_key &sec, public_key &pub) { + return crypto_ops::secret_key_to_public_key(sec, pub); + } + + /* To generate an ephemeral key used to send money to: + * * The sender generates a new key pair, which becomes the transaction key. The public transaction key is included in "extra" field. + * * Both the sender and the receiver generate key derivation from the transaction key, the receivers' "view" key and the output index. + * * The sender uses key derivation and the receivers' "spend" key to derive an ephemeral public key. + * * The receiver can either derive the public key (to check that the transaction is addressed to him) or the private key (to spend the money). + */ + inline bool generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation) { + return crypto_ops::generate_key_derivation(key1, key2, derivation); + } + inline bool derive_public_key(const key_derivation &derivation, std::size_t output_index, + const public_key &base, public_key &derived_key) { + return crypto_ops::derive_public_key(derivation, output_index, base, derived_key); + } + inline void derive_secret_key(const key_derivation &derivation, std::size_t output_index, + const secret_key &base, secret_key &derived_key) { + crypto_ops::derive_secret_key(derivation, output_index, base, derived_key); + } + + /* Generation and checking of a standard signature. + */ + inline void generate_signature(const hash &prefix_hash, const public_key &pub, const secret_key &sec, signature &sig) { + crypto_ops::generate_signature(prefix_hash, pub, sec, sig); + } + inline bool check_signature(const hash &prefix_hash, const public_key &pub, const signature &sig) { + return crypto_ops::check_signature(prefix_hash, pub, sig); + } + + /* To send money to a key: + * * The sender generates an ephemeral key and includes it in transaction output. + * * To spend the money, the receiver generates a key image from it. + * * Then he selects a bunch of outputs, including the one he spends, and uses them to generate a ring signature. + * To check the signature, it is necessary to collect all the keys that were used to generate it. To detect double spends, it is necessary to check that each key image is used at most once. + */ + inline void generate_key_image(const public_key &pub, const secret_key &sec, key_image &image) { + crypto_ops::generate_key_image(pub, sec, image); + } + inline void generate_ring_signature(const hash &prefix_hash, const key_image &image, + const public_key *const *pubs, std::size_t pubs_count, + const secret_key &sec, std::size_t sec_index, + signature *sig) { + crypto_ops::generate_ring_signature(prefix_hash, image, pubs, pubs_count, sec, sec_index, sig); + } + inline bool check_ring_signature(const hash &prefix_hash, const key_image &image, + const public_key *const *pubs, std::size_t pubs_count, + const signature *sig) { + return crypto_ops::check_ring_signature(prefix_hash, image, pubs, pubs_count, sig); + } + + /* Variants with vector parameters. + */ + inline void generate_ring_signature(const hash &prefix_hash, const key_image &image, + const std::vector &pubs, + const secret_key &sec, std::size_t sec_index, + signature *sig) { + generate_ring_signature(prefix_hash, image, pubs.data(), pubs.size(), sec, sec_index, sig); + } + inline bool check_ring_signature(const hash &prefix_hash, const key_image &image, + const std::vector &pubs, + const signature *sig) { + return check_ring_signature(prefix_hash, image, pubs.data(), pubs.size(), sig); + } + +} + + +POD_MAKE_COMPARABLE(crypto, public_key) +POD_MAKE_COMPARABLE(crypto, secret_key) +POD_MAKE_HASHABLE(crypto, key_image) +POD_MAKE_COMPARABLE(crypto, signature) +POD_MAKE_COMPARABLE(crypto, key_derivation) +POD_MAKE_LESS_OPERATOR(crypto, hash) +POD_MAKE_LESS_OPERATOR(crypto, key_image) diff --git a/src/crypto/generic-ops.h b/src/crypto/generic-ops.h new file mode 100644 index 00000000..4fe9a5ba --- /dev/null +++ b/src/crypto/generic-ops.h @@ -0,0 +1,60 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include +#include + +#define POD_MAKE_COMPARABLE(space, type) \ +namespace space { \ + inline bool operator==(const type &_v1, const type &_v2) { \ + return std::memcmp(&_v1, &_v2, sizeof(type)) == 0; \ + } \ + inline bool operator!=(const type &_v1, const type &_v2) { \ + return std::memcmp(&_v1, &_v2, sizeof(type)) != 0; \ + } \ +} + +#define POD_MAKE_LESS_OPERATOR(space, type) \ +namespace space { \ + inline bool operator<(const type &_v1, const type &_v2) { \ + return std::memcmp(&_v1, &_v2, sizeof(type)) < 0; \ + } \ +} + +#define POD_MAKE_HASHABLE(space, type) \ + POD_MAKE_COMPARABLE(space, type) \ +namespace space { \ + static_assert(sizeof(std::size_t) <= sizeof(type), "Size of " #type " must be at least that of size_t"); \ + inline std::size_t hash_value(const type &_v) { \ + return reinterpret_cast(_v); \ + } \ +} \ +namespace std { \ + template<> \ + struct hash { \ + std::size_t operator()(const space::type &_v) const { \ + return reinterpret_cast(_v); \ + } \ + }; \ +} + +// +// CONSTEXPR +// +#if ( defined(_MSC_VER) && (_MSC_VER < 1800) ) + #error MS compilers prior to v 18.00 (MSVC 2013) are not supported +#endif + +// compilation workaround for MSVC 2013 Update 5 wich does not support constexpr +#if ( defined(_MSC_VER) && (1800 <= _MSC_VER) && (_MSC_VER < 1900) ) + #define CONSTEXPR +#else // all other platforms or MSVC 2015 and later + #define CONSTEXPR constexpr +#endif + diff --git a/src/crypto/hash-ops.h b/src/crypto/hash-ops.h new file mode 100644 index 00000000..b199700e --- /dev/null +++ b/src/crypto/hash-ops.h @@ -0,0 +1,63 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#if !defined(__cplusplus) + +#include +#include +#include +#include + +#include "common/int-util.h" +#include "warnings.h" + +static inline void *padd(void *p, size_t i) { + return (char *) p + i; +} + +static inline const void *cpadd(const void *p, size_t i) { + return (const char *) p + i; +} + +PUSH_WARNINGS +DISABLE_VS_WARNINGS(4267) +static_assert(sizeof(size_t) == 4 || sizeof(size_t) == 8, "size_t must be 4 or 8 bytes long"); +static inline void place_length(uint8_t *buffer, size_t bufsize, size_t length) { + if (sizeof(size_t) == 4) { + *(uint32_t *) padd(buffer, bufsize - 4) = swap32be(length); + } else { + *(uint64_t *) padd(buffer, bufsize - 8) = swap64be(length); + } +} +POP_WARNINGS + +#pragma pack(push, 1) +union hash_state { + uint8_t b[200]; + uint64_t w[25]; +}; +#pragma pack(pop) +static_assert(sizeof(union hash_state) == 200, "Invalid structure size"); + +void hash_permutation(union hash_state *state); +void hash_process(union hash_state *state, const uint8_t *buf, size_t count); + +#endif + + +#define HASH_SIZE 32 +#define HASH_DATA_AREA 136 + + +void cn_fast_hash(const void *data, size_t length, char *hash); +//void cn_slow_hash(const void *data, size_t length, char *hash); + +void hash_extra_blake(const void *data, size_t length, char *hash); +void hash_extra_groestl(const void *data, size_t length, char *hash); +void hash_extra_jh(const void *data, size_t length, char *hash); +void hash_extra_skein(const void *data, size_t length, char *hash); + +void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash); diff --git a/src/crypto/hash.c b/src/crypto/hash.c new file mode 100644 index 00000000..219c060e --- /dev/null +++ b/src/crypto/hash.c @@ -0,0 +1,24 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include + +#include "hash-ops.h" +#include "keccak.h" + +void hash_permutation(union hash_state *state) { + keccakf((uint64_t*)state, 24); +} + +void hash_process(union hash_state *state, const uint8_t *buf, size_t count) { + keccak1600(buf, (int)count, (uint8_t*)state); +} + +void cn_fast_hash(const void *data, size_t length, char *hash) { + union hash_state state; + hash_process(&state, data, length); + memcpy(hash, &state, HASH_SIZE); +} diff --git a/src/crypto/hash.h b/src/crypto/hash.h new file mode 100644 index 00000000..d803b6e4 --- /dev/null +++ b/src/crypto/hash.h @@ -0,0 +1,46 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include + +#include "common/pod-class.h" +#include "generic-ops.h" + +namespace crypto { + + extern "C" { +#include "hash-ops.h" + } + +#pragma pack(push, 1) + POD_CLASS hash { + char data[HASH_SIZE]; + }; +#pragma pack(pop) + + static_assert(sizeof(hash) == HASH_SIZE, "Invalid structure size"); + + /* + Cryptonight hash functions + */ + + inline void cn_fast_hash(const void *data, std::size_t length, hash &hash) { + cn_fast_hash(data, length, reinterpret_cast(&hash)); + } + + inline hash cn_fast_hash(const void *data, std::size_t length) { + hash h; + cn_fast_hash(data, length, reinterpret_cast(&h)); + return h; + } + + inline void tree_hash(const hash *hashes, std::size_t count, hash &root_hash) { + tree_hash(reinterpret_cast(hashes), count, reinterpret_cast(&root_hash)); + } + +} + +POD_MAKE_HASHABLE(crypto, hash) diff --git a/src/crypto/initializer.h b/src/crypto/initializer.h new file mode 100644 index 00000000..8c84621b --- /dev/null +++ b/src/crypto/initializer.h @@ -0,0 +1,32 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#if defined(__GNUC__) +#define INITIALIZER(name) __attribute__((constructor(101))) static void name(void) +#define FINALIZER(name) __attribute__((destructor(101))) static void name(void) +#define REGISTER_FINALIZER(name) ((void) 0) + +#elif defined(_MSC_VER) +#include +#include +// http://stackoverflow.com/questions/1113409/attribute-constructor-equivalent-in-vc +// http://msdn.microsoft.com/en-us/library/bb918180.aspx +#pragma section(".CRT$XCT", read) +#define INITIALIZER(name) \ + static void __cdecl name(void); \ + __declspec(allocate(".CRT$XCT")) void (__cdecl *const _##name)(void) = &name; \ + static void __cdecl name(void) +#define FINALIZER(name) \ + static void __cdecl name(void) +#define REGISTER_FINALIZER(name) \ + do { \ + int _res = atexit(name); \ + assert(_res == 0); \ + } while (0); + +#else +#error Unsupported compiler +#endif diff --git a/src/crypto/keccak.c b/src/crypto/keccak.c new file mode 100644 index 00000000..3ee2a887 --- /dev/null +++ b/src/crypto/keccak.c @@ -0,0 +1,112 @@ +// keccak.c +// 19-Nov-11 Markku-Juhani O. Saarinen +// A baseline Keccak (3rd round) implementation. + +#include "hash-ops.h" +#include "keccak.h" + +const uint64_t keccakf_rndc[24] = +{ + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 +}; + +const int keccakf_rotc[24] = +{ + 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 +}; + +const int keccakf_piln[24] = +{ + 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 +}; + +// update the state with given number of rounds + +void keccakf(uint64_t st[25], int rounds) +{ + int i, j, round; + uint64_t t, bc[5]; + + for (round = 0; round < rounds; round++) { + + // Theta + for (i = 0; i < 5; i++) + bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20]; + + for (i = 0; i < 5; i++) { + t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); + for (j = 0; j < 25; j += 5) + st[j + i] ^= t; + } + + // Rho Pi + t = st[1]; + for (i = 0; i < 24; i++) { + j = keccakf_piln[i]; + bc[0] = st[j]; + st[j] = ROTL64(t, keccakf_rotc[i]); + t = bc[0]; + } + + // Chi + for (j = 0; j < 25; j += 5) { + for (i = 0; i < 5; i++) + bc[i] = st[j + i]; + for (i = 0; i < 5; i++) + st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5]; + } + + // Iota + st[0] ^= keccakf_rndc[round]; + } +} + +// compute a keccak hash (md) of given byte length from "in" +typedef uint64_t state_t[25]; + +int keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen) +{ + state_t st; + uint8_t temp[144]; + int i, rsiz, rsizw; + + rsiz = sizeof(state_t) == mdlen ? HASH_DATA_AREA : 200 - 2 * mdlen; + rsizw = rsiz / 8; + + memset(st, 0, sizeof(st)); + + for ( ; inlen >= rsiz; inlen -= rsiz, in += rsiz) { + for (i = 0; i < rsizw; i++) + st[i] ^= ((uint64_t *) in)[i]; + keccakf(st, KECCAK_ROUNDS); + } + + // last block and padding + memcpy(temp, in, inlen); + temp[inlen++] = 1; + memset(temp + inlen, 0, rsiz - inlen); + temp[rsiz - 1] |= 0x80; + + for (i = 0; i < rsizw; i++) + st[i] ^= ((uint64_t *) temp)[i]; + + keccakf(st, KECCAK_ROUNDS); + + memcpy(md, st, mdlen); + + return 0; +} + +void keccak1600(const uint8_t *in, int inlen, uint8_t *md) +{ + keccak(in, inlen, md, sizeof(state_t)); +} diff --git a/src/crypto/keccak.h b/src/crypto/keccak.h new file mode 100644 index 00000000..4f7f8572 --- /dev/null +++ b/src/crypto/keccak.h @@ -0,0 +1,26 @@ +// keccak.h +// 19-Nov-11 Markku-Juhani O. Saarinen + +#ifndef KECCAK_H +#define KECCAK_H + +#include +#include + +#ifndef KECCAK_ROUNDS +#define KECCAK_ROUNDS 24 +#endif + +#ifndef ROTL64 +#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y)))) +#endif + +// compute a keccak hash (md) of given byte length from "in" +int keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen); + +// update the state +void keccakf(uint64_t st[25], int norounds); + +void keccak1600(const uint8_t *in, int inlen, uint8_t *md); + +#endif diff --git a/src/crypto/random.c b/src/crypto/random.c new file mode 100644 index 00000000..b16d39c9 --- /dev/null +++ b/src/crypto/random.c @@ -0,0 +1,136 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include + +#include "hash-ops.h" +//#include "initializer.h" +#include "random.h" + +static void generate_system_random_bytes(size_t n, void *result); + +#if defined(_WIN32) + +#include +#include + +static void generate_system_random_bytes(size_t n, void *result) { + HCRYPTPROV prov; +#define must_succeed(x) do if (!(x)) assert(0); while (0) + if(!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) + { + int err = GetLastError(); + assert(0); + } + must_succeed(CryptGenRandom(prov, (DWORD)n, result)); + must_succeed(CryptReleaseContext(prov, 0)); +#undef must_succeed +} + +#else + +#include +#include +#include +#include +#include +#include +#include + +static void generate_system_random_bytes(size_t n, void *result) { + int fd; + if ((fd = open("/dev/urandom", O_RDONLY | O_NOCTTY | O_CLOEXEC)) < 0) { + err(EXIT_FAILURE, "open /dev/urandom"); + } + for (;;) { + ssize_t res = read(fd, result, n); + if ((size_t) res == n) { + break; + } + if (res < 0) { + if (errno != EINTR) { + err(EXIT_FAILURE, "read /dev/urandom"); + } + } else if (res == 0) { + errx(EXIT_FAILURE, "read /dev/urandom: end of file"); + } else { + result = padd(result, (size_t) res); + n -= (size_t) res; + } + } + if (close(fd) < 0) { + err(EXIT_FAILURE, "close /dev/urandom"); + } +} + +#endif + +/* static */ union hash_state state; // NOTE: 'static' is commented out here to be able to store/load global random generator state in tests (see also random_helper.h) + +#if !defined(NDEBUG) +static volatile int curstate; /* To catch thread safety problems. */ +#endif +/* +FINALIZER(deinit_random) { +#if !defined(NDEBUG) + assert(curstate == 1); + curstate = 0; +#endif + memset(&state, 0, sizeof(union hash_state)); +} +*/ + +//INITIALIZER(init_random) { +void init_random(void) +{ + generate_system_random_bytes(32, &state); + //REGISTER_FINA\LIZER(deinit_random); +#if !defined(NDEBUG) + assert(curstate == 0); + curstate = 1; +#endif +} + + +void grant_random_initialize(void) +{ + static bool initalized = false; + if(!initalized) + { + init_random(); + initalized = true; + } +} + +void generate_random_bytes(size_t n, void *result) { + grant_random_initialize(); +#if !defined(NDEBUG) + assert(curstate == 1); + curstate = 2; +#endif + if (n == 0) { +#if !defined(NDEBUG) + assert(curstate == 2); + curstate = 1; +#endif + return; + } + for (;;) { + hash_permutation(&state); + if (n <= HASH_DATA_AREA) { + memcpy(result, &state, n); +#if !defined(NDEBUG) + assert(curstate == 2); + curstate = 1; +#endif + return; + } else { + memcpy(result, &state, HASH_DATA_AREA); + result = padd(result, HASH_DATA_AREA); + n -= HASH_DATA_AREA; + } + } +} diff --git a/src/crypto/random.h b/src/crypto/random.h new file mode 100644 index 00000000..587d730c --- /dev/null +++ b/src/crypto/random.h @@ -0,0 +1,10 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include + +void generate_random_bytes(size_t n, void *result); +void grant_random_initialize(void); \ No newline at end of file diff --git a/src/crypto/tree-hash.c b/src/crypto/tree-hash.c new file mode 100644 index 00000000..87423fb8 --- /dev/null +++ b/src/crypto/tree-hash.c @@ -0,0 +1,40 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include + +#include "hash-ops.h" + +void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash) { + assert(count > 0); + if (count == 1) { + memcpy(root_hash, hashes, HASH_SIZE); + } else if (count == 2) { + cn_fast_hash(hashes, 2 * HASH_SIZE, root_hash); + } else { + size_t i, j; + size_t cnt = count - 1; + char (*ints)[HASH_SIZE]; + for (i = 1; i < 8 * sizeof(size_t); i <<= 1) { + cnt |= cnt >> i; + } + cnt &= ~(cnt >> 1); + ints = alloca(cnt * HASH_SIZE); + memcpy(ints, hashes, (2 * cnt - count) * HASH_SIZE); + for (i = 2 * cnt - count, j = 2 * cnt - count; j < cnt; i += 2, ++j) { + cn_fast_hash(hashes[i], 64, ints[j]); + } + assert(i == count); + while (cnt > 2) { + cnt >>= 1; + for (i = 0, j = 0; j < cnt; i += 2, ++j) { + cn_fast_hash(ints[i], 64, ints[j]); + } + } + cn_fast_hash(ints[0], 64, root_hash); + } +} diff --git a/src/crypto/wild_keccak2.cpp b/src/crypto/wild_keccak2.cpp new file mode 100644 index 00000000..ecf4b7ea --- /dev/null +++ b/src/crypto/wild_keccak2.cpp @@ -0,0 +1,76 @@ +// keccak.c +// 19-Nov-11 Markku-Juhani O. Saarinen +// A baseline Keccak (3rd round) implementation. + +// Memory-hard extension of keccak for PoW +// Copyright (c) 2014 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + + +#include "wild_keccak.h" +namespace crypto +{ + + const uint64_t keccakf_rndc[24] = + { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 + }; + + const int keccakf_rotc[24] = + { + 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 + }; + + const int keccakf_piln[24] = + { + 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 + }; + + // update the state with given number of rounds + void regular_f::keccakf2(uint64_t st[25], int round_index) + { + int i, j, round; + uint64_t t, bc[5]; + + + // Theta + for (i = 0; i < 5; i++) + bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20]; + + for (i = 0; i < 5; i++) { + t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); + for (j = 0; j < 25; j += 5) + st[j + i] ^= t; + } + + // Rho Pi + t = st[1]; + for (i = 0; i < 24; i++) { + j = keccakf_piln[i]; + bc[0] = st[j]; + st[j] = ROTL64(t, keccakf_rotc[i]); + t = bc[0]; + } + + // Chi + for (j = 0; j < 25; j += 5) { + for (i = 0; i < 5; i++) + bc[i] = st[j + i]; + for (i = 0; i < 5; i++) + st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5]; + } + + // Iota + st[0] ^= keccakf_rndc[round_index]; + } +} \ No newline at end of file diff --git a/src/crypto/wild_keccak2.h b/src/crypto/wild_keccak2.h new file mode 100644 index 00000000..2e8dbc8d --- /dev/null +++ b/src/crypto/wild_keccak2.h @@ -0,0 +1,149 @@ +// keccak.h +// 19-Nov-11 Markku-Juhani O. Saarinen + +// Copyright (c) 2014 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + + +#pragma once + +#include +#include +#include "crypto.h" + +extern "C" { +#include "crypto/alt/KeccakNISTInterface.h" + } + +#ifndef KECCAK_ROUNDS +#define KECCAK_ROUNDS 24 +#endif + +#ifndef ROTL64 +#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y)))) +#endif + +// compute a keccak hash (md) of given byte length from "in" + +#define KK_MIXIN_SIZE 24 + +namespace crypto +{ + +inline +// void wild_keccak_dbl_opt(const uint8_t *in, size_t inlen, uint8_t *md, size_t mdlen, const UINT64* pscr, UINT64 scr_sz) +// { +// Hash(256, in, inlen*8, md, pscr, scr_sz); +// Hash(256, md, mdlen*8, md, pscr, scr_sz); +// } + + + template + pod_operand_a xor_pod(const pod_operand_a& a, const pod_operand_b& b) + { + static_assert(sizeof(pod_operand_a) == sizeof(pod_operand_b), "invalid xor_h usage: different sizes"); + static_assert(sizeof(pod_operand_a)%8 == 0, "invalid xor_h usage: wrong size"); + + hash r; + for(size_t i = 0; i != 4; i++) + { + ((uint64_t*)&r)[i] = ((const uint64_t*)&a)[i] ^ ((const uint64_t*)&b)[i]; + } + return r; + } + +#define XOR_2(A, B) crypto::xor_pod(A, B) +#define XOR_3(A, B, C) crypto::xor_pod(A, XOR_2(B, C)) +#define XOR_4(A, B, C, D) crypto::xor_pod(A, XOR_3(B, C, D)) +#define XOR_5(A, B, C, D, E) crypto::xor_pod(A, XOR_4(B, C, D, E)) +#define XOR_8(A, B, C, D, F, G, H, I) crypto::xor_pod(XOR_4(A, B, C, D), XOR_4(F, G, H, I)) + + + + + typedef uint64_t state_t_m[25]; + typedef uint64_t mixin_t[KK_MIXIN_SIZE]; + + + template + int wild_keccak2(const uint8_t *in, size_t inlen, uint8_t *md, size_t mdlen, callback_t cb) + { + state_t_m st; + uint8_t temp[144]; + uint64_t rsiz, rsizw; + + rsiz = sizeof(state_t_m) == mdlen ? HASH_DATA_AREA : 200 - 2 * mdlen; + rsizw = rsiz / 8; + memset(&st[0], 0, 25*sizeof(st[0])); + + + for ( ; inlen >= rsiz; inlen -= rsiz, in += rsiz) + { + for (size_t i = 0; i < rsizw; i++) + st[i] ^= ((uint64_t *) in)[i]; + + for(size_t keccak_round = 0; keccak_round != KECCAK_ROUNDS; keccak_round++) + { + if(keccak_round != 0) + {//skip first round + mixin_t mix_in; + cb(st, mix_in); + for (size_t k = 0; k < KK_MIXIN_SIZE; k++) + st[k] ^= mix_in[k]; + } + //print_state(&st[0], "before_permut", ll); + f_traits::keccakf(st, 1); + //print_state(&st[0], "after_permut", ll); + } + } + + // last block and padding + memcpy(temp, in, inlen); + temp[inlen++] = 1; + memset(temp + inlen, 0, rsiz - inlen); + temp[rsiz - 1] |= 0x80; + + for (size_t i = 0; i < rsizw; i++) + st[i] ^= ((uint64_t *) temp)[i]; + + for(size_t keccak_round = 0; keccak_round != KECCAK_ROUNDS; keccak_round++) + { + if(keccak_round != 0) + {//skip first state with + mixin_t mix_in; + cb(st, mix_in); + for (size_t k = 0; k < KK_MIXIN_SIZE; k++) + st[k] ^= mix_in[k]; + } + f_traits::keccakf(st, 1); + } + + memcpy(md, st, mdlen); + + return 0; + } + + + template + int wild_keccak2_dbl(const uint8_t *in, size_t inlen, uint8_t *md, size_t mdlen, crypto::hash* pscratchpad, uint64_t sz) + { + //Satoshi's classic + regular_f::wild_keccak2(in, inlen, md, mdlen, cb); + regular_f::wild_keccak2(md, mdlen, md, mdlen, cb); + return 0; + } + + class regular_f + { + public: + static void keccakf(uint64_t st[25], int rounds); + }; +// +// class mul_f +// { +// public: +// static void keccakf(uint64_t st[25], int rounds); +// }; +} + diff --git a/src/currency_core/account.cpp b/src/currency_core/account.cpp new file mode 100644 index 00000000..8c57de43 --- /dev/null +++ b/src/currency_core/account.cpp @@ -0,0 +1,125 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include + +#include "include_base_utils.h" +#include "account.h" +#include "warnings.h" +#include "crypto/crypto.h" +#include "currency_core/currency_format_utils.h" +#include "common/mnemonic-encoding.h" + +using namespace std; + +DISABLE_VS_WARNINGS(4244 4345) + + + +namespace currency +{ + + + + //----------------------------------------------------------------- + account_base::account_base() + :m_keys{} + ,m_creation_timestamp{} + ,m_seed{} + { + set_null(); + } + //----------------------------------------------------------------- + void account_base::set_null() + { + m_keys = account_keys(); + } + //----------------------------------------------------------------- + void account_base::generate() + { + //generate_keys(m_keys.m_account_address.m_spend_public_key, m_keys.m_spend_secret_key); + generate_brain_keys(m_keys.m_account_address.m_spend_public_key, m_keys.m_spend_secret_key, m_seed); + dependent_key(m_keys.m_spend_secret_key, m_keys.m_view_secret_key); + if (!crypto::secret_key_to_public_key(m_keys.m_view_secret_key, m_keys.m_account_address.m_view_public_key)) + throw std::runtime_error("Failed to create public view key"); + + + m_creation_timestamp = time(NULL); + } + //----------------------------------------------------------------- + const account_keys& account_base::get_keys() const + { + return m_keys; + } + //----------------------------------------------------------------- + std::string account_base::get_restore_data() const + { + return m_seed; + } + //----------------------------------------------------------------- + std::string account_base::get_restore_braindata() const + { + std::string restore_buff = get_restore_data(); + std::vector v; + v.assign((unsigned char*)restore_buff.data(), (unsigned char*)restore_buff.data() + restore_buff.size()); + return tools::mnemonic_encoding::binary2text(v); + } + //----------------------------------------------------------------- + bool account_base::restore_keys(const std::string& restore_data) + { + //CHECK_AND_ASSERT_MES(restore_data.size() == ACCOUNT_RESTORE_DATA_SIZE, false, "wrong restore data size"); + if (restore_data.size() == BRAINWALLET_DEFAULT_SEED_SIZE) + { + crypto::keys_from_default((unsigned char*)restore_data.data(), m_keys.m_account_address.m_spend_public_key, m_keys.m_spend_secret_key); + } + else if(restore_data.size() == BRAINWALLET_SHORT_SEED_SIZE) + { + crypto::keys_from_short((unsigned char*)restore_data.data(), m_keys.m_account_address.m_spend_public_key, m_keys.m_spend_secret_key); + } + else + { + LOG_ERROR("wrong restore data size=" << restore_data.size()); + return false; + } + m_seed = restore_data; + crypto::dependent_key(m_keys.m_spend_secret_key, m_keys.m_view_secret_key); + bool r = crypto::secret_key_to_public_key(m_keys.m_view_secret_key, m_keys.m_account_address.m_view_public_key); + CHECK_AND_ASSERT_MES(r, false, "failed to secret_key_to_public_key for view key"); + set_createtime(0); + return true; + } + //----------------------------------------------------------------- + bool account_base::restore_keys_from_braindata(const std::string& restore_data) + { + + std::vector bin = tools::mnemonic_encoding::text2binary(restore_data); + if (!bin.size()) + return false; + + std::string restore_buff((const char*)&bin[0], bin.size()); + return restore_keys(restore_buff); + } + //----------------------------------------------------------------- + std::string account_base::get_public_address_str() + { + //TODO: change this code into base 58 + return get_account_address_as_str(m_keys.m_account_address); + } + //----------------------------------------------------------------- + std::string transform_addr_to_str(const account_public_address& addr) + { + return get_account_address_as_str(addr); + } + + account_public_address transform_str_to_addr(const std::string& str) + { + account_public_address ad = AUTO_VAL_INIT(ad); + get_account_address_from_str(ad, str); + return ad; + } +} \ No newline at end of file diff --git a/src/currency_core/account.h b/src/currency_core/account.h new file mode 100644 index 00000000..b7569ae6 --- /dev/null +++ b/src/currency_core/account.h @@ -0,0 +1,101 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include "currency_core/currency_basic.h" +#include "crypto/crypto.h" +#include "serialization/keyvalue_serialization.h" + + +#define ACCOUNT_RESTORE_DATA_SIZE BRAINWALLET_DEFAULT_SEED_SIZE + + + + +#define KV_SERIALIZE_ADDRESS_AS_TEXT_N(varialble, val_name) \ + KV_SERIALIZE_CUSTOM_N(varialble, std::string, currency::transform_addr_to_str, currency::transform_str_to_addr, val_name) + +#define KV_SERIALIZE_ADDRESS_AS_TEXT(varialble) KV_SERIALIZE_ADDRESS_AS_TEXT_N(varialble, #varialble) + + +namespace currency +{ + + + + struct account_keys + { + account_public_address m_account_address; + crypto::secret_key m_spend_secret_key; + crypto::secret_key m_view_secret_key; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(m_account_address) + KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_spend_secret_key) + KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_view_secret_key) + END_KV_SERIALIZE_MAP() + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + class account_base + { + public: + account_base(); + void generate(); + const account_keys& get_keys() const; + const account_public_address& get_public_address() const { return m_keys.m_account_address; }; + std::string get_public_address_str(); + std::string get_restore_data() const; + std::string get_restore_braindata() const; + + bool restore_keys(const std::string& restore_data); + bool restore_keys_from_braindata(const std::string& restore_data); + + uint64_t get_createtime() const { return m_creation_timestamp; } + void set_createtime(uint64_t val) { m_creation_timestamp = val; } + + bool load(const std::string& file_path); + bool store(const std::string& file_path); + + template + inline void serialize(t_archive &a, const unsigned int /*ver*/) + { + a & m_keys; + a & m_creation_timestamp; + a & m_seed; + } + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(m_keys) + KV_SERIALIZE(m_creation_timestamp) + KV_SERIALIZE(m_seed) + END_KV_SERIALIZE_MAP() + + private: + void set_null(); + account_keys m_keys; + uint64_t m_creation_timestamp; + std::string m_seed; + }; + + + std::string transform_addr_to_str(const account_public_address& addr); + account_public_address transform_str_to_addr(const std::string& str); + + inline bool operator==(const account_keys& lhs, const account_keys& rhs) + { + return lhs.m_account_address == rhs.m_account_address && + lhs.m_spend_secret_key == rhs.m_spend_secret_key && + lhs.m_view_secret_key == rhs.m_view_secret_key; + } + inline bool operator!=(const account_keys& lhs, const account_keys& rhs) + { + return !operator==(lhs, rhs); + } +} diff --git a/src/currency_core/account_boost_serialization.h b/src/currency_core/account_boost_serialization.h new file mode 100644 index 00000000..f4d3c616 --- /dev/null +++ b/src/currency_core/account_boost_serialization.h @@ -0,0 +1,26 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include "account.h" +#include "currency_core/currency_boost_serialization.h" + +//namespace currency { +namespace boost +{ + namespace serialization + { + template + inline void serialize(Archive &a, currency::account_keys &x, const boost::serialization::version_type ver) + { + a & x.m_account_address; + a & x.m_spend_secret_key; + a & x.m_view_secret_key; + } + + } +} diff --git a/src/currency_core/alias_helper.h b/src/currency_core/alias_helper.h new file mode 100644 index 00000000..cf027ebf --- /dev/null +++ b/src/currency_core/alias_helper.h @@ -0,0 +1,73 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include "currency_core/currency_basic.h" +#include "rpc/core_rpc_server_commands_defs.h" +#include "wallet/core_rpc_proxy.h" +//--------------------------------------------------------------- +namespace tools +{ + template + bool get_transfer_address_cb(const std::string& adr_str, currency::account_public_address& addr, std::string& payment_id, callback_t cb) + { + if (!adr_str.size()) + return false; + + std::string addr_str_local = adr_str; + + if (adr_str[0] == '@') + { + //referred by alias name + if (adr_str.size() < 2) + return false; + std::string pure_alias_name = adr_str.substr(1); + CHECK_AND_ASSERT_MES(currency::validate_alias_name(pure_alias_name), false, "wrong name set in transfer command"); + + + currency::COMMAND_RPC_GET_ALIAS_DETAILS::request req_alias_info = AUTO_VAL_INIT(req_alias_info); + req_alias_info.alias = pure_alias_name; + currency::COMMAND_RPC_GET_ALIAS_DETAILS::response alias_info = AUTO_VAL_INIT(alias_info); + + if (!cb(req_alias_info, alias_info)) + return false; + + if (alias_info.status != CORE_RPC_STATUS_OK || !alias_info.alias_details.address.size()) + return false; + + addr_str_local = alias_info.alias_details.address; + } + + return get_account_address_and_payment_id_from_str(addr, payment_id, addr_str_local); + } + + inline + bool get_transfer_address(const std::string& adr_str, currency::account_public_address& addr, std::string& payment_id, i_core_proxy* proxy) + { + return get_transfer_address_cb(adr_str, addr, payment_id, [&proxy](currency::COMMAND_RPC_GET_ALIAS_DETAILS::request& req_alias_info, + currency::COMMAND_RPC_GET_ALIAS_DETAILS::response& alias_info) + { + return proxy->call_COMMAND_RPC_GET_ALIAS_DETAILS(req_alias_info, alias_info); + }); + } + + /* + inline + bool get_transfer_address(const std::string& adr_str, currency::account_public_address& addr, epee::net_utils::http::http_simple_client& http_client, const std::string& daemon_address) + { + return get_transfer_address_cb(adr_str, addr, [&http_client, &daemon_address](currency::COMMAND_RPC_GET_ALIAS_DETAILS::request& req_alias_info, + currency::COMMAND_RPC_GET_ALIAS_DETAILS::response& alias_info) + { + return epee::net_utils::invoke_http_json_rpc(daemon_address + "/json_rpc", "get_alias_details", req_alias_info, alias_info, http_client); + }); + } + */ +} + + + diff --git a/src/currency_core/basic_api_response_codes.h b/src/currency_core/basic_api_response_codes.h new file mode 100644 index 00000000..bb1cafe5 --- /dev/null +++ b/src/currency_core/basic_api_response_codes.h @@ -0,0 +1,12 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + + + +#define BASIC_RESPONSE_STATUS_OK "OK" +#define BASIC_RESPONSE_STATUS_BUSY "BUSY" +#define BASIC_RESPONSE_STATUS_NOT_FOUND "NOT_FOUND" +#define BASIC_RESPONSE_STATUS_FAILED "FAILED" diff --git a/src/currency_core/bc_attachments_helpers.h b/src/currency_core/bc_attachments_helpers.h new file mode 100644 index 00000000..48f1fac4 --- /dev/null +++ b/src/currency_core/bc_attachments_helpers.h @@ -0,0 +1,128 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include "currency_basic.h" +#include "currency_format_utils.h" +#include "storages/portable_storage_template_helper.h" +#include "zlib_helper.h" + +namespace bc_services +{ + template + bool pack_attachment_as_gzipped_json(const t_attachment_type_t& at, currency::tx_service_attachment& att) + { + //TODO: make json without spaces and line endings here to reduce space + epee::serialization::store_t_to_json(at, att.body); + att.flags |= TX_SERVICE_ATTACHMENT_DEFLATE_BODY; +// if (!epee::zlib_helper::pack(json_buff, att.body)) +// { +// LOG_ERROR("Filed to pack tx_service_attachment as gzipped json, service id: " << att.service_id << " instruction: " << att.instruction << " flags: " << att.flags); +// return false; +// } + return true; + } + + template + bool unpack_attachment_as_gzipped_json(t_attachment_type_t& at, const currency::tx_service_attachment& att) + { + std::string json_buff; + CHECK_AND_ASSERT_MES(att.flags&TX_SERVICE_ATTACHMENT_DEFLATE_BODY, false, "unpack_attachment_as_gzipped_json didn't find TX_SERVICE_ATTACHMENT_DEFLATE_BODY in flags"); + if (!epee::zlib_helper::unpack(att.body, json_buff)) + { + LOG_ERROR("Filed to unpack tx_service_attachment as gzipped json, service id: " << att.service_id << " instruction: " << att.instruction << " flags: " << att.flags); + return false; + } + return epee::serialization::load_t_from_json(at, json_buff); + } + + template + bool unpack_attachment_as_gzipped_bin(t_attachment_type_t& at, const currency::tx_service_attachment& att) + { + std::string bin_buff; + CHECK_AND_ASSERT_MES(att.flags&TX_SERVICE_ATTACHMENT_DEFLATE_BODY, false, "unpack_attachment_as_gzipped_bin didn't find TX_SERVICE_ATTACHMENT_DEFLATE_BODY in flags"); + if (!epee::zlib_helper::unpack(att.body, bin_buff)) + { + LOG_ERROR("Filed to unpack tx_service_attachment as gzipped bin, service id: " << att.service_id << " instruction: " << att.instruction << " flags: " << att.flags); + return false; + } + return t_unserializable_object_from_blob(at, bin_buff); + } + + template + bool pack_attachment_as_gzipped_bin(const t_attachment_type_t& at, currency::tx_service_attachment& att) + { + //TODO: make json without spaces and line endings here to reduce space + ::t_serializable_object_to_blob(at, att.body); + att.flags |= TX_SERVICE_ATTACHMENT_DEFLATE_BODY; +// if (!epee::zlib_helper::pack(bin_buff, att.body)) +// { +// LOG_ERROR("Filed to pack tx_service_attachment as gzipped bin, service id: " << att.service_id << " instruction: " << att.instruction << " flags: " << att.flags); +// return false; +// } + return true; + } + + template + bool get_service_attachment_by_id_unpack(const t_attachment_type_container_t& tx_items, const std::string& id, const std::string& instruction, currency::tx_service_attachment& res) + { + bool r = get_first_service_attachment_by_id(tx_items, id, instruction, res); + if (r && res.flags&TX_SERVICE_ATTACHMENT_DEFLATE_BODY) + { + r = epee::zlib_helper::unpack(res.body); + CHECK_AND_ASSERT_MES(r, false, "Failed to unpack in get_service_attachment_by_id_unpack"); + } + return r; + } + + inline bool get_first_service_attachment_by_id(const currency::transaction& tx, const std::string& id, const std::string& instruction, currency::tx_service_attachment& res) + { + if (get_first_service_attachment_by_id(tx.extra, id, instruction, res)) + return true; + return get_first_service_attachment_by_id(tx.attachment, id, instruction, res); + } + + template + bool get_service_attachment_json_by_id(const t_attachment_type_container_t& tx_items, const std::string& id, const std::string& instruction, t_result_type& res) + { + currency::tx_service_attachment tsa = AUTO_VAL_INIT(tsa); + if (!get_first_service_attachment_by_id(tx_items, id, instruction, tsa)) + return false; + + return epee::serialization::load_t_from_json(res, tsa.body); + } + + template + bool get_service_attachment_gzipped_json_by_id(const t_attachment_type_container_t& tx_items, const std::string& id, const std::string& instruction, t_result_type& res) + { + currency::tx_service_attachment tsa = AUTO_VAL_INIT(tsa); + if (!get_first_service_attachment_by_id(tx_items, id, instruction, tsa)) + return false; + + return unpack_attachment_as_gzipped_json(res, tsa); + } + + template + bool get_service_attachment_gzipped_bin_by_id(const t_attachment_type_container_t& tx_items, const std::string& id, const std::string& instruction, t_result_type& res) + { + + currency::tx_service_attachment tsa = AUTO_VAL_INIT(tsa); + if (!get_first_service_attachment_by_id(tx_items, id, instruction, tsa)) + return false; + + return unpack_attachment_as_gzipped_bin(res, tsa); + } + template + bool get_service_attachment_bin_by_id(const t_attachment_type_container_t& tx_items, const std::string& id, const std::string& instruction, t_result_type& res) + { + + currency::tx_service_attachment tsa = AUTO_VAL_INIT(tsa); + if (!get_first_service_attachment_by_id(tx_items, id, instruction, tsa)) + return false; + + + return ::t_unserializable_object_from_blob(res, tsa.body); + } +} \ No newline at end of file diff --git a/src/currency_core/bc_attachments_helpers_basic.h b/src/currency_core/bc_attachments_helpers_basic.h new file mode 100644 index 00000000..18a8e558 --- /dev/null +++ b/src/currency_core/bc_attachments_helpers_basic.h @@ -0,0 +1,28 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include "currency_basic.h" + +namespace bc_services +{ + template + bool get_first_service_attachment_by_id(const t_attachment_type_container_t& tx_items, const std::string& id, const std::string& instruction, currency::tx_service_attachment& res) + { + for (const auto& item : tx_items) + { + if (item.type() == typeid(currency::tx_service_attachment)) + { + const currency::tx_service_attachment& tsa = boost::get(item); + if (tsa.service_id == id && tsa.instruction == instruction) + { + res = tsa; + return true; + } + } + } + return false; + } +} \ No newline at end of file diff --git a/src/currency_core/bc_attachments_service_manager.cpp b/src/currency_core/bc_attachments_service_manager.cpp new file mode 100644 index 00000000..c56015b6 --- /dev/null +++ b/src/currency_core/bc_attachments_service_manager.cpp @@ -0,0 +1,91 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bc_attachments_service_manager.h" + +namespace currency +{ + bool bc_attachment_services_manager::add_service(i_bc_service* pservice) + { + if (pservice == nullptr) + return false; + + if (m_services.count(pservice->get_id())) + { + LOG_ERROR("Service with id " << pservice->get_id() << "already registered"); + return false; + } + m_services[pservice->get_id()] = pservice; + pservice->set_core_runtime_config(m_core_runtime_config); + return true; + } + i_bc_service* bc_attachment_services_manager::get_service_by_id(const std::string& id) const + { + const auto& it = m_services.find(id); + if (it == m_services.end()) + return nullptr; + + return it->second; + } + void bc_attachment_services_manager::set_event_handler(i_core_event_handler* event_handler) + { + for (auto& s : m_services) + { + s.second->set_event_handler(event_handler); + } + } + void bc_attachment_services_manager::set_core_runtime_config(const core_runtime_config& rtc) + { + m_core_runtime_config = rtc; + for (auto& s : m_services) + { + s.second->set_core_runtime_config(rtc); + } + } + bool bc_attachment_services_manager::init(const std::string& config_folder, const boost::program_options::variables_map& vm) + { + //add service + for (auto& s : m_services) + { + s.second->init(config_folder, vm); + } + return true; + } + bool bc_attachment_services_manager::deinit() + { + //add service + for (auto& s : m_services) + { + s.second->deinit(); + } + m_services.clear(); + return true; + } + bool bc_attachment_services_manager::validate_entry(const tx_service_attachment& a, size_t i, const transaction& tx) + { + auto it = m_services.find(a.service_id); + if (it != m_services.end()) + { + return it->second->validate_entry(a, i, tx); + } + return false; + } + void bc_attachment_services_manager::handle_entry_push(const tx_service_attachment& a, size_t i, const transaction& tx, uint64_t h, const crypto::hash& bl_id, uint64_t timestamp) + { + auto it = m_services.find(a.service_id); + if (it != m_services.end()) + { + it->second->handle_entry_push(a, i, tx, h, bl_id, timestamp); + } + } + void bc_attachment_services_manager::handle_entry_pop(const tx_service_attachment& a, size_t i, const transaction& tx, uint64_t h, uint64_t timestamp) + { + auto it = m_services.find(a.service_id); + if (it != m_services.end()) + { + it->second->handle_entry_pop(a, i, tx, h, timestamp); + } + } +} diff --git a/src/currency_core/bc_attachments_service_manager.h b/src/currency_core/bc_attachments_service_manager.h new file mode 100644 index 00000000..8f95d699 --- /dev/null +++ b/src/currency_core/bc_attachments_service_manager.h @@ -0,0 +1,49 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include +#include "dispatch_core_events.h" +#include "core_runtime_config.h" + +namespace currency +{ + struct i_bc_service + { + virtual std::string get_id() = 0; + virtual bool init(const std::string& config_folder, const boost::program_options::variables_map& vm) = 0; + virtual bool deinit() = 0; + virtual void handle_entry_push(const tx_service_attachment& a, size_t i, const transaction& tx, uint64_t h, const crypto::hash& bl_id, uint64_t timestamp) = 0; + virtual void handle_entry_pop(const tx_service_attachment& a, size_t i, const transaction& tx, uint64_t h, uint64_t timestamp) = 0; + virtual bool validate_entry(const tx_service_attachment& a, size_t i, const transaction& tx) = 0; + virtual void set_event_handler(i_core_event_handler* event_handler) = 0; + virtual void set_core_runtime_config(const core_runtime_config& rtc) = 0; + }; + + class bc_attachment_services_manager + { + public: + bc_attachment_services_manager(i_core_event_handler* pcore_event_handler) : m_pcore_event_handler(pcore_event_handler), m_core_runtime_config(get_default_core_runtime_config()) + {} + + + void set_event_handler(i_core_event_handler* event_handler); + void set_core_runtime_config(const core_runtime_config& rtc); + bool add_service(i_bc_service* psrv); + i_bc_service* get_service_by_id(const std::string& id) const; + bool init(const std::string& config_folder, const boost::program_options::variables_map& vm); + bool deinit(); + bool validate_entry(const tx_service_attachment& a, size_t i, const transaction& tx); + void handle_entry_push(const tx_service_attachment& a, size_t i, const transaction& tx, uint64_t h, const crypto::hash& bl_id, uint64_t timestamp); + void handle_entry_pop(const tx_service_attachment& a, size_t i, const transaction& tx, uint64_t h, uint64_t timestamp); + + private: + std::map m_services; + i_core_event_handler* m_pcore_event_handler; + core_runtime_config m_core_runtime_config; + + }; + +} diff --git a/src/currency_core/bc_escrow_service.h b/src/currency_core/bc_escrow_service.h new file mode 100644 index 00000000..6a84b567 --- /dev/null +++ b/src/currency_core/bc_escrow_service.h @@ -0,0 +1,131 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include "account.h" + +#define BC_ESCROW_SERVICE_ID "E" + +#define BC_ESCROW_SERVICE_INSTRUCTION_PROPOSAL "PROP" +#define BC_ESCROW_SERVICE_INSTRUCTION_RELEASE_TEMPLATES "REL_TEMPL" +#define BC_ESCROW_SERVICE_INSTRUCTION_CANCEL_PROPOSAL "CAN_PROP" +#define BC_ESCROW_SERVICE_INSTRUCTION_RELEASE_NORMAL "REL_N" +#define BC_ESCROW_SERVICE_INSTRUCTION_RELEASE_CANCEL "REL_C" +#define BC_ESCROW_SERVICE_INSTRUCTION_RELEASE_BURN "REL_B" +//#define BC_ESCROW_SERVICE_INSTRUCTION_ACCEPT "ACC" +#define BC_ESCROW_SERVICE_INSTRUCTION_CHANGE "CHANGE" +#define BC_ESCROW_SERVICE_INSTRUCTION_PRIVATE_DETAILS "DETAILS" //this part supposed to be in "extra" part, not attachment +#define BC_ESCROW_SERVICE_INSTRUCTION_PUBLIC_DETAILS "PUB" //this part supposed to be in "extra" part, not attachment + +namespace bc_services +{ + + struct contract_private_details + { + std::string title; + std::string comment; + currency::account_public_address a_addr; // usually buyer + currency::account_public_address b_addr; // usually seller + uint64_t amount_to_pay; + uint64_t amount_a_pledge; + uint64_t amount_b_pledge; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_N(title, "t") + KV_SERIALIZE_N(comment, "c") + KV_SERIALIZE_ADDRESS_AS_TEXT_N(a_addr, "a_addr") + KV_SERIALIZE_ADDRESS_AS_TEXT_N(b_addr, "b_addr") + KV_SERIALIZE_N(amount_to_pay, "to_pay") + KV_SERIALIZE_N(amount_a_pledge, "a_pledge") + KV_SERIALIZE_N(amount_b_pledge, "b_pledge") + END_KV_SERIALIZE_MAP() + }; + + struct contract_public_details + { + currency::account_public_address b_addr; // usually seller + uint64_t amount_to_pay; + crypto::signature address_proof; //multisig_id signed by private spend key + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_ADDRESS_AS_TEXT_N(b_addr, "a_b") + KV_SERIALIZE_N(amount_to_pay, "to_pay") + KV_SERIALIZE_POD_AS_HEX_STRING_N(address_proof, "proof") + END_KV_SERIALIZE_MAP() + }; + + + // BC_ESCROW_SERVICE_INSTRUCTION_PROPOSAL + struct proposal_body + { + currency::transaction tx_template; + crypto::secret_key tx_onetime_secret_key; + BEGIN_SERIALIZE() + FIELD(tx_template) + FIELD(tx_onetime_secret_key) + END_SERIALIZE() + }; + + struct escrow_relese_templates_body + { + currency::transaction tx_normal_template; + currency::transaction tx_burn_template; + + BEGIN_SERIALIZE() + FIELD(tx_normal_template) + FIELD(tx_burn_template) + END_SERIALIZE() + }; + + struct escrow_cancel_templates_body + { + currency::transaction tx_cancel_template; + + BEGIN_SERIALIZE() + FIELD(tx_cancel_template) + END_SERIALIZE() + }; + +} + + +namespace boost +{ + namespace serialization + { + template + void serialize(archive_t & ar, bc_services::contract_private_details& cpd, const unsigned int version) + { + ar & cpd.title; + ar & cpd.comment; + ar & cpd.a_addr; // usually buyer + ar & cpd.b_addr; // usually seller + ar & cpd.amount_to_pay; + ar & cpd.amount_a_pledge; + ar & cpd.amount_b_pledge; + } + + + template + inline void serialize(Archive& a, bc_services::escrow_relese_templates_body& x, const unsigned int ver) + { + a & x.tx_normal_template; + a & x.tx_burn_template; + } + + template + inline void serialize(Archive& a, bc_services::escrow_cancel_templates_body& x, const unsigned int ver) + { + a & x.tx_cancel_template; + } + + template + inline void serialize(Archive& a, bc_services::proposal_body& x, const unsigned int ver) + { + a & x.tx_onetime_secret_key; + a & x.tx_template; + } + } +} \ No newline at end of file diff --git a/src/currency_core/bc_offers_serialization.h b/src/currency_core/bc_offers_serialization.h new file mode 100644 index 00000000..cee1e274 --- /dev/null +++ b/src/currency_core/bc_offers_serialization.h @@ -0,0 +1,83 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include "common/unordered_containers_boost_serialization.h" +#include "common/crypto_boost_serialization.h" +#include "offers_service_basics.h" +#include "offers_services_helpers.h" + +namespace boost +{ + namespace serialization + { + template + inline void serialize(Archive &a, bc_services::offer_details &x, const boost::serialization::version_type ver) + { + a & x.offer_type; + a & x.amount_primary; + a & x.amount_target; + a & x.bonus; + a & x.target; + a & x.primary; + a & x.location_country; + a & x.location_city; + a & x.contacts; + a & x.comment; + a & x.payment_types; + a & x.expiration_time; + a & x.category; + a & x.deal_option; + + } + + + template + inline void serialize(Archive& a, bc_services::offer_details_ex& x, const boost::serialization::version_type ver) + { + a & static_cast(x); + a & x.timestamp; + a & x.tx_hash; + a & x.index_in_tx; + a & x.tx_original_hash; + a & x.fee; + a & x.stopped; + a & x.security; + } + + template + inline void serialize(Archive& a, bc_services::offer_details_ex_with_hash& x, const boost::serialization::version_type ver) + { + a & static_cast(x); + a & x.h; + a & x.nxt_offer; + } + + template + inline void serialize(Archive &a, bc_services::cancel_offer &x, const boost::serialization::version_type ver) + { + a & x.offer_index; + a & x.sig; + a & x.tx_id; + } + + template + inline void serialize(Archive &a, bc_services::update_offer &x, const boost::serialization::version_type ver) + { + a & x.of; + a & x.offer_index; + a & x.sig; + a & x.tx_id; + } + } +} \ No newline at end of file diff --git a/src/currency_core/bc_offers_service.cpp b/src/currency_core/bc_offers_service.cpp new file mode 100644 index 00000000..44e1de3e --- /dev/null +++ b/src/currency_core/bc_offers_service.cpp @@ -0,0 +1,494 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bc_offers_service.h" + +#include "include_base_utils.h" + +#include "zlib_helper.h" +#include "currency_basic.h" +#include "currency_format_utils.h" +#include "storages/portable_storage_template_helper.h" + + +command_line::arg_descriptor arg_market_disable = { "disable-market", "Start GUI with market service disabled", false, true }; + + +namespace bc_services +{ + + bc_offers_service::bc_offers_service(currency::i_core_event_handler* pcore_event_handler) + : m_pcore_event_handler(pcore_event_handler) + , m_last_trimed_height(0) + , m_core_runtime_config(currency::get_default_core_runtime_config()) + , m_last_seen_block_id(currency::null_hash) + , m_deinitialized(false) + , m_disabled(false) + + {} + //------------------------------------------------------------------ + bc_offers_service::~bc_offers_service() + { + if (!m_deinitialized) + deinit(); + } + //------------------------------------------------------------------ + bool bc_offers_service::init(const std::string& config_folder, const boost::program_options::variables_map& vm) + { + if (command_line::get_arg(vm, arg_market_disable)) + { + LOG_PRINT_CYAN("Market DISABLED", LOG_LEVEL_0); + m_disabled = true; + return true; + } + LOG_PRINT_L0("Loading market..."); + m_config_folder = config_folder; + std::string filename = m_config_folder + "/" BC_OFFERS_CURRENCY_MARKET_FILENAME; + if (!tools::unserialize_obj_from_file(*this, filename)) + { + LOG_PRINT_L0("Can't load market from file"); + //TODO: may be rebuild it from blockchain + } + return true; + } + //------------------------------------------------------------------ + void bc_offers_service::set_event_handler(currency::i_core_event_handler* event_handler) + { + m_pcore_event_handler = event_handler; + } + //------------------------------------------------------------------ + bool bc_offers_service::deinit() + { + LOG_PRINT_L0("Storing market..."); + CRITICAL_REGION_LOCAL(m_lock); + std::string filename = m_config_folder + "/" BC_OFFERS_CURRENCY_MARKET_FILENAME; + if (!tools::serialize_obj_to_file(*this, filename)) + { + LOG_PRINT_L0("Can't store market from file"); + //TODO: may be rebuild it from blockchain + } + m_deinitialized = true; + LOG_PRINT_L0("Market stored OK"); + return true; + } + //------------------------------------------------------------------ + void bc_offers_service::handle_entry_push(const currency::tx_service_attachment& a, size_t i, const currency::transaction& tx, uint64_t h, const crypto::hash& bl_id, uint64_t timestamp) + { + if (m_disabled) + return; + //unpack data and pars json + std::string json_buff; + if (!epee::zlib_helper::unpack(a.body, json_buff)) + { + LOG_ERROR("Filed to unpack tx_service_attachment in bc_offers_service, tx_id = " << currency::get_transaction_hash(tx)); + return; + } + + bool r = false; + if (a.instruction == BC_OFFERS_SERVICE_INSTRUCTION_ADD) + { + offer_details od = AUTO_VAL_INIT(od); + r = handle_entry_push(json_buff, a, od, i, tx, h, timestamp); + CHECK_AND_ASSERT_MES_NO_RET(r, "offers service instruction " << a.instruction << " failed, offer's tx:oid : " << get_transaction_hash(tx) << ":" << i); + }else if (a.instruction == BC_OFFERS_SERVICE_INSTRUCTION_UPD) + { + update_offer od = AUTO_VAL_INIT(od); + r = handle_entry_push(json_buff, a, od, i, tx, h, timestamp); + }else if(a.instruction == BC_OFFERS_SERVICE_INSTRUCTION_DEL) + { + cancel_offer od = AUTO_VAL_INIT(od); + r = handle_entry_push(json_buff, a, od, i, tx, h, timestamp); + } + + } + //------------------------------------------------------------------ + + + bool bc_offers_service::trim_offers() + { + CRITICAL_REGION_LOCAL(m_lock); + uint64_t current_time = m_core_runtime_config.get_core_time(); + auto& index = m_offers.get(); + uint64_t size_before = m_offers.size(); + for (auto it = index.begin(); it != index.end();) + { + if (it->timestamp + OFFER_MAXIMUM_LIFE_TIME < current_time) + index.erase(it++); + else + break; + } + LOG_PRINT_GREEN("TRIM OFFERS: " << size_before - m_offers.size() << " offers removed", LOG_LEVEL_0); + return true; + } + //------------------------------------------------------------------ + crypto::hash bc_offers_service::get_last_seen_block_id() + { + return m_last_seen_block_id; + } + //------------------------------------------------------------------ + void bc_offers_service::set_last_seen_block_id(const crypto::hash& h) + { + m_last_seen_block_id = h; + } + //------------------------------------------------------------------ + bool bc_offers_service::clear() + { + m_last_trimed_height = 0; + m_last_seen_block_id = currency::null_hash; + CRITICAL_REGION_LOCAL(m_lock); + m_offers.clear(); + return true; + } + //------------------------------------------------------------------ + void bc_offers_service::init_options(boost::program_options::options_description& desc) + { + command_line::add_arg(desc, arg_market_disable); + } + //------------------------------------------------------------------ + void bc_offers_service::handle_entry_pop(const currency::tx_service_attachment& a, size_t i, const currency::transaction& tx, uint64_t h, uint64_t timestamp) + { + if (m_disabled) + return; + //unpack data and pars json + std::string json_buff; + if (!epee::zlib_helper::unpack(a.body, json_buff)) + { + LOG_ERROR("Filed to unpack tx_service_attachment in bc_offers_service, tx_id = " << get_transaction_hash(tx)); + return; + } + + bool r = false; + if (a.instruction == BC_OFFERS_SERVICE_INSTRUCTION_ADD) + { + offer_details od = AUTO_VAL_INIT(od); + r = handle_entry_pop(json_buff, od, i, tx, h, timestamp); + } + else if (a.instruction == BC_OFFERS_SERVICE_INSTRUCTION_UPD) + { + update_offer od = AUTO_VAL_INIT(od); + r = handle_entry_pop(json_buff, od, i, tx, h, timestamp); + } + else if (a.instruction == BC_OFFERS_SERVICE_INSTRUCTION_DEL) + { + cancel_offer od = AUTO_VAL_INIT(od); + r = handle_entry_pop(json_buff, od, i, tx, h, timestamp); + } + if (!r) + { + LOG_ERROR("offers service instruction " << a.instruction << " failed, offer's tx:oid : " << get_transaction_hash(tx) << ":" << i); + } + + + //trim offers once a day + if (m_last_trimed_height != h && !(h%CURRENCY_BLOCKS_PER_DAY)) + { + trim_offers(); + m_last_trimed_height = h; + } + + + } + //------------------------------------------------------------------------------------------------------------------------ + // adding new offer + + bool bc_offers_service::handle_push(offer_details& od_, const currency::tx_service_attachment& a, size_t i, const currency::transaction& tx, uint64_t h, uint64_t timestamp) + { + offer_details_ex_with_hash od = AUTO_VAL_INIT(od); + static_cast(od) = od_; + od.timestamp = timestamp; + od.index_in_tx = i; + crypto::hash tx_hash = get_transaction_hash(tx); + od.tx_hash = tx_hash; + od.stopped = false; + CHECK_AND_ASSERT_MES(a.security.size(), false, "Add offer command: no security entry"); + od.security = a.security.back(); + od.fee = currency::get_tx_fee(tx) / currency::get_service_attachments_count_in_tx(tx); + od.h = offer_id_from_hash_and_index(tx_hash, od.index_in_tx); + bool r = put_offer_to_container(od); + if (r) + rise_core_event(CORE_EVENT_ADD_OFFER, od); + return true; + } + //------------------------------------------------------------------------------------------------------------------------ + bool bc_offers_service::validate_entry(const currency::tx_service_attachment& a, size_t i, const currency::transaction& tx) + { + if (a.service_id != BC_OFFERS_SERVICE_ID) + return true; + + //don't validate other atm + if (a.instruction != BC_OFFERS_SERVICE_INSTRUCTION_DEL) + return true; + + std::string json_buff; + if (!epee::zlib_helper::unpack(a.body, json_buff)) + { + LOG_ERROR("Filed to unpack tx_service_attachment in bc_offers_service, tx_id = " << get_transaction_hash(tx)); + return false; + } + + cancel_offer co = AUTO_VAL_INIT(co); + bool r = epee::serialization::load_t_from_json(co, json_buff); + if (!r) + { + LOG_ERROR("Filed to load json from tx_service_attachment in bc_offers_service, tx_id = " << get_transaction_hash(tx) << ", body: " << json_buff); + return false; + } + offers_container::index::type::iterator oit; + return validate_cancel_order(co, oit); + } + //------------------------------------------------------------------------------------------------------------------------ + // updating offer + bool bc_offers_service::handle_push(update_offer& uo, const currency::tx_service_attachment& a, size_t i, const currency::transaction& tx, uint64_t h, uint64_t timestamp) + { + CRITICAL_REGION_LOCAL(m_lock); + auto& index = m_offers.get(); + crypto::hash offer_id = offer_id_from_hash_and_index(uo.tx_id, uo.offer_index); + auto it = index.find(offer_id); + if (it == index.end()) + { + LOG_PRINT_L2("Update offer command failed: offer not found, tx:idx : " << uo.tx_id << ":" << uo.offer_index << ", offer_id: " << offer_id); + return false; + } + + + bool r = validate_modify_order_signature(*it, uo); + CHECK_AND_NO_ASSERT_MES(r, false, "validate_modify_order_signature failed while trying to update an offer " << uo.tx_id << ":" << uo.offer_index); + + crypto::hash tx_id = get_transaction_hash(tx); + + offer_details_ex_with_hash new_off = AUTO_VAL_INIT(new_off); + static_cast(new_off) = uo.of; + new_off.timestamp = it->timestamp;// keep original offer's timestmap + new_off.index_in_tx = i; + new_off.tx_hash = tx_id; + new_off.stopped = false; + CHECK_AND_ASSERT_MES(a.security.size(), false, "Update offer command: no security entry"); + new_off.security = a.security.back(); + + new_off.fee = currency::get_tx_fee(tx) / get_service_attachments_count_in_tx(tx); + new_off.h = offer_id_from_hash_and_index(tx_id, new_off.index_in_tx); + put_offer_to_container(new_off); + + //update old order + it->nxt_offer = epee::string_tools::pod_to_hex(new_off.h); + it->stopped = true; + + //notify + update_offer_details uop = AUTO_VAL_INIT(uop); + uop.od = static_cast(new_off); + uop.tx_id = uo.tx_id; + uop.no = uo.offer_index; + uop.wallet_id = 0; // ?? is 0 okay here? + rise_core_event(CORE_EVENT_UPDATE_OFFER, uop); + + return true; + } + //------------------------------------------------------------------------------------------------------------------------ + // canceling offer + bool bc_offers_service::handle_push(cancel_offer& co, const currency::tx_service_attachment& a, size_t i, const currency::transaction& tx, uint64_t h, uint64_t timestamp) + { + CRITICAL_REGION_LOCAL(m_lock); + offers_container::index::type::iterator it = m_offers.get().end(); + bool r = validate_cancel_order(co, it); + if (!r) + return false; + + it->stopped = true; + LOG_PRINT_MAGENTA("Offer " << co.tx_id << ":" << co.offer_index << " cancelled", LOG_LEVEL_0); + rise_core_event(CORE_EVENT_REMOVE_OFFER, static_cast(*it)); + return true; + } + //------------------------------------------------------------------ + bool bc_offers_service::validate_cancel_order(const cancel_offer& co, offers_container::index::type::iterator& oit) + { + CRITICAL_REGION_LOCAL(m_lock); + auto& index = m_offers.get(); + crypto::hash offer_id = offer_id_from_hash_and_index(co.tx_id, co.offer_index); + oit = index.find(offer_id); + if (oit == index.end()) + { + LOG_PRINT_L2("Cancel offer command: tx " << co.tx_id << " not found in offers"); + return false; + } + + bool r = validate_modify_order_signature(*oit, co); + CHECK_AND_NO_ASSERT_MES(r, false, "failed to validate_modify_order_signature at validate_cancel_order"); + + return true; + } + //------------------------------------------------------------------------------------------------------------------------ + bool bc_offers_service::handle_pop(offer_details& od, size_t i, const currency::transaction& tx, uint64_t h, uint64_t timestamp) + { + crypto::hash tx_hash = currency::get_transaction_hash(tx); + CRITICAL_REGION_LOCAL(m_lock); + auto& index = m_offers.get(); + crypto::hash oid = offer_id_from_hash_and_index(tx_hash, i); + auto it = index.find(oid); + if (it == index.end()) + { + LOG_ERROR("Internal error: unprocess_blockchain_tx_attachments tx_id: " << tx_hash << " cnt_offers_ins=" << i << ", oid: " << oid << " not found"); + } + else + { + rise_core_event(CORE_EVENT_REMOVE_OFFER, *it); + index.erase(it); + } + return true; + } + //------------------------------------------------------------------------------------------------------------------------ + bool bc_offers_service::handle_pop(update_offer& uo, size_t i, const currency::transaction& tx, uint64_t h, uint64_t timestamp) + { + crypto::hash tx_id = currency::get_transaction_hash(tx); + CRITICAL_REGION_LOCAL(m_lock); + auto& index = m_offers.get(); + crypto::hash oid = offer_id_from_hash_and_index(tx_id, i); + crypto::hash original_oid = offer_id_from_hash_and_index(uo.tx_id, uo.offer_index); + auto it = index.find(oid); + CHECK_AND_ASSERT_MES(it != index.end(), false, "Unprocess update offer command: tx " << tx_id << "(" << oid << ") not found in offers"); + auto original_it = index.find(original_oid); + CHECK_AND_ASSERT_MES(original_it != index.end(), false, "Unprocess update offer command: original tx " << uo.tx_id << "(" << original_oid << ") not found in offers"); + + rise_core_event(CORE_EVENT_REMOVE_OFFER, *it); + original_it->stopped = false; + original_it->nxt_offer.clear(); + index.erase(it); + rise_core_event(CORE_EVENT_ADD_OFFER, *original_it); + return true; + } + //------------------------------------------------------------------------------------------------------------------------ + bool bc_offers_service::handle_pop(cancel_offer& co, size_t i, const currency::transaction& tx, uint64_t h, uint64_t timestamp) + { + CRITICAL_REGION_LOCAL(m_lock); + auto& index = m_offers.get(); + crypto::hash offer_id = offer_id_from_hash_and_index(co.tx_id, co.offer_index); + auto oit = index.find(offer_id); + CHECK_AND_ASSERT_MES(oit != index.end(), false, "Cancel offer command: tx " << co.tx_id << " not found in offers"); + + + CHECK_AND_ASSERT_MES(oit->stopped, false, "Cancel offer command unprocess: tx " + << co.tx_id << ": co.offer_index " << co.offer_index << ": not stopped yet"); + oit->stopped = false; + rise_core_event(CORE_EVENT_ADD_OFFER, static_cast(*oit)); + return true; + } + //------------------------------------------------------------------------------------------------------------------------ + bool bc_offers_service::put_offer_to_container(const offer_details_ex_with_hash& offer) + { + try + { + CRITICAL_REGION_LOCAL(m_lock); + auto& offers_index = m_offers.get(); + offers_index.insert(offer); + return true; + } + catch (const std::exception& err) + { + LOG_ERROR("Failed to put offer to index, error: " << err.what() << ", offer[" << offer.h << "]: " << epee::serialization::store_t_to_json(offer)); + return false; + } + catch (...) + { + LOG_ERROR("Failed to put offer to index, offer[" << offer.h << "]: " << epee::serialization::store_t_to_json(offer)); + return false; + } + } + //------------------------------------------------------------------------------------------------------------------------ + bool bc_offers_service::get_offers_by_id(const std::list& ids, std::list& offers) + { + for (auto& id : ids) + { + crypto::hash original_id = id.tx_id; + crypto::hash of_id = currency::null_hash; + of_id = offer_id_from_hash_and_index(id); + if (of_id == currency::null_hash) + continue; + + CRITICAL_REGION_LOCAL(m_lock); + auto& index_by_id = m_offers.get(); + auto it = index_by_id.find(of_id); + if (it == index_by_id.end()) + { + LOG_PRINT_L2("Unable to find offer by tx id: " << id.tx_id << ", offer id: " << of_id); + continue; + } + + if (it != index_by_id.end() && it->nxt_offer.size()) + { + crypto::hash nxt_h = currency::null_hash; + if (!epee::string_tools::parse_tpod_from_hex_string(it->nxt_offer, nxt_h)) + { + LOG_PRINT_L2("Unable to parse hash from nxt_h: " << it->nxt_offer); + } + else + { + it = index_by_id.find(nxt_h); + } + } + + if (it == index_by_id.end()) + { + LOG_PRINT_L2("Unable to find offer by tx id: " << id.tx_id << ", offer id: " << of_id); + continue; + } + offers.push_back(*it); + + if (offers.back().tx_hash != original_id) + offers.back().tx_original_hash = original_id; + } + + return true; + } + //------------------------------------------------------------------------------------------------------------------------ + void bc_offers_service::print_market(const std::string& file) + { + std::stringstream ss; + CRITICAL_REGION_LOCAL(m_lock); + for (auto& o : m_offers) + { + ss << "id: " << o.h << ENDL + << "nxt_id: " << o.nxt_offer << ENDL + << epee::serialization::store_t_to_json(o) << ENDL + << "----------------------------------------------" << ENDL; + } + if (epee::file_io_utils::save_string_to_file(file, ss.str())) + { + LOG_PRINT_L0("Market writen to file: " << file); + } + else + { + LOG_PRINT_L0("Failed to write market to file: " << file); + } + } + //------------------------------------------------------------------------------------------------------------------------ + void bc_offers_service::set_core_runtime_config(const currency::core_runtime_config& rtc) + { + m_core_runtime_config = rtc; + } + //------------------------------------------------------------------ + bool bc_offers_service::get_offers_ex(const core_offers_filter& cof, std::list& offers, uint64_t& total_count, uint64_t current_core_time) + { + CRITICAL_REGION_LOCAL(m_lock); + total_count = m_offers.size(); +#define SET_CASE_FOR_ORDER_TYPE(order_type_name) case order_type_name: return get_offers_ex_for_index::index_type>(cof, offers, current_core_time); + + switch (cof.order_by) + { + SET_CASE_FOR_ORDER_TYPE(ORDER_BY_TIMESTAMP); + SET_CASE_FOR_ORDER_TYPE(ORDER_BY_AMOUNT_PRIMARY); + SET_CASE_FOR_ORDER_TYPE(ORDER_BY_AMOUNT_TARGET); + SET_CASE_FOR_ORDER_TYPE(ORDER_BY_AMOUNT_RATE); + SET_CASE_FOR_ORDER_TYPE(ORDER_BY_PAYMENT_TYPES); + SET_CASE_FOR_ORDER_TYPE(ORDER_BY_CONTACTS); + SET_CASE_FOR_ORDER_TYPE(ORDER_BY_LOCATION); + SET_CASE_FOR_ORDER_TYPE(ORDER_BY_NAME); + default: + LOG_ERROR("Unknown order_by id: " << cof.order_by); + return false; + } + return true; + } + //------------------------------------------------------------------ + +} diff --git a/src/currency_core/bc_offers_service.h b/src/currency_core/bc_offers_service.h new file mode 100644 index 00000000..634aa6f1 --- /dev/null +++ b/src/currency_core/bc_offers_service.h @@ -0,0 +1,249 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "include_base_utils.h" + +#include "bc_offers_service_basic.h" +#include "common/boost_serialization_helper.h" +#include "bc_offers_serialization.h" +#include "bc_attachments_service_manager.h" +#include "offers_services_helpers.h" +#include "currency_format_utils.h" +#include "common/command_line.h" + + +extern command_line::arg_descriptor arg_market_disable; + +namespace bc_services +{ + class bc_offers_service : public currency::i_bc_service + { + public: + bc_offers_service(currency::i_core_event_handler* pcore_event_handler); + ~bc_offers_service(); + + typedef boost::multi_index::multi_index_container < + odeh, + boost::multi_index::indexed_by< + boost::multi_index::hashed_unique, boost::multi_index::global_fun>, + boost::multi_index::ordered_non_unique, boost::multi_index::global_fun >, + boost::multi_index::ordered_non_unique, boost::multi_index::global_fun >, + boost::multi_index::ordered_non_unique, boost::multi_index::global_fun >, + boost::multi_index::ordered_non_unique, boost::multi_index::global_fun >, + boost::multi_index::ordered_non_unique, boost::multi_index::global_fun >, + boost::multi_index::ordered_non_unique, boost::multi_index::global_fun >, + boost::multi_index::ordered_non_unique, boost::multi_index::global_fun >, + boost::multi_index::ordered_non_unique, boost::multi_index::global_fun > + > + > offers_container; + template + void serialize(archive_t & ar, const unsigned int version); + bool validate_cancel_order(const cancel_offer& co, offers_container::index::type::iterator& oit); + bool get_offers_by_id(const std::list& ids, std::list& offers); + bool get_offers_ex(const core_offers_filter& cof, std::list& offers, uint64_t& total_count, uint64_t current_core_time); + void print_market(const std::string& file); + + public: + // these members are made public only to be accessible from tests + offers_container& get_offers_container(){ return m_offers; } //TODO: need refactoring, bad design, atm just for performance tests + bool trim_offers(); + crypto::hash get_last_seen_block_id(); + void set_last_seen_block_id(const crypto::hash& h); + bool clear(); + bool is_disabled(){ return m_disabled; } + static void init_options(boost::program_options::options_description& desc); + private: + //-------------------- currency::i_bc_service --------------------------------------- + virtual std::string get_id() override { return BC_OFFERS_SERVICE_ID; } + virtual void set_event_handler(currency::i_core_event_handler* event_handler) override; + virtual bool init(const std::string& config_folder, const boost::program_options::variables_map& vm) override; + virtual bool deinit() override; + virtual void handle_entry_push(const currency::tx_service_attachment& a, size_t i, const currency::transaction& tx, uint64_t h, const crypto::hash& bl_id, uint64_t timestamp) override; + virtual void handle_entry_pop(const currency::tx_service_attachment& a, size_t i, const currency::transaction& tx, uint64_t h, uint64_t timestamp) override; + virtual bool validate_entry(const currency::tx_service_attachment& a, size_t i, const currency::transaction& tx) override; + virtual void set_core_runtime_config(const currency::core_runtime_config& rtc) override; + //----------------------------------------------------------------------------------- + + bool handle_push(offer_details& od, const currency::tx_service_attachment& a, size_t i, const currency::transaction& tx, uint64_t h, uint64_t timestamp); + bool handle_push(update_offer& od, const currency::tx_service_attachment& a, size_t i, const currency::transaction& tx, uint64_t h, uint64_t timestamp); + bool handle_push(cancel_offer& od, const currency::tx_service_attachment& a, size_t i, const currency::transaction& tx, uint64_t h, uint64_t timestamp); + bool handle_pop(offer_details& od, size_t i, const currency::transaction& tx, uint64_t h, uint64_t timestamp); + bool handle_pop(update_offer& od, size_t i, const currency::transaction& tx, uint64_t h, uint64_t timestamp); + bool handle_pop(cancel_offer& od, size_t i, const currency::transaction& tx, uint64_t h, uint64_t timestamp); + bool put_offer_to_container(const offer_details_ex_with_hash& offer); + + template + void rise_core_event(const std::string& event_name, const t_event_details& ed); + template + bool handle_entry_push(const std::string& body, const currency::tx_service_attachment& a, t_offer& offer_instruction, size_t i, const currency::transaction& tx, uint64_t h, uint64_t timestamp); + template + bool handle_entry_pop(const std::string& body, t_offer& offer_instruction, size_t i, const currency::transaction& tx, uint64_t h, uint64_t timestamp); + template + bool validate_modify_order_signature(const offer_details_ex_with_hash &odeh, const t_modify_offer& co); + template + bool get_offers_ex_for_index(const core_offers_filter& cof, std::list& offers, uint64_t current_core_time); + + + //offers + offers_container m_offers; //offers indexed by + currency::i_core_event_handler* m_pcore_event_handler; + uint64_t m_last_trimed_height; + std::string m_config_folder; + crypto::hash m_last_seen_block_id; + epee::critical_section m_lock; + currency::core_runtime_config m_core_runtime_config; + bool m_deinitialized; + bool m_disabled; + //--------------------------------------------------------------------------------------------------------------------------------------------- + + }; + + template + void bc_offers_service::rise_core_event(const std::string& event_name, const t_event_details& ed) + { + currency::core_event_v e(ed); + if (m_pcore_event_handler) + m_pcore_event_handler->on_core_event(event_name, e); + } + //--------------------------------------------------------------------------------------------------------------------------------------------- + template + bool bc_offers_service::handle_entry_push(const std::string& body, const currency::tx_service_attachment& a, t_offer& offer_instruction, size_t i, const currency::transaction& tx, uint64_t h, uint64_t timestamp) + { + bool r = epee::serialization::load_t_from_json(offer_instruction, body); + if (!r) + { + LOG_ERROR("Filed to load json from tx_service_attachment in bc_offers_service, tx_id = " << currency::get_transaction_hash(tx) << ", body: " << body); + return false; + } + return handle_push(offer_instruction, a, i, tx, h, timestamp); + } + //--------------------------------------------------------------------------------------------------------------------------------------------- + template + bool bc_offers_service::handle_entry_pop(const std::string& body, t_offer& offer_instruction, size_t i, const currency::transaction& tx, uint64_t h, uint64_t timestamp) + { + bool r = epee::serialization::load_t_from_json(offer_instruction, body); + if (!r) + { + LOG_ERROR("Filed to load json from tx_service_attachment in bc_offers_service, tx_id = " << currency::get_transaction_hash(tx) << ", body: " << body); + return false; + } + return handle_pop(offer_instruction, i, tx, h, timestamp); + } + //--------------------------------------------------------------------------------------------------------------------------------------------- + template + bool bc_offers_service::validate_modify_order_signature(const offer_details_ex_with_hash &odeh, const t_modify_offer& co) + { + if (odeh.stopped) + { + LOG_PRINT_YELLOW("offer command validation failed: already stopped, tx: " << co.tx_id << ", offer_index: " << co.offer_index, LOG_LEVEL_0); + return false; + } + + currency::blobdata buff_to_check_sig = make_offer_sig_blob(co); + bool res = crypto::check_signature(crypto::cn_fast_hash(buff_to_check_sig.data(), buff_to_check_sig.size()), odeh.security, co.sig); + CHECK_AND_ASSERT_MES(res, false, "Signature check failed for offer command: tx " << co.tx_id << ", onetime_offer_pub_key=" << epee::string_tools::pod_to_hex(odeh.security)); + + return true; + } + //--------------------------------------------------------------------------------------------------------------------------------------------- + template + bool bc_offers_service::get_offers_ex_for_index(const core_offers_filter& cof, std::list& offers, uint64_t current_core_time) + { + CRITICAL_REGION_LOCAL(m_lock); + if (!m_offers.size()) + return false; + + auto& current_index = m_offers.get(); + + auto it = current_index.begin(); + if (cof.reverse) + it = --current_index.end(); + + uint64_t selected_index = 0; + while (it != current_index.end()) + { + //-------- + if (selected_index >= cof.offset + cof.limit) + break; + + if (is_offer_matched_by_filter(*it, cof, current_core_time)) + { + //if we after offset position + if (selected_index >= cof.offset) + offers.push_back(*it); + + selected_index++; + } + + //-------- + //prepare next iteration + if (cof.reverse) + { + if (it == current_index.begin()) + break; + else + --it; + } + else + { + ++it; + } + } + + return true; + } + //--------------------------------------------------------------------------------------------------------------------------------------------- + template + void bc_offers_service::serialize(archive_t & ar, const unsigned int version) + { + if (version < BC_OFFERS_CURRENT_OFFERS_SERVICE_ARCHIVE_VER) + { + LOG_PRINT_BLUE("[OFFERS_SERVICE] data truncated cz new version", LOG_LEVEL_0); + return; + } + CHECK_PROJECT_NAME(); + ar & m_last_trimed_height; + ar & m_last_seen_block_id; + + std::list temp; + if (archive_t::is_saving::value) + { + auto& index = m_offers.get(); + for (auto it = index.begin(); it != index.end();it++) + { + temp.push_back(*it); + } + ar & temp; + } + else + { + ar & temp; + for (const auto& o : temp) + { + TRY_ENTRY() + m_offers.insert(o); + CATCH_ENTRY("error while reading market storage ", void()); + } + + } + //ar & m_offers; + } +} +BOOST_CLASS_VERSION(bc_services::bc_offers_service, BC_OFFERS_CURRENT_OFFERS_SERVICE_ARCHIVE_VER) diff --git a/src/currency_core/bc_offers_service_basic.h b/src/currency_core/bc_offers_service_basic.h new file mode 100644 index 00000000..41f06c40 --- /dev/null +++ b/src/currency_core/bc_offers_service_basic.h @@ -0,0 +1,12 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + + +#define BC_OFFERS_SERVICE_ID "M" +#define BC_OFFERS_SERVICE_INSTRUCTION_ADD "ADD" +#define BC_OFFERS_SERVICE_INSTRUCTION_UPD "UPD" +#define BC_OFFERS_SERVICE_INSTRUCTION_DEL "DEL" diff --git a/src/currency_core/bc_payments_id_service.h b/src/currency_core/bc_payments_id_service.h new file mode 100644 index 00000000..070907bd --- /dev/null +++ b/src/currency_core/bc_payments_id_service.h @@ -0,0 +1,10 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + + +#define BC_PAYMENT_ID_SERVICE_ID "P" +#define BC_PAYMENT_ID_SERVICE_SIZE_MAX 128 // (bytes) maximum allowed size of payment id body diff --git a/src/currency_core/block_flags.h b/src/currency_core/block_flags.h new file mode 100644 index 00000000..b7724e15 --- /dev/null +++ b/src/currency_core/block_flags.h @@ -0,0 +1,8 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#define CURRENCY_BLOCK_FLAG_POS_BLOCK 0x01 diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp new file mode 100644 index 00000000..40032deb --- /dev/null +++ b/src/currency_core/blockchain_storage.cpp @@ -0,0 +1,5416 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include + +#include "include_base_utils.h" + +#include "common/db_backend_lmdb.h" +#include "common/command_line.h" + +#include "blockchain_storage.h" +#include "currency_format_utils.h" +#include "currency_boost_serialization.h" +#include "currency_core/currency_config.h" +#include "miner.h" +#include "misc_language.h" +#include "profile_tools.h" +#include "file_io_utils.h" +#include "common/boost_serialization_helper.h" +#include "warnings.h" +#include "crypto/hash.h" +#include "miner_common.h" +#include "storages/portable_storage_template_helper.h" +#include "common/db_backend_lmdb.h" +#include "version.h" + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL "core" +ENABLE_CHANNEL_BY_DEFAULT("core"); + +using namespace std; +using namespace epee; +using namespace currency; + +#define BLOCKCHAIN_STORAGE_CONTAINER_BLOCKS "blocks" +#define BLOCKCHAIN_STORAGE_CONTAINER_BLOCKS_INDEX "blocks_index" +#define BLOCKCHAIN_STORAGE_CONTAINER_TRANSACTIONS "transactions" +#define BLOCKCHAIN_STORAGE_CONTAINER_SPENT_KEYS "spent_keys" +#define BLOCKCHAIN_STORAGE_CONTAINER_OUTPUTS "outputs" +#define BLOCKCHAIN_STORAGE_CONTAINER_MULTISIG_OUTS "multisig_outs" +#define BLOCKCHAIN_STORAGE_CONTAINER_INVALID_BLOCKS "invalid_blocks" +#define BLOCKCHAIN_STORAGE_CONTAINER_SOLO_OPTIONS "solo" +#define BLOCKCHAIN_STORAGE_CONTAINER_ALIASES "aliases" +#define BLOCKCHAIN_STORAGE_CONTAINER_ADDR_TO_ALIAS "addr_to_alias" +#define BLOCKCHAIN_STORAGE_CONTAINER_TX_FEE_MEDIAN "median_fee2" +#define BLOCKCHAIN_STORAGE_CONTAINER_GINDEX_INCS "gindex_increments" + +#define BLOCKCHAIN_STORAGE_OPTIONS_ID_CURRENT_BLOCK_CUMUL_SZ_LIMIT 0 +#define BLOCKCHAIN_STORAGE_OPTIONS_ID_CURRENT_PRUNED_RS_HEIGHT 1 +#define BLOCKCHAIN_STORAGE_OPTIONS_ID_LAST_WORKED_VERSION 2 +#define BLOCKCHAIN_STORAGE_OPTIONS_ID_STORAGE_MAJOR_COMPATIBILITY_VERSION 3 //mismatch here means full resync +#define BLOCKCHAIN_STORAGE_OPTIONS_ID_STORAGE_MINOR_COMPATIBILITY_VERSION 4 //mismatch here means some reinitializations + + + +DISABLE_VS_WARNINGS(4267) + +namespace +{ + const command_line::arg_descriptor arg_db_cache_l1 = { "db-cache-l1", "Specify size of memory mapped db cache file", 0, true }; + const command_line::arg_descriptor arg_db_cache_l2 = { "db-cache-l2", "Specify cached elements in db helpers", 0, true }; +} + +//------------------------------------------------------------------ +blockchain_storage::blockchain_storage(tx_memory_pool& tx_pool) :m_db(std::shared_ptr(new tools::db::lmdb_db_backend), m_rw_lock), + m_db_blocks(m_db), + m_db_blocks_index(m_db), + m_db_transactions(m_db), + m_db_spent_keys(m_db), + m_db_outputs(m_db), + m_db_multisig_outs(m_db), + m_db_solo_options(m_db), + m_db_aliases(m_db), + m_db_addr_to_alias(m_db), + m_read_lock(m_rw_lock), + m_db_current_block_cumul_sz_limit(BLOCKCHAIN_STORAGE_OPTIONS_ID_CURRENT_BLOCK_CUMUL_SZ_LIMIT, m_db_solo_options), + m_db_current_pruned_rs_height(BLOCKCHAIN_STORAGE_OPTIONS_ID_CURRENT_PRUNED_RS_HEIGHT, m_db_solo_options), + m_db_last_worked_version(BLOCKCHAIN_STORAGE_OPTIONS_ID_LAST_WORKED_VERSION, m_db_solo_options), + m_db_storage_major_compatibility_version(BLOCKCHAIN_STORAGE_OPTIONS_ID_STORAGE_MAJOR_COMPATIBILITY_VERSION, m_db_solo_options), + m_db_storage_minor_compatibility_version(BLOCKCHAIN_STORAGE_OPTIONS_ID_STORAGE_MINOR_COMPATIBILITY_VERSION, m_db_solo_options), + m_db_per_block_gindex_incs(m_db), + m_tx_pool(tx_pool), + m_is_in_checkpoint_zone(false), + m_is_blockchain_storing(false), + m_core_runtime_config(get_default_core_runtime_config()), + //m_bei_stub(AUTO_VAL_INIT(m_bei_stub)), + m_event_handler(&m_event_handler_stub), + m_services_mgr(nullptr), + m_interprocess_locker_file(0), + m_current_fee_median(0), + m_current_fee_median_effective_index(0), + m_is_reorganize_in_process(false) + + +{ + m_services_mgr.set_core_runtime_config(m_core_runtime_config); + m_performance_data.epic_failure_happend = false; +} +//------------------------------------------------------------------ +bool blockchain_storage::have_tx(const crypto::hash &id) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + return m_db_transactions.find(id) != m_db_transactions.end(); +} +//------------------------------------------------------------------ +bool blockchain_storage::have_tx_keyimg_as_spent(const crypto::key_image &key_im, uint64_t before_height /* = UINT64_MAX */) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + auto it_ptr = m_db_spent_keys.get(key_im); + if (!it_ptr) + return false; + return *it_ptr < before_height; +} +//------------------------------------------------------------------ +std::shared_ptr blockchain_storage::get_tx(const crypto::hash &id) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + auto it = m_db_transactions.find(id); + if (it == m_db_transactions.end()) + return std::shared_ptr(nullptr); + + return std::make_shared(it->tx); +} +//------------------------------------------------------------------ +void blockchain_storage::init_options(boost::program_options::options_description& desc) +{ + command_line::add_arg(desc, arg_db_cache_l1); + command_line::add_arg(desc, arg_db_cache_l2); +} +//------------------------------------------------------------------ + +uint64_t blockchain_storage::get_block_h_older_then(uint64_t timestamp) const +{ + // get avarage block position + uint64_t last_block_timestamp = m_db_blocks.back()->bl.timestamp; + if (timestamp >= last_block_timestamp) + return get_top_block_height(); + uint64_t difference = last_block_timestamp - timestamp; + uint64_t n_blocks = difference / (DIFFICULTY_TOTAL_TARGET); + if (n_blocks >= get_top_block_height()) + return 0; + uint64_t index = get_top_block_height() - n_blocks; + while (true) + { + if (index == 0) + return 0; + if (m_db_blocks[index]->bl.timestamp < timestamp) + return index; + index--; + } + return 0; +} +//------------------------------------------------------------------ +uint64_t blockchain_storage::get_current_blockchain_size() const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + return m_db_blocks.size(); +} +//------------------------------------------------------------------ +uint64_t blockchain_storage::get_top_block_height() const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + return m_db_blocks.size() - 1; +} +//------------------------------------------------------------------ +bool blockchain_storage::validate_instance(const std::string& path) +{ + std::string locker_name = path + "/" + std::string(CURRENCY_CORE_INSTANCE_LOCK_FILE); + bool r = epee::file_io_utils::open_and_lock_file(locker_name, m_interprocess_locker_file); + + if (r) + return true; + else + { + LOG_ERROR("Failed to initialize db: some other instance is already running"); + return false; + } +} +//------------------------------------------------------------------ +bool blockchain_storage::init(const std::string& config_folder, const boost::program_options::variables_map& vm) +{ +// CRITICAL_REGION_LOCAL(m_read_lock); + + if (!validate_instance(config_folder)) + { + LOG_ERROR("Failed to initialize instance"); + return false; + } + + uint64_t cache_size = CACHE_SIZE; + if (command_line::has_arg(vm, arg_db_cache_l1)) + { + cache_size = command_line::get_arg(vm, arg_db_cache_l1); + } + LOG_PRINT_GREEN("Using db file cache size(L1): " << cache_size, LOG_LEVEL_0); + + + m_config_folder = config_folder; + LOG_PRINT_L0("Loading blockchain..."); + const std::string folder_name = m_config_folder + "/" CURRENCY_BLOCKCHAINDATA_FOLDERNAME; + tools::create_directories_if_necessary(folder_name); + bool res = m_db.open(folder_name, cache_size); + CHECK_AND_ASSERT_MES(res, false, "Failed to initialize database in folder: " << folder_name); + + res = m_db_blocks.init(BLOCKCHAIN_STORAGE_CONTAINER_BLOCKS); + CHECK_AND_ASSERT_MES(res, false, "Unable to init db container"); + res = m_db_blocks_index.init(BLOCKCHAIN_STORAGE_CONTAINER_BLOCKS_INDEX); + CHECK_AND_ASSERT_MES(res, false, "Unable to init db container"); + res = m_db_transactions.init(BLOCKCHAIN_STORAGE_CONTAINER_TRANSACTIONS); + CHECK_AND_ASSERT_MES(res, false, "Unable to init db container"); + res = m_db_spent_keys.init(BLOCKCHAIN_STORAGE_CONTAINER_SPENT_KEYS); + CHECK_AND_ASSERT_MES(res, false, "Unable to init db container"); + res = m_db_outputs.init(BLOCKCHAIN_STORAGE_CONTAINER_OUTPUTS); + CHECK_AND_ASSERT_MES(res, false, "Unable to init db container"); + res = m_db_multisig_outs.init(BLOCKCHAIN_STORAGE_CONTAINER_MULTISIG_OUTS); + CHECK_AND_ASSERT_MES(res, false, "Unable to init db container"); + res = m_db_solo_options.init(BLOCKCHAIN_STORAGE_CONTAINER_SOLO_OPTIONS); + CHECK_AND_ASSERT_MES(res, false, "Unable to init db container"); + res = m_db_aliases.init(BLOCKCHAIN_STORAGE_CONTAINER_ALIASES); + CHECK_AND_ASSERT_MES(res, false, "Unable to init db container"); + res = m_db_addr_to_alias.init(BLOCKCHAIN_STORAGE_CONTAINER_ADDR_TO_ALIAS); + CHECK_AND_ASSERT_MES(res, false, "Unable to init db container"); + res = m_db_per_block_gindex_incs.init(BLOCKCHAIN_STORAGE_CONTAINER_GINDEX_INCS); + CHECK_AND_ASSERT_MES(res, false, "Unable to init db container"); + + if (command_line::has_arg(vm, arg_db_cache_l2)) + { + uint64_t cache_size = command_line::get_arg(vm, arg_db_cache_l2); + LOG_PRINT_GREEN("Using db items cache size(L2): " << cache_size, LOG_LEVEL_0); + m_db_blocks_index.set_cache_size(cache_size); + m_db_blocks.set_cache_size(cache_size); + m_db_blocks_index.set_cache_size(cache_size); + m_db_transactions.set_cache_size(cache_size); + m_db_spent_keys.set_cache_size(cache_size); + //m_db_outputs.set_cache_size(cache_size); + m_db_multisig_outs.set_cache_size(cache_size); + m_db_solo_options.set_cache_size(cache_size); + m_db_aliases.set_cache_size(cache_size); + m_db_addr_to_alias.set_cache_size(cache_size); + } + + bool need_reinit = false; + bool need_reinit_medians = false; + if (!m_db_blocks.size()) + { + need_reinit = true; + } + else if (m_db_storage_major_compatibility_version != BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION) + { + need_reinit = true; + LOG_PRINT_MAGENTA("DB storage needs reinit because it has major compatibility ver " << m_db_storage_major_compatibility_version << ", expected : " << BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION, LOG_LEVEL_0); + } + else if (m_db_storage_minor_compatibility_version != BLOCKCHAIN_STORAGE_MINOR_COMPATIBILITY_VERSION) + { + if (m_db_storage_minor_compatibility_version < 1) + need_reinit_medians = true; + } + + if (need_reinit) + { + clear(); + block bl = boost::value_initialized(); + block_verification_context bvc = boost::value_initialized(); + generate_genesis_block(bl); + add_new_block(bl, bvc); + CHECK_AND_ASSERT_MES(!bvc.m_verification_failed, false, "Failed to add genesis block to blockchain"); + LOG_PRINT_MAGENTA("Storage initialized with genesis", LOG_LEVEL_0); + } + if (need_reinit_medians) + { + bool r = rebuild_tx_fee_medians(); + CHECK_AND_ASSERT_MES(r, false, "failed to rebuild_tx_fee_medians()"); + } + + + initialize_db_solo_options_values(); + + m_services_mgr.init(config_folder, vm); + + //print information message + uint64_t timestamp_diff = m_core_runtime_config.get_core_time() - m_db_blocks.back()->bl.timestamp; + if(!m_db_blocks.back()->bl.timestamp) + timestamp_diff = m_core_runtime_config.get_core_time() - 1341378000; + + LOG_PRINT_GREEN("Blockchain initialized. (v:" << m_db_storage_major_compatibility_version << ") last block: " << m_db_blocks.size() - 1 << ENDL + << "genesis: " << get_block_hash(m_db_blocks[0]->bl) << ENDL + << "last block: " << m_db_blocks.size() - 1 << ", " << misc_utils::get_time_interval_string(timestamp_diff) << " time ago" << ENDL + << "current pos difficulty: " << get_next_diff_conditional(true) << ENDL + << "current pow difficulty: " << get_next_diff_conditional(false) << ENDL + << "total tansactions: " << m_db_transactions.size(), + LOG_LEVEL_0); + + + return true; +} +//------------------------------------------------------------------ +void blockchain_storage::initialize_db_solo_options_values() +{ + m_db.begin_transaction(); + m_db_storage_major_compatibility_version = BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION; + m_db_storage_minor_compatibility_version = BLOCKCHAIN_STORAGE_MINOR_COMPATIBILITY_VERSION; + m_db_last_worked_version = std::string(PROJECT_VERSION_LONG); + m_db.commit_transaction(); +} +//------------------------------------------------------------------ +bool blockchain_storage::deinit() +{ + m_db.close(); + epee::file_io_utils::unlock_and_close_file(m_interprocess_locker_file); + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::pop_block_from_blockchain() +{ + CRITICAL_REGION_LOCAL(m_read_lock); + + CHECK_AND_ASSERT_MES(m_db_blocks.size() > 1, false, "pop_block_from_blockchain: can't pop from blockchain with size = " << m_db_blocks.size()); + size_t h = m_db_blocks.size()-1; + auto bei_ptr = m_db_blocks[h]; + CHECK_AND_ASSERT_MES(bei_ptr.get(), false, "pop_block_from_blockchain: can't pop from blockchain"); + + uint64_t fee_total = 0; + bool r = purge_block_data_from_blockchain(bei_ptr->bl, bei_ptr->bl.tx_hashes.size(), fee_total); + CHECK_AND_ASSERT_MES(r, false, "Failed to purge_block_data_from_blockchain for block " << get_block_hash(bei_ptr->bl) << " on height " << h); + + pop_block_from_per_block_increments(bei_ptr->height); + + //remove from index + r = m_db_blocks_index.erase_validate(get_block_hash(bei_ptr->bl)); + CHECK_AND_ASSERT_MES_NO_RET(r, "pop_block_from_blockchain: block id not found in m_blocks_index while trying to delete it"); + + //pop block from core + m_db_blocks.pop_back(); + + on_block_removed(*bei_ptr); + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::set_checkpoints(checkpoints&& chk_pts) +{ + m_checkpoints = chk_pts; + try + { + m_db.begin_transaction(); + if (m_db_blocks.size() < m_checkpoints.get_top_checkpoint_height()) + m_is_in_checkpoint_zone = true; + prune_ring_signatures_and_attachments_if_need(); + m_db.commit_transaction(); + return true; + } + catch (const std::exception& ex) + { + m_db.abort_transaction(); + LOG_ERROR("UNKNOWN EXCEPTION WHILE ADDINIG NEW BLOCK: " << ex.what()); + return false; + } + catch (...) + { + m_db.abort_transaction(); + LOG_ERROR("UNKNOWN EXCEPTION WHILE ADDINIG NEW BLOCK."); + return false; + } + +} +//------------------------------------------------------------------ +bool blockchain_storage::prune_ring_signatures_and_attachments(uint64_t height, uint64_t& transactions_pruned, uint64_t& signatures_pruned, uint64_t& attachments_pruned) +{ + CRITICAL_REGION_LOCAL(m_read_lock); + + CHECK_AND_ASSERT_MES(height < m_db_blocks.size(), false, "prune_ring_signatures called with wrong parameter: " << height << ", m_blocks.size() " << m_db_blocks.size()); + auto vptr = m_db_blocks[height]; + CHECK_AND_ASSERT_MES(vptr.get(), false, "Failed to get block on height"); + + for (const auto& h : vptr->bl.tx_hashes) + { + auto it = m_db_transactions.find(h); + CHECK_AND_ASSERT_MES(it != m_db_transactions.end(), false, "failed to find transaction " << h << " in blockchain index, in block on height = " << height); + + + CHECK_AND_ASSERT_MES(it->m_keeper_block_height == height, false, + "failed to validate extra check, it->second.m_keeper_block_height = " << it->m_keeper_block_height << + "is mot equal to height = " << height << " in blockchain index, for block on height = " << height); + + transaction_chain_entry lolcal_chain_entry = *it; + signatures_pruned += lolcal_chain_entry.tx.signatures.size(); + attachments_pruned += lolcal_chain_entry.tx.attachment.size(); + lolcal_chain_entry.tx.signatures.clear(); + lolcal_chain_entry.tx.attachment.clear(); + + //reassign to db + m_db_transactions.set(h, lolcal_chain_entry); + + ++transactions_pruned; + } + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::prune_ring_signatures_and_attachments_if_need() +{ + CRITICAL_REGION_LOCAL(m_read_lock); + + if(m_db_blocks.size() && m_checkpoints.get_top_checkpoint_height() && m_checkpoints.get_top_checkpoint_height() > m_db_current_pruned_rs_height) + { + LOG_PRINT_CYAN("Starting pruning ring signatues and attachments...", LOG_LEVEL_0); + uint64_t tx_count = 0, sig_count = 0, attach_count = 0; + for(uint64_t height = m_db_current_pruned_rs_height; height < m_db_blocks.size() && height <= m_checkpoints.get_top_checkpoint_height(); height++) + { + bool res = prune_ring_signatures_and_attachments(height, tx_count, sig_count, attach_count); + CHECK_AND_ASSERT_MES(res, false, "failed to prune_ring_signatures_and_attachments for height = " << height); + } + m_db_current_pruned_rs_height = m_checkpoints.get_top_checkpoint_height(); + LOG_PRINT_CYAN("Transaction pruning finished: " << sig_count << " signatures and " << attach_count << " attachments released in " << tx_count << " transactions.", LOG_LEVEL_0); + } + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::clear() +{ + //CRITICAL_REGION_LOCAL(m_read_lock); + m_db.begin_transaction(); + + m_db_blocks.clear(); + m_db_blocks_index.clear(); + m_db_transactions.clear(); + m_db_spent_keys.clear(); + m_db_solo_options.clear(); + initialize_db_solo_options_values(); + m_db_outputs.clear(); + m_db_multisig_outs.clear(); + m_db_aliases.clear(); + m_db_addr_to_alias.clear(); + m_db_per_block_gindex_incs.clear(); + + m_db.commit_transaction(); + + + { + CRITICAL_REGION_LOCAL(m_invalid_blocks_lock); + m_invalid_blocks.clear(); // crypto::hash -> block_extended_info + } + { + CRITICAL_REGION_LOCAL(m_alternative_chains_lock); + m_alternative_chains.clear(); + m_altblocks_keyimages.clear(); + m_alternative_chains_txs.clear(); + } + + + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::reset_and_set_genesis_block(const block& b) +{ + clear(); + block_verification_context bvc = boost::value_initialized(); + add_new_block(b, bvc); + if(!bvc.m_added_to_main_chain || bvc.m_verification_failed) + { + LOG_ERROR("Blockchain reset failed.") + return false; + } + LOG_PRINT_GREEN("Blockchain reset. Genesis block: " << get_block_hash(b) << ", " << misc_utils::get_time_interval_string(m_core_runtime_config.get_core_time() - b.timestamp) << " ago", LOG_LEVEL_0); + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::purge_transaction_keyimages_from_blockchain(const transaction& tx, bool strict_check) +{ + CRITICAL_REGION_LOCAL(m_read_lock); + + struct purge_transaction_visitor: public boost::static_visitor + { + blockchain_storage& m_bcs; + key_images_container& m_spent_keys; + bool m_strict_check; + purge_transaction_visitor(blockchain_storage& bcs, key_images_container& spent_keys, bool strict_check): + m_bcs(bcs), + m_spent_keys(spent_keys), + m_strict_check(strict_check){} + + bool operator()(const txin_to_key& inp) const + { + bool r = m_spent_keys.erase_validate(inp.k_image); + CHECK_AND_ASSERT_MES( !(!r && m_strict_check), false, "purge_transaction_keyimages_from_blockchain: key image " << inp.k_image << " was not found"); + + if(inp.key_offsets.size() == 1) + { + //direct spend detected + if(!m_bcs.update_spent_tx_flags_for_input(inp.amount, inp.key_offsets[0], false)) + { + //internal error + LOG_PRINT_L0("Failed to update_spent_tx_flags_for_input"); + return false; + } + } + + return true; + } + bool operator()(const txin_gen& inp) const + { + return true; + } + bool operator()(const txin_multisig& inp) const + { + if (!m_bcs.update_spent_tx_flags_for_input(inp.multisig_out_id, 0)) + { + LOG_PRINT_L0("update_spent_tx_flags_for_input failed for multisig id " << inp.multisig_out_id << " amount: " << inp.amount); + return false; + } + return true; + } + }; + + BOOST_FOREACH(const txin_v& in, tx.vin) + { + bool r = boost::apply_visitor(purge_transaction_visitor(*this, m_db_spent_keys, strict_check), in); + CHECK_AND_ASSERT_MES(!strict_check || r, false, "failed to process purge_transaction_visitor"); + } + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::purge_transaction_from_blockchain(const crypto::hash& tx_id, uint64_t& fee) +{ + fee = 0; + CRITICAL_REGION_LOCAL(m_read_lock); + + auto tx_res_ptr = m_db_transactions.find(tx_id); + CHECK_AND_ASSERT_MES(tx_res_ptr != m_db_transactions.end(), false, "transaction " << tx_id << " is not found in blockchain index!!"); + const transaction& tx = tx_res_ptr->tx; + + fee = get_tx_fee(tx_res_ptr->tx); + purge_transaction_keyimages_from_blockchain(tx, true); + + bool r = unprocess_blockchain_tx_extra(tx); + CHECK_AND_ASSERT_MES(r, false, "failed to unprocess_blockchain_tx_extra for tx " << tx_id); + + r = unprocess_blockchain_tx_attachments(tx, get_current_blockchain_size(), 0/*TODO: add valid timestamp here in future if need*/); + + bool added_to_the_pool = false; + if(!is_coinbase(tx)) + { + currency::tx_verification_context tvc = AUTO_VAL_INIT(tvc); + added_to_the_pool = m_tx_pool.add_tx(tx, tvc, true, true); + CHECK_AND_ASSERT_MES(added_to_the_pool, false, "failed to add transaction " << tx_id << " to transaction pool"); + } + + bool res = pop_transaction_from_global_index(tx, tx_id); + CHECK_AND_ASSERT_MES_NO_RET(res, "pop_transaction_from_global_index failed for tx " << tx_id); + bool res_erase = m_db_transactions.erase_validate(tx_id); + CHECK_AND_ASSERT_MES_NO_RET(res_erase, "Failed to m_transactions.erase with id = " << tx_id); + + LOG_PRINT_L1("transaction " << tx_id << (added_to_the_pool ? " was removed from blockchain history -> to the pool" : " was removed from blockchain history")); + return res; +} + +//------------------------------------------------------------------ +bool blockchain_storage::purge_block_data_from_blockchain(const block& b, size_t processed_tx_count) +{ + uint64_t total_fee = 0; + return purge_block_data_from_blockchain(b, processed_tx_count, total_fee); +} +//------------------------------------------------------------------ +bool blockchain_storage::purge_block_data_from_blockchain(const block& bl, size_t processed_tx_count, uint64_t& fee_total) +{ + CRITICAL_REGION_LOCAL(m_read_lock); + fee_total = 0; + uint64_t fee = 0; + bool res = true; + CHECK_AND_ASSERT_MES(processed_tx_count <= bl.tx_hashes.size(), false, "wrong processed_tx_count in purge_block_data_from_blockchain"); + for(size_t count = 0; count != processed_tx_count; count++) + { + res = purge_transaction_from_blockchain(bl.tx_hashes[(processed_tx_count -1)- count], fee) && res; + fee_total += fee; + } + + res = purge_transaction_from_blockchain(get_transaction_hash(bl.miner_tx), fee) && res; + return res; +} +//------------------------------------------------------------------ +crypto::hash blockchain_storage::get_top_block_id(uint64_t& height) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + + height = get_top_block_height(); + return get_top_block_id(); +} +//------------------------------------------------------------------ +crypto::hash blockchain_storage::get_top_block_id() const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + crypto::hash id = null_hash; + if(m_db_blocks.size()) + { + auto val_ptr = m_db_blocks.back(); + CHECK_AND_ASSERT_MES(val_ptr, null_hash, "m_blocks.back() returned null"); + get_block_hash(val_ptr->bl, id); + } + return id; +} +//------------------------------------------------------------------ +bool blockchain_storage::get_top_block(block& b) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + CHECK_AND_ASSERT_MES(m_db_blocks.size(), false, "Wrong blockchain state, m_blocks.size()=0!"); + auto val_ptr = m_db_blocks.back(); + CHECK_AND_ASSERT_MES(val_ptr.get(), false, "m_blocks.back() returned null"); + b = val_ptr->bl; + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::get_short_chain_history(std::list& ids)const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + size_t i = 0; + size_t current_multiplier = 1; + size_t sz = m_db_blocks.size(); + if(!sz) + return true; + size_t current_back_offset = 1; + bool genesis_included = false; + while(current_back_offset < sz) + { + ids.push_back(get_block_hash(m_db_blocks[sz-current_back_offset]->bl)); + if(sz-current_back_offset == 0) + genesis_included = true; + if(i < 10) + { + ++current_back_offset; + }else + { + current_back_offset += current_multiplier *= 2; + } + ++i; + } + if(!genesis_included) + ids.push_back(get_block_hash(m_db_blocks[0]->bl)); + + return true; +} +//------------------------------------------------------------------ +crypto::hash blockchain_storage::get_block_id_by_height(uint64_t height) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + if(height >= m_db_blocks.size()) + return null_hash; + + return get_block_hash(m_db_blocks[height]->bl); +} +//------------------------------------------------------------------ +bool blockchain_storage::get_block_by_hash(const crypto::hash &h, block &blk) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + + // try to find block in main chain + auto it = m_db_blocks_index.find(h); + if (m_db_blocks_index.end() != it) + { + blk = m_db_blocks[*it]->bl; + return true; + } + + // try to find block in alternative chain + CRITICAL_REGION_LOCAL1(m_alternative_chains_lock); + + auto it_alt = m_alternative_chains.find(h); + if (m_alternative_chains.end() != it_alt) + { + blk = it_alt->second.bl; + return true; + } + + return false; +} +bool blockchain_storage::is_tx_related_to_altblock(crypto::hash tx_id) const +{ + CRITICAL_REGION_LOCAL1(m_alternative_chains_lock); + auto it = m_alternative_chains_txs.find(tx_id); + return it != m_alternative_chains_txs.end(); +} + +//------------------------------------------------------------------ +bool blockchain_storage::get_block_extended_info_by_hash(const crypto::hash &h, block_extended_info &blk) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + + // try to find block in main chain + auto vptr = m_db_blocks_index.find(h); + if (vptr) + { + return get_block_extended_info_by_height(*vptr, blk); + } + + // try to find block in alternative chain + CRITICAL_REGION_LOCAL1(m_alternative_chains_lock); + auto it_alt = m_alternative_chains.find(h); + if (m_alternative_chains.end() != it_alt) + { + blk = it_alt->second; + return true; + } + + return false; +} +//------------------------------------------------------------------ +bool blockchain_storage::get_block_extended_info_by_height(uint64_t h, block_extended_info &blk) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + + if (h >= m_db_blocks.size()) + return false; + + blk = *m_db_blocks[h]; + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::get_block_by_height(uint64_t h, block &blk) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + if(h >= m_db_blocks.size() ) + return false; + blk = m_db_blocks[h]->bl; + return true; +} +//------------------------------------------------------------------ +// void blockchain_storage::get_all_known_block_ids(std::list &main, std::list &alt, std::list &invalid) const +// { +// CRITICAL_REGION_LOCAL(m_blockchain_lock); +// +// for (auto &v : m_blocks_index) +// main.push_back(v.first); +// +// for (auto &v : m_alternative_chains) +// alt.push_back(v.first); +// +// for(auto &v: m_invalid_blocks) +// invalid.push_back(v.first); +// } +//------------------------------------------------------------------ +bool blockchain_storage::rollback_blockchain_switching(std::list& original_chain, size_t rollback_height) +{ + CRITICAL_REGION_LOCAL(m_read_lock); + //remove failed subchain + for(size_t i = m_db_blocks.size()-1; i >=rollback_height; i--) + { + bool r = pop_block_from_blockchain(); + CHECK_AND_ASSERT_MES(r, false, "PANIC!!! failed to remove block while chain switching during the rollback!"); + } + //return back original chain + BOOST_FOREACH(auto& bl, original_chain) + { + block_verification_context bvc = boost::value_initialized(); + bool r = handle_block_to_main_chain(bl, bvc); + CHECK_AND_ASSERT_MES(r && bvc.m_added_to_main_chain, false, "PANIC!!! failed to add (again) block while chain switching during the rollback!"); + } + + LOG_PRINT_L0("Rollback success."); + return true; +} +//------------------------------------------------------------------ +void blockchain_storage::add_alt_block_txs_hashs(const block& b) +{ + CRITICAL_REGION_LOCAL(m_alternative_chains_lock); + for (const auto& tx_hash : b.tx_hashes) + { + m_alternative_chains_txs[tx_hash]++; + } +} +//------------------------------------------------------------------ +void blockchain_storage::purge_alt_block_txs_hashs(const block& b) +{ + CRITICAL_REGION_LOCAL(m_alternative_chains_lock); + for (const auto& h : b.tx_hashes) + { + auto it = m_alternative_chains_txs.find(h); + if (it == m_alternative_chains_txs.end()) + { + LOG_ERROR("Internal error: tx with hash " << h << " not found in m_alternative_chains_txs while removing block " << get_block_hash(b)); + continue; + } + + if (it->second >= 1) + { + it->second--; + } + else + { + LOG_ERROR("Internal error: tx with hash " << h << " has invalid m_alternative_chains_txs entry (zero count) while removing block " << get_block_hash(b)); + } + if (it->second == 0) + m_alternative_chains_txs.erase(it); + } +} +//------------------------------------------------------------------ +void blockchain_storage::do_erase_altblock(alt_chain_container::iterator it) +{ + purge_altblock_keyimages_from_big_heap(it->second.bl, get_block_hash(it->second.bl)); + purge_alt_block_txs_hashs(it->second.bl); + m_alternative_chains.erase(it); +} +//------------------------------------------------------------------ +bool blockchain_storage::switch_to_alternative_blockchain(alt_chain_type& alt_chain) +{ + CRITICAL_REGION_LOCAL(m_read_lock); + CHECK_AND_ASSERT_MES(validate_blockchain_prev_links(), false, "EPIC FAIL!"); + + CHECK_AND_ASSERT_MES(alt_chain.size(), false, "switch_to_alternative_blockchain: empty chain passed"); + + size_t split_height = alt_chain.front()->second.height; + CHECK_AND_ASSERT_MES(m_db_blocks.size() >= split_height, false, "switch_to_alternative_blockchain: blockchain size is lower than split height" << ENDL + << " alt chain: " << ENDL << print_alt_chain(alt_chain) << ENDL + << " main chain: " << ENDL << get_blockchain_string(m_db_blocks.size() - 10, CURRENCY_MAX_BLOCK_NUMBER) + ); + + //disconnecting old chain + std::list disconnected_chain; + for(size_t i = m_db_blocks.size()-1; i >=split_height; i--) + { + block b = m_db_blocks[i]->bl; + bool r = pop_block_from_blockchain(); + CHECK_AND_ASSERT_MES(r, false, "failed to remove block " << get_block_hash(b) << " @ " << get_block_height(b) << " on chain switching"); + disconnected_chain.push_front(b); + CHECK_AND_ASSERT_MES(validate_blockchain_prev_links(), false, "EPIC FAIL!"); + } + + //connecting new alternative chain + for(auto alt_ch_iter = alt_chain.begin(); alt_ch_iter != alt_chain.end(); alt_ch_iter++) + { + auto ch_ent = *alt_ch_iter; + block_verification_context bvc = boost::value_initialized(); + bool r = handle_block_to_main_chain(ch_ent->second.bl, bvc); + if(!r || !bvc.m_added_to_main_chain) + { + LOG_PRINT_L0("Failed to switch to alternative blockchain"); + rollback_blockchain_switching(disconnected_chain, split_height); + LOG_PRINT_L0("The block was inserted as invalid while connecting new alternative chain, block_id: " << get_block_hash(ch_ent->second.bl)); + + for(; alt_ch_iter != alt_chain.end(); ++alt_ch_iter) + { + add_block_as_invalid((*alt_ch_iter)->second, (*alt_ch_iter)->first); + do_erase_altblock(*alt_ch_iter); + } + CHECK_AND_ASSERT_MES(validate_blockchain_prev_links(), false, "EPIC FAIL!"); + return false; + } + } + + //pushing old chain as alternative chain + for(auto& old_ch_ent : disconnected_chain) + { + block_verification_context bvc = boost::value_initialized(); + bool r = handle_alternative_block(old_ch_ent, get_block_hash(old_ch_ent), bvc); + if(!r) + { + LOG_ERROR("Failed to push ex-main chain blocks to alternative chain "); + rollback_blockchain_switching(disconnected_chain, split_height); + CHECK_AND_ASSERT_MES(validate_blockchain_prev_links(), false, "EPIC FAIL!"); + return false; + } + } + + //removing all_chain entries from alternative chain + for(auto ch_ent : alt_chain) + { + do_erase_altblock(ch_ent); + } + + LOG_PRINT_GREEN("REORGANIZE SUCCESS! on height: " << split_height << ", new blockchain size: " << m_db_blocks.size(), LOG_LEVEL_0); + return true; +} +//------------------------------------------------------------------ +wide_difficulty_type blockchain_storage::get_next_diff_conditional(bool pos) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + std::vector timestamps; + std::vector commulative_difficulties; + size_t count = 0; + if (!m_db_blocks.size()) + return DIFFICULTY_STARTER; + //skip genesis timestamp + uint64_t stop_ind = 0; + uint64_t blocks_size = m_db_blocks.size(); + for (uint64_t cur_ind = blocks_size - 1; cur_ind != stop_ind && count < DIFFICULTY_WINDOW; cur_ind--) + { + auto beiptr = m_db_blocks[cur_ind]; + + bool is_pos_bl = is_pos_block(beiptr->bl); + if (pos != is_pos_bl) + continue; + timestamps.push_back(beiptr->bl.timestamp); + commulative_difficulties.push_back(beiptr->cumulative_diff_precise); + ++count; + } + wide_difficulty_type& dif = pos ? m_cached_next_pos_difficulty : m_cached_next_pow_difficulty; + return dif = next_difficulty(timestamps, commulative_difficulties, pos ? DIFFICULTY_POS_TARGET : DIFFICULTY_POW_TARGET); +} +//------------------------------------------------------------------ +wide_difficulty_type blockchain_storage::get_next_diff_conditional2(bool pos, const alt_chain_type& alt_chain, uint64_t split_height) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + std::vector timestamps; + std::vector commulative_difficulties; + size_t count = 0; + if (!m_db_blocks.size()) + return DIFFICULTY_STARTER; + + auto cb = [&](const block_extended_info& bei, bool is_main){ + if (!bei.height) + return false; + bool is_pos_bl = is_pos_block(bei.bl); + if (pos != is_pos_bl) + return true; + timestamps.push_back(bei.bl.timestamp); + commulative_difficulties.push_back(bei.cumulative_diff_precise); + ++count; + if (count >= DIFFICULTY_WINDOW) + return false; + return true; + }; + enum_blockchain(cb, alt_chain, split_height); + return next_difficulty(timestamps, commulative_difficulties, pos ? DIFFICULTY_POS_TARGET : DIFFICULTY_POW_TARGET); +} +//------------------------------------------------------------------ +wide_difficulty_type blockchain_storage::get_cached_next_difficulty(bool pos) const +{ + wide_difficulty_type res = pos ? m_cached_next_pos_difficulty : m_cached_next_pow_difficulty; + if (!res) + { + get_next_diff_conditional(pos); + res = pos ? m_cached_next_pos_difficulty : m_cached_next_pow_difficulty; + } + return res; +} +//------------------------------------------------------------------ +std::shared_ptr blockchain_storage::get_last_block_of_type(bool looking_for_pos, const alt_chain_type& alt_chain, uint64_t split_height) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + std::shared_ptr pbei(nullptr); + + auto cb = [&](const block_extended_info& bei_local, bool is_main){ + if (looking_for_pos == is_pos_block(bei_local.bl)) + { + pbei.reset(new block_extended_info(bei_local)); + return false; + } + return true; + }; + + + enum_blockchain(cb, alt_chain, split_height); + return pbei; +} +//------------------------------------------------------------------ +wide_difficulty_type blockchain_storage::get_next_difficulty_for_alternative_chain(const alt_chain_type& alt_chain, block_extended_info& bei, bool pos) const +{ + std::vector timestamps; + std::vector commulative_difficulties; + + for (auto it = alt_chain.rbegin(); it != alt_chain.rend() && timestamps.size() < DIFFICULTY_BLOCKS_COUNT; it++) + { + bool is_pos_bl = is_pos_block((*it)->second.bl); + if (pos != is_pos_bl) + continue; + timestamps.push_back((*it)->second.bl.timestamp); + commulative_difficulties.push_back((*it)->second.cumulative_diff_precise); + } + + size_t main_chain_start_offset = (alt_chain.size() ? alt_chain.front()->second.height : bei.height)-1; + + for (uint64_t i = main_chain_start_offset; i != 0 && timestamps.size() < DIFFICULTY_BLOCKS_COUNT; --i) + { + bool is_pos_bl = is_pos_block(m_db_blocks[i]->bl); + if (pos != is_pos_bl) + continue; + + timestamps.push_back(m_db_blocks[i]->bl.timestamp); + commulative_difficulties.push_back(m_db_blocks[i]->cumulative_diff_precise); + } + + return next_difficulty(timestamps, commulative_difficulties, pos ? DIFFICULTY_POS_TARGET:DIFFICULTY_POW_TARGET); +} +//------------------------------------------------------------------ +bool blockchain_storage::prevalidate_miner_transaction(const block& b, uint64_t height, bool pos) const +{ + CHECK_AND_ASSERT_MES((pos ? (b.miner_tx.vin.size() == 2) : (b.miner_tx.vin.size() == 1)), false, "coinbase transaction in the block has no inputs"); + CHECK_AND_ASSERT_MES(b.miner_tx.vin[0].type() == typeid(txin_gen), false, "coinbase transaction in the block has the wrong type"); + if(boost::get(b.miner_tx.vin[0]).height != height) + { + LOG_PRINT_RED_L0("The miner transaction in block has invalid height: " << boost::get(b.miner_tx.vin[0]).height << ", expected: " << height); + return false; + } + if (pos) + { + CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(txin_to_key), false, "coinstake transaction in the block has the wrong type"); + } + + CHECK_AND_ASSERT_MES(get_tx_unlock_time(b.miner_tx) == height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW, + false, + "coinbase transaction has wrong unlock time: " << get_tx_unlock_time(b.miner_tx) << ", expected: " << height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + + //check outs overflow + if(!check_outs_overflow(b.miner_tx)) + { + LOG_PRINT_RED_L0("miner transaction have money overflow in block " << get_block_hash(b)); + return false; + } + + CHECK_AND_ASSERT_MES(b.miner_tx.attachment.empty(), false, "coinbase transaction has attachments; attachments are not allowed for coinbase transactions."); + + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::validate_miner_transaction(const block& b, + size_t cumulative_block_size, + uint64_t fee, + uint64_t& base_reward, + uint64_t already_generated_coins) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + //validate reward + uint64_t money_in_use = get_outs_money_amount(b.miner_tx); + + uint64_t pos_income = 0; + if (is_pos_block(b)) + { + CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(txin_to_key), false, "Wrong miner tx_in"); + pos_income = boost::get(b.miner_tx.vin[1]).amount; + } + + std::vector last_blocks_sizes; + get_last_n_blocks_sizes(last_blocks_sizes, CURRENCY_REWARD_BLOCKS_WINDOW); + size_t blocks_size_median = misc_utils::median(last_blocks_sizes); + if (!get_block_reward(is_pos_block(b), blocks_size_median, cumulative_block_size, already_generated_coins, base_reward, get_block_height(b))) + { + LOG_PRINT_L0("block size " << cumulative_block_size << " is bigger than allowed for this blockchain"); + return false; + } + if (base_reward + pos_income + fee < money_in_use) + { + LOG_ERROR("coinbase transaction spend too much money (" << print_money(money_in_use) << "). Block reward is " << print_money(base_reward + pos_income + fee) << "(" << print_money(base_reward) << "+" << print_money(pos_income) << "+" << print_money(fee) + << ", blocks_size_median = " << blocks_size_median + << ", cumulative_block_size = " << cumulative_block_size + << ", fee = " << fee + << ", already_generated_coins = " << already_generated_coins + << "), tx:"); + LOG_PRINT_L0(currency::obj_to_json_str(b.miner_tx)); + return false; + } + if (base_reward + pos_income + fee != money_in_use) + { + LOG_ERROR("coinbase transaction doesn't use full amount of block reward: spent: (" << print_money(money_in_use) << "). Block reward is " << print_money(base_reward + pos_income + fee) << "(" << print_money(base_reward) << "+" << print_money(pos_income) << "+" << print_money(fee) + << ", blocks_size_median = " << blocks_size_median + << ", cumulative_block_size = " << cumulative_block_size + << ", fee = " << fee + << ", already_generated_coins = " << already_generated_coins + << "), tx:"); + LOG_PRINT_L0(currency::obj_to_json_str(b.miner_tx)); + return false; + } + LOG_PRINT_MAGENTA("Mining tx verification ok, blocks_size_median = " << blocks_size_median, LOG_LEVEL_2); + return true; +} +//------------------------------------------------------------------ +blockchain_storage::performnce_data& blockchain_storage::get_performnce_data()const +{ + m_db.get_backend()->get_stat_info(m_performance_data.si); + return m_performance_data; +} +//------------------------------------------------------------------ +bool blockchain_storage::get_backward_blocks_sizes(size_t from_height, std::vector& sz, size_t count)const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + CHECK_AND_ASSERT_MES(from_height < m_db_blocks.size(), false, "Internal error: get_backward_blocks_sizes called with from_height=" << from_height << ", blockchain height = " << m_db_blocks.size()); + + size_t start_offset = (from_height+1) - std::min((from_height+1), count); + for(size_t i = start_offset; i != from_height+1; i++) + sz.push_back(m_db_blocks[i]->block_cumulative_size); + + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::get_last_n_blocks_sizes(std::vector& sz, size_t count) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + if(!m_db_blocks.size()) + return true; + return get_backward_blocks_sizes(m_db_blocks.size() -1, sz, count); +} +//------------------------------------------------------------------ +uint64_t blockchain_storage::get_current_comulative_blocksize_limit() const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + return m_db_current_block_cumul_sz_limit; +} +//------------------------------------------------------------------ +bool blockchain_storage::create_block_template(block& b, + const account_public_address& miner_address, + wide_difficulty_type& diffic, + uint64_t& height, + const blobdata& ex_nonce) const +{ + return create_block_template(b, miner_address, miner_address, diffic, height, ex_nonce, false, pos_entry()); +} +//------------------------------------------------------------------ +bool blockchain_storage::create_block_template(block& b, + const account_public_address& miner_address, + const account_public_address& stakeholder_address, + wide_difficulty_type& diffic, + uint64_t& height, + const blobdata& ex_nonce, + bool pos, + const pos_entry& pe, + fill_block_template_func_t custom_fill_block_template_func /* = nullptr */) const +{ + size_t median_size; + uint64_t already_generated_coins; + CRITICAL_REGION_BEGIN(m_read_lock); + b.major_version = CURRENT_BLOCK_MAJOR_VERSION; + b.minor_version = CURRENT_BLOCK_MINOR_VERSION; + b.prev_id = get_top_block_id(); + b.timestamp = m_core_runtime_config.get_core_time(); + b.nonce = 0; + b.flags = 0; + if (pos) + { + b.flags |= CURRENCY_BLOCK_FLAG_POS_BLOCK; + b.timestamp = 0; + } + + diffic = get_next_diff_conditional(pos); + + CHECK_AND_ASSERT_MES(diffic, false, "difficulty owverhead."); + + + height = m_db_blocks.size(); + + median_size = m_db_current_block_cumul_sz_limit / 2; + already_generated_coins = m_db_blocks.back()->already_generated_coins; + + CRITICAL_REGION_END(); + + size_t txs_size; + uint64_t fee; + bool block_filled = false; + if (custom_fill_block_template_func == nullptr) + block_filled = m_tx_pool.fill_block_template(b, pos, median_size, already_generated_coins, txs_size, fee, height); + else + block_filled = (*custom_fill_block_template_func)(b, pos, median_size, already_generated_coins, txs_size, fee, height); + + if (!block_filled) + return false; + + /* + instead of complicated two-phase template construction and adjustment of cumulative size with block reward we + use CURRENCY_COINBASE_BLOB_RESERVED_SIZE as penalty-free coinbase transaction reservation. + */ + bool r = construct_miner_tx(height, median_size, already_generated_coins, + txs_size, + fee, + miner_address, + stakeholder_address, + b.miner_tx, ex_nonce, + CURRENCY_MINER_TX_MAX_OUTS, + pos, + pe); + CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, first chance"); + uint64_t coinbase_size = get_object_blobsize(b.miner_tx); + // "- 100" - to reserve room for PoS additions into miner tx + CHECK_AND_ASSERT_MES(coinbase_size < CURRENCY_COINBASE_BLOB_RESERVED_SIZE - 100, false, "Failed to get block template (coinbase_size = " << coinbase_size << ") << coinbase structue: " + << ENDL << obj_to_json_str(b.miner_tx)); + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::print_transactions_statistics() const +{ + LOG_ERROR("print_transactions_statistics not implemented yet"); +// CRITICAL_REGION_LOCAL(m_blockchain_lock); +// LOG_PRINT_L0("Started to collect transaction statistics, pleas wait..."); +// size_t total_count = 0; +// size_t coinbase_count = 0; +// size_t total_full_blob = 0; +// size_t total_cropped_blob = 0; +// for(auto tx_entry: m_db_transactions) +// { +// ++total_count; +// if(is_coinbase(tx_entry.second.tx)) +// ++coinbase_count; +// else +// { +// total_full_blob += get_object_blobsize(tx_entry.second.tx); +// transaction tx = tx_entry.second.tx; +// tx.signatures.clear(); +// total_cropped_blob += get_object_blobsize(tx); +// } +// } +// LOG_PRINT_L0("Done" << ENDL +// << "total transactions: " << total_count << ENDL +// << "coinbase transactions: " << coinbase_count << ENDL +// << "avarage size of transaction: " << total_full_blob/(total_count-coinbase_count) << ENDL +// << "avarage size of transaction without ring signatures: " << total_cropped_blob/(total_count-coinbase_count) << ENDL +// ); + return true; +} +void blockchain_storage::reset_db_cache() const +{ + m_db_blocks.clear_cache(); + m_db_blocks_index.clear_cache(); + m_db_transactions.clear_cache(); + m_db_spent_keys.clear_cache(); + m_db_solo_options.clear_cache(); + m_db_multisig_outs.clear_cache(); + m_db_aliases.clear_cache(); + m_db_addr_to_alias.clear_cache(); + +} +//------------------------------------------------------------------ +void blockchain_storage::clear_altblocks() +{ + CRITICAL_REGION_LOCAL(m_alternative_chains_lock); + m_alternative_chains.clear(); + m_alternative_chains_txs.clear(); + m_altblocks_keyimages.clear(); +} +//------------------------------------------------------------------ +bool blockchain_storage::complete_timestamps_vector(uint64_t start_top_height, std::vector& timestamps) +{ + + if(timestamps.size() >= BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW) + return true; + + CRITICAL_REGION_LOCAL(m_read_lock); + size_t need_elements = BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW - timestamps.size(); + CHECK_AND_ASSERT_MES(start_top_height < m_db_blocks.size(), false, "internal error: passed start_height = " << start_top_height << " not less then m_blocks.size()=" << m_db_blocks.size()); + size_t stop_offset = start_top_height > need_elements ? start_top_height - need_elements:0; + do + { + timestamps.push_back(m_db_blocks[start_top_height]->bl.timestamp); + if(start_top_height == 0) + break; + --start_top_height; + }while(start_top_height != stop_offset); + return true; +} +//------------------------------------------------------------------ +std::string blockchain_storage::print_alt_chain(alt_chain_type alt_chain) +{ + std::stringstream ss; + for (auto it = alt_chain.begin(); it != alt_chain.end(); it++) + { + ss << "[" << (*it)->second.height << "] " << (*it)->first << "(cumul_dif: " << (*it)->second.cumulative_diff_adjusted << "), parent_id: " << (*it)->second.bl.prev_id << ENDL; + } + return ss.str(); +} +//------------------------------------------------------------------ +bool blockchain_storage::append_altblock_keyimages_to_big_heap(const crypto::hash& block_id, const std::set& alt_block_keyimages) +{ + for (auto& ki : alt_block_keyimages) + m_altblocks_keyimages[ki].push_back(block_id); + + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::purge_keyimage_from_big_heap(const crypto::key_image& ki, const crypto::hash& id) +{ + auto it = m_altblocks_keyimages.find(ki); + CHECK_AND_ASSERT_MES(it != m_altblocks_keyimages.end(), false, "internal error: keyimage " << ki + << "from altblock " << id << "not found in m_altblocks_keyimages in purge_keyimage_from_big_heap"); + + //TODO: at the moment here is simple liner algo since having the same txs in few altblocks is rare case + std::list& ki_blocks_ids = it->second; + bool found = false; + for (auto it_in_blocks = ki_blocks_ids.begin(); it_in_blocks != ki_blocks_ids.end(); it_in_blocks++) + { + if (*it_in_blocks == id) + { + //found, erase this entry + ki_blocks_ids.erase(it_in_blocks); + found = true; + break; + } + } + CHECK_AND_ASSERT_MES(found, false, "internal error: keyimage " << ki + << "from altblock " << id << "not found in m_altblocks_keyimages in purge_keyimage_from_big_heap"); + if (!ki_blocks_ids.size()) + m_altblocks_keyimages.erase(it); + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::purge_altblock_keyimages_from_big_heap(const block& b, const crypto::hash& id) +{ + if (is_pos_block(b)) + { + CHECK_AND_ASSERT_MES(b.miner_tx.vin.size()>=2, false, "paranoid check failed"); + CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(txin_to_key), false, "paranoid type check failed"); + purge_keyimage_from_big_heap(boost::get(b.miner_tx.vin[1]).k_image, id); + } + for (auto tx_id : b.tx_hashes) + { + std::shared_ptr tx_ptr; + if (!get_transaction_from_pool_or_db(tx_id, tx_ptr)) + { + LOG_ERROR("failed to get alt block tx " << tx_id << " on block detach from alts"); + continue; + } + transaction& tx = *tx_ptr; + for (size_t n = 0; n < tx.vin.size(); ++n) + { + if (tx.vin[n].type() == typeid(txin_to_key)) + { + purge_keyimage_from_big_heap(boost::get(tx.vin[n]).k_image, id); + } + } + } + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::handle_alternative_block(const block& b, const crypto::hash& id, block_verification_context& bvc) +{ + uint64_t coinbase_height = get_block_height(b); + if (m_checkpoints.is_height_passed_zone(coinbase_height, get_top_block_height())) + { + LOG_PRINT_RED_L0("Block with id: " << id << "[" << coinbase_height << "]" << ENDL << " for alternative chain, is under checkpoint zone, declined"); + bvc.m_verification_failed = true; + return false; + } + + TRY_ENTRY(); + + + CRITICAL_REGION_LOCAL(m_read_lock); + CRITICAL_REGION_LOCAL1(m_alternative_chains_lock); + + //block is not related with head of main chain + //first of all - look in alternative chains container + + auto ptr_main_prev = m_db_blocks_index.find(b.prev_id); + auto it_prev = m_alternative_chains.find(b.prev_id); + if (it_prev != m_alternative_chains.end() || ptr_main_prev != m_db_blocks_index.end()) + { + alt_chain_type alt_chain; + { + //we have new block in alternative chain + //build alternative subchain, front -> mainchain, back -> alternative head + alt_chain_container::iterator alt_it = it_prev; //m_alternative_chains.find() + std::vector timestamps; + while (alt_it != m_alternative_chains.end()) + { + alt_chain.push_front(alt_it); + timestamps.push_back(alt_it->second.bl.timestamp); + alt_it = m_alternative_chains.find(alt_it->second.bl.prev_id); + } + + if (alt_chain.size()) + { + //make sure that it has right connection to main chain + CHECK_AND_ASSERT_MES_CUSTOM(m_db_blocks.size() >= alt_chain.front()->second.height, false, bvc.m_verification_failed = true, "main blockchain wrong height: m_db_blocks.size() = " << m_db_blocks.size() + << " and alt_chain.front()->second.height = " << alt_chain.front()->second.height + << " for block " << id << ", prev_id=" << b.prev_id << ENDL + << " alt chain: " << ENDL << print_alt_chain(alt_chain) << ENDL + << " main chain: " << ENDL << get_blockchain_string(m_db_blocks.size() - 10, CURRENCY_MAX_BLOCK_NUMBER) + ); + + crypto::hash h = null_hash; + get_block_hash(m_db_blocks[alt_chain.front()->second.height - 1]->bl, h); + CHECK_AND_ASSERT_MES_CUSTOM(h == alt_chain.front()->second.bl.prev_id, false, bvc.m_verification_failed = true, "alternative chain have wrong connection to main chain"); + complete_timestamps_vector(alt_chain.front()->second.height - 1, timestamps); + } + else + { + CHECK_AND_ASSERT_MES_CUSTOM(ptr_main_prev != m_db_blocks_index.end(), false, bvc.m_verification_failed = true, "internal error: broken imperative condition it_main_prev != m_blocks_index.end()"); + complete_timestamps_vector(*ptr_main_prev, timestamps); + } + //check timestamp correct + if (!check_block_timestamp(std::move(timestamps), b)) + { + LOG_PRINT_RED_L0("Block with id: " << id + << ENDL << " for alternative chain, have invalid timestamp: " << b.timestamp); + //add_block_as_invalid(b, id);//do not add blocks to invalid storage before proof of work check was passed + bvc.m_verification_failed = true; + return false; + } + } + + alt_block_extended_info abei = AUTO_VAL_INIT(abei); + abei.bl = b; + abei.height = alt_chain.size() ? it_prev->second.height + 1 : *ptr_main_prev + 1; + CHECK_AND_ASSERT_MES_CUSTOM(coinbase_height == abei.height, false, bvc.m_verification_failed = true, "block coinbase height doesn't match with altchain height, declined"); + uint64_t connection_height = alt_chain.size() ? alt_chain.front()->second.height:abei.height; + CHECK_AND_ASSERT_MES_CUSTOM(connection_height, false, bvc.m_verification_failed = true, "INTERNAL ERROR: Wrong connection_height==0 in handle_alternative_block"); + + if (!m_checkpoints.is_in_checkpoint_zone(abei.height)) + { + m_is_in_checkpoint_zone = false; + } + else + { + m_is_in_checkpoint_zone = true; + if (!m_checkpoints.check_block(abei.height, id)) + { + LOG_ERROR("CHECKPOINT VALIDATION FAILED"); + bvc.m_verification_failed = true; + return false; + } + } + + bool pos_block = is_pos_block(abei.bl); + //check if PoS block allowed on this height + CHECK_AND_ASSERT_MES_CUSTOM(!(pos_block && abei.height < m_core_runtime_config.pos_minimum_heigh), false, bvc.m_verification_failed = true, "PoS block is not allowed on this height"); + + + //wide_difficulty_type current_diff = get_next_difficulty_for_alternative_chain(alt_chain, bei, pos_block); + wide_difficulty_type current_diff = get_next_diff_conditional2(pos_block, alt_chain, connection_height); + + CHECK_AND_ASSERT_MES_CUSTOM(current_diff, false, bvc.m_verification_failed = true, "!!!!!!! DIFFICULTY OVERHEAD !!!!!!!"); + + crypto::hash proof_of_work = null_hash; + uint64_t pos_amount = 0; + wide_difficulty_type pos_diff_final = 0; + if (pos_block) + { + //POS + bool res = validate_pos_block(abei.bl, current_diff, pos_amount, pos_diff_final, abei.stake_hash, id, true, alt_chain, connection_height); + CHECK_AND_ASSERT_MES_CUSTOM(res, false, bvc.m_verification_failed = true, "Failed to validate_pos_block on alternative block, height = " + << abei.height + << ", block id: " << get_block_hash(abei.bl)); + } + else + { + proof_of_work = get_block_longhash(abei.bl); + if (!check_hash(proof_of_work, current_diff)) + { + LOG_PRINT_RED_L0("Block with id: " << id + << ENDL << " for alternative chain, have not enough proof of work: " << proof_of_work + << ENDL << " expected difficulty: " << current_diff); + bvc.m_verification_failed = true; + return false; + } + // + } + + if (!prevalidate_miner_transaction(b, abei.height, pos_block)) + { + LOG_PRINT_RED_L0("Block with id: " << string_tools::pod_to_hex(id) + << " (as alternative) have wrong miner transaction."); + bvc.m_verification_failed = true; + return false; + } + std::set alt_block_keyimages; + uint64_t ki_lookup_total = 0; + if (!validate_alt_block_txs(b, id, alt_block_keyimages, abei, alt_chain, connection_height, ki_lookup_total)) + { + LOG_PRINT_RED_L0("Alternative block " << id << " @ " << abei.height << " has invalid transactions. Rejected."); + bvc.m_verification_failed = true; + return false; + } + + abei.difficulty = current_diff; + wide_difficulty_type cumulative_diff_delta = 0; + abei.cumulative_diff_adjusted = alt_chain.size() ? it_prev->second.cumulative_diff_adjusted : m_db_blocks[*ptr_main_prev]->cumulative_diff_adjusted; + + if (pos_block) + cumulative_diff_delta = get_adjusted_cumulative_difficulty_for_next_alt_pos(alt_chain, abei.height, current_diff, connection_height); + else + cumulative_diff_delta = current_diff; + + size_t sequence_factor = get_current_sequence_factor_for_alt(alt_chain, pos_block, connection_height); + if (abei.height >= m_core_runtime_config.pos_minimum_heigh) + cumulative_diff_delta = correct_difficulty_with_sequence_factor(sequence_factor, cumulative_diff_delta); + + abei.cumulative_diff_adjusted += cumulative_diff_delta; + + abei.cumulative_diff_precise = get_last_alt_x_block_cumulative_precise_difficulty(alt_chain, abei.height, pos_block); + abei.cumulative_diff_precise += current_diff; + +#ifdef _DEBUG + auto i_dres = m_alternative_chains.find(id); + CHECK_AND_ASSERT_MES_CUSTOM(i_dres == m_alternative_chains.end(), false, bvc.m_verification_failed = true, "insertion of new alternative block " << id << " returned as it already exist"); +#endif + auto i_res = m_alternative_chains.insert(alt_chain_container::value_type(id, abei)); + CHECK_AND_ASSERT_MES_CUSTOM(i_res.second, false, bvc.m_verification_failed = true, "insertion of new alternative block " << id << " returned as it already exist"); + append_altblock_keyimages_to_big_heap(id, alt_block_keyimages); + add_alt_block_txs_hashs(i_res.first->second.bl); + alt_chain.push_back(i_res.first); + //check if difficulty bigger then in main chain + + bvc.height_difference = get_top_block_height() >= abei.height ? get_top_block_height() - abei.height : 0; + + crypto::hash proof = null_hash; + std::stringstream ss_pow_pos_info; + if (pos_block) + { + ss_pow_pos_info << "PoS:\t" << abei.stake_hash << ", stake amount: " << print_money(pos_amount) << ", final_difficulty: " << pos_diff_final; + proof = abei.stake_hash; + } + else + { + ss_pow_pos_info << "PoW:\t" << proof_of_work; + proof = proof_of_work; + } + + LOG_PRINT_BLUE("----- BLOCK ADDED AS ALTERNATIVE ON HEIGHT " << abei.height << (pos_block ? " [PoS] Sq: " : " [PoW] Sq: ") << sequence_factor << ", altchain sz: " << alt_chain.size() << ", split h: " << connection_height + << ENDL << "id:\t" << id + << ENDL << "prev\t" << abei.bl.prev_id + << ENDL << ss_pow_pos_info.str() + << ENDL << "HEIGHT " << abei.height << ", difficulty: " << abei.difficulty << ", cumul_diff_precise: " << abei.cumulative_diff_precise << ", cumul_diff_adj: " << abei.cumulative_diff_adjusted << " (current mainchain cumul_diff_adj: " << m_db_blocks.back()->cumulative_diff_adjusted << ", ki lookup total: " << ki_lookup_total <<")" + , LOG_LEVEL_0); + + if (is_reorganize_required(*m_db_blocks.back(), abei, proof)) + { + auto a = epee::misc_utils::create_scope_leave_handler([&]() { m_is_reorganize_in_process = false; }); + CHECK_AND_ASSERT_THROW_MES(!m_is_reorganize_in_process, "Detected recursive reorganzie"); + m_is_reorganize_in_process = true; + //do reorganize! + LOG_PRINT_GREEN("###### REORGANIZE on height: " << alt_chain.front()->second.height << " of " << m_db_blocks.size() - 1 << " with cumulative_diff_adjusted " << m_db_blocks.back()->cumulative_diff_adjusted + << ENDL << " alternative blockchain size: " << alt_chain.size() << " with cumulative_diff_adjusted " << abei.cumulative_diff_adjusted, LOG_LEVEL_0); + bool r = switch_to_alternative_blockchain(alt_chain); + if(r) + bvc.m_added_to_main_chain = true; + else + bvc.m_verification_failed = true; + return r; + } + bvc.added_to_altchain = true; + return true; + }else + { + //block orphaned + bvc.m_marked_as_orphaned = true; + LOG_PRINT_RED_L0("Block recognized as orphaned and rejected, id = " << id << "," << ENDL << "parent id = " << b.prev_id << ENDL << "height = " << coinbase_height); + } + + CHECK_AND_ASSERT_MES(validate_blockchain_prev_links(), false, "EPIC FAIL!"); + return true; + CATCH_ENTRY_CUSTOM("blockchain_storage::handle_alternative_block", bvc.m_verification_failed = true, false); +} +//------------------------------------------------------------------ +bool blockchain_storage::is_reorganize_required(const block_extended_info& main_chain_bei, const block_extended_info& alt_chain_bei, const crypto::hash& proof_alt) +{ + if (main_chain_bei.cumulative_diff_adjusted < alt_chain_bei.cumulative_diff_adjusted) + return true; + else if (main_chain_bei.cumulative_diff_adjusted > alt_chain_bei.cumulative_diff_adjusted) + return false; + else // main_chain_bei.cumulative_diff_adjusted == alt_chain_bei.cumulative_diff_adjusted + { + if (!is_pos_block(main_chain_bei.bl)) + return false; // do not reorganize on the same cummul diff if it's a PoW block + + //in case of simultaneous PoS blocks are happened on the same height (quite common for PoS) + //we also try to weight them to guarantee consensus in network + if (std::memcmp(&main_chain_bei.stake_hash, &proof_alt, sizeof(main_chain_bei.stake_hash)) >= 0) + return false; + + LOG_PRINT_L2("[is_reorganize_required]:TRUE, \"by order of memcmp\" main_stake_hash:" << &main_chain_bei.stake_hash << ", alt_stake_hash" << proof_alt); + return true; + } +} +//------------------------------------------------------------------ +bool blockchain_storage::pre_validate_relayed_block(block& bl, block_verification_context& bvc, const crypto::hash& id)const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + if (!(bl.prev_id == get_top_block_id())) + { + bvc.m_added_to_main_chain = false; + bvc.m_verification_failed = false; + return true; + } + //check proof of work + bool is_pos_bl = is_pos_block(bl); + wide_difficulty_type current_diffic = get_next_diff_conditional(is_pos_bl); + CHECK_AND_ASSERT_MES_CUSTOM(current_diffic, false, bvc.m_verification_failed = true, "!!!!!!!!! difficulty overhead !!!!!!!!!"); + crypto::hash proof_hash = AUTO_VAL_INIT(proof_hash); + if (is_pos_bl) + { + wide_difficulty_type this_coin_diff = 0; + uint64_t amount = 0; + bool r = validate_pos_block(bl, current_diffic, amount, this_coin_diff, proof_hash, id, false); + CHECK_AND_ASSERT_MES_CUSTOM(r, false, bvc.m_verification_failed = true, "validate_pos_block failed!!"); + bvc.m_added_to_main_chain = true; + } + else + { + + proof_hash = get_block_longhash(bl); + + if (!check_hash(proof_hash, current_diffic)) + { + LOG_PRINT_L0("Block with id: " << id << ENDL + << " : " << proof_hash << ENDL + << "unexpected difficulty: " << current_diffic); + bvc.m_verification_failed = true; + bvc.m_added_to_main_chain = true; + return false; + } + } + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::get_blocks(uint64_t start_offset, size_t count, std::list& blocks, std::list& txs) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + if(start_offset >= m_db_blocks.size()) + return false; + for(size_t i = start_offset; i < start_offset + count && i < m_db_blocks.size();i++) + { + blocks.push_back(m_db_blocks[i]->bl); + std::list missed_ids; + get_transactions(m_db_blocks[i]->bl.tx_hashes, txs, missed_ids); + CHECK_AND_ASSERT_MES(!missed_ids.size(), false, "have missed transactions in own block in main blockchain"); + } + + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::get_tx_rpc_details(const crypto::hash& h, tx_rpc_extended_info& tei, uint64_t timestamp, bool is_short) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + auto tx_ptr = m_db_transactions.get(h); + if (!tx_ptr) + { + tei.keeper_block = -1; // tx is not confirmed yet, probably it's in the pool + return false; + } + + + if (tx_ptr && !timestamp) + { + timestamp = get_actual_timestamp(m_db_blocks[tx_ptr->m_keeper_block_height]->bl); + } + tei.keeper_block = static_cast(tx_ptr->m_keeper_block_height); + fill_tx_rpc_details(tei, tx_ptr->tx, &(*tx_ptr), h, timestamp, is_short); + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::search_by_id(const crypto::hash& id, std::list& res) const +{ + auto block_ptr = m_db_blocks_index.get(id); + if (block_ptr) + { + res.push_back("block"); + } + + auto tx_ptr = m_db_transactions.get(id); + if (tx_ptr) + { + res.push_back("tx"); + } + + auto ki_ptr = m_db_spent_keys.get( *reinterpret_cast(&id)); + if (ki_ptr) + { + res.push_back("key_image"); + } + + auto ms_ptr = m_db_multisig_outs.get(id); + if (ms_ptr) + { + res.push_back(std::string("multisig_id:") + epee::string_tools::pod_to_hex(ms_ptr->tx_id) + ":" + std::to_string(ms_ptr->out_no)); + } + + if (m_alternative_chains.end() != m_alternative_chains.find(id)) + { + res.push_back("alt_block"); + } + + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::get_global_index_details(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES_BY_AMOUNT::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES_BY_AMOUNT::response & resp) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + try + { + auto out_ptr = m_db_outputs.get_subitem(req.amount, req.i); // get_subitem can rise an out_of_range exception + if (!out_ptr) + return false; + resp.tx_id = out_ptr->tx_id; + resp.out_no = out_ptr->out_no; + return true; + } + catch (std::out_of_range&) + { + return false; + } +} +//------------------------------------------------------------------ +bool blockchain_storage::get_multisig_id_details(const COMMAND_RPC_GET_MULTISIG_INFO::request& req, COMMAND_RPC_GET_MULTISIG_INFO::response & resp) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + return get_multisig_id_details(req.ms_id, resp.tx_id, resp.out_no); +} +//------------------------------------------------------------------ +bool blockchain_storage::get_multisig_id_details(const crypto::hash& ms_id, crypto::hash& tx_id, uint64_t& out_no) const +{ + auto out_ptr = m_db_multisig_outs.get(ms_id); + if (!out_ptr) + return false; + + tx_id = out_ptr->tx_id; + out_no = out_ptr->out_no; + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::get_main_block_rpc_details(uint64_t i, block_rpc_extended_info& bei) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + auto core_bei_ptr = m_db_blocks[i]; + crypto::hash id = get_block_hash(core_bei_ptr->bl); + bei.is_orphan = false; + bei.total_fee = 0; + bei.total_txs_size = 0; + if (true/*!ignore_transactions*/) + { + crypto::hash coinbase_id = get_transaction_hash(core_bei_ptr->bl.miner_tx); + //load transactions details + bei.transactions_details.push_back(tx_rpc_extended_info()); + get_tx_rpc_details(coinbase_id, bei.transactions_details.back(), get_actual_timestamp(core_bei_ptr->bl), true); + for (auto& h : core_bei_ptr->bl.tx_hashes) + { + bei.transactions_details.push_back(tx_rpc_extended_info()); + get_tx_rpc_details(h, bei.transactions_details.back(), get_actual_timestamp(core_bei_ptr->bl), true); + bei.total_fee += bei.transactions_details.back().fee; + bei.total_txs_size += bei.transactions_details.back().blob_size; + } + } + fill_block_rpc_details(bei, *core_bei_ptr, id); + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::get_main_block_rpc_details(const crypto::hash& id, block_rpc_extended_info& bei) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + auto iptr = m_db_blocks_index.get(id); + if (!iptr) + return false; + return get_main_block_rpc_details(*iptr, bei); +} +//------------------------------------------------------------------ +bool blockchain_storage::get_alt_blocks_rpc_details(uint64_t start_offset, uint64_t count, std::vector& blocks) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + CRITICAL_REGION_LOCAL1(m_alternative_chains_lock); + + if (start_offset >= m_alternative_chains.size() || count == 0) + return true; // empty result + + if (start_offset + count >= m_alternative_chains.size()) + count = m_alternative_chains.size() - start_offset; // correct count if it's too big + + // collect iterators to all the alt blocks for speedy sorting + std::vector blocks_its; + blocks_its.reserve(m_alternative_chains.size()); + for (alt_chain_container::const_iterator it = m_alternative_chains.begin(); it != m_alternative_chains.end(); ++it) + blocks_its.push_back(it); + + // partially sort blocks by height, so only 0...(start_offset+count-1) first blocks are sorted + std::partial_sort(blocks_its.begin(), blocks_its.begin() + start_offset + count, blocks_its.end(), + [](const alt_chain_container::const_iterator &lhs, const alt_chain_container::const_iterator& rhs) ->bool { + return lhs->second.height < rhs->second.height; + } + ); + + // erase blocks from 0 till start_offset-1 + blocks_its.erase(blocks_its.begin(), blocks_its.begin() + start_offset); + + // erase the tail + blocks_its.erase(blocks_its.begin() + count, blocks_its.end()); + + // populate the result + blocks.reserve(blocks_its.size()); + for(auto it : blocks_its) + { + blocks.push_back(block_rpc_extended_info()); + get_alt_block_rpc_details(it->second, it->first, blocks.back()); + } + + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::get_alt_block_rpc_details(const crypto::hash& id, block_rpc_extended_info& bei) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + CRITICAL_REGION_LOCAL1(m_alternative_chains_lock); + auto it = m_alternative_chains.find(id); + if (it == m_alternative_chains.end()) + return false; + + const block_extended_info& bei_core = it->second; + return get_alt_block_rpc_details(bei_core, id, bei); +} +//------------------------------------------------------------------ +bool blockchain_storage::get_alt_block_rpc_details(const block_extended_info& bei_core, const crypto::hash& id, block_rpc_extended_info& bei) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + CRITICAL_REGION_LOCAL1(m_alternative_chains_lock); + + bei.is_orphan = true; + + crypto::hash coinbase_id = get_transaction_hash(bei_core.bl.miner_tx); + //load transactions details + bei.transactions_details.push_back(tx_rpc_extended_info()); + fill_tx_rpc_details(bei.transactions_details.back(), bei_core.bl.miner_tx, nullptr, coinbase_id, get_actual_timestamp(bei_core.bl)); + + bei.total_fee = 0; + for (auto& h : bei_core.bl.tx_hashes) + { + bei.transactions_details.push_back(tx_rpc_extended_info()); + if (!get_tx_rpc_details(h, bei.transactions_details.back(), get_actual_timestamp(bei_core.bl), true)) + { + //tx not in blockchain, supposed to be in tx pool + m_tx_pool.get_transaction_details(h, bei.transactions_details.back()); + } + bei.total_fee += bei.transactions_details.back().fee; + } + + fill_block_rpc_details(bei, bei_core, id); + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::get_main_blocks_rpc_details(uint64_t start_offset, size_t count, bool ignore_transactions, std::list& blocks) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + if (start_offset >= m_db_blocks.size()) + return false; + + for (size_t i = start_offset; i < start_offset + count && i < m_db_blocks.size(); i++) + { + blocks.push_back(block_rpc_extended_info()); + block_rpc_extended_info& bei = blocks.back(); + get_main_block_rpc_details(i, bei); + } + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::get_blocks(uint64_t start_offset, size_t count, std::list& blocks)const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + if(start_offset >= m_db_blocks.size()) + return false; + + for(size_t i = start_offset; i < start_offset + count && i < m_db_blocks.size();i++) + blocks.push_back(m_db_blocks[i]->bl); + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp)const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + rsp.current_blockchain_height = get_current_blockchain_size(); + std::list blocks; + get_blocks(arg.blocks, blocks, rsp.missed_ids); + + BOOST_FOREACH(const auto& bl, blocks) + { + std::list txs; + get_transactions(bl.tx_hashes, txs, rsp.missed_ids); + + CHECK_AND_ASSERT_MES(!rsp.missed_ids.size(), false, "Host have requested block with missed transactions missed_tx_id.size()=" << rsp.missed_ids.size() + << ENDL << "for block id = " << get_block_hash(bl)); + rsp.blocks.push_back(block_complete_entry()); + block_complete_entry& e = rsp.blocks.back(); + //pack block + e.block = t_serializable_object_to_blob(bl); + //pack transactions + BOOST_FOREACH(transaction& tx, txs) + e.txs.push_back(t_serializable_object_to_blob(tx)); + + } + //get another transactions, if need + std::list txs; + get_transactions(arg.txs, txs, rsp.missed_ids); + //pack aside transactions + BOOST_FOREACH(const auto& tx, txs) + rsp.txs.push_back(t_serializable_object_to_blob(tx)); + + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::get_transactions_daily_stat(uint64_t& daily_cnt, uint64_t& daily_volume) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + daily_cnt = daily_volume = 0; + for(size_t i = (m_db_blocks.size() > CURRENCY_BLOCKS_PER_DAY ? m_db_blocks.size() - CURRENCY_BLOCKS_PER_DAY:0 ); i!=m_db_blocks.size(); i++) + { + auto ptr = m_db_blocks[i]; + for(auto& h : ptr->bl.tx_hashes) + { + ++daily_cnt; + auto tx_ptr = m_db_transactions.find(h); + CHECK_AND_ASSERT_MES(tx_ptr, false, "Wrong transaction hash " << h << " in block on height " << i); + uint64_t am = 0; + bool r = get_inputs_money_amount(tx_ptr->tx, am); + CHECK_AND_ASSERT_MES(r, false, "failed to get_inputs_money_amount"); + daily_volume += am; + } + } + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::check_keyimages(const std::list& images, std::list& images_stat) const +{ + //true - unspent, false - spent + CRITICAL_REGION_LOCAL(m_read_lock); + for (auto& ki : images) + { + auto ki_ptr = m_db_spent_keys.get(ki); + if(ki_ptr) + images_stat.push_back(*ki_ptr); + else + images_stat.push_back(0); + } + return true; +} +//------------------------------------------------------------------ +uint64_t blockchain_storage::get_seconds_between_last_n_block(size_t n) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + if (m_db_blocks.size() <= n) + return 0; + + uint64_t top_block_ts = get_actual_timestamp(m_db_blocks[m_db_blocks.size() - 1]->bl); + uint64_t n_block_ts = get_actual_timestamp(m_db_blocks[m_db_blocks.size() - 1 - n]->bl); + + return top_block_ts > n_block_ts ? top_block_ts - n_block_ts : 0; +} +//------------------------------------------------------------------ +uint64_t blockchain_storage::get_current_hashrate(size_t aprox_count) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + if (aprox_count == 0 || m_db_blocks.size() <= aprox_count) + return 0; // incorrect parameters + + uint64_t nearest_front_pow_block_i = m_db_blocks.size() - 1; + while (nearest_front_pow_block_i != 0) + { + if (!is_pos_block(m_db_blocks[nearest_front_pow_block_i]->bl)) + break; + --nearest_front_pow_block_i; + } + + uint64_t nearest_back_pow_block_i = m_db_blocks.size() - aprox_count; + while (nearest_back_pow_block_i != 0) + { + if (!is_pos_block(m_db_blocks[nearest_back_pow_block_i]->bl)) + break; + --nearest_back_pow_block_i; + } + + std::shared_ptr front_blk_ptr = m_db_blocks[nearest_front_pow_block_i]; + std::shared_ptr back_blk_ptr = m_db_blocks[nearest_back_pow_block_i]; + uint64_t front_blk_ts = front_blk_ptr->bl.timestamp; + uint64_t back_blk_ts = back_blk_ptr->bl.timestamp; + + uint64_t ts_delta = front_blk_ts > back_blk_ts ? front_blk_ts - back_blk_ts : DIFFICULTY_POW_TARGET; + + wide_difficulty_type w_hr = (front_blk_ptr->cumulative_diff_precise - back_blk_ptr->cumulative_diff_precise) / ts_delta; + + return w_hr.convert_to(); +} +//------------------------------------------------------------------ +bool blockchain_storage::get_alternative_blocks(std::list& blocks) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + CRITICAL_REGION_LOCAL1(m_alternative_chains_lock); + BOOST_FOREACH(const auto& alt_bl, m_alternative_chains) + { + blocks.push_back(alt_bl.second.bl); + } + return true; +} +//------------------------------------------------------------------ +size_t blockchain_storage::get_alternative_blocks_count() const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + CRITICAL_REGION_LOCAL1(m_alternative_chains_lock); + return m_alternative_chains.size(); +} +//------------------------------------------------------------------ +bool blockchain_storage::add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, uint64_t amount, size_t i, uint64_t mix_count, bool use_only_forced_to_mix) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + auto out_ptr = m_db_outputs.get_subitem(amount, i); + auto tx_ptr = m_db_transactions.find(out_ptr->tx_id); + CHECK_AND_ASSERT_MES(tx_ptr, false, "internal error: transaction with id " << out_ptr->tx_id << ENDL << + ", used in mounts global index for amount=" << amount << ": i=" << i << "not found in transactions index"); + CHECK_AND_ASSERT_MES(tx_ptr->tx.vout.size() > out_ptr->out_no, false, "internal error: in global outs index, transaction out index=" + << out_ptr->out_no << " more than transaction outputs = " << tx_ptr->tx.vout.size() << ", for tx id = " << out_ptr->tx_id); + + const transaction& tx = tx_ptr->tx; + CHECK_AND_ASSERT_MES(tx.vout[out_ptr->out_no].target.type() == typeid(txout_to_key), false, "unknown tx out type"); + + CHECK_AND_ASSERT_MES(tx_ptr->m_spent_flags.size() == tx.vout.size(), false, "internal error"); + + //do not use outputs that obviously spent for mixins + if (tx_ptr->m_spent_flags[out_ptr->out_no]) + return false; + + //check if transaction is unlocked + if (!is_tx_spendtime_unlocked(get_tx_unlock_time(tx))) + return false; + + //use appropriate mix_attr out + uint8_t mix_attr = boost::get(tx.vout[out_ptr->out_no].target).mix_attr; + + if(mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX) + return false; //COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS call means that ring signature will have more than one entry. + else if(use_only_forced_to_mix && mix_attr == CURRENCY_TO_KEY_OUT_RELAXED) + return false; //relaxed not allowed + else if(mix_attr != CURRENCY_TO_KEY_OUT_RELAXED && mix_attr > mix_count) + return false;//mix_attr set to specific minimum, and mix_count is less then desired count + + + COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry& oen = *result_outs.outs.insert(result_outs.outs.end(), COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry()); + oen.global_amount_index = i; + oen.out_key = boost::get(tx.vout[out_ptr->out_no].target).key; + return true; +} +//------------------------------------------------------------------ +size_t blockchain_storage::find_end_of_allowed_index(uint64_t amount) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + uint64_t sz = m_db_outputs.get_item_size(amount); + + if (!sz) + return 0; + uint64_t i = sz; + do + { + --i; + auto out_ptr = m_db_outputs.get_subitem(amount, i); + auto tx_ptr = m_db_transactions.find(out_ptr->tx_id); + CHECK_AND_ASSERT_MES(tx_ptr, 0, "internal error: failed to find transaction from outputs index with tx_id=" << out_ptr->tx_id); + if (tx_ptr->m_keeper_block_height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW <= get_current_blockchain_size()) + return i+1; + } while (i != 0); + return 0; +} +//------------------------------------------------------------------ +bool blockchain_storage::get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res)const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + BOOST_FOREACH(uint64_t amount, req.amounts) + { + COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs = *res.outs.insert(res.outs.end(), COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount()); + result_outs.amount = amount; + uint64_t outs_container_size = m_db_outputs.get_item_size(amount); + if (!outs_container_size) + { + LOG_ERROR("COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS: not outs for amount " << amount << ", wallet should use some real outs when it lookup for some mix, so, at least one out for this amount should exist"); + continue;//actually this is strange situation, wallet should use some real outs when it lookup for some mix, so, at least one out for this amount should exist + } + //it is not good idea to use top fresh outs, because it increases possibility of transaction canceling on split + //lets find upper bound of not fresh outs + size_t up_index_limit = find_end_of_allowed_index(amount); + CHECK_AND_ASSERT_MES(up_index_limit <= outs_container_size, false, "internal error: find_end_of_allowed_index returned wrong index=" << up_index_limit << ", with amount_outs.size = " << outs_container_size); + if (up_index_limit >= req.outs_count) + { + std::set used; + size_t try_count = 0; + for(uint64_t j = 0; j != req.outs_count && try_count < up_index_limit;) + { + size_t i = crypto::rand()%up_index_limit; + if(used.count(i)) + continue; + bool added = add_out_to_get_random_outs(result_outs, amount, i, req.outs_count, req.use_forced_mix_outs); + used.insert(i); + if(added) + ++j; + ++try_count; + } + if (result_outs.outs.size() < req.outs_count) + { + LOG_PRINT_RED_L0("Not enough inputs for amount " << amount << ", needed " << req.outs_count << ", added " << result_outs.outs.size() << " good outs from " << up_index_limit << " unlocked of " << outs_container_size << " total"); + } + }else + { + size_t added = 0; + for (size_t i = 0; i != up_index_limit; i++) + added += add_out_to_get_random_outs(result_outs, amount, i, req.outs_count, req.use_forced_mix_outs) ? 1 : 0; + LOG_PRINT_RED_L0("Not enough inputs for amount " << amount << ", needed " << req.outs_count << ", added " << added << " good outs from " << up_index_limit << " unlocked of " << outs_container_size << " total - respond with all good outs"); + } + } + return true; +} +//------------------------------------------------------------------ +uint64_t blockchain_storage::total_coins() const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + if (!m_db_blocks.size()) + return 0; + + return m_db_blocks.back()->already_generated_coins; +} +//------------------------------------------------------------------ +bool blockchain_storage::is_pos_allowed() const +{ + return get_top_block_height() >= m_core_runtime_config.pos_minimum_heigh; +} +//------------------------------------------------------------------ +bool blockchain_storage::update_spent_tx_flags_for_input(uint64_t amount, const txout_v& o, bool spent) +{ + if (o.type() == typeid(ref_by_id)) + return update_spent_tx_flags_for_input(boost::get(o).tx_id, boost::get(o).n, spent); + else if (o.type() == typeid(uint64_t)) + return update_spent_tx_flags_for_input(amount, boost::get(o), spent); + + LOG_ERROR("Unknown txout_v type"); + return false; +} +//------------------------------------------------------------------ +bool blockchain_storage::update_spent_tx_flags_for_input(uint64_t amount, uint64_t global_index, bool spent) +{ + CRITICAL_REGION_LOCAL(m_read_lock); + uint64_t outs_count = m_db_outputs.get_item_size(amount); + CHECK_AND_ASSERT_MES(outs_count, false, "Amount " << amount << " have not found during update_spent_tx_flags_for_input()"); + CHECK_AND_ASSERT_MES(global_index < outs_count, false, "Global index" << global_index << " for amount " << amount << " bigger value than amount's vector size()=" << outs_count); + auto out_ptr = m_db_outputs.get_subitem(amount, global_index); + return update_spent_tx_flags_for_input(out_ptr->tx_id, out_ptr->out_no, spent); +} +//------------------------------------------------------------------ +bool blockchain_storage::update_spent_tx_flags_for_input(const crypto::hash& tx_id, size_t n, bool spent) +{ + CRITICAL_REGION_LOCAL(m_read_lock); + auto tx_ptr = m_db_transactions.find(tx_id); + CHECK_AND_ASSERT_MES(tx_ptr, false, "Can't find transaction id: " << tx_id); + transaction_chain_entry tce_local = *tx_ptr; + + CHECK_AND_ASSERT_MES(n < tce_local.m_spent_flags.size(), false, "Wrong input offset: " << n << " in transaction id: " << tx_id); + + tce_local.m_spent_flags[n] = spent; + m_db_transactions.set(tx_id, tce_local); + + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::update_spent_tx_flags_for_input(const crypto::hash& multisig_id, uint64_t spent_height) +{ + CRITICAL_REGION_LOCAL(m_read_lock); + auto ms_ptr = m_db_multisig_outs.find(multisig_id); + CHECK_AND_ASSERT_MES(ms_ptr, false, "unable to find multisig_id " << multisig_id); + + // update spent height at ms container + ms_output_entry msoe_local = *ms_ptr; + if (msoe_local.spent_height != 0 && spent_height != 0) + { + LOG_PRINT_YELLOW(LOCATION_SS << ": WARNING: ms out " << multisig_id << " was already marked as SPENT at height " << msoe_local.spent_height << ", new spent_height: " << spent_height , LOG_LEVEL_0); + } + msoe_local.spent_height = spent_height; + m_db_multisig_outs.set(multisig_id, msoe_local); + + return update_spent_tx_flags_for_input(ms_ptr->tx_id, ms_ptr->out_no, spent_height != 0); +} +//------------------------------------------------------------------ +bool blockchain_storage::has_multisig_output(const crypto::hash& multisig_id) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + return static_cast(m_db_multisig_outs.find(multisig_id)); +} +//------------------------------------------------------------------ +bool blockchain_storage::is_multisig_output_spent(const crypto::hash& multisig_id) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + + auto multisig_ptr = m_db_multisig_outs.find(multisig_id); + if (!multisig_ptr) + return false; // there's no such output - treat as not spent + + const crypto::hash& source_tx_id = multisig_ptr->tx_id; + size_t ms_out_index = multisig_ptr->out_no; // index of multisig output in source tx + + auto source_tx_ptr = m_db_transactions.find(source_tx_id); + CHECK_AND_ASSERT_MES(source_tx_ptr, true, "Internal error: source tx not found for ms out " << multisig_id << ", ms out is treated as spent for safety"); + CHECK_AND_ASSERT_MES(ms_out_index < source_tx_ptr->m_spent_flags.size(), true, "Internal error: ms out " << multisig_id << " has incorrect index " << ms_out_index << " in source tx " << source_tx_id << ", ms out is treated as spent for safety"); + + return source_tx_ptr->m_spent_flags[ms_out_index]; +} +//------------------------------------------------------------------ +// bool blockchain_storage::resync_spent_tx_flags() +// { +// LOG_PRINT_L0("Started re-building spent tx outputs data..."); +// CRITICAL_REGION_LOCAL(m_blockchain_lock); +// for(auto& tx: m_db_transactions) +// { +// if(is_coinbase(tx.second.tx)) +// continue; +// +// for(auto& in: tx.second.tx.vin) +// { +// CHECKED_GET_SPECIFIC_VARIANT(in, txin_to_key, in_to_key, false); +// if(in_to_key.key_offsets.size() != 1) +// continue; +// +// //direct spending +// if(!update_spent_tx_flags_for_input(in_to_key.amount, in_to_key.key_offsets[0], true)) +// return false; +// +// } +// } +// LOG_PRINT_L0("Finished re-building spent tx outputs data"); +// return true; +// } +//------------------------------------------------------------------ +bool blockchain_storage::find_blockchain_supplement(const std::list& qblock_ids, uint64_t& starter_offset)const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + + if(!qblock_ids.size() /*|| !req.m_total_height*/) + { + LOG_ERROR("Client sent wrong NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << qblock_ids.size() << /*", m_height=" << req.m_total_height <<*/ ", dropping connection"); + return false; + } + //check genesis match + if(qblock_ids.back() != get_block_hash(m_db_blocks[0]->bl)) + { + LOG_ERROR("Client sent wrong NOTIFY_REQUEST_CHAIN: genesis block missmatch: " << ENDL << "id: " + << string_tools::pod_to_hex(qblock_ids.back()) << ", " << ENDL << "expected: " << get_block_hash(m_db_blocks[0]->bl) + << "," << ENDL << " dropping connection"); + return false; + } + + /* Figure out what blocks we should request to get state_normal */ + for(auto& bl: qblock_ids) + { + auto block_index_ptr = m_db_blocks_index.find(bl); + if(block_index_ptr) + { + //we start to put block ids INCLUDING last known id, just to make other side be sure + starter_offset = *block_index_ptr; + return true; + } + } + + LOG_ERROR("Internal error handling connection, can't find split point"); + return false; +} +//------------------------------------------------------------------ +wide_difficulty_type blockchain_storage::block_difficulty(size_t i) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + CHECK_AND_ASSERT_MES(i < m_db_blocks.size(), false, "wrong block index i = " << i << " at blockchain_storage::block_difficulty()"); + return m_db_blocks[i]->difficulty; +} +//------------------------------------------------------------------ +bool blockchain_storage::forecast_difficulty(std::vector> &out_height_2_diff_vector, bool pos) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + + std::vector timestamps; + std::vector cumulative_difficulties; + + uint64_t blocks_size = m_db_blocks.size(); + size_t count = 0; + + uint64_t max_block_height_for_this_type = 0; + uint64_t min_block_height_for_this_type = UINT64_MAX; + wide_difficulty_type last_block_diff_for_this_type = 0; + + for (uint64_t cur_ind = blocks_size - 1; cur_ind != 0 && count < DIFFICULTY_WINDOW; cur_ind--) + { + auto beiptr = m_db_blocks[cur_ind]; + bool is_pos_bl = is_pos_block(beiptr->bl); + if (pos != is_pos_bl) + continue; + + if (max_block_height_for_this_type < beiptr->height) + max_block_height_for_this_type = beiptr->height; + if (min_block_height_for_this_type > beiptr->height) + min_block_height_for_this_type = beiptr->height; + if (last_block_diff_for_this_type == 0) + last_block_diff_for_this_type = beiptr->difficulty; + + timestamps.push_back(beiptr->bl.timestamp); + cumulative_difficulties.push_back(beiptr->cumulative_diff_precise); + ++count; + } + + if (count != DIFFICULTY_WINDOW) + return false; + + const uint64_t target_seconds = pos ? DIFFICULTY_POS_TARGET : DIFFICULTY_POW_TARGET; + const uint64_t avg_interval = std::max(static_cast(1), (max_block_height_for_this_type - min_block_height_for_this_type) / count); + uint64_t height = max_block_height_for_this_type; + out_height_2_diff_vector.clear(); + out_height_2_diff_vector.push_back(std::make_pair(height, last_block_diff_for_this_type)); // the first element corresponds to the last block of this type + for (size_t i = 0; i < DIFFICULTY_CUT; ++i) + { + wide_difficulty_type diff = next_difficulty(timestamps, cumulative_difficulties, target_seconds); + height += avg_interval; + out_height_2_diff_vector.push_back(std::make_pair(height, diff)); + + timestamps.pop_back(); // keep sorted in descending order + timestamps.insert(timestamps.begin(), timestamps.front() + target_seconds); // increment time so it won't be affected by sorting in next_difficulty + + cumulative_difficulties.pop_back(); + cumulative_difficulties.insert(cumulative_difficulties.begin(), 0); // does not matter + } + + return true; +} +//------------------------------------------------------------------ +size_t blockchain_storage::get_current_sequence_factor(bool pos) const +{ + size_t n = 0; + CRITICAL_REGION_LOCAL(m_read_lock); + uint64_t sz = m_db_blocks.size(); + if (!sz) + return n; + + for (uint64_t i = sz - 1; i != 0; --i, n++) + { + if (pos != is_pos_block(m_db_blocks[i]->bl)) + break; + } + return n; +} +//------------------------------------------------------------------ +size_t blockchain_storage::get_current_sequence_factor_for_alt(alt_chain_type& alt_chain, bool pos, uint64_t connection_height) const +{ + size_t n = 0; + for (auto it = alt_chain.rbegin(); it != alt_chain.rend(); it++, n++) + { + if (pos != is_pos_block((*it)->second.bl)) + return n; + } + + CRITICAL_REGION_LOCAL(m_read_lock); + for (uint64_t h = connection_height - 1; h != 0; --h, n++) + { + if (pos != is_pos_block(m_db_blocks[h]->bl)) + { + return n; + } + } + return n; +} +//------------------------------------------------------------------ +std::string blockchain_storage::get_blockchain_string(uint64_t start_index, uint64_t end_index) const +{ + std::stringstream ss; + CRITICAL_REGION_LOCAL(m_read_lock); + if (start_index >= m_db_blocks.size()) + { + LOG_PRINT_L0("Wrong starter index set: " << start_index << ", expected max index " << m_db_blocks.size() - 1); + return ss.str(); + } + + for (size_t i = start_index; i != m_db_blocks.size() && i != end_index; i++) + { + ss << (is_pos_block(m_db_blocks[i]->bl) ? "[PoS]" : "[PoW]") << "h: " << i << ", timestamp: " << m_db_blocks[i]->bl.timestamp << "(" << epee::misc_utils::get_time_str_v2(m_db_blocks[i]->bl.timestamp) << ")" + << ", cumul_diff_adj: " << m_db_blocks[i]->cumulative_diff_adjusted + << ", cumul_diff_pcs: " << m_db_blocks[i]->cumulative_diff_precise + << ", cumul_size: " << m_db_blocks[i]->block_cumulative_size + << ", id: " << get_block_hash(m_db_blocks[i]->bl) + << ", difficulty: " << block_difficulty(i) << ", nonce " << m_db_blocks[i]->bl.nonce << ", tx_count " << m_db_blocks[i]->bl.tx_hashes.size() << ENDL; + } + return ss.str(); +} +//------------------------------------------------------------------ +void blockchain_storage::print_blockchain(uint64_t start_index, uint64_t end_index) const +{ + //LOG_ERROR("NOT IMPLEMENTED YET"); + + LOG_PRINT_L1("Current blockchain:" << ENDL << get_blockchain_string(start_index, end_index)); + LOG_PRINT_L0("Blockchain printed with log level 1"); +} + +void blockchain_storage::print_blockchain_with_tx(uint64_t start_index, uint64_t end_index) const +{ + boost::filesystem::ofstream ss; + ss.exceptions(/*std::ifstream::failbit |*/ std::ifstream::badbit); + ss.open(log_space::log_singletone::get_default_log_folder() + "/blockchain_with_tx.txt", std::ios_base::binary | std::ios_base::out | std::ios_base::trunc); + + + CRITICAL_REGION_LOCAL(m_read_lock); + if (start_index >= m_db_blocks.size()) + { + LOG_PRINT_L0("Wrong starter index set: " << start_index << ", expected max index " << m_db_blocks.size() - 1); + return; + } + + for (size_t i = start_index; i != m_db_blocks.size() && i != end_index; i++) + { + ss << (is_pos_block(m_db_blocks[i]->bl) ? "[PoS]" : "[PoW]") << "h: " << i << ", timestamp: " << m_db_blocks[i]->bl.timestamp << "(" << epee::misc_utils::get_time_str_v2(m_db_blocks[i]->bl.timestamp) << ")" + << ", cumul_diff_adj: " << m_db_blocks[i]->cumulative_diff_adjusted + << ", cumul_diff_pcs: " << m_db_blocks[i]->cumulative_diff_precise + << ", cumul_size: " << m_db_blocks[i]->block_cumulative_size + << ", id: " << get_block_hash(m_db_blocks[i]->bl) + << ", difficulty: " << block_difficulty(i) << ", nonce " << m_db_blocks[i]->bl.nonce << ", tx_count " << m_db_blocks[i]->bl.tx_hashes.size() << ENDL; + + ss << "[miner id]: " << get_transaction_hash(m_db_blocks[i]->bl.miner_tx) << ENDL << currency::obj_to_json_str(m_db_blocks[i]->bl.miner_tx) << ENDL; + + for (size_t j = 0; j != m_db_blocks[i]->bl.tx_hashes.size(); j++) + { + auto tx_it = m_db_transactions.find(m_db_blocks[i]->bl.tx_hashes[j]); + if (tx_it == m_db_transactions.end()) + { + LOG_ERROR("internal error: tx id " << m_db_blocks[i]->bl.tx_hashes[j] << " not found in transactions index"); + continue; + } + ss << "[id]:" << m_db_blocks[i]->bl.tx_hashes[j] << ENDL << currency::obj_to_json_str(tx_it->tx) << ENDL; + } + + } + ss.close(); +} +//------------------------------------------------------------------ +void blockchain_storage::print_blockchain_index() const +{ + LOG_ERROR("NOT IMPLEMENTED YET"); +// std::stringstream ss; +// CRITICAL_REGION_LOCAL(m_blockchain_lock); +// BOOST_FOREACH(const blocks_by_id_index::value_type& v, m_db_blocks_index) +// ss << "id\t\t" << v.first << " height" << v.second << ENDL << ""; +// +// LOG_PRINT_L0("Current blockchain index:" << ENDL << ss.str()); +} +//------------------------------------------------------------------ +void blockchain_storage::print_db_cache_perfeormance_data() const +{ +#define DB_CONTAINER_PERF_DATA_ENTRY(container_name) \ + << #container_name << ": hit_percent: " << m_db_blocks.get_performance_data().hit_percent.get_avg() << "%," \ + << " read_cache: " << container_name.get_performance_data().read_cache_microsec.get_avg() \ + << " read_db: " << container_name.get_performance_data().read_db_microsec.get_avg() \ + << " upd_cache: " << container_name.get_performance_data().update_cache_microsec.get_avg() \ + << " write_cache: " << container_name.get_performance_data().write_to_cache_microsec.get_avg() \ + << " write_db: " << container_name.get_performance_data().write_to_db_microsec.get_avg() \ + << " native_db_set_t: " << container_name.get_performance_data_native().backend_set_t_time.get_avg() \ + << " native_db_set_pod: " << container_name.get_performance_data_native().backend_set_pod_time.get_avg() \ + << " native_db_seriz: " << container_name.get_performance_data_native().set_serialize_t_time.get_avg() + + + LOG_PRINT_L0("DB_PERFORMANCE_DATA: " << ENDL + DB_CONTAINER_PERF_DATA_ENTRY(m_db_blocks) << ENDL + DB_CONTAINER_PERF_DATA_ENTRY(m_db_blocks_index) << ENDL + DB_CONTAINER_PERF_DATA_ENTRY(m_db_transactions) << ENDL + DB_CONTAINER_PERF_DATA_ENTRY(m_db_spent_keys) << ENDL + //DB_CONTAINER_PERF_DATA_ENTRY(m_db_outputs) << ENDL + DB_CONTAINER_PERF_DATA_ENTRY(m_db_multisig_outs) << ENDL + DB_CONTAINER_PERF_DATA_ENTRY(m_db_solo_options) << ENDL + DB_CONTAINER_PERF_DATA_ENTRY(m_db_aliases) << ENDL + DB_CONTAINER_PERF_DATA_ENTRY(m_db_addr_to_alias) << ENDL + //DB_CONTAINER_PERF_DATA_ENTRY(m_db_per_block_gindex_incs) << ENDL + //DB_CONTAINER_PERF_DATA_ENTRY(m_tx_fee_median) << ENDL + ); +} +//------------------------------------------------------------------ +void blockchain_storage::print_blockchain_outs_stat() const +{ + LOG_ERROR("NOT IMPLEMENTED YET"); +// std::stringstream ss; +// CRITICAL_REGION_LOCAL(m_blockchain_lock); +// BOOST_FOREACH(const outputs_container::value_type& v, m_db_outputs) +// { +// const std::vector >& vals = v.second; +// if (vals.size()) +// { +// ss << "amount: " << print_money(v.first); +// uint64_t total_count = vals.size(); +// uint64_t unused_count = 0; +// for (size_t i = 0; i != vals.size(); i++) +// { +// bool used = false; +// auto it_tx = m_db_transactions.find(vals[i].first); +// if (it_tx == m_db_transactions.end()) +// { +// LOG_ERROR("Tx with id not found " << vals[i].first); +// } +// else +// { +// if (vals[i].second >= it_tx->second.m_spent_flags.size()) +// { +// LOG_ERROR("Tx with id " << vals[i].first << " in global index have wrong entry in global index, offset in tx = " << vals[i].second +// << ", it_tx->second.m_spent_flags.size()=" << it_tx->second.m_spent_flags.size() +// << ", it_tx->second.tx.vin.size()=" << it_tx->second.tx.vin.size()); +// } +// used = it_tx->second.m_spent_flags[vals[i].second]; +// +// } +// if (!used) +// ++unused_count; +// } +// ss << "\t total: " << total_count << "\t unused: " << unused_count << ENDL; +// } +// } +// LOG_PRINT_L0("OUTS: " << ENDL << ss.str()); +} +//------------------------------------------------------------------ +void blockchain_storage::print_blockchain_outs(const std::string& file) const +{ + LOG_ERROR("NOT IMPLEMENTED YET"); +// std::stringstream ss; +// CRITICAL_REGION_LOCAL(m_blockchain_lock); +// BOOST_FOREACH(const outputs_container::value_type& v, m_db_outputs) +// { +// const std::vector >& vals = v.second; +// if(vals.size()) +// { +// ss << "amount: " << print_money(v.first) << ENDL; +// for (size_t i = 0; i != vals.size(); i++) +// { +// bool used = false; +// auto it_tx = m_db_transactions.find(vals[i].first); +// if (it_tx == m_db_transactions.end()) +// { +// LOG_ERROR("Tx with id not found " << vals[i].first); +// } +// else +// { +// if (vals[i].second >= it_tx->second.m_spent_flags.size()) +// { +// LOG_ERROR("Tx with id " << vals[i].first << " in global index have wrong entry in global index, offset in tx = " << vals[i].second +// << ", it_tx->second.m_spent_flags.size()=" << it_tx->second.m_spent_flags.size() +// << ", it_tx->second.tx.vin.size()=" << it_tx->second.tx.vin.size()); +// } +// used = it_tx->second.m_spent_flags[vals[i].second]; +// } +// +// ss << "\t" << vals[i].first << ": " << vals[i].second << ",used:" << used << ENDL; +// } +// } +// } +// if(file_io_utils::save_string_to_file(file, ss.str())) +// { +// LOG_PRINT_L0("Current outputs index writen to file: " << file); +// }else +// { +// LOG_PRINT_L0("Failed to write current outputs index to file: " << file); +// } +} +//------------------------------------------------------------------ + +//------------------------------------------------------------------ +bool blockchain_storage::find_blockchain_supplement(const std::list& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp)const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + if(!find_blockchain_supplement(qblock_ids, resp.start_height)) + return false; + + resp.total_height = get_current_blockchain_size(); + size_t count = 0; + + block_context_info* pprevinfo = nullptr; + size_t i = 0; + for (i = resp.start_height; i != m_db_blocks.size() && count < BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT; i++, count++) + { + resp.m_block_ids.push_back(block_context_info()); + + if (pprevinfo) + pprevinfo->h = m_db_blocks[i]->bl.prev_id; + resp.m_block_ids.back().cumul_size = m_db_blocks[i]->block_cumulative_size; + pprevinfo = &resp.m_block_ids.back(); + } + if (pprevinfo) + pprevinfo->h = get_block_hash(m_db_blocks[--i]->bl); + + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::find_blockchain_supplement(const std::list& qblock_ids, std::list > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count)const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + blocks_direct_container blocks_direct; + if (!find_blockchain_supplement(qblock_ids, blocks_direct, total_height, start_height, max_count)) + return false; + + for (auto& bd : blocks_direct) + { + blocks.push_back(std::pair >()); + blocks.back().first = bd.first->bl; + for (auto& tx_ptr : bd.second) + { + blocks.back().second.push_back(tx_ptr->tx); + } + } + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::find_blockchain_supplement(const std::list& qblock_ids, blocks_direct_container& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count)const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + if (!find_blockchain_supplement(qblock_ids, start_height)) + return false; + + total_height = get_current_blockchain_size(); + size_t count = 0; + for (size_t i = start_height; i != m_db_blocks.size() && count < max_count; i++, count++) + { + blocks.resize(blocks.size() + 1); + blocks.back().first = m_db_blocks[i]; + std::list mis; + get_transactions_direct(m_db_blocks[i]->bl.tx_hashes, blocks.back().second, mis); + CHECK_AND_ASSERT_MES(!mis.size(), false, "internal error, transaction from block not found"); + } + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::add_block_as_invalid(const block& bl, const crypto::hash& h) +{ + block_extended_info bei = AUTO_VAL_INIT(bei); + bei.bl = bl; + return add_block_as_invalid(bei, h); +} +//------------------------------------------------------------------ +bool blockchain_storage::add_block_as_invalid(const block_extended_info& bei, const crypto::hash& h) +{ + CRITICAL_REGION_LOCAL(m_read_lock); + CRITICAL_REGION_LOCAL1(m_invalid_blocks_lock); + auto i_res = m_invalid_blocks.insert(std::map::value_type(h, bei)); + CHECK_AND_ASSERT_MES(i_res.second, false, "at insertion invalid by tx returned status existed"); + LOG_PRINT_L0("BLOCK ADDED AS INVALID: " << h << ENDL << ", prev_id=" << bei.bl.prev_id << ", m_invalid_blocks count=" << m_invalid_blocks.size()); + CHECK_AND_ASSERT_MES(validate_blockchain_prev_links(), false, "EPIC FAIL!"); + return true; +} +//------------------------------------------------------------------ +void blockchain_storage::inspect_blocks_index()const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + LOG_PRINT_L0("Started block index inspecting...."); + m_db_blocks_index.enumerate_items([&](uint64_t count, const crypto::hash& id, uint64_t index) + { + CHECK_AND_ASSERT_MES(index < m_db_blocks.size(), true, "invalid index " << index << "(m_db_blocks.size()=" << m_db_blocks.size() << ") for id " << id << " "); + crypto::hash calculated_id = get_block_hash(m_db_blocks[index]->bl); + CHECK_AND_ASSERT_MES(id == calculated_id, true, "ID MISSMATCH ON INDEX " << index << ENDL + << "m_db_blocks_index keeps: " << id << ENDL + << "referenced to block with id " << calculated_id + ); + return true; + }); + LOG_PRINT_L0("Block index inspecting finished"); +} +//------------------------------------------------------------------ +bool blockchain_storage::have_block(const crypto::hash& id)const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + if(m_db_blocks_index.find(id)) + return true; + { + CRITICAL_REGION_LOCAL1(m_alternative_chains_lock); + if (m_alternative_chains.count(id)) + return true; + + } + /*if(m_orphaned_blocks.get().count(id)) + return true;*/ + + /*if(m_orphaned_by_tx.count(id)) + return true;*/ + { + CRITICAL_REGION_LOCAL1(m_invalid_blocks_lock); + if (m_invalid_blocks.count(id)) + return true; + } + + return false; +} +//------------------------------------------------------------------ +bool blockchain_storage::handle_block_to_main_chain(const block& bl, block_verification_context& bvc) +{ + crypto::hash id = get_block_hash(bl); + return handle_block_to_main_chain(bl, id, bvc); +} +//------------------------------------------------------------------ +bool blockchain_storage::push_transaction_to_global_outs_index(const transaction& tx, const crypto::hash& tx_id, std::vector& global_indexes) +{ + CRITICAL_REGION_LOCAL(m_read_lock); + size_t i = 0; + BOOST_FOREACH(const auto& ot, tx.vout) + { + if (ot.target.type() == typeid(txout_to_key)) + { + m_db_outputs.push_back_item(ot.amount, global_output_entry::construct(tx_id, i)); + global_indexes.push_back(m_db_outputs.get_item_size(ot.amount) - 1); + } + else if (ot.target.type() == typeid(txout_multisig)) + { + + crypto::hash multisig_out_id = get_multisig_out_id(tx, i); + CHECK_AND_ASSERT_MES(multisig_out_id != null_hash, false, "internal error during handling get_multisig_out_id() with tx id " << tx_id); + CHECK_AND_ASSERT_MES(!m_db_multisig_outs.find(multisig_out_id), false, "Internal error: already have multisig_out_id " << multisig_out_id << "in multisig outs index"); + m_db_multisig_outs.set(multisig_out_id, ms_output_entry::construct(tx_id, i)); + global_indexes.push_back(0); // just stub to make other code easier + } + + ++i; + } + return true; +} +//------------------------------------------------------------------ +size_t blockchain_storage::get_total_transactions()const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + return m_db_transactions.size(); +} +//------------------------------------------------------------------ +bool blockchain_storage::get_outs(uint64_t amount, std::list& pkeys)const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + uint64_t sz = m_db_outputs.get_item_size(amount); + + if (!sz) + return true; + + for (uint64_t i = 0; i != sz; i++) + { + auto out_entry_ptr = m_db_outputs.get_subitem(amount, i); + + auto tx_ptr = m_db_transactions.find(out_entry_ptr->tx_id); + CHECK_AND_ASSERT_MES(tx_ptr, false, "transactions outs global index consistency broken: can't find tx " << out_entry_ptr->tx_id << " in DB, for amount: " << amount << ", gindex: " << i); + CHECK_AND_ASSERT_MES(tx_ptr->tx.vout.size() > out_entry_ptr->out_no, false, "transactions outs global index consistency broken: index in tx_outx == " << out_entry_ptr->out_no << " is greather than tx.vout size == " << tx_ptr->tx.vout.size() << ", for amount: " << amount << ", gindex: " << i); + CHECK_AND_ASSERT_MES(tx_ptr->tx.vout[out_entry_ptr->out_no].target.type() == typeid(txout_to_key), false, "transactions outs global index consistency broken: out #" << out_entry_ptr->out_no << " in tx " << out_entry_ptr->tx_id << " has wrong type, for amount: " << amount << ", gindex: " << i); + pkeys.push_back(boost::get(tx_ptr->tx.vout[out_entry_ptr->out_no].target).key); + } + + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::pop_transaction_from_global_index(const transaction& tx, const crypto::hash& tx_id) +{ + CRITICAL_REGION_LOCAL(m_read_lock); + size_t i = tx.vout.size()-1; + BOOST_REVERSE_FOREACH(const auto& ot, tx.vout) + { + if (ot.target.type() == typeid(txout_to_key)) + { + uint64_t sz= m_db_outputs.get_item_size(ot.amount); + CHECK_AND_ASSERT_MES(sz, false, "transactions outs global index: empty index for amount: " << ot.amount); + auto back_item = m_db_outputs.get_subitem(ot.amount, sz - 1); + CHECK_AND_ASSERT_MES(back_item->tx_id == tx_id, false, "transactions outs global index consistency broken: tx id missmatch"); + CHECK_AND_ASSERT_MES(back_item->out_no == i, false, "transactions outs global index consistency broken: in transaction index missmatch"); + m_db_outputs.pop_back_item(ot.amount); + //do not let to exist empty m_outputs entries - this will broke scratchpad selector + //if (!it->second.size()) + // m_db_outputs.erase(it); + } + else if (ot.target.type() == typeid(txout_multisig)) + { + crypto::hash multisig_out_id = get_multisig_out_id(tx, i); + CHECK_AND_ASSERT_MES(multisig_out_id != null_hash, false, "internal error during handling get_multisig_out_id() with tx id " << tx_id); + bool res = m_db_multisig_outs.erase_validate(multisig_out_id); + CHECK_AND_ASSERT_MES(res, false, "Internal error: multisig out not found, multisig_out_id " << multisig_out_id << "in multisig outs index"); + } + --i; + } + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::unprocess_blockchain_tx_extra(const transaction& tx) +{ + tx_extra_info ei = AUTO_VAL_INIT(ei); + bool r = parse_and_validate_tx_extra(tx, ei); + CHECK_AND_ASSERT_MES(r, false, "failed to validate transaction extra on unprocess_blockchain_tx_extra"); + if(ei.m_alias.m_alias.size()) + { + r = pop_alias_info(ei.m_alias); + CHECK_AND_ASSERT_MES(r, false, "failed to pop_alias_info"); + } + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::get_alias_info(const std::string& alias, extra_alias_entry_base& info)const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + auto al_ptr = m_db_aliases.find(alias); + if (al_ptr) + { + if (al_ptr->size()) + { + info = al_ptr->back(); + return true; + } + } + return false; +} +//------------------------------------------------------------------ +uint64_t blockchain_storage::get_aliases_count() const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + return m_db_aliases.size(); +} +//------------------------------------------------------------------ +std::string blockchain_storage::get_alias_by_address(const account_public_address& addr)const +{ + auto alias_ptr = m_db_addr_to_alias.find(addr); + if (alias_ptr && alias_ptr->size()) + { + return *(alias_ptr->begin()); + } + + return ""; +} +//------------------------------------------------------------------ +bool blockchain_storage::pop_alias_info(const extra_alias_entry& ai) +{ + CRITICAL_REGION_LOCAL(m_read_lock); + + CHECK_AND_ASSERT_MES(ai.m_alias.size(), false, "empty name in pop_alias_info"); + auto alias_history_ptr = m_db_aliases.find(ai.m_alias); + CHECK_AND_ASSERT_MES(alias_history_ptr && alias_history_ptr->size(), false, "empty name list in pop_alias_info"); + + auto addr_to_alias_ptr = m_db_addr_to_alias.find(alias_history_ptr->back().m_address); + if (addr_to_alias_ptr) + { + //update db + address_to_aliases_container::t_value_type local_v = *addr_to_alias_ptr; + + auto it_in_set = local_v.find(ai.m_alias); + CHECK_AND_ASSERT_MES(it_in_set != local_v.end(), false, "it_in_set != it->second.end() validation failed"); + + local_v.erase(it_in_set); + if (!local_v.size()) + { + //delete the whole record from db + m_db_addr_to_alias.erase(alias_history_ptr->back().m_address); + } + else + { + //update db + m_db_addr_to_alias.set(alias_history_ptr->back().m_address, local_v); + } + } + else + { + LOG_ERROR("In m_addr_to_alias not found " << get_account_address_as_str(alias_history_ptr->back().m_address)); + } + + aliases_container::t_value_type local_alias_hist = *alias_history_ptr; + local_alias_hist.pop_back(); + if(local_alias_hist.size()) + m_db_aliases.set(ai.m_alias, local_alias_hist); + else + m_db_aliases.erase(ai.m_alias); + + if (local_alias_hist.size()) + { + address_to_aliases_container::t_value_type local_copy = AUTO_VAL_INIT(local_copy); + auto set_ptr = m_db_addr_to_alias.get(local_alias_hist.back().m_address); + if (set_ptr) + local_copy = *set_ptr; + + local_copy.insert(ai.m_alias); + m_db_addr_to_alias.set(local_alias_hist.back().m_address, local_copy); + } + + LOG_PRINT_MAGENTA("[ALIAS_UNREGISTERED]: " << ai.m_alias << ": " << get_account_address_as_str(ai.m_address) << " -> " << (!alias_history_ptr->empty() ? get_account_address_as_str(alias_history_ptr->back().m_address) : "(available)"), LOG_LEVEL_0); + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::put_alias_info(const transaction & tx, extra_alias_entry & ai) +{ + CRITICAL_REGION_LOCAL(m_read_lock); + + CHECK_AND_ASSERT_MES(ai.m_alias.size(), false, "empty name in put_alias_info"); + aliases_container::t_value_type local_alias_history = AUTO_VAL_INIT(local_alias_history); + auto alias_history_ptr_ = m_db_aliases.get(ai.m_alias); + if (alias_history_ptr_) + local_alias_history = *alias_history_ptr_; + + if (!local_alias_history.size()) + { + + //update alias entry in db + local_alias_history.push_back(ai); + m_db_aliases.set(ai.m_alias, local_alias_history); + + //update addr-to-alias db entry + address_to_aliases_container::t_value_type addr_to_alias_local = AUTO_VAL_INIT(addr_to_alias_local); + auto addr_to_alias_ptr_ = m_db_addr_to_alias.get(local_alias_history.back().m_address); + if (addr_to_alias_ptr_) + addr_to_alias_local = *addr_to_alias_ptr_; + + addr_to_alias_local.insert(ai.m_alias); + m_db_addr_to_alias.set(local_alias_history.back().m_address, addr_to_alias_local); + + //@@ remove get_tx_fee_median(); + LOG_PRINT_MAGENTA("[ALIAS_REGISTERED]: " << ai.m_alias << ": " << get_account_address_as_str(ai.m_address) << ", fee median: " << get_tx_fee_median(), LOG_LEVEL_1); + rise_core_event(CORE_EVENT_ADD_ALIAS, alias_info_to_rpc_alias_info(ai)); + }else + { + //update procedure + CHECK_AND_ASSERT_MES(ai.m_sign.size() == 1, false, "alias " << ai.m_alias << " can't be update, wrong ai.m_sign.size() count: " << ai.m_sign.size()); + //std::string signed_buff; + //make_tx_extra_alias_entry(signed_buff, ai, true); + std::string old_address = currency::get_account_address_as_str(local_alias_history.back().m_address); + bool r = crypto::check_signature(get_sign_buff_hash_for_alias_update(ai), local_alias_history.back().m_address.m_spend_public_key, ai.m_sign.back()); + CHECK_AND_ASSERT_MES(r, false, "Failed to check signature, alias update failed." << ENDL + << "alias: " << ai.m_alias << ENDL + << "signed_buff_hash: " << get_sign_buff_hash_for_alias_update(ai) << ENDL + << "public key: " << local_alias_history.back().m_address.m_spend_public_key << ENDL + << "new_address: " << get_account_address_as_str(ai.m_address) << ENDL + << "signature: " << epee::string_tools::pod_to_hex(ai.m_sign) << ENDL + << "alias_history.size() = " << local_alias_history.size()); + + //update adr-to-alias db + auto addr_to_alias_ptr_ = m_db_addr_to_alias.find(local_alias_history.back().m_address); + if (addr_to_alias_ptr_) + { + address_to_aliases_container::t_value_type addr_to_alias_local = *addr_to_alias_ptr_; + auto it_in_set = addr_to_alias_local.find(ai.m_alias); + if (it_in_set == addr_to_alias_local.end()) + { + LOG_ERROR("it_in_set == it->second.end()"); + } + else + { + addr_to_alias_local.erase(it_in_set); + } + + if (!addr_to_alias_local.size()) + m_db_addr_to_alias.erase(local_alias_history.back().m_address); + else + m_db_addr_to_alias.set(local_alias_history.back().m_address, addr_to_alias_local); + } + else + { + LOG_ERROR("Wrong m_addr_to_alias state: address not found " << get_account_address_as_str(local_alias_history.back().m_address)); + } + + //update alias db + local_alias_history.push_back(ai); + m_db_aliases.set(ai.m_alias, local_alias_history); + + //update addr_to_alias db + address_to_aliases_container::t_value_type addr_to_alias_local2 = AUTO_VAL_INIT(addr_to_alias_local2); + auto addr_to_alias_ptr_2 = m_db_addr_to_alias.get(local_alias_history.back().m_address); + if (addr_to_alias_ptr_2) + addr_to_alias_local2 = *addr_to_alias_ptr_2; + + addr_to_alias_local2.insert(ai.m_alias); + m_db_addr_to_alias.set(local_alias_history.back().m_address, addr_to_alias_local2); + + LOG_PRINT_MAGENTA("[ALIAS_UPDATED]: " << ai.m_alias << ": from: " << old_address << " to " << get_account_address_as_str(ai.m_address), LOG_LEVEL_0); + rise_core_event(CORE_EVENT_UPDATE_ALIAS, alias_info_to_rpc_update_alias_info(ai, old_address)); + + } + return true; +} +//------------------------------------------------------------------ +void blockchain_storage::set_event_handler(i_core_event_handler* event_handler) const +{ + if (event_handler == nullptr) + { + m_event_handler = &m_event_handler_stub; + m_services_mgr.set_event_handler(nullptr); + } + else + { + m_event_handler = event_handler; + m_services_mgr.set_event_handler(event_handler); + } + +} +//------------------------------------------------------------------ +i_core_event_handler* blockchain_storage::get_event_handler() const +{ + return m_event_handler; +} +//------------------------------------------------------------------ +uint64_t blockchain_storage::validate_alias_reward(const transaction& tx, const std::string& alias) const +{ + + //validate alias coast + uint64_t fee_for_alias = get_alias_coast(alias); + + //validate the price had been paid + uint64_t found_alias_reward = get_amount_for_zero_pubkeys(tx); + + //@#@ + //work around for net 68's generation +#if CURRENCY_FORMATION_VERSION == 68 + if (alias == "bhrfrrrtret" && get_transaction_hash(tx) == epee::string_tools::parse_tpod_from_hex_string("760b85546678d2235a1843e18d8a016a2e4d9b8273cc4d7c09bebff1f6fa7eaf") ) + return true; + if (alias == "test-420" && get_transaction_hash(tx) == epee::string_tools::parse_tpod_from_hex_string("10f8a2539b2551bd0919bf7e3b1dfbae7553eca63e58cd2264ae60f90030edf8")) + return true; +#endif + + CHECK_AND_ASSERT_MES(found_alias_reward >= fee_for_alias, false, "registration of alias '" + << alias << "' goes with a reward of " << print_money(found_alias_reward) << " which is less than expected: " << print_money(fee_for_alias) + <<"(fee median: " << get_tx_fee_median() << ")" + << ", tx: " << get_transaction_hash(tx)); + + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::prevalidate_alias_info(const transaction& tx, extra_alias_entry& eae) +{ + + bool r = validate_alias_name(eae.m_alias); + CHECK_AND_ASSERT_MES(r, false, "failed to validate alias name!"); + bool already_have_alias = false; + { + CRITICAL_REGION_LOCAL(m_read_lock); + auto existing_ptr = m_db_aliases.find(eae.m_alias); + if (existing_ptr && existing_ptr->size()) + { + already_have_alias = true; + } + + } + //auto alias_history_ptr_ = m_db_aliases.get(eae.m_alias); + if (!already_have_alias) + { + bool r = validate_alias_reward(tx, eae.m_alias); + CHECK_AND_ASSERT_MES(r, false, "failed to validate_alias_reward"); + + if (eae.m_alias.size() < ALIAS_MINIMUM_PUBLIC_SHORT_NAME_ALLOWED) + { + //short alias name, this aliases should be issued only by specific authority + CHECK_AND_ASSERT_MES(eae.m_sign.size() == 1, false, "alias " << eae.m_alias << " can't be update, wrong ai.m_sign.size() count: " << eae.m_sign.size()); + + bool r = crypto::check_signature(get_sign_buff_hash_for_alias_update(eae), m_core_runtime_config.alias_validation_pubkey, eae.m_sign.back()); + CHECK_AND_ASSERT_MES(r, false, "Failed to check signature, short alias registration failed." << ENDL + << "alias: " << eae.m_alias << ENDL + << "signed_buff_hash: " << get_sign_buff_hash_for_alias_update(eae) << ENDL + << "public key: " << m_core_runtime_config.alias_validation_pubkey << ENDL + << "new_address: " << get_account_address_as_str(eae.m_address) << ENDL + << "signature: " << epee::string_tools::pod_to_hex(eae.m_sign)); + } + } + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::process_blockchain_tx_extra(const transaction& tx) +{ + //check transaction extra + tx_extra_info ei = AUTO_VAL_INIT(ei); + bool r = parse_and_validate_tx_extra(tx, ei); + CHECK_AND_ASSERT_MES(r, false, "failed to validate transaction extra"); + if (ei.m_alias.m_alias.size()) + { + r = prevalidate_alias_info(tx, ei.m_alias); + CHECK_AND_ASSERT_MES(r, false, "failed to prevalidate_alias_info"); + + r = put_alias_info(tx, ei.m_alias); + CHECK_AND_ASSERT_MES(r, false, "failed to put_alias_info"); + } + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::get_outs_index_stat(outs_index_stat& outs_stat) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + outs_stat.amount_0_001 = m_db_outputs.get_item_size(COIN / 1000); + outs_stat.amount_0_01 = m_db_outputs.get_item_size(COIN / 100); + outs_stat.amount_0_1 = m_db_outputs.get_item_size(COIN / 10); + outs_stat.amount_1 = m_db_outputs.get_item_size(COIN); + outs_stat.amount_10 = m_db_outputs.get_item_size(COIN * 10); + outs_stat.amount_100 = m_db_outputs.get_item_size(COIN * 100); + outs_stat.amount_1000 = m_db_outputs.get_item_size(COIN * 1000); + outs_stat.amount_10000 = m_db_outputs.get_item_size(COIN * 10000); + outs_stat.amount_100000 = m_db_outputs.get_item_size(COIN * 100000); + outs_stat.amount_1000000 = m_db_outputs.get_item_size(COIN * 1000000); + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::process_blockchain_tx_attachments(const transaction& tx, uint64_t h, const crypto::hash& bl_id, uint64_t timestamp) +{ + //check transaction extra + uint64_t count = 0; + + for (const auto& at : tx.attachment) + { + if (at.type() == typeid(tx_service_attachment)) + { + m_services_mgr.handle_entry_push(boost::get(at), count, tx, h, bl_id, timestamp); //handle service + ++count; + } + } + return true; +} + +//------------------------------------------------------------------ +uint64_t blockchain_storage::get_tx_fee_median() const +{ + uint64_t h = m_db_blocks.size(); + if (m_current_fee_median_effective_index != get_tx_fee_median_effective_index(h)) + { + m_current_fee_median = tx_fee_median_for_height(h); + m_current_fee_median_effective_index = get_tx_fee_median_effective_index(h); + } + + if (!m_current_fee_median) + m_current_fee_median = ALIAS_VERY_INITAL_COAST; + return m_current_fee_median; +} +//------------------------------------------------------------------ +uint64_t blockchain_storage::get_alias_coast(const std::string& alias) const +{ + uint64_t median_fee = get_tx_fee_median(); + //CHECK_AND_ASSERT_MES_NO_RET(median_fee, "can't calculate median"); + + if (!median_fee) + median_fee = ALIAS_VERY_INITAL_COAST; + + + return get_alias_coast_from_fee(alias, median_fee); +} +//------------------------------------------------------------------ +bool blockchain_storage::unprocess_blockchain_tx_attachments(const transaction& tx, uint64_t h, uint64_t timestamp) +{ + + size_t cnt_serv_attach = get_service_attachments_count_in_tx(tx); + if (cnt_serv_attach == 0) + return true; + + --cnt_serv_attach; + for (auto it = tx.attachment.rbegin(); it != tx.attachment.rend(); it++) + { + auto& at = *it; + if (at.type() == typeid(tx_service_attachment)) + { + m_services_mgr.handle_entry_pop(boost::get(at), cnt_serv_attach, tx, h, timestamp); + --cnt_serv_attach; + } + } + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::validate_tx_service_attachmens_in_services(const tx_service_attachment& a, size_t i, const transaction& tx) const +{ + return m_services_mgr.validate_entry(a, i, tx); +} +//------------------------------------------------------------------ +namespace currency +{ + struct add_transaction_input_visitor : public boost::static_visitor + { + blockchain_storage& m_bcs; + blockchain_storage::key_images_container& m_db_spent_keys; + const crypto::hash& m_tx_id; + const crypto::hash& m_bl_id; + const uint64_t m_bl_height; + add_transaction_input_visitor(blockchain_storage& bcs, blockchain_storage::key_images_container& m_db_spent_keys, const crypto::hash& tx_id, const crypto::hash& bl_id, const uint64_t bl_height) : + m_bcs(bcs), + m_db_spent_keys(m_db_spent_keys), + m_tx_id(tx_id), + m_bl_id(bl_id), + m_bl_height(bl_height) + {} + bool operator()(const txin_to_key& in) const + { + const crypto::key_image& ki = in.k_image; + + auto ki_ptr = m_db_spent_keys.get(ki); + if (ki_ptr) + { + //double spend detected + LOG_PRINT_RED_L0("tx with id: " << m_tx_id << " in block id: " << m_bl_id << " have input marked as spent with key image: " << ki << ", block declined"); + return false; + } + m_db_spent_keys.set(ki, m_bl_height); + + if (in.key_offsets.size() == 1) + { + //direct spend detected + if (!m_bcs.update_spent_tx_flags_for_input(in.amount, in.key_offsets[0], true)) + { + //internal error + LOG_PRINT_RED_L0("Failed to update_spent_tx_flags_for_input"); + return false; + } + } + + return true; + } + + bool operator()(const txin_gen& in) const { return true; } + bool operator()(const txin_multisig& in) const + { + //mark out as spent + if (!m_bcs.update_spent_tx_flags_for_input(in.multisig_out_id, m_bl_height)) + { + //internal error + LOG_PRINT_RED_L0("Failed to update_spent_tx_flags_for_input"); + return false; + } + return true; + } + }; +} + + +bool blockchain_storage::add_transaction_from_block(const transaction& tx, const crypto::hash& tx_id, const crypto::hash& bl_id, uint64_t bl_height, uint64_t timestamp) +{ + bool need_to_profile = !is_coinbase(tx); + TIME_MEASURE_START_PD(tx_append_rl_wait); + CRITICAL_REGION_LOCAL(m_read_lock); + TIME_MEASURE_FINISH_PD_COND(need_to_profile, tx_append_rl_wait); + + TIME_MEASURE_START_PD(tx_append_is_expired); + CHECK_AND_ASSERT_MES(!is_tx_expired(tx), false, "Transaction can't be added to the blockchain since it's already expired. tx expiration time: " << get_tx_expiration_time(tx) << ", blockchain median time: " << get_tx_expiration_median()); + TIME_MEASURE_FINISH_PD_COND(need_to_profile, tx_append_is_expired); + + TIME_MEASURE_START_PD(tx_process_extra); + bool r = process_blockchain_tx_extra(tx); + CHECK_AND_ASSERT_MES(r, false, "failed to process_blockchain_tx_extra"); + TIME_MEASURE_FINISH_PD_COND(need_to_profile, tx_process_extra); + + TIME_MEASURE_START_PD(tx_process_attachment); + process_blockchain_tx_attachments(tx, bl_height, bl_id, timestamp); + TIME_MEASURE_FINISH_PD_COND(need_to_profile, tx_process_attachment); + + + TIME_MEASURE_START_PD(tx_process_inputs); + BOOST_FOREACH(const txin_v& in, tx.vin) + { + if(!boost::apply_visitor(add_transaction_input_visitor(*this, m_db_spent_keys, tx_id, bl_id, bl_height), in)) + { + LOG_ERROR("critical internal error: add_transaction_input_visitor failed. but key_images should be already checked"); + purge_transaction_keyimages_from_blockchain(tx, false); + bool r = unprocess_blockchain_tx_extra(tx); + CHECK_AND_ASSERT_MES(r, false, "failed to unprocess_blockchain_tx_extra"); + + unprocess_blockchain_tx_attachments(tx, bl_height, timestamp); + + return false; + } + } + TIME_MEASURE_FINISH_PD_COND(need_to_profile, tx_process_inputs); + + //check if there is already transaction with this hash + TIME_MEASURE_START_PD(tx_check_exist); + auto tx_entry_ptr = m_db_transactions.get(tx_id); + if (tx_entry_ptr) + { + LOG_ERROR("critical internal error: tx with id: " << tx_id << " in block id: " << bl_id << " already in blockchain"); + purge_transaction_keyimages_from_blockchain(tx, true); + bool r = unprocess_blockchain_tx_extra(tx); + CHECK_AND_ASSERT_MES(r, false, "failed to unprocess_blockchain_tx_extra"); + + unprocess_blockchain_tx_attachments(tx, bl_height, timestamp); + return false; + } + TIME_MEASURE_FINISH_PD_COND(need_to_profile, tx_check_exist); + TIME_MEASURE_START_PD(tx_push_global_index); + transaction_chain_entry ch_e; + ch_e.m_keeper_block_height = bl_height; + ch_e.m_spent_flags.resize(tx.vout.size(), false); + ch_e.tx = tx; + r = push_transaction_to_global_outs_index(tx, tx_id, ch_e.m_global_output_indexes); + CHECK_AND_ASSERT_MES(r, false, "failed to return push_transaction_to_global_outs_index tx id " << tx_id); + TIME_MEASURE_FINISH_PD_COND(need_to_profile, tx_push_global_index); + + //store everything to db + TIME_MEASURE_START_PD(tx_store_db); + m_db_transactions.set(tx_id, ch_e); + TIME_MEASURE_FINISH_PD_COND(need_to_profile, tx_store_db); + + TIME_MEASURE_START_PD(tx_print_log); + LOG_PRINT_L1("Added tx to blockchain: " << tx_id << " via block at " << bl_height << " id " << print16(bl_id) + << ", ins: " << tx.vin.size() << ", outs: " << tx.vout.size() << ", outs sum: " << print_money_brief(get_outs_money_amount(tx)) << " (fee: " << (is_coinbase(tx) ? "0[coinbase]" : print_money_brief(get_tx_fee(tx))) << ")"); + TIME_MEASURE_FINISH_PD_COND(need_to_profile, tx_print_log); + //@#@ del me +// LOG_PRINT_L0("APPEND_TX_TIME_INNER: " << m_performance_data.tx_append_rl_wait.get_last_val() +// << " | " << m_performance_data.tx_append_is_expired.get_last_val() +// << " | " << m_performance_data.tx_process_extra.get_last_val() +// << " | " << m_performance_data.tx_process_attachment.get_last_val() +// << " | " << m_performance_data.tx_process_inputs.get_last_val() +// << " | " << m_performance_data.tx_check_exist.get_last_val() +// << " | " << m_performance_data.tx_push_global_index.get_last_val() +// << " | " << m_performance_data.tx_store_db.get_last_val() +// << " | " << m_performance_data.tx_print_log.get_last_val() +// ); + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector& indexs)const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + auto tx_ptr = m_db_transactions.find(tx_id); + if (!tx_ptr) + { + LOG_PRINT_RED_L0("warning: get_tx_outputs_gindexs failed to find transaction with id = " << tx_id); + return false; + } + + CHECK_AND_ASSERT_MES(tx_ptr->m_global_output_indexes.size(), false, "internal error: global indexes for transaction " << tx_id << " is empty"); + indexs = tx_ptr->m_global_output_indexes; + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t& max_used_block_height, crypto::hash& max_used_block_id) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + bool res = check_tx_inputs(tx, tx_prefix_hash, &max_used_block_height); + if(!res) return false; + CHECK_AND_ASSERT_MES(max_used_block_height < m_db_blocks.size(), false, "internal error: max used block index=" << max_used_block_height << " is not less then blockchain size = " << m_db_blocks.size()); + get_block_hash(m_db_blocks[max_used_block_height]->bl, max_used_block_id); + return true; +} +//------------------------------------------------------------------ +#define PERIOD_DISABLED 0xffffffffffffffffLL + +bool blockchain_storage::rebuild_tx_fee_medians() +{ + uint64_t sz = m_db_blocks.size(); + m_db.begin_transaction(); + LOG_PRINT_L0("Started reinitialization of median fee..."); + math_helper::once_a_time_seconds<10> log_idle; + + epee::misc_utils::median_helper blocks_median; + for (uint64_t i = 0; i != sz; i++) + { + log_idle.do_call([&]() {std::cout << "block " << i << " of " << sz << std::endl; return true; }); + + auto bptr = m_db_blocks[i]; + block_extended_info new_bei = *bptr; + //assign effective median + new_bei.effective_tx_fee_median = blocks_median.get_median(); + + //calculate current median for this particular block + std::vector fees; + for (auto& h: new_bei.bl.tx_hashes) + { + auto txptr = get_tx_chain_entry(h); + CHECK_AND_ASSERT_MES(txptr, false, "failed to find tx id " << h << " from block " << i); + fees.push_back(get_tx_fee(txptr->tx)); + } + new_bei.this_block_tx_fee_median = epee::misc_utils::median(fees); + m_db_blocks.set(i, new_bei); + + + //prepare median helper for next block + if(new_bei.this_block_tx_fee_median) + blocks_median.push_item(new_bei.this_block_tx_fee_median, i); + + //create callbacks + + bool is_pos_allowed_l = i >= m_core_runtime_config.pos_minimum_heigh; + uint64_t period = is_pos_allowed_l ? ALIAS_COAST_PERIOD : ALIAS_COAST_PERIOD / 2; + if (period >= i+1) + continue; + uint64_t starter_block_index = i+1 - period; + + uint64_t purge_recent_period = is_pos_allowed_l ? ALIAS_COAST_RECENT_PERIOD : ALIAS_COAST_RECENT_PERIOD / 2; + uint64_t purge_recent_block_index = 0; + if (purge_recent_period >= i + 1) + purge_recent_block_index = PERIOD_DISABLED; + else + purge_recent_block_index = i + 1 - purge_recent_period; + + + auto cb = [&](uint64_t fee, uint64_t height) + { + if (height >= starter_block_index) + return true; + return false; + }; + + auto cb_final_eraser = [&](uint64_t fee, uint64_t height) + { + if (purge_recent_block_index == PERIOD_DISABLED) + return true; + if (height >= purge_recent_block_index) + return true; + + return false; + }; + + blocks_median.scan_items(cb, cb_final_eraser); + } + + m_db.commit_transaction(); + LOG_PRINT_L0("Reinitialization of median fee finished!") + return true; +} +//------------------------------------------------------------------ +uint64_t blockchain_storage::get_tx_fee_median_effective_index(uint64_t h)const +{ + if (h <= ALIAS_MEDIAN_RECALC_INTERWAL + 1) + return 0; + + h -= 1; // for transactions of block that h%ALIAS_MEDIAN_RECALC_INTERWAL==0 we still handle fee median from previous day + return h - (h % ALIAS_MEDIAN_RECALC_INTERWAL); +} +//------------------------------------------------------------------ +uint64_t blockchain_storage::tx_fee_median_for_height(uint64_t h)const +{ + uint64_t effective_index = get_tx_fee_median_effective_index(h); + CHECK_AND_ASSERT_THROW_MES(effective_index < m_db_blocks.size(), "internal error: effective_index= " << effective_index << " while m_db_blocks.size()=" << m_db_blocks.size()); + return m_db_blocks[effective_index]->effective_tx_fee_median; +} +//------------------------------------------------------------------ +bool blockchain_storage::validate_all_aliases_for_new_median_mode() +{ + + LOG_PRINT_L0("Started reinitialization of median fee..."); + math_helper::once_a_time_seconds<10> log_idle; + uint64_t sz = m_db_blocks.size(); + for (uint64_t i = 0; i != sz; i++) + { + log_idle.do_call([&]() {std::cout << "block " << i << " of " << sz << std::endl; return true; }); + + auto bptr = m_db_blocks[i]; + for (auto& tx_id : bptr->bl.tx_hashes) + { + auto tx_ptr = m_db_transactions.find(tx_id); + CHECK_AND_ASSERT_MES(tx_ptr, false, "Internal error: tx " << tx_id << " from block " << i << " not found"); + tx_extra_info tei = AUTO_VAL_INIT(tei); + bool r = parse_and_validate_tx_extra(tx_ptr->tx, tei); + CHECK_AND_ASSERT_MES(r, false, "Internal error: tx " << tx_id << " from block " << i << " was failed to parse"); + if (tei.m_alias.m_alias.size() && !tei.m_alias.m_sign.size()) + { + //reward + //validate alias coast + uint64_t median_fee = tx_fee_median_for_height(i); + uint64_t fee_for_alias = get_alias_coast_from_fee(tei.m_alias.m_alias, median_fee); + + //validate the price had been paid + uint64_t found_alias_reward = get_amount_for_zero_pubkeys(tx_ptr->tx); + if (found_alias_reward < fee_for_alias) + { + LOG_PRINT_RED_L0("[" << i << "]Found collision on alias: " << tei.m_alias.m_alias + << ", expected fee: " << print_money(fee_for_alias) << "(median:" << print_money(median_fee) << ")" + <<" found reward: " << print_money(found_alias_reward) <<". tx_id: " << tx_id); + } + } + } + } + + LOG_PRINT_L0("Finished."); + + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::have_tx_keyimges_as_spent(const transaction &tx) const +{ + // check all tx's inputs for being already spent + for (const txin_v& in : tx.vin) + { + if (in.type() == typeid(txin_to_key)) + { + if (have_tx_keyimg_as_spent(boost::get(in).k_image)) + return true; + } + else if (in.type() == typeid(txin_multisig)) + { + if (is_multisig_output_spent(boost::get(in).multisig_out_id)) + return true; + } + else if (in.type() == typeid(txin_gen)) + { + // skip txin_gen + } + else + { + LOG_ERROR("Unexpected input type: " << in.type().name()); + } + } + return false; +} +//------------------------------------------------------------------ +// bool blockchain_storage::check_tx_inputs(const transaction& tx, uint64_t* pmax_used_block_height) const +// { +// TIME_MEASURE_START_PD(tx_check_inputs_prefix_hash); +// crypto::hash tx_prefix_hash = get_transaction_prefix_hash(tx); +// TIME_MEASURE_FINISH_PD(tx_check_inputs_prefix_hash); +// return check_tx_inputs(tx, tx_prefix_hash, pmax_used_block_height); +// } +//------------------------------------------------------------------ +bool blockchain_storage::check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t* pmax_used_block_height) const +{ + size_t sig_index = 0; + if(pmax_used_block_height) + *pmax_used_block_height = 0; + + std::vector sig_stub; + const std::vector* psig = &sig_stub; + + TIME_MEASURE_START_PD(tx_check_inputs_loop); + BOOST_FOREACH(const auto& txin, tx.vin) + { + if (!m_is_in_checkpoint_zone) + { + CHECK_AND_ASSERT_MES(sig_index < tx.signatures.size(), false, "Wrong transaction: missing signature entry for input #" << sig_index << " tx: " << tx_prefix_hash); + psig = &tx.signatures[sig_index]; + } + + if (txin.type() == typeid(txin_to_key)) + { + const txin_to_key& in_to_key = boost::get(txin); + + CHECK_AND_ASSERT_MES(in_to_key.key_offsets.size(), false, "Empty in_to_key.key_offsets for input #" << sig_index << " tx: " << tx_prefix_hash); + TIME_MEASURE_START_PD(tx_check_inputs_loop_kimage_check); + if (have_tx_keyimg_as_spent(in_to_key.k_image)) + { + LOG_ERROR("Key image was already spent in blockchain: " << string_tools::pod_to_hex(in_to_key.k_image) << " for input #" << sig_index << " tx: " << tx_prefix_hash); + return false; + } + TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_kimage_check); + if (!check_tx_input(tx, sig_index, in_to_key, tx_prefix_hash, *psig, pmax_used_block_height)) + { + LOG_ERROR("Failed to validate input #" << sig_index << " tx: " << tx_prefix_hash); + return false; + } + } + else if (txin.type() == typeid(txin_multisig)) + { + const txin_multisig& in_ms = boost::get(txin); + if (!check_tx_input(tx, sig_index, in_ms, tx_prefix_hash, *psig, pmax_used_block_height)) + { + LOG_ERROR("Failed to validate multisig input #" << sig_index << " (ms out id: " << in_ms.multisig_out_id << ") in tx: " << tx_prefix_hash); + return false; + } + + } + sig_index++; + } + TIME_MEASURE_FINISH_PD(tx_check_inputs_loop); + + TIME_MEASURE_START_PD(tx_check_inputs_attachment_check); + if (!m_is_in_checkpoint_zone) + { + CHECK_AND_ASSERT_MES(tx.signatures.size() == sig_index, false, "tx signatures count differs from inputs"); + if (!get_tx_flags(tx)&TX_FLAG_SIGNATURE_MODE_SEPARATE) + { + bool r = validate_attachment_info(tx.extra, tx.attachment, false); + CHECK_AND_ASSERT_MES(r, false, "Failed to validate attachments in tx " << tx_prefix_hash << ": incorrect extra_attachment_info in tx.extra"); + } + } + TIME_MEASURE_FINISH_PD(tx_check_inputs_attachment_check); + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::is_tx_spendtime_unlocked(uint64_t unlock_time) const +{ + return currency::is_tx_spendtime_unlocked(unlock_time, get_current_blockchain_size(), m_core_runtime_config.get_core_time()); +} + +//------------------------------------------------------------------ +bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, uint64_t* pmax_related_block_height) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + + //TIME_MEASURE_START_PD(tx_check_inputs_loop_ch_in_get_keys_loop); + + std::vector output_keys; + if(!get_output_keys_for_input_with_checks(txin, output_keys, pmax_related_block_height)) + { + LOG_PRINT_L0("Failed to get output keys for input #" << in_index << " (amount = " << print_money(txin.amount) << ", key_offset.size = " << txin.key_offsets.size() << ")"); + return false; + } + //TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_ch_in_get_keys_loop); + + std::vector output_keys_ptrs; + output_keys_ptrs.reserve(output_keys.size()); + for (auto& ptr : output_keys) + output_keys_ptrs.push_back(&ptr); + + return check_tokey_input(tx, in_index, txin, tx_prefix_hash, sig, output_keys_ptrs); +} +//------------------------------------------------------------------ +// Checks each referenced output for: +// 1) source tx unlock time validity +// 2) mixin restrictions +// 3) general gindex/ref_by_id corectness +bool blockchain_storage::get_output_keys_for_input_with_checks(const txin_to_key& txin, std::vector& output_keys, uint64_t* pmax_related_block_height /* = NULL */) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + + struct outputs_visitor + { + std::vector& m_results_collector; + const blockchain_storage& m_bch; + outputs_visitor(std::vector& results_collector, + const blockchain_storage& bch) :m_results_collector(results_collector), m_bch(bch) + {} + bool handle_output(const transaction& tx, const tx_out& out) + { + //check tx unlock time + if (!m_bch.is_tx_spendtime_unlocked(get_tx_unlock_time(tx))) + { + LOG_PRINT_L0("One of outputs for one of inputs have wrong tx.unlock_time = " << get_tx_unlock_time(tx)); + return false; + } + + if(out.target.type() != typeid(txout_to_key)) + { + LOG_PRINT_L0("Output have wrong type id, which=" << out.target.which()); + return false; + } + crypto::public_key pk = boost::get(out.target).key; + m_results_collector.push_back(pk); + return true; + } + }; + + outputs_visitor vi(output_keys, *this); + return scan_outputkeys_for_indexes(txin, vi, pmax_related_block_height); +} +//------------------------------------------------------------------ +// Note: this function can be used for checking to_key inputs against either main chain or alt chain, that's why it has output_keys_ptrs parameter +// Doesn't check spent flags, the caller must check it. +bool blockchain_storage::check_tokey_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, const std::vector& output_keys_ptrs) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + + TIME_MEASURE_START_PD(tx_check_inputs_loop_ch_in_val_sig); + + if (txin.key_offsets.size() != output_keys_ptrs.size()) + { + LOG_PRINT_L0("Output keys for tx with amount = " << txin.amount << " and count indexes " << txin.key_offsets.size() << " returned wrong keys count " << output_keys_ptrs.size()); + return false; + } + + if(m_is_in_checkpoint_zone) + return true; + + if (get_tx_flags(tx) & TX_FLAG_SIGNATURE_MODE_SEPARATE) + { + // check attachments, mentioned directly in this input + bool r = validate_attachment_info(txin.etc_details, tx.attachment, in_index != tx.vin.size() - 1); // attachment info can be omitted for all inputs, except the last one + CHECK_AND_ASSERT_MES(r, false, "Failed to validate attachments in tx " << tx_prefix_hash << ": incorrect extra_attachment_info in etc_details in input #" << in_index); + } + else + { + // make sure normal tx does not have extra_attachment_info in etc_details + CHECK_AND_ASSERT_MES(!have_type_in_variant_container(txin.etc_details), false, "Incorrect using of extra_attachment_info in etc_details in input #" << in_index << " for tx " << tx_prefix_hash); + } + + // check signatures + size_t expected_signatures_count = output_keys_ptrs.size(); + bool need_to_check_extra_sign = false; + if (get_tx_flags(tx)&TX_FLAG_SIGNATURE_MODE_SEPARATE && in_index == tx.vin.size() - 1) + { + expected_signatures_count++; + need_to_check_extra_sign = true; + } + + CHECK_AND_ASSERT_MES(expected_signatures_count == sig.size(), false, "internal error: tx signatures count=" << sig.size() << " mismatch with outputs keys count for inputs=" << expected_signatures_count); + crypto::hash tx_hash_for_signature = prepare_prefix_hash_for_sign(tx, in_index, tx_prefix_hash); + CHECK_AND_ASSERT_MES(tx_hash_for_signature != null_hash, false, "failed to prepare_prefix_hash_for_sign"); + + LOG_PRINT_L4("CHECK RING SIGNATURE: tx_prefix_hash " << tx_prefix_hash + << "tx_hash_for_signature" << tx_hash_for_signature + << "txin.k_image" << txin.k_image + << "key_ptr:" << *output_keys_ptrs[0] + << "signature:" << sig[0]); + bool r = crypto::validate_key_image(txin.k_image); + CHECK_AND_ASSERT_MES(r, false, "key image for input #" << in_index << " is invalid: " << txin.k_image); + + r = crypto::check_ring_signature(tx_hash_for_signature, txin.k_image, output_keys_ptrs, sig.data()); + CHECK_AND_ASSERT_MES(r, false, "failed to check ring signature for input #" << in_index << ENDL << dump_ring_sig_data(tx_hash_for_signature, txin.k_image, output_keys_ptrs, sig)); + if (need_to_check_extra_sign) + { + //here we check extra signature to validate that transaction was finalized by authorized subject + r = crypto::check_signature(tx_prefix_hash, get_tx_pub_key_from_extra(tx), sig.back()); + CHECK_AND_ASSERT_MES(r, false, "failed to check extra signature for last input with TX_FLAG_SIGNATURE_MODE_SEPARATE"); + } + + TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_ch_in_val_sig); + return r; +} +//------------------------------------------------------------------ +// Note: this function doesn't check spent flags by design (to be able to use either for main chain and alt chains). +// The caller MUST check spent flags. +bool blockchain_storage::check_ms_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, const transaction& source_tx, size_t out_n) const +{ +#define LOC_CHK(cond, msg) CHECK_AND_ASSERT_MES(cond, false, "ms input check failed: ms_id: " << txin.multisig_out_id << ", input #" << in_index << " in tx " << tx_prefix_hash << ", refers to ms output #" << out_n << " in source tx " << get_transaction_hash(source_tx) << ENDL << msg) + CRITICAL_REGION_LOCAL(m_read_lock); + + uint64_t unlock_time = get_tx_unlock_time(source_tx); + LOC_CHK(is_tx_spendtime_unlocked(unlock_time), "Source transaction is LOCKED! unlock_time: " << unlock_time << ", now is " << m_core_runtime_config.get_core_time() << ", blockchain size is " << get_current_blockchain_size()); + + LOC_CHK(source_tx.vout.size() > out_n, "internal error: out_n==" << out_n << " is out-of-bounds of source_tx.vout, size=" << source_tx.vout.size()); + const tx_out& source_tx_out = source_tx.vout[out_n]; + const txout_multisig& source_ms_out_target = boost::get(source_tx_out.target); + + LOC_CHK(txin.sigs_count == source_ms_out_target.minimum_sigs, + "ms input's sigs_count (" << txin.sigs_count << ") does not match to ms output's minimum signatures expected (" << source_ms_out_target.minimum_sigs << ")" + << ", source_tx_out.amount=" << print_money(source_tx_out.amount) + << ", txin.amount = " << print_money(txin.amount)); + + LOC_CHK(source_tx_out.amount == txin.amount, + "amount missmatch" + << ", source_tx_out.amount=" << print_money(source_tx_out.amount) + << ", txin.amount = " << print_money(txin.amount)); + + if (m_is_in_checkpoint_zone) + return true; + + if (get_tx_flags(tx) & TX_FLAG_SIGNATURE_MODE_SEPARATE) + { + // check attachments, mentioned directly in this input + bool r = validate_attachment_info(txin.etc_details, tx.attachment, in_index != tx.vin.size() - 1); // attachment info can be omitted for all inputs, except the last one + LOC_CHK(r, "Failed to validate attachments in tx " << tx_prefix_hash << ": incorrect extra_attachment_info in etc_details in input #" << in_index); + } + else + { + // make sure normal tx does not have extra_attachment_info in etc_details + LOC_CHK(!have_type_in_variant_container(txin.etc_details), "Incorrect using of extra_attachment_info in etc_details in input #" << in_index << " for tx " << tx_prefix_hash); + } + + LOC_CHK(tx.signatures.size() > in_index, "ms input index is out of signatures container bounds, tx.signatures.size() = " << tx.signatures.size()); + const std::vector& input_signatures = tx.signatures[in_index]; + + size_t expected_signatures_count = txin.sigs_count; + bool need_to_check_extra_sign = false; + if (get_tx_flags(tx)&TX_FLAG_SIGNATURE_MODE_SEPARATE && in_index == tx.vin.size() - 1) // last input in TX_FLAG_SIGNATURE_MODE_SEPARATE must contain one more signature to ensure that tx was completed by an authorized subject + { + expected_signatures_count++; + need_to_check_extra_sign = true; + } + + LOC_CHK(expected_signatures_count == input_signatures.size(), "Invalid input's signatures count: " << input_signatures.size() << ", expected: " << expected_signatures_count); + + crypto::hash tx_hash_for_signature = prepare_prefix_hash_for_sign(tx, in_index, tx_prefix_hash); + LOC_CHK(tx_hash_for_signature != null_hash, "prepare_prefix_hash_for_sign failed"); + + LOC_CHK(txin.sigs_count <= source_ms_out_target.keys.size(), "source tx invariant failed: ms output's minimum sigs == ms input's sigs_count (" << txin.sigs_count << ") is GREATHER than keys.size() = " << source_ms_out_target.keys.size()); // NOTE: sig_count == minimum_sigs as checked above + size_t out_key_index = 0; // index in source_ms_out_target.keys + for (size_t i = 0; i != txin.sigs_count; /* nothing */) + { + // if we run out of keys for this signature, then it's invalid signature + LOC_CHK(out_key_index < source_ms_out_target.keys.size(), "invalid signature #" << i << ": " << input_signatures[i]); + + // check signature #i against ms output key #out_key_index + if (crypto::check_signature(tx_hash_for_signature, source_ms_out_target.keys[out_key_index], input_signatures[i])) + { + // match: go for the next signature and the next key + i++; + out_key_index++; + } + else + { + // missmatch: go for the next key for this signature + out_key_index++; + } + } + if (need_to_check_extra_sign) + { + //here we check extra signature to validate that transaction was finilized by authorized subject + bool r = crypto::check_signature(tx_prefix_hash, get_tx_pub_key_from_extra(tx), tx.signatures[in_index].back()); + LOC_CHK(r, "failed to check extra signature for last out with TX_FLAG_SIGNATURE_MODE_SEPARATE"); + } + + return true; +#undef LOC_CHK +} + +//------------------------------------------------------------------ +bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, uint64_t* pmax_related_block_height) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + + auto multisig_ptr = m_db_multisig_outs.find(txin.multisig_out_id); + CHECK_AND_ASSERT_MES(multisig_ptr, false, "Unable to find txin.multisig_out_id=" << txin.multisig_out_id << " for ms input #" << in_index << " in tx " << tx_prefix_hash); + + const crypto::hash& source_tx_id = multisig_ptr->tx_id; // source tx hash + size_t n = multisig_ptr->out_no; // index of multisig output in source tx + +#define LOC_CHK(cond, msg) CHECK_AND_ASSERT_MES(cond, false, "ms input check failed: ms_id: " << txin.multisig_out_id << ", input #" << in_index << " in tx " << tx_prefix_hash << ", refers to ms output #" << n << " in source tx " << source_tx_id << ENDL << msg) + + LOC_CHK(multisig_ptr->spent_height == 0, "ms output is already spent on height " << multisig_ptr->spent_height); + + auto source_tx_ptr = m_db_transactions.find(source_tx_id); + LOC_CHK(source_tx_ptr, "Can't find source transaction"); + LOC_CHK(source_tx_ptr->tx.vout.size() > n, "ms output index is incorrect, source tx's vout size is " << source_tx_ptr->tx.vout.size()); + LOC_CHK(source_tx_ptr->tx.vout[n].target.type() == typeid(txout_multisig), "ms output has wrong type, txout_multisig expected"); + LOC_CHK(source_tx_ptr->m_spent_flags.size() > n, "Internal error, m_spent_flags size (" << source_tx_ptr->m_spent_flags.size() << ") less then expected, n: " << n); + LOC_CHK(source_tx_ptr->m_spent_flags[n] == false, "Internal error, ms output is already spent"); // should never happen as multisig_ptr->spent_height is checked above + + if (!check_ms_input(tx, in_index, txin, tx_prefix_hash, sig, source_tx_ptr->tx, n)) + return false; + + if (pmax_related_block_height != nullptr) + *pmax_related_block_height = source_tx_ptr->m_keeper_block_height; + + return true; +#undef LOC_CHK +} +//------------------------------------------------------------------ +uint64_t blockchain_storage::get_adjusted_time() const +{ + //TODO: add collecting median time + return m_core_runtime_config.get_core_time(); +} +//------------------------------------------------------------------ +std::vector blockchain_storage::get_last_n_blocks_timestamps(size_t n) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + std::vector timestamps; + size_t offset = m_db_blocks.size() <= n ? 0 : m_db_blocks.size() - n; + for (; offset != m_db_blocks.size(); ++offset) + timestamps.push_back(m_db_blocks[offset]->bl.timestamp); + return timestamps; +} +//------------------------------------------------------------------ +uint64_t blockchain_storage::get_last_n_blocks_timestamps_median(size_t n) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + auto it = m_timestamps_median_cache.find(n); + if (it != m_timestamps_median_cache.end()) + return it->second; + + std::vector timestamps = get_last_n_blocks_timestamps(n); + uint64_t median_res = epee::misc_utils::median(timestamps); + m_timestamps_median_cache[n] = median_res; + return median_res; +} +//------------------------------------------------------------------ +uint64_t blockchain_storage::get_last_timestamps_check_window_median() const +{ + return get_last_n_blocks_timestamps_median(BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW); +} +//------------------------------------------------------------------ +uint64_t blockchain_storage::get_tx_expiration_median() const +{ + return get_last_n_blocks_timestamps_median(TX_EXPIRATION_TIMESTAMP_CHECK_WINDOW); +} +//------------------------------------------------------------------ +bool blockchain_storage::check_block_timestamp_main(const block& b) const +{ + if(b.timestamp > get_adjusted_time() + CURRENCY_BLOCK_FUTURE_TIME_LIMIT) + { + LOG_PRINT_L0("Timestamp of block with id: " << get_block_hash(b) << ", " << b.timestamp << ", bigger than adjusted time + " + epee::misc_utils::get_time_interval_string(CURRENCY_BLOCK_FUTURE_TIME_LIMIT)); + return false; + } + if (is_pos_block(b) && b.timestamp > get_adjusted_time() + CURRENCY_POS_BLOCK_FUTURE_TIME_LIMIT) + { + LOG_PRINT_L0("Timestamp of PoS block with id: " << get_block_hash(b) << ", " << b.timestamp << ", bigger than adjusted time + " + epee::misc_utils::get_time_interval_string(CURRENCY_POS_BLOCK_FUTURE_TIME_LIMIT) + ": " << get_adjusted_time() << " (" << b.timestamp - get_adjusted_time() << ")"); + return false; + } + + std::vector timestamps = get_last_n_blocks_timestamps(BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW); + + return check_block_timestamp(std::move(timestamps), b); +} +//------------------------------------------------------------------ +bool blockchain_storage::check_block_timestamp(std::vector timestamps, const block& b) const +{ + if(timestamps.size() < BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW) + return true; + + if (is_pos_block(b) && b.timestamp > get_adjusted_time() + CURRENCY_POS_BLOCK_FUTURE_TIME_LIMIT) + { + LOG_PRINT_L0("Timestamp of PoS block with id: " << get_block_hash(b) << ", " << b.timestamp << ", bigger than adjusted time + " + epee::misc_utils::get_time_interval_string(CURRENCY_POS_BLOCK_FUTURE_TIME_LIMIT) + ": " << get_adjusted_time() << " (" << b.timestamp - get_adjusted_time() << ")"); + return false; + } + + uint64_t median_ts = epee::misc_utils::median(timestamps); + + if(b.timestamp < median_ts) + { + LOG_PRINT_L0("Timestamp of block with id: " << get_block_hash(b) << ", " << b.timestamp << ", less than median of last " << BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW << " blocks, " << median_ts); + return false; + } + + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::is_tx_expired(const transaction& tx) const +{ + return currency::is_tx_expired(tx, get_tx_expiration_median()); +} +//------------------------------------------------------------------ +std::shared_ptr blockchain_storage::find_key_image_and_related_tx(const crypto::key_image& ki, crypto::hash& id_result) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + auto ki_index_ptr = m_db_spent_keys.find(ki); + if (!ki_index_ptr) + return std::shared_ptr(); + + auto block_entry = m_db_blocks[*ki_index_ptr]; + if (!block_entry) + { + LOG_ERROR("Internal error: broken index, key image " << ki + << " reffered to height " << *ki_index_ptr << " but couldnot find block on this height"); + return std::shared_ptr(); + } + + //look up coinbase + for (auto& in: block_entry->bl.miner_tx.vin) + { + if (in.type() == typeid(txin_to_key)) + { + if (boost::get(in).k_image == ki) + { + id_result = get_transaction_hash(block_entry->bl.miner_tx); + return get_tx_chain_entry(id_result); + } + } + } + //lookup transactions + for (auto& tx_id : block_entry->bl.tx_hashes) + { + auto tx_chain_entry = get_tx_chain_entry(tx_id); + if (!tx_chain_entry) + { + LOG_ERROR("Internal error: broken index, tx_id " << tx_id + << " not found in tx index, block no " << *ki_index_ptr); + return std::shared_ptr(); + } + for (auto& in : tx_chain_entry->tx.vin) + { + if (in.type() == typeid(txin_to_key)) + { + if (boost::get(in).k_image == ki) + { + id_result = get_transaction_hash(tx_chain_entry->tx); + return tx_chain_entry; + } + } + } + } + return std::shared_ptr(); +} +//------------------------------------------------------------------ +bool blockchain_storage::prune_aged_alt_blocks() +{ + CRITICAL_REGION_LOCAL(m_read_lock); + CRITICAL_REGION_LOCAL1(m_alternative_chains_lock); + uint64_t current_height = get_current_blockchain_size(); + + for(auto it = m_alternative_chains.begin(); it != m_alternative_chains.end();) + { + if (current_height > it->second.height && current_height - it->second.height > CURRENCY_ALT_BLOCK_LIVETIME_COUNT) + { + do_erase_altblock(it++); + } + else + { + ++it; + } + } + + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::validate_pos_block(const block& b, const crypto::hash& id, bool for_altchain) const +{ + //validate + wide_difficulty_type basic_diff = get_next_diff_conditional(true); + return validate_pos_block(b, basic_diff, id, for_altchain); +} +//------------------------------------------------------------------ +bool blockchain_storage::validate_pos_block(const block& b, wide_difficulty_type basic_diff, const crypto::hash& id, bool for_altchain) const +{ + uint64_t coin_age = 0; + wide_difficulty_type final_diff = 0; + crypto::hash proof_hash = null_hash; + return validate_pos_block(b, basic_diff, coin_age, final_diff, proof_hash, id, for_altchain); +} +//------------------------------------------------------------------ +#define POS_STAKE_TO_DIFF_COEFF 100 // total_coins_in_minting * POS_STAKE_TO_DIFF_COEFF =~ pos_difficulty + +void blockchain_storage::get_pos_mining_estimate(uint64_t amount_coins, + uint64_t time, + uint64_t& estimate_result, + uint64_t& pos_diff_and_amount_rate, + std::vector& days) const +{ + estimate_result = 0; + if (!is_pos_allowed()) + return; + + // new algo + // 1. get (CURRENCY_BLOCKS_PER_DAY / 2) PoS blocks (a day in case of PoS/PoW==50/50) + // 2. calculate total minted money C (normalized for 1 day interval) and average difficulty D (based on last (CURRENCY_BLOCKS_PER_DAY / 2) PoS blocks) + // 3. calculate total coins participating in PoS minting as M = D / pos_diff_ratio + // 4. calculate owner's money proportion as P = amount_coins / (M + amount_coins) + // 5. estimate PoS minting income for this day as I = C * P + // 6. amount_coins += I, goto 3 + + epee::critical_region_t read_lock_region(m_read_lock); + + size_t estimated_pos_blocks_count_per_day = CURRENCY_BLOCKS_PER_DAY / 2; // 50% of all blocks in a perfect world + + uint64_t pos_ts_min = UINT64_MAX, pos_ts_max = 0; + size_t pos_blocks_count = 0; + uint64_t pos_total_minted_money = 0; + wide_difficulty_type pos_avg_difficulty = 0; + // scan blockchain backward for PoS blocks and collect data + for (size_t h = m_db_blocks.size() - 1; h != 0 && pos_blocks_count < estimated_pos_blocks_count_per_day; --h) + { + auto bei = m_db_blocks[h]; + if (!is_pos_block(bei->bl)) + continue; + uint64_t ts = get_actual_timestamp(bei->bl); + pos_ts_min = min(pos_ts_min, ts); + pos_ts_max = max(pos_ts_max, ts); + pos_total_minted_money += get_reward_from_miner_tx(bei->bl.miner_tx); + pos_avg_difficulty += bei->difficulty; + ++pos_blocks_count; + } + if (pos_blocks_count < estimated_pos_blocks_count_per_day || pos_ts_max <= pos_ts_min) + return; // too little pos blocks found or invalid ts + pos_avg_difficulty /= pos_blocks_count; + uint64_t found_blocks_interval = pos_ts_max - pos_ts_min; // will be close to 24 * 60 * 60 in case of PoS/PoW == 50/50 + uint64_t pos_last_day_total_minted_money = pos_total_minted_money * (24 * 60 * 60) / found_blocks_interval; // total minted money normalized for 1 day interval + + uint64_t estimated_total_minting_coins = static_cast(pos_avg_difficulty / POS_STAKE_TO_DIFF_COEFF); + + uint64_t current_amount = amount_coins; + uint64_t days_count = time / (60 * 60 * 24); + for (uint64_t d = 0; d != days_count; d++) + { + double user_minting_coins_proportion = static_cast(current_amount) / (estimated_total_minting_coins + current_amount); + current_amount += pos_last_day_total_minted_money * user_minting_coins_proportion; + days.push_back(current_amount); + } + estimate_result = current_amount; +} +//------------------------------------------------------------------ +bool blockchain_storage::validate_pos_block(const block& b, + wide_difficulty_type basic_diff, + uint64_t& amount, + wide_difficulty_type& final_diff, + crypto::hash& proof_hash, + const crypto::hash& id, + bool for_altchain, + const alt_chain_type& alt_chain, + uint64_t split_height + )const +{ + bool is_pos = is_pos_block(b); + CHECK_AND_ASSERT_MES(is_pos, false, "is_pos_block() returned false validate_pos_block()"); + + //check timestamp + CHECK_AND_ASSERT_MES(b.timestamp%POS_SCAN_STEP == 0, false, "wrong timestamp in PoS block(b.timestamp%POS_SCAN_STEP == 0), b.timestamp = " <(b.miner_tx.vin[1]); + if (!for_altchain && have_tx_keyimg_as_spent(in_to_key.k_image)) + { + LOG_PRINT_L0("Key image in coinstake already spent in blockchain: " << string_tools::pod_to_hex(in_to_key.k_image)); + return false; + } + + + //check actual time if it there + uint64_t actual_ts = get_actual_timestamp(b); + if ((actual_ts > b.timestamp && actual_ts - b.timestamp > POS_MAC_ACTUAL_TIMESTAMP_TO_MINED) || + (actual_ts < b.timestamp && b.timestamp - actual_ts > POS_MAC_ACTUAL_TIMESTAMP_TO_MINED) + ) + { + LOG_PRINT_L0("PoS block actual timestamp " << actual_ts << " differs from b.timestamp " << b.timestamp << " by " << ((int64_t)actual_ts - (int64_t)b.timestamp) << " s, it's more than allowed " << POS_MAC_ACTUAL_TIMESTAMP_TO_MINED << " s."); + return false; + } + + //check kernel + stake_kernel sk = AUTO_VAL_INIT(sk); + + stake_modifier_type sm = AUTO_VAL_INIT(sm); + bool r = build_stake_modifier(sm, alt_chain, split_height); + CHECK_AND_ASSERT_MES(r, false, "failed to build_stake_modifier"); + amount = 0; + r = build_kernel(b, sk, amount, sm); + CHECK_AND_ASSERT_MES(r, false, "failed to build kernel_stake"); + CHECK_AND_ASSERT_MES(amount!=0, false, "failed to build kernel_stake, amount == 0"); + + proof_hash = crypto::cn_fast_hash(&sk, sizeof(sk)); + + LOG_PRINT_L2("STAKE KERNEL for bl ID: " << get_block_hash(b) << ENDL + << print_stake_kernel_info(sk) + << "amount: " << print_money(amount) << ENDL + << "kernel_hash: " << proof_hash); + + + final_diff = basic_diff / amount; + if (!check_hash(proof_hash, final_diff)) + { + LOG_ERROR("PoS difficulty check failed for block " << get_block_hash(b) << " @ HEIGHT " << get_block_height(b) << ":" << ENDL + << " basic_diff: " << basic_diff << ENDL + << " final_diff: " << final_diff << ENDL + << " amount: " << print_money_brief(amount) << ENDL + << " kernel_hash: " << proof_hash << ENDL + ); + return false; + } + + //validate signature + uint64_t max_related_block_height = 0; + const txin_to_key& coinstake_in = boost::get(b.miner_tx.vin[1]); + CHECK_AND_ASSERT_MES(b.miner_tx.signatures.size() == 1, false, "PoS block's miner_tx has incorrect signatures size = " << b.miner_tx.signatures.size() << ", block_id = " << get_block_hash(b)); + if (!for_altchain) + { + // Do coinstake input validation for main chain only. + // Txs in alternative PoS blocks (including miner_tx) are validated by validate_alt_block_txs() + r = check_tx_input(b.miner_tx, 1, coinstake_in, id, b.miner_tx.signatures[0], &max_related_block_height); + CHECK_AND_ASSERT_MES(r, false, "Failed to validate coinstake input in miner tx, block_id = " << get_block_hash(b)); + } + + uint64_t block_height = for_altchain ? split_height + alt_chain.size() : m_db_blocks.size(); + uint64_t coinstake_age = block_height - max_related_block_height - 1; + + CHECK_AND_ASSERT_MES(coinstake_age >= m_core_runtime_config.min_coinstake_age, false, + "Coinstake age is: " << coinstake_age << " is less than minimum expected: " << m_core_runtime_config.min_coinstake_age); + + return true; +} +//------------------------------------------------------------------ +wide_difficulty_type blockchain_storage::get_adjusted_cumulative_difficulty_for_next_pos(wide_difficulty_type next_diff) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + wide_difficulty_type last_pow_diff = 0; + wide_difficulty_type last_pos_diff = 0; + uint64_t sz = m_db_blocks.size(); + if (!sz) + return next_diff; + + uint64_t i = sz - 1; + + for (; i < sz && !(last_pow_diff && last_pos_diff); i--) + { + if (is_pos_block(m_db_blocks[i]->bl)) + { + if (!last_pos_diff) + { + last_pos_diff = m_db_blocks[i]->difficulty; + } + }else + { + if (!last_pow_diff) + { + last_pow_diff = m_db_blocks[i]->difficulty; + } + } + } + if (!last_pos_diff) + return next_diff; + return next_diff*last_pow_diff/last_pos_diff; +} +//------------------------------------------------------------------ +wide_difficulty_type blockchain_storage::get_adjusted_cumulative_difficulty_for_next_alt_pos(alt_chain_type& alt_chain, uint64_t block_height, wide_difficulty_type next_diff, uint64_t connection_height) const +{ + + wide_difficulty_type last_pow_diff = 0; + wide_difficulty_type last_pos_diff = 0; + + for (auto it = alt_chain.rbegin(); it != alt_chain.rend() && !(last_pos_diff && last_pow_diff); it++) + { + if (is_pos_block((*it)->second.bl )) + { + if (!last_pos_diff) + { + last_pos_diff = (*it)->second.difficulty; + } + } + else + { + if (!last_pow_diff) + { + last_pow_diff = (*it)->second.difficulty; + } + } + } + + CRITICAL_REGION_LOCAL(m_read_lock); + for (uint64_t h = connection_height - 1; h != 0 && !(last_pos_diff && last_pow_diff); --h) + { + if (is_pos_block(m_db_blocks[h]->bl)) + { + if (!last_pos_diff) + { + last_pos_diff = m_db_blocks[h]->difficulty; + } + } + else + { + if (!last_pow_diff) + { + last_pow_diff = m_db_blocks[h]->difficulty; + } + } + } + if (!last_pos_diff) + return next_diff; + return next_diff*last_pow_diff / last_pos_diff; +} +//------------------------------------------------------------------ +uint64_t blockchain_storage::get_last_x_block_height(bool pos) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + uint64_t sz = m_db_blocks.size(); + if (!sz) + return 0; + + uint64_t i = sz-1; + + for (; i < sz; i--) + { + if (is_pos_block(m_db_blocks[i]->bl) == pos) + return i; + } + return 0; +} +//------------------------------------------------------------------ +wide_difficulty_type blockchain_storage::get_last_alt_x_block_cumulative_precise_difficulty(alt_chain_type& alt_chain, uint64_t block_height, bool pos) const +{ + uint64_t main_chain_first_block = block_height - 1; + for (auto it = alt_chain.rbegin(); it != alt_chain.rend(); it++) + { + if (is_pos_block((*it)->second.bl) == pos) + return (*it)->second.cumulative_diff_precise; + main_chain_first_block = (*it)->second.height - 1; + } + + + CRITICAL_REGION_LOCAL(m_read_lock); + CHECK_AND_ASSERT_MES(main_chain_first_block < m_db_blocks.size(), false, "Intrnal error: main_chain_first_block(" << main_chain_first_block << ") < m_blocks.size() (" << m_db_blocks.size() << ")"); + + for (uint64_t i = main_chain_first_block; i != 0; i--) + { + if (is_pos_block(m_db_blocks[i]->bl) == pos) + return m_db_blocks[i]->cumulative_diff_precise; + } + return 0; +} +//------------------------------------------------------------------ +bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypto::hash& id, block_verification_context& bvc) +{ + TIME_MEASURE_START_PD_MS(block_processing_time_0_ms); + CRITICAL_REGION_LOCAL(m_read_lock); + TIME_MEASURE_START_PD(block_processing_time_1); + if(bl.prev_id != get_top_block_id()) + { + LOG_PRINT_L0("Block with id: " << id << ENDL + << "have wrong prev_id: " << bl.prev_id << ENDL + << "expected: " << get_top_block_id()); + return false; + } +#ifdef _DEBUG + uint64_t h = get_block_height(bl); +#endif// _DEBUG + + if(!check_block_timestamp_main(bl)) + { + LOG_PRINT_L0("Block with id: " << id << ENDL + << "have invalid timestamp: " << bl.timestamp); + //add_block_as_invalid(bl, id);//do not add blocks to invalid storage befor proof of work check was passed + bvc.m_verification_failed = true; + return false; + } + + if (m_checkpoints.is_in_checkpoint_zone(get_current_blockchain_size())) + { + m_is_in_checkpoint_zone = true; + if (!m_checkpoints.check_block(get_current_blockchain_size(), id)) + { + LOG_ERROR("CHECKPOINT VALIDATION FAILED"); + bvc.m_verification_failed = true; + return false; + } + } + else + m_is_in_checkpoint_zone = false; + + crypto::hash proof_hash = null_hash; + uint64_t pos_coinstake_amount = 0; + wide_difficulty_type this_coin_diff = 0; + bool is_pos_bl = is_pos_block(bl); + //check if PoS allowed in this height + CHECK_AND_ASSERT_MES_CUSTOM(!(is_pos_bl && m_db_blocks.size() < m_core_runtime_config.pos_minimum_heigh), false, bvc.m_verification_failed = true, "PoS block not allowed on height " << m_db_blocks.size()); + + //check proof of work + TIME_MEASURE_START_PD(target_calculating_time_2); + wide_difficulty_type current_diffic = get_next_diff_conditional(is_pos_bl); + CHECK_AND_ASSERT_MES_CUSTOM(current_diffic, false, bvc.m_verification_failed = true, "!!!!!!!!! difficulty overhead !!!!!!!!!"); + TIME_MEASURE_FINISH_PD(target_calculating_time_2); + + TIME_MEASURE_START_PD(longhash_calculating_time_3); + if (is_pos_bl) + { + bool r = validate_pos_block(bl, current_diffic, pos_coinstake_amount, this_coin_diff, proof_hash, id, false); + CHECK_AND_ASSERT_MES_CUSTOM(r, false, bvc.m_verification_failed = true, "validate_pos_block failed!!"); + } + else + { + proof_hash = get_block_longhash(bl); + + if (!check_hash(proof_hash, current_diffic)) + { + LOG_ERROR("Block with id: " << id << ENDL + << " : " << proof_hash << ENDL + << "unexpected difficulty: " << current_diffic); + bvc.m_verification_failed = true; + return false; + } + } + TIME_MEASURE_FINISH_PD(longhash_calculating_time_3); + + size_t aliases_count_befor_block = m_db_aliases.size(); + + if (!prevalidate_miner_transaction(bl, m_db_blocks.size(), is_pos_bl)) + { + LOG_PRINT_L0("Block with id: " << id + << " failed to pass prevalidation"); + bvc.m_verification_failed = true; + return false; + } + size_t cumulative_block_size = 0; + size_t coinbase_blob_size = get_object_blobsize(bl.miner_tx); + + /* + instead of complicated two-phase template construction and adjustment of cumulative size with block reward we + use CURRENCY_COINBASE_BLOB_RESERVED_SIZE as penalty-free coinbase transaction reservation. + */ + if (coinbase_blob_size > CURRENCY_COINBASE_BLOB_RESERVED_SIZE) + { + cumulative_block_size += coinbase_blob_size; + LOG_PRINT_CYAN("Big coinbase transaction detected: coinbase_blob_size = " << coinbase_blob_size, LOG_LEVEL_0); + } + + std::vector block_fees; + block_fees.reserve(bl.tx_hashes.size()); + //process transactions + TIME_MEASURE_START_PD(all_txs_insert_time_5); + if (!add_transaction_from_block(bl.miner_tx, get_transaction_hash(bl.miner_tx), id, get_current_blockchain_size(), get_actual_timestamp(bl))) + { + LOG_PRINT_L0("Block with id: " << id << " failed to add transaction to blockchain storage"); + bvc.m_verification_failed = true; + return false; + } + //preserve extra data to support alt pos blocks validation + //amount = > gindex_increment; a map to store how many txout_to_key outputs with such amount this block has in its transactions(including miner tx) + std::unordered_map gindices; + append_per_block_increments_for_tx(bl.miner_tx, gindices); + + + + size_t tx_processed_count = 0; + uint64_t fee_summary = 0; + + for(const crypto::hash& tx_id : bl.tx_hashes) + { + transaction tx; + size_t blob_size = 0; + uint64_t fee = 0; + if(!m_tx_pool.take_tx(tx_id, tx, blob_size, fee)) + { + LOG_PRINT_L0("Block with id: " << id << " has at least one unknown transaction with id: " << tx_id); + purge_block_data_from_blockchain(bl, tx_processed_count); + //add_block_as_invalid(bl, id); + bvc.m_verification_failed = true; + return false; + } + + append_per_block_increments_for_tx(tx, gindices); + + //If we under checkpoints, ring signatures should be pruned + if(m_is_in_checkpoint_zone) + { + tx.signatures.clear(); + tx.attachment.clear(); + } + TIME_MEASURE_START_PD(tx_add_one_tx_time); + TIME_MEASURE_START_PD(tx_check_inputs_time); + if(!check_tx_inputs(tx, tx_id)) + { + LOG_PRINT_L0("Block with id: " << id << " has at least one transaction (id: " << tx_id << ") with wrong inputs."); + currency::tx_verification_context tvc = AUTO_VAL_INIT(tvc); + bool add_res = m_tx_pool.add_tx(tx, tvc, true, true); + m_tx_pool.add_transaction_to_black_list(tx); + CHECK_AND_ASSERT_MES_NO_RET(add_res, "handle_block_to_main_chain: failed to add transaction back to transaction pool"); + purge_block_data_from_blockchain(bl, tx_processed_count); + add_block_as_invalid(bl, id); + LOG_PRINT_L0("Block with id " << id << " added as invalid becouse of wrong inputs in transactions"); + bvc.m_verification_failed = true; + return false; + } + TIME_MEASURE_FINISH_PD(tx_check_inputs_time); + + TIME_MEASURE_START_PD(tx_prapare_append); + uint64_t current_bc_size = get_current_blockchain_size(); + uint64_t actual_timestamp = get_actual_timestamp(bl); + TIME_MEASURE_FINISH_PD(tx_prapare_append); + TIME_MEASURE_START_PD(tx_append_time); + if(!add_transaction_from_block(tx, tx_id, id, current_bc_size, actual_timestamp)) + { + LOG_PRINT_L0("Block with id: " << id << " failed to add transaction to blockchain storage"); + currency::tx_verification_context tvc = AUTO_VAL_INIT(tvc); + bool add_res = m_tx_pool.add_tx(tx, tvc, true, true); + m_tx_pool.add_transaction_to_black_list(tx); + CHECK_AND_ASSERT_MES_NO_RET(add_res, "handle_block_to_main_chain: failed to add transaction back to transaction pool"); + purge_block_data_from_blockchain(bl, tx_processed_count); + bvc.m_verification_failed = true; + return false; + } + TIME_MEASURE_FINISH_PD(tx_append_time); + //LOG_PRINT_L0("APPEND_TX_TIME: " << m_performance_data.tx_append_time.get_last_val()); + TIME_MEASURE_FINISH_PD(tx_add_one_tx_time); + fee_summary += fee; + cumulative_block_size += blob_size; + ++tx_processed_count; + if (fee) + block_fees.push_back(fee); + } + TIME_MEASURE_FINISH_PD(all_txs_insert_time_5); + + TIME_MEASURE_START_PD(etc_stuff_6); + //check aliases count + if (m_db_aliases.size() - aliases_count_befor_block > MAX_ALIAS_PER_BLOCK) + { + LOG_PRINT_L0("Block with id: " << id + << " have registered too many aliases " << m_db_aliases.size() - aliases_count_befor_block << ", expected no more than " << MAX_ALIAS_PER_BLOCK); + purge_block_data_from_blockchain(bl, tx_processed_count); + bvc.m_verification_failed = true; + return false; + } + + uint64_t base_reward = 0; + uint64_t already_generated_coins = m_db_blocks.size() ? m_db_blocks.back()->already_generated_coins:0; + if (!validate_miner_transaction(bl, cumulative_block_size, fee_summary, base_reward, already_generated_coins)) + { + LOG_PRINT_L0("Block with id: " << id + << " have wrong miner transaction"); + purge_block_data_from_blockchain(bl, tx_processed_count); + bvc.m_verification_failed = true; + return false; + } + + //fill block_extended_info + block_extended_info bei = boost::value_initialized(); + bei.bl = bl; + bei.height = m_db_blocks.size(); + bei.block_cumulative_size = cumulative_block_size; + bei.difficulty = current_diffic; + if (is_pos_bl) + bei.stake_hash = proof_hash; + + //precise difficulty - difficulty used to calculate next difficulty + uint64_t last_x_h = get_last_x_block_height(is_pos_bl); + if (!last_x_h) + bei.cumulative_diff_precise = current_diffic; + else + bei.cumulative_diff_precise = m_db_blocks[last_x_h]->cumulative_diff_precise + current_diffic; + + if (m_db_blocks.size()) + { + bei.cumulative_diff_adjusted = m_db_blocks.back()->cumulative_diff_adjusted; + } + + //adjusted difficulty - difficulty used to switch blockchain + wide_difficulty_type cumulative_diff_delta = 0; + if (is_pos_bl) + cumulative_diff_delta = get_adjusted_cumulative_difficulty_for_next_pos(current_diffic); + else + cumulative_diff_delta = current_diffic; + + + size_t sequence_factor = get_current_sequence_factor(is_pos_bl); + if (bei.height >= m_core_runtime_config.pos_minimum_heigh) + cumulative_diff_delta = correct_difficulty_with_sequence_factor(sequence_factor, cumulative_diff_delta); + + bei.cumulative_diff_adjusted += cumulative_diff_delta; + + //etc + bei.already_generated_coins = already_generated_coins + base_reward; + + auto blocks_index_ptr = m_db_blocks_index.get(id); + if (blocks_index_ptr) + { + LOG_ERROR("block with id: " << id << " already in block indexes"); + purge_block_data_from_blockchain(bl, tx_processed_count); + bvc.m_verification_failed = true; + return false; + } + if (bei.height%ALIAS_MEDIAN_RECALC_INTERWAL) + { + bei.effective_tx_fee_median = get_tx_fee_median(); + } + else + { + if (bei.height == 0) + bei.effective_tx_fee_median = 0; + else + { + LOG_PRINT_L0("Recalculating median fee..."); + std::vector blocks_medians; + blocks_medians.reserve(ALIAS_COAST_PERIOD); + for (uint64_t i = bei.height - 1; i != 0 && ALIAS_COAST_PERIOD >= bei.height - i ; i--) + { + uint64_t i_median = m_db_blocks[i]->this_block_tx_fee_median; + if (i_median) + blocks_medians.push_back(i_median); + } + bei.effective_tx_fee_median = epee::misc_utils::median(blocks_medians); + LOG_PRINT_L0("Median fee recalculated for h = " << bei.height << " as " << print_money(bei.effective_tx_fee_median)); + } + } + if (block_fees.size()) + { + uint64_t block_fee_median = epee::misc_utils::median(block_fees); + bei.this_block_tx_fee_median = block_fee_median; + } + + m_db_blocks_index.set(id, bei.height); + push_block_to_per_block_increments(bei.height, gindices); + TIME_MEASURE_FINISH_PD(etc_stuff_6); + + + TIME_MEASURE_START_PD(insert_time_4); + m_db_blocks.push_back(bei); + TIME_MEASURE_FINISH_PD(insert_time_4); + TIME_MEASURE_FINISH_PD(block_processing_time_1); + TIME_MEASURE_FINISH_PD_MS(block_processing_time_0_ms); + + //print result + stringstream powpos_str_entry, timestamp_str_entry; + if (is_pos_bl) + { // PoS + int64_t actual_ts = get_actual_timestamp(bei.bl); // signed int is intentionally used here + int64_t ts_diff = actual_ts - m_core_runtime_config.get_core_time(); + powpos_str_entry << "PoS:\t" << proof_hash << ", stake amount: " << print_money_brief(pos_coinstake_amount) << ", final_difficulty: " << this_coin_diff; + timestamp_str_entry << ", actual ts: " << actual_ts << " (diff: " << std::showpos << ts_diff << "s) block ts: " << std::noshowpos << bei.bl.timestamp << " (shift: " << std::showpos << static_cast(bei.bl.timestamp) - actual_ts << ")"; + } + else + { // PoW + int64_t ts_diff = bei.bl.timestamp - static_cast(m_core_runtime_config.get_core_time()); + powpos_str_entry << "PoW:\t" << proof_hash; + timestamp_str_entry << ", block ts: " << bei.bl.timestamp << " (diff: " << std::showpos << ts_diff << "s)"; + } + LOG_PRINT_L1("+++++ BLOCK SUCCESSFULLY ADDED " << (is_pos_bl ? "[PoS]" : "[PoW]") << " Sq: " << sequence_factor + << ENDL << "id:\t" << id << timestamp_str_entry.str() + << ENDL << powpos_str_entry.str() + << ENDL << "HEIGHT " << bei.height << ", difficulty: " << current_diffic << ", cumul_diff_precise: " << bei.cumulative_diff_precise << ", cumul_diff_adj: " << bei.cumulative_diff_adjusted << " (+" << cumulative_diff_delta << ")" + << ENDL << "block reward: " << print_money_brief(base_reward + fee_summary) << " (" << print_money_brief(base_reward) << " + " << print_money_brief(fee_summary) + << ")" << ", coinbase_blob_size: " << coinbase_blob_size << ", cumulative size: " << cumulative_block_size << ", tx_count: " << bei.bl.tx_hashes.size() + << ", " << block_processing_time_0_ms + << "(" << block_processing_time_1 + << "/" << target_calculating_time_2 + << "/" << longhash_calculating_time_3 + << "/" << insert_time_4 + << "/" << all_txs_insert_time_5 + << "/" << etc_stuff_6 + << ")micrs"); + + on_block_added(bei, id); + + bvc.m_added_to_main_chain = true; + return true; +} +void blockchain_storage::on_block_added(const block_extended_info& bei, const crypto::hash& id) +{ + update_next_comulative_size_limit(); + m_timestamps_median_cache.clear(); + + m_tx_pool.on_blockchain_inc(bei.height, id); + TIME_MEASURE_START_PD(raise_block_core_event); + rise_core_event(CORE_EVENT_BLOCK_ADDED, void_struct()); + TIME_MEASURE_FINISH_PD(raise_block_core_event); +} +//------------------------------------------------------------------ +void blockchain_storage::on_block_removed(const block_extended_info& bei) +{ + m_tx_pool.on_blockchain_dec(m_db_blocks.size() - 1, get_top_block_id()); + m_timestamps_median_cache.clear(); + LOG_PRINT_L2("block at height " << bei.height << " was removed from the blockchain"); +} +//------------------------------------------------------------------ +void blockchain_storage::on_abort_transaction() +{ + if (m_event_handler) m_event_handler->on_clear_events(); + CHECK_AND_ASSERT_MES_NO_RET(validate_blockchain_prev_links(), "EPIC FAIL! 4"); + m_timestamps_median_cache.clear(); +} +//------------------------------------------------------------------ +bool blockchain_storage::update_next_comulative_size_limit() +{ + std::vector sz; + get_last_n_blocks_sizes(sz, CURRENCY_REWARD_BLOCKS_WINDOW); + + uint64_t median = misc_utils::median(sz); + if(median <= CURRENCY_BLOCK_GRANTED_FULL_REWARD_ZONE) + median = CURRENCY_BLOCK_GRANTED_FULL_REWARD_ZONE; + + m_db_current_block_cumul_sz_limit = median * 2; + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::add_new_block(const block& bl_, block_verification_context& bvc) +{ + try + { + m_db.begin_transaction(); + + block bl = bl_; + crypto::hash id = get_block_hash(bl); + CRITICAL_REGION_LOCAL(m_tx_pool); + //CRITICAL_REGION_LOCAL1(m_read_lock); + if (have_block(id)) + { + LOG_PRINT_L3("block with id = " << id << " already exists"); + bvc.m_already_exists = true; + m_db.commit_transaction(); + CHECK_AND_ASSERT_MES(validate_blockchain_prev_links(), false, "EPIC FAIL! 1"); + return false; + } + + //check that block refers to chain tail + + if (!(bl.prev_id == get_top_block_id())) + { + //chain switching or wrong block + bvc.m_added_to_main_chain = false; + bool r = handle_alternative_block(bl, id, bvc); + if (!r || bvc.m_verification_failed) + { + m_db.abort_transaction(); + CHECK_AND_ASSERT_MES(validate_blockchain_prev_links(), false, "EPIC FAIL! 2.2"); + m_tx_pool.on_finalize_db_transaction(); + return r; + } + m_db.commit_transaction(); + CHECK_AND_ASSERT_MES(validate_blockchain_prev_links(), false, "EPIC FAIL! 2"); + m_tx_pool.on_finalize_db_transaction(); + return r; + //never relay alternative blocks + } + + + bool res = handle_block_to_main_chain(bl, id, bvc); + if (bvc.m_verification_failed || !res) + { + m_db.abort_transaction(); + m_tx_pool.on_finalize_db_transaction(); + on_abort_transaction(); + if (m_event_handler) m_event_handler->on_clear_events(); + return res; + } + m_db.commit_transaction(); + CHECK_AND_ASSERT_MES(validate_blockchain_prev_links(), false, "EPIC FAIL! 3"); + m_tx_pool.on_finalize_db_transaction(); + if (m_event_handler) m_event_handler->on_complete_events(); + + return res; + } + catch (const std::exception& ex) + { + bvc.m_verification_failed = true; + bvc.m_added_to_main_chain = false; + m_db.abort_transaction(); + m_tx_pool.on_finalize_db_transaction(); + on_abort_transaction(); + LOG_ERROR("UNKNOWN EXCEPTION WHILE ADDINIG NEW BLOCK: " << ex.what()); + + return false; + } + catch (...) + { + bvc.m_verification_failed = true; + bvc.m_added_to_main_chain = false; + m_db.abort_transaction(); + m_tx_pool.on_finalize_db_transaction(); + on_abort_transaction(); + LOG_ERROR("UNKNOWN EXCEPTION WHILE ADDINIG NEW BLOCK."); + return false; + } +} +//------------------------------------------------------------------ +bool blockchain_storage::truncate_blockchain(uint64_t to_height) +{ + m_db.begin_transaction(); + uint64_t inital_height = get_current_blockchain_size(); + while (get_current_blockchain_size() > to_height) + { + pop_block_from_blockchain(); + } + CRITICAL_REGION_LOCAL(m_alternative_chains_lock); + m_alternative_chains.clear(); + m_altblocks_keyimages.clear(); + m_alternative_chains_txs.clear(); + LOG_PRINT_MAGENTA("Blockchain truncated from " << inital_height << " to " << get_current_blockchain_size(), LOG_LEVEL_0); + m_db.commit_transaction(); + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::calc_tx_cummulative_blob(const block& bl)const +{ + uint64_t cummulative_size_pool = 0; + uint64_t cummulative_size_calc = 0; + uint64_t cummulative_size_serialized = 0; + uint64_t i = 0; + std::stringstream ss; + uint64_t calculated_sz_miner = get_object_blobsize(bl.miner_tx); + blobdata b = t_serializable_object_to_blob(bl.miner_tx); + uint64_t serialized_size_miner = b.size(); + + ss << "[COINBASE]: " << calculated_sz_miner << "|" << serialized_size_miner << ENDL; + + for (auto& h : bl.tx_hashes) + { + uint64_t calculated_sz = 0; + uint64_t serialized_size = 0; + tx_memory_pool::tx_details td = AUTO_VAL_INIT(td); + bool in_pool = m_tx_pool.get_transaction(h, td); + if (in_pool) + { + calculated_sz = get_object_blobsize(td.tx); + blobdata b = t_serializable_object_to_blob(td.tx); + serialized_size = b.size(); + if (td.blob_size != calculated_sz || calculated_sz != serialized_size) + { + LOG_PRINT_RED("BLOB SIZE MISMATCH IN TX: " << h << " calculated_sz: " << calculated_sz + << " serialized_size: " << serialized_size + << " td.blob_size: " << td.blob_size, LOG_LEVEL_0); + } + cummulative_size_pool += td.blob_size; + } + else + { + auto tx_ptr = m_db_transactions.get(h); + CHECK_AND_ASSERT_MES(tx_ptr, false, "tx " << h << " not found in blockchain nor tx_pool"); + calculated_sz = get_object_blobsize(tx_ptr->tx); + blobdata b = t_serializable_object_to_blob(tx_ptr->tx); + serialized_size = b.size(); + if (calculated_sz != serialized_size) + { + LOG_PRINT_RED("BLOB SIZE MISMATCH IN TX: " << h << " calculated_sz: " << calculated_sz + << " serialized_size: " << serialized_size, LOG_LEVEL_0); + } + } + cummulative_size_calc += calculated_sz; + cummulative_size_serialized += serialized_size; + ss << "[" << i << "]" << h << ": " << calculated_sz << ENDL; + i++; + + } + LOG_PRINT_MAGENTA("CUMMULATIVE_BLOCK_SIZE_TRACE: " << get_block_hash(bl) << ENDL + << "cummulative_size_calc: " << cummulative_size_calc << ENDL + << "cummulative_size_serialized: " << cummulative_size_serialized << ENDL + << "cummulative_size_pool: " << cummulative_size_pool << ENDL + << ss.str(), LOG_LEVEL_0); + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::build_kernel(const block& bl, stake_kernel& kernel, uint64_t& amount, const stake_modifier_type& stake_modifier) const +{ + CHECK_AND_ASSERT_MES(bl.miner_tx.vin.size() == 2, false, "wrong miner transaction"); + CHECK_AND_ASSERT_MES(bl.miner_tx.vin[0].type() == typeid(txin_gen), false, "wrong miner transaction"); + CHECK_AND_ASSERT_MES(bl.miner_tx.vin[1].type() == typeid(txin_to_key), false, "wrong miner transaction"); + + const txin_to_key& txin = boost::get(bl.miner_tx.vin[1]); + CHECK_AND_ASSERT_MES(txin.key_offsets.size(), false, "wrong miner transaction"); + amount = txin.amount; + + return build_kernel(txin.amount, txin.k_image, kernel, stake_modifier, bl.timestamp); +} +//------------------------------------------------------------------ +bool blockchain_storage::build_stake_modifier(stake_modifier_type& sm, const alt_chain_type& alt_chain, uint64_t split_height, crypto::hash *p_last_block_hash /* = nullptr */) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + sm = stake_modifier_type(); + + auto pbei_last_pos = get_last_block_of_type(true, alt_chain, split_height); + auto pbei_last_pow = get_last_block_of_type(false, alt_chain, split_height); + CHECK_AND_ASSERT_THROW_MES(pbei_last_pow, "Internal error: pbei_last_pow is null"); + + if (pbei_last_pos) + sm.last_pos_kernel_id = pbei_last_pos->stake_hash; + else + { + bool r = string_tools::parse_tpod_from_hex_string(POS_STARTER_KERNEL_HASH, sm.last_pos_kernel_id); + CHECK_AND_ASSERT_MES(r, false, "Failed to parse POS_STARTER_MODFIFIER"); + } + + sm.last_pow_id = get_block_hash(pbei_last_pow->bl); + + if (p_last_block_hash != nullptr) + *p_last_block_hash = get_block_hash(m_db_blocks.back()->bl); + + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::build_kernel(uint64_t amount, + const crypto::key_image& ki, + stake_kernel& kernel, + const stake_modifier_type& stake_modifier, + uint64_t timestamp)const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + kernel = stake_kernel(); + kernel.kimage = ki; + kernel.stake_modifier = stake_modifier; + kernel.block_timestamp = timestamp; + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::scan_pos(const COMMAND_RPC_SCAN_POS::request& sp, COMMAND_RPC_SCAN_POS::response& rsp) const +{ + uint64_t timstamp_start = 0; + wide_difficulty_type basic_diff = 0; + CRITICAL_REGION_BEGIN(m_read_lock); + timstamp_start = m_db_blocks.back()->bl.timestamp; + basic_diff = get_next_diff_conditional(true); + CRITICAL_REGION_END(); + + stake_modifier_type sm = AUTO_VAL_INIT(sm); + bool r = build_stake_modifier(sm); + CHECK_AND_ASSERT_MES(r, false, "failed to build_stake_modifier"); + + for (size_t i = 0; i != sp.pos_entries.size(); i++) + { + stake_kernel sk = AUTO_VAL_INIT(sk); + build_kernel(sp.pos_entries[i].amount, sp.pos_entries[i].keyimage, sk, sm, 0); + + for (uint64_t ts = timstamp_start; ts < timstamp_start + POS_SCAN_WINDOW; ts++) + { + sk.block_timestamp = ts; + crypto::hash kernel_hash = crypto::cn_fast_hash(&sk, sizeof(sk)); + wide_difficulty_type this_coin_diff = basic_diff / sp.pos_entries[i].amount; + if (!check_hash(kernel_hash, this_coin_diff)) + continue; + else + { + //found kernel + LOG_PRINT_GREEN("Found kernel: amount=" << print_money(sp.pos_entries[i].amount) << ", key_image" << sp.pos_entries[i].keyimage, LOG_LEVEL_0); + rsp.index = i; + rsp.block_timestamp = ts; + rsp.status = CORE_RPC_STATUS_OK; + return true; + } + } + } + rsp.status = CORE_RPC_STATUS_NOT_FOUND; + return false; +} +//------------------------------------------------------------------ +void blockchain_storage::set_core_runtime_config(const core_runtime_config& pc) const +{ + m_core_runtime_config = pc; + m_services_mgr.set_core_runtime_config(pc); +} +//------------------------------------------------------------------ +const core_runtime_config& blockchain_storage::get_core_runtime_config() const +{ + return m_core_runtime_config; +} +//------------------------------------------------------------------ +std::shared_ptr blockchain_storage::get_tx_chain_entry(const crypto::hash& tx_hash) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + return m_db_transactions.find(tx_hash); +} +//------------------------------------------------------------------ +bool blockchain_storage::get_tx_chain_entry(const crypto::hash& tx_hash, transaction_chain_entry& entry) const +{ + auto ch_entry_ptr = get_tx_chain_entry(tx_hash); + if (!ch_entry_ptr) + return false; + entry = *ch_entry_ptr; + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::validate_blockchain_prev_links(size_t last_n_blocks_to_check /* = 10 */) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + + TRY_ENTRY() + + if (m_db_blocks.size() < 2 || last_n_blocks_to_check < 1) + return true; + + bool ok = true; + for(size_t attempt_counter = 1; attempt_counter <= 2; ++attempt_counter) + { + ok = true; + for (size_t height = m_db_blocks.size() - 1, blocks_to_check = last_n_blocks_to_check; height != 0 && blocks_to_check != 0; --height, --blocks_to_check) + { + auto bei_ptr = m_db_blocks[height]; + auto& bei = *bei_ptr; + if (bei.height != height) + { + LOG_ERROR("bei.height = " << bei.height << ", expected: " << height); + ok = false; + } + + auto prev_bei_ptr = m_db_blocks[height - 1]; + auto& prev_bei = *prev_bei_ptr; + crypto::hash prev_id = get_block_hash(prev_bei.bl); + if (bei.bl.prev_id != prev_id) + { + LOG_ERROR("EPIC FAIL: Block " << get_block_hash(bei.bl) << " @ " << height << " has prev_id == " << bei.bl.prev_id << + " while block @ " << height - 1 << " has id: " << prev_id << ENDL << + "Block @" << height << ":" << ENDL << currency::obj_to_json_str(bei.bl) << ENDL << + "Block @" << height - 1 << ":" << ENDL << currency::obj_to_json_str(prev_bei.bl)); + m_performance_data.epic_failure_happend = true; + ok = false; + } + } + + if (ok && attempt_counter == 1) + { + break; + } + else if (!ok && attempt_counter == 1) + { + LOG_PRINT_YELLOW("************* EPIC FAIL workaround attempt: try to reset DB cache and re-check *************", LOG_LEVEL_0); + reset_db_cache(); + continue; + } + else if (!ok && attempt_counter == 2) + { + LOG_PRINT_RED("************* EPIC FAIL workaround attempt failed *************", LOG_LEVEL_0); + break; + } + else if (ok && attempt_counter == 2) + { + LOG_PRINT_GREEN("************* EPIC FAIL workaround attempt succeded! *************", LOG_LEVEL_0); + break; + } + else + { + LOG_ERROR("should never get here"); + return false; + } + + LOG_ERROR("should never get here also"); + return false; + } + + return ok; + + CATCH_ENTRY2(false); +} +//------------------------------------------------------------------ +void blockchain_storage::push_block_to_per_block_increments(uint64_t height_, std::unordered_map& gindices) +{ + CRITICAL_REGION_LOCAL(m_read_lock); + uint32_t height = static_cast(height_); + + block_gindex_increments bgi = AUTO_VAL_INIT(bgi); + bgi.increments.reserve(gindices.size()); + for (auto& v : gindices) + bgi.increments.push_back(gindex_increment::construct(v.first, v.second)); + + m_db_per_block_gindex_incs.set(height, bgi); +} +//------------------------------------------------------------------ +void blockchain_storage::pop_block_from_per_block_increments(uint64_t height_) +{ + CRITICAL_REGION_LOCAL(m_read_lock); + uint32_t height = static_cast(height_); + m_db_per_block_gindex_incs.erase(height); +} +//------------------------------------------------------------------ +void blockchain_storage::calculate_local_gindex_lookup_table_for_height(uint64_t height, std::map& gindexes) const +{ + gindexes.clear(); + + CHECK_AND_ASSERT_THROW_MES(m_db_per_block_gindex_incs.size() == m_db_blocks.size(), "invariant failure: m_db_per_block_gindex_incs.size() == " << m_db_per_block_gindex_incs.size() << ", m_db_blocks.size() == " << m_db_blocks.size()); + + CRITICAL_REGION_LOCAL(m_read_lock); + + // Calculate total number of outputs for each amount in the main chain from given height + size_t top_block_height = static_cast(m_db_blocks.size()) - 1; + uint64_t h = height; + while (h <= top_block_height) + { + auto p = m_db_per_block_gindex_incs.get(h); + CHECK_AND_ASSERT_THROW_MES(p, "null p for height " << h); + + for (auto& el : p->increments) + gindexes[el.amount] += el.increment; + + ++h; + } + + // Translate total number of outputs for each amount into global output indexes these amounts had at given height. + // (those amounts which are not present in the main chain after given height have the same gindexes at given height and at the most recent block) + for (auto it = gindexes.begin(); it != gindexes.end(); ++it) + { + uint64_t amount = it->first; + uint64_t gindexes_in_mainchain = m_db_outputs.get_item_size(amount); + CHECK_AND_ASSERT_THROW_MES(gindexes_in_mainchain >= it->second, "inconsistent gindex increments for amount " << amount << ": gindexes_in_mainchain == " << gindexes_in_mainchain << ", gindex increment for height " << height << " is " << it->second); + it->second = gindexes_in_mainchain - it->second; + } +} +//------------------------------------------------------------------ +bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, std::set& collected_keyimages, const crypto::hash& bl_id, const crypto::hash& input_tx_hash, size_t input_index, + const std::vector& input_sigs, uint64_t split_height, const alt_chain_type& alt_chain, const std::set& alt_chain_block_ids, uint64_t& ki_lookuptime, + uint64_t* p_max_related_block_height /* = nullptr */) const +{ + // Main and alt chain outline: + // + // A- A- A- B- B- B- B- <-- main chain + // | + // \- C- C- C- <-- alt chain + // ^ + // | + // split height + // + // List of possible cases + // + // | src tx | another | this tx | + // # | output | tx input | input | meaning + // ------------ bad cases ------------------ + // b1 A A C already spent in main chain + // b2 A C C already spent in alt chain + // b3 C C C already spent in alt chain + // b4 B B/- C output not found (in case there's no valid outs in altchain C) + // ------------ good cases ------------------ + // g1 A - C normal spending output from main chain A + // g2 A B C normal spending output from main chain A (although it is spent in main chain B as well) + // g3 C - C normal spending output from alt chain C + // g4 B,C - C src tx added to both main chain B and alt chain C + // g5 B,C B C src tx added to both main chain B and alt chain C, also spent in B + + CRITICAL_REGION_LOCAL(m_read_lock); + bool r = false; + + if (p_max_related_block_height != nullptr) + *p_max_related_block_height = 0; + + CHECK_AND_ASSERT_MES(input_index < input_tx.vin.size() && input_tx.vin[input_index].type() == typeid(txin_to_key), false, "invalid input index: " << input_index); + const txin_to_key& input = boost::get(input_tx.vin[input_index]); + + // check case b1: key_image spent status in main chain, should be either non-spent or has spent height >= split_height + auto p = m_db_spent_keys.get(input.k_image); + CHECK_AND_ASSERT_MES(p == nullptr || *p >= split_height, false, "key image " << input.k_image << " has been already spent in main chain at height " << *p << ", split height: " << split_height); + + TIME_MEASURE_START(ki_lookup_time); + //check key_image in altchain + //check among this alt block already collected key images first + if (collected_keyimages.find(input.k_image) != collected_keyimages.end()) + { + // cases b2, b3 + LOG_ERROR("key image " << input.k_image << " already spent in this alt block"); + return false; + } + auto ki_it = m_altblocks_keyimages.find(input.k_image); + if (ki_it != m_altblocks_keyimages.end()) + { + //have some entry for this key image. Check if this key image belongs to this alt chain + const std::list& key_image_block_ids = ki_it->second; + for (auto& h : key_image_block_ids) + { + if (alt_chain_block_ids.find(h) != alt_chain_block_ids.end()) + { + // cases b2, b3 + LOG_ERROR("key image " << input.k_image << " already spent in altchain"); + return false; + } + } + } + //update altchain with key image + collected_keyimages.insert(input.k_image); + TIME_MEASURE_FINISH(ki_lookup_time); + ki_lookuptime = ki_lookup_time; + + std::vector abs_key_offsets = relative_output_offsets_to_absolute(input.key_offsets); + CHECK_AND_ASSERT_MES(abs_key_offsets.size() > 0 && abs_key_offsets.size() == input.key_offsets.size(), false, "internal error: abs_key_offsets.size()==" << abs_key_offsets.size() << ", input.key_offsets.size()==" << input.key_offsets.size()); + // eventually we should found all public keys for all outputs this input refers to, for checking ring signature + std::vector pub_keys(abs_key_offsets.size(), null_pkey); + + // + // let's try to resolve references and populate pub keys container for check_tokey_input() + // + uint64_t global_outs_for_amount = 0; + //figure out if this amount touched alt_chain amount's index and if it is, get + bool amount_touched_altchain = false; + //auto abg_it = abei.gindex_lookup_table.find(input.amount); + //if (abg_it == abei.gindex_lookup_table.end()) + + if (!alt_chain.empty()) + { + auto abg_it = alt_chain.back()->second.gindex_lookup_table.find(input.amount); + if (abg_it != alt_chain.back()->second.gindex_lookup_table.end()) + { + amount_touched_altchain = true; + //Notice: since transactions is not allowed to refer to each other in one block, then we can consider that index in + //tx input would be always less then top for previous block, so just take it + global_outs_for_amount = abg_it->second; + } + else + { + //quite easy, + global_outs_for_amount = m_db_outputs.get_item_size(input.amount); + } + } + else + { + //quite easy, + global_outs_for_amount = m_db_outputs.get_item_size(input.amount); + } + + CHECK_AND_ASSERT_MES(pub_keys.size() == abs_key_offsets.size(), false, "pub_keys.size()==" << pub_keys.size() << " != abs_key_offsets.size()==" << abs_key_offsets.size()); // just a little bit of paranoia + std::vector pub_key_pointers; + for (size_t pk_n = 0; pk_n < pub_keys.size(); ++pk_n) + { + crypto::public_key& pk = pub_keys[pk_n]; + crypto::hash tx_id = null_hash; + uint64_t out_n = UINT64_MAX; + auto &off = abs_key_offsets[pk_n]; + if (off.type() == typeid(uint64_t)) + { + uint64_t offset_gindex = boost::get(off); + CHECK_AND_ASSERT_MES(offset_gindex < global_outs_for_amount, false, + "invalid global output index " << offset_gindex << " for amount=" << input.amount << + ", max is " << global_outs_for_amount << + ", referred to by offset #" << pk_n << + ", amount_touched_altchain = " << amount_touched_altchain); + if (amount_touched_altchain) + { + bool found_the_key = false; + for (auto alt_it = alt_chain.rbegin(); alt_it != alt_chain.rend(); alt_it++) + { + auto it_aag = (*alt_it)->second.gindex_lookup_table.find(input.amount); + if (it_aag == (*alt_it)->second.gindex_lookup_table.end()) + { + CHECK_AND_ASSERT_MES(alt_it != alt_chain.rbegin(), false, "internal error: was marked as amount_touched_altchain but unable to find on first entry"); + //item supposed to be in main chain + break; + } + if (offset_gindex >= it_aag->second) + { + //GOT IT!! + //TODO: At the moment we ignore check of mix_attr again mixing to simplify alt chain check, but in future consider it for stronger validation + uint64_t local_offset = offset_gindex - it_aag->second; + auto& alt_keys = (*alt_it)->second.outputs_pub_keys; + CHECK_AND_ASSERT_MES(local_offset < alt_keys[input.amount].size(), false, "Internal error: local_offset=" << local_offset << " while alt_keys[" << input.amount << " ].size()=" << alt_keys.size()); + pk = alt_keys[input.amount][local_offset]; + pub_key_pointers.push_back(&pk); + found_the_key = true; + break; + } + } + if (found_the_key) + break; + //otherwise lookup in main chain index + } + auto p = m_db_outputs.get_subitem(input.amount, offset_gindex); + CHECK_AND_ASSERT_MES(p != nullptr, false, "global output was not found, amount: " << input.amount << ", gindex: " << offset_gindex << ", referred to by offset #" << pk_n); + tx_id = p->tx_id; + out_n = p->out_no; + } + else if (off.type() == typeid(ref_by_id)) + { + auto &rbi = boost::get(off); + tx_id = rbi.tx_id; + out_n = rbi.n; + } + + auto p = m_db_transactions.get(tx_id); + CHECK_AND_ASSERT_MES(p != nullptr && out_n < p->tx.vout.size(), false, "can't find output #" << out_n << " for tx " << tx_id << " referred by offset #" << pk_n); + auto &t = p->tx.vout[out_n].target; + CHECK_AND_ASSERT_MES(t.type() == typeid(txout_to_key), false, "txin_to_key input offset #" << pk_n << " refers to incorrect output type " << t.type().name()); + auto& out_tk = boost::get(t); + pk = out_tk.key; + bool mixattr_ok = is_mixattr_applicable_for_fake_outs_counter(out_tk.mix_attr, abs_key_offsets.size() - 1); + CHECK_AND_ASSERT_MES(mixattr_ok, false, "input offset #" << pk_n << " violates mixin restrictions: mix_attr = " << static_cast(out_tk.mix_attr) << ", input's key_offsets.size = " << abs_key_offsets.size()); + + // case b4 (make sure source tx in the main chain is preceding split point, otherwise this referece is invalid) + CHECK_AND_ASSERT_MES(p->m_keeper_block_height < split_height, false, "input offset #" << pk_n << " refers to main chain tx " << tx_id << " at height " << p->m_keeper_block_height << " while split height is " << split_height); + + if (p_max_related_block_height != nullptr && *p_max_related_block_height < p->m_keeper_block_height) + *p_max_related_block_height = p->m_keeper_block_height; + + // TODO: consider checking p->tx for unlock time validity as it's checked in get_output_keys_for_input_with_checks() + // make sure it was actually found + CHECK_AND_ASSERT_MES(pk != null_pkey, false, "Can't determine output public key for offset " << pk_n); + pub_key_pointers.push_back(&pk); + } + + // do input checks (attachment_info, ring signature and extra signature, etc.) + r = check_tokey_input(input_tx, input_index, input, input_tx_hash, input_sigs, pub_key_pointers); + CHECK_AND_ASSERT_MES(r, false, "to_key input validation failed"); + + // TODO: consider checking input_tx for valid extra attachment info as it's checked in check_tx_inputs() + + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::validate_alt_block_ms_input(const transaction& input_tx, const crypto::hash& input_tx_hash, size_t input_index, const std::vector& input_sigs, uint64_t split_height, const alt_chain_type& alt_chain) const +{ + // Main and alt chain outline: + // + // A- A- A- B- B- B- B- <-- main chain + // | + // \- C- C- C- <-- alt chain + // ^ + // | + // split height + // + // List of possible cases + // + // | src tx | another | this tx | + // # | output | tx input | input | meaning + // ------------ bad cases ------------------ + // b1 A A C already spent in main chain + // b2 A C C already spent in alt chain + // b3 C C C already spent in alt chain + // b4 B B/- C output not found (in case there's no valid outs in altchain C) + // ------------ good cases ------------------ + // g1 A - C normal spending output from main chain A + // g2 A B C normal spending output from main chain A (although it is spent in main chain B as well) + // g3 C - C normal spending output from alt chain C + // g4 B,C - C src tx added to both main chain B and alt chain C + // g5 B,C B C src tx added to both main chain B and alt chain C, also spent in B + + CRITICAL_REGION_LOCAL(m_read_lock); + bool r = false; + + CHECK_AND_ASSERT_MES(input_index < input_tx.vin.size() && input_tx.vin[input_index].type() == typeid(txin_multisig), false, "invalid ms input index: " << input_index << " or type"); + const txin_multisig& input = boost::get(input_tx.vin[input_index]); + + // check corresponding ms out in the main chain + auto p = m_db_multisig_outs.get(input.multisig_out_id); + if (p != nullptr) + { + // check case b1 (note: need to distinguish from case g2) + CHECK_AND_ASSERT_MES(p->spent_height == 0 || p->spent_height >= split_height, false, "ms output was already spent in main chain at height " << p->spent_height << " while split_height is " << split_height); + + const crypto::hash& source_tx_id = p->tx_id; + auto p_source_tx = m_db_transactions.get(source_tx_id); + CHECK_AND_ASSERT_MES(p_source_tx != nullptr, false, "source tx for ms output " << source_tx_id << " was not found, ms out id: " << input.multisig_out_id); + + if (p_source_tx->m_keeper_block_height < split_height) + { + // cases g1, g2 + return check_ms_input(input_tx, input_index, input, input_tx_hash, input_sigs, p_source_tx->tx, p->out_no); + } + + // p_source_tx is above split_height in main chain B, so it can't be a source for this input + // do nohting here and proceed to alt chain scan for possible cases b4, g4, g5 + } + else + { + // ms out was not found in DB + // do nothing here and proceed to alt chain scan for possible cases b2, b3, g3, g4, g5 + } + + + // walk the alt chain backward (from the the last added alt block towards split point -- it important as we stop scanning when find correct output, need to make sure it was not already spent) + for (alt_chain_type::const_reverse_iterator it = alt_chain.rbegin(); it != alt_chain.rend(); ++it) + { + const block_extended_info& bei = (*it)->second; + const block& b = bei.bl; + bool output_found = false; + + auto tx_altchain_checker = [&](const transaction& tx, const crypto::hash& tx_id) -> bool + { + // check ms out being already spent in current alt chain + for (auto& in : tx.vin) + { + if (in.type() == typeid(txin_multisig)) + { + // check cases b2, b3 + CHECK_AND_ASSERT_MES(input.multisig_out_id != boost::get(in).multisig_out_id, false, "ms out " << input.multisig_out_id << " has been already spent in altchain by tx " << tx_id << " in block " << get_block_hash(b) << " height " << bei.height); + } + } + + for (size_t out_n = 0; out_n < tx.vout.size(); ++out_n) + { + const tx_out& out = tx.vout[out_n]; + if (out.target.type() == typeid(txout_multisig)) + { + const crypto::hash& ms_out_id = get_multisig_out_id(tx, out_n); + if (ms_out_id == input.multisig_out_id) + { + // cases g3, g4, g5 + output_found = true; + return check_ms_input(input_tx, input_index, input, input_tx_hash, input_sigs, tx, out_n); + } + } + } + return true; + }; + + // for each alt block look into miner_tx and txs + CHECK_AND_ASSERT_MES(tx_altchain_checker(b.miner_tx, get_transaction_hash(b.miner_tx)), false, "tx_altchain_checker failed for miner tx"); + if (output_found) + return true; // g3, g4, g5 + for (auto& tx_id : b.tx_hashes) + { + std::shared_ptr tx_ptr; + r = get_transaction_from_pool_or_db(tx_id, tx_ptr, split_height); + CHECK_AND_ASSERT_MES(r, false, "can't get transaction " << tx_id << " for alt block " << get_block_hash(b) << " height " << bei.height << ", split height is " << split_height); + transaction& tx = *tx_ptr; + CHECK_AND_ASSERT_MES(tx_altchain_checker(tx, tx_id), false, "tx_altchain_checker failed for tx " << tx_id); + if (output_found) + return true; // g3, g4, g5 + } + } + + // case b4 + LOG_ERROR("ms outout " << input.multisig_out_id << " was not found neither in main chain, nor in alt chain"); + return false; +} +//------------------------------------------------------------------ +bool blockchain_storage::get_transaction_from_pool_or_db(const crypto::hash& tx_id, std::shared_ptr& tx_ptr, uint64_t min_allowed_block_height /* = 0 */) const +{ + tx_ptr.reset(new transaction()); + + if (!m_tx_pool.get_transaction(tx_id, *tx_ptr)) // first try to get from the pool + { + auto p = m_db_transactions.get(tx_id); // if not found in the pool -- get from the DB + CHECK_AND_ASSERT_MES(p != nullptr, false, "can't get tx " << tx_id << " neither from the pool, nor from db_transactions"); + CHECK_AND_ASSERT_MES(p->m_keeper_block_height >= min_allowed_block_height, false, "tx " << tx_id << " found in the main chain at height " << p->m_keeper_block_height << " while required min allowed height is " << min_allowed_block_height); + *tx_ptr = p->tx; + } + + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::update_alt_out_indexes_for_tx_in_block(const transaction& tx, alt_block_extended_info& abei) const +{ + //add tx outputs to gindex_lookup_table + for (auto o : tx.vout) + { + if (o.target.type() == typeid(txout_to_key)) + { + //LOG_PRINT_MAGENTA("ALT_OUT KEY ON H[" << abei.height << "] AMOUNT: " << o.amount, LOG_LEVEL_0); + // first, look at local gindexes tables + if (abei.gindex_lookup_table.find(o.amount) == abei.gindex_lookup_table.end()) + { + // amount was not found in altchain gindexes container, start indexing from current main chain gindex + abei.gindex_lookup_table[o.amount] = m_db_outputs.get_item_size(o.amount); + //LOG_PRINT_MAGENTA("FIRST TOUCH: size=" << abei.gindex_lookup_table[o.amount], LOG_LEVEL_0); + } + abei.outputs_pub_keys[o.amount].push_back(boost::get(o.target).key); + //TODO: At the moment we ignore check of mix_attr again mixing to simplify alt chain check, but in future consider it for stronger validation + } + } + return true; +} + +bool blockchain_storage::validate_alt_block_txs(const block& b, const crypto::hash& id, std::set& collected_keyimages, alt_block_extended_info& abei, const alt_chain_type& alt_chain, uint64_t split_height, uint64_t& ki_lookup_time_total) const +{ + uint64_t height = abei.height; + bool r = false; + std::set alt_chain_block_ids; + + alt_chain_block_ids.insert(id); + // prepare data structure for output global indexes tracking within current alt chain + if (alt_chain.size()) + { + //TODO: in this two lines we scarify memory to earn speed for algo, but need to be careful with RAM consuming on long switches + abei.gindex_lookup_table = alt_chain.back()->second.gindex_lookup_table; + + //adjust indices for next alt block entry according to emount of pubkeys in txs of prev block + auto& prev_alt_keys = alt_chain.back()->second.outputs_pub_keys; + for (auto it = prev_alt_keys.begin(); it != prev_alt_keys.end(); it++) + { + auto it_amont_in_abs_ind = abei.gindex_lookup_table.find(it->first); + CHECK_AND_ASSERT_MES(it_amont_in_abs_ind != abei.gindex_lookup_table.end(), false, "internal error: not found amount " << it->first << "in gindex_lookup_table"); + //increase index starter for amount of outputs in prev block + it_amont_in_abs_ind->second += it->second.size(); + } + //generate set of alt block ids + for (auto& ch : alt_chain) + { + alt_chain_block_ids.insert(get_block_hash(ch->second.bl)); + } + + } + else + { + // initialize alt chain entry with initial gindexes + calculate_local_gindex_lookup_table_for_height(split_height, abei.gindex_lookup_table); + } + + if (is_pos_block(b)) + { + // check PoS block miner tx in a special way + CHECK_AND_ASSERT_MES(b.miner_tx.signatures.size() == 1 && b.miner_tx.vin.size() == 2, false, "invalid PoS block's miner_tx, signatures size = " << b.miner_tx.signatures.size() << ", miner_tx.vin.size() = " << b.miner_tx.vin.size()); + uint64_t max_related_block_height = 0; + uint64_t ki_lookup = 0; + r = validate_alt_block_input(b.miner_tx, collected_keyimages, id, get_block_hash(b), 1, b.miner_tx.signatures[0], split_height, alt_chain, alt_chain_block_ids, ki_lookup, &max_related_block_height); + CHECK_AND_ASSERT_MES(r, false, "miner tx " << get_transaction_hash(b.miner_tx) << ": validation failed"); + ki_lookup_time_total += ki_lookup; + // check stake age + uint64_t coinstake_age = height - max_related_block_height - 1; + CHECK_AND_ASSERT_MES(coinstake_age >= m_core_runtime_config.min_coinstake_age, false, + "miner tx's coinstake age is " << coinstake_age << ", that is less than minimum required " << m_core_runtime_config.min_coinstake_age << "; max_related_block_height == " << max_related_block_height); + } + update_alt_out_indexes_for_tx_in_block(b.miner_tx, abei); + + for (auto tx_id : b.tx_hashes) + { + std::shared_ptr tx_ptr; + CHECK_AND_ASSERT_MES(get_transaction_from_pool_or_db(tx_id, tx_ptr, split_height), false, "failed to get alt block tx " << tx_id << " with split_height == " << split_height); + transaction& tx = *tx_ptr; + CHECK_AND_ASSERT_MES(tx.signatures.size() == tx.vin.size(), false, "invalid tx: tx.signatures.size() == " << tx.signatures.size() << ", tx.vin.size() == " << tx.vin.size()); + for (size_t n = 0; n < tx.vin.size(); ++n) + { + if (tx.vin[n].type() == typeid(txin_to_key)) + { + uint64_t ki_lookup = 0; + r = validate_alt_block_input(tx, collected_keyimages, id, tx_id, n, tx.signatures[n], split_height, alt_chain, alt_chain_block_ids, ki_lookup); + CHECK_AND_ASSERT_MES(r, false, "tx " << tx_id << ", input #" << n << ": validation failed"); + ki_lookup_time_total += ki_lookup; + } + else if (tx.vin[n].type() == typeid(txin_multisig)) + { + r = validate_alt_block_ms_input(tx, tx_id, n, tx.signatures[n], split_height, alt_chain); + CHECK_AND_ASSERT_MES(r, false, "tx " << tx_id << ", input #" << n << " (multisig): validation failed"); + } + else if (tx.vin[n].type() == typeid(txin_gen)) + { + // genesis can't be in tx_hashes + CHECK_AND_ASSERT_MES(false, false, "input #" << n << " has unexpected type (" << tx.vin[n].type().name() << ", genesis can't be in tx_hashes), tx " << tx_id); + } + else + { + CHECK_AND_ASSERT_MES(false, false, "input #" << n << " has unexpected type (" << tx.vin[n].type().name() << "), tx " << tx_id); + } + } + + // Updating abei (and not updating alt_chain) during this cycle is safe because txs in the same block can't reference one another, + // so only valid references are either to previous alt blocks (accessed via alt_chain) or to main chain blocks. + update_alt_out_indexes_for_tx_in_block(tx, abei); + } + + + return true; +} + + diff --git a/src/currency_core/blockchain_storage.h b/src/currency_core/blockchain_storage.h new file mode 100644 index 00000000..93b32816 --- /dev/null +++ b/src/currency_core/blockchain_storage.h @@ -0,0 +1,762 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include "file_io_utils.h" +#include "serialization/serialization.h" +#include "serialization/string.h" +#include "serialization/multiprecision.h" + +#include "tx_pool.h" +#include "blockchain_storage_basic.h" +#include "common/util.h" +#include "common/db_abstract_accessor.h" +#include "currency_protocol/currency_protocol_defs.h" +#include "rpc/core_rpc_server_commands_defs.h" +#include "difficulty.h" +#include "common/difficulty_boost_serialization.h" +#include "currency_core/currency_format_utils.h" +#include "verification_context.h" +#include "crypto/hash.h" +#include "checkpoints.h" +#include "core_runtime_config.h" +#include "dispatch_core_events.h" +#include "bc_attachments_service_manager.h" +#include "common/median_db_cache.h" + + +MARK_AS_POD_C11(crypto::key_image); +typedef std::pair macro_alias_1; +MARK_AS_POD_C11(macro_alias_1); + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL "core" + +namespace currency +{ + + // blue core + + class blockchain_storage + { + public: + struct performnce_data + { + //block processing zone + epee::math_helper::average block_processing_time_0_ms; + epee::math_helper::average block_processing_time_1; + epee::math_helper::average target_calculating_time_2; + epee::math_helper::average longhash_calculating_time_3; + epee::math_helper::average all_txs_insert_time_5; + epee::math_helper::average etc_stuff_6; + epee::math_helper::average insert_time_4; + epee::math_helper::average raise_block_core_event; + + //tx processing zone + epee::math_helper::average tx_check_inputs_time; + epee::math_helper::average tx_add_one_tx_time; + epee::math_helper::average tx_process_extra; + epee::math_helper::average tx_process_attachment; + epee::math_helper::average tx_process_inputs ; + epee::math_helper::average tx_push_global_index; + epee::math_helper::average tx_check_exist; + epee::math_helper::average tx_print_log; + epee::math_helper::average tx_prapare_append; + + epee::math_helper::average tx_append_time; + epee::math_helper::average tx_append_rl_wait; + epee::math_helper::average tx_append_is_expired; + + epee::math_helper::average tx_store_db; + + epee::math_helper::average tx_check_inputs_prefix_hash; + epee::math_helper::average tx_check_inputs_attachment_check; + epee::math_helper::average tx_check_inputs_loop; + epee::math_helper::average tx_check_inputs_loop_kimage_check; + epee::math_helper::average tx_check_inputs_loop_ch_in_val_sig; + epee::math_helper::average tx_check_inputs_loop_scan_outputkeys_get_item_size; + epee::math_helper::average tx_check_inputs_loop_scan_outputkeys_relative_to_absolute; + epee::math_helper::average tx_check_inputs_loop_scan_outputkeys_loop; + epee::math_helper::average tx_check_inputs_loop_scan_outputkeys_loop_get_subitem; + epee::math_helper::average tx_check_inputs_loop_scan_outputkeys_loop_find_tx; + epee::math_helper::average tx_check_inputs_loop_scan_outputkeys_loop_handle_output; + + + //TODO: move this to suitable place or remove it all + std::atomic epic_failure_happend; + tools::db::stat_info si; + }; + + + struct key_images_ptr_compare + { + bool operator()(const std::shared_ptr& a, const std::shared_ptr& b) const + { + return *a == *b; + } + }; + + struct key_images_ptr_hash + { + std::size_t operator()(const std::shared_ptr& i) const + { + return crypto::hash_value(*i); // TODO: BAD hash function, replace with something better! + } + }; + + struct key_images_ptr_less + { + typedef bool result_type; + bool operator()(const std::shared_ptr& _Left, const std::shared_ptr& _Right) const + { + return (*_Left < *_Right); + } + }; + + // == Output indexes local lookup table conception == + // Main chain gindex table (outputs_container) contains data which is valid only for the most recent block. + // Thus it can't be used to get output's global index for any arbitrary height because there's no height data. + // Having local gindex lookup table for a given height one could retrieve global output index table as it was + // at the given height using the following algorithm: + // + // local_gindex_lookup_table = calculate_local_gindex_lookup_table_for_height(height) + // if amount exists in local_gindex_lookup_table: + // retrieve gindex from local_gindex_lookup_table # there are outputs having given amount after the given height + // else: + // retrieve gindex from main chain gindex table # not outputs having given amount are present after the given height + // + + struct alt_block_extended_info: public block_extended_info + { + // {amount -> gindex } output global index lookup table for this altblock (if an amount isn't present -- it's retreived from main outputs_container) + std::map gindex_lookup_table; + + // {amount -> pub_keys} map of outputs' pub_keys appeared in this alt block ( index_in_vector == output_gindex - gindex_lookup_table[output_amount] ) + std::map > outputs_pub_keys; + }; + typedef std::unordered_map alt_chain_container; + typedef std::list alt_chain_type; + + typedef std::unordered_map blocks_ext_by_hash; + + typedef tools::db::basic_key_to_array_accessor outputs_container; // out_amount => ['global_output', ...] + typedef tools::db::cached_key_value_accessor key_images_container; + typedef std::list, std::list > > > blocks_direct_container; + + friend struct add_transaction_input_visitor; + //--------------------------------------------------------------------------------- + + blockchain_storage(tx_memory_pool& tx_pool); + + + bool init(const boost::program_options::variables_map& vm) { return init(tools::get_default_data_dir(), vm); } + bool init(const std::string& config_folder, const boost::program_options::variables_map& vm); + bool deinit(); + static void init_options(boost::program_options::options_description& desc); + + bool set_checkpoints(checkpoints&& chk_pts); + + //TODO: set this method to const + checkpoints& get_checkpoints() { return m_checkpoints; } + bool is_in_checkpoint_zone() const { return m_is_in_checkpoint_zone; } + + //------------- modifying members -------------- + bool add_new_block(const block& bl_, block_verification_context& bvc); + bool clear(); + bool reset_and_set_genesis_block(const block& b); + //debug function + bool truncate_blockchain(uint64_t to_height); + //------------- readers members ----------------- + bool pre_validate_relayed_block(block& b, block_verification_context& bvc, const crypto::hash& id)const ; + //bool push_new_block(); + bool get_blocks(uint64_t start_offset, size_t count, std::list& blocks, std::list& txs) const ; + bool get_blocks(uint64_t start_offset, size_t count, std::list& blocks) const; + bool get_main_blocks_rpc_details(uint64_t start_offset, size_t count, bool ignore_transactions, std::list& blocks) const; + bool get_main_block_rpc_details(uint64_t i, block_rpc_extended_info& bei) const; + bool get_main_block_rpc_details(const crypto::hash& id, block_rpc_extended_info& bei) const; + bool get_alt_block_rpc_details(const crypto::hash& id, block_rpc_extended_info& bei) const; + bool get_alt_block_rpc_details(const block_extended_info& bei_core, const crypto::hash& id, block_rpc_extended_info& bei) const; + bool get_alt_blocks_rpc_details(uint64_t start_offset, uint64_t count, std::vector& blocks) const; + bool get_tx_rpc_details(const crypto::hash&, tx_rpc_extended_info& tei, uint64_t timestamp, bool is_short) const; + bool search_by_id(const crypto::hash& id, std::list& res) const; + bool get_global_index_details(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES_BY_AMOUNT::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES_BY_AMOUNT::response & resp) const; + bool get_multisig_id_details(const COMMAND_RPC_GET_MULTISIG_INFO::request& req, COMMAND_RPC_GET_MULTISIG_INFO::response & resp) const; + bool get_multisig_id_details(const crypto::hash& ms_id, crypto::hash& tx_id, uint64_t& out_no) const; + bool get_alternative_blocks(std::list& blocks) const; + size_t get_alternative_blocks_count() const; + crypto::hash get_block_id_by_height(uint64_t height) const; + bool get_block_by_hash(const crypto::hash &h, block &blk) const; + bool get_block_extended_info_by_height(uint64_t h, block_extended_info &blk) const; + bool get_block_extended_info_by_hash(const crypto::hash &h, block_extended_info &blk) const; + bool get_block_by_height(uint64_t h, block &blk) const; + bool is_tx_related_to_altblock(crypto::hash tx_id) const; + //void get_all_known_block_ids(std::list &main, std::list &alt, std::list &invalid) const; + + bc_attachment_services_manager& get_attachment_services_manager(){ return m_services_mgr; } + + bool have_tx(const crypto::hash &id) const; + bool have_tx_keyimges_as_spent(const transaction &tx) const; + bool have_tx_keyimg_as_spent(const crypto::key_image &key_im, uint64_t before_height = UINT64_MAX) const; + std::shared_ptr get_tx(const crypto::hash &id) const; + + template + bool scan_outputkeys_for_indexes(const txin_to_key& tx_in_to_key, visitor_t& vis, uint64_t* pmax_related_block_height = NULL) const ; + + uint64_t get_current_blockchain_size() const; + uint64_t get_top_block_height() const; + crypto::hash get_top_block_id() const; + crypto::hash get_top_block_id(uint64_t& height) const; + bool get_top_block(block& b) const; + wide_difficulty_type get_next_diff_conditional(bool pos) const; + wide_difficulty_type get_next_diff_conditional2(bool pos, const alt_chain_type& alt_chain, uint64_t split_height) const; + wide_difficulty_type get_cached_next_difficulty(bool pos) const; + + typedef bool fill_block_template_func_t(block &bl, bool pos, size_t median_size, uint64_t already_generated_coins, size_t &total_size, uint64_t &fee, uint64_t height); + bool create_block_template(block& b, const account_public_address& miner_address, const account_public_address& stakeholder_address, wide_difficulty_type& di, uint64_t& height, const blobdata& ex_nonce, bool pos, const pos_entry& pe, fill_block_template_func_t custom_fill_block_template_func = nullptr) const; + bool create_block_template(block& b, const account_public_address& miner_address, wide_difficulty_type& di, uint64_t& height, const blobdata& ex_nonce) const; + + bool have_block(const crypto::hash& id) const; + size_t get_total_transactions()const; + bool get_outs(uint64_t amount, std::list& pkeys)const; + bool get_short_chain_history(std::list& ids)const; + bool find_blockchain_supplement(const std::list& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp)const; + bool find_blockchain_supplement(const std::list& qblock_ids, uint64_t& starter_offset)const; + bool find_blockchain_supplement(const std::list& qblock_ids, std::list > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count)const; + bool find_blockchain_supplement(const std::list& qblock_ids, blocks_direct_container& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count)const; + //bool find_blockchain_supplement(const std::list& qblock_ids, std::list > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count)const; + bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp)const; + bool handle_get_objects(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res)const; + bool get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res)const; + bool get_backward_blocks_sizes(size_t from_height, std::vector& sz, size_t count)const; + bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector& indexs)const; + bool get_alias_info(const std::string& alias, extra_alias_entry_base& info)const; + std::string get_alias_by_address(const account_public_address& addr)const; + template + bool enumerate_aliases(cb_t cb) const; + template + bool get_aliases(cb_t cb, uint64_t offset, uint64_t count) const; + uint64_t get_aliases_count()const; + uint64_t get_block_h_older_then(uint64_t timestamp) const; + bool validate_tx_service_attachmens_in_services(const tx_service_attachment& a, size_t i, const transaction& tx)const; + bool check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, uint64_t* pmax_related_block_height = NULL)const; + bool check_tx_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, uint64_t* pmax_related_block_height = NULL)const; + bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t* pmax_used_block_height = NULL)const; + //bool check_tx_inputs(const transaction& tx, uint64_t* pmax_used_block_height = NULL)const; + bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t& pmax_used_block_height, crypto::hash& max_used_block_id)const; + bool check_ms_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, const transaction& source_tx, size_t out_n) const; + bool get_output_keys_for_input_with_checks(const txin_to_key& txin, std::vector& output_keys, uint64_t* pmax_related_block_height = NULL) const; + bool check_tokey_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, const std::vector& output_keys_ptrs) const; + uint64_t get_current_comulative_blocksize_limit()const; + uint64_t get_current_hashrate(size_t aprox_count)const; + uint64_t get_seconds_between_last_n_block(size_t n)const; + bool has_multisig_output(const crypto::hash& multisig_id) const; + bool is_multisig_output_spent(const crypto::hash& multisig_id) const; + uint64_t total_coins()const; + bool is_pos_allowed()const; + uint64_t get_tx_fee_median()const; + uint64_t get_tx_expiration_median() const; + uint64_t validate_alias_reward(const transaction& tx, const std::string& ai)const; + void set_event_handler(i_core_event_handler* event_handler) const; + i_core_event_handler* get_event_handler() const; + uint64_t get_last_timestamps_check_window_median() const; + uint64_t get_last_n_blocks_timestamps_median(size_t n) const; + bool prevalidate_alias_info(const transaction& tx, extra_alias_entry& eae); + bool validate_miner_transaction(const block& b, size_t cumulative_block_size, uint64_t fee, uint64_t& base_reward, uint64_t already_generated_coins) const; + performnce_data& get_performnce_data()const; + bool validate_instance(const std::string& path); + bool is_tx_expired(const transaction& tx) const; + std::shared_ptr find_key_image_and_related_tx(const crypto::key_image& ki, crypto::hash& id_result) const; + + wide_difficulty_type block_difficulty(size_t i)const; + bool forecast_difficulty(std::vector> &out_height_2_diff_vector, bool pos) const; + bool prune_aged_alt_blocks(); + bool get_transactions_daily_stat(uint64_t& daily_cnt, uint64_t& daily_volume)const; + bool check_keyimages(const std::list& images, std::list& images_stat)const;//true - unspent, false - spent + bool build_kernel(const block& bl, stake_kernel& kernel, uint64_t& amount, const stake_modifier_type& stake_modifier)const; + // --- PoS --- + bool build_kernel(uint64_t amount, + const crypto::key_image& ki, + stake_kernel& kernel, + const stake_modifier_type& stake_modifier, + uint64_t timestamp)const; + bool build_stake_modifier(stake_modifier_type& sm, const alt_chain_type& alt_chain = alt_chain_type(), uint64_t split_height = 0, crypto::hash *p_last_block_hash = nullptr) const; + + bool scan_pos(const COMMAND_RPC_SCAN_POS::request& sp, COMMAND_RPC_SCAN_POS::response& rsp)const; + bool validate_pos_block(const block& b, const crypto::hash& id, bool for_altchain)const; + bool validate_pos_block(const block& b, wide_difficulty_type basic_diff, const crypto::hash& id, bool for_altchain)const; + bool validate_pos_block(const block& b, + wide_difficulty_type basic_diff, + uint64_t& amount, + wide_difficulty_type& final_diff, + crypto::hash& proof_hash, + const crypto::hash& id, + bool for_altchain, + const alt_chain_type& alt_chain = alt_chain_type(), + uint64_t split_height = 0)const; + void set_core_runtime_config(const core_runtime_config& pc) const; + const core_runtime_config& get_core_runtime_config()const; + size_t get_current_sequence_factor(bool pos)const; + bool get_last_n_blocks_sizes(std::vector& sz, size_t count)const; + std::shared_ptr get_last_block_of_type(bool looking_for_pos, const alt_chain_type& alt_chain = alt_chain_type(), uint64_t split_height = 0)const; + void get_pos_mining_estimate(uint64_t amuont_coins, + uint64_t time, + uint64_t& estimate_result, + uint64_t& pos_coins_and_pos_diff_rate, + std::vector& days)const; + + uint64_t get_alias_coast(const std::string& alias)const; + const outputs_container& get_outputs_container() const { return m_db_outputs; } + std::shared_ptr get_tx_chain_entry(const crypto::hash& tx_hash) const; + bool get_tx_chain_entry(const crypto::hash& tx_hash, transaction_chain_entry& entry) const; + template + void enumerate_transactions(cb_t cb) const { CRITICAL_REGION_LOCAL(m_read_lock); m_db_transactions.enumerate_keys(cb); } + + + + //this function mostly made for debug purposes + template + void rise_core_event(const std::string& event_name, const t_event_details& ed) + { + core_event_v e(ed); + m_event_handler->on_core_event(event_name, e); + } + + template + bool get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs)const + { + CRITICAL_REGION_LOCAL(m_read_lock); + + for(const auto& bl_id: block_ids) + { + auto block_ind_ptr = m_db_blocks_index.find(bl_id); + if (!block_ind_ptr) + missed_bs.push_back(bl_id); + else + { + CHECK_AND_ASSERT_MES(*block_ind_ptr < m_db_blocks.size(), false, "Internal error: bl_id=" << string_tools::pod_to_hex(bl_id) + << " have index record with offset=" << *block_ind_ptr << ", bigger then m_blocks.size()=" << m_db_blocks.size()); + blocks.push_back(m_db_blocks[*block_ind_ptr]->bl); + } + } + return true; + } + + template + bool get_transactions(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs)const + { + CRITICAL_REGION_LOCAL(m_read_lock); + + BOOST_FOREACH(const auto& tx_id, txs_ids) + { + auto tx_ptr = m_db_transactions.find(tx_id); + if (!tx_ptr) + { + transaction tx; + if (!m_tx_pool.get_transaction(tx_id, tx)) + missed_txs.push_back(tx_id); + else + txs.push_back(tx); + } + else + txs.push_back(tx_ptr->tx); + } + return true; + } + + + template + bool get_transactions_direct(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs)const + { + CRITICAL_REGION_LOCAL(m_read_lock); + + for(const auto& tx_id: txs_ids) + { + auto tx_ptr = m_db_transactions.find(tx_id); + if (!tx_ptr) + missed_txs.push_back(tx_id); + else + txs.push_back(tx_ptr); + } + return true; + } + + //TODO: set to const + void get_alternative_chains(alt_chain_container& ach) { CRITICAL_REGION_LOCAL(m_alternative_chains_lock); ach = m_alternative_chains; } + void set_alternative_chains(const alt_chain_container& ach) { CRITICAL_REGION_LOCAL(m_alternative_chains_lock); m_alternative_chains = ach; } + + template + void serialize(archive_t & ar, const unsigned int version); + + + + //debug functions + bool validate_blockchain_prev_links(size_t last_n_blocks_to_check = 10) const; + bool print_transactions_statistics()const; + void print_blockchain(uint64_t start_index, uint64_t end_index) const ; + std::string get_blockchain_string(uint64_t start_index, uint64_t end_index) const; + void print_blockchain_with_tx(uint64_t start_index, uint64_t end_index) const; + void print_blockchain_index() const; + void print_blockchain_outs(const std::string& file) const; + void print_blockchain_outs_stat() const; + void print_db_cache_perfeormance_data() const; + bool calc_tx_cummulative_blob(const block& bl)const; + bool get_outs_index_stat(outs_index_stat& outs_stat)const; + bool print_lookup_key_image(const crypto::key_image& ki) const; + void reset_db_cache() const; + void clear_altblocks(); + void inspect_blocks_index() const; + bool rebuild_tx_fee_medians(); + bool validate_all_aliases_for_new_median_mode(); + private: + + //-------------- DB containers -------------- + typedef tools::db::cached_key_value_accessor blocks_by_id_index; + typedef tools::db::cached_key_value_accessor transactions_container; + + typedef tools::db::array_accessor blocks_container; + + typedef tools::db::cached_key_value_accessor, true, true> aliases_container; + typedef tools::db::cached_key_value_accessor, true, false> address_to_aliases_container; + typedef tools::db::cached_key_value_accessor multisig_outs_container;// ms out id => ms_output_entry + typedef tools::db::cached_key_value_accessor solo_options_container; + typedef tools::db::basic_key_value_accessor per_block_gindex_increments_container; // height => [(amount, gindex_increment), ...] + + //----------------------------------------- + + tx_memory_pool& m_tx_pool; + mutable bc_attachment_services_manager m_services_mgr; + + /* + At the moment we don't use synchronization for read operations since db do all dirty work. + Write operation synchronized by db_backend.begin_transaction() if it called with write permissions + and caches disabled for all other threads while writer is acting. + The only problem left is that when readers threads still do some work, writer can commit changes and enable cache, + which can lead to wrong interpretation of core data structure (state of the core changed while reader assume that state is the same). + To avoid this cases we use read-write lock, which acquired exclusive access only when writer finished his work and want to commit changes + and enable caches - with this acquiring writer wait wile all readers finish their reading. + */ + epee::shared_recursive_mutex m_rw_lock; + //mutable dummy_critical_section m_read_lock; + mutable epee::shared_membership m_read_lock; + + //---------- db members --------------------- + //main accessor + tools::db::basic_db_accessor m_db; + //containers + blocks_container m_db_blocks; + blocks_by_id_index m_db_blocks_index; + transactions_container m_db_transactions; + key_images_container m_db_spent_keys; + solo_options_container m_db_solo_options; + tools::db::solo_db_value m_db_current_block_cumul_sz_limit; + tools::db::solo_db_value m_db_current_pruned_rs_height; + tools::db::solo_db_value m_db_last_worked_version; + tools::db::solo_db_value m_db_storage_major_compatibility_version; + tools::db::solo_db_value m_db_storage_minor_compatibility_version; + outputs_container m_db_outputs; + multisig_outs_container m_db_multisig_outs; + aliases_container m_db_aliases; + address_to_aliases_container m_db_addr_to_alias; + per_block_gindex_increments_container m_db_per_block_gindex_incs; + + + + + + mutable critical_section m_invalid_blocks_lock; + blocks_ext_by_hash m_invalid_blocks; // crypto::hash -> block_extended_info + mutable critical_section m_alternative_chains_lock; + alt_chain_container m_alternative_chains; // crypto::hash -> alt_block_extended_info + std::unordered_map m_alternative_chains_txs; // tx_id -> how many alt blocks it related to (always >= 1) + std::unordered_map> m_altblocks_keyimages; // key image -> list of alt blocks hashes where it appears in inputs + + std::atomic m_is_in_checkpoint_zone; + std::atomic m_is_blockchain_storing; + + std::string m_config_folder; + //events + checkpoints m_checkpoints; + mutable core_runtime_config m_core_runtime_config; + mutable i_core_event_handler* m_event_handler; + mutable i_core_event_handler m_event_handler_stub; + + //tools::median_db_cache m_tx_fee_median; + mutable std::unordered_map m_timestamps_median_cache; + mutable performnce_data m_performance_data; + std::list m_core_events_pack; + mutable epee::file_io_utils::native_filesystem_handle m_interprocess_locker_file; + //just informational + mutable wide_difficulty_type m_cached_next_pow_difficulty; + mutable wide_difficulty_type m_cached_next_pos_difficulty; + //work like a cache to avoid + mutable uint64_t m_current_fee_median; + mutable uint64_t m_current_fee_median_effective_index; + bool m_is_reorganize_in_process; + + + bool init_tx_fee_median(); + bool update_tx_fee_median(); + void initialize_db_solo_options_values(); + bool switch_to_alternative_blockchain(alt_chain_type& alt_chain); + void purge_alt_block_txs_hashs(const block& b); + void add_alt_block_txs_hashs(const block& b); + bool pop_block_from_blockchain(); + bool purge_block_data_from_blockchain(const block& b, size_t processed_tx_count); + bool purge_block_data_from_blockchain(const block& b, size_t processed_tx_count, uint64_t& fee); + bool purge_transaction_from_blockchain(const crypto::hash& tx_id, uint64_t& fee); + bool purge_transaction_keyimages_from_blockchain(const transaction& tx, bool strict_check); + wide_difficulty_type get_next_difficulty_for_alternative_chain(const alt_chain_type& alt_chain, block_extended_info& bei, bool pos) const; + bool handle_block_to_main_chain(const block& bl, block_verification_context& bvc); + bool handle_block_to_main_chain(const block& bl, const crypto::hash& id, block_verification_context& bvc); + std::string print_alt_chain(alt_chain_type alt_chain); + bool handle_alternative_block(const block& b, const crypto::hash& id, block_verification_context& bvc); + bool is_reorganize_required(const block_extended_info& main_chain_bei, const block_extended_info& alt_chain_bei, const crypto::hash& proof_alt); + bool purge_keyimage_from_big_heap(const crypto::key_image& ki, const crypto::hash& id); + bool purge_altblock_keyimages_from_big_heap(const block& b, const crypto::hash& id); + bool append_altblock_keyimages_to_big_heap(const crypto::hash& block_id, const std::set& alt_block_keyimages); + bool validate_alt_block_input(const transaction& input_tx, std::set& collected_keyimages, const crypto::hash& bl_id, const crypto::hash& input_tx_hash, size_t input_index, const std::vector& input_sigs, uint64_t split_height, const alt_chain_type& alt_chain, const std::set& alt_chain_block_ids, uint64_t& ki_lookuptime, uint64_t* p_max_related_block_height = nullptr) const; + bool validate_alt_block_ms_input(const transaction& input_tx, const crypto::hash& input_tx_hash, size_t input_index, const std::vector& input_sigs, uint64_t split_height, const alt_chain_type& alt_chain) const; + bool validate_alt_block_txs(const block& b, const crypto::hash& id, std::set& collected_keyimages, alt_block_extended_info& abei, const alt_chain_type& alt_chain, uint64_t split_height, uint64_t& ki_lookup_time_total) const; + bool update_alt_out_indexes_for_tx_in_block(const transaction& tx, alt_block_extended_info& abei)const; + bool get_transaction_from_pool_or_db(const crypto::hash& tx_id, std::shared_ptr& tx_ptr, uint64_t min_allowed_block_height = 0) const; + + bool prevalidate_miner_transaction(const block& b, uint64_t height, bool pos)const; + bool validate_transaction(const block& b, uint64_t height, const transaction& tx)const; + bool rollback_blockchain_switching(std::list& original_chain, size_t rollback_height); + bool add_transaction_from_block(const transaction& tx, const crypto::hash& tx_id, const crypto::hash& bl_id, uint64_t bl_height, uint64_t timestamp); + bool push_transaction_to_global_outs_index(const transaction& tx, const crypto::hash& tx_id, std::vector& global_indexes); + bool pop_transaction_from_global_index(const transaction& tx, const crypto::hash& tx_id); + bool add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, uint64_t amount, size_t i, uint64_t mix_count, bool use_only_forced_to_mix = false) const; + bool is_tx_spendtime_unlocked(uint64_t unlock_time)const; + bool add_block_as_invalid(const block& bl, const crypto::hash& h); + bool add_block_as_invalid(const block_extended_info& bei, const crypto::hash& h); + size_t find_end_of_allowed_index(uint64_t amount)const; + bool check_block_timestamp_main(const block& b)const; + bool check_block_timestamp(std::vector timestamps, const block& b)const; + std::vector get_last_n_blocks_timestamps(size_t n)const; + const std::vector& get_txin_etc_options(const txin_v& in)const; + void on_block_added(const block_extended_info& bei, const crypto::hash& id); + void on_block_removed(const block_extended_info& bei); + uint64_t tx_fee_median_for_height(uint64_t h) const; + uint64_t get_tx_fee_median_effective_index(uint64_t h) const; + void on_abort_transaction(); + + + uint64_t get_adjusted_time()const; + bool complete_timestamps_vector(uint64_t start_height, std::vector& timestamps); + bool update_next_comulative_size_limit(); + //bool get_block_for_scratchpad_alt(uint64_t connection_height, uint64_t block_index, std::list& alt_chain, block & b); + bool process_blockchain_tx_extra(const transaction& tx); + bool unprocess_blockchain_tx_extra(const transaction& tx); + bool process_blockchain_tx_attachments(const transaction& tx, uint64_t h, const crypto::hash& bl_id, uint64_t timestamp); + bool unprocess_blockchain_tx_attachments(const transaction& tx, uint64_t h, uint64_t timestamp); + bool pop_alias_info(const extra_alias_entry& ai); + bool put_alias_info(const transaction& tx, extra_alias_entry& ai); + void fill_addr_to_alias_dict(); + //bool resync_spent_tx_flags(); + bool prune_ring_signatures_and_attachments_if_need(); + bool prune_ring_signatures_and_attachments(uint64_t height, uint64_t& transactions_pruned, uint64_t& signatures_pruned, uint64_t& attachments_pruned); + // bool build_stake_modifier_for_alt(const alt_chain_type& alt_chain, stake_modifier_type& sm); + template + bool enum_blockchain(visitor_t& v, const alt_chain_type& alt_chain = alt_chain_type(), uint64_t split_height = 0) const; + bool update_spent_tx_flags_for_input(uint64_t amount, const txout_v& o, bool spent); + bool update_spent_tx_flags_for_input(uint64_t amount, uint64_t global_index, bool spent); + bool update_spent_tx_flags_for_input(const crypto::hash& multisig_id, uint64_t spent_height); + bool update_spent_tx_flags_for_input(const crypto::hash& tx_id, size_t n, bool spent); + + void push_block_to_per_block_increments(uint64_t height_, std::unordered_map& gindices); + void pop_block_from_per_block_increments(uint64_t height_); + void calculate_local_gindex_lookup_table_for_height(uint64_t split_height, std::map& increments) const; + void do_erase_altblock(alt_chain_container::iterator it); + + + + + //POS + wide_difficulty_type get_adjusted_cumulative_difficulty_for_next_pos(wide_difficulty_type next_diff)const; + wide_difficulty_type get_adjusted_cumulative_difficulty_for_next_alt_pos(alt_chain_type& alt_chain, uint64_t block_height, wide_difficulty_type next_diff, uint64_t connection_height)const; + uint64_t get_last_x_block_height(bool pos)const; + wide_difficulty_type get_last_alt_x_block_cumulative_precise_difficulty(alt_chain_type& alt_chain, uint64_t block_height, bool pos)const; + size_t get_current_sequence_factor_for_alt(alt_chain_type& alt_chain, bool pos, uint64_t connection_height)const; + }; + + /************************************************************************/ + /* end of class class blockchain_storage */ + /************************************************************************/ + + template + bool blockchain_storage::enum_blockchain(visitor_t& v, const alt_chain_type& alt_chain, uint64_t split_height) const + { + + bool keep_going = true; + for (auto it = alt_chain.rbegin(); it != alt_chain.rend() && keep_going; it++) + { + keep_going = v((*it)->second, false); + } + + if (!keep_going || !m_db_blocks.size()) + return !keep_going; + + size_t main_chain_start_offset = 0; + if (split_height) + main_chain_start_offset = split_height - 1; + else + main_chain_start_offset = (alt_chain.size() ? alt_chain.front()->second.height : m_db_blocks.size()) - 1; + + CRITICAL_REGION_LOCAL(m_read_lock); + for (uint64_t i = main_chain_start_offset; i != 0 && keep_going; --i) + { + keep_going = v(*m_db_blocks[i], true); + } + + return !keep_going; + } + + //------------------------------------------------------------------ + //------------------------------------------------------------------ + template + bool blockchain_storage::scan_outputkeys_for_indexes(const txin_to_key& tx_in_to_key, visitor_t& vis, uint64_t* pmax_related_block_height) const + { + CRITICAL_REGION_LOCAL(m_read_lock); + TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_get_item_size); + + uint64_t outs_count_for_amount = m_db_outputs.get_item_size(tx_in_to_key.amount); + TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_get_item_size); + if (!outs_count_for_amount) + return false; + TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_relative_to_absolute); + std::vector absolute_offsets = relative_output_offsets_to_absolute(tx_in_to_key.key_offsets); + TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_relative_to_absolute); + TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop); + size_t output_index = 0; + for(const txout_v& o : absolute_offsets) + { + crypto::hash tx_id = null_hash; + size_t n = 0; + if (o.type() == typeid(ref_by_id)) + { + tx_id = boost::get(o).tx_id; + n = boost::get(o).n; + } + else if (o.type() == typeid(uint64_t)) + { + TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop_get_subitem); + uint64_t i = boost::get(o); + if (i >= outs_count_for_amount) + { + LOG_ERROR("Wrong index in transaction inputs: " << i << ", expected maximum " << outs_count_for_amount - 1); + return false; + } + auto out_ptr = m_db_outputs.get_subitem(tx_in_to_key.amount, i); + tx_id = out_ptr->tx_id; + n = out_ptr->out_no; + TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop_get_subitem); + } + TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop_find_tx); + auto tx_ptr = m_db_transactions.find(tx_id); + CHECK_AND_ASSERT_MES(tx_ptr, false, "Wrong transaction id in output indexes: " << string_tools::pod_to_hex(tx_id)); + CHECK_AND_ASSERT_MES(n < tx_ptr->tx.vout.size(), false, + "Wrong index in transaction outputs: " << n << ", expected less then " << tx_ptr->tx.vout.size()); + //check mix_attr + TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop_find_tx); + + CHECKED_GET_SPECIFIC_VARIANT(tx_ptr->tx.vout[n].target, const txout_to_key, outtk, false); + + CHECK_AND_ASSERT_MES(tx_in_to_key.key_offsets.size() >= 1, false, "internal error: tx input has empty key_offsets"); // should never happen as input correctness must be handled by the caller + bool mixattr_ok = is_mixattr_applicable_for_fake_outs_counter(outtk.mix_attr, tx_in_to_key.key_offsets.size() - 1); + CHECK_AND_ASSERT_MES(mixattr_ok, false, "tx output #" << output_index << " violates mixin restrictions: mix_attr = " << static_cast(outtk.mix_attr) << ", key_offsets.size = " << tx_in_to_key.key_offsets.size()); + + TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output); + if (!vis.handle_output(tx_ptr->tx, tx_ptr->tx.vout[n])) + { + LOG_PRINT_L0("Failed to handle_output for output id = " << tx_id << ", no " << n); + return false; + } + TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output); + + if (pmax_related_block_height) + { + if (*pmax_related_block_height < tx_ptr->m_keeper_block_height) + *pmax_related_block_height = tx_ptr->m_keeper_block_height; + } + + ++output_index; + } + TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop); + return true; + } + + //------------------------------------------------------------------ + template + bool blockchain_storage::get_aliases(cb_t cb, uint64_t offset, uint64_t count) const + { + CRITICAL_REGION_LOCAL(m_read_lock); + + uint64_t counter = 0; + + m_db_aliases.enumerate_items([&](uint64_t i, const std::string& alias, const std::list& alias_entries) + { + if (alias_entries.empty()) + return true; // continue + + if (counter < offset) + { + ++counter; + return true; // continue + } + + if (counter >= offset + count) + return false; // stop + + ++counter; + + cb(alias, alias_entries.back()); + return true; + }); + return true; + } + //------------------------------------------------------------------ + // callback: (uint64_t i, const std::string& alias, const extra_alias_entry_base& alias_entry) -> bool + // callback should return false to stop enumeration, true - to continue + template + bool blockchain_storage::enumerate_aliases(cb_t cb) const + { + CRITICAL_REGION_LOCAL(m_read_lock); + + m_db_aliases.enumerate_items([&](uint64_t i, const std::string& alias, const std::list& alias_entries) + { + return cb(i, alias, alias_entries.back()); + }); + + return true; + } + + + +} // namespace currency + + +BOOST_CLASS_VERSION(currency::transaction_chain_entry, CURRENT_TRANSACTION_CHAIN_ENTRY_ARCHIVE_VER) +BOOST_CLASS_VERSION(currency::block_extended_info, CURRENT_BLOCK_EXTENDED_INFO_ARCHIVE_VER) + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL NULL + +#include "blockchain_storage_boost_serialization.h" +#include "currency_boost_serialization.h" diff --git a/src/currency_core/blockchain_storage_basic.h b/src/currency_core/blockchain_storage_basic.h new file mode 100644 index 00000000..d29afc8c --- /dev/null +++ b/src/currency_core/blockchain_storage_basic.h @@ -0,0 +1,131 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include +#include + +#include + +#include +#include +#include + +#include "currency_basic.h" +#include "difficulty.h" + +namespace currency +{ + + struct transaction_chain_entry + { + transaction tx; + uint64_t m_keeper_block_height; + std::vector m_global_output_indexes; + std::vector m_spent_flags; + uint32_t version; + + DEFINE_SERIALIZATION_VERSION(1); + BEGIN_SERIALIZE_OBJECT() + VERSION_ENTRY(version) + FIELD(version) + FIELDS(tx) + FIELD(m_keeper_block_height) + FIELD(m_global_output_indexes) + FIELD(m_spent_flags) + END_SERIALIZE() + }; + + struct block_extended_info + { + block bl; + uint64_t height; + uint64_t block_cumulative_size; + wide_difficulty_type cumulative_diff_adjusted; + wide_difficulty_type cumulative_diff_precise; + wide_difficulty_type difficulty; + uint64_t already_generated_coins; + crypto::hash stake_hash; //TODO: unused field for PoW blocks, subject for refactoring + uint32_t version; + uint64_t this_block_tx_fee_median; //tx fee median for current block transactions + uint64_t effective_tx_fee_median; //current fee median which applied for current block's alias registrations + + DEFINE_SERIALIZATION_VERSION(2); + BEGIN_SERIALIZE_OBJECT() + VERSION_ENTRY(version) + FIELDS(bl) + FIELD(height) + FIELD(block_cumulative_size) + FIELD(cumulative_diff_adjusted) + FIELD(cumulative_diff_precise) + FIELD(difficulty) + FIELD(already_generated_coins) + FIELD(stake_hash) + if (version >= 2) + { + FIELD(this_block_tx_fee_median) + FIELD(effective_tx_fee_median) + } + END_SERIALIZE() + }; + + struct gindex_increment + { + uint64_t amount; // the amount in global outputs table + uint32_t increment; // how many outputs of such amount a block adds to global outputs container + + static gindex_increment construct(uint64_t amount, uint32_t increment) + { + gindex_increment r = { amount, increment }; + return r; + } + + BEGIN_SERIALIZE() + VARINT_FIELD(amount) + VARINT_FIELD(increment) + END_SERIALIZE() + }; + + struct block_gindex_increments + { + std::vector increments; + + BEGIN_SERIALIZE() + FIELD(increments) + END_SERIALIZE() + }; + + // element of txout_to_key global outputs container + struct global_output_entry + { + crypto::hash tx_id; // corresponding tx + uint32_t out_no; // local output index in tx + + static global_output_entry construct(crypto::hash tx_id, uint32_t out_no) + { + global_output_entry v = { tx_id, out_no }; + return v; + } + }; + + // element of multisig DB container + struct ms_output_entry + { + crypto::hash tx_id; // source tx id + uint32_t out_no; // output index in source tx + uint32_t spent_height; // height at which this output was spent (0 - not spent yet) + + static ms_output_entry construct(crypto::hash tx_id, uint32_t out_no, uint32_t spent_height = 0) + { + ms_output_entry v = { tx_id, out_no, spent_height }; + return v; + } + }; + + + +} \ No newline at end of file diff --git a/src/currency_core/blockchain_storage_boost_serialization.h b/src/currency_core/blockchain_storage_boost_serialization.h new file mode 100644 index 00000000..a16a36da --- /dev/null +++ b/src/currency_core/blockchain_storage_boost_serialization.h @@ -0,0 +1,48 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +namespace boost +{ + namespace serialization + { + + + template + void serialize(archive_t & ar, currency::transaction_chain_entry& te, const unsigned int version) + { + ar & te.tx; + ar & te.m_keeper_block_height; + ar & te.m_global_output_indexes; + ar & te.m_spent_flags; + } + + template + void serialize(archive_t & ar, currency::block_extended_info& ei, const unsigned int version) + { + ar & ei.bl; + ar & ei.height; + ar & ei.cumulative_diff_adjusted; + ar & ei.cumulative_diff_precise; + ar & ei.difficulty; + ar & ei.block_cumulative_size; + ar & ei.already_generated_coins; + ar & ei.stake_hash; + } + + template + void serialize(archive_t & ar, currency::extra_alias_entry_base& ai, const unsigned int version) + { + ar & ai.m_address.m_spend_public_key; + ar & ai.m_address.m_view_public_key; + ar & ai.m_view_key; + ar & ai.m_sign; + ar & ai.m_text_comment; + //ar & ai.; + } + } +} diff --git a/src/currency_core/checkpoints.cpp b/src/currency_core/checkpoints.cpp new file mode 100644 index 00000000..2d997691 --- /dev/null +++ b/src/currency_core/checkpoints.cpp @@ -0,0 +1,71 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "include_base_utils.h" +using namespace epee; + +#include "checkpoints.h" + +namespace currency +{ + //--------------------------------------------------------------------------- + checkpoints::checkpoints() + { + } + //--------------------------------------------------------------------------- + bool checkpoints::add_checkpoint(uint64_t height, const std::string& hash_str) + { + crypto::hash h = null_hash; + bool r = epee::string_tools::parse_tpod_from_hex_string(hash_str, h); + CHECK_AND_ASSERT_MES(r, false, "WRONG HASH IN CHECKPOINTS!!!"); + CHECK_AND_ASSERT_MES(0 == m_points.count(height), false, "WRONG HASH IN CHECKPOINTS!!!"); + m_points[height] = h; + return true; + } + //--------------------------------------------------------------------------- + bool checkpoints::is_in_checkpoint_zone(uint64_t height) const + { + return !m_points.empty() && (height <= (--m_points.end())->first); + } + //--------------------------------------------------------------------------- + bool checkpoints::is_height_passed_zone(uint64_t height, uint64_t blockchain_last_block_height) const + { + if(height > blockchain_last_block_height) + return false; + + auto it = m_points.lower_bound(height); + if(it == m_points.end()) + return false; + if(it->first <= blockchain_last_block_height) + return true; + else + return false; + } + //--------------------------------------------------------------------------- + uint64_t checkpoints::get_top_checkpoint_height() const + { + if (!m_points.size()) + return 0; + return (--m_points.end())->first; + } + //--------------------------------------------------------------------------- + bool checkpoints::check_block(uint64_t height, const crypto::hash& h) const + { + auto it = m_points.find(height); + if(it == m_points.end()) + return true; + + if(it->second == h) + { + LOG_PRINT_GREEN("CHECKPOINT PASSED FOR HEIGHT " << height << " " << h, LOG_LEVEL_0); + return true; + }else + { + LOG_ERROR("CHECKPOINT FAILED FOR HEIGHT " << height << ". EXPECTED HASH: " << it->second << ", FETCHED HASH: " << h); + return false; + } + } +} diff --git a/src/currency_core/checkpoints.h b/src/currency_core/checkpoints.h new file mode 100644 index 00000000..a845e6eb --- /dev/null +++ b/src/currency_core/checkpoints.h @@ -0,0 +1,26 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include + +#include "currency_core/currency_format_utils.h" + +namespace currency +{ + class checkpoints + { + public: + checkpoints(); + bool add_checkpoint(uint64_t height, const std::string& hash_str); + bool is_in_checkpoint_zone(uint64_t height) const; + bool is_height_passed_zone(uint64_t height, uint64_t blockchain_last_block_height) const; + bool check_block(uint64_t height, const crypto::hash& h) const; + uint64_t get_top_checkpoint_height() const; + private: + std::map m_points; + }; +} diff --git a/src/currency_core/checkpoints_create.h b/src/currency_core/checkpoints_create.h new file mode 100644 index 00000000..e404c659 --- /dev/null +++ b/src/currency_core/checkpoints_create.h @@ -0,0 +1,20 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include "checkpoints.h" +#include "misc_log_ex.h" + +#define ADD_CHECKPOINT(h, hash) CHECK_AND_ASSERT(checkpoints.add_checkpoint(h, hash), false); + +namespace currency { + inline bool create_checkpoints(currency::checkpoints& checkpoints) + { + + return true; + } +} diff --git a/src/currency_core/connection_context.h b/src/currency_core/connection_context.h new file mode 100644 index 00000000..27c54cf7 --- /dev/null +++ b/src/currency_core/connection_context.h @@ -0,0 +1,76 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include +#include +#include "net/net_utils_base.h" +#include "copyable_atomic.h" + +namespace currency +{ + + struct block_context_info + { + crypto::hash h; + uint64_t cumul_size; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_VAL_POD_AS_BLOB(h) + KV_SERIALIZE(cumul_size) + END_KV_SERIALIZE_MAP() + }; + + + struct uncopybale_currency_context + { + uncopybale_currency_context() = default; + uncopybale_currency_context(const uncopybale_currency_context& /**/) {} + uncopybale_currency_context& operator =(const uncopybale_currency_context& /**/) { return *this; } + //members that supposed to be accessed only from one thread + std::list m_needed_objects; + std::unordered_set m_requested_objects; + std::string m_remote_version; + std::atomic m_callback_request_count; //in debug purpose: problem with double callback rise + + }; + + struct currency_connection_context: public epee::net_utils::connection_context_base + { + enum state + { + state_befor_handshake = 0, //default state + state_synchronizing, + state_idle, + state_normal + }; + + state m_state; + uint64_t m_remote_blockchain_height; + uint64_t m_last_response_height; + int64_t m_time_delta; + private: + template friend class t_currency_protocol_handler; + uncopybale_currency_context m_priv; + }; + + inline std::string get_protocol_state_string(currency_connection_context::state s) + { + switch (s) + { + case currency_connection_context::state_befor_handshake: + return "state_befor_handshake"; + case currency_connection_context::state_synchronizing: + return "state_synchronizing"; + case currency_connection_context::state_idle: + return "state_idle"; + case currency_connection_context::state_normal: + return "state_normal"; + default: + return "unknown"; + } + } + +} diff --git a/src/currency_core/core_runtime_config.h b/src/currency_core/core_runtime_config.h new file mode 100644 index 00000000..f046ce02 --- /dev/null +++ b/src/currency_core/core_runtime_config.h @@ -0,0 +1,42 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include "misc_language.h" +#include "string_tools.h" + +namespace currency +{ + typedef uint64_t (*core_time_func_t)(); + + struct core_runtime_config + { + uint64_t min_coinstake_age; + uint64_t pos_minimum_heigh; //height + uint64_t tx_pool_min_fee; + uint64_t tx_default_fee; + crypto::public_key alias_validation_pubkey; + core_time_func_t get_core_time; + + static uint64_t _default_core_time_function() + { + return time(NULL); + } + }; + + inline core_runtime_config get_default_core_runtime_config() + { + core_runtime_config pc = AUTO_VAL_INIT(pc); + pc.min_coinstake_age = POS_MINIMUM_COINSTAKE_AGE; + pc.pos_minimum_heigh = POS_START_HEIGHT; + pc.tx_pool_min_fee = TX_MINIMUM_FEE; + pc.tx_default_fee = TX_DEFAULT_FEE; + pc.get_core_time = &core_runtime_config::_default_core_time_function; + bool r = epee::string_tools::hex_to_pod(ALIAS_SHORT_NAMES_VALIDATION_PUB_KEY, pc.alias_validation_pubkey); + CHECK_AND_ASSERT_THROW_MES(r, "failed to parse alias_validation_pub_key"); + return pc; + } +} diff --git a/src/currency_core/core_tools.h b/src/currency_core/core_tools.h new file mode 100644 index 00000000..38d7362f --- /dev/null +++ b/src/currency_core/core_tools.h @@ -0,0 +1,58 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include "blockchain_storage.h" +#include "bc_offers_service.h" + +namespace currency +{ + inline + bool resync_market(blockchain_storage& bcs, bc_services::bc_offers_service& offers_service) + { + offers_service.clear(); + uint64_t top_block_height = bcs.get_top_block_height(); + currency::block b = AUTO_VAL_INIT(b); + bcs.get_top_block(b); + uint64_t start_height = bcs.get_block_h_older_then(b.timestamp - OFFER_MAXIMUM_LIFE_TIME); + uint64_t print_height_interval = std::max((top_block_height - start_height) / 10ull + 1, 10ull), next_print_height = start_height + print_height_interval; + LOG_PRINT_MAGENTA("Resynchronizing market from height " << start_height << " to height " << top_block_height, LOG_LEVEL_0); + for (uint64_t i = start_height; i <= top_block_height; i++) + { + if (i == next_print_height) + { + LOG_PRINT_MAGENTA("Resynchronizing market: height " << i << " of " << top_block_height << " (" << ((i - start_height) * 100 / (top_block_height - start_height)) << "%)", LOG_LEVEL_0); + next_print_height += print_height_interval; + } + + bcs.get_block_by_height(i, b); + crypto::hash block_id = get_block_hash(b); + for (auto tx_id : b.tx_hashes) + { + auto tx_ptr = bcs.get_tx(tx_id); + CHECK_AND_ASSERT_MES(tx_ptr, false, "Internal error: Failed to get transaction " << tx_id << "from block[" << i << "]"); + uint64_t count = 0; + for (const auto& at : tx_ptr->attachment) + { + if (at.type() == typeid(currency::tx_service_attachment)) + { + const currency::tx_service_attachment& tsa = boost::get(at); + if (tsa.service_id == BC_OFFERS_SERVICE_ID) + { + static_cast(&offers_service)->handle_entry_push(tsa, count, *tx_ptr, i, block_id, b.timestamp); //handle service + } + ++count; + } + } + } + } + LOG_PRINT_MAGENTA("Resynchronizing market finished.", LOG_LEVEL_0); + return true; + } +} \ No newline at end of file diff --git a/src/currency_core/currency_basic.h b/src/currency_core/currency_basic.h new file mode 100644 index 00000000..81d5bac3 --- /dev/null +++ b/src/currency_core/currency_basic.h @@ -0,0 +1,616 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Copyright (c) 2014-2015 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include // memcmp +#include +#include + +#include "include_base_utils.h" + +#include "serialization/binary_archive.h" +#include "serialization/crypto.h" +#include "serialization/stl_containers.h" +#include "serialization/serialization.h" +#include "serialization/variant.h" +#include "serialization/json_archive.h" +#include "serialization/debug_archive.h" +#include "serialization/keyvalue_serialization.h" // epee key-value serialization +#include "string_tools.h" +#include "currency_config.h" +#include "crypto/crypto.h" +#include "crypto/hash.h" +#include "misc_language.h" +#include "block_flags.h" +#include "etc_custom_serialization.h" + +namespace currency +{ + + const static crypto::hash null_hash = AUTO_VAL_INIT(null_hash); + const static crypto::public_key null_pkey = AUTO_VAL_INIT(null_pkey); + const static crypto::key_image null_ki = AUTO_VAL_INIT(null_ki); + const static crypto::secret_key null_skey = AUTO_VAL_INIT(null_skey); + const static crypto::signature null_sig = AUTO_VAL_INIT(null_sig); + const static crypto::key_derivation null_derivation = AUTO_VAL_INIT(null_derivation); + + + + + /************************************************************************/ + /* */ + /************************************************************************/ + + //since structure used in blockchain as a key accessor, then be sure that there is no padding inside +#pragma pack(push, 1) + struct account_public_address + { + crypto::public_key m_spend_public_key; + crypto::public_key m_view_public_key; + + BEGIN_SERIALIZE_OBJECT() + FIELD(m_spend_public_key) + FIELD(m_view_public_key) + END_SERIALIZE() + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_spend_public_key) + KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_view_public_key) + END_KV_SERIALIZE_MAP() + }; +#pragma pack(pop) + + const static account_public_address null_pub_addr = AUTO_VAL_INIT(null_pub_addr); + + typedef std::vector ring_signature; + + /************************************************************************/ + /* extra structures */ + /************************************************************************/ + struct extra_attachment_info + { + uint64_t sz; + crypto::hash hsh; + uint64_t cnt; + + BEGIN_SERIALIZE() + VARINT_FIELD(sz) + FIELD(hsh) + VARINT_FIELD(cnt) + END_SERIALIZE() + }; + + /* outputs */ + +// 'mix_attr' possible values +#define CURRENCY_TO_KEY_OUT_RELAXED 0 // the output may be mixed with any fake outputs +#define CURRENCY_TO_KEY_OUT_FORCED_NO_MIX 1 // the output can't be mixed, only direct spend allowed +#define CURRENCY_TO_KEY_OUT_FORCED_MIX_LOWER_BOUND 2 // this and greather values means minimum number of total outputs (fakes + 1) must be mixed together for using that one + + #pragma pack(push, 1) + struct txout_to_key + { + txout_to_key() : key(null_pkey), mix_attr(0) { } + txout_to_key(const crypto::public_key &_key) : key(_key), mix_attr(0) { } + + crypto::public_key key; + uint8_t mix_attr; + }; + #pragma pack(pop) + + /* inputs */ + + struct txin_gen + { + size_t height; + + BEGIN_SERIALIZE_OBJECT() + VARINT_FIELD(height) + END_SERIALIZE() + }; + + // ref_by_id is used by txin_to_key to reference an output by source transaction hash and output's internal index, + // rather than amount and global output index (by default). Useful when output global index is unknown or may change. + struct ref_by_id + { + crypto::hash tx_id; // source transaction hash + uint32_t n; // output index in source transaction + + BEGIN_SERIALIZE_OBJECT() + FIELD(tx_id) + VARINT_FIELD(n) + END_SERIALIZE() + }; + + typedef boost::variant txout_v; + + + struct signed_parts + { + BEGIN_SERIALIZE_OBJECT() + VARINT_FIELD(n_outs) + VARINT_FIELD(n_extras) + END_SERIALIZE() + + uint32_t n_outs; + uint32_t n_extras; + }; + + + typedef boost::variant txin_etc_details_v; + + struct txin_to_key + { + uint64_t amount; + std::vector key_offsets; + crypto::key_image k_image; // double spending protection + std::vector etc_details; //this flag used when TX_FLAG_SIGNATURE_MODE_SEPARATE flag is set, point to which amount of outputs(starting from zero) used in signature + + BEGIN_SERIALIZE_OBJECT() + VARINT_FIELD(amount) + FIELD(key_offsets) + FIELD(k_image) + FIELD(etc_details) + END_SERIALIZE() + }; + + struct txin_multisig + { + uint64_t amount; + crypto::hash multisig_out_id; + uint32_t sigs_count; // actual number of signatures that are used to sign this input; needed to calculate tx blob size; must be equal to minimum_sigs of corresponding ms output + std::vector etc_details; + + BEGIN_SERIALIZE_OBJECT() + VARINT_FIELD(amount) + FIELD(multisig_out_id) + VARINT_FIELD(sigs_count) + FIELD(etc_details) + END_SERIALIZE() + }; + + struct txout_multisig + { + uint32_t minimum_sigs; + std::vector keys; + + BEGIN_SERIALIZE_OBJECT() + VARINT_FIELD(minimum_sigs) + FIELD(keys) + END_SERIALIZE() + }; + + typedef boost::variant txin_v; + + typedef boost::variant txout_target_v; + + //typedef std::pair out_t; + struct tx_out + { + uint64_t amount; + txout_target_v target; + + BEGIN_SERIALIZE_OBJECT() + VARINT_FIELD(amount) + FIELD(target) + END_SERIALIZE() + }; + + + + struct tx_comment + { + std::string comment; + + BEGIN_SERIALIZE() + FIELD(comment) + END_SERIALIZE() + }; + + struct tx_payer + { + account_public_address acc_addr; + + BEGIN_SERIALIZE() + FIELD(acc_addr) + END_SERIALIZE() + }; + + struct tx_receiver + { + account_public_address acc_addr; + + BEGIN_SERIALIZE() + FIELD(acc_addr) + END_SERIALIZE() + }; + + struct tx_crypto_checksum + { + //we put tx encrypted key_derivation into tx attachment/extra, to let sender decrypt attachments that had been encrypted. + // key_derivation encrypted on sender private send address + crypto::key_derivation encrypted_key_derivation; + uint32_t derivation_hash; + + BEGIN_SERIALIZE() + FIELD(encrypted_key_derivation) + FIELD(derivation_hash) + END_SERIALIZE() + }; + + struct tx_message + { + std::string msg; + + BEGIN_SERIALIZE() + FIELD(msg) + END_SERIALIZE() + }; + + struct tx_service_attachment + { + std::string service_id; //string identifying service which addressed this attachment + std::string instruction; //string identifying specific instructions for service/way to interpret data + std::string body; //any data identifying service, options etc + std::vector security; //some of commands need proof of owner + uint8_t flags; //special flags (ex: TX_SERVICE_ATTACHMENT_ENCRYPT_BODY), see below + + BEGIN_SERIALIZE() + FIELD(service_id) + FIELD(instruction) + FIELD(body) + FIELD(security) + FIELD(flags) + END_SERIALIZE() + }; + +// applicable flags for tx_service_attachment::flags, can be combined using bitwise OR +#define TX_SERVICE_ATTACHMENT_ENCRYPT_BODY static_cast(1 << 0) +#define TX_SERVICE_ATTACHMENT_DEFLATE_BODY static_cast(1 << 1) + //, + + + struct extra_user_data + { + std::string buff; + + BEGIN_SERIALIZE() + FIELD(buff) + END_SERIALIZE() + }; + + + struct extra_alias_entry_base + { + account_public_address m_address; + std::string m_text_comment; + std::vector m_view_key; // only one or zero elments expected (std::vector is using as memory efficient container for such a case) + std::vector m_sign; // only one or zero elments expected (std::vector is using as memory efficient container for such a case) + //uint8_t flags; + + BEGIN_SERIALIZE() + FIELD(m_address) + FIELD(m_text_comment) + FIELD(m_view_key) + FIELD(m_sign) + //FIELD(flags) + END_SERIALIZE() + }; + + struct extra_alias_entry: public extra_alias_entry_base + { + std::string m_alias; + + BEGIN_SERIALIZE() + FIELD(m_alias) + FIELDS(*static_cast(this)) + END_SERIALIZE() + }; + + + + struct extra_padding + { + std::vector buff; //stub + + BEGIN_SERIALIZE() + FIELD(buff) + END_SERIALIZE() + }; + + + //number of block (or time), used as a limitation: spend this tx not early then block/time + struct etc_tx_details_unlock_time + { + uint64_t v; + BEGIN_SERIALIZE() + VARINT_FIELD(v) + END_SERIALIZE() + }; + + struct etc_tx_details_expiration_time + { + uint64_t v; + BEGIN_SERIALIZE() + VARINT_FIELD(v) + END_SERIALIZE() + }; + + /* + this structure used to put real time into PoS block(or could be other meaning), to have more suitable dates in transactions + */ + struct etc_tx_time + { + uint64_t v; + BEGIN_SERIALIZE() + VARINT_FIELD(v) + END_SERIALIZE() + }; + + struct etc_tx_details_flags + { + uint64_t v; + BEGIN_SERIALIZE() + VARINT_FIELD(v) + END_SERIALIZE() + }; + + struct etc_tx_derivation_hint + { + uint16_t v; + BEGIN_SERIALIZE() + FIELD(v) + END_SERIALIZE() + }; + + typedef boost::mpl::vector all_payload_types; + typedef boost::make_variant_over::type attachment_v; + typedef boost::make_variant_over::type extra_v; + typedef boost::make_variant_over::type payload_items_v; + + class transaction_prefix + { + public: + // tx version information + size_t version; + //extra + std::vector extra; + std::vector vin; + std::vector vout; + + BEGIN_SERIALIZE() + VARINT_FIELD(version) + if(CURRENT_TRANSACTION_VERSION < version) return false; + FIELD(vin) + FIELD(vout) + FIELD(extra) + END_SERIALIZE() + + protected: + transaction_prefix(){} + }; + +/* + TX_FLAG_SIGNATURE_MODE_SEPARATE - flag that set different signature validation mode. + With this mode each signature sign prefix with it's own txin entry only, that allow + construct transaction partially, supposed to be in use to construct multisig-based escrow transaction. +*/ +#define TX_FLAG_SIGNATURE_MODE_SEPARATE 0x01 + + + + + class transaction: public transaction_prefix + { + public: + std::vector > signatures; //count signatures always the same as inputs count + std::vector attachment; + + transaction(); + + BEGIN_SERIALIZE_OBJECT() + FIELDS(*static_cast(this)) + FIELD(signatures) + FIELD(attachment) + END_SERIALIZE() + + + }; + + + + + inline + transaction::transaction() + { + version = 0; + vin.clear(); + vout.clear(); + extra.clear(); + signatures.clear(); + attachment.clear(); + + } + /* + inline + transaction::~transaction() + { + //set_null(); + } + + inline + void transaction::set_null() + { + version = 0; + unlock_time = 0; + vin.clear(); + vout.clear(); + extra.clear(); + signatures.clear(); + } + */ + + + + + /************************************************************************/ + /* */ + /************************************************************************/ + struct block_header + { + uint8_t major_version; + uint8_t minor_version; + uint64_t timestamp; + crypto::hash prev_id; + uint64_t nonce; + uint8_t flags; + + BEGIN_SERIALIZE() + FIELD(major_version) + if(major_version > CURRENT_BLOCK_MAJOR_VERSION) return false; + FIELD(nonce) + FIELD(prev_id) + VARINT_FIELD(minor_version) + VARINT_FIELD(timestamp) + FIELD(flags) + END_SERIALIZE() + }; + + struct block: public block_header + { + transaction miner_tx; + std::vector tx_hashes; + + BEGIN_SERIALIZE_OBJECT() + FIELDS(*static_cast(this)) + FIELD(miner_tx) + FIELD(tx_hashes) + END_SERIALIZE() + }; + + + + + struct keypair + { + crypto::public_key pub; + crypto::secret_key sec; + + static inline keypair generate() + { + keypair k; + generate_keys(k.pub, k.sec); + return k; + } + }; + //--------------------------------------------------------------- + //PoS + //based from ppcoin/novacoin approach + + /* + POS PROTOCOL, stake modifier + */ + //------------------------------------------------------------------------------------------------------------------- + + + +#pragma pack(push, 1) + struct stake_modifier_type + { + crypto::hash last_pow_id; + crypto::hash last_pos_kernel_id; + }; + + struct stake_kernel + { + + stake_modifier_type stake_modifier; + uint64_t block_timestamp; //this block timestamp + crypto::key_image kimage; + }; +#pragma pack(pop) + + struct pos_entry + { + uint64_t amount; + uint64_t index; + crypto::key_image keyimage; + uint64_t block_timestamp; + //not for serialization + uint64_t wallet_index; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(amount) + KV_SERIALIZE(index) + KV_SERIALIZE(block_timestamp) + KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(keyimage) + END_KV_SERIALIZE_MAP() + }; +} + +POD_MAKE_HASHABLE(currency, account_public_address); + +BLOB_SERIALIZER(currency::txout_to_key); + +#define SET_VARIANT_TAGS(type_name, id, json_tag) \ + VARIANT_TAG(binary_archive, type_name, id); \ + VARIANT_TAG(json_archive, type_name, json_tag) + + + +// txin_v variant currency +SET_VARIANT_TAGS(currency::txin_gen, 0, "gen"); +SET_VARIANT_TAGS(currency::txin_to_key, 1, "key"); +SET_VARIANT_TAGS(currency::txin_multisig, 2, "multisig"); +// txout_target_v variant definitions +SET_VARIANT_TAGS(currency::txout_to_key, 3, "key"); +SET_VARIANT_TAGS(currency::txout_multisig, 4, "multisig"); +SET_VARIANT_TAGS(currency::transaction, 5, "tx"); +SET_VARIANT_TAGS(currency::block, 6, "block"); +//attachment_v definitions +SET_VARIANT_TAGS(currency::tx_comment, 7, "comment"); +SET_VARIANT_TAGS(currency::tx_payer, 8, "payer"); +SET_VARIANT_TAGS(std::string, 9, "string"); +SET_VARIANT_TAGS(currency::tx_crypto_checksum, 10, "checksum"); +SET_VARIANT_TAGS(currency::tx_message, 11, "message"); +SET_VARIANT_TAGS(currency::tx_service_attachment, 12, "attachment"); +//SET_VARIANT_TAGS(currency::tx_onetime_secret_key, 13, "sec_key"); +SET_VARIANT_TAGS(currency::etc_tx_details_unlock_time, 14, "unlock_time"); +SET_VARIANT_TAGS(currency::etc_tx_details_expiration_time, 15, "expiration_time"); +SET_VARIANT_TAGS(currency::etc_tx_details_flags, 16, "flags"); +//txin_etc_details_v definitions +SET_VARIANT_TAGS(currency::signed_parts, 17, "signed_outs"); +//extra_v definitions +SET_VARIANT_TAGS(currency::extra_attachment_info, 18, "extra_attach_info"); +SET_VARIANT_TAGS(currency::extra_user_data, 19, "user_data"); +SET_VARIANT_TAGS(currency::extra_alias_entry, 20, "alias_entry"); +SET_VARIANT_TAGS(currency::extra_padding, 21, "extra_padding"); +SET_VARIANT_TAGS(crypto::public_key, 22, "pub_key"); +SET_VARIANT_TAGS(currency::etc_tx_derivation_hint, 23, "derive_hint"); +SET_VARIANT_TAGS(uint16_t, 24, "derive_xor"); +//txout_v +SET_VARIANT_TAGS(currency::ref_by_id, 25, "ref_by_id"); +SET_VARIANT_TAGS(uint64_t, 26, "uint64_t"); +//etc +SET_VARIANT_TAGS(currency::etc_tx_time, 27, "etc_tx_time"); +SET_VARIANT_TAGS(uint32_t, 28, "uint32_t"); +SET_VARIANT_TAGS(currency::tx_receiver, 29, "payer"); + +#undef SET_VARIANT_TAGS diff --git a/src/currency_core/currency_boost_serialization.h b/src/currency_core/currency_boost_serialization.h new file mode 100644 index 00000000..6802afd4 --- /dev/null +++ b/src/currency_core/currency_boost_serialization.h @@ -0,0 +1,243 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include "currency_basic.h" +#include "common/unordered_containers_boost_serialization.h" +#include "common/crypto_boost_serialization.h" +#include "offers_services_helpers.h" + +#define CURRENT_BLOCK_ARCHIVE_VER 2 +BOOST_CLASS_VERSION(currency::block, CURRENT_BLOCK_ARCHIVE_VER) + +namespace boost +{ + namespace serialization + { + + template + inline void serialize(Archive &a, currency::account_public_address &x, const boost::serialization::version_type ver) + { + a & x.m_spend_public_key; + a & x.m_view_public_key; + } + + + template + inline void serialize(Archive &a, currency::txout_to_key &x, const boost::serialization::version_type ver) + { + a & x.key; + a & x.mix_attr; + } + + template + inline void serialize(Archive &a, currency::txout_multisig &x, const boost::serialization::version_type ver) + { + a & x.minimum_sigs; + a & x.keys; + } + + template + inline void serialize(Archive &a, currency::txin_gen &x, const boost::serialization::version_type ver) + { + a & x.height; + } + + + template + inline void serialize(Archive &a, currency::txin_multisig &x, const boost::serialization::version_type ver) + { + + a & x.amount; + a & x.multisig_out_id; + a & x.sigs_count; + a & x.etc_details; + } + + + template + inline void serialize(Archive &a, currency::txin_to_key &x, const boost::serialization::version_type ver) + { + a & x.amount; + a & x.key_offsets; + a & x.k_image; + a & x.etc_details; + } + + template + inline void serialize(Archive &a, currency::tx_out &x, const boost::serialization::version_type ver) + { + a & x.amount; + a & x.target; + } + + + + template + inline void serialize(Archive &a, currency::tx_comment &x, const boost::serialization::version_type ver) + { + a & x.comment; + } + + template + inline void serialize(Archive &a, currency::tx_payer &x, const boost::serialization::version_type ver) + { + a & x.acc_addr; + } + template + inline void serialize(Archive &a, currency::tx_receiver &x, const boost::serialization::version_type ver) + { + a & x.acc_addr; + } + template + inline void serialize(Archive &a, currency::tx_crypto_checksum &x, const boost::serialization::version_type ver) + { + a & x.encrypted_key_derivation; + a & x.derivation_hash; + } + template + inline void serialize(Archive &a, currency::tx_message &x, const boost::serialization::version_type ver) + { + a & x.msg; + } + + template + inline void serialize(Archive &a, currency::extra_attachment_info &x, const boost::serialization::version_type ver) + { + a & x.hsh; + a & x.sz; + a & x.cnt; + } + + template + inline void serialize(Archive &a, currency::extra_user_data &x, const boost::serialization::version_type ver) + { + a & x.buff; + } + + template + inline void serialize(Archive &a, currency::extra_alias_entry_base &x, const boost::serialization::version_type ver) + { + a & x.m_address; + a & x.m_text_comment; + a & x.m_view_key; + a & x.m_sign; + } + + + template + inline void serialize(Archive &a, currency::signed_parts &x, const boost::serialization::version_type ver) + { + a & x.n_outs; + a & x.n_extras; + } + + template + inline void serialize(Archive &a, currency::extra_alias_entry &x, const boost::serialization::version_type ver) + { + a & x.m_alias; + a & static_cast(x); + } + + template + inline void serialize(Archive &a, currency::extra_padding &x, const boost::serialization::version_type ver) + { + a & x.buff; + } + + template + inline void serialize(Archive &a, currency::transaction &x, const boost::serialization::version_type ver) + { + a & x.version; + a & x.vin; + a & x.vout; + a & x.extra; + a & x.signatures; + a & x.attachment; + } + + template + inline void serialize(Archive &a, currency::keypair &kp, const boost::serialization::version_type ver) + { + a & kp.pub; + a & kp.sec; + } + + template + inline void serialize(Archive &a, currency::tx_service_attachment &at, const boost::serialization::version_type ver) + { + a & at.service_id; + a & at.security; + a & at.instruction; + a & at.body; + a & at.flags; + } + + template + inline void serialize(Archive &a, currency::etc_tx_details_unlock_time &at, const boost::serialization::version_type ver) + { + a & at.v; + } + template + inline void serialize(Archive &a, currency::etc_tx_details_expiration_time &at, const boost::serialization::version_type ver) + { + a & at.v; + } + template + inline void serialize(Archive &a, currency::etc_tx_details_flags &at, const boost::serialization::version_type ver) + { + a & at.v; + } + template + inline void serialize(Archive &a, currency::etc_tx_time &at, const boost::serialization::version_type ver) + { + a & at.v; + } + + template + inline void serialize(Archive &a, currency::etc_tx_derivation_hint &at, const boost::serialization::version_type ver) + { + a & at.v; + } + + + template + inline void serialize(Archive &a, currency::block &b, const boost::serialization::version_type ver) + { + if (ver < CURRENT_BLOCK_ARCHIVE_VER) + { + throw std::runtime_error("wrong block serialization version"); + } + a & b.major_version; + a & b.minor_version; + a & b.timestamp; + a & b.prev_id; + a & b.nonce; + //------------------ + a & b.miner_tx; + a & b.tx_hashes; + a & b.flags; + } + + + template + inline void serialize(Archive &a, currency::ref_by_id &o, const boost::serialization::version_type ver) + { + a & o.tx_id; + a & o.n; + } + + + } +} diff --git a/src/currency_core/currency_config.h b/src/currency_core/currency_config.h new file mode 100644 index 00000000..5cabbf25 --- /dev/null +++ b/src/currency_core/currency_config.h @@ -0,0 +1,217 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + + +#define CURRENCY_FORMATION_VERSION 74 + + +#define CURRENCY_MAX_BLOCK_NUMBER 500000000 +#define CURRENCY_MAX_BLOCK_SIZE 500000000 // block header blob limit, never used! +#define CURRENCY_TX_MAX_ALLOWED_OUTS 2000 +#define CURRENCY_PUBLIC_ADDRESS_TEXTBLOB_VER 0 +#define CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX 197 // addresses start with 'Z' +#define CURRENCY_PUBLIC_INTEG_ADDRESS_BASE58_PREFIX 0x3678 // addresses start with 'iZ' +#define CURRENCY_MINED_MONEY_UNLOCK_WINDOW 10 +#define CURRENT_TRANSACTION_VERSION 1 +#define CURRENT_BLOCK_MAJOR_VERSION 1 +#define CURRENT_BLOCK_MINOR_VERSION 0 +#define CURRENCY_BLOCK_FUTURE_TIME_LIMIT 60*60*2 +#define CURRENCY_POS_BLOCK_FUTURE_TIME_LIMIT 60*20 + +#define BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW 60 + + +// TOTAL_MONEY_SUPPLY - total number coins to be generated +#define TOTAL_MONEY_SUPPLY ((uint64_t)(-1)) + +#define EMISSION_POS_REWARD_DEVIDER 5425518 // originally based on formula "1/((sqrt(1.05, (740*366)) - 1))" which is avr 5% per year, and then adjusted +#define EMISSION_POW_REWARD_DEVIDER 27098500 // originally based on formula "1/((sqrt(1.01, (740*366)) - 1))" which is avr 1% per year, and then adjusted + +#define POS_START_HEIGHT 0 + +#define CURRENCY_REWARD_BLOCKS_WINDOW 400 +#define CURRENCY_BLOCK_GRANTED_FULL_REWARD_ZONE 125000 //size of block (bytes) after which reward for block calculated using block size +#define CURRENCY_COINBASE_BLOB_RESERVED_SIZE 1100 +#define CURRENCY_MAX_TRANSACTION_BLOB_SIZE (CURRENCY_BLOCK_GRANTED_FULL_REWARD_ZONE - CURRENCY_COINBASE_BLOB_RESERVED_SIZE*2) +#define CURRENCY_FREE_TX_MAX_BLOB_SIZE 1024 // soft txpool-based limit for free-of-charge txs (such as BC_OFFERS_SERVICE_INSTRUCTION_DEL) +#define CURRENCY_DISPLAY_DECIMAL_POINT 8 + +// COIN - number of smallest units in one coin +#define COIN ((uint64_t)100000000) // pow(10, CURRENCY_DISPLAY_DECIMAL_POINT) +#define BASE_REWARD_DUST_THRESHOLD ((uint64_t)1000000) // pow(10, 6) - change this will cause hard-fork! +#define DEFAULT_DUST_THRESHOLD ((uint64_t)0)//((uint64_t)100000) // pow(10, 5) + +#define TX_DEFAULT_FEE ((uint64_t)100000) // pow(10, 5) +#define TX_MINIMUM_FEE ((uint64_t)100000) // pow(10, 5) + +#define CURRENCY_FIXED_REWARD_ZONE_HEIGHT 300 // blocks will have fixed reward up to this height (including) +#define CURRENCY_FIXED_REWARD_ZONE_REWARD_AMOUNT ((uint64_t)100000000) // should be TX_MINIMUM_FEE * CURRENCY_FIXED_REWARD_ZONE_FEE_MULTIPLIER +#define CURRENCY_FIXED_REWARD_ZONE_FEE_MULTIPLIER 1000 // reward in minimum fees for a block in the zone + +#define WALLET_MAX_ALLOWED_OUTPUT_AMOUNT ((uint64_t)0xffffffffffffffffLL) +#define CURRENCY_MINER_TX_MAX_OUTS CURRENCY_TX_MAX_ALLOWED_OUTS + +#define ORPHANED_BLOCKS_MAX_COUNT 100 + +#define DIFFICULTY_STARTER 1 +#define DIFFICULTY_POS_TARGET 120 // seconds +#define DIFFICULTY_POW_TARGET 120 // seconds +#define DIFFICULTY_TOTAL_TARGET ((DIFFICULTY_POS_TARGET + DIFFICULTY_POW_TARGET) / 4) +#define DIFFICULTY_WINDOW 720 // blocks +#define DIFFICULTY_LAG 15 // !!! +#define DIFFICULTY_CUT 60 // timestamps to cut after sorting +#define DIFFICULTY_BLOCKS_COUNT (DIFFICULTY_WINDOW + DIFFICULTY_LAG) + +#define CURRENCY_BLOCKS_PER_DAY ((60*60*24)/(DIFFICULTY_TOTAL_TARGET)) + + +#define TX_EXPIRATION_TIMESTAMP_CHECK_WINDOW 20 +#define TX_EXPIRATION_MEDIAN_SHIFT ((TX_EXPIRATION_TIMESTAMP_CHECK_WINDOW)/2)*DIFFICULTY_TOTAL_TARGET + +#define CURRENCY_LOCKED_TX_ALLOWED_DELTA_SECONDS (DIFFICULTY_TOTAL_TARGET * CURRENCY_LOCKED_TX_ALLOWED_DELTA_BLOCKS) +#define CURRENCY_LOCKED_TX_ALLOWED_DELTA_BLOCKS 1 + +#define DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN DIFFICULTY_TOTAL_TARGET //just alias + +#define MAX_ALIAS_PER_BLOCK 1000 +#define ALIAS_COAST_PERIOD CURRENCY_BLOCKS_PER_DAY*7 //week +#define ALIAS_COAST_RECENT_PERIOD CURRENCY_BLOCKS_PER_DAY*8 //week + 1 day (we guarantee split depth at least 1 day) +#define ALIAS_VERY_INITAL_COAST ((uint64_t)10000) // to avoid split when default fee changed +#define ALIAS_MEDIAN_RECALC_INTERWAL CURRENCY_BLOCKS_PER_DAY + + +#define BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT 2000 //by default, blocks ids count in synchronizing +#define BLOCKS_SYNCHRONIZING_DEFAULT_COUNT 200 //by default, blocks count in blocks downloading +#define BLOCKS_SYNCHRONIZING_DEFAULT_SIZE 2000000 //by default keep synchronizing packets not bigger then 2MB +#define CURRENCY_PROTOCOL_HOP_RELAX_COUNT 3 //value of hop, after which we use only announce of new block + + +#define CURRENCY_ALT_BLOCK_LIVETIME_COUNT (CURRENCY_BLOCKS_PER_DAY*7)//one week +#define CURRENCY_MEMPOOL_TX_LIVETIME 345600 //seconds, 4 days + +#ifndef TESTNET +#define P2P_DEFAULT_PORT (CURRENCY_FORMATION_VERSION+11121) +#define RPC_DEFAULT_PORT 11211 +#define STRATUM_DEFAULT_PORT 11777 +#define P2P_NETWORK_ID_TESTNET_FLAG 0 +#else +#define P2P_DEFAULT_PORT (CURRENCY_FORMATION_VERSION+11112) +#define RPC_DEFAULT_PORT 12111 +#define STRATUM_DEFAULT_PORT 11888 +#define STRARUM_DEFAULT_PORT 51113 +#define P2P_NETWORK_ID_TESTNET_FLAG 1 +#endif + +#define P2P_NETWORK_ID_VER (CURRENCY_FORMATION_VERSION+0) + +#define COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT 4000 + +#define P2P_LOCAL_WHITE_PEERLIST_LIMIT 1000 +#define P2P_LOCAL_GRAY_PEERLIST_LIMIT 5000 + +#define P2P_DEFAULT_CONNECTIONS_COUNT 8 +#define P2P_DEFAULT_HANDSHAKE_INTERVAL 60 //secondes +#define P2P_DEFAULT_PACKET_MAX_SIZE 50000000 //50000000 bytes maximum packet size +#define P2P_DEFAULT_PEERS_IN_HANDSHAKE 250 +#define P2P_DEFAULT_CONNECTION_TIMEOUT 5000 //5 seconds +#define P2P_DEFAULT_PING_CONNECTION_TIMEOUT 2000 //2 seconds +#define P2P_DEFAULT_INVOKE_TIMEOUT 60*2*1000 //2 minutes +#define P2P_DEFAULT_HANDSHAKE_INVOKE_TIMEOUT 10000 //10 seconds +#define P2P_MAINTAINERS_PUB_KEY "888db12b7e0cd325880c815ea13d7062f4c4a89dafc355f4d7b93a7f18342df3" +#define P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT 70 +#define P2P_FAILED_ADDR_FORGET_SECONDS (60*5) //5 minutes + +#define P2P_IP_BLOCKTIME (60*60*24) //24 hours +#define P2P_IP_FAILS_BEFOR_BLOCK 10 +#define P2P_IDLE_CONNECTION_KILL_INTERVAL (5*60) //5 minutes + +//PoS definitions +#define POS_SCAN_WINDOW 60*10 //seconds // 10 minutes +#define POS_SCAN_STEP 15 //seconds +#define POS_MAC_ACTUAL_TIMESTAMP_TO_MINED (POS_SCAN_WINDOW+100) + +#define POS_STARTER_KERNEL_HASH "00000000000000000006382a8d8f94588ce93a1351924f6ccb9e07dd287c6e4b" +#define POS_MODFIFIER_INTERVAL 10 +#define POS_WALLET_MINING_SCAN_INTERVAL POS_SCAN_STEP //seconds +#define POS_MINIMUM_COINSTAKE_AGE 10 // blocks count + + +#define WALLET_FILE_SIGNATURE 0x1111012101101011LL //Bender's nightmare +#define WALLET_FILE_MAX_BODY_SIZE 0x88888888L //2GB +#define WALLET_FILE_MAX_KEYS_SIZE 10000 // + +#define OFFER_MAXIMUM_LIFE_TIME (60*60*24*30) // 30 days + +#define GUI_BLOCKS_DISPLAY_COUNT 40 +#define GUI_DISPATCH_QUE_MAXSIZE 100 + +#define ALLOW_DEBUG_COMMANDS + + + +#define CURRENCY_NAME_ABR "ZAN" +#define CURRENCY_NAME_BASE "Zano" +#define CURRENCY_NAME_SHORT_BASE "Zano" +#ifndef TESTNET +#define CURRENCY_NAME CURRENCY_NAME_BASE +#define CURRENCY_NAME_SHORT CURRENCY_NAME_SHORT_BASE +#else +#define CURRENCY_NAME CURRENCY_NAME_BASE"_testnet" +#define CURRENCY_NAME_SHORT CURRENCY_NAME_SHORT_BASE"_testnet" +#endif + +//premine +#define PREMINE_AMOUNT (500000000000000) + +//alias registration wallet +#define ALIAS_REWARDS_ACCOUNT_SPEND_PUB_KEY "0000000000000000000000000000000000000000000000000000000000000000" //burn alias money +#define ALIAS_REWARDS_ACCOUNT_VIEW_PUB_KEY "0000000000000000000000000000000000000000000000000000000000000000" //burn alias money +#define ALIAS_REWARDS_ACCOUNT_VIEW_SEC_KEY "0000000000000000000000000000000000000000000000000000000000000000" //burn alias money + +#define ALIAS_MINIMUM_PUBLIC_SHORT_NAME_ALLOWED 6 +#define ALIAS_SHORT_NAMES_VALIDATION_PUB_KEY "3b63cb2f3d425053f4120b10bced73d87e98c27b6e4bcfd123a5cfac688c551f" + + +#define ALIAS_NAME_MAX_LEN 255 +#define ALIAS_VALID_CHARS "0123456789abcdefghijklmnopqrstuvwxyz-." +#define ALIAS_COMMENT_MAX_SIZE_BYTES 400 + +#define CURRENCY_CORE_INSTANCE_LOCK_FILE "lock.lck" + + +#define CURRENCY_POOLDATA_FOLDERNAME "poolstate" +#define CURRENCY_BLOCKCHAINDATA_FOLDERNAME "blockchain" +#define P2P_NET_DATA_FILENAME "p2pstate.bin" +#define MINER_CONFIG_FILENAME "miner_conf.json" +#define GUI_SECURE_CONFIG_FILENAME "gui_secure_conf.bin" +#define GUI_CONFIG_FILENAME "gui_settings.json" +#define GUI_INTERNAL_CONFIG "gui_internal_config.bin" + + +#define CURRENT_TRANSACTION_CHAIN_ENTRY_ARCHIVE_VER 3 +#define CURRENT_BLOCK_EXTENDED_INFO_ARCHIVE_VER 1 + +#define BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION CURRENCY_FORMATION_VERSION + 4 +#define BLOCKCHAIN_STORAGE_MINOR_COMPATIBILITY_VERSION 1 + + +#define BC_OFFERS_CURRENT_OFFERS_SERVICE_ARCHIVE_VER CURRENCY_FORMATION_VERSION + BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION + 9 +#define BC_OFFERS_CURRENCY_MARKET_FILENAME "market.bin" + + +#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+62) + +#define CURRENT_MEMPOOL_ARCHIVE_VER (CURRENCY_FORMATION_VERSION+31) + + + + +static_assert(CURRENCY_MINER_TX_MAX_OUTS <= CURRENCY_TX_MAX_ALLOWED_OUTS, "Miner tx must obey normal tx max outs limit"); +static_assert(PREMINE_AMOUNT / WALLET_MAX_ALLOWED_OUTPUT_AMOUNT < CURRENCY_MINER_TX_MAX_OUTS, "Premine can't be divided into reasonable number of outs"); +static_assert(CURRENCY_FIXED_REWARD_ZONE_REWARD_AMOUNT == TX_MINIMUM_FEE * CURRENCY_FIXED_REWARD_ZONE_FEE_MULTIPLIER, "CURRENCY_FIXED_REWARD_ZONE_REWARD_AMOUNT is incorrect with regard to TX_MINIMUM_FEE"); diff --git a/src/currency_core/currency_core.cpp b/src/currency_core/currency_core.cpp new file mode 100644 index 00000000..c4b785f4 --- /dev/null +++ b/src/currency_core/currency_core.cpp @@ -0,0 +1,702 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "include_base_utils.h" +using namespace epee; + +#include +#include +#include "currency_core.h" +#include "common/command_line.h" +#include "common/util.h" +#include "warnings.h" +#include "crypto/crypto.h" +#include "currency_core/currency_config.h" +#include "currency_format_utils.h" +#include "misc_language.h" + +DISABLE_VS_WARNINGS(4355) +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL "core" +ENABLE_CHANNEL_BY_DEFAULT("core"); +namespace currency +{ + + //----------------------------------------------------------------------------------------------- + core::core(i_currency_protocol* pprotocol): + m_mempool(m_blockchain_storage, pprotocol), + m_blockchain_storage(m_mempool), + m_miner(this, m_blockchain_storage), + m_miner_address(boost::value_initialized()), + m_starter_message_showed(false) + { + set_currency_protocol(pprotocol); + } + void core::set_currency_protocol(i_currency_protocol* pprotocol) + { + if(pprotocol) + m_pprotocol = pprotocol; + else + m_pprotocol = &m_protocol_stub; + + m_mempool.set_protocol(m_pprotocol); + } + //----------------------------------------------------------------------------------- + bool core::set_checkpoints(checkpoints&& chk_pts) + { + return m_blockchain_storage.set_checkpoints(std::move(chk_pts)); + } + //----------------------------------------------------------------------------------- + void core::init_options(boost::program_options::options_description& desc) + { + blockchain_storage::init_options(desc); + } + //----------------------------------------------------------------------------------------------- + std::string core::get_config_folder() + { + return m_config_folder; + } + //----------------------------------------------------------------------------------------------- + bool core::handle_command_line(const boost::program_options::variables_map& vm) + { + m_config_folder = command_line::get_arg(vm, command_line::arg_data_dir); + return true; + } + //----------------------------------------------------------------------------------------------- + uint64_t core::get_current_blockchain_size() const + { + return m_blockchain_storage.get_current_blockchain_size(); + } + //----------------------------------------------------------------------------------------------- + uint64_t core::get_top_block_height() const + { + return m_blockchain_storage.get_top_block_height(); + } + //----------------------------------------------------------------------------------------------- + bool core::get_blockchain_top(uint64_t& height, crypto::hash& top_id) const + { + top_id = m_blockchain_storage.get_top_block_id(height); + return true; + } + //----------------------------------------------------------------------------------------------- + bool core::get_blocks(uint64_t start_offset, size_t count, std::list& blocks, std::list& txs) + { + return m_blockchain_storage.get_blocks(start_offset, count, blocks, txs); + } + //----------------------------------------------------------------------------------------------- + bool core::get_blocks(uint64_t start_offset, size_t count, std::list& blocks) + { + return m_blockchain_storage.get_blocks(start_offset, count, blocks); + } //----------------------------------------------------------------------------------------------- + bool core::get_transactions(const std::vector& txs_ids, std::list& txs, std::list& missed_txs) + { + return m_blockchain_storage.get_transactions(txs_ids, txs, missed_txs); + } + //----------------------------------------------------------------------------------------------- + bool core::get_transaction(const crypto::hash &h, transaction &tx) + { + std::vector ids; + ids.push_back(h); + std::list ltx; + std::list missing; + if (m_blockchain_storage.get_transactions(ids, ltx, missing)) + { + if (ltx.size() > 0) + { + tx = *ltx.begin(); + return true; + } + } + + return false; + } + //----------------------------------------------------------------------------------------------- + bool core::get_alternative_blocks(std::list& blocks) + { + return m_blockchain_storage.get_alternative_blocks(blocks); + } + //----------------------------------------------------------------------------------------------- + size_t core::get_alternative_blocks_count() + { + return m_blockchain_storage.get_alternative_blocks_count(); + } + //----------------------------------------------------------------------------------------------- + bool core::init(const boost::program_options::variables_map& vm) + { + bool r = handle_command_line(vm); + + r = m_mempool.init(m_config_folder); + CHECK_AND_ASSERT_MES(r, false, "Failed to initialize memory pool"); + + r = m_blockchain_storage.init(m_config_folder, vm); + CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage"); + + r = m_miner.init(vm); + CHECK_AND_ASSERT_MES(r, false, "Failed to initialize miner"); + + //check if tx_pool module synchronized with blockchaine storage +// if (m_blockchain_storage.get_top_block_id() != m_mempool.get_last_core_hash()) +// { +// m_mempool.clear(); +// LOG_PRINT_MAGENTA("Tx pool had been reset due to missmatch top block id", LOG_LEVEL_0); +// } + + return load_state_data(); + } + //----------------------------------------------------------------------------------------------- + bool core::set_genesis_block(const block& b) + { + return m_blockchain_storage.reset_and_set_genesis_block(b); + } + //----------------------------------------------------------------------------------------------- + bool core::load_state_data() + { + // may be some code later + return true; + } + //----------------------------------------------------------------------------------------------- + bool core::deinit() + { + //m_mempool.set_last_core_hash(m_blockchain_storage.get_top_block_id()); + + m_miner.stop(); + m_miner.deinit(); + m_mempool.deinit(); + m_blockchain_storage.deinit(); + return true; + } + //----------------------------------------------------------------------------------------------- + bool core::handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool kept_by_block) + { + tvc = boost::value_initialized(); + //want to process all transactions sequentially + TIME_MEASURE_START_MS(wait_lock_time); + CRITICAL_REGION_LOCAL(m_incoming_tx_lock); + TIME_MEASURE_FINISH_MS(wait_lock_time); + + if(tx_blob.size() > get_max_tx_size()) + { + LOG_PRINT_L0("WRONG TRANSACTION BLOB, too big size " << tx_blob.size() << ", rejected"); + tvc.m_verification_failed = true; + return false; + } + + crypto::hash tx_hash = null_hash; + transaction tx; + TIME_MEASURE_START_MS(parse_tx_time); + if(!parse_tx_from_blob(tx, tx_hash, tx_blob)) + { + LOG_PRINT_L0("WRONG TRANSACTION BLOB, Failed to parse, rejected"); + tvc.m_verification_failed = true; + return false; + } + TIME_MEASURE_FINISH_MS(parse_tx_time); + + + TIME_MEASURE_START_MS(check_tx_syntax_time); + if(!check_tx_syntax(tx)) + { + LOG_PRINT_L0("WRONG TRANSACTION BLOB, Failed to check tx " << tx_hash << " syntax, rejected"); + tvc.m_verification_failed = true; + return false; + } + TIME_MEASURE_FINISH_MS(check_tx_syntax_time); + + TIME_MEASURE_START_MS(check_tx_semantic_time); + if(!check_tx_semantic(tx, kept_by_block)) + { + LOG_PRINT_L0("WRONG TRANSACTION BLOB, Failed to check tx " << tx_hash << " semantic, rejected"); + tvc.m_verification_failed = true; + return false; + } + TIME_MEASURE_FINISH_MS(check_tx_semantic_time); + + TIME_MEASURE_START_MS(add_new_tx_time); + bool r = add_new_tx(tx, tx_hash, get_object_blobsize(tx), tvc, kept_by_block); + TIME_MEASURE_FINISH_MS(add_new_tx_time); + + if(tvc.m_verification_failed) + {LOG_PRINT_RED_L0("Transaction verification failed: " << tx_hash);} + else if(tvc.m_verification_impossible) + {LOG_PRINT_RED_L0("Transaction verification impossible: " << tx_hash);} + + if (tvc.m_added_to_pool) + { + LOG_PRINT_L2("incoming tx " << tx_hash << " was added to the pool"); + } + LOG_PRINT_L2("[CORE HANDLE_INCOMING_TX]: timing " << wait_lock_time + << "/" << parse_tx_time + << "/" << check_tx_syntax_time + << "/" << check_tx_semantic_time + << "/" << add_new_tx_time); + return r; + } + //----------------------------------------------------------------------------------------------- + bool core::get_stat_info(const core_stat_info::params& pr, core_stat_info& st_inf) + { + st_inf.mining_speed = m_miner.get_speed(); + st_inf.alternative_blocks = m_blockchain_storage.get_alternative_blocks_count(); + st_inf.blockchain_height = m_blockchain_storage.get_current_blockchain_size(); + st_inf.tx_pool_size = m_mempool.get_transactions_count(); + st_inf.top_block_id_str = epee::string_tools::pod_to_hex(m_blockchain_storage.get_top_block_id()); + + std::list blocks; + m_blockchain_storage.get_blocks(m_blockchain_storage.get_current_blockchain_size() - pr.chain_len, static_cast(pr.chain_len), blocks); + for (auto& b : blocks) + { + st_inf.main_chain_blocks.push_back(chain_entry()); + st_inf.main_chain_blocks.back().h = get_block_height(b); + st_inf.main_chain_blocks.back().id = epee::string_tools::pod_to_hex(get_block_hash(b)); + } + blocks.clear(); + m_blockchain_storage.get_alternative_blocks(blocks); + for (auto& b : blocks) + { + st_inf.alt_chain_blocks.push_back(chain_entry()); + st_inf.alt_chain_blocks.back().h = get_block_height(b); + st_inf.alt_chain_blocks.back().id = epee::string_tools::pod_to_hex(get_block_hash(b)); + } + blocks.clear(); + + auto ch_locked_proxy_container = epee::log_space::get_channels_errors_stat_container(); + epee::log_space::channels_err_stat_container_type& ch_container_std = *ch_locked_proxy_container; + for (const auto& entry : ch_container_std) + { + st_inf.errors_stat.push_back(error_stat_entry()); + st_inf.errors_stat.back().channel = entry.first; + st_inf.errors_stat.back().err_count = entry.second; + } + st_inf.epic_failure_happend = m_blockchain_storage.get_performnce_data().epic_failure_happend; + epee::log_space::log_singletone::get_journal_items(st_inf.errors_journal, pr.logs_journal_len); + //check deadlocks + auto dl_list = epee::deadlock_guard_singleton::get_deadlock_journal(); + if (dl_list.size()) + { + st_inf.epic_failure_happend = true; + st_inf.errors_journal.insert(st_inf.errors_journal.end(), dl_list.begin(), dl_list.end()); + } + + return true; + } + + //----------------------------------------------------------------------------------------------- + bool core::check_tx_semantic(const transaction& tx, bool kept_by_block) + { + if(!tx.vin.size()) + { + LOG_PRINT_RED_L0("tx with empty inputs, rejected for tx id= " << get_transaction_hash(tx)); + return false; + } + + if(!check_inputs_types_supported(tx)) + { + LOG_PRINT_RED_L0("unsupported input types for tx id= " << get_transaction_hash(tx)); + return false; + } + + if(!check_outs_valid(tx)) + { + LOG_PRINT_RED_L0("tx with invalid outputs, rejected for tx id= " << get_transaction_hash(tx)); + return false; + } + + if(!check_money_overflow(tx)) + { + LOG_PRINT_RED_L0("tx has money overflow, rejected for tx id= " << get_transaction_hash(tx)); + return false; + } + + uint64_t amount_in = 0; + get_inputs_money_amount(tx, amount_in); + uint64_t amount_out = get_outs_money_amount(tx); + + if(amount_in < amount_out) + { + LOG_PRINT_RED_L0("tx with wrong amounts: ins " << amount_in << ", outs " << amount_out << ", rejected for tx id= " << get_transaction_hash(tx)); + return false; + } + + if(!kept_by_block && get_object_blobsize(tx) >= m_blockchain_storage.get_current_comulative_blocksize_limit() - CURRENCY_COINBASE_BLOB_RESERVED_SIZE) + { + LOG_PRINT_RED_L0("tx has too big size " << get_object_blobsize(tx) << ", expected no bigger than " << m_blockchain_storage.get_current_comulative_blocksize_limit() - CURRENCY_COINBASE_BLOB_RESERVED_SIZE); + return false; + } + + //check if tx use different key images + if(!check_tx_inputs_keyimages_diff(tx)) + { + LOG_PRINT_RED_L0("tx inputs have the same key images"); + return false; + } + + if(!check_tx_extra(tx)) + { + LOG_PRINT_RED_L0("tx has wrong extra, rejected"); + return false; + } + + return true; + } + //----------------------------------------------------------------------------------------------- + bool core::check_tx_extra(const transaction& tx) + { + tx_extra_info ei = AUTO_VAL_INIT(ei); + bool r = parse_and_validate_tx_extra(tx, ei); + if(!r) + return false; + return true; + } + //----------------------------------------------------------------------------------------------- + bool core::check_tx_inputs_keyimages_diff(const transaction& tx) + { + std::unordered_set ki; + BOOST_FOREACH(const auto& in, tx.vin) + { + if (in.type() == typeid(txin_to_key)) + { + CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false); + if (!ki.insert(tokey_in.k_image).second) + return false; + } + } + return true; + } + //----------------------------------------------------------------------------------------------- + bool core::add_new_tx(const transaction& tx, tx_verification_context& tvc, bool kept_by_block) + { + crypto::hash tx_hash = null_hash; + uint64_t blob_size = 0; + get_transaction_hash(tx, tx_hash, blob_size); + return add_new_tx(tx, tx_hash, blob_size, tvc, kept_by_block); + } + //----------------------------------------------------------------------------------------------- + size_t core::get_blockchain_total_transactions() + { + return m_blockchain_storage.get_total_transactions(); + } + //----------------------------------------------------------------------------------------------- + bool core::get_outs(uint64_t amount, std::list& pkeys) + { + return m_blockchain_storage.get_outs(amount, pkeys); + } + //----------------------------------------------------------------------------------------------- + bool core::add_new_tx(const transaction& tx, const crypto::hash& tx_hash, size_t blob_size, tx_verification_context& tvc, bool kept_by_block) + { + if(m_mempool.have_tx(tx_hash)) + { + LOG_PRINT_L3("add_new_tx: already have tx " << tx_hash << " in the pool"); + return true; + } + + if(m_blockchain_storage.have_tx(tx_hash)) + { + LOG_PRINT_L3("add_new_tx: already have tx " << tx_hash << " in the blockchain"); + return true; + } + + return m_mempool.add_tx(tx, tx_hash, blob_size, tvc, kept_by_block); + } + //----------------------------------------------------------------------------------------------- + bool core::get_block_template(block& b, const account_public_address& adr, const account_public_address& stakeholder_address, wide_difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce, bool pos, const pos_entry& pe) + { + return m_blockchain_storage.create_block_template(b, adr, stakeholder_address, diffic, height, ex_nonce, pos, pe); + } + //----------------------------------------------------------------------------------------------- + bool core::find_blockchain_supplement(const std::list& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp) const + { + return m_blockchain_storage.find_blockchain_supplement(qblock_ids, resp); + } + //----------------------------------------------------------------------------------------------- + bool core::find_blockchain_supplement(const std::list& qblock_ids, std::list > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count) const + { + return m_blockchain_storage.find_blockchain_supplement(qblock_ids, blocks, total_height, start_height, max_count); + } + //----------------------------------------------------------------------------------------------- + void core::print_blockchain(uint64_t start_index, uint64_t end_index) + { + m_blockchain_storage.print_blockchain(start_index, end_index); + } + //----------------------------------------------------------------------------------------------- + void core::print_blockchain_index() + { + m_blockchain_storage.print_blockchain_index(); + } + //----------------------------------------------------------------------------------------------- + void core::print_blockchain_outs(const std::string& file) + { + m_blockchain_storage.print_blockchain_outs(file); + } + //----------------------------------------------------------------------------------------------- + bool core::get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res) + { + return m_blockchain_storage.get_random_outs_for_amounts(req, res); + } + //----------------------------------------------------------------------------------------------- + bool core::get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector& indexs) + { + return m_blockchain_storage.get_tx_outputs_gindexs(tx_id, indexs); + } + //----------------------------------------------------------------------------------------------- + void core::pause_mine() + { + m_miner.pause(); + } + //----------------------------------------------------------------------------------------------- + void core::resume_mine() + { + m_miner.resume(); + } + //----------------------------------------------------------------------------------------------- + bool core::handle_block_found(const block& b, block_verification_context* p_verification_result /* = nullptr */) + { + TIME_MEASURE_START_MS(time_total_ms); + block_verification_context bvc = boost::value_initialized(); + if (!p_verification_result) + p_verification_result = &bvc; + + m_miner.pause(); + misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler([this]() + { + m_miner.resume(); + }); + + TIME_MEASURE_START_MS(time_add_new_block_ms); + m_blockchain_storage.add_new_block(b, *p_verification_result); + TIME_MEASURE_FINISH_MS(time_add_new_block_ms); + + + //anyway - update miner template + TIME_MEASURE_START_MS(time_update_block_template_ms); + update_miner_block_template(); + TIME_MEASURE_FINISH_MS(time_update_block_template_ms); + + uint64_t time_pack_txs_ms = 0, time_relay_ms = 0; + + if (p_verification_result->m_verification_failed || !p_verification_result->m_added_to_main_chain) + { + LOG_PRINT2("failed_mined_blocks.log", "verification_failed: " << p_verification_result->m_verification_failed << ", added_to_main_chain: " << p_verification_result->m_added_to_main_chain << ENDL << + currency::obj_to_json_str(b), LOG_LEVEL_0); + } + CHECK_AND_ASSERT_MES(!p_verification_result->m_verification_failed, false, "mined block has failed to pass verification: id " << get_block_hash(b) << " @ height " << get_block_height(b) << " prev_id: " << b.prev_id); + + if(p_verification_result->m_added_to_main_chain) + { + time_pack_txs_ms = epee::misc_utils::get_tick_count(); + currency_connection_context exclude_context = boost::value_initialized(); + NOTIFY_NEW_BLOCK::request arg = AUTO_VAL_INIT(arg); + arg.hop = 0; + arg.current_blockchain_height = m_blockchain_storage.get_current_blockchain_size(); + std::list missed_txs; + std::list txs; + m_blockchain_storage.get_transactions(b.tx_hashes, txs, missed_txs); + if(missed_txs.size() && m_blockchain_storage.get_block_id_by_height(get_block_height(b)) != get_block_hash(b)) + { + LOG_PRINT_L0("Block found (id " << get_block_hash(b) << " @ height " << get_block_height(b) << ") but it seems that reorganize just happened after that, do not relay this block"); + return true; + } + if (txs.size() != b.tx_hashes.size() || missed_txs.size() != 0) + { + std::stringstream ss; + ss << "txs:" << ENDL; + for (auto& t : txs) + ss << get_transaction_hash(t) << ENDL; + ss << "missed txs:" << ENDL; + for (auto& tx_id : missed_txs) + ss << tx_id << ENDL; + LOG_ERROR("can't find some transactions in found block: " << get_block_hash(b) << ", txs.size()=" << txs.size() + << ", b.tx_hashes.size()=" << b.tx_hashes.size() << ", missed_txs.size()=" << missed_txs.size() << ENDL << ss.str()); + return false; + } + + block_to_blob(b, arg.b.block); + //pack transactions + for(auto& tx : txs) + arg.b.txs.push_back(t_serializable_object_to_blob(tx)); + + TIME_MEASURE_FINISH_MS(time_pack_txs_ms); + + time_relay_ms = epee::misc_utils::get_tick_count(); + m_pprotocol->relay_block(arg, exclude_context); + TIME_MEASURE_FINISH_MS(time_relay_ms); + } + + TIME_MEASURE_FINISH_MS(time_total_ms); + LOG_PRINT_L2("handle_block_found timings (ms): total: " << time_total_ms << ", add new block: " << time_add_new_block_ms << ", update template: " << time_update_block_template_ms << ", pack txs: " << time_pack_txs_ms << ", relay: " << time_relay_ms); + + return p_verification_result->m_added_to_main_chain; + } + //----------------------------------------------------------------------------------------------- + void core::on_synchronized() + { + m_miner.on_synchronized(); + } + bool core::get_backward_blocks_sizes(uint64_t from_height, std::vector& sizes, size_t count) + { + return m_blockchain_storage.get_backward_blocks_sizes(from_height, sizes, count); + } + //----------------------------------------------------------------------------------------------- + bool core::add_new_block(const block& b, block_verification_context& bvc) + { + return m_blockchain_storage.add_new_block(b, bvc); + } + //----------------------------------------------------------------------------------------------- + bool core::parse_block(const blobdata& block_blob, block& b, block_verification_context& bvc) + { + if (block_blob.size() > get_max_block_size()) + { + LOG_PRINT_L0("WRONG BLOCK BLOB, too big size " << block_blob.size() << ", rejected"); + bvc.m_verification_failed = true; + return false; + } + + b = AUTO_VAL_INIT_T(block); + if (!parse_and_validate_block_from_blob(block_blob, b)) + { + LOG_PRINT_L0("Failed to parse and validate new block"); + bvc.m_verification_failed = true; + return false; + } + return true; + } + //----------------------------------------------------------------------------------------------- + bool core::pre_validate_block(block& b, block_verification_context& bvc, const crypto::hash& id) + { + return m_blockchain_storage.pre_validate_relayed_block(b, bvc, id); + } + //----------------------------------------------------------------------------------------------- + bool core::handle_incoming_block(const blobdata& block_blob, block_verification_context& bvc, bool update_miner_blocktemplate) + { + bvc = AUTO_VAL_INIT_T(block_verification_context); + block b = AUTO_VAL_INIT(b); + if (!parse_block(block_blob, b, bvc)) + { + LOG_PRINT_L0("Failed to parse and validate new block"); + bvc.m_verification_failed = true; + return false; + } + return handle_incoming_block(b, bvc, update_miner_blocktemplate); + } + //----------------------------------------------------------------------------------------------- + bool core::handle_incoming_block(const block& b, block_verification_context& bvc, bool update_miner_blocktemplate) + { + bool r = add_new_block(b, bvc); + if (update_miner_blocktemplate && bvc.m_added_to_main_chain) + update_miner_block_template(); + return r; + } + //----------------------------------------------------------------------------------------------- + crypto::hash core::get_tail_id() + { + return m_blockchain_storage.get_top_block_id(); + } + //----------------------------------------------------------------------------------------------- + size_t core::get_pool_transactions_count() + { + return m_mempool.get_transactions_count(); + } + //----------------------------------------------------------------------------------------------- + bool core::have_block(const crypto::hash& id) + { + return m_blockchain_storage.have_block(id); + } + //----------------------------------------------------------------------------------------------- + bool core::parse_tx_from_blob(transaction& tx, crypto::hash& tx_hash, const blobdata& blob) + { + return parse_and_validate_tx_from_blob(blob, tx, tx_hash); + } + //----------------------------------------------------------------------------------------------- + bool core::check_tx_syntax(const transaction& tx) + { + return true; + } + //----------------------------------------------------------------------------------------------- + bool core::get_pool_transactions(std::list& txs) + { + return m_mempool.get_transactions(txs); + } + //----------------------------------------------------------------------------------------------- + bool core::get_short_chain_history(std::list& ids) + { + return m_blockchain_storage.get_short_chain_history(ids); + } + //----------------------------------------------------------------------------------------------- + bool core::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp, currency_connection_context& context)const + { + return m_blockchain_storage.handle_get_objects(arg, rsp); + } + //----------------------------------------------------------------------------------------------- + crypto::hash core::get_block_id_by_height(uint64_t height)const + { + return m_blockchain_storage.get_block_id_by_height(height); + } + //----------------------------------------------------------------------------------------------- + bool core::get_block_by_hash(const crypto::hash &h, block &blk) { + return m_blockchain_storage.get_block_by_hash(h, blk); + } + //----------------------------------------------------------------------------------------------- +// void core::get_all_known_block_ids(std::list &main, std::list &alt, std::list &invalid) { +// m_blockchain_storage.get_all_known_block_ids(main, alt, invalid); +// } + //----------------------------------------------------------------------------------------------- + std::string core::print_pool(bool short_format) + { + return m_mempool.print_pool(short_format); + } + //----------------------------------------------------------------------------------------------- + bool core::update_miner_block_template() + { + notify_blockchain_update_listeners(); + m_miner.on_block_chain_update(); + return true; + } + //----------------------------------------------------------------------------------------------- + bool core::on_idle() + { + if(!m_starter_message_showed) + { + LOG_PRINT_L0(ENDL + << "**********************************************************************" << ENDL + << "The daemon will start synchronizing with the network. It may take up to several hours." << ENDL + << ENDL + << "You can adjust verbosity by using command: \"set_log \", where 0 is the least verbose and 3 is the most." << ENDL + << ENDL + << "Use \"help\" command to list all available commands." << ENDL + << ENDL + << "Note: in case you need to interrupt the process, use \"exit\" command. Otherwise, the current progress might not be saved." << ENDL + << "**********************************************************************"); + m_starter_message_showed = true; + } + + m_prune_alt_blocks_interval.do_call([this](){return m_blockchain_storage.prune_aged_alt_blocks();}); + m_miner.on_idle(); + m_mempool.on_idle(); + return true; + } + //----------------------------------------------------------------------------------------------- + void core::add_blockchain_update_listener(i_blockchain_update_listener *l) + { + CRITICAL_REGION_LOCAL(m_blockchain_update_listeners_lock); + m_blockchain_update_listeners.push_back(l); + } + //----------------------------------------------------------------------------------------------- + void core::remove_blockchain_update_listener(i_blockchain_update_listener *l) + { + CRITICAL_REGION_LOCAL(m_blockchain_update_listeners_lock); + m_blockchain_update_listeners.erase(std::remove(m_blockchain_update_listeners.begin(), m_blockchain_update_listeners.end(), l), m_blockchain_update_listeners.end()); + } + //----------------------------------------------------------------------------------------------- + void core::notify_blockchain_update_listeners() + { + CRITICAL_REGION_LOCAL(m_blockchain_update_listeners_lock); + for(auto l : m_blockchain_update_listeners) + l->on_blockchain_update(); + } + //----------------------------------------------------------------------------------------------- + +} +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL NULL \ No newline at end of file diff --git a/src/currency_core/currency_core.h b/src/currency_core/currency_core.h new file mode 100644 index 00000000..294939e5 --- /dev/null +++ b/src/currency_core/currency_core.h @@ -0,0 +1,165 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include + +#include "p2p/net_node_common.h" +#include "currency_protocol/currency_protocol_handler_common.h" +#include "storages/portable_storage_template_helper.h" +#include "tx_pool.h" +#include "blockchain_storage.h" +#ifdef USE_OPENCL +#include "gpu_miner.h" +#else +#include "miner.h" +#endif +#include "connection_context.h" +#include "currency_core/currency_stat_info.h" +#include "warnings.h" +#include "crypto/hash.h" + +PUSH_WARNINGS +DISABLE_VS_WARNINGS(4355) + +namespace currency +{ + struct i_blockchain_update_listener + { + virtual void on_blockchain_update() = 0; + }; + + + /************************************************************************/ + /* */ + /************************************************************************/ + class core: public i_miner_handler + { + public: + core(i_currency_protocol* pprotocol); + bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp, currency_connection_context& context)const ; + bool on_idle(); + bool handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool kept_by_block); + bool handle_incoming_block(const blobdata& block_blob, block_verification_context& bvc, bool update_miner_blocktemplate = true); + bool handle_incoming_block(const block& b, block_verification_context& bvc, bool update_miner_blocktemplate = true); + bool parse_block(const blobdata& block_blob, block& b, block_verification_context& bvc); + bool pre_validate_block(block& b, block_verification_context& bvc, const crypto::hash& id); + i_currency_protocol* get_protocol(){return m_pprotocol;} + tx_memory_pool& get_tx_pool(){ return m_mempool; }; + + //-------------------- i_miner_handler ----------------------- + virtual bool handle_block_found(const block& b, block_verification_context* p_verification_result = nullptr); + virtual bool get_block_template(block& b, const account_public_address& adr, const account_public_address& stakeholder_address, wide_difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce, bool pos = false, const pos_entry& pe = pos_entry()); + +#ifdef USE_OPENCL + gpu_miner& get_miner(){return m_miner;} +#else + miner& get_miner(){ return m_miner; } +#endif + static void init_options(boost::program_options::options_description& desc); + bool init(const boost::program_options::variables_map& vm); + bool set_genesis_block(const block& b); + bool deinit(); + uint64_t get_current_blockchain_size() const; + uint64_t get_top_block_height() const; + std::string get_config_folder(); + bool get_blockchain_top(uint64_t& heeight, crypto::hash& top_id) const; + bool get_blocks(uint64_t start_offset, size_t count, std::list& blocks, std::list& txs); + bool get_blocks(uint64_t start_offset, size_t count, std::list& blocks); + template + bool get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs) + { + return m_blockchain_storage.get_blocks(block_ids, blocks, missed_bs); + } + crypto::hash get_block_id_by_height(uint64_t height)const ; + bool get_transactions(const std::vector& txs_ids, std::list& txs, std::list& missed_txs); + bool get_transaction(const crypto::hash &h, transaction &tx); + bool get_block_by_hash(const crypto::hash &h, block &blk); +// void get_all_known_block_ids(std::list &main, std::list &alt, std::list &invalid); + + bool get_alternative_blocks(std::list& blocks); + size_t get_alternative_blocks_count(); + + void set_currency_protocol(i_currency_protocol* pprotocol); + bool set_checkpoints(checkpoints&& chk_pts); + + bool get_pool_transactions(std::list& txs); + size_t get_pool_transactions_count(); + size_t get_blockchain_total_transactions(); + bool get_outs(uint64_t amount, std::list& pkeys); + bool have_block(const crypto::hash& id); + bool get_short_chain_history(std::list& ids); + bool find_blockchain_supplement(const std::list& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp) const ; + bool find_blockchain_supplement(const std::list& qblock_ids, std::list > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count) const ; + bool get_stat_info(const core_stat_info::params& pr, core_stat_info& st_inf); + bool get_backward_blocks_sizes(uint64_t from_height, std::vector& sizes, size_t count); + bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector& indexs); + crypto::hash get_tail_id(); + bool get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res); + void pause_mine(); + void resume_mine(); + blockchain_storage& get_blockchain_storage() { return m_blockchain_storage; } + const blockchain_storage& get_blockchain_storage() const { return m_blockchain_storage; } + //debug functions + void print_blockchain(uint64_t start_index, uint64_t end_index); + void print_blockchain_index(); + std::string print_pool(bool short_format); + void print_blockchain_outs(const std::string& file); + void on_synchronized(); + + void add_blockchain_update_listener(i_blockchain_update_listener *l); + void remove_blockchain_update_listener(i_blockchain_update_listener *l); + + private: + bool add_new_tx(const transaction& tx, const crypto::hash& tx_hash, size_t blob_size, tx_verification_context& tvc, bool kept_by_block); + bool add_new_tx(const transaction& tx, tx_verification_context& tvc, bool kept_by_block); + bool add_new_block(const block& b, block_verification_context& bvc); + bool load_state_data(); + bool parse_tx_from_blob(transaction& tx, crypto::hash& tx_hash, const blobdata& blob); + bool check_tx_extra(const transaction& tx); + + bool check_tx_syntax(const transaction& tx); + //check correct values, amounts and all lightweight checks not related with database + bool check_tx_semantic(const transaction& tx, bool kept_by_block); + //check if tx already in memory pool or in main blockchain + + bool is_key_image_spent(const crypto::key_image& key_im); + + bool check_tx_ring_signature(const txin_to_key& tx, const crypto::hash& tx_prefix_hash, const std::vector& sig); + bool is_tx_spendtime_unlocked(uint64_t unlock_time); + bool update_miner_block_template(); + bool handle_command_line(const boost::program_options::variables_map& vm); + bool on_update_blocktemplate_interval(); + bool check_tx_inputs_keyimages_diff(const transaction& tx); + + void notify_blockchain_update_listeners(); + + + blockchain_storage m_blockchain_storage; + tx_memory_pool m_mempool; + i_currency_protocol* m_pprotocol; + critical_section m_incoming_tx_lock; +#ifdef USE_OPENCL + gpu_miner m_miner; +#else + miner m_miner; +#endif + account_public_address m_miner_address; + std::string m_config_folder; + currency_protocol_stub m_protocol_stub; + math_helper::once_a_time_seconds<60*60*12, false> m_prune_alt_blocks_interval; + friend class tx_validate_inputs; + std::atomic m_starter_message_showed; + + critical_section m_blockchain_update_listeners_lock; + std::vector m_blockchain_update_listeners; + }; +} + +POP_WARNINGS diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp new file mode 100644 index 00000000..7154b402 --- /dev/null +++ b/src/currency_core/currency_format_utils.cpp @@ -0,0 +1,2879 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "include_base_utils.h" +#include +#include +using namespace epee; + +#include "print_fixed_point_helper.h" +#include "currency_format_utils.h" +#include "serialization/binary_utils.h" +#include "serialization/stl_containers.h" +#include "currency_core/currency_config.h" +#include "miner.h" +#include "crypto/crypto.h" +#include "crypto/hash.h" +#include "common/int-util.h" +#include "common/base58.h" +#include "bc_offers_service_basic.h" +#include "bc_payments_id_service.h" +#include "bc_escrow_service.h" +#include "bc_attachments_helpers.h" +#include "genesis.h" +#include "genesis_acc.h" +namespace currency +{ + //--------------------------------------------------------------- + void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h) + { + std::ostringstream s; + binary_archive a(s); + ::serialization::serialize(a, const_cast(tx)); + std::string data = s.str(); + crypto::cn_fast_hash(data.data(), data.size(), h); + } + //--------------------------------------------------------------- + crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx) + { + crypto::hash h = null_hash; + get_transaction_prefix_hash(tx, h); + return h; + } + //--------------------------------------------------------------- + bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx) + { + std::stringstream ss; + ss << tx_blob; + binary_archive ba(ss); + bool r = ::serialization::serialize(ba, tx); + CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob"); + return true; + } + //--------------------------------------------------------------- + bool add_tx_extra_alias(transaction& tx, const extra_alias_entry& alinfo) + { + tx.extra.push_back(alinfo); + return true; + } + //--------------------------------------------------------------- + bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash) + { + std::stringstream ss; + ss << tx_blob; + binary_archive ba(ss); + bool r = ::serialization::serialize(ba, tx); + CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob"); + //TODO: validate tx + + //crypto::cn_fast_hash(tx_blob.data(), tx_blob.size(), tx_hash); + get_transaction_prefix_hash(tx, tx_hash); + return true; + } + //--------------------------------------------------------------- + /* + bool construct_miner_tx(size_t height, size_t median_size, uint64_t already_generated_coins, + size_t current_block_size, + uint64_t fee, + const account_public_address &miner_address, + transaction& tx, + const blobdata& extra_nonce, + size_t max_outs) + { + + alias_info alias = AUTO_VAL_INIT(alias); + return construct_miner_tx(height, median_size, already_generated_coins, current_block_size, + fee, + miner_address, + tx, + extra_nonce, + max_outs, + alias, + false, + pos_entry()); + }*/ + //--------------------------------------------------------------- + uint64_t get_coinday_weight(uint64_t amount) + { + return amount; + } + //--------------------------------------------------------------- + wide_difficulty_type correct_difficulty_with_sequence_factor(size_t sequence_factor, wide_difficulty_type diff) + { + //delta=delta*(0.75^n) + for (size_t i = 0; i != sequence_factor; i++) + { + diff = diff - diff / 4; + } + return diff; + } + //------------------------------------------------------------------ + bool construct_miner_tx(size_t height, size_t median_size, uint64_t already_generated_coins, + size_t current_block_size, + uint64_t fee, + const account_public_address &miner_address, + const account_public_address &stakeholder_address, + transaction& tx, + const blobdata& extra_nonce, + size_t max_outs, + bool pos, + const pos_entry& pe) + { + uint64_t block_reward; + if (!get_block_reward(pos, median_size, current_block_size, already_generated_coins, block_reward, height)) + { + LOG_ERROR("Block is too big"); + return false; + } + block_reward += fee; + + std::vector out_amounts; + decompose_amount_into_digits(block_reward, DEFAULT_DUST_THRESHOLD, + [&out_amounts](uint64_t a_chunk) { out_amounts.push_back(a_chunk); }, + [&out_amounts](uint64_t a_dust) { out_amounts.push_back(a_dust); }); + + CHECK_AND_ASSERT_MES(1 <= max_outs, false, "max_out must be non-zero"); + while (max_outs < out_amounts.size()) + { + out_amounts[out_amounts.size() - 2] += out_amounts.back(); + out_amounts.resize(out_amounts.size() - 1); + } + + std::vector destinations; + for (auto a : out_amounts) + { + tx_destination_entry de; + de.addr.push_back(miner_address); + de.amount = a; + destinations.push_back(de); + } + + if (pos) + destinations.push_back(tx_destination_entry(pe.amount, stakeholder_address)); + + return construct_miner_tx(height, median_size, already_generated_coins, current_block_size, fee, destinations, tx, extra_nonce, max_outs, pos, pe); + } + //------------------------------------------------------------------ + bool construct_miner_tx(size_t height, size_t median_size, uint64_t already_generated_coins, + size_t current_block_size, + uint64_t fee, + const std::vector& destinations, + transaction& tx, + const blobdata& extra_nonce, + size_t max_outs, + bool pos, + const pos_entry& pe) + { + CHECK_AND_ASSERT_MES(destinations.size() <= CURRENCY_TX_MAX_ALLOWED_OUTS || height == 0, false, "Too many outs (" << destinations.size() << ")! Miner tx can't be constructed."); + + tx.vin.clear(); + tx.vout.clear(); + tx.extra.clear(); + + keypair txkey = keypair::generate(); + add_tx_pub_key_to_extra(tx, txkey.pub); + if (extra_nonce.size()) + if (!add_tx_extra_userdata(tx, extra_nonce)) + return false; + + //we always add extra_padding with 2 bytes length to make possible for get_block_template to adjust cumulative size + tx.extra.push_back(extra_padding()); + + txin_gen in; + in.height = height; + tx.vin.push_back(in); + + if (pos) + { + txin_to_key posin; + posin.amount = pe.amount; + posin.key_offsets.push_back(pe.index); + posin.k_image = pe.keyimage; + tx.vin.push_back(posin); + //reserve place for ring signature + tx.signatures.resize(1); + tx.signatures[0].resize(posin.key_offsets.size()); + } + + uint64_t no = 0; + std::set deriv_cache; + for (auto& d : destinations) + { + bool r = construct_tx_out(d, txkey.sec, no, tx, deriv_cache); + CHECK_AND_ASSERT_MES(r, false, "Failed to contruct miner tx out"); + no++; + } + + + tx.version = CURRENT_TRANSACTION_VERSION; + set_tx_unlock_time(tx, height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + return true; + } + //--------------------------------------------------------------- + bool derive_ephemeral_key_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral) + { + crypto::key_derivation recv_derivation = AUTO_VAL_INIT(recv_derivation); + bool r = crypto::generate_key_derivation(tx_public_key, ack.m_view_secret_key, recv_derivation); + CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to generate_key_derivation(" << tx_public_key << ", " << ack.m_view_secret_key << ")"); + + r = crypto::derive_public_key(recv_derivation, real_output_index, ack.m_account_address.m_spend_public_key, in_ephemeral.pub); + CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to derive_public_key(" << recv_derivation << ", " << real_output_index << ", " << ack.m_account_address.m_spend_public_key << ")"); + + crypto::derive_secret_key(recv_derivation, real_output_index, ack.m_spend_secret_key, in_ephemeral.sec); + return true; + } + //--------------------------------------------------------------- + alias_rpc_details alias_info_to_rpc_alias_info(const currency::extra_alias_entry& ai) + { + alias_rpc_details ari; + alias_info_to_rpc_alias_info(ai, ari); + return ari; + } + //--------------------------------------------------------------- + update_alias_rpc_details alias_info_to_rpc_update_alias_info(const currency::extra_alias_entry& ai, const std::string& old_address) + { + update_alias_rpc_details uard; + alias_info_to_rpc_alias_info(ai, uard); + uard.old_address = old_address; + return uard; + } + //--------------------------------------------------------------- + bool generate_key_image_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki) + { + bool r = derive_ephemeral_key_helper(ack, tx_public_key, real_output_index, in_ephemeral); + CHECK_AND_ASSERT_MES(r, false, "Failed to call derive_ephemeral_key_helper(...)"); + + crypto::generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki); + return true; + } + //--------------------------------------------------------------- + uint64_t power_integral(uint64_t a, uint64_t b) + { + if (b == 0) + return 1; + uint64_t total = a; + for (uint64_t i = 1; i != b; i++) + total *= a; + return total; + } + //--------------------------------------------------------------- + bool is_mixattr_applicable_for_fake_outs_counter(uint8_t mix_attr, uint64_t fake_outputs_count) + { + if (mix_attr >= CURRENCY_TO_KEY_OUT_FORCED_MIX_LOWER_BOUND) + return fake_outputs_count + 1 >= mix_attr; + else if (mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX) + return fake_outputs_count == 0; + else + return true; + } + //--------------------------------------------------------------- + bool parse_amount(uint64_t& amount, const std::string& str_amount_) + { + std::string str_amount = str_amount_; + boost::algorithm::trim(str_amount); + + size_t point_index = str_amount.find_first_of('.'); + size_t fraction_size; + if (std::string::npos != point_index) + { + fraction_size = str_amount.size() - point_index - 1; + while (CURRENCY_DISPLAY_DECIMAL_POINT < fraction_size && '0' == str_amount.back()) + { + str_amount.erase(str_amount.size() - 1, 1); + --fraction_size; + } + if (CURRENCY_DISPLAY_DECIMAL_POINT < fraction_size) + return false; + str_amount.erase(point_index, 1); + } + else + { + fraction_size = 0; + } + + if (str_amount.empty()) + return false; + + if (fraction_size < CURRENCY_DISPLAY_DECIMAL_POINT) + { + str_amount.append(CURRENCY_DISPLAY_DECIMAL_POINT - fraction_size, '0'); + } + + return string_tools::get_xtype_from_string(amount, str_amount); + } + //-------------------------------------------------------------------------------- + std::string print_stake_kernel_info(const stake_kernel& sk) + { + std::stringstream ss; + ss << "block_timestamp: " << sk.block_timestamp << ENDL + << "kimage: " << sk.kimage << ENDL + << "stake_modifier.last_pos_kernel_id: " << sk.stake_modifier.last_pos_kernel_id << ENDL + << "stake_modifier.last_pow_id: " << sk.stake_modifier.last_pow_id << ENDL; + return ss.str(); + } + + //--------------------------------------------------------------- + bool get_tx_fee(const transaction& tx, uint64_t & fee) + { + fee = 0; + if (is_coinbase(tx)) + return true; + uint64_t amount_in = 0; + uint64_t amount_out = get_outs_money_amount(tx); + + BOOST_FOREACH(auto& in, tx.vin) + { + amount_in += get_amount_from_variant(in); + } + + + + CHECK_AND_ASSERT_MES(amount_in >= amount_out, false, "transaction spend (" << amount_in << ") more than it has (" << amount_out << ")"); + fee = amount_in - amount_out; + return true; + } + //--------------------------------------------------------------- + uint64_t get_tx_fee(const transaction& tx) + { + uint64_t r = 0; + if (!get_tx_fee(tx, r)) + return 0; + return r; + } + //--------------------------------------------------------------- + crypto::public_key get_tx_pub_key_from_extra(const transaction& tx) + { + crypto::public_key pk = null_pkey; + get_type_in_variant_container(tx.extra, pk); + return pk; + } + //--------------------------------------------------------------- + bool parse_and_validate_tx_extra(const transaction& tx, crypto::public_key& tx_pub_key) + { + tx_extra_info e = AUTO_VAL_INIT(e); + bool r = parse_and_validate_tx_extra(tx, e); + tx_pub_key = e.m_tx_pub_key; + return r; + } + //--------------------------------------------------------------- + bool sign_extra_alias_entry(extra_alias_entry& ai, const crypto::public_key& pkey, const crypto::secret_key& skey) + { + ai.m_sign.clear(); + get_sign_buff_hash_for_alias_update(ai); + crypto::signature sig = AUTO_VAL_INIT(sig); + crypto::generate_signature(get_sign_buff_hash_for_alias_update(ai), pkey, skey, sig); + ai.m_sign.push_back(sig); + return true; + } + //--------------------------------------------------------------- + crypto::hash get_sign_buff_hash_for_alias_update(const extra_alias_entry& ai) + { + const extra_alias_entry* pale = &ai; + extra_alias_entry eae_local = AUTO_VAL_INIT(eae_local); + if (ai.m_sign.size()) + { + eae_local = ai; + eae_local.m_sign.clear(); + pale = &eae_local; + } + return get_object_hash(*pale); + } + //--------------------------------------------------------------- + struct tx_extra_handler : public boost::static_visitor + { + mutable bool was_padding; //let the padding goes only at the end + mutable bool was_pubkey; + mutable bool was_attachment; + mutable bool was_userdata; + mutable bool was_alias; + + tx_extra_info& rei; + const transaction& rtx; + + tx_extra_handler(tx_extra_info& ei, const transaction& tx) :rei(ei), rtx(tx) + { + was_padding = was_pubkey = was_attachment = was_userdata = was_alias = false; + } + +#define ENSURE_ONETIME(varname, entry_name) CHECK_AND_ASSERT_MES(varname == false, false, "double entry in tx_extra: " entry_name); varname = true; + + + bool operator()(const crypto::public_key& k) const + { + ENSURE_ONETIME(was_pubkey, "public_key"); + rei.m_tx_pub_key = k; + return true; + } + bool operator()(const extra_attachment_info& ai) const + { + ENSURE_ONETIME(was_attachment, "attachment"); + rei.m_attachment_info = ai; + return true; + } + + bool operator()(const extra_alias_entry& ae) const + { + ENSURE_ONETIME(was_alias, "alias"); + rei.m_alias = ae; + return true; + } + bool operator()(const extra_user_data& ud) const + { + ENSURE_ONETIME(was_userdata, "userdata"); + if (!ud.buff.empty()) + rei.m_user_data_blob.assign((const char*)&ud.buff[0], ud.buff.size()); + return true; + } + bool operator()(const extra_padding& k) const + { + ENSURE_ONETIME(was_padding, "padding"); + return true; + } + template + bool operator()(const t_extra_typename& k) const + { + //do notheing for rest + return true; + } + }; + //------------------------------------------------------------------------------------ + bool parse_and_validate_tx_extra(const transaction& tx, tx_extra_info& extra) + { + extra.m_tx_pub_key = null_pkey; + + tx_extra_handler vtr(extra, tx); + + for (const auto& ex_v : tx.extra) + { + if (!boost::apply_visitor(vtr, ex_v)) + return false; + } + return true; + } + //--------------------------------------------------------------- + bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key) + { + tx.extra.push_back(tx_pub_key); + return true; + } + //--------------------------------------------------------------- + //--------------------------------------------------------------- + + struct multisig_id_generator + { + //std::vector vin; + crypto::public_key onetime_key; + std::vector vout; + + BEGIN_SERIALIZE() + //FIELD(vin) + FIELD(onetime_key) + FIELD(vout) + END_SERIALIZE() + }; + crypto::hash get_multisig_out_id(const transaction& tx, size_t n) + { + multisig_id_generator msg = AUTO_VAL_INIT(msg); + //msg.vin = tx.vin; + msg.onetime_key = get_tx_pub_key_from_extra(tx); + CHECK_AND_ASSERT_MES(tx.vout.size() > n, null_hash, "tx.vout.size() > n condition failed "); + CHECK_AND_ASSERT_MES(tx.vout[n].target.type() == typeid(txout_multisig), null_hash, "tx.vout[n].target.type() == typeid(txout_multisig) condition failed"); + msg.vout.push_back(tx.vout[n]); + return get_object_hash(msg); + } + //--------------------------------------------------------------- + bool add_tx_extra_userdata(transaction& tx, const blobdata& extra_nonce) + { + CHECK_AND_ASSERT_MES(extra_nonce.size() <= 255, false, "extra nonce could be 255 bytes max"); + extra_user_data eud = AUTO_VAL_INIT(eud); + eud.buff = extra_nonce; + tx.extra.push_back(eud); + return true; + } + //--------------------------------------------------------------- + bool derive_public_key_from_target_address(const account_public_address& destination_addr, const crypto::secret_key& tx_sec_key, size_t index, crypto::public_key& out_eph_public_key) + { + crypto::key_derivation derivation = AUTO_VAL_INIT(derivation); + return derive_public_key_from_target_address(destination_addr, tx_sec_key, index, out_eph_public_key, derivation); + } + //--------------------------------------------------------------- + bool derive_public_key_from_target_address(const account_public_address& destination_addr, const crypto::secret_key& tx_sec_key, size_t index, crypto::public_key& out_eph_public_key, crypto::key_derivation& derivation) + { + bool r = crypto::generate_key_derivation(destination_addr.m_view_public_key, tx_sec_key, derivation); + CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << destination_addr.m_view_public_key << ", " << tx_sec_key << ")"); + + r = crypto::derive_public_key(derivation, index, destination_addr.m_spend_public_key, out_eph_public_key); + CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to derive_public_key(" << derivation << ", " << index << ", " << destination_addr.m_view_public_key << ")"); + return r; + } + //--------------------------------------------------------------- + uint64_t get_string_uint64_hash(const std::string& str) + { + crypto::hash h = crypto::cn_fast_hash(str.data(), str.size()); + uint64_t* phash_as_array = (uint64_t*)&h; + return phash_as_array[0] ^ phash_as_array[1] ^ phash_as_array[2] ^ phash_as_array[3]; + } + //--------------------------------------------------------------- + uint16_t get_derivation_xor(const crypto::key_derivation& derivation) + { + uint16_t* pderiv_as_array = (uint16_t*)&derivation; + uint16_t res = pderiv_as_array[0]; + for (size_t i = 1; i != sizeof(derivation) / sizeof(uint16_t); i++) + res ^= pderiv_as_array[i]; + return res; + } + //--------------------------------------------------------------- + bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set& deriv_cache, uint8_t tx_outs_attr) + { + CHECK_AND_ASSERT_MES(de.addr.size() == 1 || (de.addr.size() > 1 && de.minimum_sigs <= de.addr.size()), false, "Invalid destination entry: amount: " << de.amount << " minimum_sigs: " << de.minimum_sigs << " addr.size(): " << de.addr.size()); + + std::vector target_keys; + target_keys.reserve(de.addr.size()); + for (auto& apa : de.addr) + { + crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key); + if (apa.m_spend_public_key == null_pkey && apa.m_view_public_key == null_pkey) + { + //burning money(for example alias reward) + out_eph_public_key = null_pkey; + } + else + { + crypto::key_derivation derivation = AUTO_VAL_INIT(derivation); + bool r = derive_public_key_from_target_address(apa, tx_sec_key, output_index, out_eph_public_key, derivation); + CHECK_AND_ASSERT_MES(r, false, "failed to derive_public_key_from_target_address"); + etc_tx_derivation_hint dh = AUTO_VAL_INIT(dh); + dh.v = get_derivation_xor(derivation); + if (deriv_cache.count(dh.v) == 0) + { + tx.extra.push_back(dh); + deriv_cache.insert(dh.v); + } + } + target_keys.push_back(out_eph_public_key); + } + + tx_out out; + out.amount = de.amount; + if (target_keys.size() == 1) + { + //out to key + txout_to_key tk; + tk.key = target_keys.back(); + tk.mix_attr = tx_outs_attr; + out.target = tk; + } + else + { + //multisig out + txout_multisig ms = AUTO_VAL_INIT(ms); + ms.keys = std::move(target_keys); + ms.minimum_sigs = de.minimum_sigs; + out.target = ms; + } + tx.vout.push_back(out); + return true; + } + //--------------------------------------------------------------- + bool have_attachment_service_in_container(const std::vector& av, const std::string& service_id, const std::string& instruction) + { + for (auto& ai : av) + { + if (ai.type() == typeid(tx_service_attachment)) + { + const tx_service_attachment& tsa = boost::get(ai); + if (tsa.service_id == service_id && tsa.instruction == instruction) + return true; + } + } + return false; + } + //--------------------------------------------------------------- + void get_attachment_extra_info_details(const std::vector& attachment, extra_attachment_info& eai) + { + eai = extra_attachment_info(); + if (!attachment.size()) + return; + + //put hash into extra + std::stringstream ss; + binary_archive oar(ss); + ::do_serialize(oar, const_cast&>(attachment)); + std::string buff = ss.str(); + eai.sz = buff.size(); + eai.hsh = get_blob_hash(buff); + eai.cnt = attachment.size(); + } + //--------------------------------------------------------------- + bool construct_tx(const account_keys& sender_account_keys, const std::vector& sources, + const std::vector& destinations, + const std::vector& attachments, + transaction& tx, + uint64_t unlock_time, + uint8_t tx_outs_attr, bool shuffle) + { + crypto::secret_key one_time_secret_key = AUTO_VAL_INIT(one_time_secret_key); + return construct_tx(sender_account_keys, sources, destinations, std::vector(), attachments, tx, one_time_secret_key, unlock_time, tx_outs_attr, shuffle); + } + //--------------------------------------------------------------- + struct encrypt_attach_visitor : public boost::static_visitor + { + bool& m_was_crypted_entries; + const crypto::key_derivation& m_key; + encrypt_attach_visitor(bool& was_crypted_entries, const crypto::key_derivation& key) :m_was_crypted_entries(was_crypted_entries), m_key(key) + {} + void operator()(tx_comment& comment) + { + crypto::chacha_crypt(comment.comment, m_key); + m_was_crypted_entries = true; + } + void operator()(tx_payer& pr) + { + crypto::chacha_crypt(pr.acc_addr, m_key); + m_was_crypted_entries = true; + } + void operator()(tx_receiver& m) + { + crypto::chacha_crypt(m.acc_addr, m_key); + m_was_crypted_entries = true; + } + void operator()(tx_message& m) + { + crypto::chacha_crypt(m.msg, m_key); + m_was_crypted_entries = true; + } + void operator()(tx_service_attachment& sa) + { + if (sa.flags&TX_SERVICE_ATTACHMENT_DEFLATE_BODY) + { + zlib_helper::pack(sa.body); + } + + if (sa.flags&TX_SERVICE_ATTACHMENT_ENCRYPT_BODY) + { + crypto::chacha_crypt(sa.body, m_key); + m_was_crypted_entries = true; + } + } + + template + void operator()(attachment_t& comment) + {} + }; + + struct decrypt_attach_visitor : public boost::static_visitor + { + const crypto::key_derivation& rkey; + std::vector& rdecrypted_att; + decrypt_attach_visitor(const crypto::key_derivation& key, + std::vector& decrypted_att) : + rkey(key), + rdecrypted_att(decrypted_att) + {} + void operator()(const tx_comment& comment) + { + tx_comment local_comment = comment; + crypto::chacha_crypt(local_comment.comment, rkey); + rdecrypted_att.push_back(local_comment); + } + + void operator()(const tx_message& m) + { + tx_message local_msg = m; + crypto::chacha_crypt(local_msg.msg, rkey); + rdecrypted_att.push_back(local_msg); + } + + void operator()(const tx_service_attachment& sa) + { + tx_service_attachment local_sa = sa; + if (sa.flags&TX_SERVICE_ATTACHMENT_ENCRYPT_BODY) + { + crypto::chacha_crypt(local_sa.body, rkey); + } + + if (sa.flags&TX_SERVICE_ATTACHMENT_DEFLATE_BODY) + { + zlib_helper::unpack(local_sa.body); + } + rdecrypted_att.push_back(local_sa); + } + + void operator()(const tx_payer& pr) + { + tx_payer payer_local = pr; + crypto::chacha_crypt(payer_local.acc_addr, rkey); + rdecrypted_att.push_back(payer_local); + } + void operator()(const tx_receiver& pr) + { + tx_receiver receiver_local = pr; + crypto::chacha_crypt(receiver_local.acc_addr, rkey); + rdecrypted_att.push_back(receiver_local); + } + + template + void operator()(const attachment_t& att) + { + rdecrypted_att.push_back(att); + } + }; + + //--------------------------------------------------------------- + template + bool decrypt_payload_items(const crypto::key_derivation& derivation, const items_container_t& items_to_decrypt, std::vector& decrypted_att) + { + decrypt_attach_visitor v(derivation, decrypted_att); + for (auto& a : items_to_decrypt) + boost::apply_visitor(v, a); + + return true; + } + //--------------------------------------------------------------- + bool is_derivation_used_to_encrypt(const transaction& tx, const crypto::key_derivation& derivation) + { + tx_crypto_checksum crypto_info = AUTO_VAL_INIT(crypto_info); + if (!get_type_in_variant_container(tx.extra, crypto_info) && !get_type_in_variant_container(tx.attachment, crypto_info)) + { + //no crypt info in tx + return false; + } + //validate derivation we here. + crypto::hash hash_for_check_sum = crypto::cn_fast_hash(&derivation, sizeof(derivation)); + if (*(uint32_t*)&hash_for_check_sum == crypto_info.derivation_hash) + return true; + + return false; + } + //--------------------------------------------------------------- + crypto::key_derivation get_encryption_key_derivation(bool is_income, const transaction& tx, const account_keys& acc_keys) + { + crypto::key_derivation derivation = null_derivation; + tx_crypto_checksum crypto_info = AUTO_VAL_INIT(crypto_info); + if (!get_type_in_variant_container(tx.extra, crypto_info) && !get_type_in_variant_container(tx.attachment, crypto_info)) + { + //no crypt info in tx + return null_derivation; + } + + if (is_income) + { + crypto::public_key tx_pub_key = currency::get_tx_pub_key_from_extra(tx); + + bool r = crypto::generate_key_derivation(tx_pub_key, acc_keys.m_view_secret_key, derivation); + CHECK_AND_ASSERT_MES(r, null_derivation, "failed to generate_key_derivation"); + LOG_PRINT_GREEN("DECRYPTING ON KEY: " << epee::string_tools::pod_to_hex(derivation) << ", key derived from destination addr: " << currency::get_account_address_as_str(acc_keys.m_account_address), LOG_LEVEL_0); + } + else + { + derivation = crypto_info.encrypted_key_derivation; + crypto::chacha_crypt(derivation, acc_keys.m_spend_secret_key); + LOG_PRINT_GREEN("DECRYPTING ON KEY: " << epee::string_tools::pod_to_hex(derivation) << ", key decrypted from sender address: " << currency::get_account_address_as_str(acc_keys.m_account_address), LOG_LEVEL_0); + } + + //validate derivation we here. Yoda style + crypto::hash hash_for_check_sum = crypto::cn_fast_hash(&derivation, sizeof(derivation)); + CHECK_AND_ASSERT_MES(*(uint32_t*)&hash_for_check_sum == crypto_info.derivation_hash, null_derivation, "Derivation hash missmatched in tx id " << currency::get_transaction_hash(tx)); + return derivation; + } + //--------------------------------------------------------------- + template + struct back_inserter : public boost::static_visitor + { + total_t_container& ttc; + back_inserter(total_t_container& tt) :ttc(tt) + {} + template + void operator()(const attachment_t& att) + { + ttc.push_back(att); + } + }; + + bool decrypt_payload_items(bool is_income, const transaction& tx, const account_keys& acc_keys, std::vector& decrypted_items) + { + PROFILE_FUNC("currency::decrypt_payload_items"); + crypto::key_derivation derivation = get_encryption_key_derivation(is_income, tx, acc_keys); + if (derivation == null_derivation) + { + back_inserter > v(decrypted_items); + for (auto& a : tx.extra) + boost::apply_visitor(v, a); + + for (auto& a : tx.attachment) + boost::apply_visitor(v, a); + + return true; + } + + decrypt_payload_items(derivation, tx.extra, decrypted_items); + decrypt_payload_items(derivation, tx.attachment, decrypted_items); + return true; + } + + //--------------------------------------------------------------- + void encrypt_attachments(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key) + { + crypto::key_derivation derivation = AUTO_VAL_INIT(derivation); + bool r = crypto::generate_key_derivation(destination_addr.m_view_public_key, tx_random_key.sec, derivation); + CHECK_AND_ASSERT_MES(r, void(), "failed to generate_key_derivation"); + bool was_attachment_crypted_entries = false; + bool was_extra_crypted_entries = false; + + encrypt_attach_visitor v(was_attachment_crypted_entries, derivation); + for (auto& a : tx.attachment) + boost::apply_visitor(v, a); + + encrypt_attach_visitor v2(was_extra_crypted_entries, derivation); + for (auto& a : tx.extra) + boost::apply_visitor(v2, a); + + + if (was_attachment_crypted_entries || was_extra_crypted_entries) + { + crypto::hash hash_for_check_sum = crypto::cn_fast_hash(&derivation, sizeof(derivation)); + tx_crypto_checksum chs; + //put derivation hash to be sure that we decrypting right way + chs.derivation_hash = *(uint32_t*)&hash_for_check_sum; + //put encrypted derivation to let sender decrypt all this data from attachment/extra + chs.encrypted_key_derivation = derivation; + crypto::chacha_crypt(chs.encrypted_key_derivation, sender_keys.m_spend_secret_key); + if (was_extra_crypted_entries) + tx.extra.push_back(chs); + else + tx.attachment.push_back(chs); + + LOG_PRINT_GREEN("ENCRYPTING ATTACHMENTS ON KEY: " << epee::string_tools::pod_to_hex(derivation) + << " destination addr: " << currency::get_account_address_as_str(destination_addr) + << " tx_random_key.sec" << tx_random_key.sec + << " tx_random_key.pub" << tx_random_key.pub + << " sender address: " << currency::get_account_address_as_str(sender_keys.m_account_address) + , LOG_LEVEL_0); + + } + } + //--------------------------------------------------------------- + uint64_t get_tx_type(const transaction& tx) + { + if (is_coinbase(tx)) + return GUI_TX_TYPE_COIN_BASE; + + // aliases + tx_extra_info ei = AUTO_VAL_INIT(ei); + parse_and_validate_tx_extra(tx, ei); + if (ei.m_alias.m_alias.size()) + { + if (ei.m_alias.m_sign.size()) + return GUI_TX_TYPE_UPDATE_ALIAS; + else + return GUI_TX_TYPE_NEW_ALIAS; + } + + // offers + tx_service_attachment a = AUTO_VAL_INIT(a); + if (get_type_in_variant_container(tx.attachment, a)) + { + if (a.service_id == BC_OFFERS_SERVICE_ID) + { + if (a.instruction == BC_OFFERS_SERVICE_INSTRUCTION_ADD) + return GUI_TX_TYPE_PUSH_OFFER; + else if (a.instruction == BC_OFFERS_SERVICE_INSTRUCTION_UPD) + return GUI_TX_TYPE_UPDATE_OFFER; + else if (a.instruction == BC_OFFERS_SERVICE_INSTRUCTION_DEL) + return GUI_TX_TYPE_CANCEL_OFFER; + } + } + + // escrow + tx_service_attachment tsa = AUTO_VAL_INIT(tsa); + if (bc_services::get_first_service_attachment_by_id(tx, BC_ESCROW_SERVICE_ID, BC_ESCROW_SERVICE_INSTRUCTION_RELEASE_TEMPLATES, tsa)) + return GUI_TX_TYPE_ESCROW_TRANSFER; + if (bc_services::get_first_service_attachment_by_id(tx, BC_ESCROW_SERVICE_ID, BC_ESCROW_SERVICE_INSTRUCTION_PROPOSAL, tsa)) + return GUI_TX_TYPE_ESCROW_PROPOSAL; + if (bc_services::get_first_service_attachment_by_id(tx, BC_ESCROW_SERVICE_ID, BC_ESCROW_SERVICE_INSTRUCTION_RELEASE_NORMAL, tsa)) + return GUI_TX_TYPE_ESCROW_RELEASE_NORMAL; + if (bc_services::get_first_service_attachment_by_id(tx, BC_ESCROW_SERVICE_ID, BC_ESCROW_SERVICE_INSTRUCTION_RELEASE_BURN, tsa)) + return GUI_TX_TYPE_ESCROW_RELEASE_BURN; + if (bc_services::get_first_service_attachment_by_id(tx, BC_ESCROW_SERVICE_ID, BC_ESCROW_SERVICE_INSTRUCTION_RELEASE_CANCEL, tsa)) + return GUI_TX_TYPE_ESCROW_RELEASE_CANCEL; + if (bc_services::get_first_service_attachment_by_id(tx, BC_ESCROW_SERVICE_ID, BC_ESCROW_SERVICE_INSTRUCTION_CANCEL_PROPOSAL, tsa)) + return GUI_TX_TYPE_ESCROW_CANCEL_PROPOSAL; + + return GUI_TX_TYPE_NORMAL; + } + //--------------------------------------------------------------- + size_t get_multisig_out_index(const std::vector& outs) + { + size_t n = 0; + for (; n != outs.size(); n++) + { + if (outs[n].target.type() == typeid(txout_multisig)) + break; + } + return n; + } + //--------------------------------------------------------------- + size_t get_multisig_in_index(const std::vector& inputs) + { + size_t n = 0; + for (; n != inputs.size(); n++) + { + if (inputs[n].type() == typeid(txin_multisig)) + break; + } + return n; + } + //--------------------------------------------------------------- + account_public_address get_crypt_address_from_destinations(const account_keys& sender_account_keys, const std::vector& destinations) + { + for (const auto& de : destinations) + { + if (de.addr.size() == 1 && sender_account_keys.m_account_address != de.addr.back()) + return de.addr.back(); // return the first destination address that is non-multisig and not equal to the sender's address + } + return sender_account_keys.m_account_address; // otherwise, fallback to sender's address + } + //--------------------------------------------------------------- + bool construct_tx(const account_keys& sender_account_keys, + const std::vector& sources, + const std::vector& destinations, + const std::vector& extra, + const std::vector& attachments, + transaction& tx, + crypto::secret_key& one_time_secret_key, + uint64_t unlock_time, + uint8_t tx_outs_attr, + bool shuffle, + uint64_t flags) + { + // + //find target account to encrypt attachment. + //for now we use just firs target account that is not sender, + //in case if there is no real targets we use sender credentials to encrypt attachments + account_public_address crypt_destination_addr = get_crypt_address_from_destinations(sender_account_keys, destinations); + + return construct_tx(sender_account_keys, sources, destinations, extra, attachments, tx, one_time_secret_key, unlock_time, + crypt_destination_addr, + 0, + tx_outs_attr, + shuffle, + flags); + } + + bool construct_tx(const account_keys& sender_account_keys, const std::vector& sources, + const std::vector& destinations, + const std::vector& extra, + const std::vector& attachments, + transaction& tx, + crypto::secret_key& one_time_secret_key, + uint64_t unlock_time, + const account_public_address& crypt_destination_addr, + uint64_t expiration_time, + uint8_t tx_outs_attr, + bool shuffle, + uint64_t flags) + { + CHECK_AND_ASSERT_MES(destinations.size() <= CURRENCY_TX_MAX_ALLOWED_OUTS, false, "Too many outs (" << destinations.size() << ")! Tx can't be constructed."); + + bool append_mode = false; + if (flags&TX_FLAG_SIGNATURE_MODE_SEPARATE && tx.vin.size()) + append_mode = true; + + keypair txkey = AUTO_VAL_INIT(txkey); + + + if (!append_mode) + { + tx.vin.clear(); + tx.vout.clear(); + tx.signatures.clear(); + tx.extra = extra; + + tx.version = CURRENT_TRANSACTION_VERSION; + if (unlock_time != 0) + set_tx_unlock_time(tx, unlock_time); + + if (flags != 0) + set_tx_flags(tx, flags); + //generate key pair + if (expiration_time != 0) + set_tx_expiration_time(tx, expiration_time); + + txkey = keypair::generate(); + add_tx_pub_key_to_extra(tx, txkey.pub); + one_time_secret_key = txkey.sec; + + //include offers if need + tx.attachment = attachments; + encrypt_attachments(tx, sender_account_keys, crypt_destination_addr, txkey); + } + else + { + txkey.pub = get_tx_pub_key_from_extra(tx); + txkey.sec = one_time_secret_key; + CHECK_AND_ASSERT_MES(txkey.pub != null_pkey && txkey.sec != null_skey, false, "In append mode both public and secret keys must be provided"); + + //separately encrypt attachments without putting extra + crypto::key_derivation derivation = get_encryption_key_derivation(true, tx, sender_account_keys); + CHECK_AND_ASSERT_MES(derivation != null_derivation, false, "failed to generate_key_derivation"); + bool was_attachment_crypted_entries = false; + std::vector extra_local = extra; + std::vector attachments_local = attachments; + + encrypt_attach_visitor v(was_attachment_crypted_entries, derivation); + for (auto& a : attachments_local) + boost::apply_visitor(v, a); + for (auto& a : extra_local) + boost::apply_visitor(v, a); + + + tx.attachment.insert(tx.attachment.end(), attachments_local.begin(), attachments_local.end()); + tx.extra.insert(tx.extra.end(), extra_local.begin(), extra_local.end()); + } + + + + // prepare inputs + struct input_generation_context_data + { + keypair in_ephemeral; + //std::vector participants_derived_keys; + }; + std::vector in_contexts; + + size_t input_starter_index = tx.vin.size(); + uint64_t summary_inputs_money = 0; + //fill inputs + for (const tx_source_entry& src_entr : sources) + { + in_contexts.push_back(input_generation_context_data()); + if (!src_entr.is_multisig()) + { + keypair& in_ephemeral = in_contexts.back().in_ephemeral; + //txin_to_key + if (src_entr.real_output >= src_entr.outputs.size()) + { + LOG_ERROR("real_output index (" << src_entr.real_output << ") greater than or equal to output_keys.size()=" << src_entr.outputs.size()); + return false; + } + summary_inputs_money += src_entr.amount; + + //key_derivation recv_derivation; + crypto::key_image img; + if (!generate_key_image_helper(sender_account_keys, src_entr.real_out_tx_key, src_entr.real_output_in_tx_index, in_ephemeral, img)) + return false; + + //check that derivated key is equal with real output key + if (!(in_ephemeral.pub == src_entr.outputs[src_entr.real_output].second)) + { + LOG_ERROR("derived public key missmatch with output public key! " << ENDL << "derived_key:" + << string_tools::pod_to_hex(in_ephemeral.pub) << ENDL << "real output_public_key:" + << string_tools::pod_to_hex(src_entr.outputs[src_entr.real_output].second)); + return false; + } + + //put key image into tx input + txin_to_key input_to_key; + input_to_key.amount = src_entr.amount; + input_to_key.k_image = img; + + //fill outputs array and use relative offsets + BOOST_FOREACH(const tx_source_entry::output_entry& out_entry, src_entr.outputs) + input_to_key.key_offsets.push_back(out_entry.first); + + input_to_key.key_offsets = absolute_output_offsets_to_relative(input_to_key.key_offsets); + tx.vin.push_back(input_to_key); + } + else + {//multisig input + txin_multisig input_multisig = AUTO_VAL_INIT(input_multisig); + summary_inputs_money += input_multisig.amount = src_entr.amount; + input_multisig.multisig_out_id = src_entr.multisig_id; + input_multisig.sigs_count = src_entr.ms_sigs_count; + tx.vin.push_back(input_multisig); + } + } + + // "Shuffle" outs + std::vector shuffled_dsts(destinations); + if (shuffle) + std::sort(shuffled_dsts.begin(), shuffled_dsts.end(), [](const tx_destination_entry& de1, const tx_destination_entry& de2) { return de1.amount < de2.amount; }); + + uint64_t summary_outs_money = 0; + //fill outputs + size_t output_index = tx.vout.size(); // in case of append mode we need to start output indexing from the last one + 1 + std::set deriv_cache; + BOOST_FOREACH(const tx_destination_entry& dst_entr, shuffled_dsts) + { + CHECK_AND_ASSERT_MES(dst_entr.amount > 0, false, "Destination with wrong amount: " << dst_entr.amount); + bool r = construct_tx_out(dst_entr, txkey.sec, output_index, tx, deriv_cache, tx_outs_attr); + CHECK_AND_ASSERT_MES(r, false, "Failed to construc tx out"); + output_index++; + summary_outs_money += dst_entr.amount; + } + + //check money + if (!(flags&TX_FLAG_SIGNATURE_MODE_SEPARATE)) + { + if (summary_outs_money > summary_inputs_money) + { + LOG_ERROR("Transaction inputs money (" << summary_inputs_money << ") less than outputs money (" << summary_outs_money << ")"); + return false; + } + } + + + + //process offers and put there offers derived keys + uint64_t att_count = 0; + for (auto& o : tx.attachment) + { + if (o.type() == typeid(tx_service_attachment)) + { + tx_service_attachment& tsa = boost::get(o); + if (tsa.security.size()) + { + CHECK_AND_ASSERT_MES(tsa.security.size() == 1, false, "Wrong tsa.security.size() = " << tsa.security.size()); + + bool r = derive_public_key_from_target_address(sender_account_keys.m_account_address, one_time_secret_key, att_count, tsa.security.back()); + CHECK_AND_ASSERT_MES(r, false, "Failed to derive_public_key_from_target_address"); + } + att_count++; + } + } + if (!flags&TX_FLAG_SIGNATURE_MODE_SEPARATE) + { + //take hash from attachment and put into extra + if (tx.attachment.size()) + add_attachments_info_to_extra(tx.extra, tx.attachment); + } + else + { + // for separately signed tx each input has to contain information about corresponding outputs, extra entries and attachments + for (size_t in_index = input_starter_index; in_index != tx.vin.size(); in_index++) + { + // add signed_parts to each input's details (number of outputs and extra entries) + signed_parts so = AUTO_VAL_INIT(so); + so.n_outs = tx.vout.size(); + so.n_extras = tx.extra.size(); + get_txin_etc_options(tx.vin[in_index]).push_back(so); + + // put attachment extra info to each input's details (in case there are attachments) + add_attachments_info_to_extra(get_txin_etc_options(tx.vin[in_index]), tx.attachment); + } + } + + //generate ring signatures + crypto::hash tx_prefix_hash; + get_transaction_prefix_hash(tx, tx_prefix_hash); + + std::stringstream ss_ring_s; + size_t input_index = input_starter_index; + size_t in_context_index = 0; + BOOST_FOREACH(const tx_source_entry& src_entr, sources) + { + crypto::hash tx_hash_for_signature = prepare_prefix_hash_for_sign(tx, input_index, tx_prefix_hash); + CHECK_AND_ASSERT_MES(tx_hash_for_signature != null_hash, false, "failed to prepare_prefix_hash_for_sign"); + + tx.signatures.push_back(std::vector()); + std::vector& sigs = tx.signatures.back(); + + if (!src_entr.is_multisig()) + { + // txin_to_key + ss_ring_s << "input #" << input_index << ", pub_keys:" << ENDL; + std::vector keys_ptrs; + BOOST_FOREACH(const tx_source_entry::output_entry& o, src_entr.outputs) + { + keys_ptrs.push_back(&o.second); + ss_ring_s << o.second << ENDL; + } + sigs.resize(src_entr.outputs.size()); + + crypto::generate_ring_signature(tx_hash_for_signature, boost::get(tx.vin[input_index]).k_image, keys_ptrs, in_contexts[in_context_index].in_ephemeral.sec, src_entr.real_output, sigs.data()); + ss_ring_s << "signatures:" << ENDL; + std::for_each(sigs.begin(), sigs.end(), [&](const crypto::signature& s){ss_ring_s << s << ENDL; }); + ss_ring_s << "prefix_hash:" << tx_prefix_hash << ENDL << "in_ephemeral_key: " << in_contexts[in_context_index].in_ephemeral.sec << ENDL << "real_output: " << src_entr.real_output << ENDL; + } + else + { + // txin_multisig -- don't sign anything here (see also sign_multisig_input_in_tx()) + sigs.resize(src_entr.ms_keys_count, null_sig); // just reserve keys.size() null signatures (NOTE: not minimum_sigs!) + } + if (src_entr.separately_signed_tx_complete) + { + // if separately signed tx is complete, put one more signature to the last bunch using tx secret key, which confirms that transaction has been generated by authorized subject + CHECK_AND_ASSERT_MES(input_index == tx.vin.size() - 1, false, "separately_signed_tx_complete flag is set for source entry #" << input_index << ", allowed only for the last one"); + CHECK_AND_ASSERT_MES(flags & TX_FLAG_SIGNATURE_MODE_SEPARATE, false, "sorce entry separately_signed_tx_complete flag is set for tx with no TX_FLAG_SIGNATURE_MODE_SEPARATE flag"); + CHECK_AND_ASSERT_MES(tx_hash_for_signature == tx_prefix_hash, false, "internal error: hash_for_sign for the last input of separately signed complete tx expected to be the same as tx prefix hash"); + sigs.resize(sigs.size() + 1); + crypto::generate_signature(tx_prefix_hash, txkey.pub, txkey.sec, sigs.back()); + } + + input_index++; + in_context_index++; + } + + LOG_PRINT2("construct_tx.log", "transaction_created: " << get_transaction_hash(tx) << ENDL << obj_to_json_str(tx) << ENDL << ss_ring_s.str(), LOG_LEVEL_3); + + return true; + } + //--------------------------------------------------------------- + uint64_t get_reward_from_miner_tx(const transaction& tx) + { + uint64_t income = 0; + for (auto& in : tx.vin) + { + if (in.type() == typeid(txin_gen)) + { + continue; + } + else if (in.type() == typeid(txin_to_key)) + { + income += boost::get(in).amount; + } + } + uint64_t reward = 0; + for (auto& out : tx.vout) + { + reward += out.amount; + } + reward -= income; + return reward; + } + //--------------------------------------------------------------- + bool sign_multisig_input_in_tx(currency::transaction& tx, size_t ms_input_index, const currency::account_keys& keys, const currency::transaction& source_tx, bool *p_is_input_fully_signed /* = nullptr */) + { +#define LOC_CHK(cond, msg) CHECK_AND_ASSERT_MES(cond, false, msg << ", ms input index: " << ms_input_index << ", tx: " << get_transaction_hash(tx) << ", source tx: " << get_transaction_hash(source_tx)) + if (p_is_input_fully_signed != nullptr) + *p_is_input_fully_signed = false; + + LOC_CHK(ms_input_index < tx.vin.size(), "ms input index is out of bounds, vin.size() = " << tx.vin.size()); + LOC_CHK(tx.vin[ms_input_index].type() == typeid(txin_multisig), "ms input has wrong type, txin_multisig expected"); + const txin_multisig& ms_in = boost::get(tx.vin[ms_input_index]); + + // search ms output in source tx by ms_in.multisig_out_id + size_t ms_out_index = SIZE_MAX; + for (size_t i = 0; i < source_tx.vout.size(); ++i) + { + if (source_tx.vout[i].target.type() == typeid(txout_multisig) && ms_in.multisig_out_id == get_multisig_out_id(source_tx, i)) + { + ms_out_index = i; + break; + } + } + LOC_CHK(ms_out_index != SIZE_MAX, "failed to find ms output in source tx " << get_transaction_hash(source_tx) << " by ms id " << ms_in.multisig_out_id); + const txout_multisig& out_ms = boost::get(source_tx.vout[ms_out_index].target); + + crypto::public_key source_tx_pub_key = get_tx_pub_key_from_extra(source_tx); + + keypair ms_in_ephemeral_key = AUTO_VAL_INIT(ms_in_ephemeral_key); + bool r = currency::derive_ephemeral_key_helper(keys, source_tx_pub_key, ms_out_index, ms_in_ephemeral_key); + LOC_CHK(r, "derive_ephemeral_key_helper failed"); + + size_t participant_index = std::find(out_ms.keys.begin(), out_ms.keys.end(), ms_in_ephemeral_key.pub) - out_ms.keys.begin(); + LOC_CHK(participant_index < out_ms.keys.size(), "Can't find given participant's ms key in ms output keys list"); + LOC_CHK(ms_input_index < tx.signatures.size(), "transaction does not have signatures vectory entry for ms input #" << ms_input_index); + + auto& sigs = tx.signatures[ms_input_index]; + LOC_CHK(!sigs.empty(), "empty signatures container"); + + bool extra_signature_expected = (get_tx_flags(tx) & TX_FLAG_SIGNATURE_MODE_SEPARATE) && ms_input_index == tx.vin.size() - 1; + size_t allocated_sigs_for_participants = extra_signature_expected ? sigs.size() - 1 : sigs.size(); + LOC_CHK(participant_index < allocated_sigs_for_participants, "participant index (" << participant_index << ") is out of bound: " << allocated_sigs_for_participants); // NOTE: this may fail if the input has already been fully signed and 'sigs' was compacted + + crypto::hash tx_hash_for_signature = prepare_prefix_hash_for_sign(tx, ms_input_index, get_transaction_hash(tx)); + LOC_CHK(tx_hash_for_signature != null_hash, "failed to prepare_prefix_hash_for_sign"); + + crypto::generate_signature(tx_hash_for_signature, ms_in_ephemeral_key.pub, ms_in_ephemeral_key.sec, sigs[participant_index]); + + // check whether the input is fully signed + size_t non_null_sigs_count = 0; + for (size_t i = 0; i < allocated_sigs_for_participants; ++i) + { + if (sigs[i] != null_sig) + ++non_null_sigs_count; + } + LOC_CHK(non_null_sigs_count <= out_ms.minimum_sigs, "somehow there are too many non-null signatures for this input: " << non_null_sigs_count << ", minimum_sigs: " << out_ms.minimum_sigs); + if (non_null_sigs_count == out_ms.minimum_sigs) + { + // this input is fully signed, now we gonna compact sigs container by removing null signatures + sigs.erase(std::remove(sigs.begin(), sigs.end(), null_sig), sigs.end()); + + if (p_is_input_fully_signed != nullptr) + *p_is_input_fully_signed = true; + } + + return true; +#undef LOC_CHK + } + //--------------------------------------------------------------- + uint64_t get_inputs_money_amount(const transaction& tx) + { + uint64_t r = 0; + get_inputs_money_amount(tx, r); + return r; + } + //--------------------------------------------------------------- + bool get_inputs_money_amount(const transaction& tx, uint64_t& money) + { + money = 0; + BOOST_FOREACH(const auto& in, tx.vin) + { + uint64_t this_amount = get_amount_from_variant(in); + if (!this_amount) + return false; + money += this_amount; + } + return true; + } + //--------------------------------------------------------------- + uint64_t get_block_height(const transaction& coinbase) + { + CHECK_AND_ASSERT_MES(coinbase.vin.size() == 1 || coinbase.vin.size() == 2, 0, "wrong miner tx in block: -----, b.miner_tx.vin.size() != 1"); + CHECKED_GET_SPECIFIC_VARIANT(coinbase.vin[0], const txin_gen, coinbase_in, 0); + return coinbase_in.height; + } + //--------------------------------------------------------------- + uint64_t get_block_height(const block& b) + { + return get_block_height(b.miner_tx); + } + //--------------------------------------------------------------- + bool check_inputs_types_supported(const transaction& tx) + { + BOOST_FOREACH(const auto& in, tx.vin) + { + CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key) || in.type() == typeid(txin_multisig), false, "wrong variant type: " + << in.type().name() << ", expected " << typeid(txin_to_key).name() + << ", in transaction id=" << get_transaction_hash(tx)); + + } + return true; + } + //------------------------------------------------------------------ + /* + bool add_padding_to_tx(transaction& tx, size_t count) + { + + WARNING: potantially unsafe implementation! + 1) requires extra_padding being previously added to tx's extra; + 2) transaction size may increase by more than 'count' bytes due to varint encoding (thus, if 'count' is 128 it will add 129 bytes) + See also check_add_padding_to_tx test (uncomment and update it, if necessary). + + if (!count) + return true; + + for (auto& ex : tx.extra) + { + if (ex.type() == typeid(extra_padding)) + { + boost::get(ex).buff.insert(boost::get(ex).buff.end(), count, 0); + return true; + } + } + CHECK_AND_ASSERT_THROW_MES(false, "extra_padding entry not found in template mining transaction"); + return false; + } + */ + //------------------------------------------------------------------ + bool remove_padding_from_tx(transaction& tx, size_t count) + { + if (!count) + return true; + + for (auto ex : tx.extra) + { + if (ex.type() == typeid(extra_padding)) + { + std::vector& buff = boost::get(ex).buff; + CHECK_AND_ASSERT_MES(buff.size() >= count, false, "Attempt to remove_padding_from_tx for count = " << count << ", while buff.size()=" << buff.size()); + buff.resize(buff.size() - count); + return true; + } + } + CHECK_AND_ASSERT_THROW_MES(false, "extra_padding entry not found in template mining transaction"); + return false; + } + //------------------------------------------------------------------ + bool is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t current_blockchain_size, uint64_t current_time) + { + if (unlock_time < CURRENCY_MAX_BLOCK_NUMBER) + { + //interpret as block index + return unlock_time <= current_blockchain_size - 1 + CURRENCY_LOCKED_TX_ALLOWED_DELTA_BLOCKS; + } + + //interpret as time + return unlock_time <= current_time + CURRENCY_LOCKED_TX_ALLOWED_DELTA_SECONDS; + } + //----------------------------------------------------------------------------------------------- + bool check_outs_valid(const transaction& tx) + { + BOOST_FOREACH(const tx_out& out, tx.vout) + { + CHECK_AND_NO_ASSERT_MES(0 < out.amount, false, "zero amount ouput in transaction id=" << get_transaction_hash(tx)); + if (out.target.type() == typeid(txout_to_key)) + { + if (!check_key(boost::get(out.target).key)) + return false; + } + else if (out.target.type() == typeid(txout_multisig)) + { + const txout_multisig& ms = boost::get(out.target); + if (!(ms.keys.size() > 0 && ms.minimum_sigs > 0 && ms.minimum_sigs <= ms.keys.size())) + { + LOG_ERROR("wrong multisig in transaction id=" << get_transaction_hash(tx)); + return false; + } + } + else + { + LOG_ERROR("wrong variant type: " << out.target.type().name() << ", expected " << typeid(txout_to_key).name() + << ", in transaction id=" << get_transaction_hash(tx)); + } + } + return true; + } + //----------------------------------------------------------------------------------------------- + bool check_money_overflow(const transaction& tx) + { + return check_inputs_overflow(tx) && check_outs_overflow(tx); + } + //--------------------------------------------------------------- + bool check_inputs_overflow(const transaction& tx) + { + uint64_t money = 0; + BOOST_FOREACH(const auto& in, tx.vin) + { + uint64_t this_amount = 0; + if (in.type() == typeid(txin_to_key)) + { + CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false); + this_amount = tokey_in.amount; + } + else if (in.type() == typeid(txin_multisig)) + { + CHECKED_GET_SPECIFIC_VARIANT(in, const txin_multisig, tokey_in, false); + this_amount = tokey_in.amount; + } + else + { + LOG_ERROR("Unknow type in in: " << in.type().name()); + return false; + } + if (money > this_amount + money) + return false; + money += this_amount; + } + return true; + } + //--------------------------------------------------------------- + bool check_outs_overflow(const transaction& tx) + { + uint64_t money = 0; + BOOST_FOREACH(const auto& o, tx.vout) + { + if (money > o.amount + money) + return false; + money += o.amount; + } + return true; + } + //--------------------------------------------------------------- + uint64_t get_outs_money_amount(const transaction& tx) + { + uint64_t outputs_amount = 0; + for(const auto& o : tx.vout) + outputs_amount += o.amount; + return outputs_amount; + } + //--------------------------------------------------------------- + std::string short_hash_str(const crypto::hash& h) + { + std::string res = string_tools::pod_to_hex(h); + CHECK_AND_ASSERT_MES(res.size() == 64, res, "wrong hash256 with string_tools::pod_to_hex conversion"); + auto erased_pos = res.erase(8, 48); + res.insert(8, "...."); + return res; + } + //--------------------------------------------------------------- + bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::key_derivation& derivation, size_t output_index) + { + crypto::public_key pk; + derive_public_key(derivation, output_index, acc.m_account_address.m_spend_public_key, pk); + return pk == out_key.key; + } + //--------------------------------------------------------------- + bool is_out_to_acc(const account_keys& acc, const txout_multisig& out_multisig, const crypto::key_derivation& derivation, size_t output_index) + { + crypto::public_key pk; + derive_public_key(derivation, output_index, acc.m_account_address.m_spend_public_key, pk); + auto it = std::find(out_multisig.keys.begin(), out_multisig.keys.end(), pk); + if (out_multisig.keys.end() == it) + return false; + return true; + } + //--------------------------------------------------------------- + bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector& outs, uint64_t& money_transfered, crypto::key_derivation& derivation) + { + crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx); + if (null_pkey == tx_pub_key) + return false; + return lookup_acc_outs(acc, tx, get_tx_pub_key_from_extra(tx), outs, money_transfered, derivation); + } + //--------------------------------------------------------------- + bool check_tx_derivation_hint(const transaction& tx, const crypto::key_derivation& derivation) + { + bool found_der_xor = false; + uint16_t my_derive_xor = get_derivation_xor(derivation); + for (auto& e : tx.extra) + { + if (e.type() == typeid(etc_tx_derivation_hint)) + { + found_der_xor = true; + if (my_derive_xor == boost::get(e).v) + return true; + } + } + //if tx doesn't have any hints - feature is not supported, use full scan + if (!found_der_xor) + return true; + + return false; + } + //--------------------------------------------------------------- + bool lookup_acc_outs_genesis(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, uint64_t& money_transfered, crypto::key_derivation& derivation) + { + uint64_t offset = 0; + bool r = get_account_genesis_offset_by_address(get_account_address_as_str(acc.m_account_address), offset); + if (!r) + return true; + + CHECK_AND_ASSERT_MES(offset < tx.vout.size(), false, "condition failed: offset(" << offset << ") < tx.vout.size() (" << tx.vout.size() << ")"); + auto& o = tx.vout[offset]; + CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key), false, "condition failed: o.target.type() == typeid(txout_to_key)"); + if (is_out_to_acc(acc, boost::get(o.target), derivation, offset)) + { + outs.push_back(offset); + money_transfered += o.amount; + } + return true; + } + //--------------------------------------------------------------- + bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, uint64_t& money_transfered, crypto::key_derivation& derivation) + { + money_transfered = 0; + generate_key_derivation(tx_pub_key, acc.m_view_secret_key, derivation); + + if (is_coinbase(tx) && get_block_height(tx) == 0 && tx_pub_key == ggenesis_tx_pub_key) + { + //genesis coinbase + return lookup_acc_outs_genesis(acc, tx, tx_pub_key, outs, money_transfered, derivation); + } + + + if (!check_tx_derivation_hint(tx, derivation)) + return true; + + size_t i = 0; + BOOST_FOREACH(const tx_out& o, tx.vout) + { + if (o.target.type() == typeid(txout_to_key)) + { + if (is_out_to_acc(acc, boost::get(o.target), derivation, i)) + { + outs.push_back(i); + money_transfered += o.amount; + } + } + else if (o.target.type() == typeid(txout_multisig)) + { + if (is_out_to_acc(acc, boost::get(o.target), derivation, i)) + { + outs.push_back(i); + //don't count this money + } + } + else + { + LOG_ERROR("Wrong type at lookup_acc_outs, unexpected type is: " << o.target.type().name()); + return false; + } + i++; + } + return true; + } + //--------------------------------------------------------------- + bool set_payment_id_to_tx(std::vector& att, const std::string& payment_id) + { + if (!is_payment_id_size_ok(payment_id)) + return false; + + tx_service_attachment tsa = AUTO_VAL_INIT(tsa); + tsa.service_id = BC_PAYMENT_ID_SERVICE_ID; + tsa.body = payment_id; + att.push_back(tsa); + return true; + } + //--------------------------------------------------------------- + void get_blob_hash(const blobdata& blob, crypto::hash& res) + { + cn_fast_hash(blob.data(), blob.size(), res); + } + + std::string print_fixed_decimal_point(uint64_t amount, size_t decimal_point) + { + return epee::string_tools::print_fixed_decimal_point(amount, decimal_point); + } + //--------------------------------------------------------------- + std::string print_money(uint64_t amount) + { + return print_fixed_decimal_point(amount, CURRENCY_DISPLAY_DECIMAL_POINT); + } + //--------------------------------------------------------------- + std::string print_money_brief(uint64_t amount) + { + uint64_t remainder = amount % COIN; + amount /= COIN; + if (remainder == 0) + return std::to_string(amount) + ".0"; + std::string r = std::to_string(remainder); + if (r.size() < CURRENCY_DISPLAY_DECIMAL_POINT) + r.insert(0, CURRENCY_DISPLAY_DECIMAL_POINT - r.size(), '0'); + return std::to_string(amount) + '.' + r.substr(0, r.find_last_not_of('0') + 1); + } + //--------------------------------------------------------------- + crypto::hash get_blob_hash(const blobdata& blob) + { + crypto::hash h = null_hash; + get_blob_hash(blob, h); + return h; + } + //--------------------------------------------------------------- + crypto::hash get_transaction_hash(const transaction& t) + { + return get_transaction_prefix_hash(t); + } + //--------------------------------------------------------------- + bool get_transaction_hash(const transaction& t, crypto::hash& res) + { + uint64_t blob_size = 0; + return get_object_hash(static_cast(t), res, blob_size); + } + //--------------------------------------------------------------- + bool get_transaction_hash(const transaction& t, crypto::hash& res, uint64_t& blob_size) + { + blob_size = 0; + bool r = get_object_hash(static_cast(t), res, blob_size); + blob_size = get_object_blobsize(t, blob_size); + return r; + } + //--------------------------------------------------------------- + /*bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t& blob_size) + { + + + return get_object_hash(t, res, blob_size); + }*/ + //------------------------------------------------------------------ + template + crypto::hash hash_together(const pod_operand_a& a, const pod_operand_b& b) + { + std::string blob; + string_tools::apped_pod_to_strbuff(blob, a); + string_tools::apped_pod_to_strbuff(blob, b); + return crypto::cn_fast_hash(blob.data(), blob.size()); + } + //------------------------------------------------------------------ + //-------------------------------------------------------------- + bool unserialize_block_complete_entry(const currency::COMMAND_RPC_GET_BLOCKS_FAST::response& serialized, + currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response& unserialized) + { + for (const auto& bl_entry : serialized.blocks) + { + unserialized.blocks.push_back(block_direct_data_entry()); + block_direct_data_entry& bdde = unserialized.blocks.back(); + auto blextin_ptr = std::make_shared(); + bool r = currency::parse_and_validate_block_from_blob(bl_entry.block, blextin_ptr->bl); + bdde.block_ptr = blextin_ptr; + CHECK_AND_ASSERT_MES(r, false, "failed to parse block from blob: " << string_tools::buff_to_hex_nodelimer(bl_entry.block)); + for (const auto& tx_blob : bl_entry.txs) + { + std::shared_ptr tche_ptr(new currency::transaction_chain_entry()); + r = parse_and_validate_tx_from_blob(tx_blob, tche_ptr->tx); + CHECK_AND_ASSERT_MES(r, false, "failed to parse tx from blob: " << string_tools::buff_to_hex_nodelimer(tx_blob)); + bdde.txs_ptr.push_back(tche_ptr); + } + } + return true; + } + //-------------------------------------------------------------- + crypto::hash get_block_longhash(uint64_t height, const crypto::hash& block_long_ash, uint64_t nonce) + { + //TODO: add wild keccak 2 + return null_hash;//TODO; + } + //--------------------------------------------------------------- + void get_block_longhash(const block& b, crypto::hash& res) + { + //TODO: add wild keccak 2 + } + //--------------------------------------------------------------- + crypto::hash get_block_longhash(const block& b) + { + crypto::hash p = null_hash; + get_block_longhash(b, p); + return p; + } + //--------------------------------------------------------------- + uint64_t get_alias_coast_from_fee(const std::string& alias, uint64_t median_fee) + { + return median_fee * 10; + } + //--------------------------------------------------------------- + uint64_t get_actual_timestamp(const block& b) + { + uint64_t tes_ts = b.timestamp; + if (is_pos_block(b)) + { + etc_tx_time t = AUTO_VAL_INIT(t); + if(get_type_in_variant_container(b.miner_tx.extra, t)) + tes_ts = t.v; + } + return tes_ts; + } + //------------------------------------------------------------------ + bool validate_alias_name(const std::string& al) + { + CHECK_AND_ASSERT_MES(al.size() <= ALIAS_NAME_MAX_LEN, false, "Too long alias name, please use name no longer than " << ALIAS_NAME_MAX_LEN); + /*allowed symbols "0-9", "a-z", "-", "." */ + static bool alphabet[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, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + for (const auto ch : al) + { + CHECK_AND_ASSERT_MES(alphabet[static_cast(ch)], false, "Wrong character in alias: '" << ch << "'"); + } + return true; + } + + + //------------------------------------------------------------------ +#define ANTI_OVERFLOW_AMOUNT 1000000 +#define GET_PERECENTS_BIG_NUMBERS(per, total) (per/ANTI_OVERFLOW_AMOUNT)*100 / (total/ANTI_OVERFLOW_AMOUNT) + + void print_reward_change() + { + std::cout << std::endl << "Reward change for 10 years:" << std::endl; + std::cout << std::setw(10) << std::left << "day" << std::setw(19) << "block reward" << std::setw(19) << "generated coins" << std::endl; + + uint64_t already_generated_coins = PREMINE_AMOUNT; + uint64_t money_was_at_begining_of_year = already_generated_coins; + uint64_t total_generated_in_year_by_pos = 0; + uint64_t total_generated_in_year_by_pow = 0; + //uint64_t total_money_supply = TOTAL_MONEY_SUPPLY; + uint64_t h = 0; + for (uint64_t day = 0; day != 365 * 10; ++day) + { + if (!(day % 366)) + { + uint64_t emission_reward = 0; + get_block_reward(h % 2, 0, 0, already_generated_coins, emission_reward, h); + + std::cout << std::left + << std::setw(10) << day + << std::setw(19) << print_money(emission_reward) + << std::setw(4) << print_money(already_generated_coins) + << "(POS: " << std::to_string(GET_PERECENTS_BIG_NUMBERS(total_generated_in_year_by_pos, money_was_at_begining_of_year)) << "%" + << ", POW: " << std::to_string(GET_PERECENTS_BIG_NUMBERS(total_generated_in_year_by_pow, money_was_at_begining_of_year)) << "%)" + + << std::setw(19) << ",PoS coins/year: " << print_money(total_generated_in_year_by_pos) + << std::setw(19) << ",PoW coins/year:" << print_money(total_generated_in_year_by_pow) + + + << std::endl; + + + total_generated_in_year_by_pos = total_generated_in_year_by_pow = 0; + money_was_at_begining_of_year = already_generated_coins; + + } + + + for (size_t i = 0; i != CURRENCY_BLOCKS_PER_DAY; i++) + { + uint64_t emission_reward = 0; + h++; + get_block_reward(h % 2, 0, 0, already_generated_coins, emission_reward, h); + already_generated_coins += emission_reward; + if (h % 2) + total_generated_in_year_by_pos += emission_reward; + else + total_generated_in_year_by_pow += emission_reward; + + } + } + } + void print_reward_change_short() + { +// std::cout << std::endl << "Reward change for 20 days:" << std::endl; +// std::cout << std::setw(10) << std::left << "day" << std::setw(19) << "block reward" << std::setw(19) << "generated coins" << std::endl; +// +// uint64_t already_generated_coins = PREMINE_AMOUNT; +// //uint64_t total_money_supply = TOTAL_MONEY_SUPPLY; +// uint64_t h = 0; +// for (uint64_t day = 0; day != 20; ++day) +// { +// uint64_t emission_reward = 0; +// get_block_reward(h % 2, 0, 0, already_generated_coins, emission_reward, h, (already_generated_coins - PREMINE_AMOUNT) * 140); +// +// std::cout << std::left +// << std::setw(10) << day +// << std::setw(19) << print_money(emission_reward) +// << std::setw(4) << print_money(already_generated_coins)//std::string(std::to_string(GET_PERECENTS_BIG_NUMBERS((already_generated_coins), total_money_supply)) + "%") +// << std::endl; +// +// +// +// for (size_t i = 0; i != 720; i++) +// { +// h++; +// get_block_reward(h % 2, 0, 0, already_generated_coins, emission_reward, h, (already_generated_coins - PREMINE_AMOUNT) * 140); +// already_generated_coins += emission_reward; +// if (h < POS_START_HEIGHT && i > 360) +// break; +// } +// } + } + + std::string print_reward_change_first_blocks(size_t n_of_first_blocks) + { + std::stringstream ss; + ss << std::endl << "Reward change for the first " << n_of_first_blocks << " blocks:" << std::endl; + ss << std::setw(10) << std::left << "block #" << std::setw(20) << "block reward" << std::setw(20) << "generated coins" << std::setw(8) << "type" << std::endl; + + uint64_t already_generated_coins = 0; + uint64_t total_generated_pos = 0; + uint64_t total_generated_pow = 0; + + for (size_t h = 0; h != n_of_first_blocks; ++h) + { + bool is_pos = h < 10 ? false : h % 2 == 0; + uint64_t emission_reward = 0; + + if (h == 0) + { + emission_reward = PREMINE_AMOUNT; + } + else + { + currency::get_block_reward(is_pos, 0, 0, already_generated_coins, emission_reward, h); + (is_pos ? total_generated_pos : total_generated_pow) += emission_reward; + } + + already_generated_coins += emission_reward; + + ss << std::left + << std::setw(10) << h + << std::setw(20) << currency::print_money(emission_reward) + << std::setw(20) << currency::print_money(already_generated_coins) + << std::setw(8) << (h == 0 ? "genesis" : (is_pos ? "PoS" : "PoW")) + << std::endl; + } + ss << "total generated PoW: " << currency::print_money(total_generated_pow) << std::endl; + ss << "total generated PoS: " << currency::print_money(total_generated_pos) << std::endl; + return ss.str(); + } + //------------------------------------------------------------------ + void print_currency_details() + { + //for future forks + + std::cout << "Currency name: \t\t" << CURRENCY_NAME << "(" << CURRENCY_NAME_SHORT << ")" << std::endl; + std::cout << "Money supply: \t\t" << print_money(TOTAL_MONEY_SUPPLY) << " coins" + << "(" << print_money(TOTAL_MONEY_SUPPLY) << "), dev bounties is ???" << std::endl; + + std::cout << "PoS block interval: \t" << DIFFICULTY_POS_TARGET << " seconds" << std::endl; + std::cout << "PoW block interval: \t" << DIFFICULTY_POW_TARGET << " seconds" << std::endl; + std::cout << "Total blocks per day: \t" << CURRENCY_BLOCKS_PER_DAY << " seconds" << std::endl; + std::cout << "Default p2p port: \t" << P2P_DEFAULT_PORT << std::endl; + std::cout << "Default rpc port: \t" << RPC_DEFAULT_PORT << std::endl; +#ifndef TEST_FAST_EMISSION_CURVE + print_reward_change(); +#else + print_reward_change_short(); +#endif + } + //------------------------------------------------------------------ + std::string dump_patch(const std::map& patch) + { + std::stringstream ss; + for (auto& p : patch) + { + ss << "[" << p.first << "]" << p.second << ENDL; + } + return ss.str(); + } + //--------------------------------------------------------------- + blobdata get_block_hashing_blob(const block& b) + { + blobdata blob = t_serializable_object_to_blob(static_cast(b)); + crypto::hash tree_root_hash = get_tx_tree_hash(b); + blob.append((const char*)&tree_root_hash, sizeof(tree_root_hash)); + blob.append(tools::get_varint_data(b.tx_hashes.size() + 1)); + return blob; + } + //--------------------------------------------------------------- + bool get_block_hash(const block& b, crypto::hash& res) + { + return get_object_hash(get_block_hashing_blob(b), res); + } + //--------------------------------------------------------------- + crypto::hash get_block_hash(const block& b) + { + crypto::hash p = null_hash; + get_block_hash(b, p); + return p; + } + //--------------------------------------------------------------- + bool generate_genesis_block(block& bl) + { + //genesis block + bl = boost::value_initialized(); + +#ifndef TESTNET +// std::string genesis_coinbase_tx_hex((const char*)&ggenesis_tx_raw, sizeof(ggenesis_tx_raw)); + +#else + std::string genesis_coinbase_tx_hex = ""; +#endif + + blobdata tx_bl((const char*)&ggenesis_tx_raw, sizeof(ggenesis_tx_raw)); + //string_tools::parse_hexstr_to_binbuff(genesis_coinbase_tx_hex, tx_bl); + bool r = parse_and_validate_tx_from_blob(tx_bl, bl.miner_tx); + CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob"); + bl.major_version = CURRENT_BLOCK_MAJOR_VERSION; + bl.minor_version = CURRENT_BLOCK_MINOR_VERSION; + bl.timestamp = 0; + bl.nonce = 101010121 + CURRENCY_FORMATION_VERSION; //bender's nightmare + //miner::find_nonce_for_given_block(bl, 1, 0,); + LOG_PRINT_GREEN("Generated genesis: " << get_block_hash(bl), LOG_LEVEL_0); + return true; + } + //--------------------------------------------------------------- + //---------------------------------------------------------------------------------------------------- + const crypto::hash& get_genesis_hash(bool need_to_set, const crypto::hash& h) + { + static crypto::hash genesis_id = null_hash; + if (genesis_id == null_hash && !need_to_set) + { + LOG_PRINT_GREEN("Calculating genesis....", LOG_LEVEL_0); + block b = AUTO_VAL_INIT(b); + bool r = generate_genesis_block(b); + CHECK_AND_ASSERT_MES(r, null_hash, "failed to generate genesis block"); + genesis_id = get_block_hash(b); + } + + if (need_to_set) + { + genesis_id = h; + } + return genesis_id; + } + //--------------------------------------------------------------- + std::vector relative_output_offsets_to_absolute(const std::vector& off) + { + //if array has both types of outs, then global index (uint64_t) should be first, and then the rest could be out_by_id + + std::vector res = off; + for (size_t i = 1; i < res.size(); i++) + { + if (res[i].type() == typeid(ref_by_id)) + break; + boost::get(res[i]) += boost::get(res[i - 1]); + } + + return res; + } + //--------------------------------------------------------------- + std::vector absolute_output_offsets_to_relative(const std::vector& off) + { + std::vector res = off; + if (off.size() < 2) + return res; + + std::sort(res.begin(), res.end(), [](const txout_v& lft, const txout_v& rght) + { + if (lft.type() == typeid(uint64_t)) + { + if (rght.type() == typeid(uint64_t)) + return boost::get(lft) < boost::get(rght); + else if (rght.type() == typeid(ref_by_id)) + return true; + else + LOG_ERROR("Unknown type in txout_v"); + } + else if (lft.type() == typeid(ref_by_id)) + { + if (rght.type() == typeid(uint64_t)) + return false; + else if (rght.type() == typeid(ref_by_id)) + return false; // don't change the order of ref_by_id elements + else + LOG_ERROR("Unknown type in txout_v"); + } + return false; + });//just to be sure, actually it is already should be sorted + + //find starter index - skip ref_by_id entries + size_t i = res.size() - 1; + while (i != 0 && res[i].type() == typeid(ref_by_id)) + --i; + + for (; i != 0; i--) + { + boost::get(res[i]) -= boost::get(res[i - 1]); + } + + + return res; + } + //--------------------------------------------------------------- + bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b) + { + return t_unserializable_object_from_blob(b, b_blob); + } + //--------------------------------------------------------------- + size_t get_object_blobsize(const transaction& t) + { + size_t tx_blob_size = get_object_blobsize(static_cast(t)); + return get_object_blobsize(t, tx_blob_size); + } + //--------------------------------------------------------------- + size_t get_object_blobsize(const transaction& t, uint64_t prefix_blob_size) + { + size_t tx_blob_size = prefix_blob_size; + + if (is_coinbase(t)) + return tx_blob_size; + + // for purged tx, with empty signatures and attachments, this function should return the blob size + // which the tx would have if the signatures and attachments were correctly filled with actual data + + // 1. signatures + bool separately_signed_tx = get_tx_flags(t) & TX_FLAG_SIGNATURE_MODE_SEPARATE; + + tx_blob_size += tools::get_varint_packed_size(t.vin.size()); // size of transaction::signatures (equals to total inputs count) + + for (size_t i = 0; i != t.vin.size(); i++) + { + size_t sig_count = get_input_expected_signatures_count(t.vin[i]); + if (separately_signed_tx && i == t.vin.size() - 1) + ++sig_count; // count in one more signature for the last input in a complete separately signed tx + tx_blob_size += tools::get_varint_packed_size(sig_count); // size of transaction::signatures[i] + tx_blob_size += sizeof(crypto::signature) * sig_count; // size of signatures' data itself + } + + // 2. attachments (try to find extra_attachment_info in tx prefix and count it in if succeed) + extra_attachment_info eai = AUTO_VAL_INIT(eai); + bool got_eai = false; + if (separately_signed_tx) + { + // for separately-signed tx, try to obtain extra_attachment_info from the last input's etc_details + const std::vector* p_etc_details = get_input_etc_details(t.vin.back()); + got_eai = p_etc_details != nullptr && get_type_in_variant_container(*p_etc_details, eai); + } + if (!got_eai) + got_eai = get_type_in_variant_container(t.extra, eai); // then from the extra + + if (got_eai) + tx_blob_size += eai.sz; // sz is a size of whole serialized attachment blob, including attachments vector size + else + tx_blob_size += tools::get_varint_packed_size(static_cast(0)); // no extra_attachment_info found - just add zero vector's size, 'cause it's serialized anyway + + return tx_blob_size; + } + //--------------------------------------------------------------- + blobdata block_to_blob(const block& b) + { + return t_serializable_object_to_blob(b); + } + //--------------------------------------------------------------- + bool block_to_blob(const block& b, blobdata& b_blob) + { + return t_serializable_object_to_blob(b, b_blob); + } + //--------------------------------------------------------------- + blobdata tx_to_blob(const transaction& tx) + { + return t_serializable_object_to_blob(tx); + } + //--------------------------------------------------------------- + bool tx_to_blob(const transaction& tx, blobdata& b_blob) + { + return t_serializable_object_to_blob(tx, b_blob); + } + //--------------------------------------------------------------- + void get_tx_tree_hash(const std::vector& tx_hashes, crypto::hash& h) + { + tree_hash(tx_hashes.data(), tx_hashes.size(), h); + } + //--------------------------------------------------------------- + crypto::hash get_tx_tree_hash(const std::vector& tx_hashes) + { + crypto::hash h = null_hash; + get_tx_tree_hash(tx_hashes, h); + return h; + } + //--------------------------------------------------------------- + crypto::hash get_tx_tree_hash(const block& b) + { + std::vector txs_ids; + crypto::hash h = null_hash; + get_transaction_hash(b.miner_tx, h); + txs_ids.push_back(h); + BOOST_FOREACH(auto& th, b.tx_hashes) + txs_ids.push_back(th); + return get_tx_tree_hash(txs_ids); + } + //--------------------------------------------------------------- + bool is_service_tx(const transaction& tx) + { + auto tx_type = get_tx_type(tx); + if (GUI_TX_TYPE_NORMAL == tx_type || + GUI_TX_TYPE_COIN_BASE == tx_type) + return false; + + return true; + } + //--------------------------------------------------------------- + bool is_showing_sender_addres(const transaction& tx) + { + return have_type_in_variant_container(tx.attachment); + } + //--------------------------------------------------------------- + bool is_mixin_tx(const transaction& tx) + { + for (const auto& e : tx.vin) + { + if (e.type() != typeid(txin_to_key)) + return false; + if (boost::get(e).key_offsets.size() < 2) + return false; + } + + return true; + } + //--------------------------------------------------------------- + uint64_t get_amount_for_zero_pubkeys(const transaction& tx) + { + uint64_t found_alias_reward = 0; + for (const auto& out : tx.vout) + { + if (out.target.type() != typeid(txout_to_key)) + continue; + + const txout_to_key& o = boost::get(out.target); + if (o.key == null_pkey) + found_alias_reward += out.amount; + } + return found_alias_reward; + } + + //--------------------------------------------------------------- + bool get_aliases_reward_account(account_public_address& acc) + { + bool r = string_tools::parse_tpod_from_hex_string(ALIAS_REWARDS_ACCOUNT_SPEND_PUB_KEY, acc.m_spend_public_key); + r &= string_tools::parse_tpod_from_hex_string(ALIAS_REWARDS_ACCOUNT_VIEW_PUB_KEY, acc.m_view_public_key); + return r; + } + //------------------------------------------------------------------ + size_t get_service_attachments_count_in_tx(const transaction& tx) + { + size_t cnt = 0; + for (const auto& at : tx.attachment) + { + if (at.type() == typeid(tx_service_attachment)) + ++cnt; + } + return cnt; + } + + struct rpc_tx_payload_handler : public boost::static_visitor + { + tx_extra_rpc_entry& tv; + rpc_tx_payload_handler(tx_extra_rpc_entry& t) : tv(t) + {} + + bool operator()(const tx_service_attachment& ee) + { + tv.type = "service"; + tv.short_view = ee.service_id + ":" + ee.instruction; + if (ee.flags&TX_SERVICE_ATTACHMENT_ENCRYPT_BODY) + tv.short_view += "(encrypted)"; + else + { + std::string deflated_buff; + const std::string* pfinalbuff = &ee.body; + if (ee.flags&TX_SERVICE_ATTACHMENT_DEFLATE_BODY) + { + bool r = epee::zlib_helper::unpack(ee.body, deflated_buff); + CHECK_AND_ASSERT_MES(r, false, "Failed to unpack"); + pfinalbuff = &deflated_buff; + } + if (ee.service_id == BC_PAYMENT_ID_SERVICE_ID || ee.service_id == BC_OFFERS_SERVICE_ID) + tv.datails_view = *pfinalbuff; + else + tv.datails_view = "BINARY DATA"; + } + return true; + } + bool operator()(const tx_crypto_checksum& ee) + { + tv.type = "crypto_checksum"; + tv.short_view = std::string("derivation_hash: ") + epee::string_tools::pod_to_hex(ee.derivation_hash); + tv.datails_view = std::string("derivation_hash: ") + epee::string_tools::pod_to_hex(ee.derivation_hash) + "\n" + + "encrypted_key_derivation: " + epee::string_tools::pod_to_hex(ee.encrypted_key_derivation); + + return true; + } + bool operator()(const etc_tx_time& ee) + { + tv.type = "pos_time"; + tv.short_view = std::string("timestamp: ") + std::to_string(ee.v) + " " + epee::misc_utils::get_internet_time_str(ee.v); + return true; + } + bool operator()(const etc_tx_details_unlock_time& ee) + { + tv.type = "unlock_time"; + if (ee.v < CURRENCY_MAX_BLOCK_NUMBER) + tv.short_view = std::string("height: ") + std::to_string(ee.v); + else + tv.short_view = std::string("timestamp: ") + std::to_string(ee.v) + " " + epee::misc_utils::get_internet_time_str(ee.v); + + return true; + } + bool operator()(const etc_tx_details_expiration_time& ee) + { + tv.type = "expiration_time"; + if (ee.v < CURRENCY_MAX_BLOCK_NUMBER) + tv.short_view = std::string("height: ") + std::to_string(ee.v); + else + tv.short_view = std::string("timestamp: ") + std::to_string(ee.v) + " " + epee::misc_utils::get_internet_time_str(ee.v); + + return true; + } + bool operator()(const etc_tx_details_flags& ee) + { + tv.type = "details_flags"; + tv.short_view = epee::string_tools::pod_to_hex(ee.v); + return true; + } + bool operator()(const crypto::public_key& ee) + { + tv.type = "pub_key"; + tv.short_view = epee::string_tools::pod_to_hex(ee); + return true; + } + bool operator()(const extra_attachment_info& ee) + { + tv.type = "attachment_info"; + tv.short_view = std::to_string(ee.sz) + " bytes"; + tv.datails_view = currency::obj_to_json_str(ee); + return true; + } + bool operator()(const extra_alias_entry& ee) + { + tv.type = "alias_info"; + tv.short_view = ee.m_alias + "-->" + get_account_address_as_str(ee.m_address); + tv.datails_view = currency::obj_to_json_str(ee); + + return true; + } + bool operator()(const extra_user_data& ee) + { + tv.type = "user_data"; + tv.short_view = std::to_string(ee.buff.size()) + " bytes"; + tv.datails_view = epee::string_tools::buff_to_hex_nodelimer(ee.buff); + + return true; + } + bool operator()(const extra_padding& ee) + { + tv.type = "extra_padding"; + tv.short_view = std::to_string(ee.buff.size()) + " bytes"; + if (!ee.buff.empty()) + tv.datails_view = epee::string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast(&ee.buff[0]), ee.buff.size())); + + return true; + } + bool operator()(const tx_comment& ee) + { + tv.type = "comment"; + tv.short_view = std::to_string(ee.comment.size()) + " bytes(encrypted)"; + tv.datails_view = epee::string_tools::buff_to_hex_nodelimer(ee.comment); + + return true; + } + bool operator()(const tx_payer& ee) + { + //const tx_payer& ee = boost::get(extra); + tv.type = "payer"; + tv.short_view = "(encrypted)"; + + return true; + } + + bool operator()(const tx_receiver& ee) + { + //const tx_payer& ee = boost::get(extra); + tv.type = "receiver"; + tv.short_view = "(encrypted)"; + + return true; + } + bool operator()(const tx_message& ee) + { + tv.type = "message"; + tv.short_view = std::to_string(ee.msg.size()) + " bytes"; + tv.datails_view = epee::string_tools::buff_to_hex_nodelimer(ee.msg); + + return true; + } + bool operator()(const std::string& ee) + { + tv.type = "string"; + tv.short_view = std::to_string(ee.size()) + " bytes"; + tv.datails_view = epee::string_tools::buff_to_hex_nodelimer(ee); + + return true; + } + bool operator()(const etc_tx_derivation_hint& dh) + { + tv.type = "XOR"; + tv.short_view = epee::string_tools::pod_to_hex(dh); + tv.datails_view = epee::string_tools::pod_to_hex(dh); + + return true; + } + + }; + + + //------------------------------------------------------------------ + template + bool fill_tx_rpc_payload_items(std::vector& target_vector, const t_container& tc) + { + //handle extra + for (auto& extra : tc) + { + target_vector.push_back(tx_extra_rpc_entry()); + tx_extra_rpc_entry& tv = target_vector.back(); + + rpc_tx_payload_handler vstr(tv); + boost::apply_visitor(vstr, extra); + } + return true; + } + //------------------------------------------------------------------ + bool fill_tx_rpc_outputs(tx_rpc_extended_info& tei, const transaction& tx, const transaction_chain_entry* ptce) + { + size_t i = 0; + for (auto& out : tx.vout) + { + tei.outs.push_back(tx_out_rpc_entry()); + tei.outs.back().amount = out.amount; + tei.outs.back().is_spent = ptce ? ptce->m_spent_flags[i] : false; + tei.outs.back().global_index = ptce ? ptce->m_global_output_indexes[i] : 0; + + if (out.target.type() == typeid(txout_to_key)) + { + const txout_to_key& otk = boost::get(out.target); + tei.outs.back().pub_keys.push_back(epee::string_tools::pod_to_hex(otk.key)); + if (otk.mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX) + tei.outs.back().pub_keys.back() += "(FORCED_NO_MIX)"; + if (otk.mix_attr >= CURRENCY_TO_KEY_OUT_FORCED_MIX_LOWER_BOUND) + tei.outs.back().pub_keys.back() += std::string("(FORCED_MIX_LOWER_BOUND: ") + std::to_string(otk.mix_attr) + ")"; + } + else if (out.target.type() == typeid(txout_multisig)) + { + const txout_multisig& otm = boost::get(out.target); + for (auto& k : otm.keys) + { + tei.outs.back().pub_keys.push_back(epee::string_tools::pod_to_hex(k)); + } + tei.outs.back().minimum_sigs = otm.minimum_sigs; + } + + ++i; + } + return true; + } + //------------------------------------------------------------------ + bool fill_tx_rpc_inputs(tx_rpc_extended_info& tei, const transaction& tx) + { + //handle inputs + for (auto in : tx.vin) + { + tei.ins.push_back(tx_in_rpc_entry()); + if (in.type() == typeid(txin_gen)) + { + tei.ins.back().amount = 0; + } + else if (in.type() == typeid(txin_to_key)) + { + txin_to_key& tk = boost::get(in); + tei.ins.back().amount = tk.amount; + tei.ins.back().kimage_or_ms_id = epee::string_tools::pod_to_hex(tk.k_image); + std::vector absolute_offsets = relative_output_offsets_to_absolute(tk.key_offsets); + for (auto& ao : absolute_offsets) + { + tei.ins.back().global_indexes.push_back(0); + if (ao.type() == typeid(uint64_t)) + { + tei.ins.back().global_indexes.back() = boost::get(ao); + } + else// if (ao.type() == typeid(ref_by_id)) + { + //disable for the reset at the moment + tei.ins.back().global_indexes.back() = std::numeric_limits::max(); + } + } + //tk.etc_details -> visualize it may be later + } + else if (in.type() == typeid(txin_multisig)) + { + txin_multisig& tms = boost::get(in); + tei.ins.back().amount = tms.amount; + tei.ins.back().kimage_or_ms_id = epee::string_tools::pod_to_hex(tms.multisig_out_id); + if (tx.signatures.size() >= tei.ins.size()) + tei.ins.back().multisig_count = tx.signatures[tei.ins.size() - 1].size(); + } + } + return true; + } + bool fill_block_rpc_details(block_rpc_extended_info& pei_rpc, const block_extended_info& bei_chain, const crypto::hash& h) + { + pei_rpc.difficulty = bei_chain.difficulty.convert_to(); + pei_rpc.cumulative_diff_adjusted = bei_chain.cumulative_diff_adjusted.convert_to(); + pei_rpc.cumulative_diff_precise = bei_chain.cumulative_diff_precise.convert_to(); + pei_rpc.block_cumulative_size = bei_chain.block_cumulative_size; + pei_rpc.timestamp = bei_chain.bl.timestamp; + pei_rpc.id = epee::string_tools::pod_to_hex(h); + pei_rpc.prev_id = epee::string_tools::pod_to_hex(bei_chain.bl.prev_id); + pei_rpc.actual_timestamp = get_actual_timestamp(bei_chain.bl); + pei_rpc.type = is_pos_block(bei_chain.bl) ? 0 : 1; + pei_rpc.already_generated_coins = bei_chain.already_generated_coins; + pei_rpc.this_block_fee_median = bei_chain.this_block_tx_fee_median; + pei_rpc.effective_fee_median = bei_chain.effective_tx_fee_median; + pei_rpc.height = bei_chain.height; + pei_rpc.object_in_json = currency::obj_to_json_str(bei_chain.bl); + + extra_user_data eud = AUTO_VAL_INIT(eud); + if (get_type_in_variant_container(bei_chain.bl.miner_tx.extra, eud)) + { + pei_rpc.miner_text_info = eud.buff; + } + + pei_rpc.base_reward = get_base_block_reward(is_pos_block(bei_chain.bl), bei_chain.already_generated_coins, bei_chain.height); + pei_rpc.summary_reward = get_reward_from_miner_tx(bei_chain.bl.miner_tx); + pei_rpc.penalty = (pei_rpc.base_reward + pei_rpc.total_fee) - pei_rpc.summary_reward; + return true; + } + //--------------------------------------------------------------- + bool fill_tx_rpc_details(tx_rpc_extended_info& tei, const transaction& tx, const transaction_chain_entry* ptce, const crypto::hash& h, uint64_t timestamp, bool is_short) + { + //tei.blob = tx_ptr->tx + tei.id = epee::string_tools::pod_to_hex(h); + if(!tei.blob_size) + tei.blob_size = get_object_blobsize(tx); + + tei.fee = get_tx_fee(tx); + tei.pub_key = epee::string_tools::pod_to_hex(get_tx_pub_key_from_extra(tx)); + tei.timestamp = timestamp; + tei.amount = get_outs_money_amount(tx); + + if (is_short) + return true; + + fill_tx_rpc_inputs(tei, tx); + fill_tx_rpc_outputs(tei, tx, ptce); + fill_tx_rpc_payload_items(tei.extra, tx.extra); + fill_tx_rpc_payload_items(tei.attachments, tx.attachment); + return true; + } + //------------------------------------------------------------------ + void append_per_block_increments_for_tx(const transaction& tx, std::unordered_map& gindices) + { + for (size_t n = 0; n < tx.vout.size(); ++n) + { + if (tx.vout[n].target.type() == typeid(txout_to_key)) + { + uint64_t amount = tx.vout[n].amount; + gindices[amount] += 1; + } + } + } + //--------------------------------------------------------------- + bool get_aliases_reward_account(account_public_address& acc, crypto::secret_key& acc_view_key) + { + bool r = get_aliases_reward_account(acc); + r &= string_tools::parse_tpod_from_hex_string(ALIAS_REWARDS_ACCOUNT_VIEW_SEC_KEY, acc_view_key); + return r; + } + //--------------------------------------------------------------- + bool is_pos_block(const block& b) + { + if (!b.flags&CURRENCY_BLOCK_FLAG_POS_BLOCK) + return false; + return is_pos_block(b.miner_tx); + } + //--------------------------------------------------------------- + bool is_pos_block(const transaction& tx) + { + if (tx.vin.size() == 2 && + tx.vin[0].type() == typeid(txin_gen) && + tx.vin[1].type() == typeid(txin_to_key)) + return true; + return false; + } + size_t get_max_block_size() + { + return CURRENCY_MAX_BLOCK_SIZE; + } + //----------------------------------------------------------------------------------------------- + size_t get_max_tx_size() + { + return CURRENCY_MAX_TRANSACTION_BLOB_SIZE; + } + //----------------------------------------------------------------------------------------------- + uint64_t get_base_block_reward(bool is_pos, uint64_t already_generated_coins, uint64_t height) + { + if (!height) + return PREMINE_AMOUNT; + + if (height <= CURRENCY_FIXED_REWARD_ZONE_HEIGHT) + return CURRENCY_FIXED_REWARD_ZONE_REWARD_AMOUNT; + + uint64_t reward = 0; + if (is_pos) + reward = already_generated_coins / EMISSION_POS_REWARD_DEVIDER; + else + reward = already_generated_coins / EMISSION_POW_REWARD_DEVIDER; + + //crop dust if it make sense + if (reward <= BASE_REWARD_DUST_THRESHOLD) + return reward; + + reward = reward - reward%BASE_REWARD_DUST_THRESHOLD; + return reward; + } + //----------------------------------------------------------------------------------------------- + bool get_block_reward(bool is_pos, size_t median_size, size_t current_block_size, uint64_t already_generated_coins, uint64_t &reward, uint64_t height) + { + uint64_t base_reward = get_base_block_reward(is_pos, already_generated_coins, height); + + //make it soft + if (median_size < CURRENCY_BLOCK_GRANTED_FULL_REWARD_ZONE) + { + median_size = CURRENCY_BLOCK_GRANTED_FULL_REWARD_ZONE; + } + + + if (current_block_size <= median_size || height == 0) + { + reward = base_reward; + return true; + } + + if (current_block_size > 2 * median_size) + { + LOG_PRINT_L4("Block cumulative size is too big: " << current_block_size << ", expected less than " << 2 * median_size); + return false; + } + + uint64_t product_hi; + // BUGFIX(taken from Monero): 32-bit saturation bug (e.g. ARM7), the result was being + // treated as 32-bit by default. + uint64_t multiplicand = 2 * median_size - current_block_size; + multiplicand *= current_block_size; + + uint64_t product_lo = mul128(base_reward, multiplicand, &product_hi); + + uint64_t reward_hi; + uint64_t reward_lo; + div128_32(product_hi, product_lo, static_cast(median_size), &reward_hi, &reward_lo); + div128_32(reward_hi, reward_lo, static_cast(median_size), &reward_hi, &reward_lo); + CHECK_AND_ASSERT_MES(0 == reward_hi, false, "0 == reward_hi"); + CHECK_AND_ASSERT_MES(reward_lo < base_reward, false, "reward_lo < base_reward, reward: " << reward << ", base_reward: " << base_reward << ", current_block_size: " << current_block_size << ", median_size: " << median_size); + + reward = reward_lo; + return true; + } + + //----------------------------------------------------------------------- + bool is_coinbase(const transaction& tx) + { + if (!tx.vin.size() || tx.vin.size() > 2) + return false; + + if (tx.vin[0].type() != typeid(txin_gen)) + return false; + + return true; + } + //----------------------------------------------------------------------- + bool is_coinbase(const transaction& tx, bool& pos_coinbase) + { + if (!is_coinbase(tx)) + return false; + + pos_coinbase = (tx.vin.size() == 2 && tx.vin[1].type() == typeid(txin_to_key)); + return true; + } + //----------------------------------------------------------------------- + bool is_payment_id_size_ok(const std::string& payment_id) + { + return payment_id.size() <= BC_PAYMENT_ID_SERVICE_SIZE_MAX; + } + //----------------------------------------------------------------------- + std::string get_account_address_as_str(const account_public_address& addr) + { + return tools::base58::encode_addr(CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX, t_serializable_object_to_blob(addr)); + } + //----------------------------------------------------------------------- + std::string get_account_address_and_payment_id_as_str(const account_public_address& addr, const std::string& payment_id) + { + return tools::base58::encode_addr(CURRENCY_PUBLIC_INTEG_ADDRESS_BASE58_PREFIX, t_serializable_object_to_blob(addr) + payment_id); + } + //----------------------------------------------------------------------- + bool get_account_address_from_str(account_public_address& addr, const std::string& str) + { + std::string integrated_payment_id; // won't be used + return get_account_address_and_payment_id_from_str(addr, integrated_payment_id, str); + } + //----------------------------------------------------------------------- + bool get_account_address_and_payment_id_from_str(account_public_address& addr, std::string& payment_id, const std::string& str) + { + static const size_t addr_blob_size = sizeof(account_public_address); + blobdata blob; + uint64_t prefix; + if (!tools::base58::decode_addr(str, prefix, blob)) + { + LOG_PRINT_L1("Invalid address format: base58 decoding failed for \"" << str << "\""); + return false; + } + + if (blob.size() < addr_blob_size) + { + LOG_PRINT_L1("Address " << str << " has invalid format: blob size is " << blob.size() << " which is less, than expected " << addr_blob_size); + return false; + } + + if (blob.size() > addr_blob_size + BC_PAYMENT_ID_SERVICE_SIZE_MAX) + { + LOG_PRINT_L1("Address " << str << " has invalid format: blob size is " << blob.size() << " which is more, than allowed " << addr_blob_size + BC_PAYMENT_ID_SERVICE_SIZE_MAX); + return false; + } + + if (prefix == CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX) + { + // nothing + } + else if (prefix == CURRENCY_PUBLIC_INTEG_ADDRESS_BASE58_PREFIX) + { + payment_id = blob.substr(addr_blob_size); + blob = blob.substr(0, addr_blob_size); + } + else + { + LOG_PRINT_L1("Address " << str << " has wrong prefix " << prefix << ", expected " << CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX << " or " << CURRENCY_PUBLIC_INTEG_ADDRESS_BASE58_PREFIX); + return false; + } + + if (!::serialization::parse_binary(blob, addr)) + { + LOG_PRINT_L1("Account public address keys can't be parsed for address \"" << str << "\""); + return false; + } + + if (!crypto::check_key(addr.m_spend_public_key) || !crypto::check_key(addr.m_view_public_key)) + { + LOG_PRINT_L1("Failed to validate address keys for address \"" << str << "\""); + return false; + } + + return true; + } + //------------------------------------------------------------------ + bool is_tx_expired(const transaction& tx, uint64_t expiration_ts_median) + { + /// tx expiration condition (tx is ok if the following is true) + /// tx_expiration_time - TX_EXPIRATION_MEDIAN_SHIFT > get_last_n_blocks_timestamps_median(TX_EXPIRATION_TIMESTAMP_CHECK_WINDOW) + uint64_t expiration_time = get_tx_expiration_time(tx); + if (expiration_time == 0) + return false; // 0 means it never expires + return expiration_time <= expiration_ts_median + TX_EXPIRATION_MEDIAN_SHIFT; + } + //-------------------------------------------------------------------------------- + crypto::hash prepare_prefix_hash_for_sign(const transaction& tx, uint64_t in_index, const crypto::hash& tx_id) + { + CHECK_AND_ASSERT_MES(tx.vin.size() > in_index, null_hash, "condition failed: tx.vin.size(" << tx.vin.size() << ") > in_index( " << in_index << " )"); + + crypto::hash tx_hash_for_signature = tx_id; + if (get_tx_flags(tx) & TX_FLAG_SIGNATURE_MODE_SEPARATE) + { + // separately signed transaction case - figure out all the outputs, extra entries and attachments the given input refers to + size_t signed_outputs_count = 0; + size_t signed_extras_count = 0; + size_t signed_att_count = 0; + + // extra_attachment_info can be stored either in the tx extra (default) and/or in the input's etc_details (it overrides the default one) + extra_attachment_info eai = AUTO_VAL_INIT(eai); + if (get_type_in_variant_container(tx.extra, eai)) + signed_att_count = static_cast(eai.cnt); // get signed attachments count from default extra_attachment_info (if exists) + + for (size_t i = 0; i != in_index + 1; i++) + { + // get signed outputs and extra entries count from input's details (each input has to have it) + signed_parts so = AUTO_VAL_INIT(so); + bool r = get_type_in_variant_container(get_txin_etc_options(tx.vin[i]), so); + CHECK_AND_ASSERT_MES(r, null_hash, "Invalid input #" << i << " (of " << tx.vin.size() << ") contains no signed_parts"); + CHECK_AND_ASSERT_MES(signed_outputs_count <= so.n_outs, null_hash, "Invalid input #" << i << " (of " << tx.vin.size() << "): Next signed_outputs_count is less then prev"); + CHECK_AND_ASSERT_MES(signed_extras_count <= so.n_extras, null_hash, "Invalid input #" << i << " (of " << tx.vin.size() << "): Next signed_extras_count is less then prev"); + signed_outputs_count = so.n_outs; + signed_extras_count = so.n_extras; + + // get signed attachments count from input's extra_attachment_info (it's optional, if exists - override default) + if (get_type_in_variant_container(get_txin_etc_options(tx.vin[i]), eai)) + { + CHECK_AND_ASSERT_MES(signed_att_count <= eai.cnt, null_hash, "Invalid input #" << i << " (of " << tx.vin.size() << "): Next signed_att_count is less then prev"); + signed_att_count = static_cast(eai.cnt); + } + } + + if (in_index == tx.vin.size() - 1) + { + // for the last input make sure all outs, extra entries and attachments was counted correctly + CHECK_AND_ASSERT_MES(signed_outputs_count == tx.vout.size(), null_hash, "Separately signed complete tx has to mention all the outputs in its inputs: signed_outputs_count=" << signed_outputs_count << " tx.vout.size()=" << tx.vout.size()); + CHECK_AND_ASSERT_MES(signed_extras_count == tx.extra.size(), null_hash, "Separately signed complete tx has to mention all the extra entries in its inputs: signed_extras_count=" << signed_extras_count << " tx.extra.size()=" << tx.extra.size()); + CHECK_AND_ASSERT_MES(signed_att_count == tx.attachment.size(), null_hash, "Separately signed complete tx has to mention all the attachments in its inputs: signed_att_count=" << signed_att_count << " tx.attachment.size()=" << tx.attachment.size()); + // okay, there's nothing to crop - tx_hash_for_signature is tx prefix hash + } + else + { + // the given input isn't the last one - we have to crop some data in order to calculate correct hash for signing + transaction tx_local = tx; + + // crop all inputs past the given one + tx_local.vin.resize(static_cast(in_index) + 1); + + // crop outs + CHECK_AND_ASSERT_MES(signed_outputs_count <= tx_local.vout.size(), null_hash, "signed_outputs_count(" << signed_outputs_count << " ) more than tx_local.vout.size()" << tx_local.vout.size()); + tx_local.vout.resize(signed_outputs_count); + + // crop extra + CHECK_AND_ASSERT_MES(signed_extras_count <= tx_local.extra.size(), null_hash, "signed_extras_count(" << signed_extras_count << " ) more than tx_local.extra.size()" << tx_local.vout.size()); + tx_local.extra.resize(signed_extras_count); + + // crop attachments + CHECK_AND_ASSERT_MES(signed_att_count <= tx_local.attachment.size(), null_hash, "signed_att_count(" << signed_att_count << " ) more than tx_local.attachment.size()" << tx_local.attachment.size()); + tx_local.attachment.resize(signed_att_count); + + // calculate hash of cropped tx as the result + tx_hash_for_signature = get_transaction_hash(tx_local); + } + } + + return tx_hash_for_signature; + } + //------------------------------------------------------------------ + std::string dump_ring_sig_data(const crypto::hash& hash_for_sig, const crypto::key_image& k_image, const std::vector& output_keys_ptrs, const std::vector& sig) + { + std::stringstream s; + s << " hash for sig: " << hash_for_sig << ENDL + << " k_image: " << k_image << ENDL + << " out keys (" << output_keys_ptrs.size() << ")" << ENDL; + size_t i = 0; + for (auto& p_out_k : output_keys_ptrs) + s << " " << std::setw(2) << i++ << " " << *p_out_k << ENDL; + + s << " signatures (" << sig.size() << ")" << ENDL; + i = 0; + for (auto& sig_el : sig) + s << " " << std::setw(2) << i++ << " " << sig_el << ENDL; + + return s.str(); + } + + + //-------------------------------------------------------------------------------- + std::ostream& operator <<(std::ostream& o, const ref_by_id& r) + { + return o << "<" << r.n << ":" << r.tx_id << ">"; + } + //-------------------------------------------------------------------------------- + const std::locale& utf8_get_conversion_locale() + { + static std::locale loc = boost::locale::generator().generate("en_US.UTF-8"); + return loc; + } + std::string utf8_to_upper(const std::string& s) + { + return boost::locale::to_upper(s, utf8_get_conversion_locale()); + } + std::string utf8_to_lower(const std::string& s) + { + return boost::locale::to_lower(s, utf8_get_conversion_locale()); + } + bool utf8_substring_test_case_insensitive(const std::string& match, const std::string& s) + { + if (match.empty()) + return true; + return utf8_to_lower(s).find(utf8_to_lower(match), 0) != std::string::npos; + } + //-------------------------------------------------------------------------------- + bool operator ==(const currency::transaction& a, const currency::transaction& b) { + return currency::get_transaction_hash(a) == currency::get_transaction_hash(b); + } + + bool operator ==(const currency::block& a, const currency::block& b) { + return currency::get_block_hash(a) == currency::get_block_hash(b); + } + bool operator ==(const currency::extra_attachment_info& a, const currency::extra_attachment_info& b) + { + if (a.cnt == b.cnt && a.hsh == b.hsh && a.sz == b.sz) + return true; + else + return false; + } + +} // namespace currency + + +bool parse_hash256(const std::string str_hash, crypto::hash& hash) +{ + std::string buf; + bool res = epee::string_tools::parse_hexstr_to_binbuff(str_hash, buf); + if (!res || buf.size() != sizeof(crypto::hash)) + { + std::cout << "invalid hash format: <" << str_hash << '>' << std::endl; + return false; + } + else + { + buf.copy(reinterpret_cast(&hash), sizeof(crypto::hash)); + return true; + } +} diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h new file mode 100644 index 00000000..8efc358d --- /dev/null +++ b/src/currency_core/currency_format_utils.h @@ -0,0 +1,860 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include +#include + +#include "currency_protocol/currency_protocol_defs.h" + +#include "account.h" +#include "include_base_utils.h" +#include "crypto/crypto.h" +#include "crypto/hash.h" +#include "difficulty.h" +//#include "offers_services_helpers.h" +#include "rpc/core_rpc_server_commands_defs.h" +#include "bc_payments_id_service.h" +#include "bc_attachments_helpers_basic.h" +#include "blockchain_storage_basic.h" + +// ------ get_tx_type_definition ------------- +#define GUI_TX_TYPE_NORMAL 0 +#define GUI_TX_TYPE_PUSH_OFFER 1 +#define GUI_TX_TYPE_UPDATE_OFFER 2 +#define GUI_TX_TYPE_CANCEL_OFFER 3 +#define GUI_TX_TYPE_NEW_ALIAS 4 +#define GUI_TX_TYPE_UPDATE_ALIAS 5 +#define GUI_TX_TYPE_COIN_BASE 6 +#define GUI_TX_TYPE_ESCROW_PROPOSAL 7 +#define GUI_TX_TYPE_ESCROW_TRANSFER 8 +#define GUI_TX_TYPE_ESCROW_RELEASE_NORMAL 9 +#define GUI_TX_TYPE_ESCROW_RELEASE_BURN 10 +#define GUI_TX_TYPE_ESCROW_CANCEL_PROPOSAL 11 +#define GUI_TX_TYPE_ESCROW_RELEASE_CANCEL 12 + + + + +//------ + +namespace currency +{ + bool operator ==(const currency::transaction& a, const currency::transaction& b); + bool operator ==(const currency::block& a, const currency::block& b); + bool operator ==(const currency::extra_attachment_info& a, const currency::extra_attachment_info& b); + + + + typedef boost::multiprecision::uint128_t uint128_tl; + struct tx_source_entry + { + typedef std::pair output_entry; // txout_v is either global output index or ref_by_id; public_key - is output ephemeral pub key + + std::vector outputs; //index + key + uint64_t real_output; //index in outputs vector of real output_entry + crypto::public_key real_out_tx_key; //real output's transaction's public key + size_t real_output_in_tx_index; //index in transaction outputs vector + uint64_t amount; //money + crypto::hash multisig_id; //if txin_multisig: multisig output id + size_t ms_sigs_count; //if txin_multisig: must be equal to output's minimum_sigs + size_t ms_keys_count; //if txin_multisig: must be equal to size of output's keys container + bool separately_signed_tx_complete; //for separately signed tx only: denotes the last source entry in complete tx to explicitly mark the final step of tx creation + + bool is_multisig() const { return ms_sigs_count > 0; } + }; + + struct tx_destination_entry + { + uint64_t amount; //money + std::list addr; //destination address, in case of 1 address - txout_to_key, in case of more - txout_multisig + size_t minimum_sigs; // if txout_multisig: minimum signatures that are required to spend this output (minimum_sigs <= addr.size()) IF txout_to_key - not used + uint64_t amount_to_provide; //amount money that provided by initial creator of tx, used with partially created transactions + + tx_destination_entry() : amount(0), minimum_sigs(0), amount_to_provide(0){} + tx_destination_entry(uint64_t a, const account_public_address& ad) : amount(a), addr(1, ad), minimum_sigs(0), amount_to_provide(0){} + tx_destination_entry(uint64_t a, const std::list& addr) : amount(a), addr(addr), minimum_sigs(addr.size()), amount_to_provide(0){} + }; + + struct tx_extra_info + { + crypto::public_key m_tx_pub_key; + //crypto::hash m_offers_hash; + extra_alias_entry m_alias; + std::string m_user_data_blob; + extra_attachment_info m_attachment_info; + }; + + //--------------------------------------------------------------------------------------------------------------- + struct genesis_payment_entry + { + std::string paid_prm; + std::string prm_usd_price; + std::string paid_xmr; + std::string xmr_usd_price; + std::string paid_qtum; + std::string qtum_usd_price; + std::string paid_bch; + std::string bch_usd_price; + std::string paid_rep; + std::string rep_usd_price; + std::string paid_dash; + std::string dash_usd_price; + std::string paid_ltc; + std::string ltc_usd_price; + std::string paid_eos; + std::string eos_usd_price; + std::string paid_eth; + std::string eth_usd_price; + std::string paid_btc; + std::string btc_usd_price; + std::string address_this; + double amount_this_coin_fl; + double amount_this_coin_int; + std::string this_usd_price; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(paid_prm) + KV_SERIALIZE(prm_usd_price) + KV_SERIALIZE(paid_xmr) + KV_SERIALIZE(xmr_usd_price) + KV_SERIALIZE(paid_qtum) + KV_SERIALIZE(qtum_usd_price) + KV_SERIALIZE(paid_bch) + KV_SERIALIZE(bch_usd_price) + KV_SERIALIZE(paid_rep) + KV_SERIALIZE(rep_usd_price) + KV_SERIALIZE(paid_dash) + KV_SERIALIZE(dash_usd_price) + KV_SERIALIZE(paid_ltc) + KV_SERIALIZE(ltc_usd_price) + KV_SERIALIZE(paid_eos) + KV_SERIALIZE(eos_usd_price) + KV_SERIALIZE(paid_eth) + KV_SERIALIZE(eth_usd_price) + KV_SERIALIZE(paid_btc) + KV_SERIALIZE(btc_usd_price) + KV_SERIALIZE(address_this) + KV_SERIALIZE_N(amount_this_coin_fl, "amount_this") + KV_SERIALIZE(this_usd_price) + END_KV_SERIALIZE_MAP() + }; + struct genesis_config_json_struct + { + std::list payments; + std::string proof_string; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(payments) + KV_SERIALIZE(proof_string) + END_KV_SERIALIZE_MAP() + }; + + + //--------------------------------------------------------------- + void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h); + crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx); + bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash); + bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx); + bool construct_miner_tx(size_t height, size_t median_size, uint64_t already_generated_coins, + size_t current_block_size, + uint64_t fee, + const account_public_address &miner_address, + const account_public_address &stakeholder_address, + transaction& tx, + const blobdata& extra_nonce = blobdata(), + size_t max_outs = CURRENCY_MINER_TX_MAX_OUTS, + bool pos = false, + const pos_entry& pe = pos_entry()); + + bool construct_miner_tx(size_t height, size_t median_size, uint64_t already_generated_coins, + size_t current_block_size, + uint64_t fee, + const std::vector& destinations, + transaction& tx, + const blobdata& extra_nonce = blobdata(), + size_t max_outs = CURRENCY_MINER_TX_MAX_OUTS, + bool pos = false, + const pos_entry& pe = pos_entry()); + + + //--------------------------------------------------------------- + template + uint64_t get_tx_x_detail(const transaction& tx) + { + extra_type_t e = AUTO_VAL_INIT(e); + get_type_in_variant_container(tx.extra, e); + return e.v; + } + template + void set_tx_x_detail(transaction& tx, uint64_t v) + { + extra_type_t e = AUTO_VAL_INIT(e); + e.v = v; + update_or_add_field_to_extra(tx.extra, e); + } + + inline uint64_t get_tx_unlock_time(const transaction& tx){ return get_tx_x_detail(tx);} + inline uint64_t get_tx_flags(const transaction& tx){ return get_tx_x_detail(tx); } + inline uint64_t get_tx_expiration_time(const transaction& tx){ return get_tx_x_detail(tx); } + inline void set_tx_unlock_time(transaction& tx, uint64_t v){ set_tx_x_detail(tx, v); } + inline void set_tx_flags(transaction& tx, uint64_t v){ set_tx_x_detail(tx, v); } + inline void set_tx_expiration_time(transaction& tx, uint64_t v){ set_tx_x_detail(tx, v); } + account_public_address get_crypt_address_from_destinations(const account_keys& sender_account_keys, const std::vector& destinations); + + bool is_tx_expired(const transaction& tx, uint64_t expiration_ts_median); + + template + std::string print_t_array(const std::vector& vec) + { + std::stringstream ss; + for (auto& v : vec) + ss << v << " "; + return ss.str(); + } + + uint64_t get_string_uint64_hash(const std::string& str); + bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set& deriv_cache, uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED); + bool validate_alias_name(const std::string& al); + void get_attachment_extra_info_details(const std::vector& attachment, extra_attachment_info& eai); + bool construct_tx(const account_keys& sender_account_keys, + const std::vector& sources, + const std::vector& destinations, + const std::vector& attachments, + transaction& tx, + uint64_t unlock_time, + uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED, + bool shuffle = true); + bool construct_tx(const account_keys& sender_account_keys, + const std::vector& sources, + const std::vector& destinations, + const std::vector& extra, + const std::vector& attachments, + transaction& tx, + crypto::secret_key& one_time_secret_key, + uint64_t unlock_time, + uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED, + bool shuffle = true, + uint64_t flags = 0); + bool construct_tx(const account_keys& sender_account_keys, + const std::vector& sources, + const std::vector& destinations, + const std::vector& extra, + const std::vector& attachments, + transaction& tx, + crypto::secret_key& one_time_secret_key, + uint64_t unlock_time, + const account_public_address& crypt_account, + uint64_t expiration_time, + uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED, + bool shuffle = true, + uint64_t flags = 0); + + bool sign_multisig_input_in_tx(currency::transaction& tx, size_t ms_input_index, const currency::account_keys& keys, const currency::transaction& source_tx, bool *p_is_input_fully_signed = nullptr); + + bool sign_extra_alias_entry(extra_alias_entry& ai, const crypto::public_key& pkey, const crypto::secret_key& skey); + crypto::hash get_sign_buff_hash_for_alias_update(const extra_alias_entry& ai); + bool add_tx_extra_alias(transaction& tx, const extra_alias_entry& alinfo); + bool parse_and_validate_tx_extra(const transaction& tx, tx_extra_info& extra); + bool parse_and_validate_tx_extra(const transaction& tx, crypto::public_key& tx_pub_key); + crypto::public_key get_tx_pub_key_from_extra(const transaction& tx); + bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key); + bool add_tx_extra_userdata(transaction& tx, const blobdata& extra_nonce); + + crypto::hash get_multisig_out_id(const transaction& tx, size_t n); + bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::key_derivation& derivation, size_t output_index); + bool is_out_to_acc(const account_keys& acc, const txout_multisig& out_multisig, const crypto::key_derivation& derivation, size_t output_index); + bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, uint64_t& money_transfered, crypto::key_derivation& derivation); + bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector& outs, uint64_t& money_transfered, crypto::key_derivation& derivation); + bool get_tx_fee(const transaction& tx, uint64_t & fee); + uint64_t get_tx_fee(const transaction& tx); + bool derive_ephemeral_key_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral); + bool generate_key_image_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki); + bool derive_public_key_from_target_address(const account_public_address& destination_addr, const crypto::secret_key& tx_sec_key, size_t index, crypto::public_key& out_eph_public_key, crypto::key_derivation& derivation); + bool derive_public_key_from_target_address(const account_public_address& destination_addr, const crypto::secret_key& tx_sec_key, size_t index, crypto::public_key& out_eph_public_key); + void get_blob_hash(const blobdata& blob, crypto::hash& res); + crypto::hash get_blob_hash(const blobdata& blob); + std::string short_hash_str(const crypto::hash& h); + bool is_mixattr_applicable_for_fake_outs_counter(uint8_t mix_attr, uint64_t fake_attr_count); + bool is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t current_blockchain_size, uint64_t current_time); + bool decrypt_payload_items(bool is_income, const transaction& tx, const account_keys& acc_keys, std::vector& decrypted_items); + void encrypt_attachments(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key); + bool is_derivation_used_to_encrypt(const transaction& tx, const crypto::key_derivation& derivation); + uint64_t get_tx_type(const transaction& tx); + size_t get_multisig_out_index(const std::vector& outs); + size_t get_multisig_in_index(const std::vector& inputs); + + uint64_t get_reward_from_miner_tx(const transaction& tx); + + crypto::hash get_transaction_hash(const transaction& t); + bool get_transaction_hash(const transaction& t, crypto::hash& res); + bool get_transaction_hash(const transaction& t, crypto::hash& res, uint64_t& blob_size); + //bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t& blob_size); + blobdata get_block_hashing_blob(const block& b); + bool get_block_hash(const block& b, crypto::hash& res); + crypto::hash get_block_hash(const block& b); + bool generate_genesis_block(block& bl); + const crypto::hash& get_genesis_hash(bool need_to_set = false, const crypto::hash& h = null_hash); + bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b); + uint64_t get_inputs_money_amount(const transaction& tx); + bool get_inputs_money_amount(const transaction& tx, uint64_t& money); + uint64_t get_outs_money_amount(const transaction& tx); + bool check_inputs_types_supported(const transaction& tx); + bool check_outs_valid(const transaction& tx); + bool parse_amount(uint64_t& amount, const std::string& str_amount); + + crypto::hash get_block_longhash(uint64_t h, const crypto::hash& block_long_ash, uint64_t nonce); + void get_block_longhash(const block& b, crypto::hash& res); + crypto::hash get_block_longhash(const block& b); + bool unserialize_block_complete_entry(const COMMAND_RPC_GET_BLOCKS_FAST::response& serialized, + COMMAND_RPC_GET_BLOCKS_DIRECT::response& unserialized); + + + uint64_t get_alias_coast_from_fee(const std::string& alias, uint64_t fee_median); + //const crypto::public_key get_offer_secure_key_by_index_from_tx(const transaction& tx, size_t index); + + bool check_money_overflow(const transaction& tx); + bool check_outs_overflow(const transaction& tx); + bool check_inputs_overflow(const transaction& tx); + uint64_t get_block_height(const transaction& coinbase); + uint64_t get_block_height(const block& b); + std::vector relative_output_offsets_to_absolute(const std::vector& off); + std::vector absolute_output_offsets_to_relative(const std::vector& off); + // prints amount in format "3.14000000", "0.00000000" + std::string print_money(uint64_t amount); + std::string print_fixed_decimal_point(uint64_t amount, size_t decimal_point); + // prints amount in format "3.14", "0.0" + std::string print_money_brief(uint64_t amount); + uint64_t get_actual_timestamp(const block& b); + + bool addendum_to_hexstr(const std::vector& add, std::string& hex_buff); + bool hexstr_to_addendum(const std::string& hex_buff, std::vector& add); + bool set_payment_id_to_tx(std::vector& att, const std::string& payment_id); + bool add_padding_to_tx(transaction& tx, size_t count); + bool is_service_tx(const transaction& tx); + bool is_mixin_tx(const transaction& tx); + bool is_showing_sender_addres(const transaction& tx); + uint64_t get_amount_for_zero_pubkeys(const transaction& tx); + //std::string get_comment_from_tx(const transaction& tx); + std::string print_stake_kernel_info(const stake_kernel& sk); + std::string dump_ring_sig_data(const crypto::hash& hash_for_sig, const crypto::key_image& k_image, const std::vector& output_keys_ptrs, const std::vector& sig); + + //PoS + bool is_pos_block(const block& b); + bool is_pos_block(const transaction& tx); + uint64_t get_coinday_weight(uint64_t amount); + wide_difficulty_type correct_difficulty_with_sequence_factor(size_t sequence_factor, wide_difficulty_type diff); + void print_currency_details(); + std::string print_reward_change_first_blocks(size_t n_of_first_blocks); + bool get_aliases_reward_account(account_public_address& acc, crypto::secret_key& acc_view_key); + bool get_aliases_reward_account(account_public_address& acc); + alias_rpc_details alias_info_to_rpc_alias_info(const currency::extra_alias_entry& ai); + update_alias_rpc_details alias_info_to_rpc_update_alias_info(const currency::extra_alias_entry& ai, const std::string& old_address); + size_t get_service_attachments_count_in_tx(const transaction& tx); + bool fill_tx_rpc_outputs(tx_rpc_extended_info& tei, const transaction& tx, const transaction_chain_entry* ptce); + bool fill_tx_rpc_inputs(tx_rpc_extended_info& tei, const transaction& tx); + bool fill_tx_rpc_details(tx_rpc_extended_info& tei, const transaction& tx, const transaction_chain_entry* ptce, const crypto::hash& h, uint64_t timestamp, bool is_short = false); + bool fill_block_rpc_details(block_rpc_extended_info& pei_rpc, const block_extended_info& bei_chain, const crypto::hash& h); + void append_per_block_increments_for_tx(const transaction& tx, std::unordered_map& gindices); + + /************************************************************************/ + /* */ + /************************************************************************/ + template + struct array_hasher : std::unary_function + { + std::size_t operator()(const t_array& val) const + { + return boost::hash_range(&val.data[0], &val.data[sizeof(val.data)]); + } + }; + + template + typename std::conditional::value, const std::vector, std::vector >::type& get_txin_etc_options(t_txin_v& in) + { + static typename std::conditional::value, const std::vector, std::vector >::type stub; + + + //static stub; + + if (in.type() == typeid(txin_to_key)) + return boost::get(in).etc_details; + else if (in.type() == typeid(txin_multisig)) + return boost::get(in).etc_details; + else + return stub; + } + + template + bool add_attachments_info_to_extra(t_extra_container& extra_container, const std::vector& attachments) + { + if (!attachments.empty()) + { + extra_attachment_info eai = AUTO_VAL_INIT(eai); + get_attachment_extra_info_details(attachments, eai); + extra_container.push_back(eai); + } + return true; + } + + + /************************************************************************/ + /* helper functions */ + /************************************************************************/ + size_t get_max_block_size(); + size_t get_max_tx_size(); + bool get_block_reward(bool is_pos, size_t median_size, size_t current_block_size, uint64_t already_generated_coins, uint64_t &reward, uint64_t height); + uint64_t get_base_block_reward(bool is_pos, uint64_t already_generated_coins, uint64_t height); + bool is_payment_id_size_ok(const std::string& payment_id); + std::string get_account_address_as_str(const account_public_address& addr); + std::string get_account_address_and_payment_id_as_str(const account_public_address& addr, const std::string& payment_id); + bool get_account_address_from_str(account_public_address& addr, const std::string& str); + bool get_account_address_and_payment_id_from_str(account_public_address& addr, std::string& payment_id, const std::string& str); + bool is_coinbase(const transaction& tx); + bool is_coinbase(const transaction& tx, bool& pos_coinbase); + bool have_attachment_service_in_container(const std::vector& av, const std::string& service_id, const std::string& instruction); + crypto::hash prepare_prefix_hash_for_sign(const transaction& tx, uint64_t in_index, const crypto::hash& tx_id); + + //------------------------------------------------------------------------------------ + template + result_type get_pod_checksum(const t_pod_type& bl) + { + const unsigned char* pbuf = reinterpret_cast(&bl); + result_type summ = 0; + for (size_t i = 0; i != sizeof(t_pod_type)-1; i++) + summ += pbuf[i]; + + return summ; + } + //--------------------------------------------------------------- + template + bool is_out_to_acc(const account_keys& acc, const tx_out_t& out_key, const crypto::public_key& tx_pub_key, size_t output_index) + { + crypto::key_derivation derivation; + generate_key_derivation(tx_pub_key, acc.m_view_secret_key, derivation); + return is_out_to_acc(acc, out_key, derivation, output_index); + } + //--------------------------------------------------------------- + template + bool have_type_in_variant_container(const variant_t_container& av) + { + for (auto& ai : av) + { + if (ai.type() == typeid(specic_type_t)) + { + return true; + } + } + return false; + } + //--------------------------------------------------------------- + template + size_t count_type_in_variant_container(const variant_t_container& av) + { + size_t result = 0; + for (auto& ai : av) + { + if (ai.type() == typeid(specic_type_t)) + ++result; + } + return result; + } + //--------------------------------------------------------------- + template + bool get_type_in_variant_container(const variant_t_container& av, specic_type_t& a) + { + for (auto& ai : av) + { + if (ai.type() == typeid(specic_type_t)) + { + a = boost::get(ai); + return true; + } + } + return false; + } + //--------------------------------------------------------------- + template + bool check_allowed_types_in_variant_container(const variant_container_t& container, const std::unordered_set& allowed_types, bool elements_must_be_unique = true) + { + for (auto it = container.begin(); it != container.end(); ++it) + { + if (allowed_types.count(std::type_index(it->type())) == 0) + return false; + + if (elements_must_be_unique) + { + for (auto jt = it + 1; jt != container.end(); ++jt) + if (it->type().hash_code() == jt->type().hash_code()) + return false; + } + } + return true; + } + //--------------------------------------------------------------- + template + bool check_allowed_types_in_variant_container(const variant_container_t& container, const variant_container_t& allowed_types_examples, bool elements_must_be_unique = true) + { + std::unordered_set allowed_types; + for (auto& el : allowed_types_examples) + if (!allowed_types.insert(std::type_index(el.type())).second) + return false; // invalid allowed_types_examples container + + return check_allowed_types_in_variant_container(container, allowed_types, elements_must_be_unique); + } + //--------------------------------------------------------------- + template + std::string stringize_types_in_variant_container(const variant_container_t& container) + { + std::string result; + for (auto it = container.begin(); it != container.end(); ++it) + result = (result + it->type().name()) + (it + 1 != container.end() ? ", " : ""); + return result; + } + //---------------------------------------------------------------------------------------------------- + template + bool validate_attachment_info(const t_container& container, const std::vector& attachments, bool allow_no_info_for_non_empty_attachments_container) + { + // this routine makes sure the container has correct and valid extra_attachment_info + extra_attachment_info eai = AUTO_VAL_INIT(eai); + bool r = get_type_in_variant_container(container, eai); + if (!r && allow_no_info_for_non_empty_attachments_container) + return true; + + // two valid options here: 1) no attachment info and empty attachements container; 2) attachment info present and the container is not empty + CHECK_AND_ASSERT_MES(r == !attachments.empty(), false, "Invalid attachment info: extra_attachment_info is " << (r ? "present" : "not present") << " while attachments size is " << attachments.size()); + + CHECK_AND_ASSERT_MES(eai.cnt <= attachments.size(), false, "Incorrect attachments counter: " << eai.cnt << " while attachments size is " << attachments.size()); + + extra_attachment_info eai_local = AUTO_VAL_INIT(eai_local); + if (eai.cnt == attachments.size()) + { + get_attachment_extra_info_details(attachments, eai_local); + } + else + { + std::vector attachments_local(attachments.begin(), attachments.begin() + static_cast(eai.cnt)); // make a local copy of eai.cnt attachments + get_attachment_extra_info_details(attachments_local, eai_local); + } + + // ...and compare with the one from the container + CHECK_AND_ASSERT_MES(eai == eai_local, false, "Invalid attachments info: (" << eai.cnt << "," << eai.hsh << "," << eai.sz << ") expected: (" << eai_local.cnt << "," << eai_local.hsh << "," << eai_local.sz << ")"); + + return true; + } + + //------------------------------------------------------------------ + template + bool alias_info_to_rpc_alias_info(const currency::extra_alias_entry& ai, alias_rpc_details_t& ari) + { + return alias_info_to_rpc_alias_info(ai.m_alias, ai, ari); + } + + template + bool alias_info_to_rpc_alias_info(const std::string& alias, const currency::extra_alias_entry_base& aib, alias_rpc_details_t& ari) + { + ari.alias = alias; + ari.details.address = currency::get_account_address_as_str(aib.m_address); + ari.details.comment = aib.m_text_comment; + if (aib.m_view_key.size()) + ari.details.tracking_key = epee::string_tools::pod_to_hex(aib.m_view_key.back()); + + return true; + } + + template + bool alias_rpc_details_to_alias_info(const alias_rpc_details_t& ard, currency::extra_alias_entry& ai) + { + if (!currency::get_account_address_from_str(ai.m_address, ard.details.address)) + { + LOG_ERROR("Failed to parse address: " << ard.details.address); + return false; + } + if (ard.details.tracking_key.size()) + { + if (!epee::string_tools::parse_tpod_from_hex_string(ard.details.tracking_key, ai.m_view_key)) + { + LOG_ERROR("Failed to parse tracking_key: " << ard.details.tracking_key); + return false; + } + } + //ai.m_sign; atm alias updating disabled + ai.m_text_comment = ard.details.comment; + ai.m_alias = ard.alias; + return true; + } + + + template + extra_t& get_or_add_field_to_extra(std::vector& extra) + { + for (auto& ev : extra) + { + if (ev.type() == typeid(extra_t)) + return boost::get(ev); + } + extra.push_back(extra_t()); + return boost::get(extra.back()); + } + template + void update_or_add_field_to_extra(std::vector& variant_container, const variant_type_t& v) + { + for (auto& ev : variant_container) + { + if (ev.type() == typeid(variant_type_t)) + { + boost::get(ev) = v; + return; + } + } + variant_container.push_back(v); + } + + //--------------------------------------------------------------- + template + bool get_payment_id_from_tx(const t_container& att, std::string& payment_id) + { + tx_service_attachment sa = AUTO_VAL_INIT(sa); + if (bc_services::get_first_service_attachment_by_id(att, BC_PAYMENT_ID_SERVICE_ID, "", sa)) + { + payment_id = sa.body; + return true; + } + return false; + } + + + + //--------------------------------------------------------------- + template + bool get_object_hash(const t_object& o, crypto::hash& res) + { + get_blob_hash(t_serializable_object_to_blob(o), res); + return true; + } + //--------------------------------------------------------------- + template + crypto::hash get_object_hash(const t_object& o) + { + crypto::hash h; + get_object_hash(o, h); + return h; + } + //--------------------------------------------------------------- + + template + size_t get_object_blobsize(const t_object& o) + { + blobdata b = t_serializable_object_to_blob(o); + return b.size(); + } + //--------------------------------------------------------------- + size_t get_object_blobsize(const transaction& t); + size_t get_object_blobsize(const transaction& t, uint64_t prefix_blob_size); + //--------------------------------------------------------------- + template + bool get_object_hash(const t_object& o, crypto::hash& res, uint64_t& blob_size) + { + blobdata bl = t_serializable_object_to_blob(o); + blob_size = bl.size(); + get_blob_hash(bl, res); + return true; + } + //--------------------------------------------------------------- + template + std::string obj_to_json_str(const T& obj) + { + std::stringstream ss; + json_archive ar(ss, true); + bool r = ::serialization::serialize(ar, const_cast(obj)); + CHECK_AND_ASSERT_MES(r, "", "obj_to_json_str failed: serialization::serialize returned false"); + return ss.str(); + } + //--------------------------------------------------------------- + // 62387455827 -> 455827 + 7000000 + 80000000 + 300000000 + 2000000000 + 60000000000, where 455827 <= dust_threshold + template + void decompose_amount_into_digits(uint64_t amount, uint64_t dust_threshold, const chunk_handler_t& chunk_handler, const dust_handler_t& dust_handler, uint64_t max_output_allowed, size_t max_outs_count, size_t outs_count = 0) + { + CHECK_AND_ASSERT_MES(amount != 0, void(), "zero amount"); + CHECK_AND_ASSERT_MES(amount / max_output_allowed <= max_outs_count, void(), "too big amount: " << print_money(amount) << " for given max_output_allowed: " << print_money(max_output_allowed) << ", it would require >" << amount / max_output_allowed << " outputs"); + + bool is_dust_handled = false; + uint64_t dust = 0; + uint64_t multiplier = 1; + while (0 != amount ) + { + uint64_t chunk = (amount % 10) * multiplier; + if (chunk > max_output_allowed) + break; + amount /= 10; + multiplier *= 10; + + + + if (dust + chunk <= dust_threshold) + { + dust += chunk; + } + else + { + if (!is_dust_handled && 0 != dust) + { + dust_handler(dust); + is_dust_handled = true; + } + if (0 != chunk) + { + chunk_handler(chunk); + ++outs_count; + } + } + } + if (amount) + { + //CHECK_AND_ASSERT_MES_NO_RET(max_output_allowed >= multiplier, "max_output_allowed > multiplier"); + CHECK_AND_ASSERT_MES(multiplier != 0, void(), "decompose_amount_into_digits: internal error: multiplier == 0"); + uint64_t amount_multiplied = amount * multiplier; + while (amount_multiplied >= max_output_allowed) + { + amount_multiplied -= max_output_allowed; + chunk_handler(max_output_allowed); + ++outs_count; + CHECK_AND_ASSERT_MES(outs_count < max_outs_count || amount_multiplied == 0, void(), "decompose_amount_into_digits: too many outputs"); + } + + if (amount_multiplied != 0) + decompose_amount_into_digits(amount_multiplied, dust_threshold, chunk_handler, dust_handler, max_output_allowed, max_outs_count, outs_count); + } + + + if (!is_dust_handled && 0 != dust) + { + dust_handler(dust); + } + } + + template + void decompose_amount_into_digits(uint64_t amount, uint64_t dust_threshold, const chunk_handler_t& chunk_handler, const dust_handler_t& dust_handler) + { + decompose_amount_into_digits(amount, dust_threshold, chunk_handler, dust_handler, WALLET_MAX_ALLOWED_OUTPUT_AMOUNT, CURRENCY_TX_MAX_ALLOWED_OUTS, 0); + } + + template + void decompose_amount_into_digits(uint64_t amount, uint64_t dust_threshold, const chunk_handler_t& chunk_handler, const dust_handler_t& dust_handler, uint64_t max_output_allowed) + { + decompose_amount_into_digits(amount, dust_threshold, chunk_handler, dust_handler, max_output_allowed, CURRENCY_TX_MAX_ALLOWED_OUTS, 0); + } + //--------------------------------------------------------------- + inline size_t get_input_expected_signatures_count(const txin_v& tx_in) + { + struct txin_signature_size_visitor : public boost::static_visitor + { + size_t operator()(const txin_gen& /*txin*/) const { return 0; } + size_t operator()(const txin_to_key& txin) const { return txin.key_offsets.size(); } + size_t operator()(const txin_multisig& txin) const { return txin.sigs_count; } + }; + + return boost::apply_visitor(txin_signature_size_visitor(), tx_in); + } + //--------------------------------------------------------------- + inline const std::vector* get_input_etc_details(const txin_v& in) + { + if (in.type().hash_code() == typeid(txin_to_key).hash_code()) + return &boost::get(in).etc_details; + if (in.type().hash_code() == typeid(txin_multisig).hash_code()) + return &boost::get(in).etc_details; + return nullptr; + } + //--------------------------------------------------------------- + inline std::vector* get_input_etc_details(txin_v& in) + { + if (in.type().hash_code() == typeid(txin_to_key).hash_code()) + return &boost::get(in).etc_details; + if (in.type().hash_code() == typeid(txin_multisig).hash_code()) + return &boost::get(in).etc_details; + return nullptr; + } + //--------------------------------------------------------------- + + blobdata block_to_blob(const block& b); + bool block_to_blob(const block& b, blobdata& b_blob); + blobdata tx_to_blob(const transaction& b); + bool tx_to_blob(const transaction& b, blobdata& b_blob); + void get_tx_tree_hash(const std::vector& tx_hashes, crypto::hash& h); + crypto::hash get_tx_tree_hash(const std::vector& tx_hashes); + crypto::hash get_tx_tree_hash(const block& b); + +#define CHECKED_GET_SPECIFIC_VARIANT(variant_var, specific_type, variable_name, fail_return_val) \ + CHECK_AND_ASSERT_MES(variant_var.type() == typeid(specific_type), fail_return_val, "wrong variant type: " << variant_var.type().name() << ", expected " << typeid(specific_type).name()); \ + specific_type& variable_name = boost::get(variant_var); + + struct input_amount_getter : public boost::static_visitor + { + template + uint64_t operator()(const t_input& i) const{return i.amount;} + uint64_t operator()(const txin_gen& i) const {return 0;} + }; + + inline uint64_t get_amount_from_variant(const txin_v& v) + { + return boost::apply_visitor(input_amount_getter(), v); + } + + //--------------------------------------------------------------- + std::ostream& operator <<(std::ostream& o, const ref_by_id& r); + //--------------------------------------------------------------- + std::string utf8_to_upper(const std::string& s); + std::string utf8_to_lower(const std::string& s); + bool utf8_substring_test_case_insensitive(const std::string& match, const std::string& s); // Returns true is 's' contains 'match' (case-insensitive) + +} // namespace currency + +template +std::ostream &print256(std::ostream &o, const T &v) { + return o << "<" << epee::string_tools::pod_to_hex(v) << ">"; +} + +template +std::ostream &print16(std::ostream &o, const T &v) { + return o << "<" << epee::string_tools::pod_to_hex(v).substr(0, 5) << "..>"; +} + +template +std::string print16(const T &v) { + return std::string("<") + epee::string_tools::pod_to_hex(v).substr(0, 5) + "..>"; +} + + +//POD_MAKE_COMPARABLE(currency, extra_attachment_info) + + +// namespace std +// { +// inline +// bool operator ==(const currency::transaction& a, const currency::transaction& b) +// { +// return currency::get_transaction_hash(a) == currency::get_transaction_hash(b); +// } +// inline +// bool operator ==(const currency::block& a, const currency::block& b) +// { +// return currency::get_block_hash(a) == currency::get_block_hash(b); +// } +// } + +bool parse_hash256(const std::string str_hash, crypto::hash& hash); + +namespace crypto { + inline std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) { return print256(o, v); } + inline std::ostream &operator <<(std::ostream &o, const crypto::secret_key &v) { return print256(o, v); } + inline std::ostream &operator <<(std::ostream &o, const crypto::key_derivation &v) { return print256(o, v); } + inline std::ostream &operator <<(std::ostream &o, const crypto::key_image &v) { return print256(o, v); } + inline std::ostream &operator <<(std::ostream &o, const crypto::signature &v) { return print256(o, v); } + inline std::ostream &operator <<(std::ostream &o, const crypto::hash &v) { return print256(o, v); } +} diff --git a/src/currency_core/currency_stat_info.h b/src/currency_core/currency_stat_info.h new file mode 100644 index 00000000..2c490a28 --- /dev/null +++ b/src/currency_core/currency_stat_info.h @@ -0,0 +1,72 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include "serialization/keyvalue_serialization.h" + + +namespace currency +{ + + struct chain_entry + { + uint64_t h; + std::string id; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(h) + KV_SERIALIZE(id) + END_KV_SERIALIZE_MAP() + }; + + + struct error_stat_entry + { + std::string channel; + uint64_t err_count; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(channel) + KV_SERIALIZE(err_count) + END_KV_SERIALIZE_MAP() + }; + + struct core_stat_info + { + struct params + { + uint64_t chain_len; + uint64_t logs_journal_len; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(chain_len) + KV_SERIALIZE(logs_journal_len) + END_KV_SERIALIZE_MAP() + }; + + uint64_t tx_pool_size; + uint64_t blockchain_height; + uint64_t mining_speed; + uint64_t alternative_blocks; + bool epic_failure_happend; + std::string top_block_id_str; + std::list main_chain_blocks; + std::list alt_chain_blocks; + std::list errors_stat; + std::list errors_journal; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(tx_pool_size) + KV_SERIALIZE(blockchain_height) + KV_SERIALIZE(mining_speed) + KV_SERIALIZE(alternative_blocks) + KV_SERIALIZE(main_chain_blocks) + KV_SERIALIZE(top_block_id_str) + //KV_SERIALIZE(alt_chain_blocks) + KV_SERIALIZE(errors_stat) + KV_SERIALIZE(epic_failure_happend) + KV_SERIALIZE(errors_journal) + END_KV_SERIALIZE_MAP() + }; +} diff --git a/src/currency_core/difficulty.cpp b/src/currency_core/difficulty.cpp new file mode 100644 index 00000000..a496d463 --- /dev/null +++ b/src/currency_core/difficulty.cpp @@ -0,0 +1,224 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include + +#include "misc_log_ex.h" + +#include "common/int-util.h" +#include "crypto/hash.h" +#include "currency_core/currency_config.h" +#include "difficulty.h" +#include "profile_tools.h" + +namespace currency { + + using std::size_t; + using std::uint64_t; + using std::vector; + +#if defined(_MSC_VER) +#include +#include + + static inline void mul(uint64_t a, uint64_t b, uint64_t &low, uint64_t &high) { + boost::multiprecision::uint128_t res = boost::multiprecision::uint128_t(a) * b; + low = (res & 0xffffffffffffffffLL).convert_to(); + high = (res >> 64).convert_to(); + //low = _umul128(a, b, &high); + //low = UnsignedMultiply128(a, b, &high); + } + +#else + + static inline void mul(uint64_t a, uint64_t b, uint64_t &low, uint64_t &high) { + typedef unsigned __int128 uint128_t; + uint128_t res = (uint128_t) a * (uint128_t) b; + low = (uint64_t) res; + high = (uint64_t) (res >> 64); + } + +#endif + + static inline bool cadd(uint64_t a, uint64_t b) { + return a + b < a; + } + + static inline bool cadc(uint64_t a, uint64_t b, bool c) { + return a + b < a || (c && a + b == (uint64_t) -1); + } + + bool check_hash_old(const crypto::hash &hash, difficulty_type difficulty) { + uint64_t low, high, top, cur; + // First check the highest word, this will most likely fail for a random hash. + mul(swap64le(((const uint64_t *) &hash)[3]), difficulty, top, high); + if (high != 0) { + return false; + } + mul(swap64le(((const uint64_t *) &hash)[0]), difficulty, low, cur); + mul(swap64le(((const uint64_t *) &hash)[1]), difficulty, low, high); + bool carry = cadd(cur, low); + cur = high; + mul(swap64le(((const uint64_t *) &hash)[2]), difficulty, low, high); + carry = cadc(cur, low, carry); + carry = cadc(high, top, carry); + return !carry; + } + +#if defined(_MSC_VER) +#ifdef max +#undef max +#endif +#endif + + const wide_difficulty_type max64bit(std::numeric_limits::max()); + const boost::multiprecision::uint256_t max128bit(std::numeric_limits::max()); + const boost::multiprecision::uint512_t max256bit(std::numeric_limits::max()); + + bool check_hash(const crypto::hash &hash_, wide_difficulty_type difficulty) + { + //revert byte order + crypto::hash h = {}; + for (size_t i = 0; i != sizeof(h); i++) + { + *(((char*)&h) + (sizeof(h)-(i + 1))) = *(((char*)&hash_) +i ); + } + + PROFILE_FUNC("check_hash"); + if (difficulty < max64bit) + { // if can convert to small difficulty - do it + std::uint64_t dl = difficulty.convert_to(); + uint64_t low, high, top, cur; + // First check the highest word, this will most likely fail for a random hash. + mul(swap64le(((const uint64_t *) &h)[3]), dl, top, high); + if (high != 0) + return false; + mul(swap64le(((const uint64_t *) &h)[0]), dl, low, cur); + mul(swap64le(((const uint64_t *) &h)[1]), dl, low, high); + bool carry = cadd(cur, low); + cur = high; + mul(swap64le(((const uint64_t *) &h)[2]), dl, low, high); + carry = cadc(cur, low, carry); + carry = cadc(high, top, carry); + return !carry; + } + // fast check + if (((const uint64_t *) &h)[3] > 0) + return false; + // usual slow check + boost::multiprecision::uint512_t hashVal = 0; + for(int i = 1; i < 4; i++) + { // highest word is zero + hashVal |= swap64le(((const uint64_t *) &h)[3 - i]); + hashVal << 64; + } + return (hashVal * difficulty > max256bit); + } + + uint64_t difficulty_to_boundary(wide_difficulty_type difficulty) + { + boost::multiprecision::uint256_t nominal_hash = std::numeric_limits::max(); + nominal_hash = nominal_hash / difficulty; + uint64_t res = (nominal_hash >> 192).convert_to(); + return res; + } + + void difficulty_to_boundary_long(wide_difficulty_type difficulty, crypto::hash& result) + { + boost::multiprecision::uint256_t nominal_hash = std::numeric_limits::max(); + nominal_hash = nominal_hash / difficulty; + + static_assert(sizeof(uint64_t) * 4 == sizeof(result), "!"); + for (size_t i = 0; i < 4; ++i) + { + (reinterpret_cast(&result))[i] = nominal_hash.convert_to(); + nominal_hash >>= 64; + } + } + + difficulty_type next_difficulty_old(vector timestamps, vector cumulative_difficulties, size_t target_seconds) { + //cutoff DIFFICULTY_LAG + if(timestamps.size() > DIFFICULTY_WINDOW) + { + timestamps.resize(DIFFICULTY_WINDOW); + cumulative_difficulties.resize(DIFFICULTY_WINDOW); + } + + + size_t length = timestamps.size(); + assert(length == cumulative_difficulties.size()); + if (length <= 1) { + return DIFFICULTY_STARTER; + } + static_assert(DIFFICULTY_WINDOW >= 2, "Window is too small"); + assert(length <= DIFFICULTY_WINDOW); + sort(timestamps.begin(), timestamps.end()); + size_t cut_begin, cut_end; + static_assert(2 * DIFFICULTY_CUT <= DIFFICULTY_WINDOW - 2, "Cut length is too large"); + if (length <= DIFFICULTY_WINDOW - 2 * DIFFICULTY_CUT) { + cut_begin = 0; + cut_end = length; + } else { + cut_begin = (length - (DIFFICULTY_WINDOW - 2 * DIFFICULTY_CUT) + 1) / 2; + cut_end = cut_begin + (DIFFICULTY_WINDOW - 2 * DIFFICULTY_CUT); + } + assert(/*cut_begin >= 0 &&*/ cut_begin + 2 <= cut_end && cut_end <= length); + uint64_t time_span = timestamps[cut_end - 1] - timestamps[cut_begin]; + if (time_span == 0) { + time_span = 1; + } + difficulty_type total_work = cumulative_difficulties[cut_end - 1] - cumulative_difficulties[cut_begin]; + assert(total_work > 0); + uint64_t low, high; + mul(total_work, target_seconds, low, high); + if (high != 0 || low + time_span - 1 < low) { + return 0; + } + return (low + time_span - 1) / time_span; + } + + wide_difficulty_type next_difficulty(vector timestamps, vector cumulative_difficulties, size_t target_seconds) { + //cutoff DIFFICULTY_LAG + if(timestamps.size() > DIFFICULTY_WINDOW) + { + timestamps.resize(DIFFICULTY_WINDOW); + cumulative_difficulties.resize(DIFFICULTY_WINDOW); + } + + + size_t length = timestamps.size(); + CHECK_AND_ASSERT_MES(length == cumulative_difficulties.size(), 0, "Check \"length == cumulative_difficulties.size()\" failed"); + if (length <= 1) { + return DIFFICULTY_STARTER; + } + static_assert(DIFFICULTY_WINDOW >= 2, "Window is too small"); + CHECK_AND_ASSERT_MES(length <= DIFFICULTY_WINDOW, 0, "length <= DIFFICULTY_WINDOW check failed, length=" << length); + sort(timestamps.begin(), timestamps.end(), std::greater()); + size_t cut_begin, cut_end; + static_assert(2 * DIFFICULTY_CUT <= DIFFICULTY_WINDOW - 2, "Cut length is too large"); + if (length <= DIFFICULTY_WINDOW - 2 * DIFFICULTY_CUT) { + cut_begin = 0; + cut_end = length; + } else { + cut_begin = (length - (DIFFICULTY_WINDOW - 2 * DIFFICULTY_CUT) + 1) / 2; + cut_end = cut_begin + (DIFFICULTY_WINDOW - 2 * DIFFICULTY_CUT); + } + assert(/*cut_begin >= 0 &&*/ cut_begin + 2 <= cut_end && cut_end <= length); + uint64_t time_span = timestamps[cut_begin] - timestamps[cut_end - 1]; + if (time_span == 0) { + time_span = 1; + } + wide_difficulty_type total_work = cumulative_difficulties[cut_begin] - cumulative_difficulties[cut_end - 1]; + boost::multiprecision::uint256_t res = (boost::multiprecision::uint256_t(total_work) * target_seconds + time_span - 1) / time_span; + if(res > max128bit) + return 0; // to behave like previous implementation, may be better return max128bit? + return res.convert_to(); + } +} diff --git a/src/currency_core/difficulty.h b/src/currency_core/difficulty.h new file mode 100644 index 00000000..127fadce --- /dev/null +++ b/src/currency_core/difficulty.h @@ -0,0 +1,29 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include + +#include + +#include "crypto/hash.h" + +namespace currency +{ + typedef std::uint64_t difficulty_type; + typedef boost::multiprecision::uint128_t wide_difficulty_type; + + bool check_hash_old(const crypto::hash &hash, difficulty_type difficulty); + difficulty_type next_difficulty_old(std::vector timestamps, std::vector cumulative_difficulties); + difficulty_type next_difficulty_old(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds); + + bool check_hash(const crypto::hash &hash, wide_difficulty_type difficulty); + wide_difficulty_type next_difficulty(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds); + uint64_t difficulty_to_boundary(wide_difficulty_type difficulty); + void difficulty_to_boundary_long(wide_difficulty_type difficulty, crypto::hash& result); +} diff --git a/src/currency_core/dispatch_core_events.h b/src/currency_core/dispatch_core_events.h new file mode 100644 index 00000000..dadff8b1 --- /dev/null +++ b/src/currency_core/dispatch_core_events.h @@ -0,0 +1,48 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2014-2015 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include "currency_basic.h" +#include "offers_service_basics.h" //TODO: point to refactoring +#include "rpc/core_rpc_server_commands_defs.h" +//#include "serialization/keyvalue_serialization_boost_variant.h" + +#define CORE_EVENT_ADD_OFFER "CORE_EVENT_ADD_OFFER" +#define CORE_EVENT_REMOVE_OFFER "CORE_EVENT_REMOVE_OFFER" +#define CORE_EVENT_UPDATE_OFFER "CORE_EVENT_UPDATE_OFFER" +#define CORE_EVENT_ADD_ALIAS "CORE_EVENT_ADD_ALIAS" +#define CORE_EVENT_UPDATE_ALIAS "CORE_EVENT_UPDATE_ALIAS" +#define CORE_EVENT_BLOCK_ADDED "CORE_EVENT_BLOCK_ADDED" + + +namespace currency +{ + typedef boost::variant core_event_v; + + struct core_event + { + std::string method; + core_event_v details; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(method) + //KV_SERIALIZE(details) + END_KV_SERIALIZE_MAP() + }; + + + + /************************************************************************/ + /* */ + /************************************************************************/ + struct i_core_event_handler + { + virtual void on_core_event(const std::string event_name, const core_event_v& e){}; + virtual void on_complete_events(){}; + virtual void on_clear_events(){}; + }; +} \ No newline at end of file diff --git a/src/currency_core/etc_custom_serialization.cpp b/src/currency_core/etc_custom_serialization.cpp new file mode 100644 index 00000000..555ec799 --- /dev/null +++ b/src/currency_core/etc_custom_serialization.cpp @@ -0,0 +1,25 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2014-2015 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "currency_format_utils.h" +#include "etc_custom_serialization.h" + +namespace bc_services +{ + std::string transform_amount_to_string(const uint64_t& a) + { +// double d = static_cast(a); +// d /= ETC_AMOUNT_DIVIDER; + return std::to_string(a);//print_money(a, ETC_AMOUNT_DIVIDER_DECIMAL_POINT); + } + + uint64_t transform_string_to_amount(const std::string& d) + { + uint64_t n = 0; + epee::string_tools::get_xtype_from_string(n, d); + return n; + } +} \ No newline at end of file diff --git a/src/currency_core/etc_custom_serialization.h b/src/currency_core/etc_custom_serialization.h new file mode 100644 index 00000000..b0269ba9 --- /dev/null +++ b/src/currency_core/etc_custom_serialization.h @@ -0,0 +1,17 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2014-2015 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include +#define ETC_AMOUNT_DIVIDER 100000000 +#define ETC_AMOUNT_DIVIDER_DECIMAL_POINT 8 + +namespace bc_services +{ + std::string transform_amount_to_string(const uint64_t& a); + uint64_t transform_string_to_amount(const std::string& a); + +} diff --git a/src/currency_core/genesis.cpp b/src/currency_core/genesis.cpp new file mode 100644 index 00000000..c3457ffc --- /dev/null +++ b/src/currency_core/genesis.cpp @@ -0,0 +1,15 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "genesis.h" + +namespace currency +{ + const genesis_tx_raw_data ggenesis_tx_raw = { { + 0xe980800500000101,0x4c8e410316deb183,0x05dd061422e91958,0x485eb197e544946e,0xd7140a7b5b9eb8de,0x808000ea57342851,0xd3530316deb183e9,0x3e9a1019308058c6,0x07729e9e4683aead,0xae8521fc934a1d79,0x80000bb75ba1dd6d,0x5b0316deb183e980,0x98baefe7be9750fe,0xa50ef15adc5af73a,0x5086ca4ebadb9e01,0x00a78f2f9069699e,0x0316deb183e98080,0xab49b3c9fa79c665,0xa7ff95caf24e03c0,0xc6633659b32c545e,0x5081ddf42a3e7cbd,0x16deb183e9808000,0x33f1751141376803,0x776c2649e24c29f8,0xa956f3ec171294b2,0x91e727347006cd50,0x8d9c4a02160800cd,0xa4cbac8dd1535e29,0xc1b12659d4ba40f8,0x1b830f7079e20e51,0x8917001563cc51fd,0x17750417bd8617c8,0x000a0e5ebd17ee6e }, + { 0x00 } }; + +} + diff --git a/src/currency_core/genesis.h b/src/currency_core/genesis.h new file mode 100644 index 00000000..1f8875f4 --- /dev/null +++ b/src/currency_core/genesis.h @@ -0,0 +1,23 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include +namespace currency +{ +#pragma pack(push, 1) + struct genesis_tx_raw_data + { + uint64_t const v[33]; + uint8_t const r[1]; + }; +#pragma pack(pop) + extern const genesis_tx_raw_data ggenesis_tx_raw; +} + + + + diff --git a/src/currency_core/genesis_acc.cpp b/src/currency_core/genesis_acc.cpp new file mode 100644 index 00000000..82d2c50b --- /dev/null +++ b/src/currency_core/genesis_acc.cpp @@ -0,0 +1,25 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "genesis_acc.h" + + +namespace currency +{ + const std::string ggenesis_tx_pub_key_str = "024a9c8d295e53d18daccba4f840bad45926b1c1510ee279700f831bfd51cc63"; + const crypto::public_key ggenesis_tx_pub_key = epee::string_tools::parse_tpod_from_hex_string(ggenesis_tx_pub_key_str); + + const genesis_tx_dictionary_entry ggenesis_dict[5] = { + { 785828676124507135ULL,1 }, + { 1231353406545874119ULL,4 }, + { 2713905913089194270ULL,3 }, + { 3738391252528226312ULL,0 }, + { 11261277230714331250ULL,2 } + }; +} + + + diff --git a/src/currency_core/genesis_acc.h b/src/currency_core/genesis_acc.h new file mode 100644 index 00000000..ec6ff29d --- /dev/null +++ b/src/currency_core/genesis_acc.h @@ -0,0 +1,50 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include +#include +#include "currency_format_utils.h" + +namespace currency +{ + + +#pragma pack(push, 1) + struct genesis_tx_dictionary_entry + { + uint64_t addr_hash; + uint64_t offset; + + bool operator< (const genesis_tx_dictionary_entry& s) const + { + return addr_hash < s.addr_hash; + } + }; +#pragma pack(pop) + extern const genesis_tx_dictionary_entry ggenesis_dict[5]; + + extern const crypto::public_key ggenesis_tx_pub_key; + + inline bool get_account_genesis_offset_by_address(const std::string& addr, uint64_t& offset) + { + genesis_tx_dictionary_entry key_entry = AUTO_VAL_INIT(key_entry); + key_entry.addr_hash = get_string_uint64_hash(addr); + + const genesis_tx_dictionary_entry* pfirst = &ggenesis_dict[0]; + const genesis_tx_dictionary_entry* plast = &ggenesis_dict[sizeof(ggenesis_dict) / sizeof(ggenesis_dict[0])]; + const genesis_tx_dictionary_entry* plower = std::lower_bound(pfirst, plast, key_entry); + if (plower == plast) + return false; + if (plower->addr_hash != key_entry.addr_hash) + return false; + offset = plower->offset; + return true; + } +} + + + + diff --git a/src/currency_core/miner.cpp b/src/currency_core/miner.cpp new file mode 100644 index 00000000..5d32c6fe --- /dev/null +++ b/src/currency_core/miner.cpp @@ -0,0 +1,361 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include +#include "misc_language.h" +#include "include_base_utils.h" + +#include "currency_format_utils.h" +#include "file_io_utils.h" +#include "common/command_line.h" +#include "string_coding.h" +#include "version.h" +#include "storages/portable_storage_template_helper.h" + +using namespace epee; + +#include "miner.h" + + + +namespace currency +{ + + namespace + { + const command_line::arg_descriptor arg_extra_messages = {"extra-messages-file", "Specify file for extra messages to include into coinbase transactions", "", true}; + const command_line::arg_descriptor arg_start_mining = {"start-mining", "Specify wallet address to mining for", "", true}; + const command_line::arg_descriptor arg_mining_threads = {"mining-threads", "Specify mining threads count", 0, true}; + const command_line::arg_descriptor arg_block_template_extra_text = { "miner-text-info", "Set block extra text info", "", true }; + } + + + miner::miner(i_miner_handler* phandler, blockchain_storage& bc):m_stop(1), + m_bc(bc), + m_template(boost::value_initialized()), + m_template_no(0), + m_diffic(0), + m_thread_index(0), + m_phandler(phandler), + m_height(0), + m_pausers_count(0), + m_threads_total(0), + m_starter_nonce(0), + m_do_print_hashrate(false), + m_do_mining(false), + m_current_hash_rate(0), + m_last_hr_merge_time(0), + m_hashes(0), + m_config(AUTO_VAL_INIT(m_config)) + { + } + //----------------------------------------------------------------------------------------------------- + miner::~miner() + { + stop(); + } + //----------------------------------------------------------------------------------------------------- + bool miner::set_block_template(const block& bl, const wide_difficulty_type& di, uint64_t height) + { + CRITICAL_REGION_LOCAL(m_template_lock); + m_template = bl; + m_diffic = di; + m_height = height; + ++m_template_no; + m_starter_nonce = crypto::rand(); + return true; + } + //----------------------------------------------------------------------------------------------------- + bool miner::on_block_chain_update() + { + if(!is_mining()) + return true; + + //here miner threads may work few rounds without + return request_block_template(); + } + //----------------------------------------------------------------------------------------------------- + bool miner::request_block_template() + { + block bl = AUTO_VAL_INIT(bl); + wide_difficulty_type di = AUTO_VAL_INIT(di); + uint64_t height = AUTO_VAL_INIT(height); + currency::blobdata extra_nonce = m_template_extra_text; + if(m_extra_messages.size() && m_config.current_extra_message_index < m_extra_messages.size()) + { + extra_nonce += std::string("|") + m_extra_messages[m_config.current_extra_message_index]; + } + if(!m_phandler->get_block_template(bl, m_mine_address, m_mine_address, di, height, extra_nonce)) + { + LOG_ERROR("Failed to get_block_template()"); + return false; + } + set_block_template(bl, di, height); + return true; + } + //----------------------------------------------------------------------------------------------------- + bool miner::on_idle() + { + m_update_block_template_interval.do_call([&](){ + if(is_mining())request_block_template(); + return true; + }); + + m_update_merge_hr_interval.do_call([&](){ + merge_hr(); + return true; + }); + + return true; + } + //----------------------------------------------------------------------------------------------------- + void miner::do_print_hashrate(bool do_hr) + { + m_do_print_hashrate = do_hr; + } + //----------------------------------------------------------------------------------------------------- + void miner::merge_hr() + { + if(m_last_hr_merge_time && is_mining()) + { + m_current_hash_rate = (m_hashes * 1000) / ((misc_utils::get_tick_count() - m_last_hr_merge_time + 1)); + } + m_last_hr_merge_time = misc_utils::get_tick_count(); + m_hashes = 0; + if(m_do_print_hashrate && is_mining()) + std::cout << "hr: " << m_current_hash_rate << ENDL; + } + //----------------------------------------------------------------------------------------------------- + void miner::init_options(boost::program_options::options_description& desc) + { + command_line::add_arg(desc, arg_extra_messages); + command_line::add_arg(desc, arg_start_mining); + command_line::add_arg(desc, arg_mining_threads); + command_line::add_arg(desc, arg_block_template_extra_text); + } + //----------------------------------------------------------------------------------------------------- + bool miner::init(const boost::program_options::variables_map& vm) + { + m_config_folder = command_line::get_arg(vm, command_line::arg_data_dir); + epee::serialization::load_t_from_json_file(m_config, m_config_folder + "/" + MINER_CONFIG_FILENAME); + + if(command_line::has_arg(vm, arg_extra_messages)) + { + std::string buff; + bool r = file_io_utils::load_file_to_string(command_line::get_arg(vm, arg_extra_messages), buff); + CHECK_AND_ASSERT_MES(r, false, "Failed to load file with extra messages: " << command_line::get_arg(vm, arg_extra_messages)); + std::vector extra_vec; + boost::split(extra_vec, buff, boost::is_any_of("\n"), boost::token_compress_on ); + m_extra_messages.resize(extra_vec.size()); + for(size_t i = 0; i != extra_vec.size(); i++) + { + string_tools::trim(extra_vec[i]); + if(!extra_vec[i].size()) + continue; + buff = string_encoding::base64_decode(extra_vec[i]); + if(buff != "0") + m_extra_messages[i] = buff; + } + LOG_PRINT_L0("Loaded " << m_extra_messages.size() << " extra messages, current index " << m_config.current_extra_message_index); + } + + if(command_line::has_arg(vm, arg_start_mining)) + { + if(!currency::get_account_address_from_str(m_mine_address, command_line::get_arg(vm, arg_start_mining))) + { + LOG_ERROR("Target account address " << command_line::get_arg(vm, arg_start_mining) << " has wrong format, starting daemon canceled"); + return false; + } + m_threads_total = 1; + m_do_mining = true; + if(command_line::has_arg(vm, arg_mining_threads)) + { + m_threads_total = command_line::get_arg(vm, arg_mining_threads); + } + } + + if (command_line::has_arg(vm, arg_block_template_extra_text)) + { + m_template_extra_text = command_line::get_arg(vm, arg_block_template_extra_text); + } + else + { + m_template_extra_text = PROJECT_VERSION_LONG; + } + return true; + } + //----------------------------------------------------------------------------------------------------- + bool miner::deinit() + { + if (!tools::create_directories_if_necessary(m_config_folder)) + { + LOG_PRINT_L0("Failed to create data directory: " << m_config_folder); + return false; + } + epee::serialization::store_t_to_json_file(m_config, m_config_folder + "/" + MINER_CONFIG_FILENAME); + return true; + } + //----------------------------------------------------------------------------------------------------- + bool miner::is_mining() + { + return !m_stop; + } + //----------------------------------------------------------------------------------------------------- + bool miner::start(const account_public_address& adr, size_t threads_count) + { + + m_mine_address = adr; + m_threads_total = static_cast(threads_count); + m_starter_nonce = crypto::rand(); + CRITICAL_REGION_LOCAL(m_threads_lock); + if(is_mining()) + { + LOG_PRINT_L0("Starting miner: miner already running"); + return false; + } + + if(!m_threads.empty()) + { + LOG_ERROR("Starting miner canceled: there are still active mining threads"); + return false; + } + + if(!m_template_no) + request_block_template();//lets update block template + + boost::interprocess::ipcdetail::atomic_write32(&m_stop, 0); + boost::interprocess::ipcdetail::atomic_write32(&m_thread_index, 0); + + for(size_t i = 0; i != threads_count; i++) + m_threads.push_back(boost::thread(boost::bind(&miner::worker_thread, this))); + + LOG_PRINT_L0("Mining has started with " << threads_count << " threads, good luck!" ) + return true; + } + //----------------------------------------------------------------------------------------------------- + uint64_t miner::get_speed() + { + if(is_mining()) + return m_current_hash_rate; + else + return 0; + } + //----------------------------------------------------------------------------------------------------- + void miner::send_stop_signal() + { + boost::interprocess::ipcdetail::atomic_write32(&m_stop, 1); + } + //----------------------------------------------------------------------------------------------------- + bool miner::stop() + { + send_stop_signal(); + CRITICAL_REGION_LOCAL(m_threads_lock); + + BOOST_FOREACH(boost::thread& th, m_threads) + th.join(); + + m_threads.clear(); + LOG_PRINT_L0("Mining has been stopped, " << m_threads.size() << " finished" ); + return true; + } + //----------------------------------------------------------------------------------------------------- + void miner::on_synchronized() + { + if(m_do_mining) + { + start(m_mine_address, m_threads_total); + } + } + //----------------------------------------------------------------------------------------------------- + void miner::pause() + { + CRITICAL_REGION_LOCAL(m_miners_count_lock); + ++m_pausers_count; + if(m_pausers_count == 1 && is_mining()) + LOG_PRINT_L2("MINING PAUSED"); + } + //----------------------------------------------------------------------------------------------------- + void miner::resume() + { + CRITICAL_REGION_LOCAL(m_miners_count_lock); + --m_pausers_count; + if(m_pausers_count < 0) + { + m_pausers_count = 0; + LOG_PRINT_RED_L0("Unexpected miner::resume() called"); + } + if(!m_pausers_count && is_mining()) + LOG_PRINT_L2("MINING RESUMED"); + } + //----------------------------------------------------------------------------------------------------- + bool miner::worker_thread() + { + uint32_t th_local_index = boost::interprocess::ipcdetail::atomic_inc32(&m_thread_index); + LOG_PRINT_L0("Miner thread was started ["<< th_local_index << "]"); + log_space::log_singletone::set_thread_log_prefix(std::string("[miner ") + std::to_string(th_local_index) + "]"); + uint64_t nonce = m_starter_nonce + th_local_index; + wide_difficulty_type local_diff = 0; + uint32_t local_template_ver = 0; + //uint64_t local_template_height = 0; + block b; + + while(!m_stop) + { + if(m_pausers_count)//anti split workaround + { + misc_utils::sleep_no_w(100); + continue; + } + + if(local_template_ver != m_template_no) + { + CRITICAL_REGION_BEGIN(m_template_lock); + b = m_template; + local_diff = m_diffic; + CRITICAL_REGION_END(); + //local_template_height = get_block_height(b); + local_template_ver = m_template_no; + nonce = m_starter_nonce + th_local_index; + } + + if(!local_template_ver)//no any set_block_template call + { + LOG_PRINT_L2("Block template not set yet"); + epee::misc_utils::sleep_no_w(1000); + continue; + } + b.nonce = nonce; + crypto::hash h = get_block_longhash(b); + + if(check_hash(h, local_diff)) + { + ++m_config.current_extra_message_index; + LOG_PRINT_GREEN("Found block for difficulty: " << local_diff, LOG_LEVEL_0); + if(!m_phandler->handle_block_found(b)) + { + --m_config.current_extra_message_index; + } + else + { + //success, let's update config + epee::serialization::store_t_to_json_file(m_config, m_config_folder + "/" + MINER_CONFIG_FILENAME); + } + } + nonce+=m_threads_total; + ++m_hashes; + } + LOG_PRINT_L0("Miner thread stopped ["<< th_local_index << "]"); + return true; + } + //----------------------------------------------------------------------------------------------------- +} + diff --git a/src/currency_core/miner.h b/src/currency_core/miner.h new file mode 100644 index 00000000..c1955684 --- /dev/null +++ b/src/currency_core/miner.h @@ -0,0 +1,133 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include +#include +#include "currency_basic.h" +#include "difficulty.h" +#include "math_helper.h" +#include "blockchain_storage.h" + +#define CURRENCY_MINER_BLOCK_BLOB_NONCE_OFFSET 1 + +namespace currency +{ + + inline uint64_t& access_nonce_in_block_blob(blobdata& bd) + { + return *reinterpret_cast(&bd[CURRENCY_MINER_BLOCK_BLOB_NONCE_OFFSET]); + } + + inline const uint64_t& access_nonce_in_block_blob(const blobdata& bd) + { + return *reinterpret_cast(&bd[CURRENCY_MINER_BLOCK_BLOB_NONCE_OFFSET]); + } + + struct i_miner_handler + { + virtual bool handle_block_found(const block& b, block_verification_context* p_verification_result = nullptr) = 0; + virtual bool get_block_template(block& b, const account_public_address& adr, const account_public_address& stakeholder_address, wide_difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce, bool pos = false, const pos_entry& pe = pos_entry()) = 0; + protected: + ~i_miner_handler(){}; + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + class miner + { + public: + miner(i_miner_handler* phandler, blockchain_storage& bc); + ~miner(); + bool init(const boost::program_options::variables_map& vm); + bool deinit(); + static void init_options(boost::program_options::options_description& desc); + bool on_block_chain_update(); + bool start(const account_public_address& adr, size_t threads_count); + uint64_t get_speed(); + void send_stop_signal(); + bool stop(); + bool is_mining(); + bool on_idle(); + void on_synchronized(); + //synchronous analog (for fast calls) + void pause(); + void resume(); + void do_print_hashrate(bool do_hr); + + inline + static bool find_nonce_for_given_block(block& bl, const wide_difficulty_type& diffic, uint64_t height) + { + blobdata bd = get_block_hashing_blob(bl); + access_nonce_in_block_blob(bd) = 0; + crypto::hash bl_hash = crypto::cn_fast_hash(bd.data(), bd.size()); + + for(; bl.nonce != std::numeric_limits::max(); bl.nonce++) + { + crypto::hash h = get_block_longhash(height, bl_hash, bl.nonce); + if(check_hash(h, diffic)) + { + LOG_PRINT_L0("Found nonce for block: " << get_block_hash(bl) << "[" << height << "]: PoW:" << h << "(diff:" << diffic << "), ts: " << bl.timestamp); + return true; + } + } + return false; + } + + private: + bool set_block_template(const block& bl, const wide_difficulty_type& diffic, uint64_t height); + bool worker_thread(); + bool request_block_template(); + void merge_hr(); + + struct miner_config + { + uint64_t current_extra_message_index; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(current_extra_message_index) + END_KV_SERIALIZE_MAP() + }; + + + volatile uint32_t m_stop; + ::critical_section m_template_lock; + block m_template; + std::atomic m_template_no; + std::atomic m_starter_nonce; + wide_difficulty_type m_diffic; + uint64_t m_height; + volatile uint32_t m_thread_index; + volatile uint32_t m_threads_total; + std::atomic m_pausers_count; + ::critical_section m_miners_count_lock; + + std::list m_threads; + ::critical_section m_threads_lock; + i_miner_handler* m_phandler; + blockchain_storage& m_bc; + account_public_address m_mine_address; + math_helper::once_a_time_seconds<5> m_update_block_template_interval; + math_helper::once_a_time_seconds<2> m_update_merge_hr_interval; + std::vector m_extra_messages; + miner_config m_config; + std::string m_config_folder; + std::string m_template_extra_text; + std::atomic m_current_hash_rate; + std::atomic m_last_hr_merge_time; + std::atomic m_hashes; + bool m_do_print_hashrate; + bool m_do_mining; + + }; +} + + + diff --git a/src/currency_core/miner_common.h b/src/currency_core/miner_common.h new file mode 100644 index 00000000..4c49e173 --- /dev/null +++ b/src/currency_core/miner_common.h @@ -0,0 +1,30 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#define SCRATCHPAD_DEFAULT_FILENAME "scratchpad.bin" +#define WILD_KECCAK_ADDENDUMS_ARRAY_SIZE 10 + +#pragma pack (push, 1) + +struct export_scratchpad_hi +{ + crypto::hash prevhash; + uint64_t height; +}; +struct export_addendums_array_entry +{ + export_scratchpad_hi prev_hi; + uint64_t add_size; +}; +struct export_scratchpad_file_header +{ + export_scratchpad_hi current_hi; + export_addendums_array_entry add_arr[WILD_KECCAK_ADDENDUMS_ARRAY_SIZE]; + uint64_t scratchpad_size; +}; +#pragma pack(pop) diff --git a/src/currency_core/offers_service_basics.h b/src/currency_core/offers_service_basics.h new file mode 100644 index 00000000..0c73d4f3 --- /dev/null +++ b/src/currency_core/offers_service_basics.h @@ -0,0 +1,128 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + + + +#include "serialization/keyvalue_serialization.h" +#include "crypto/crypto.h" +#include "etc_custom_serialization.h" +namespace bc_services +{ + /************************************************************************/ + /* offer structures */ + /************************************************************************/ + struct offer_details + { + + //fields filled in UI + uint8_t offer_type; // OFFER_TYPE_PRIMARY_TO_TARGET - 0, OFFER_TYPE_TARGET_TO_PRIMARY - 1 etc. + uint64_t amount_primary; // amount of the currency + uint64_t amount_target; // amount of other currency or goods + std::string bonus; // + std::string target; // [] currency / goods + std::string primary; // currency for goods + std::string location_country; // ex: US + std::string location_city; // ex: ChIJD7fiBh9u5kcRYJSMaMOCCwQ (google geo-autocomplete id) + std::string contacts; // [] (Skype, mail, ICQ, etc., website) + std::string comment; // [] + std::string payment_types; // []money accept type(bank transaction, internet money, cash, etc) + std::string deal_option; // []full amount, by parts + std::string category; // [] + uint8_t expiration_time; // n-days + //----------------- + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_N(offer_type, "ot") + KV_SERIALIZE_CUSTOM_N(amount_primary, std::string, bc_services::transform_amount_to_string, bc_services::transform_string_to_amount, "ap") + KV_SERIALIZE_CUSTOM_N(amount_target, std::string, bc_services::transform_amount_to_string, bc_services::transform_string_to_amount, "at") + KV_SERIALIZE_N(bonus, "b") + KV_SERIALIZE_N(target, "t") + KV_SERIALIZE_N(primary, "p") + KV_SERIALIZE_N(location_country, "lco") + KV_SERIALIZE_N(location_city, "lci") + KV_SERIALIZE_N(contacts, "cnt") + KV_SERIALIZE_N(comment, "com") + KV_SERIALIZE_N(payment_types, "pt") + KV_SERIALIZE_N(deal_option, "do") + KV_SERIALIZE_N(category, "cat") + KV_SERIALIZE_N(expiration_time, "et") + END_KV_SERIALIZE_MAP() + }; + + struct offer_details_ex : public offer_details + { + //fields contained in dictionary and also returned to UI/ + crypto::hash tx_hash; + crypto::hash tx_original_hash; + uint64_t index_in_tx; + uint64_t timestamp; //this is not kept by transaction, info filled by corresponding transaction + uint64_t fee; //value of fee to pay(or paid in case of existing offers) to rank it + crypto::public_key security; //key used for updating offer + //----------------- + + mutable bool stopped; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_POD_AS_HEX_STRING(tx_hash) + KV_SERIALIZE_POD_AS_HEX_STRING(tx_original_hash) + KV_SERIALIZE(index_in_tx) + KV_SERIALIZE(timestamp) + KV_SERIALIZE(fee) + KV_SERIALIZE_POD_AS_HEX_STRING(security) + KV_CHAIN_BASE(offer_details) + END_KV_SERIALIZE_MAP() + }; + + struct cancel_offer + { + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_POD_AS_HEX_STRING_N(tx_id, "id") + KV_SERIALIZE_N(offer_index, "oi") + KV_SERIALIZE_POD_AS_HEX_STRING_N(sig, "sig") + END_KV_SERIALIZE_MAP() + + crypto::hash tx_id; + uint64_t offer_index; + crypto::signature sig; //tx_id signed by transaction secret key + }; + + + struct update_offer + { + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_POD_AS_HEX_STRING_N(tx_id, "id") + KV_SERIALIZE_N(offer_index, "oi") + KV_SERIALIZE_POD_AS_HEX_STRING_N(sig, "sig") + KV_SERIALIZE_N(of, "of") + END_KV_SERIALIZE_MAP() + + crypto::hash tx_id; + uint64_t offer_index; + crypto::signature sig; //tx_id signed by transaction secret key + offer_details of; + }; + + struct update_offer_details + { + uint64_t wallet_id; + crypto::hash tx_id; + uint64_t no; + offer_details_ex od; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(wallet_id) + KV_SERIALIZE_POD_AS_HEX_STRING_N(tx_id, "id") + KV_SERIALIZE_N(no, "oi") + KV_SERIALIZE_N(od, "of") + END_KV_SERIALIZE_MAP() + }; + + + typedef boost::variant offers_attachment_t; +} \ No newline at end of file diff --git a/src/currency_core/offers_services_helpers.cpp b/src/currency_core/offers_services_helpers.cpp new file mode 100644 index 00000000..ba068b8d --- /dev/null +++ b/src/currency_core/offers_services_helpers.cpp @@ -0,0 +1,305 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + + +#include + +#include "string_coding.h" +#include "offers_services_helpers.h" +#include "etc_custom_serialization.h" + +#include "misc_language.h" +#include "currency_basic.h" + + +namespace bc_services +{ + std::string transform_double_to_string(const double& a) + { + return std::to_string(a); + } + + double transform_string_to_double(const std::string& d) + { + double n = 0; + epee::string_tools::get_xtype_from_string(n, d); + return n; + } + + bool order_offers_by_timestamp(const offer_details_ex* a, const offer_details_ex* b) + { + return a->timestamp < b->timestamp; + } + //------------------------------------------------------------------ + bool order_offers_by_amount_primary(const offer_details_ex* a, const offer_details_ex* b) + { + return a->amount_primary < b->amount_primary; + } + //------------------------------------------------------------------ + bool order_offers_by_amount_target(const offer_details_ex* a, const offer_details_ex* b) + { + return a->amount_target < b->amount_target; + } + //------------------------------------------------------------------ + bool order_offers_by_rate(const offer_details_ex* a, const offer_details_ex* b) + { + return calculate_offer_rate(*a) < calculate_offer_rate(*b); + } + //------------------------------------------------------------------ + bool order_offers_by_payment_types(const offer_details_ex* a, const offer_details_ex* b) + { + return a->payment_types < b->payment_types; + } + //------------------------------------------------------------------ + bool order_offers_by_contacts(const offer_details_ex* a, const offer_details_ex* b) + { + return a->contacts < b->contacts; + } + //------------------------------------------------------------------ + bool order_offers_by_location(const offer_details_ex* a, const offer_details_ex* b) + { + return a->location_city < b->location_city; + } + //------------------------------------------------------------------ + bool order_offers_by_name(const offer_details_ex* a, const offer_details_ex* b) + { + return currency::utf8_to_lower(a->target) < currency::utf8_to_lower(b->target); + } + //------------------------------------------------------------------ + std::vector gsort_offers_predicates; + bool init_vector = epee::misc_utils::static_initializer([](){ + gsort_offers_predicates.resize(ORDER_CALLBACKS_COUNT); + gsort_offers_predicates[ORDER_BY_TIMESTAMP] = &order_offers_by_timestamp; + gsort_offers_predicates[ORDER_BY_AMOUNT_PRIMARY] = &order_offers_by_amount_primary; + gsort_offers_predicates[ORDER_BY_AMOUNT_TARGET] = &order_offers_by_amount_target; + gsort_offers_predicates[ORDER_BY_AMOUNT_RATE] = &order_offers_by_rate; + gsort_offers_predicates[ORDER_BY_PAYMENT_TYPES] = &order_offers_by_payment_types; + gsort_offers_predicates[ORDER_BY_CONTACTS] = &order_offers_by_contacts; + gsort_offers_predicates[ORDER_BY_LOCATION] = &order_offers_by_location; + gsort_offers_predicates[ORDER_BY_NAME] = &order_offers_by_name; + return true; + }); + // std::locale locale_utf8; + bool init_locale = epee::misc_utils::static_initializer([](){ + setlocale(LC_ALL, ""); + return true; + }); + + + + + to_low_case_ptr_type to_low_case_external = nullptr; + + void set_external_to_low_converter(to_low_case_ptr_type cb) + { + to_low_case_external = cb; + } + + + std::wstring to_lower_local_w(const std::string& s) + { + //std::u16string a; + std::wstring ws = epee::string_encoding::utf8_to_wstring(s); + if (to_low_case_external) + return to_low_case_external(ws); + //std::transform(ws.begin(), ws.end(), ws.begin(), ::towlower); + boost::algorithm::to_lower(ws); + return ws; + } + +#define SECONDS_IN_ONE_DAY (60*60*24) + + + bool is_offer_matched_by_filter(const offer_details_ex& o, const core_offers_filter& of, uint64_t current_time) + { + if (o.stopped) + return false; + //check offer type condition + if (of.offer_type_mask) + { + switch (o.offer_type) + { + case OFFER_TYPE_PRIMARY_TO_TARGET: + if (!(of.offer_type_mask & OFFER_TYPE_MASK_PRIMARY_TO_TARGET)) + return false; + break; + case OFFER_TYPE_TARGET_TO_PRIMARY: + if (!(of.offer_type_mask & OFFER_TYPE_MASK_TARGET_TO_PRIMARY)) + return false; + break; + case OFFER_TYPE_GOODS_TO_PRIMARY: + if (!(of.offer_type_mask & OFFER_TYPE_MASK_GOODS_TO_PRIMARY)) + return false; + break; + case OFFER_TYPE_PRIMARY_TO_GOODS: + if (!(of.offer_type_mask & OFFER_TYPE_MASK_PRIMARY_TO_GOODS)) + return false; + break; + default: + return false; + } + } + + //check timestamp condition + if (of.timestamp_start && (o.timestamp < of.timestamp_start)) + return false; + if (of.timestamp_stop && (o.timestamp > of.timestamp_stop)) + return false; + + //check bonus field + if (of.bonus && o.bonus.empty()) + return false; + + //check category + if (!of.category.empty() && o.category.find(of.category) == std::string::npos) + return false; + + //check target condition + if (of.target.size() && !currency::utf8_substring_test_case_insensitive(of.target, o.target)) + return false; + + if (of.primary.size() && !currency::utf8_substring_test_case_insensitive(of.primary, o.primary)) + return false; + + + //check payment_types condition (TODO: add more complicated algo here) + if (of.payment_types.size()) + { + for (const auto& ot : of.payment_types) + { + if (std::string::npos == o.payment_types.find(ot)) + return false; + } + } + + + //check target condition + if (of.location_country.size() && (of.location_country != o.location_country)) + return false; + + //check target condition + if (of.location_city.size() && !currency::utf8_substring_test_case_insensitive(of.location_city, o.location_city)) + return false; + + //check amount + if (of.amount_low_limit && (of.amount_low_limit > o.amount_primary)) + return false; + if (of.amount_up_limit && (of.amount_up_limit < o.amount_primary)) + return false; + + double rate = ((static_cast(o.amount_target) / ETC_AMOUNT_DIVIDER)) / (static_cast(o.amount_primary) / COIN); + //check rate + if (of.rate_low_limit && (of.rate_low_limit > rate)) + return false; + if (of.rate_up_limit && (of.rate_up_limit < rate)) + return false; + + + + //check keywords + if (!of.keyword.empty()) + { + std::wstring all_in_apper; + all_in_apper += to_lower_local_w(o.bonus); + all_in_apper += to_lower_local_w(o.target); + all_in_apper += to_lower_local_w(o.location_country); + all_in_apper += to_lower_local_w(o.location_city); + all_in_apper += to_lower_local_w(o.contacts); + all_in_apper += to_lower_local_w(o.comment); + all_in_apper += to_lower_local_w(o.payment_types); + all_in_apper += to_lower_local_w(o.deal_option); + all_in_apper += to_lower_local_w(o.category); + std::wstring keyword_lowcase = to_lower_local_w(of.keyword); + if (all_in_apper.find(keyword_lowcase) == std::wstring::npos) + { + return false; + } + } + if (o.expiration_time && current_time > o.timestamp && current_time - o.timestamp > o.expiration_time*SECONDS_IN_ONE_DAY) + return false; + + + return true; + } + //-------------------------------------------------------------------------------- + bool filter_offers_list(std::list& offers, const bc_services::core_offers_filter& filter, uint64_t current_core_time) + { + + //filter + offers.remove_if([&](bc_services::offer_details_ex& o) -> bool { + return !is_offer_matched_by_filter(o, filter, current_core_time); + }); + + //sort + CHECK_AND_ASSERT_MES(filter.order_by < gsort_offers_predicates.size(), false, "Wrong cof.order_by value"); + auto cb = *gsort_offers_predicates[static_cast(filter.order_by)]; + + //sort iterators in needed way + if (!filter.reverse) + { + offers.sort([&](const bc_services::offer_details_ex& a, const bc_services::offer_details_ex& b) + { + return cb(&a, &b); + }); + } + else + { + offers.sort([&](const bc_services::offer_details_ex& a, const bc_services::offer_details_ex& b) + { + return cb(&b, &a); + }); + } + + //now cut what not needed + auto it = std::next(offers.begin(), std::min(filter.offset, offers.size())); + offers.erase(offers.begin(), it); + // cut limit + it = std::next(offers.begin(), std::min(filter.limit, offers.size())); + offers.erase(it, offers.end()); + + return true; + } + //-------------------------------------------------------------------------------- + crypto::hash offer_id_from_hash_and_index(const crypto::hash& tx_id, uint64_t index) + { + crypto::hash r = tx_id; + //xor + *(uint64_t*)&r ^= index; + return r; + } + //--------------------------------------------------------------- + crypto::hash offer_id_from_hash_and_index(const offer_id& oid) + { + return offer_id_from_hash_and_index(oid.tx_id, oid.index); + } + //--------------------------------------------------------------- + const crypto::public_key get_offer_secure_key_by_index_from_tx(const currency::transaction& tx, size_t index) + { + size_t count = 0; + for (const auto& a : tx.attachment) + { + if (a.type() == typeid(currency::tx_service_attachment)) + { + const currency::tx_service_attachment& txsa = boost::get(a); + if (txsa.service_id == BC_OFFERS_SERVICE_ID) + { + if (count != index) + { + count++; + continue; + } + + if (txsa.security.empty()) + return currency::null_pkey; + return txsa.security.back(); + } + } + } + return currency::null_pkey; + } + + +} // namespace bc_services diff --git a/src/currency_core/offers_services_helpers.h b/src/currency_core/offers_services_helpers.h new file mode 100644 index 00000000..14d6bb92 --- /dev/null +++ b/src/currency_core/offers_services_helpers.h @@ -0,0 +1,275 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include "profile_tools.h" +#include "serialization/keyvalue_serialization.h" +#include "storages/portable_storage_template_helper.h" +#include "currency_basic.h" +#include "offers_service_basics.h" +#include "currency_protocol/blobdatatype.h" +#include "zlib_helper.h" +#include "bc_offers_service_basic.h" +#include "bc_attachments_helpers.h" + +namespace bc_services +{ + + std::string transform_double_to_string(const double& a); + double transform_string_to_double(const std::string& d); + + + struct core_offers_filter + { + uint64_t order_by; + bool reverse; + uint64_t offset; + uint64_t limit; + //filter entry + uint64_t timestamp_start; + uint64_t timestamp_stop; + uint64_t offer_type_mask; + uint64_t amount_low_limit; + uint64_t amount_up_limit; + double rate_low_limit; + double rate_up_limit; + std::list payment_types; + std::string location_country; + std::string location_city; + std::string target; + std::string primary; + bool bonus; + std::string category; + std::string keyword; + bool fake; + uint64_t current_time; + + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(order_by) + KV_SERIALIZE(reverse) + KV_SERIALIZE(offset) + KV_SERIALIZE(limit) + KV_SERIALIZE(timestamp_start) + KV_SERIALIZE(timestamp_stop) + KV_SERIALIZE(offer_type_mask) + KV_SERIALIZE(amount_low_limit) + KV_SERIALIZE(amount_up_limit) + KV_SERIALIZE_CUSTOM(rate_low_limit, std::string, bc_services::transform_double_to_string, bc_services::transform_string_to_double) + KV_SERIALIZE_CUSTOM(rate_up_limit, std::string, bc_services::transform_double_to_string, bc_services::transform_string_to_double) + KV_SERIALIZE(payment_types) + KV_SERIALIZE(location_country) + KV_SERIALIZE(location_city) + KV_SERIALIZE(target) + KV_SERIALIZE(primary) + KV_SERIALIZE(bonus) + KV_SERIALIZE(category) + KV_SERIALIZE(keyword) + KV_SERIALIZE(fake) + END_KV_SERIALIZE_MAP() + }; + + + struct offer_id + { + crypto::hash tx_id; + uint64_t index; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_POD_AS_HEX_STRING(tx_id) + KV_SERIALIZE(index) + END_KV_SERIALIZE_MAP() + }; + +#define ORDER_BY_TIMESTAMP 0 +#define ORDER_BY_AMOUNT_PRIMARY 1 +#define ORDER_BY_AMOUNT_TARGET 2 +#define ORDER_BY_AMOUNT_RATE 3 +#define ORDER_BY_PAYMENT_TYPES 4 +#define ORDER_BY_CONTACTS 5 +#define ORDER_BY_LOCATION 6 +#define ORDER_BY_NAME 7 + +#define ORDER_CALLBACKS_COUNT 8 + + + typedef std::wstring(*to_low_case_ptr_type)(const std::wstring& soruce); + + void set_external_to_low_converter(to_low_case_ptr_type cb); + + typedef bool(*sort_offers_func_type)(const offer_details_ex* a, const offer_details_ex* b); + extern std::vector gsort_offers_predicates; + bool is_offer_matched_by_filter(const offer_details_ex& o, const core_offers_filter& of, uint64_t currnet_time); + bool filter_offers_list(std::list& offers, const core_offers_filter& filter, uint64_t current_core_time); + crypto::hash offer_id_from_hash_and_index(const crypto::hash& tx_id, uint64_t index); + crypto::hash offer_id_from_hash_and_index(const offer_id& oid); + const crypto::public_key get_offer_secure_key_by_index_from_tx(const currency::transaction& tx, size_t index); + + inline double calculate_offer_rate(const offer_details& od) + { + return od.amount_primary > 0 ? static_cast(od.amount_target) / od.amount_primary : 0; + } + + template + void put_offer_into_attachment(const offer_instruction_t& oi, std::vector& att_container) + { + std::string json_buff; + currency::tx_service_attachment att = AUTO_VAL_INIT(att); + + bool r = bc_services::pack_attachment_as_gzipped_json(oi, att); + CHECK_AND_ASSERT_MES(r, void(), "Failed to pack_attachment_as_gzipped_json"); + + att.service_id = BC_OFFERS_SERVICE_ID; + if (typeid(offer_instruction_t) == typeid(offer_details)) + { + att.instruction = BC_OFFERS_SERVICE_INSTRUCTION_ADD; + } + else if (typeid(offer_instruction_t) == typeid(update_offer)) + { + att.instruction = BC_OFFERS_SERVICE_INSTRUCTION_UPD; + } + else if (typeid(offer_instruction_t) == typeid(cancel_offer)) + { + att.instruction = BC_OFFERS_SERVICE_INSTRUCTION_DEL; + } + else + { + LOG_ERROR("Filed to pack tx_service_attachment in bc_offers_service, unknown_type: " << typeid(offer_instruction_t).name()); + return; + } + + //if att.security vector contain public_key then transaction constructor put there correct public_key related with one time transaction keys + if (att.instruction == BC_OFFERS_SERVICE_INSTRUCTION_ADD || att.instruction == BC_OFFERS_SERVICE_INSTRUCTION_UPD) + att.security.push_back(currency::null_pkey); + + att_container.push_back(att); + } + + inline currency::blobdata make_offer_sig_blob(const update_offer& uo) + { + currency::blobdata bd; + epee::string_tools::apped_pod_to_strbuff(bd, uo.tx_id); + epee::string_tools::apped_pod_to_strbuff(bd, uo.offer_index); + bd += epee::serialization::store_t_to_binary(uo.of); + return bd; + } + + inline currency::blobdata make_offer_sig_blob(const cancel_offer& co) + { + currency::blobdata bd; + epee::string_tools::apped_pod_to_strbuff(bd, co.tx_id); + epee::string_tools::apped_pod_to_strbuff(bd, co.offer_index); + return bd; + } + + //---------------------------------------------------------------------------------------------------- + template + bool extract_type_and_add(const std::string& body, t_srv_attachments_container& srv_cnt) + { + std::string json_buff; + if (!epee::zlib_helper::unpack(body, json_buff)) + { + LOG_ERROR("Filed to unpack tx_service_attachment in bc_offers_service, tx_id"); + return false; + } + t_contained_type obj = AUTO_VAL_INIT(obj); + bool r = epee::serialization::load_t_from_json(obj, json_buff); + if (!r) + { + LOG_ERROR("Filed to load json from tx_service_attachment in bc_offers_service, body: " << body); + return false; + } + srv_cnt.push_back(obj); + return true; + } + //---------------------------------------------------------------------------------------------------- + template + void extract_market_instructions(t_srv_attachments_container& cnt, const t_tx_attachments_container& raw_att) + { + PROFILE_FUNC("bc_service::extract_market_instructions"); + for (auto& att : raw_att) + { + if (att.type() == typeid(currency::tx_service_attachment)) + { + const currency::tx_service_attachment& sa = boost::get(att); + if (sa.service_id == BC_OFFERS_SERVICE_ID) + { + if (sa.instruction == BC_OFFERS_SERVICE_INSTRUCTION_ADD) + { + extract_type_and_add(sa.body, cnt); + } + else if (sa.instruction == BC_OFFERS_SERVICE_INSTRUCTION_UPD) + { + extract_type_and_add(sa.body, cnt); + } + else if (sa.instruction == BC_OFFERS_SERVICE_INSTRUCTION_DEL) + { + extract_type_and_add(sa.body, cnt); + } + } + } + } + } + + + + +#define OFFER_TYPE_PRIMARY_TO_TARGET 0 +#define OFFER_TYPE_TARGET_TO_PRIMARY 1 +#define OFFER_TYPE_GOODS_TO_PRIMARY 2 +#define OFFER_TYPE_PRIMARY_TO_GOODS 3 + +#define OFFER_TYPE_MASK_PRIMARY_TO_TARGET 0x00000001 +#define OFFER_TYPE_MASK_TARGET_TO_PRIMARY 0x00000002 +#define OFFER_TYPE_MASK_GOODS_TO_PRIMARY 0x00000004 +#define OFFER_TYPE_MASK_PRIMARY_TO_GOODS 0x00000008 + +#define OFFER_TYPE_UNDEFINED 255 + + + struct offer_details_ex_with_hash : public offer_details_ex + { + crypto::hash h; + mutable std::string nxt_offer; //in case of updated offer + }; + + typedef offer_details_ex_with_hash odeh; + + inline crypto::hash extract_id(const odeh& v) { return v.h; } + inline uint64_t extrct_timestamp(const odeh& v) { return v.timestamp; } + inline uint64_t extract_amount_primary(const odeh& v) { return v.amount_primary; } + inline uint64_t extract_amount_target(const odeh& v) { return v.amount_target; } + inline double extract_rate(const odeh& v) { return calculate_offer_rate(v); } + inline size_t extract_payment_types(const odeh& v) { return v.payment_types.size(); } + inline std::string extract_contacts(const odeh& v) { return v.contacts; } + inline std::string extract_location(const odeh& v) { return currency::utf8_to_lower(v.location_country + v.location_city); } + inline std::string extract_name(const odeh& v) { return currency::utf8_to_lower(v.target); } + + template + struct sort_id_to_type + {}; + +#define TAG_NAME(tag_name) struct tag_name{}; + TAG_NAME(by_id); + TAG_NAME(by_timestamp); + TAG_NAME(by_amount_primary); + TAG_NAME(by_amount_target); + TAG_NAME(by_rate); + TAG_NAME(by_payment_types); + TAG_NAME(by_contacts); + TAG_NAME(by_location); + TAG_NAME(by_name); +#undef TAG_NAME + + template<> struct sort_id_to_type { typedef by_timestamp index_type; }; + template<> struct sort_id_to_type { typedef by_amount_primary index_type; }; + template<> struct sort_id_to_type { typedef by_amount_target index_type; }; + template<> struct sort_id_to_type { typedef by_rate index_type; }; + template<> struct sort_id_to_type { typedef by_payment_types index_type; }; + template<> struct sort_id_to_type { typedef by_contacts index_type; }; + template<> struct sort_id_to_type { typedef by_location index_type; }; + template<> struct sort_id_to_type { typedef by_name index_type; }; +} diff --git a/src/currency_core/tx_pool.cpp b/src/currency_core/tx_pool.cpp new file mode 100644 index 00000000..f8165353 --- /dev/null +++ b/src/currency_core/tx_pool.cpp @@ -0,0 +1,1354 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include + +#include "common/db_backend_lmdb.h" +#include "tx_pool.h" +#include "currency_boost_serialization.h" +#include "currency_core/currency_config.h" +#include "blockchain_storage.h" +#include "common/boost_serialization_helper.h" +#include "common/int-util.h" +#include "misc_language.h" +#include "warnings.h" +#include "crypto/hash.h" +#include "offers_service_basics.h" +#include "profile_tools.h" + +DISABLE_VS_WARNINGS(4244 4345 4503) //'boost::foreach_detail_::or_' : decorated name length exceeded, name was truncated + +#define TRANSACTION_POOL_CONTAINER_TRANSACTIONS "transactions" +#define TRANSACTION_POOL_CONTAINER_CANCEL_OFFER_HASH "cancel_offer_hash" +#define TRANSACTION_POOL_CONTAINER_BLACK_TX_LIST "black_tx_list" +#define TRANSACTION_POOL_CONTAINER_ALIAS_NAMES "alias_names" +#define TRANSACTION_POOL_CONTAINER_ALIAS_ADDRESSES "alias_addresses" +#define TRANSACTION_POOL_CONTAINER_KEY_IMAGES "key_images" +#define TRANSACTION_POOL_CONTAINER_SOLO_OPTIONS "solo" +#define TRANSACTION_POOL_MAJOR_COMPATIBILITY_VERSION BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION + 1 + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL "tx_pool" +ENABLE_CHANNEL_BY_DEFAULT("tx_pool"); + +namespace currency +{ + //--------------------------------------------------------------------------------- + tx_memory_pool::tx_memory_pool(blockchain_storage& bchs, i_currency_protocol* pprotocol) : + m_blockchain(bchs), + m_pprotocol(pprotocol), + m_db(std::shared_ptr(new tools::db::lmdb_db_backend), m_dummy_rw_lock), + m_db_transactions(m_db), + m_db_cancel_offer_hash(m_db), + m_db_black_tx_list(m_db), + m_db_solo_options(m_db), + m_db_key_images_set(m_db), + m_db_alias_names(m_db), + m_db_alias_addresses(m_db), + m_db_storage_major_compatibility_version(TRANSACTION_POOL_MAJOR_COMPATIBILITY_VERSION, m_db_solo_options) + { + + } + + bool tx_memory_pool::is_valid_contract_finalization_tx(const transaction &tx)const + { + if (tx.vin.size() != 1 || tx.vin[0].type() != typeid(txin_multisig)) + { + return false; + } + + const txin_multisig& ms_in = boost::get(tx.vin[0]); + crypto::hash related_tx_id = null_hash; uint64_t out_no = 0; + if (!m_blockchain.get_multisig_id_details(ms_in.multisig_out_id, related_tx_id, out_no)) + { + LOG_ERROR("Related multisig tx not found, multisig_out_id=" << ms_in.multisig_out_id); + return false; + } + + auto related_tx_ptr = m_blockchain.get_tx_chain_entry(related_tx_id); + if (!related_tx_ptr) + { + LOG_ERROR("Tx " << related_tx_id << " related to multisig id " << ms_in.multisig_out_id + << "(discovered by reviewing tx " << get_transaction_hash(tx) <<") tx not found in blockchain, multisig_out_id=" << ms_in.multisig_out_id); + return false; + } + + if (get_tx_fee(tx) < get_tx_fee(related_tx_ptr->tx)) + { + LOG_ERROR("Tx " << get_transaction_hash(tx) << " fee=" << get_tx_fee(tx) << " less then parent multisig tx " << related_tx_id << " fee= " << get_tx_fee(related_tx_ptr->tx)); + return false; + } + + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::add_tx(const transaction &tx, const crypto::hash &id, uint64_t blob_size, tx_verification_context& tvc, bool kept_by_block, bool from_core) + { + TIME_MEASURE_START_PD(tx_processing_time); + TIME_MEASURE_START_PD(check_inputs_types_supported_time); + if(!check_inputs_types_supported(tx)) + { + tvc.m_verification_failed = true; + return false; + } + TIME_MEASURE_FINISH_PD(check_inputs_types_supported_time); + + TIME_MEASURE_START_PD(expiration_validate_time); + if (!from_core && !kept_by_block && m_blockchain.is_tx_expired(tx)) + { + uint64_t tx_expiration_time = get_tx_expiration_time(tx); + uint64_t ts_median = m_blockchain.get_tx_expiration_median(); + LOG_PRINT_L0("transaction " << id << " is expired, rejected by tx pool (tx timestamp: " << tx_expiration_time << " - " << TX_EXPIRATION_MEDIAN_SHIFT << " (median shift) = " << + tx_expiration_time - TX_EXPIRATION_MEDIAN_SHIFT << ", blockchain timestamp median: " << ts_median << + ", diff: " << epee::misc_utils::get_time_interval_string(ts_median + TX_EXPIRATION_MEDIAN_SHIFT - tx_expiration_time) << ")"); + tvc.m_verification_failed = true; + return false; + } + TIME_MEASURE_FINISH_PD(expiration_validate_time); + + TIME_MEASURE_START_PD(validate_amount_time); + uint64_t inputs_amount = 0; + if(!get_inputs_money_amount(tx, inputs_amount)) + { + tvc.m_verification_failed = true; + return false; + } + + CHECK_AND_ASSERT_MES_CUSTOM(tx.vout.size() <= CURRENCY_TX_MAX_ALLOWED_OUTS, false, tvc.m_verification_failed = true, "transaction has too many outs = " << tx.vout.size()); + + uint64_t outputs_amount = get_outs_money_amount(tx); + + if(outputs_amount > inputs_amount) + { + LOG_PRINT_L0("transaction use more money then it has: use " << outputs_amount << ", have " << inputs_amount); + tvc.m_verification_failed = true; + return false; + } + TIME_MEASURE_FINISH_PD(validate_amount_time); + + TIME_MEASURE_START_PD(validate_alias_time); + if (!from_core && !validate_alias_info(tx, kept_by_block)) + { + LOG_PRINT_RED_L0("validate_alias_info failed"); + tvc.m_verification_failed = true; + return false; + } + TIME_MEASURE_FINISH_PD(validate_alias_time); + + TIME_MEASURE_START_PD(check_keyimages_ws_ms_time); + //check key images for transaction if it is not kept by block + if(!from_core && !kept_by_block) + { + if(have_tx_keyimges_as_spent(tx)) + { + LOG_ERROR("Transaction with id= "<< id << " used already spent key images"); + tvc.m_verification_failed = true; + return false; + } + + //transaction spam protection, soft rule + uint64_t tx_fee = inputs_amount - outputs_amount; + if (tx_fee < m_blockchain.get_core_runtime_config().tx_pool_min_fee) + { + //exception for cancel offer transactions + if (process_cancel_offer_rules(tx)) + { + // this tx has valid offer cansellation instructions and thus can go for free + // check soft size constrain + if (blob_size > CURRENCY_FREE_TX_MAX_BLOB_SIZE) + { + LOG_ERROR("Blob size (" << blob_size << ") << exceeds limit for transaction " << id << " that contains offer cancellation and has smaller fee (" << tx_fee << ") than expected"); + tvc.m_verification_failed = true; + return false; + } + } + else if (is_valid_contract_finalization_tx(tx)) + { + // that means tx has less fee then allowed by current tx pull rules, but this transaction is actually + // a finalization of contract, and template of this contract finalization tx was prepared actually before + // fee rules had been changed, so it's ok, let it in. + } + else + { + // this tx has no fee OR invalid offer cancellations instructions -- so the exceptions of zero fee is not applicable + LOG_ERROR("Transaction with id= " << id << " has too small fee: " << tx_fee << ", expected fee: " << m_blockchain.get_core_runtime_config().tx_pool_min_fee); + tvc.m_verification_failed = false; + tvc.m_should_be_relayed = false; + tvc.m_added_to_pool = false; + return true; + } + } + + // check tx multisig inputs/output against tx in the pool and in the blockchain + if (!check_tx_multisig_ins_and_outs(tx, true)) + { + tvc.m_verification_failed = true; + return false; + } + } + TIME_MEASURE_FINISH_PD(check_keyimages_ws_ms_time); + + TIME_MEASURE_START_PD(check_inputs_time); + crypto::hash max_used_block_id = null_hash; + uint64_t max_used_block_height = 0; + bool ch_inp_res = m_blockchain.check_tx_inputs(tx, id, max_used_block_height, max_used_block_id); + if (!ch_inp_res && !kept_by_block && !from_core) + { + LOG_PRINT_L0("tx used wrong inputs, rejected"); + tvc.m_verification_failed = true; + return false; + } + TIME_MEASURE_FINISH_PD(check_inputs_time); + + do_insert_transaction(tx, id, blob_size, kept_by_block, inputs_amount - outputs_amount, ch_inp_res ? max_used_block_id : null_hash, ch_inp_res ? max_used_block_height : 0); + + TIME_MEASURE_FINISH_PD(tx_processing_time); + tvc.m_added_to_pool = true; + tvc.m_should_be_relayed = ch_inp_res; // relay tx only if it has valid inputs (i.e. do not relay kept_by_block tx with wrong inputs) + tvc.m_verification_impossible = !ch_inp_res; // mark 'kept_by_block' tx with wrong inputs as impossible to be verified + tvc.m_verification_failed = false; + //succeed + + LOG_PRINT_L2("[TX_POOL ADD_TX] timing(micsec) : " << print_fixed_decimal_point(tx_processing_time, 3) + << "("<< m_performance_data.check_inputs_types_supported_time.get_last_val() + << "/" << m_performance_data.expiration_validate_time.get_last_val() + << "/" << m_performance_data.validate_amount_time.get_last_val() + << "/" << m_performance_data.validate_alias_time.get_last_val() + << "/" << m_performance_data.check_keyimages_ws_ms_time.get_last_val() + << "/" << m_performance_data.check_inputs_time.get_last_val() + << "/" << m_performance_data.begin_tx_time.get_last_val() + << "/" << m_performance_data.update_db_time.get_last_val() + << "/" << m_performance_data.db_commit_time.get_last_val() << ")" ); + + return true; + } + //--------------------------------------------------------------------------------- +#define LOCAL_READONLY_TRANSACTION() \ + m_db.begin_readonly_transaction(); \ + misc_utils::auto_scope_leave_caller db_tx_closer = misc_utils::create_scope_leave_handler([&]() \ + { \ + m_db.commit_transaction(); \ + }); + + + bool tx_memory_pool::do_insert_transaction(const transaction &tx, const crypto::hash &id, uint64_t blob_size, bool kept_by_block, uint64_t fee, const crypto::hash& max_used_block_id, uint64_t max_used_block_height) + { + TIME_MEASURE_START_PD(begin_tx_time); + m_db.begin_transaction(); + TIME_MEASURE_FINISH_PD(begin_tx_time); + + TIME_MEASURE_START_PD(update_db_time); + misc_utils::auto_scope_leave_caller seh = misc_utils::create_scope_leave_handler([&]() + { + TIME_MEASURE_START_PD(db_commit_time); + m_db.commit_transaction(); + TIME_MEASURE_FINISH_PD(db_commit_time); + + }); + //CHECK_AND_ASSERT_MES_CUSTOM(!m_db_transactions.get(id), false, (tvc.m_added_to_pool = false, tvc.m_verification_failed = true), "internal error: failed to add transaction " << id << " to the pool as it already exists"); + tx_details td = AUTO_VAL_INIT(td); + td.blob_size = blob_size; + td.tx = tx; + td.kept_by_block = kept_by_block; + td.fee = fee; + td.max_used_block_id = max_used_block_id; + td.max_used_block_height = max_used_block_height; + td.last_failed_height = 0; + td.last_failed_id = null_hash; + td.receive_time = get_core_time(); + + m_db_transactions.set(id, td); + on_tx_add(tx, kept_by_block); + + TIME_MEASURE_FINISH_PD(update_db_time); + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::check_is_taken(const crypto::hash& id) const + { + CRITICAL_REGION_LOCAL(m_taken_txs_lock); + return m_taken_txs.count(id) ? true : false; + } + //--------------------------------------------------------------------------------- + void tx_memory_pool::set_taken(const crypto::hash& id) + { + CRITICAL_REGION_LOCAL(m_taken_txs_lock); + m_taken_txs.insert(id); + } + //--------------------------------------------------------------------------------- + void tx_memory_pool::reset_all_taken() + { + CRITICAL_REGION_LOCAL(m_taken_txs_lock); + m_taken_txs.clear(); + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::process_cancel_offer_rules(const transaction& tx) + { + //TODO: this code doesn't take into account offer id in source tx + //TODO: add scan on tx size for free transaction here + m_db_transactions.begin_transaction(); + misc_utils::auto_scope_leave_caller seh = misc_utils::create_scope_leave_handler([&](){m_db_transactions.commit_transaction(); }); + + + size_t serv_att_count = 0; + std::list co_list; + for (const auto& a: tx.attachment) + { + if (a.type() == typeid(tx_service_attachment)) + { + const tx_service_attachment& srv_at = boost::get(a); + if (srv_at.service_id == BC_OFFERS_SERVICE_ID && srv_at.instruction == BC_OFFERS_SERVICE_INSTRUCTION_DEL) + { + if (!m_blockchain.validate_tx_service_attachmens_in_services(srv_at, serv_att_count, tx)) + { + LOG_ERROR("validate_tx_service_attachmens_in_services failed for an offer cancellation transaction"); + return false; + } + bc_services::extract_type_and_add(srv_at.body, co_list); + if (m_db_cancel_offer_hash.get(co_list.back().tx_id)) + { + LOG_ERROR("cancellation of offer " << co_list.back().tx_id << " has already been processed earlier; zero fee is disallowed"); + return false; + } + } + serv_att_count++; + } + } + if (!co_list.size()) + { + LOG_PRINT_L1("No cancel offers found"); + return false; + } + + for (auto co : co_list) + { + m_db_cancel_offer_hash.set(co.tx_id, true); + } + + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::unprocess_cancel_offer_rules(const transaction& tx) + { + m_db_transactions.begin_transaction(); + misc_utils::auto_scope_leave_caller seh = misc_utils::create_scope_leave_handler([&](){m_db_transactions.commit_transaction(); }); + + std::list co_list; + for (const auto& a : tx.attachment) + { + if (a.type() == typeid(tx_service_attachment)) + { + const tx_service_attachment& srv_at = boost::get(a); + if (srv_at.service_id == BC_OFFERS_SERVICE_ID && srv_at.instruction == BC_OFFERS_SERVICE_INSTRUCTION_DEL) + { + co_list.clear(); + bc_services::extract_type_and_add(srv_at.body, co_list); + if (!co_list.size()) + return false; + auto vptr = m_db_cancel_offer_hash.find(co_list.back().tx_id); + if (vptr == m_db_cancel_offer_hash.end()) + return false; + m_db_cancel_offer_hash.erase(co_list.back().tx_id); + } + } + } + return true; + } +// //--------------------------------------------------------------------------------- + bool tx_memory_pool::get_aliases_from_tx_pool(std::list& aliases)const + { + + //TODO: OPTIMIZATION put cache here!!!!! + + m_db_transactions.enumerate_items([&](uint64_t i, const crypto::hash& h, const tx_details &tx_entry) + { + tx_extra_info ei = AUTO_VAL_INIT(ei); + bool r = parse_and_validate_tx_extra(tx_entry.tx, ei); + CHECK_AND_ASSERT_MES(r, false, "failed to validate transaction extra on unprocess_blockchain_tx_extra"); + if (ei.m_alias.m_alias.size()) + aliases.push_back(ei.m_alias); + + return true; + }); + return true; + + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::get_aliases_from_tx_pool(std::map& aliases)const + { + std::list aliases_local; + get_aliases_from_tx_pool(aliases_local); + + for (auto& alias_info : aliases_local) + { + ++aliases[alias_info.m_alias]; + } + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::validate_alias_info(const transaction& tx, bool is_in_block) const + { + LOCAL_READONLY_TRANSACTION(); + extra_alias_entry eai = AUTO_VAL_INIT(eai); + if (get_type_in_variant_container(tx.extra, eai)) + { + //check in blockchain + extra_alias_entry eai2 = AUTO_VAL_INIT(eai2); + bool already_have_alias_registered = m_blockchain.get_alias_info(eai.m_alias, eai2); + //size_t alias_size = eai.m_alias.size(); + + if (!is_in_block && !eai.m_sign.size() && already_have_alias_registered) + { + LOG_PRINT_L0("Alias \"" << eai.m_alias << "\" already registered in blockchain, transaction rejected"); + return false; + } + + std::string prev_alias = m_blockchain.get_alias_by_address(eai.m_address); + if (!is_in_block && !eai.m_sign.size() && + prev_alias.size()) + { + LOG_PRINT_L0("Address \"" << get_account_address_as_str(eai.m_address) + << "\" already registered with \""<< prev_alias + << "\" aliass in blockchain (new alias: \"" << eai.m_alias << "\"), transaction rejected"); + return false; + } + + if (!is_in_block) + { + if (m_db_alias_names.get(eai.m_alias)) + { + LOG_PRINT_L0("Alias \"" << eai.m_alias << "\" already in transaction pool, transaction rejected"); + return false; + } + if (m_db_alias_addresses.get(eai.m_address)) + { + LOG_PRINT_L0("Alias \"" << eai.m_alias << "\" already in transaction pool by it's address(" << get_account_address_as_str(eai.m_address) << ") , transaction rejected"); + return false; + } + //validate alias reward + if (!m_blockchain.prevalidate_alias_info(tx, eai)) + { + LOG_PRINT_L0("Alias \"" << eai.m_alias << "\" reward validation failed, transaction rejected"); + return false; + } + } + + + } + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::add_tx(const transaction &tx, tx_verification_context& tvc, bool kept_by_block, bool from_core) + { + crypto::hash h = null_hash; + uint64_t blob_size = 0; + + get_transaction_hash(tx, h, blob_size); + return add_tx(tx, h, blob_size, tvc, kept_by_block, from_core); + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::take_tx(const crypto::hash &id, transaction &tx, size_t& blob_size, uint64_t& fee) + { + + m_db_transactions.begin_transaction(); + misc_utils::auto_scope_leave_caller seh = misc_utils::create_scope_leave_handler([&](){m_db_transactions.commit_transaction();}); + + auto txe_tr = m_db_transactions.find(id); + if (txe_tr == m_db_transactions.end()) + return false; + + tx = txe_tr->tx; + blob_size = txe_tr->blob_size; + fee = txe_tr->fee; + unprocess_cancel_offer_rules(txe_tr->tx); + m_db_transactions.erase(id); + on_tx_remove(tx, txe_tr->kept_by_block); + set_taken(id); + return true; + } + //--------------------------------------------------------------------------------- + void tx_memory_pool::on_idle() + { + m_remove_stuck_tx_interval.do_call([this](){return remove_stuck_transactions();}); + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::remove_stuck_transactions() + { + if (!CRITICAL_SECTION_TRY_LOCK(m_remove_stuck_txs_lock)) + return true; + + CRITICAL_REGION_LOCAL(m_remove_stuck_txs_lock); + CRITICAL_SECTION_UNLOCK(m_remove_stuck_txs_lock);// release try_lock iteration + + m_db_transactions.begin_transaction(); + misc_utils::auto_scope_leave_caller seh = misc_utils::create_scope_leave_handler([&](){m_db_transactions.commit_transaction(); }); + + struct tx_to_delete_entry + { + tx_to_delete_entry(const crypto::hash &hash, const transaction &tx, bool kept_by_block) + : hash(hash), tx(tx), kept_by_block(kept_by_block) + {} + crypto::hash hash; + transaction tx; + bool kept_by_block; + }; + + std::vector to_delete; + + const uint64_t tx_expiration_ts_median = m_blockchain.get_tx_expiration_median(); + m_db_transactions.enumerate_items([&](uint64_t i, const crypto::hash& h, const tx_details &tx_entry) + { + //never remove transactions which related to alt blocks, + //or we can get network split as a worst case (impossible to switch to + //altchain if it won, and node stuck forever). + if (m_blockchain.is_tx_related_to_altblock(h)) + return true; + + // maximum age check - remove too old + uint64_t tx_age = get_core_time() - tx_entry.receive_time; + if ((tx_age > CURRENCY_MEMPOOL_TX_LIVETIME )) + { + + LOG_PRINT_L0("Tx " << h << " removed from tx pool, reason: outdated, age: " << tx_age); + to_delete.push_back(tx_to_delete_entry(h, tx_entry.tx, tx_entry.kept_by_block)); + } + + // expiration time check - remove expired + if (is_tx_expired(tx_entry.tx, tx_expiration_ts_median) ) + { + LOG_PRINT_L0("Tx " << h << " removed from tx pool, reason: expired, expiration time: " << get_tx_expiration_time(tx_entry.tx) << ", blockchain median: " << tx_expiration_ts_median); + to_delete.push_back(tx_to_delete_entry(h, tx_entry.tx, tx_entry.kept_by_block)); + } + + return true; + }); + + for (auto& e : to_delete) + { + m_db_transactions.erase(e.hash); + on_tx_remove(e.tx, e.kept_by_block); + } + + + return true; + } + //--------------------------------------------------------------------------------- + size_t tx_memory_pool::get_transactions_count() const + { + return m_db_transactions.size(); + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::get_transactions(std::list& txs) const + { + m_db_transactions.enumerate_items([&](uint64_t i, const crypto::hash& h, const tx_details &tx_entry) + { + txs.push_back(tx_entry.tx); + return true; + }); + + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::get_all_transactions_details(std::list& txs) const + { + m_db_transactions.enumerate_items([&](uint64_t i, const crypto::hash& h, const tx_details &tx_entry) + { + txs.push_back(tx_rpc_extended_info()); + tx_rpc_extended_info& trei = txs.back(); + trei.blob_size = tx_entry.blob_size; + fill_tx_rpc_details(trei, tx_entry.tx, nullptr, h, tx_entry.receive_time, true); + return true; + }); + + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::get_all_transactions_brief_details(std::list& txs) const + { + m_db_transactions.enumerate_items([&](uint64_t i, const crypto::hash& h, const tx_details &tx_entry) + { + txs.push_back(tx_rpc_brief_info()); + tx_rpc_brief_info& trbi = txs.back(); + trbi.id = epee::string_tools::pod_to_hex(h); + trbi.fee = tx_entry.fee; + trbi.sz = tx_entry.blob_size; + trbi.total_amount = get_outs_money_amount(tx_entry.tx); + return true; + }); + + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::get_all_transactions_list(std::list& txs)const + { + m_db_transactions.enumerate_items([&](uint64_t i, const crypto::hash& h, const tx_details &tx_entry) + { + txs.push_back(epee::string_tools::pod_to_hex(h)); + return true; + }); + + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::get_transactions_details(const std::list& ids, std::list& txs) const + { + for (auto& id_str: ids) + { + crypto::hash id = null_hash; + if (!epee::string_tools::hex_to_pod(id_str, id)) + { + LOG_ERROR("Failed to parse id in list: " << id_str); + return false; + } + + auto ptei = m_db_transactions.get(id); + if (!ptei) + return false; + + txs.push_back(tx_rpc_extended_info()); + tx_rpc_extended_info& trei = txs.back(); + trei.blob_size = ptei->blob_size; + fill_tx_rpc_details(trei, ptei->tx, nullptr, id, ptei->receive_time, false); + } + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::get_transactions_brief_details(const std::list& ids, std::list& txs)const + { + LOCAL_READONLY_TRANSACTION(); + for (auto& id_str : ids) + { + crypto::hash id = null_hash; + if (!epee::string_tools::hex_to_pod(id_str, id)) + { + LOG_ERROR("Failed to parse id in list: " << id_str); + return false; + } + + auto ptei = m_db_transactions.get(id); + if (!ptei) + return false; + + txs.push_back(tx_rpc_brief_info()); + tx_rpc_brief_info& trbi = txs.back(); + trbi.sz = ptei->blob_size; + trbi.id = id_str; + trbi.fee = ptei->fee; + trbi.total_amount = get_outs_money_amount(ptei->tx); + } + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::get_transaction_details(const crypto::hash& id, tx_rpc_extended_info& trei) const + { + auto ptei = m_db_transactions.get(id); + if (!ptei) + return false; + + fill_tx_rpc_details(trei, ptei->tx, nullptr, id, ptei->receive_time, false); + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::get_transaction(const crypto::hash& id, transaction& tx) const + { + auto tx_ptr = m_db_transactions.find(id); + if (tx_ptr == m_db_transactions.end()) + return false; + tx = tx_ptr->tx; + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::get_transaction(const crypto::hash& id, tx_details& txd) const + { + auto tx_ptr = m_db_transactions.find(id); + if (tx_ptr == m_db_transactions.end()) + return false; + txd = *tx_ptr; + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::on_blockchain_inc(uint64_t new_block_height, const crypto::hash& top_block_id) + { + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::on_blockchain_dec(uint64_t new_block_height, const crypto::hash& top_block_id) + { + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::on_finalize_db_transaction() + { + reset_all_taken(); + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::set_protocol(i_currency_protocol* pprotocol) + { + m_pprotocol = pprotocol; + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::force_relay_pool() const + { + LOG_PRINT_GREEN("Preparing relay message...", LOG_LEVEL_0); + NOTIFY_NEW_TRANSACTIONS::request r = AUTO_VAL_INIT(r); + + m_db_transactions.enumerate_items([&](uint64_t i, const crypto::hash& k, const tx_details& v) + { + r.txs.push_back(t_serializable_object_to_blob(v.tx)); + return true; + }); + LOG_PRINT_GREEN("Sending....", LOG_LEVEL_0); + CHECK_AND_ASSERT_MES(m_pprotocol, false, "m_pprotocol is not set"); + currency_connection_context fake_context = AUTO_VAL_INIT(fake_context); + m_pprotocol->relay_transactions(r, fake_context); + LOG_PRINT_GREEN("Sent.", LOG_LEVEL_0); + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::add_transaction_to_black_list(const transaction& tx) + { + // atm: + // 1) the only side effect of a tx being blacklisted is the one is just ignored by fill_block_template(), but it still can be added to blockchain/pool + // 2) it's permanent + LOG_PRINT_YELLOW("TX ADDED TO POOL'S BLACKLIST: " << get_transaction_hash(tx), LOG_LEVEL_0); + m_db.begin_transaction(); + m_db_black_tx_list.set(get_transaction_hash(tx), true); + m_db.commit_transaction(); + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::have_tx(const crypto::hash &id) const + { + if(m_db_transactions.get(id)) + return true; + + if (check_is_taken(id)) + return true; + return false; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::have_tx_keyimges_as_spent(const transaction& tx) const + { + for(const auto& in : tx.vin) + { + if (in.type() == typeid(txin_to_key)) + { + CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, true);//should never fail + if(have_tx_keyimg_as_spent(tokey_in.k_image)) + return true; + + } + } + return false; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::insert_key_images(const transaction& tx, bool kept_by_block) + { + for(const auto& in : tx.vin) + { + if (in.type() == typeid(txin_to_key)) + { + CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, true);//should never fail + uint64_t count = 0; + auto ki_entry_ptr = m_db_key_images_set.get(tokey_in.k_image); + if (ki_entry_ptr.get()) + count = *ki_entry_ptr; + ++count; + m_db_key_images_set.set(tokey_in.k_image, count); + } + } + return false; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::on_tx_add(const transaction& tx, bool kept_by_block) + { + if (!kept_by_block) + insert_key_images(tx, kept_by_block); // take into account only key images from txs that are not 'kept_by_block' + insert_alias_info(tx); + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::on_tx_remove(const transaction& tx, bool kept_by_block) + { + if (!kept_by_block) + remove_key_images(tx, kept_by_block); // take into account only key images from txs that are not 'kept_by_block' + remove_alias_info(tx); + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::insert_alias_info(const transaction& tx) + { + tx_extra_info ei = AUTO_VAL_INIT(ei); + bool r = parse_and_validate_tx_extra(tx, ei); + CHECK_AND_ASSERT_MES(r, false, "failed to validate transaction extra on unprocess_blockchain_tx_extra"); + if (ei.m_alias.m_alias.size()) + { + m_db_alias_names.set(ei.m_alias.m_alias, true); + m_db_alias_addresses.set(ei.m_alias.m_address, true); + } + + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::remove_alias_info(const transaction& tx) + { + + tx_extra_info ei = AUTO_VAL_INIT(ei); + bool r = parse_and_validate_tx_extra(tx, ei); + CHECK_AND_ASSERT_MES(r, false, "failed to validate transaction extra on unprocess_blockchain_tx_extra"); + if (ei.m_alias.m_alias.size()) + { + m_db_alias_names.erase(ei.m_alias.m_alias); + m_db_alias_addresses.erase(ei.m_alias.m_address); + } + + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::remove_key_images(const transaction& tx, bool kept_by_block) + { + for(const auto& in : tx.vin) + { + if (in.type() == typeid(txin_to_key)) + { + CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, true);//should never fail + uint64_t count = 0; + auto ki_entry_ptr = m_db_key_images_set.get(tokey_in.k_image); + if (!ki_entry_ptr.get() || *ki_entry_ptr == 0) + { + LOG_ERROR("INTERNAL_ERROR: for tx " << get_transaction_hash(tx) << " key image " << tokey_in.k_image << " not found"); + continue; + } + count = *ki_entry_ptr; + --count; + if (count) + m_db_key_images_set.set(tokey_in.k_image, count); + else + m_db_key_images_set.erase(tokey_in.k_image); + } + } + return false; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::get_key_images_from_tx_pool(std::unordered_set& key_images) const + { + + m_db_transactions.enumerate_items([&](uint64_t i, const crypto::hash& h, const tx_details &tx_entry) + { + for (auto& in : tx_entry.tx.vin) + { + if (in.type() == typeid(txin_to_key)) + { + key_images.insert(boost::get(in).k_image); + } + } + return true; + }); + + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::have_tx_keyimg_as_spent(const crypto::key_image& key_im)const + { + + auto ptr = m_db_key_images_set.find(key_im); + if (ptr) + return true; + return false; + } + //--------------------------------------------------------------------------------- + void tx_memory_pool::lock() + { + CRITICAL_SECTION_LOCK(m_remove_stuck_txs_lock); + } + //--------------------------------------------------------------------------------- + void tx_memory_pool::unlock() + { + CRITICAL_SECTION_UNLOCK(m_remove_stuck_txs_lock); + } + //--------------------------------------------------------------------------------- + void tx_memory_pool::purge_transactions() + { + + m_db.begin_transaction(); + m_db_transactions.clear(); + m_db_key_images_set.clear(); + m_db_cancel_offer_hash.clear(); + m_db.commit_transaction(); + // should m_db_black_tx_list be cleared here? + } + //--------------------------------------------------------------------------------- + void tx_memory_pool::clear() + { + m_db.begin_transaction(); + m_db_transactions.clear(); + m_db_cancel_offer_hash.clear(); + m_db_black_tx_list.clear(); + m_db_key_images_set.clear(); + m_db.commit_transaction(); + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::is_transaction_ready_to_go(tx_details& txd, const crypto::hash& id)const + { + //not the best implementation at this time, sorry :( + + if (m_db_black_tx_list.get(get_transaction_hash(txd.tx))) + return false; + + //check is ring_signature already checked ? + if(txd.max_used_block_id == null_hash) + {//not checked, lets try to check + + if(txd.last_failed_id != null_hash && m_blockchain.get_current_blockchain_size() > txd.last_failed_height && txd.last_failed_id == m_blockchain.get_block_id_by_height(txd.last_failed_height)) + return false;//we already sure that this tx is broken for this height + + if(!m_blockchain.check_tx_inputs(txd.tx, id, txd.max_used_block_height, txd.max_used_block_id)) + { + txd.last_failed_height = m_blockchain.get_top_block_height(); + txd.last_failed_id = m_blockchain.get_block_id_by_height(txd.last_failed_height); + return false; + } + }else + { + if(txd.max_used_block_height >= m_blockchain.get_current_blockchain_size()) + return false; + if(m_blockchain.get_block_id_by_height(txd.max_used_block_height) != txd.max_used_block_id) + { + //if we already failed on this height and id, skip actual ring signature check + if(txd.last_failed_id == m_blockchain.get_block_id_by_height(txd.last_failed_height)) + return false; + //check ring signature again, it is possible (with very small chance) that this transaction become again valid + if(!m_blockchain.check_tx_inputs(txd.tx, id, txd.max_used_block_height, txd.max_used_block_id)) + { + txd.last_failed_height = m_blockchain.get_top_block_height(); + txd.last_failed_id = m_blockchain.get_block_id_by_height(txd.last_failed_height); + return false; + } + } + } + //if we here, transaction seems valid, but, anyway, check for key_images collisions with blockchain, just to be sure + if(m_blockchain.have_tx_keyimges_as_spent(txd.tx)) + return false; + + if (!check_tx_multisig_ins_and_outs(txd.tx, false)) + return false; + + //transaction is ok. + return true; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::have_key_images(const std::unordered_set& k_images, const transaction& tx)const + { + LOCAL_READONLY_TRANSACTION(); + for(size_t i = 0; i!= tx.vin.size(); i++) + { + if (tx.vin[i].type() == typeid(txin_to_key)) + { + CHECKED_GET_SPECIFIC_VARIANT(tx.vin[i], const txin_to_key, itk, false); + if (k_images.count(itk.k_image)) + return true; + } + } + return false; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::append_key_images(std::unordered_set& k_images, const transaction& tx) + { + for(size_t i = 0; i!= tx.vin.size(); i++) + { + if (tx.vin[i].type() == typeid(txin_to_key)) + { + CHECKED_GET_SPECIFIC_VARIANT(tx.vin[i], const txin_to_key, itk, false); + auto i_res = k_images.insert(itk.k_image); + CHECK_AND_ASSERT_MES(i_res.second, false, "internal error: key images pool cache - inserted duplicate image in set: " << itk.k_image); + } + } + return true; + } + //--------------------------------------------------------------------------------- + std::string tx_memory_pool::print_pool(bool short_format)const + { + std::stringstream ss; + if (short_format) + { + std::list> txs; + { + + m_db_transactions.enumerate_items([&txs](uint64_t i, const crypto::hash& h, const tx_details &tx_entry) { txs.push_back(std::make_pair(h, tx_entry)); return true; }); + } + if (txs.empty()) + return "(no transactions, the pool is empty)"; + // sort output by receive time + txs.sort([](const std::pair& lhs, const std::pair& rhs) -> bool { return lhs.second.receive_time < rhs.second.receive_time; }); + ss << "# | transaction id | size | fee | ins | outs | outs money | live_time | max used block | last failed block | kept by a block?" << ENDL; + // 1234 87157 0.10000111 2000 2000 112000.12345678 d0.h10.m16.s17 123456 <12345..> 123456 <12345..> YES + size_t i = 0; + for (auto& tx : txs) + { + auto& txd = tx.second; + ss << std::left + << std::setw(4) << i++ << " " + << tx.first << " " + << std::setw(5) << txd.blob_size << " " + << std::setw(10) << print_money_brief(txd.fee) << " " + << std::setw(4) << txd.tx.vin.size() << " " + << std::setw(4) << txd.tx.vout.size() << " " + << std::right << std::setw(15) << print_money(get_outs_money_amount(txd.tx)) << std::left << " " + << std::setw(14) << epee::misc_utils::get_time_interval_string(get_core_time() - txd.receive_time) << " " + << std::setw(6) << txd.max_used_block_height << " " + << std::setw(9) << print16(txd.max_used_block_id) << " " + << std::setw(6) << txd.last_failed_height << " " + << std::setw(9) << print16(txd.last_failed_id) << " " + << (txd.kept_by_block ? "YES" : "no ") + << ENDL; + } + return ss.str(); + } + + // long format + + m_db_transactions.enumerate_items([&](uint64_t i, const crypto::hash& h, const tx_details &tx_entry) + { + auto& txd = tx_entry; + ss << "id: " << h << ENDL + << obj_to_json_str(txd.tx) << ENDL + << "blob_size: " << txd.blob_size << ENDL + << "fee: " << txd.fee << ENDL + << "kept_by_block: " << (txd.kept_by_block ? "true" : "false") << ENDL + << "max_used_block_height: " << txd.max_used_block_height << ENDL + << "max_used_block_id: " << txd.max_used_block_id << ENDL + << "last_failed_height: " << txd.last_failed_height << ENDL + << "last_failed_id: " << txd.last_failed_id << ENDL + << "live_time: " << epee::misc_utils::get_time_interval_string(get_core_time() - txd.receive_time) << ENDL; + return true; + }); + + return ss.str(); + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::fill_block_template(block &bl, + bool pos, + size_t median_size, + uint64_t already_generated_coins, + size_t &total_size, + uint64_t &fee, + uint64_t height) + { + LOCAL_READONLY_TRANSACTION(); + //typedef transactions_container::value_type txv; + typedef std::pair > txv; + + + std::vector txs_v; + txs_v.reserve(m_db_transactions.size()); + std::vector txs; + + //std::transform(m_transactions.begin(), m_transactions.end(), txs.begin(), [](txv &a) -> txv * { return &a; }); + //keep getting it as a values cz db items cache will keep it as unserialied object stored by shared ptrs + m_db_transactions.enumerate_keys([&](uint64_t i, crypto::hash& k){txs_v.resize(i + 1); txs_v[i].first = k; return true;}); + txs.resize(txs_v.size(), nullptr); + + for (uint64_t i = 0; i != txs_v.size(); i++) + { + auto& k = txs_v[i].first; + txs_v[i].second = m_db_transactions.get(k); + if (!txs_v[i].second) + { + LOG_ERROR("Internal tx pool db error: key " << k << " was enumerated as key but couldn't get value"); + continue; + } + txs[i] = &txs_v[i]; + } + + + + std::sort(txs.begin(), txs.end(), [](txv *a, txv *b) -> bool { + boost::multiprecision::uint128_t a_, b_; + a_ = boost::multiprecision::uint128_t(a->second->fee) * b->second->blob_size; + b_ = boost::multiprecision::uint128_t(b->second->fee) * a->second->blob_size; + return a_ > b_; + }); + + size_t current_size = 0; + uint64_t current_fee = 0; + uint64_t best_money; + if (!get_block_reward(pos, median_size, CURRENCY_COINBASE_BLOB_RESERVED_SIZE, already_generated_coins, best_money, height)) { + LOG_ERROR("Block with just a miner transaction is already too large!"); + return false; + } + size_t best_position = 0; + total_size = 0; + fee = 0; + uint64_t alias_count = 0; + + // scan txs for alias reg requests - if there are such requests, don't process alias updates + bool alias_regs_exist = false; + for (auto txp : txs) + { + tx_extra_info ei = AUTO_VAL_INIT(ei); + bool r = parse_and_validate_tx_extra(txp->second->tx, ei); + CHECK_AND_ASSERT_MES(r, false, "parse_and_validate_tx_extra failed while looking up the tx pool"); + if (!ei.m_alias.m_alias.empty() && !ei.m_alias.m_sign.size()) { + alias_regs_exist = true; + break; + } + } + + const uint64_t tx_expiration_ts_median = m_blockchain.get_tx_expiration_median(); + + std::unordered_set k_images; + + for (size_t i = 0; i < txs.size(); i++) + { + txv &tx(*txs[i]); + + // expiration time check -- skip expired transactions + if (is_tx_expired(tx.second->tx, tx_expiration_ts_median)) + { + txs[i] = nullptr; + continue; + } + + // alias checks + tx_extra_info ei = AUTO_VAL_INIT(ei); + bool r = parse_and_validate_tx_extra(tx.second->tx, ei); + CHECK_AND_ASSERT_MES(r, false, "failed to validate transaction extra on unprocess_blockchain_tx_extra"); + if (!ei.m_alias.m_alias.empty()) + { + bool update_an_alias = !ei.m_alias.m_sign.empty(); + if ((alias_count >= MAX_ALIAS_PER_BLOCK) || // IF this tx registers/updates an alias AND alias per block threshold exceeded + (update_an_alias && alias_regs_exist)) // OR this tx updates an alias AND there are alias reg requests... + { + txs[i] = NULL; // ...skip this tx + continue; + } + } + + //is_transaction_ready_to_go can change tx_details in case of some errors, so we make local copy, + //do check if it's changed and reassign it to db if needed + tx_details local_copy_txd = *(tx.second); + bool is_tx_ready_to_go_result = is_transaction_ready_to_go(local_copy_txd, tx.first); + if (!is_tx_ready_to_go_result && + (local_copy_txd.last_failed_height != tx.second->last_failed_height || local_copy_txd.last_failed_id != tx.second->last_failed_id)) + { + m_db_transactions.begin_transaction(); + m_db_transactions.set(get_transaction_hash(local_copy_txd.tx), local_copy_txd); + m_db_transactions.commit_transaction(); + } + + if (!is_tx_ready_to_go_result || have_key_images(k_images, tx.second->tx)) { + txs[i] = NULL; + continue; + } + append_key_images(k_images, tx.second->tx); + + current_size += tx.second->blob_size; + current_fee += tx.second->fee; + + uint64_t current_reward; + if (!get_block_reward(pos, median_size, current_size + CURRENCY_COINBASE_BLOB_RESERVED_SIZE, already_generated_coins, current_reward, height)) + { + break; // current block size is too big + } + + if (best_money < current_reward + current_fee) { + best_money = current_reward + current_fee; + best_position = i + 1; + total_size = current_size; + fee = current_fee; + } + + if (!ei.m_alias.m_alias.empty()) + ++alias_count; + } + + for (size_t i = 0; i != txs.size(); i++) + { + if (txs[i]) + { + if (i < best_position) + { + bl.tx_hashes.push_back(txs[i]->first); + } + else if (have_attachment_service_in_container(txs[i]->second->tx.attachment, BC_OFFERS_SERVICE_ID, BC_OFFERS_SERVICE_INSTRUCTION_DEL)) + { + // BC_OFFERS_SERVICE_INSTRUCTION_DEL transactions has zero fee, so include them here regardless of reward effectiveness + bl.tx_hashes.push_back(txs[i]->first); + total_size += txs[i]->second->blob_size; + } + } + } + return true; + } + //--------------------------------------------------------------------------------- + void tx_memory_pool::initialize_db_solo_options_values() + { + m_db.begin_transaction(); + m_db_storage_major_compatibility_version = TRANSACTION_POOL_MAJOR_COMPATIBILITY_VERSION; + m_db.commit_transaction(); + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::init(const std::string& config_folder) + { + m_config_folder = config_folder; + + uint64_t cache_size = CACHE_SIZE; + LOG_PRINT_GREEN("Using pool db file cache size(L1): " << cache_size, LOG_LEVEL_0); + + LOG_PRINT_L0("Loading blockchain..."); + const std::string folder_name = m_config_folder + "/" CURRENCY_POOLDATA_FOLDERNAME; + tools::create_directories_if_necessary(folder_name); + bool res = m_db.open(folder_name, cache_size); + CHECK_AND_ASSERT_MES(res, false, "Failed to initialize pool database in folder: " << folder_name); + + res = m_db_transactions.init(TRANSACTION_POOL_CONTAINER_TRANSACTIONS); + CHECK_AND_ASSERT_MES(res, false, "Unable to init db container"); + res = m_db_key_images_set.init(TRANSACTION_POOL_CONTAINER_KEY_IMAGES); + CHECK_AND_ASSERT_MES(res, false, "Unable to init db container"); + res = m_db_cancel_offer_hash.init(TRANSACTION_POOL_CONTAINER_CANCEL_OFFER_HASH); + CHECK_AND_ASSERT_MES(res, false, "Unable to init db container"); + res = m_db_black_tx_list.init(TRANSACTION_POOL_CONTAINER_BLACK_TX_LIST); + CHECK_AND_ASSERT_MES(res, false, "Unable to init db container"); + res = m_db_alias_names.init(TRANSACTION_POOL_CONTAINER_ALIAS_NAMES); + CHECK_AND_ASSERT_MES(res, false, "Unable to init db container"); + res = m_db_alias_addresses.init(TRANSACTION_POOL_CONTAINER_ALIAS_ADDRESSES); + CHECK_AND_ASSERT_MES(res, false, "Unable to init db container"); + res = m_db_solo_options.init(TRANSACTION_POOL_CONTAINER_SOLO_OPTIONS); + CHECK_AND_ASSERT_MES(res, false, "Unable to init db container"); + + + m_db_transactions.set_cache_size(1000); + m_db_alias_names.set_cache_size(10000); + m_db_alias_addresses.set_cache_size(10000); + m_db_cancel_offer_hash.set_cache_size(1000); + m_db_black_tx_list.set_cache_size(1000); + + bool need_reinit = false; + if (m_db_storage_major_compatibility_version != TRANSACTION_POOL_MAJOR_COMPATIBILITY_VERSION) + need_reinit = true; + + if (need_reinit) + { + clear(); + LOG_PRINT_MAGENTA("Tx Pool reinitialized.", LOG_LEVEL_0); + } + initialize_db_solo_options_values(); + + LOG_PRINT_GREEN("TX_POOL Initialized ok. (" << m_db_transactions.size() << " transactions)", LOG_LEVEL_0); + return true; + } + + //--------------------------------------------------------------------------------- + bool tx_memory_pool::deinit() + { + m_db.close(); + return true; + } + //--------------------------------------------------------------------------------- + uint64_t tx_memory_pool::get_core_time() const + { + return m_blockchain.get_core_runtime_config().get_core_time(); + } + //--------------------------------------------------------------------------------- + namespace + { + struct ms_out_info + { + crypto::hash multisig_id; + size_t input_output_index; + bool is_input; + }; + } + //--------------------------------------------------------------------------------- + void collect_multisig_ids_from_tx(const transaction& tx, std::vector& result) + { + result.reserve(tx.vin.size() + tx.vout.size()); + + size_t idx = 0; + for (const auto& in : tx.vin) + { + if (in.type() == typeid(txin_multisig)) + result.push_back(ms_out_info({ boost::get(in).multisig_out_id, idx, true })); + ++idx; + } + + idx = 0; + for (const auto& out : tx.vout) + { + if (out.target.type() == typeid(txout_multisig)) + result.push_back(ms_out_info({ get_multisig_out_id(tx, idx), idx, false })); + ++idx; + } + } + //--------------------------------------------------------------------------------- + bool does_tx_have_given_multisig_id(const transaction& tx, const crypto::hash& multisig_id) + { + for (const auto& in : tx.vin) + { + if (in.type() == typeid(txin_multisig) && boost::get(in).multisig_out_id == multisig_id) + return true; + } + + size_t idx = 0; + for (const auto& out : tx.vout) + { + if (out.target.type() == typeid(txout_multisig) && get_multisig_out_id(tx, idx) == multisig_id) + return true; + ++idx; + } + + return false; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::check_tx_multisig_ins_and_outs(const transaction& tx, bool check_against_pool_txs) const + { + + LOCAL_READONLY_TRANSACTION(); + std::vector ms_ids; + collect_multisig_ids_from_tx(tx, ms_ids); + + for (auto& el : ms_ids) + { + // check given multisig output against all blockchain's multisig outputs + if (!el.is_input && m_blockchain.has_multisig_output(el.multisig_id)) + { + LOG_PRINT_L0("Transaction " << get_transaction_hash(tx) << " : output #" << el.input_output_index << " has multisig id " << el.multisig_id << " that is already in the blockchain"); + return false; + } + + // check given multisig input/output against all transactions in the pool + if (check_against_pool_txs) + { + bool has_found = false; + m_db_transactions.enumerate_items([&](uint64_t i, const crypto::hash& h, const tx_details &tx_entry) + { + if (does_tx_have_given_multisig_id(tx_entry.tx, el.multisig_id)) + { + has_found = true; + LOG_PRINT_L0("Transaction " << get_transaction_hash(tx) << (el.is_input ? " : input #" : " : output #") << el.input_output_index << " has multisig id " << el.multisig_id << + " that is already in the pool in tx " << get_transaction_hash(tx_entry.tx)); + return false; + } + return true; + }); + if (has_found) + return false; + } + } + + return true; + } +} + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL NULL + + diff --git a/src/currency_core/tx_pool.h b/src/currency_core/tx_pool.h new file mode 100644 index 00000000..d8dd4ed2 --- /dev/null +++ b/src/currency_core/tx_pool.h @@ -0,0 +1,244 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include "include_base_utils.h" +using namespace epee; + + +#include +#include +#include +#include +#include + +#include "string_tools.h" +#include "syncobj.h" +#include "math_helper.h" + +#include "common/db_abstract_accessor.h" + +#include "currency_format_utils.h" +#include "verification_context.h" +#include "crypto/hash.h" +#include "common/boost_serialization_helper.h" +#include "currency_protocol/currency_protocol_handler_common.h" + +namespace currency +{ + class blockchain_storage; + /************************************************************************/ + /* */ + /************************************************************************/ + + class tx_memory_pool: boost::noncopyable + { + public: + + struct tx_details + { + transaction tx; + size_t blob_size; + uint64_t fee; + crypto::hash max_used_block_id; + uint64_t max_used_block_height; + bool kept_by_block; + // + uint64_t last_failed_height; + crypto::hash last_failed_id; + time_t receive_time; + + BEGIN_SERIALIZE_OBJECT() + FIELD(tx) + FIELD(blob_size) + FIELD(fee) + FIELD(max_used_block_id) + FIELD(max_used_block_height) + FIELD(kept_by_block) + FIELD(last_failed_height) + FIELD(last_failed_id) + FIELD(receive_time) + END_SERIALIZE() + + }; + + struct performnce_data + { + //tx zone + epee::math_helper::average tx_processing_time; + epee::math_helper::average check_inputs_types_supported_time; + epee::math_helper::average expiration_validate_time; + epee::math_helper::average validate_amount_time; + epee::math_helper::average validate_alias_time; + epee::math_helper::average check_keyimages_ws_ms_time; + epee::math_helper::average check_inputs_time; + epee::math_helper::average begin_tx_time; + epee::math_helper::average update_db_time; + epee::math_helper::average db_commit_time; + }; + + + tx_memory_pool(blockchain_storage& bchs, i_currency_protocol* pprotocol); + bool add_tx(const transaction &tx, const crypto::hash &id, uint64_t blob_size, tx_verification_context& tvc, bool kept_by_block, bool from_core = false); + bool add_tx(const transaction &tx, tx_verification_context& tvc, bool kept_by_block, bool from_core = false); + + bool do_insert_transaction(const transaction &tx, const crypto::hash &id, uint64_t blob_size, bool kept_by_block, uint64_t fee, const crypto::hash& max_used_block_id, uint64_t max_used_block_height); + //gets tx and remove it from pool + bool take_tx(const crypto::hash &id, transaction &tx, size_t& blob_size, uint64_t& fee); + + + bool have_tx(const crypto::hash &id)const; + bool have_tx_keyimg_as_spent(const crypto::key_image& key_im)const; + bool have_tx_keyimges_as_spent(const transaction& tx)const; + const performnce_data& get_performnce_data() const { return m_performance_data; } + + + bool check_tx_multisig_ins_and_outs(const transaction& tx, bool check_against_pool_txs)const; + + bool on_blockchain_inc(uint64_t new_block_height, const crypto::hash& top_block_id); + bool on_blockchain_dec(uint64_t new_block_height, const crypto::hash& top_block_id); + bool on_finalize_db_transaction(); + bool add_transaction_to_black_list(const transaction& tx); + bool force_relay_pool() const; + bool set_protocol(i_currency_protocol* pprotocol); + + + void on_idle(); + + void lock(); + void unlock(); + void purge_transactions(); + void clear(); + + // load/store operations + bool init(const std::string& config_folder); + bool deinit(); + bool fill_block_template(block &bl, bool pos, size_t median_size, uint64_t already_generated_coins, size_t &total_size, uint64_t &fee, uint64_t height); + bool get_transactions(std::list& txs) const; + bool get_all_transactions_details(std::list& txs)const; + bool get_all_transactions_brief_details(std::list& txs)const; + bool get_all_transactions_list(std::list& txs)const; + bool get_transactions_details(const std::list& ids, std::list& txs)const; + bool get_transactions_brief_details(const std::list& ids, std::list& txs)const; + + bool get_transaction_details(const crypto::hash& id, tx_rpc_extended_info& trei)const; + bool get_transaction(const crypto::hash& h, transaction& tx)const; + bool get_transaction(const crypto::hash& h, tx_details& txd)const; + size_t get_transactions_count() const; + bool have_key_images(const std::unordered_set& kic, const transaction& tx)const; + bool append_key_images(std::unordered_set& kic, const transaction& tx); + std::string print_pool(bool short_format)const; + uint64_t get_core_time() const; + bool get_aliases_from_tx_pool(std::list& aliases)const; + bool get_aliases_from_tx_pool(std::map& aliases)const; + //crypto::hash get_last_core_hash() {return m_last_core_top_hash;} + //void set_last_core_hash(const crypto::hash& h) { m_last_core_top_hash = h; } + + + private: + bool on_tx_add(const transaction& tx, bool kept_by_block); + bool on_tx_remove(const transaction& tx, bool kept_by_block); + bool insert_key_images(const transaction& tx, bool kept_by_block); + bool remove_key_images(const transaction& tx, bool kept_by_block); + bool insert_alias_info(const transaction& tx); + bool remove_alias_info(const transaction& tx); + + bool is_valid_contract_finalization_tx(const transaction &tx)const; + void initialize_db_solo_options_values(); + bool remove_stuck_transactions(); + bool is_transaction_ready_to_go(tx_details& txd, const crypto::hash& id)const; + bool validate_alias_info(const transaction& tx, bool is_in_block)const; + bool get_key_images_from_tx_pool(std::unordered_set& key_images)const; + //bool push_alias_info(const transaction& tx); + //bool pop_alias_info(const transaction& tx); + bool process_cancel_offer_rules(const transaction& tx); + bool unprocess_cancel_offer_rules(const transaction& tx); + bool check_is_taken(const crypto::hash& id) const; + void set_taken(const crypto::hash& id); + void reset_all_taken(); + + typedef tools::db::cached_key_value_accessor transactions_container; + typedef tools::db::cached_key_value_accessor hash_container; + typedef tools::db::cached_key_value_accessor key_images_container; + typedef tools::db::cached_key_value_accessor solo_options_container; + typedef tools::db::cached_key_value_accessor aliases_container; + typedef tools::db::cached_key_value_accessor address_to_aliases_container; + + + //main accessor + epee::shared_recursive_mutex m_dummy_rw_lock; + tools::db::basic_db_accessor m_db; + //containers + + transactions_container m_db_transactions; + hash_container m_db_cancel_offer_hash; + hash_container m_db_black_tx_list; + key_images_container m_db_key_images_set; + aliases_container m_db_alias_names; + address_to_aliases_container m_db_alias_addresses; + solo_options_container m_db_solo_options; + tools::db::solo_db_value m_db_storage_major_compatibility_version; + //crypto::hash m_last_core_top_hash; + + + epee::math_helper::once_a_time_seconds<30> m_remove_stuck_tx_interval; + + performnce_data m_performance_data; + std::string m_config_folder; + blockchain_storage& m_blockchain; + i_currency_protocol* m_pprotocol; + + //in memory containers + mutable epee::critical_section m_taken_txs_lock; + std::unordered_set m_taken_txs; + mutable epee::critical_section m_remove_stuck_txs_lock; + + + /************************************************************************/ + /* */ + /************************************************************************/ + class amount_visitor: public boost::static_visitor + { + public: + uint64_t operator()(const txin_to_key& tx) const + { + return tx.amount; + } + uint64_t operator()(const txin_gen& /*tx*/) const + { + CHECK_AND_ASSERT_MES(false, 0, "coinbase transaction in memory pool"); + return 0; + } + uint64_t operator()(const txin_multisig& in) const { return in.amount; } + }; + + }; +} + +namespace boost +{ + namespace serialization + { + template + void serialize(archive_t & ar, currency::tx_memory_pool::tx_details& td, const unsigned int version) + { + ar & td.blob_size; + ar & td.fee; + ar & td.tx; + ar & td.max_used_block_height; + ar & td.max_used_block_id; + ar & td.last_failed_height; + ar & td.last_failed_id; + ar & td.receive_time; + ar & td.kept_by_block; + } + } +} + +BOOST_CLASS_VERSION(currency::tx_memory_pool, CURRENT_MEMPOOL_ARCHIVE_VER) + + + diff --git a/src/currency_core/verification_context.h b/src/currency_core/verification_context.h new file mode 100644 index 00000000..a9f1f646 --- /dev/null +++ b/src/currency_core/verification_context.h @@ -0,0 +1,31 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + + +#pragma once +namespace currency +{ + /************************************************************************/ + /* */ + /************************************************************************/ + struct tx_verification_context + { + bool m_should_be_relayed; + bool m_verification_failed; //bad tx, should drop connection + bool m_verification_impossible; //the transaction is related to alternative blockchain + bool m_added_to_pool; + }; + + struct block_verification_context + { + bool m_added_to_main_chain; + bool m_verification_failed; //bad block, should drop connection + bool m_marked_as_orphaned; + bool m_already_exists; + bool added_to_altchain; + uint64_t height_difference; + }; +} diff --git a/src/currency_protocol/blobdatatype.h b/src/currency_protocol/blobdatatype.h new file mode 100644 index 00000000..b3d614aa --- /dev/null +++ b/src/currency_protocol/blobdatatype.h @@ -0,0 +1,10 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +namespace currency +{ + typedef std::string blobdata; +} diff --git a/src/currency_protocol/currency_protocol_defs.h b/src/currency_protocol/currency_protocol_defs.h new file mode 100644 index 00000000..3164749c --- /dev/null +++ b/src/currency_protocol/currency_protocol_defs.h @@ -0,0 +1,170 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include +#include "serialization/keyvalue_serialization.h" +#include "currency_core/currency_basic.h" +#include "currency_core/connection_context.h" +#include "currency_core/blockchain_storage_basic.h" +#include "currency_protocol/blobdatatype.h" + +namespace currency +{ + + +#define BC_COMMANDS_POOL_BASE 2000 + + + /************************************************************************/ + /* */ + /************************************************************************/ + struct block_complete_entry + { + blobdata block; + std::list txs; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(block) + KV_SERIALIZE(txs) + END_KV_SERIALIZE_MAP() + }; + + struct block_direct_data_entry + { + std::shared_ptr block_ptr; + std::list > txs_ptr; + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + struct NOTIFY_NEW_BLOCK + { + const static int ID = BC_COMMANDS_POOL_BASE + 1; + + struct request + { + block_complete_entry b; + uint64_t current_blockchain_height; + uint32_t hop; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(b) + KV_SERIALIZE(current_blockchain_height) + KV_SERIALIZE(hop) + END_KV_SERIALIZE_MAP() + }; + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + struct NOTIFY_NEW_TRANSACTIONS + { + const static int ID = BC_COMMANDS_POOL_BASE + 2; + + struct request + { + std::list txs; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(txs) + END_KV_SERIALIZE_MAP() + }; + }; + /************************************************************************/ + /* */ + /************************************************************************/ + struct NOTIFY_REQUEST_GET_OBJECTS + { + const static int ID = BC_COMMANDS_POOL_BASE + 3; + + struct request + { + std::list txs; + std::list blocks; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(txs) + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(blocks) + END_KV_SERIALIZE_MAP() + }; + }; + + struct NOTIFY_RESPONSE_GET_OBJECTS + { + const static int ID = BC_COMMANDS_POOL_BASE + 4; + + struct request + { + std::list txs; + std::list blocks; + std::list missed_ids; + uint64_t current_blockchain_height; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(txs) + KV_SERIALIZE(blocks) + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(missed_ids) + KV_SERIALIZE(current_blockchain_height) + END_KV_SERIALIZE_MAP() + }; + }; + + struct CORE_SYNC_DATA + { + uint64_t current_height; + crypto::hash top_id; + uint64_t last_checkpoint_height; + uint64_t core_time; + std::string client_version; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(current_height) + KV_SERIALIZE_VAL_POD_AS_BLOB(top_id) + KV_SERIALIZE(last_checkpoint_height) + KV_SERIALIZE(core_time) + KV_SERIALIZE(client_version) + END_KV_SERIALIZE_MAP() + }; + + struct NOTIFY_REQUEST_CHAIN + { + const static int ID = BC_COMMANDS_POOL_BASE + 6; + + struct request + { + std::list block_ids; /*IDs of the first 10 blocks are sequential, next goes with pow(2,n) offset, like 2, 4, 8, 16, 32, 64 and so on, and the last one is always genesis block */ + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(block_ids) + END_KV_SERIALIZE_MAP() + }; + }; + + + + struct NOTIFY_RESPONSE_CHAIN_ENTRY + { + const static int ID = BC_COMMANDS_POOL_BASE + 7; + + struct request + { + uint64_t start_height; + uint64_t total_height; + std::list m_block_ids; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(start_height) + KV_SERIALIZE(total_height) + KV_SERIALIZE(m_block_ids) + END_KV_SERIALIZE_MAP() + }; + }; + +} diff --git a/src/currency_protocol/currency_protocol_handler.h b/src/currency_protocol/currency_protocol_handler.h new file mode 100644 index 00000000..795354fc --- /dev/null +++ b/src/currency_protocol/currency_protocol_handler.h @@ -0,0 +1,140 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include + +#include "storages/levin_abstract_invoke2.h" +#include "warnings.h" +#include "currency_protocol_defs.h" +#include "currency_protocol_handler_common.h" +#include "currency_core/connection_context.h" +#include "currency_core/currency_stat_info.h" +#include "currency_core/verification_context.h" + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL "currency_protocol" + +PUSH_WARNINGS +DISABLE_VS_WARNINGS(4355) + +#define ASYNC_RELAY_MODE + +namespace currency +{ + + template + class t_currency_protocol_handler: public i_currency_protocol + { + public: + typedef currency_connection_context connection_context; + typedef core_stat_info stat_info; + typedef t_currency_protocol_handler currency_protocol_handler; + typedef CORE_SYNC_DATA payload_type; + typedef std::pair relay_que_entry; + + t_currency_protocol_handler(t_core& rcore, nodetool::i_p2p_endpoint* p_net_layout); + ~t_currency_protocol_handler(); + + BEGIN_INVOKE_MAP2(currency_protocol_handler) + HANDLE_NOTIFY_T2(NOTIFY_NEW_BLOCK, ¤cy_protocol_handler::handle_notify_new_block) + HANDLE_NOTIFY_T2(NOTIFY_NEW_TRANSACTIONS, ¤cy_protocol_handler::handle_notify_new_transactions) + HANDLE_NOTIFY_T2(NOTIFY_REQUEST_GET_OBJECTS, ¤cy_protocol_handler::handle_request_get_objects) + HANDLE_NOTIFY_T2(NOTIFY_RESPONSE_GET_OBJECTS, ¤cy_protocol_handler::handle_response_get_objects) + HANDLE_NOTIFY_T2(NOTIFY_REQUEST_CHAIN, ¤cy_protocol_handler::handle_request_chain) + HANDLE_NOTIFY_T2(NOTIFY_RESPONSE_CHAIN_ENTRY, ¤cy_protocol_handler::handle_response_chain_entry) + END_INVOKE_MAP2() + + bool on_idle(); + bool init(const boost::program_options::variables_map& vm); + bool deinit(); + void set_p2p_endpoint(nodetool::i_p2p_endpoint* p2p); + //bool process_handshake_data(const blobdata& data, currency_connection_context& context); + bool process_payload_sync_data(const CORE_SYNC_DATA& hshd, currency_connection_context& context, bool is_inital); + bool get_payload_sync_data(blobdata& data); + bool get_payload_sync_data(CORE_SYNC_DATA& hshd); + bool get_stat_info(const core_stat_info::params& pr, core_stat_info& stat_inf); + bool on_callback(currency_connection_context& context); + t_core& get_core(){return m_core;} + virtual bool is_synchronized(){ return m_synchronized; } + void log_connections(); + uint64_t get_core_inital_height(); + uint64_t get_max_seen_height(); + virtual size_t get_synchronized_connections_count(); + virtual size_t get_synchronizing_connections_count(); + int64_t get_net_time_delta_median(); + + private: + //----------------- commands handlers ---------------------------------------------- + int handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, currency_connection_context& context); + int handle_notify_new_transactions(int command, NOTIFY_NEW_TRANSACTIONS::request& arg, currency_connection_context& context); + int handle_request_get_objects(int command, NOTIFY_REQUEST_GET_OBJECTS::request& arg, currency_connection_context& context); + int handle_response_get_objects(int command, NOTIFY_RESPONSE_GET_OBJECTS::request& arg, currency_connection_context& context); + int handle_request_chain(int command, NOTIFY_REQUEST_CHAIN::request& arg, currency_connection_context& context); + int handle_response_chain_entry(int command, NOTIFY_RESPONSE_CHAIN_ENTRY::request& arg, currency_connection_context& context); + + + //----------------- i_bc_protocol_layout --------------------------------------- + virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, currency_connection_context& exclude_context); + virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, currency_connection_context& exclude_context); + //---------------------------------------------------------------------------------- + //bool get_payload_sync_data(HANDSHAKE_DATA::request& hshd, currency_connection_context& context); + bool request_missing_objects(currency_connection_context& context, bool check_having_blocks); + bool on_connection_synchronized(); + void relay_que_worker(); + void process_current_relay_que(const std::list& que); + bool check_stop_flag_and_drop_cc(currency_connection_context& context); + + t_core& m_core; + + nodetool::p2p_endpoint_stub m_p2p_stub; + nodetool::i_p2p_endpoint* m_p2p; + std::atomic m_syncronized_connections_count; + std::atomic m_synchronized; + std::atomic m_have_been_synchronized; + std::atomic m_max_height_seen; + std::atomic m_core_inital_height; + + std::unordered_set m_blocks_id_que; + std::recursive_mutex m_blocks_id_que_lock; + + std::list m_relay_que; + std::mutex m_relay_que_lock; + std::condition_variable m_relay_que_cv; + std::thread m_relay_que_thread; + std::atomic m_want_stop; + + template + bool post_notify(typename t_parametr::request& arg, currency_connection_context& context) + { + LOG_PRINT_L2("[POST]" << typeid(t_parametr).name()); + std::string blob; + epee::serialization::store_t_to_binary(arg, blob); + return m_p2p->invoke_notify_to_peer(t_parametr::ID, blob, context); + } + + template + bool relay_post_notify(typename t_parametr::request& arg, currency_connection_context& exlude_context) + { + std::string arg_buff; + epee::serialization::store_t_to_binary(arg, arg_buff); + std::list relayed_peers; + bool r = m_p2p->relay_notify_to_all(t_parametr::ID, arg_buff, exlude_context, relayed_peers); + + LOG_PRINT_GREEN("[POST RELAY] " << typeid(t_parametr).name() << " relayed contexts list: " << ENDL << print_connection_context_list(relayed_peers), LOG_LEVEL_2); + return r; + } + }; +} + + +#include "currency_protocol_handler.inl" + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL NULL + +POP_WARNINGS diff --git a/src/currency_protocol/currency_protocol_handler.inl b/src/currency_protocol/currency_protocol_handler.inl new file mode 100644 index 00000000..83917f92 --- /dev/null +++ b/src/currency_protocol/currency_protocol_handler.inl @@ -0,0 +1,777 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include "currency_core/currency_format_utils.h" +#include "profile_tools.h" +namespace currency +{ + + //----------------------------------------------------------------------------------------------------------------------- + template + t_currency_protocol_handler::t_currency_protocol_handler(t_core& rcore, nodetool::i_p2p_endpoint* p_net_layout):m_core(rcore), + m_p2p(p_net_layout), + m_syncronized_connections_count(0), + m_synchronized(false), + m_have_been_synchronized(false), + m_max_height_seen(0), + m_core_inital_height(0), + m_want_stop(false) + + + { + if(!m_p2p) + m_p2p = &m_p2p_stub; + } + //----------------------------------------------------------------------------------------------------------------------- + template + t_currency_protocol_handler::~t_currency_protocol_handler() + { + deinit(); + } + //----------------------------------------------------------------------------------------------------------------------- + template + bool t_currency_protocol_handler::init(const boost::program_options::variables_map& vm) + { + m_relay_que_thread = std::thread([this](){relay_que_worker();}); + return true; + } + //------------------------------------------------------------------------------------------------------------------------ + template + bool t_currency_protocol_handler::deinit() + { + m_want_stop = true; + m_relay_que_cv.notify_all(); + if (m_relay_que_thread.joinable()) + m_relay_que_thread.join(); + return true; + } + //------------------------------------------------------------------------------------------------------------------------ + template + void t_currency_protocol_handler::set_p2p_endpoint(nodetool::i_p2p_endpoint* p2p) + { + if(p2p) + m_p2p = p2p; + else + m_p2p = &m_p2p_stub; + } + //------------------------------------------------------------------------------------------------------------------------ + template + bool t_currency_protocol_handler::on_callback(currency_connection_context& context) + { + LOG_PRINT_L3("callback fired"); + CHECK_AND_ASSERT_MES_CC( context.m_priv.m_callback_request_count > 0, false, "false callback fired, but context.m_priv.m_callback_request_count=" << context.m_priv.m_callback_request_count); + --context.m_priv.m_callback_request_count; + + if(context.m_state == currency_connection_context::state_synchronizing) + { + NOTIFY_REQUEST_CHAIN::request r = boost::value_initialized(); + m_core.get_short_chain_history(r.block_ids); + post_notify(r, context); + } + + return true; + } + //------------------------------------------------------------------------------------------------------------------------ + template + bool t_currency_protocol_handler::get_stat_info(const core_stat_info::params& pr, core_stat_info& stat_inf) + { + return m_core.get_stat_info(pr, stat_inf); + } + //------------------------------------------------------------------------------------------------------------------------ + template + void t_currency_protocol_handler::log_connections() + { + std::stringstream ss; + + ss << std::setw(29) << std::left << "Remote Host" + << std::setw(20) << "Peer id" + << std::setw(25) << "Recv/Sent (idle,sec)" + << std::setw(25) << "State" + << std::setw(20) << "Livetime(seconds)" + << std::setw(20) << "Client version" << ENDL; + + m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id) + { + ss << std::setw(29) << std::left << std::string(cntxt.m_is_income ? "[INC]":"[OUT]") + + string_tools::get_ip_string_from_int32(cntxt.m_remote_ip) + ":" + std::to_string(cntxt.m_remote_port) + << std::setw(20) << std::hex << peer_id + << std::setw(25) << std::to_string(cntxt.m_recv_cnt)+ "(" + std::to_string(time(NULL) - cntxt.m_last_recv) + ")" + "/" + std::to_string(cntxt.m_send_cnt) + "(" + std::to_string(time(NULL) - cntxt.m_last_send) + ")" + << std::setw(25) << get_protocol_state_string(cntxt.m_state) + << std::setw(20) << std::to_string(time(NULL) - cntxt.m_started) + << std::setw(20) << cntxt.m_priv.m_remote_version + << ENDL; + return true; + }); + LOG_PRINT_L0("Connections: " << ENDL << ss.str()); + } + //------------------------------------------------------------------------------------------------------------------------ + template + bool t_currency_protocol_handler::process_payload_sync_data(const CORE_SYNC_DATA& hshd, currency_connection_context& context, bool is_inital) + { + + + context.m_priv.m_remote_version = hshd.client_version; + + if(context.m_state == currency_connection_context::state_befor_handshake && !is_inital) + return true; + + context.m_time_delta = m_core.get_blockchain_storage().get_core_runtime_config().get_core_time() - hshd.core_time; + + if(context.m_state == currency_connection_context::state_synchronizing) + return true; + + + bool have_in_que = false; + CRITICAL_REGION_BEGIN(m_blocks_id_que_lock); + have_in_que = m_blocks_id_que.find(hshd.top_id) != m_blocks_id_que.end(); + CRITICAL_REGION_END(); + + if(have_in_que || m_core.have_block(hshd.top_id)) + { + + context.m_state = currency_connection_context::state_normal; + if(is_inital) + on_connection_synchronized(); + return true; + } + + int64_t diff = static_cast(hshd.current_height) - static_cast(m_core.get_current_blockchain_size()); + LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, (is_inital ? "Inital ":"Idle ") << "sync data returned unknown top block (" << hshd.top_id << "): " << m_core.get_top_block_height() << " -> " << hshd.current_height - 1 + << " [" << std::abs(diff) << " blocks (" << diff / (24 * 60 * 60 / DIFFICULTY_TOTAL_TARGET ) << " days) " + << (0 <= diff ? std::string("behind") : std::string("ahead")) + << "] " << ENDL << "SYNCHRONIZATION started", (is_inital ? LOG_LEVEL_0 : LOG_LEVEL_1), (is_inital ? epee::log_space::console_color_yellow : epee::log_space::console_color_magenta)); + LOG_PRINT_L1("Remote top block height: " << hshd.current_height << ", id: " << hshd.top_id); +// m_synchronized = false; + LOG_PRINT_MAGENTA("Synchronized set to FALSE (process_payload_sync_data)", LOG_LEVEL_0); + /*check if current height is in remote's checkpoints zone*/ + if(hshd.last_checkpoint_height + && m_core.get_blockchain_storage().get_checkpoints().get_top_checkpoint_height() < hshd.last_checkpoint_height + && m_core.get_current_blockchain_size() < hshd.last_checkpoint_height ) + { + LOG_PRINT_RED("Remote node have longer checkpoints zone( " << hshd.last_checkpoint_height << ") " << + "that local (" << m_core.get_blockchain_storage().get_checkpoints().get_top_checkpoint_height() << ")" << + "That means that current software is outdated, please updated it." << + "Current heigh lay under checkpoints on remote host, so it is not possible validate this transactions on local host, disconnecting.", LOG_LEVEL_0); + return false; + }else if (m_core.get_blockchain_storage().get_checkpoints().get_top_checkpoint_height() < hshd.last_checkpoint_height) + { + LOG_PRINT_MAGENTA("Remote node have longer checkpoints zone( " << hshd.last_checkpoint_height << ") " << + "that local (" << m_core.get_blockchain_storage().get_checkpoints().get_top_checkpoint_height() << ")" << + "That means that current software is outdated, please updated it.", LOG_LEVEL_0); + } + + context.m_state = currency_connection_context::state_synchronizing; + context.m_remote_blockchain_height = hshd.current_height; + //let the socket to send response to handshake, but request callback, to let send request data after response + LOG_PRINT_L3("requesting callback"); + ++context.m_priv.m_callback_request_count; + m_p2p->request_callback(context); + //update progress vars + if (m_max_height_seen < hshd.current_height) + m_max_height_seen = hshd.current_height; + if (!m_core_inital_height) + m_core_inital_height = m_core.get_current_blockchain_size(); + + return true; + } + //------------------------------------------------------------------------------------------------------------------------ + template + uint64_t t_currency_protocol_handler::get_core_inital_height() + { + return m_core_inital_height; + } + //------------------------------------------------------------------------------------------------------------------------ + template + uint64_t t_currency_protocol_handler::get_max_seen_height() + { + return m_max_height_seen; + } + //------------------------------------------------------------------------------------------------------------------------ + template + bool t_currency_protocol_handler::get_payload_sync_data(CORE_SYNC_DATA& hshd) + { + m_core.get_blockchain_top(hshd.current_height, hshd.top_id); + hshd.current_height +=1; + hshd.last_checkpoint_height = m_core.get_blockchain_storage().get_checkpoints().get_top_checkpoint_height(); + hshd.core_time = m_core.get_blockchain_storage().get_core_runtime_config().get_core_time(); + hshd.client_version = PROJECT_VERSION_LONG; + return true; + } + //------------------------------------------------------------------------------------------------------------------------ + template + bool t_currency_protocol_handler::get_payload_sync_data(blobdata& data) + { + CORE_SYNC_DATA hsd = AUTO_VAL_INIT(hsd); + get_payload_sync_data(hsd); + epee::serialization::store_t_to_binary(hsd, data); + return true; + } + //------------------------------------------------------------------------------------------------------------------------ + template + int t_currency_protocol_handler::handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, currency_connection_context& context) + { + if(context.m_state != currency_connection_context::state_normal) + return 1; + + + //check if block already exists + block b = AUTO_VAL_INIT(b); + block_verification_context bvc = AUTO_VAL_INIT(bvc); + if (!m_core.parse_block(arg.b.block, b, bvc)) + { + LOG_PRINT_RED("Block parsing failed, dropping connection", LOG_LEVEL_0); + m_p2p->drop_connection(context); + return 1; + } + crypto::hash block_id = get_block_hash(b); + LOG_PRINT_GREEN("[HANDLE]NOTIFY_NEW_BLOCK " << block_id << " HEIGHT " << get_block_height(b) << " (hop " << arg.hop << ")", LOG_LEVEL_2); + + CRITICAL_REGION_BEGIN(m_blocks_id_que_lock); + auto it = m_blocks_id_que.find(block_id); + if (it != m_blocks_id_que.end()) + { + //already have this block handler in que + LOG_PRINT("Block " << block_id << " already in processing que", LOG_LEVEL_2); + return 1; + } + else + { + m_blocks_id_que.insert(block_id); + } + CRITICAL_REGION_END(); + auto slh = epee::misc_utils::create_scope_leave_handler([&]() + { + CRITICAL_REGION_LOCAL(m_blocks_id_que_lock); + auto it = m_blocks_id_que.find(block_id); + CHECK_AND_ASSERT_MES_NO_RET(it != m_blocks_id_que.end(), "Internal error, block " << block_id << " not found in m_blocks_id_que"); + m_blocks_id_que.erase(it); + }); + + if (m_core.have_block(block_id)) + { + LOG_PRINT_L3("Block " << block_id << " already in core"); + return 1; + } + + //pre-validate block here, and propagate it to network asap to avoid latency of handling big block (tx flood) + bool prevalidate_relayed = false; + if (m_core.pre_validate_block(b, bvc, block_id) && bvc.m_added_to_main_chain) + { + //not alternative block, relay it + ++arg.hop; + relay_block(arg, context); + prevalidate_relayed = true; + } + + //now actually process block + for(auto tx_blob_it = arg.b.txs.begin(); tx_blob_it!=arg.b.txs.end();tx_blob_it++) + { + currency::tx_verification_context tvc = AUTO_VAL_INIT(tvc); + m_core.handle_incoming_tx(*tx_blob_it, tvc, true); + if(tvc.m_verification_failed) + { + LOG_PRINT_L0("Block verification failed: transaction verification failed, dropping connection"); + m_p2p->drop_connection(context); + return 1; + } + } + + m_core.pause_mine(); + m_core.handle_incoming_block(b, bvc); + m_core.resume_mine(); + if(bvc.m_verification_failed) + { + LOG_PRINT_L0("Block verification failed, dropping connection"); + m_p2p->drop_connection(context); + return 1; + } + LOG_PRINT_GREEN("[HANDLE]NOTIFY_NEW_BLOCK EXTRA: id: " << block_id + << ",bvc.m_added_to_main_chain " << bvc.m_added_to_main_chain + << ",prevalidate_result " << prevalidate_relayed + << ",bvc.added_to_altchain " << bvc.added_to_altchain + << ",bvc.m_marked_as_orphaned " << bvc.m_marked_as_orphaned, LOG_LEVEL_2); + + if (bvc.m_added_to_main_chain || (bvc.added_to_altchain && bvc.height_difference < 2)) + { + if (!prevalidate_relayed) + { + // pre-validation failed prevoiusly, but complete check was success, not an alternative block + ++arg.hop; + //TODO: Add here announce protocol usage + relay_block(arg, context); + } + }else if(bvc.m_marked_as_orphaned) + { + context.m_state = currency_connection_context::state_synchronizing; + NOTIFY_REQUEST_CHAIN::request r = boost::value_initialized(); + m_core.get_short_chain_history(r.block_ids); + LOG_PRINT_MAGENTA("State changed to state_synchronizing.", LOG_LEVEL_2); + LOG_PRINT_L2("[REQUEST]NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() ); + post_notify(r, context); + } + + return 1; + } + //------------------------------------------------------------------------------------------------------------------------ + template + int t_currency_protocol_handler::handle_notify_new_transactions(int command, NOTIFY_NEW_TRANSACTIONS::request& arg, currency_connection_context& context) + { + if(context.m_state != currency_connection_context::state_normal) + return 1; + uint64_t inital_tx_count = arg.txs.size(); + TIME_MEASURE_START_MS(new_transactions_handle_time); + for(auto tx_blob_it = arg.txs.begin(); tx_blob_it!=arg.txs.end();) + { + currency::tx_verification_context tvc = AUTO_VAL_INIT(tvc); + + m_core.handle_incoming_tx(*tx_blob_it, tvc, false); + if(tvc.m_verification_failed) + { + LOG_PRINT_L0("NOTIFY_NEW_TRANSACTIONS: Tx verification failed, dropping connection"); + m_p2p->drop_connection(context); + + return 1; + } + if(tvc.m_should_be_relayed) + ++tx_blob_it; + else + arg.txs.erase(tx_blob_it++); + } + + if(arg.txs.size()) + { + //TODO: add announce usage here + relay_transactions(arg, context); + } + TIME_MEASURE_FINISH_MS(new_transactions_handle_time); + + LOG_PRINT_L2("NOTIFY_NEW_TRANSACTIONS: " << new_transactions_handle_time << "ms (inital_tx_count: " << inital_tx_count << ", relayed_tx_count: " << arg.txs.size() << ")"); + + return true; + } + //------------------------------------------------------------------------------------------------------------------------ + template + int t_currency_protocol_handler::handle_request_get_objects(int command, NOTIFY_REQUEST_GET_OBJECTS::request& arg, currency_connection_context& context) + { + NOTIFY_RESPONSE_GET_OBJECTS::request rsp; + if(!m_core.handle_get_objects(arg, rsp, context)) + { + LOG_ERROR_CCONTEXT("failed to handle request NOTIFY_REQUEST_GET_OBJECTS, dropping connection"); + m_p2p->drop_connection(context); + } + LOG_PRINT_L2("[HANDLE]NOTIFY_RESPONSE_GET_OBJECTS: blocks.size()=" << rsp.blocks.size() << ", txs.size()=" << rsp.txs.size() + << ", rsp.m_current_blockchain_height=" << rsp.current_blockchain_height << ", missed_ids.size()=" << rsp.missed_ids.size()); + post_notify(rsp, context); + return 1; + } + //------------------------------------------------------------------------------------------------------------------------ + template + bool t_currency_protocol_handler::check_stop_flag_and_drop_cc(currency_connection_context& context) + { + if (m_p2p->is_stop_signal_sent() || m_want_stop) + { + m_p2p->drop_connection(context); + return true; + } + return false; + } +#define CHECK_STOP_FLAG__DROP_AND_RETURN_IF_SET(ret_v, msg) if (check_stop_flag_and_drop_cc(context)) { LOG_PRINT_YELLOW("Stop flag detected within NOTIFY_RESPONSE_GET_OBJECTS. " << msg, LOG_LEVEL_0); return ret_v; } + //------------------------------------------------------------------------------------------------------------------------ + template + int t_currency_protocol_handler::handle_response_get_objects(int command, NOTIFY_RESPONSE_GET_OBJECTS::request& arg, currency_connection_context& context) + { + LOG_PRINT_L2("NOTIFY_RESPONSE_GET_OBJECTS"); + if(context.m_last_response_height > arg.current_blockchain_height) + { + LOG_ERROR_CCONTEXT("sent wrong NOTIFY_HAVE_OBJECTS: arg.m_current_blockchain_height=" << arg.current_blockchain_height + << " < m_last_response_height=" << context.m_last_response_height << ", dropping connection"); + m_p2p->drop_connection(context); + return 1; + } + + context.m_remote_blockchain_height = arg.current_blockchain_height; + + uint64_t total_blocks_parsing_time = 0; + size_t count = 0; + for (const block_complete_entry& block_entry : arg.blocks) + { + CHECK_STOP_FLAG__DROP_AND_RETURN_IF_SET(1, "Blocks processing interrupted, connection dropped"); + + ++count; + block b; + TIME_MEASURE_START(block_parsing_time); + if(!parse_and_validate_block_from_blob(block_entry.block, b)) + { + LOG_ERROR_CCONTEXT("sent wrong block: failed to parse and validate block: \r\n" + << string_tools::buff_to_hex_nodelimer(block_entry.block) << "\r\n dropping connection"); + m_p2p->drop_connection(context); + m_p2p->add_ip_fail(context.m_remote_ip); + return 1; + } + TIME_MEASURE_FINISH(block_parsing_time); + total_blocks_parsing_time += block_parsing_time; + + //to avoid concurrency in core between connections, suspend connections which delivered block later then first one + if(count == 2) + { + if(m_core.have_block(get_block_hash(b))) + { + context.m_state = currency_connection_context::state_idle; + context.m_priv.m_needed_objects.clear(); + context.m_priv.m_requested_objects.clear(); + LOG_PRINT_L1("Connection set to idle state."); + return 1; + } + } + + auto req_it = context.m_priv.m_requested_objects.find(get_block_hash(b)); + if(req_it == context.m_priv.m_requested_objects.end()) + { + LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << string_tools::pod_to_hex(get_blob_hash(block_entry.block)) + << " wasn't requested, dropping connection"); + m_p2p->drop_connection(context); + return 1; + } + if(b.tx_hashes.size() != block_entry.txs.size()) + { + LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << string_tools::pod_to_hex(get_blob_hash(block_entry.block)) + << ", tx_hashes.size()=" << b.tx_hashes.size() << " mismatch with block_complete_entry.m_txs.size()=" << block_entry.txs.size() << ", dropping connection"); + m_p2p->drop_connection(context); + return 1; + } + + context.m_priv.m_requested_objects.erase(req_it); + } + + LOG_PRINT_CYAN("Block parsing time avr: " << (count > 0 ? total_blocks_parsing_time / count : 0) << " mcs, total for " << count << " blocks: " << total_blocks_parsing_time / 1000 << " ms", LOG_LEVEL_2); + + if(context.m_priv.m_requested_objects.size()) + { + LOG_PRINT_RED("returned not all requested objects (context.m_priv.m_requested_objects.size()=" + << context.m_priv.m_requested_objects.size() << "), dropping connection", LOG_LEVEL_0); + m_p2p->drop_connection(context); + return 1; + } + + { + m_core.pause_mine(); + misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler( + boost::bind(&t_core::resume_mine, &m_core)); + + for (const block_complete_entry& block_entry : arg.blocks) + { + CHECK_STOP_FLAG__DROP_AND_RETURN_IF_SET(1, "Blocks processing interrupted, connection dropped"); + + //process transactions + TIME_MEASURE_START(transactions_process_time); + for (const auto& tx_blob : block_entry.txs) + { + CHECK_STOP_FLAG__DROP_AND_RETURN_IF_SET(1, "Block txs processing interrupted, connection dropped"); + + tx_verification_context tvc = AUTO_VAL_INIT(tvc); + m_core.handle_incoming_tx(tx_blob, tvc, true); + if(tvc.m_verification_failed) + { + LOG_ERROR_CCONTEXT("transaction verification failed on NOTIFY_RESPONSE_GET_OBJECTS, \r\ntx_id = " + << string_tools::pod_to_hex(get_blob_hash(tx_blob)) << ", dropping connection"); + m_p2p->drop_connection(context); + return 1; + } + } + TIME_MEASURE_FINISH(transactions_process_time); + + //process block + TIME_MEASURE_START(block_process_time); + block_verification_context bvc = boost::value_initialized(); + + m_core.handle_incoming_block(block_entry.block, bvc, false); + + if(bvc.m_verification_failed) + { + LOG_PRINT_L0("Block verification failed, dropping connection"); + m_p2p->drop_connection(context); + m_p2p->add_ip_fail(context.m_remote_ip); + return 1; + } + if(bvc.m_marked_as_orphaned) + { + LOG_PRINT_L0("Block received at sync phase was marked as orphaned, dropping connection"); + m_p2p->drop_connection(context); + m_p2p->add_ip_fail(context.m_remote_ip); + return 1; + } + + TIME_MEASURE_FINISH(block_process_time); + LOG_PRINT_L2("Block process time: " << block_process_time + transactions_process_time << "(" << transactions_process_time << "/" << block_process_time << ")ms"); + } + } + uint64_t current_size = m_core.get_blockchain_storage().get_current_blockchain_size(); + LOG_PRINT_YELLOW(">>>>>>>>> sync progress: " << arg.blocks.size() << " blocks added, now have " + << current_size << " of " << context.m_remote_blockchain_height + << " ( " << std::fixed << std::setprecision(2) << current_size * 100.0 / context.m_remote_blockchain_height << "% ) and " + << context.m_remote_blockchain_height - current_size << " blocks left" + , LOG_LEVEL_0); + + request_missing_objects(context, true); + return 1; + } +#undef CHECK_STOP_FLAG__DROP_AND_RETURN_IF_SET + //------------------------------------------------------------------------------------------------------------------------ + template + bool t_currency_protocol_handler::on_idle() + { + bool have_synced_conn = false; + m_p2p->for_each_connection([&](currency_connection_context& context, nodetool::peerid_type peer_id)->bool{ + if (context.m_state == currency_connection_context::state_normal) + { + have_synced_conn = true; + return false; + } + return true; + }); + + if (have_synced_conn && !m_synchronized) + { + on_connection_synchronized(); + m_synchronized = true; + LOG_PRINT_MAGENTA("Synchronized set to TRUE (idle)", LOG_LEVEL_0); + } + else if (!have_synced_conn && m_synchronized) + { + LOG_PRINT_MAGENTA("Synchronized set to FALSE (idle)", LOG_LEVEL_0); + m_synchronized = false; + } + + return m_core.on_idle(); + } + //------------------------------------------------------------------------------------------------------------------------ + template + int t_currency_protocol_handler::handle_request_chain(int command, NOTIFY_REQUEST_CHAIN::request& arg, currency_connection_context& context) + { + NOTIFY_RESPONSE_CHAIN_ENTRY::request r; + if(!m_core.find_blockchain_supplement(arg.block_ids, r)) + { + LOG_ERROR_CCONTEXT("Failed to handle NOTIFY_REQUEST_CHAIN."); + return 1; + } + LOG_PRINT_L2("[HANDLE]NOTIFY_RESPONSE_CHAIN_ENTRY: m_start_height=" << r.start_height << ", m_total_height=" << r.total_height << ", m_block_ids.size()=" << r.m_block_ids.size()); + post_notify(r, context); + return 1; + } + //------------------------------------------------------------------------------------------------------------------------ + template + bool t_currency_protocol_handler::request_missing_objects(currency_connection_context& context, bool check_having_blocks) + { + if(context.m_priv.m_needed_objects.size()) + { + //we know objects that we need, request this objects + NOTIFY_REQUEST_GET_OBJECTS::request req; + size_t count = 0; + auto it = context.m_priv.m_needed_objects.begin(); + uint64_t requested_cumulative_size = 0; + + while (it != context.m_priv.m_needed_objects.end() && count < BLOCKS_SYNCHRONIZING_DEFAULT_COUNT && requested_cumulative_size < BLOCKS_SYNCHRONIZING_DEFAULT_SIZE) + { + if( !(check_having_blocks && m_core.have_block(it->h))) + { + req.blocks.push_back(it->h); + requested_cumulative_size += it->cumul_size; + ++count; + context.m_priv.m_requested_objects.insert(it->h); + } + context.m_priv.m_needed_objects.erase(it++); + } + + LOG_PRINT_L2("[REQUESTING]NOTIFY_REQUEST_GET_OBJECTS: requested_cumulative_size=" << requested_cumulative_size << ", blocks.size()=" << req.blocks.size() << ", txs.size()=" << req.txs.size()); + post_notify(req, context); + }else if(context.m_last_response_height < context.m_remote_blockchain_height-1) + {//we have to fetch more objects ids, request blockchain entry + + NOTIFY_REQUEST_CHAIN::request r = boost::value_initialized(); + m_core.get_short_chain_history(r.block_ids); + LOG_PRINT_L2("[REQUESTING]NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() ); + post_notify(r, context); + }else + { + CHECK_AND_ASSERT_MES(context.m_last_response_height == context.m_remote_blockchain_height-1 + && !context.m_priv.m_needed_objects.size() + && !context.m_priv.m_requested_objects.size(), false, "request_missing_blocks final condition failed!" + << "\r\nm_last_response_height=" << context.m_last_response_height + << "\r\nm_remote_blockchain_height=" << context.m_remote_blockchain_height + << "\r\nm_needed_objects.size()=" << context.m_priv.m_needed_objects.size() + << "\r\nm_requested_objects.size()=" << context.m_priv.m_requested_objects.size() + << "\r\non connection [" << net_utils::print_connection_context_short(context)<< "]"); + + context.m_state = currency_connection_context::state_normal; + LOG_PRINT_GREEN("[HANDLE]NOTIFY_REQUEST_GET_OBJECTS: SYNCHRONIZED OK", LOG_LEVEL_0); + on_connection_synchronized(); + } + return true; + } + //------------------------------------------------------------------------------------------------------------------------ + template + bool t_currency_protocol_handler::on_connection_synchronized() + { + bool val_expected = false; + if (m_have_been_synchronized.compare_exchange_strong(val_expected, true)) + { + m_core.on_synchronized(); + } + return true; + } + //------------------------------------------------------------------------------------------------------------------------ + template + void t_currency_protocol_handler::relay_que_worker() + { + while (!m_want_stop) + { + std::list local_que; + { + std::unique_lock lk(m_relay_que_lock); + //m_relay_que_cv.wait(lk); + local_que.swap(m_relay_que); + } + if (local_que.size()) + process_current_relay_que(local_que); + + epee::misc_utils::sleep_no_w(500); + } + } + //------------------------------------------------------------------------------------------------------------------------ + template + void t_currency_protocol_handler::process_current_relay_que(const std::list& que) + { + if (que.size() > 1){LOG_PRINT_MAGENTA("RELAY_QUE: " << que.size(), LOG_LEVEL_0);} + + TIME_MEASURE_START_MS(ms); + std::stringstream debug_ss; + std::list connections; + m_p2p->get_connections(connections); + for (auto& cc : connections) + { + NOTIFY_NEW_TRANSACTIONS::request req = AUTO_VAL_INIT(req); + for (auto& qe : que) + { + //exclude relaying to original sender + if (qe.second.m_connection_id == cc.m_connection_id) + continue; + req.txs.insert(req.txs.begin(), qe.first.txs.begin(), qe.first.txs.end()); + } + if (req.txs.size()) + { + post_notify(req, cc); + print_connection_context_short(cc, debug_ss); + debug_ss << ": " << req.txs.size() << ENDL; + } + } + TIME_MEASURE_FINISH_MS(ms); + LOG_PRINT_GREEN("[POST RELAY] NOTIFY_NEW_TRANSACTIONS relayed (" << ms << "ms)contexts list: " << debug_ss.str(), LOG_LEVEL_2); + + } + //------------------------------------------------------------------------------------------------------------------------ + template + size_t t_currency_protocol_handler::get_synchronized_connections_count() + { + size_t count = 0; + m_p2p->for_each_connection([&](currency_connection_context& context, nodetool::peerid_type peer_id)->bool{ + if (context.m_state == currency_connection_context::state_normal) + ++count; + return true; + }); + return count; + } + //------------------------------------------------------------------------------------------------------------------------ + template + size_t t_currency_protocol_handler::get_synchronizing_connections_count() + { + size_t count = 0; + m_p2p->for_each_connection([&](currency_connection_context& context, nodetool::peerid_type peer_id)->bool{ + if (context.m_state == currency_connection_context::state_synchronizing) + ++count; + return true; + }); + return count; + } + //------------------------------------------------------------------------------------------------------------------------ + template + int64_t t_currency_protocol_handler::get_net_time_delta_median() + { + std::vector deltas; + m_p2p->for_each_connection([&](currency_connection_context& context, nodetool::peerid_type peer_id)->bool{ + deltas.push_back(context.m_time_delta); + return true; + }); + + return epee::misc_utils::median(deltas); + } + //------------------------------------------------------------------------------------------------------------------------ + template + int t_currency_protocol_handler::handle_response_chain_entry(int command, NOTIFY_RESPONSE_CHAIN_ENTRY::request& arg, currency_connection_context& context) + { + LOG_PRINT_L2("NOTIFY_RESPONSE_CHAIN_ENTRY: m_block_ids.size()=" << arg.m_block_ids.size() + << ", m_start_height=" << arg.start_height << ", m_total_height=" << arg.total_height); + + if(!arg.m_block_ids.size()) + { + LOG_ERROR_CCONTEXT("sent empty m_block_ids, dropping connection"); + m_p2p->drop_connection(context); + m_p2p->add_ip_fail(context.m_remote_ip); + return 1; + } + + if(!m_core.have_block(arg.m_block_ids.front().h)) + { + LOG_ERROR_CCONTEXT("sent m_block_ids starting from unknown id: " + << string_tools::pod_to_hex(arg.m_block_ids.front()) << " , dropping connection"); + m_p2p->drop_connection(context); + m_p2p->add_ip_fail(context.m_remote_ip); + return 1; + } + + context.m_remote_blockchain_height = arg.total_height; + context.m_last_response_height = arg.start_height + arg.m_block_ids.size()-1; + if(context.m_last_response_height > context.m_remote_blockchain_height) + { + LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_CHAIN_ENTRY, with \r\nm_total_height=" << arg.total_height + << "\r\nm_start_height=" << arg.start_height + << "\r\nm_block_ids.size()=" << arg.m_block_ids.size()); + //m_p2p->drop_connection(context); + } + + BOOST_FOREACH(auto& bl_details, arg.m_block_ids) + { + if (!m_core.have_block(bl_details.h)) + context.m_priv.m_needed_objects.push_back(bl_details); + } + + request_missing_objects(context, false); + return 1; + } + //------------------------------------------------------------------------------------------------------------------------ + template + bool t_currency_protocol_handler::relay_block(NOTIFY_NEW_BLOCK::request& arg, currency_connection_context& exclude_context) + { + return relay_post_notify(arg, exclude_context); + } + //------------------------------------------------------------------------------------------------------------------------ + template + bool t_currency_protocol_handler::relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, currency_connection_context& exclude_context) + { +#ifdef ASYNC_RELAY_MODE + { + std::unique_lock lk(m_relay_que_lock); + m_relay_que.push_back(AUTO_VAL_INIT(relay_que_entry())); + m_relay_que.back().first = arg; + m_relay_que.back().second = exclude_context; + } + //m_relay_que_cv.notify_all(); + return true; +#else + return relay_post_notify(arg, exclude_context); +#endif + } +} diff --git a/src/currency_protocol/currency_protocol_handler_common.h b/src/currency_protocol/currency_protocol_handler_common.h new file mode 100644 index 00000000..ccbd88b2 --- /dev/null +++ b/src/currency_protocol/currency_protocol_handler_common.h @@ -0,0 +1,39 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include "p2p/net_node_common.h" +#include "currency_protocol/currency_protocol_defs.h" +#include "currency_core/connection_context.h" +namespace currency +{ + /************************************************************************/ + /* */ + /************************************************************************/ + struct i_currency_protocol + { + virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, currency_connection_context& exclude_context)=0; + virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, currency_connection_context& exclude_context)=0; + //virtual bool request_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, currency_connection_context& context)=0; + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + struct currency_protocol_stub: public i_currency_protocol + { + virtual bool relay_block(NOTIFY_NEW_BLOCK::request& /*arg*/, currency_connection_context& /*exclude_context*/) + { + return false; + } + virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& /*arg*/, currency_connection_context& /*exclude_context*/) + { + return false; + } + + }; +} diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp new file mode 100644 index 00000000..459cc8e2 --- /dev/null +++ b/src/daemon/daemon.cpp @@ -0,0 +1,320 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +// node.cpp : Defines the entry point for the console application. +// + +#include "include_base_utils.h" +#include "version.h" + +using namespace epee; + +#include + +#include "crypto/hash.h" +#include "console_handler.h" +#include "p2p/net_node.h" +#include "currency_core/checkpoints_create.h" +#include "currency_core/currency_core.h" +#include "rpc/core_rpc_server.h" +#include "currency_protocol/currency_protocol_handler.h" +#include "daemon_commands_handler.h" +#include "common/miniupnp_helper.h" +#include "version.h" +#include "currency_core/core_tools.h" + +#if defined(WIN32) +#include +#pragma comment(lib, "ntdll") // <-- why do we need this? +#endif + + +//TODO: need refactoring here. (template classes can't be used in BOOST_CLASS_VERSION) +BOOST_CLASS_VERSION(nodetool::node_server >, CURRENT_P2P_STORAGE_ARCHIVE_VER); + + +namespace po = boost::program_options; + +bool command_line_preprocessor(const boost::program_options::variables_map& vm); + +int main(int argc, char* argv[]) +{ + string_tools::set_module_name_and_folder(argv[0]); +#ifdef WIN32 + _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); + //_CrtSetAllocHook(alloc_hook); + +#endif + log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2); + log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL); + log_space::log_singletone::enable_channels("core,currency_protocol,tx_pool,wallet"); + LOG_PRINT_L0("Starting..."); + + tools::signal_handler::install_fatal([](int sig_number, void* address) { + LOG_ERROR("\n\nFATAL ERROR\nsig: " << sig_number << ", address: " << address); + std::fflush(nullptr); // all open output streams are flushed + }); + + TRY_ENTRY(); + + po::options_description desc_cmd_only("Command line options"); + po::options_description desc_cmd_sett("Command line options and settings options", 130, 83); + + command_line::add_arg(desc_cmd_only, command_line::arg_help); + command_line::add_arg(desc_cmd_only, command_line::arg_version); + command_line::add_arg(desc_cmd_only, command_line::arg_os_version); + // tools::get_default_data_dir() can't be called during static initialization + command_line::add_arg(desc_cmd_only, command_line::arg_data_dir, tools::get_default_data_dir()); + command_line::add_arg(desc_cmd_only, command_line::arg_config_file); + + command_line::add_arg(desc_cmd_sett, command_line::arg_log_dir); + command_line::add_arg(desc_cmd_sett, command_line::arg_log_level); + command_line::add_arg(desc_cmd_sett, command_line::arg_console); + command_line::add_arg(desc_cmd_sett, command_line::arg_show_details); + command_line::add_arg(desc_cmd_sett, command_line::arg_show_rpc_autodoc); + + + arg_market_disable.default_value = true; + arg_market_disable.not_use_default = false; + + currency::core::init_options(desc_cmd_sett); + currency::core_rpc_server::init_options(desc_cmd_sett); + nodetool::node_server >::init_options(desc_cmd_sett); +#ifdef USE_OPENCL + currency::gpu_miner::init_options(desc_cmd_sett); +#else + currency::miner::init_options(desc_cmd_sett); +#endif + bc_services::bc_offers_service::init_options(desc_cmd_sett); + + + po::options_description desc_options("Allowed options"); + desc_options.add(desc_cmd_only).add(desc_cmd_sett); + + po::variables_map vm; + bool r = command_line::handle_error_helper(desc_options, [&]() + { + po::store(po::parse_command_line(argc, argv, desc_options), vm); + + if (command_line::get_arg(vm, command_line::arg_help)) + { + std::cout << CURRENCY_NAME << " v" << PROJECT_VERSION_LONG << ENDL << ENDL; + std::cout << desc_options << std::endl; + return false; + } +#ifdef USE_OPENCL + if (currency::gpu_miner::handle_cli_info_commands(vm)) + return false; +#endif + + std::string data_dir = command_line::get_arg(vm, command_line::arg_data_dir); + std::string config = command_line::get_arg(vm, command_line::arg_config_file); + + boost::filesystem::path data_dir_path(data_dir); + boost::filesystem::path config_path(config); + if (!config_path.has_parent_path()) + { + config_path = data_dir_path / config_path; + } + + boost::system::error_code ec; + if (boost::filesystem::exists(config_path, ec)) + { + po::store(po::parse_config_file(config_path.string().c_str(), desc_cmd_sett), vm); + } + po::notify(vm); + + return true; + }); + if (!r) + return 1; + + //set up logging options + std::string log_dir; + std::string log_file_name = log_space::log_singletone::get_default_log_file(); + //check if there was specific option + if (command_line::has_arg(vm, command_line::arg_log_dir)) + { + log_dir = command_line::get_arg(vm, command_line::arg_log_dir); + } + else + { + log_dir = command_line::get_arg(vm, command_line::arg_data_dir); + } + + log_space::log_singletone::add_logger(LOGGER_FILE, log_file_name.c_str(), log_dir.c_str()); + LOG_PRINT_L0(CURRENCY_NAME << " v" << PROJECT_VERSION_LONG); + + if (command_line_preprocessor(vm)) + { + return 0; + } + + + + + LOG_PRINT("Module folder: " << argv[0], LOG_LEVEL_0); + + //create objects and link them + bc_services::bc_offers_service offers_service(nullptr); + currency::core ccore(NULL); + currency::t_currency_protocol_handler cprotocol(ccore, NULL ); + nodetool::node_server > p2psrv(cprotocol); + currency::core_rpc_server rpc_server(ccore, p2psrv, offers_service); + cprotocol.set_p2p_endpoint(&p2psrv); + ccore.set_currency_protocol(&cprotocol); + daemon_cmmands_handler dch(p2psrv, rpc_server); + tools::miniupnp_helper upnp_helper; + ccore.get_blockchain_storage().get_attachment_services_manager().add_service(&offers_service); + + if (command_line::get_arg(vm, command_line::arg_show_rpc_autodoc)) + { + LOG_PRINT_L0("Dumping RPC auto-generated documents!"); + epee::net_utils::http::http_request_info query_info; + epee::net_utils::http::http_response_info response_info; + epee::net_utils::connection_context_base conn_context; + std::string generate_reference = std::string("RPC_COMMANDS_LIST:\n"); + bool call_found = false; + rpc_server.handle_http_request_map(query_info, response_info, conn_context, call_found, generate_reference); + std::string json_rpc_reference; + query_info.m_URI = JSON_RPC_REFERENCE_MARKER; + query_info.m_body = "{\"jsonrpc\": \"2.0\", \"method\": \"nonexisting_method\", \"params\": {}},"; + rpc_server.handle_http_request_map(query_info, response_info, conn_context, call_found, json_rpc_reference); + + LOG_PRINT_L0(generate_reference << ENDL << "----------------------------------------" << ENDL << json_rpc_reference); + } + + + bool res = false; + //initialize objects + LOG_PRINT_L0("Initializing p2p server..."); + res = p2psrv.init(vm); + CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize p2p server."); + LOG_PRINT_L0("P2p server initialized OK on port: " << p2psrv.get_this_peer_port()); + + LOG_PRINT_L0("Starting UPnP"); + upnp_helper.start_regular_mapping(p2psrv.get_this_peer_port(), p2psrv.get_this_peer_port(), 20*60*1000); + + LOG_PRINT_L0("Initializing currency protocol..."); + res = cprotocol.init(vm); + CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize currency protocol."); + LOG_PRINT_L0("Currency protocol initialized OK"); + + LOG_PRINT_L0("Initializing core rpc server..."); + res = rpc_server.init(vm); + CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core rpc server."); + LOG_PRINT_GREEN("Core rpc server initialized OK on port: " << rpc_server.get_binded_port(), LOG_LEVEL_0); + + //initialize core here + LOG_PRINT_L0("Initializing core..."); + res = ccore.init(vm); + CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core"); + LOG_PRINT_L0("Core initialized OK"); + + auto& bcs = ccore.get_blockchain_storage(); + if (!offers_service.is_disabled() && bcs.get_current_blockchain_size() > 1 && bcs.get_top_block_id() != offers_service.get_last_seen_block_id()) + { + res = resync_market(bcs, offers_service); + CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core: resync_market"); + } + + currency::checkpoints checkpoints; + res = currency::create_checkpoints(checkpoints); + CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize checkpoints"); + res = ccore.set_checkpoints(std::move(checkpoints)); + CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core"); + + // start components + if (!command_line::has_arg(vm, command_line::arg_console)) + { + dch.start_handling(); + } + + LOG_PRINT_L0("Starting core rpc server..."); + res = rpc_server.run(2, false); + CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core rpc server."); + LOG_PRINT_L0("Core rpc server started ok"); + + + tools::signal_handler::install([&dch, &p2psrv] { + dch.stop_handling(); + p2psrv.send_stop_signal(); + }); + + LOG_PRINT_L0("Starting p2p net loop..."); + p2psrv.run(); + LOG_PRINT_L0("p2p net loop stopped"); + + LOG_PRINT_L0("Stopping core rpc server..."); + rpc_server.send_stop_signal(); + rpc_server.timed_wait_server_stop(5000); + + //deinitialize components + LOG_PRINT_L0("Deinitializing core..."); + offers_service.set_last_seen_block_id(ccore.get_blockchain_storage().get_top_block_id()); + ccore.deinit(); + + LOG_PRINT_L0("Deinitializing market..."); + (static_cast(offers_service)).deinit(); + + LOG_PRINT_L0("Deinitializing rpc server ..."); + rpc_server.deinit(); + LOG_PRINT_L0("Deinitializing currency_protocol..."); + cprotocol.deinit(); + LOG_PRINT_L0("Deinitializing p2p..."); + p2psrv.deinit(); + + + ccore.set_currency_protocol(NULL); + cprotocol.set_p2p_endpoint(NULL); + + LOG_PRINT("Node stopped.", LOG_LEVEL_0); + return 0; + + CATCH_ENTRY_L0("main", 1); +} + +bool command_line_preprocessor(const boost::program_options::variables_map& vm) +{ + bool exit = false; + if (command_line::get_arg(vm, command_line::arg_version)) + { + std::cout << CURRENCY_NAME << " v" << PROJECT_VERSION_LONG << ENDL; + exit = true; + } + + if (command_line::get_arg(vm, command_line::arg_show_details)) + { + currency::print_currency_details(); + exit = true; + } + if (command_line::get_arg(vm, command_line::arg_os_version)) + { + std::cout << "OS: " << tools::get_os_version_string() << ENDL; + exit = true; + } + + if (exit) + { + return true; + } + + if (command_line::has_arg(vm, command_line::arg_log_level)) + { + int new_log_level = command_line::get_arg(vm, command_line::arg_log_level); + if (new_log_level < LOG_LEVEL_MIN || new_log_level > LOG_LEVEL_MAX) + { + LOG_PRINT_L0("Wrong log level value: "); + } + else if (log_space::get_set_log_detalisation_level(false) != new_log_level) + { + log_space::get_set_log_detalisation_level(true, new_log_level); + LOG_PRINT_L0("LOG_LEVEL set to " << new_log_level); + } + } + + return false; +} diff --git a/src/daemon/daemon_commands_handler.h b/src/daemon/daemon_commands_handler.h new file mode 100644 index 00000000..2be07432 --- /dev/null +++ b/src/daemon/daemon_commands_handler.h @@ -0,0 +1,613 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include + +#include "console_handler.h" +#include "p2p/net_node.h" +#include "currency_protocol/currency_protocol_handler.h" +#include "common/util.h" +#include "crypto/hash.h" +#include "warnings.h" +#include "currency_core/bc_offers_service.h" + +PUSH_WARNINGS +DISABLE_VS_WARNINGS(4100) + +class daemon_cmmands_handler +{ + typedef nodetool::node_server > srv_type; + srv_type& m_srv; + currency::core_rpc_server& m_rpc; + typedef epee::srv_console_handlers_binder > > cmd_binder_type; + cmd_binder_type m_cmd_binder; +public: + daemon_cmmands_handler(nodetool::node_server >& srv, currency::core_rpc_server& rpc) :m_srv(srv), m_rpc(rpc) + { + m_cmd_binder.set_handler("help", boost::bind(&console_handlers_binder::help, &m_cmd_binder, _1), "Show this help"); + m_cmd_binder.set_handler("print_pl", boost::bind(&daemon_cmmands_handler::print_pl, this, _1), "Print peer list"); + m_cmd_binder.set_handler("print_cn", boost::bind(&daemon_cmmands_handler::print_cn, this, _1), "Print connections"); + m_cmd_binder.set_handler("print_bc", boost::bind(&daemon_cmmands_handler::print_bc, this, _1), "Print blockchain info in a given blocks range, print_bc []"); + m_cmd_binder.set_handler("print_bc_tx", boost::bind(&daemon_cmmands_handler::print_bc_tx, this, _1), "Print blockchain info with trnsactions in a given blocks range, print_bc []"); + //m_cmd_binder.set_handler("print_bci", boost::bind(&daemon_cmmands_handler::print_bci, this, _1)); + m_cmd_binder.set_handler("print_bc_outs", boost::bind(&daemon_cmmands_handler::print_bc_outs, this, _1)); + m_cmd_binder.set_handler("print_market", boost::bind(&daemon_cmmands_handler::print_market, this, _1)); + m_cmd_binder.set_handler("print_bc_outs_stat", boost::bind(&daemon_cmmands_handler::print_bc_outs_stat, this, _1)); + m_cmd_binder.set_handler("print_block", boost::bind(&daemon_cmmands_handler::print_block, this, _1), "Print block, print_block | "); + m_cmd_binder.set_handler("print_tx", boost::bind(&daemon_cmmands_handler::print_tx, this, _1), "Print transaction, print_tx "); + m_cmd_binder.set_handler("start_mining", boost::bind(&daemon_cmmands_handler::start_mining, this, _1), "Start mining for specified address, start_mining [threads=1]"); + m_cmd_binder.set_handler("stop_mining", boost::bind(&daemon_cmmands_handler::stop_mining, this, _1), "Stop mining"); + m_cmd_binder.set_handler("print_pool", boost::bind(&daemon_cmmands_handler::print_pool, this, _1), "Print transaction pool (long format)"); + m_cmd_binder.set_handler("print_pool_sh", boost::bind(&daemon_cmmands_handler::print_pool_sh, this, _1), "Print transaction pool (short format)"); + m_cmd_binder.set_handler("show_hr", boost::bind(&daemon_cmmands_handler::show_hr, this, _1), "Start showing hash rate"); + m_cmd_binder.set_handler("hide_hr", boost::bind(&daemon_cmmands_handler::hide_hr, this, _1), "Stop showing hash rate"); + m_cmd_binder.set_handler("save", boost::bind(&daemon_cmmands_handler::save, this, _1), "Save blockchain"); + m_cmd_binder.set_handler("print_daemon_stat", boost::bind(&daemon_cmmands_handler::print_daemon_stat, this, _1), "Print daemon stat"); + m_cmd_binder.set_handler("print_debug_stat", boost::bind(&daemon_cmmands_handler::print_debug_stat, this, _1), "Print debug stat info"); + m_cmd_binder.set_handler("get_transactions_statics", boost::bind(&daemon_cmmands_handler::get_transactions_statistics, this, _1), "Calculates transactions statistics"); + m_cmd_binder.set_handler("force_relay_tx_pool", boost::bind(&daemon_cmmands_handler::force_relay_tx_pool, this, _1), "re-relay all transactions from pool"); + m_cmd_binder.set_handler("enable_channel", boost::bind(&daemon_cmmands_handler::enable_channel, this, _1), "Enable specified log channel"); + m_cmd_binder.set_handler("disable_channel", boost::bind(&daemon_cmmands_handler::disable_channel, this, _1), "Enable specified log channel"); + m_cmd_binder.set_handler("clear_cache", boost::bind(&daemon_cmmands_handler::clear_cache, this, _1), "Clear blockchain storage cache"); + m_cmd_binder.set_handler("clear_altblocks", boost::bind(&daemon_cmmands_handler::clear_altblocks, this, _1), "Clear blockchain storage cache"); + m_cmd_binder.set_handler("truncate_bc", boost::bind(&daemon_cmmands_handler::truncate_bc, this, _1), "Truncate blockchain to specified height"); + m_cmd_binder.set_handler("inspect_block_index", boost::bind(&daemon_cmmands_handler::inspect_block_index, this, _1), "Inspects block index for internal errors"); + m_cmd_binder.set_handler("print_db_performance_data", boost::bind(&daemon_cmmands_handler::print_db_performance_data, this, _1), "Dumps all db containers performance counters"); + m_cmd_binder.set_handler("search_by_id", boost::bind(&daemon_cmmands_handler::search_by_id, this, _1), "Search all possible elemets by given id"); + m_cmd_binder.set_handler("find_key_image", boost::bind(&daemon_cmmands_handler::find_key_image, this, _1), "Try to find tx related to key_image"); + m_cmd_binder.set_handler("rescan_aliases", boost::bind(&daemon_cmmands_handler::rescan_aliases, this, _1), "Debug function"); + m_cmd_binder.set_handler("forecast_difficulty", boost::bind(&daemon_cmmands_handler::forecast_difficulty, this, _1), "Prints PoW and PoS difficulties for as many future blocks as possible based on current conditions"); + m_cmd_binder.set_handler("print_deadlock_guard", boost::bind(&daemon_cmmands_handler::print_deadlock_guard, this, _1), "Print all threads which is blocked or involved in mutex ownership"); + } + + bool start_handling() + { + m_cmd_binder.start_handling(&m_srv, "", ""); + return true; + } + + void stop_handling() + { + m_cmd_binder.stop_handling(); + } + +private: + + +// //-------------------------------------------------------------------------------- +// std::string get_commands_str() +// { +// return m_cmd_binder.get_usage(); +// } +// //-------------------------------------------------------------------------------- +// bool help(const std::vector& /*args*/) +// { +// std::cout << get_commands_str() << ENDL; +// return true; +// } + //-------------------------------------------------------------------------------- + bool print_pl(const std::vector& args) + { + m_srv.log_peerlist(); + return true; + } + //-------------------------------------------------------------------------------- + bool save(const std::vector& args) + { + return true; + } + //-------------------------------------------------------------------------------- + bool print_daemon_stat(const std::vector& args) + { + currency::COMMAND_RPC_GET_INFO::request req = AUTO_VAL_INIT(req); + req.flags = COMMAND_RPC_GET_INFO_FLAG_ALL_FLAGS; + currency::COMMAND_RPC_GET_INFO::response resp = AUTO_VAL_INIT(resp); + currency::core_rpc_server::connection_context cc = AUTO_VAL_INIT(cc); + m_rpc.on_get_info(req, resp, cc); + LOG_PRINT_L0("STAT INFO:" << ENDL << epee::serialization::store_t_to_json(resp).c_str()); + return true; + } + //-------------------------------------------------------------------------------- + bool print_debug_stat(const std::vector& args) + { + currency::core_stat_info si = AUTO_VAL_INIT(si); + currency::core_stat_info::params pr = AUTO_VAL_INIT(pr); + pr.chain_len = 10; + m_srv.get_payload_object().get_core().get_stat_info(pr, si); + LOG_PRINT_GREEN("CORE_STAT_INFO: " << epee::serialization::store_t_to_json(si), LOG_LEVEL_0); + + return true; + } + //-------------------------------------------------------------------------------- + bool get_transactions_statistics(const std::vector& args) + { + m_srv.get_payload_object().get_core().get_blockchain_storage().print_transactions_statistics(); + return true; + } + //-------------------------------------------------------------------------------- + bool force_relay_tx_pool(const std::vector& args) + { + m_srv.get_payload_object().get_core().get_tx_pool().force_relay_pool(); + return true; + } + bool enable_channel(const std::vector& args) + { + if (args.size() != 1) + { + std::cout << "Missing channel name to enable." << ENDL; + return true; + } + epee::log_space::log_singletone::enable_channel(args[0]); + return true; + } + bool disable_channel(const std::vector& args) + { + if (args.size() != 1) + { + std::cout << "Missing channel name to disable." << ENDL; + return true; + } + epee::log_space::log_singletone::disable_channel(args[0]); + return true; + } + + bool clear_cache(const std::vector& args) + { + m_srv.get_payload_object().get_core().get_blockchain_storage().reset_db_cache(); + return true; + } + bool clear_altblocks(const std::vector& args) + { + m_srv.get_payload_object().get_core().get_blockchain_storage().clear_altblocks(); + return true; + } + + //-------------------------------------------------------------------------------- + bool show_hr(const std::vector& args) + { + if(!m_srv.get_payload_object().get_core().get_miner().is_mining()) + { + std::cout << "Mining is not started. You need start mining before you can see hash rate." << ENDL; + } else + { + m_srv.get_payload_object().get_core().get_miner().do_print_hashrate(true); + } + return true; + } + //-------------------------------------------------------------------------------- + bool hide_hr(const std::vector& args) + { + m_srv.get_payload_object().get_core().get_miner().do_print_hashrate(false); + return true; + } + //-------------------------------------------------------------------------------- + bool print_bc_outs(const std::vector& args) + { + if(args.size() != 1) + { + std::cout << "need file path as parameter" << ENDL; + return true; + } + m_srv.get_payload_object().get_core().print_blockchain_outs(args[0]); + return true; + } + //-------------------------------------------------------------------------------- + bool print_market(const std::vector& args) + { + bc_services::bc_offers_service* offers_service = dynamic_cast(m_srv.get_payload_object().get_core().get_blockchain_storage().get_attachment_services_manager().get_service_by_id(BC_OFFERS_SERVICE_ID)); + CHECK_AND_ASSERT_MES(offers_service != nullptr, false, "Offers service was not registered in attachment service manager!"); + + offers_service->print_market(log_space::log_singletone::get_default_log_folder() + "/market.txt"); + return true; + } + //-------------------------------------------------------------------------------- + bool print_bc_outs_stat(const std::vector& args) + { + m_srv.get_payload_object().get_core().get_blockchain_storage().print_blockchain_outs_stat(); + return true; + } + //-------------------------------------------------------------------------------- + bool print_cn(const std::vector& args) + { + m_srv.get_payload_object().log_connections(); + return true; + } + //-------------------------------------------------------------------------------- + bool print_bc(const std::vector& args) + { + if(!args.size()) + { + std::cout << "need block index parameter" << ENDL; + return false; + } + uint64_t start_index = 0; + uint64_t end_block_parametr = m_srv.get_payload_object().get_core().get_current_blockchain_size(); + if(!string_tools::get_xtype_from_string(start_index, args[0])) + { + std::cout << "wrong starter block index parameter" << ENDL; + return false; + } + if(args.size() >1 && !string_tools::get_xtype_from_string(end_block_parametr, args[1])) + { + std::cout << "wrong end block index parameter" << ENDL; + return false; + } + + m_srv.get_payload_object().get_core().print_blockchain(start_index, end_block_parametr); + return true; + } + //-------------------------------------------------------------------------------- + bool truncate_bc(const std::vector& args) + { + if (!args.size()) + { + std::cout << "truncate height needed" << ENDL; + return false; + } + uint64_t tr_h = 0; + if (!string_tools::get_xtype_from_string(tr_h, args[0])) + { + std::cout << "wrong truncate index" << ENDL; + return false; + } + + m_srv.get_payload_object().get_core().get_blockchain_storage().truncate_blockchain(tr_h); + return true; + } + bool inspect_block_index(const std::vector& args) + { + m_srv.get_payload_object().get_core().get_blockchain_storage().inspect_blocks_index(); + return true; + } + bool print_db_performance_data(const std::vector& args) + { + m_srv.get_payload_object().get_core().get_blockchain_storage().print_db_cache_perfeormance_data(); + return true; + } + //-------------------------------------------------------------------------------- + bool search_by_id(const std::vector& args) + { + + if (!args.size()) + { + std::cout << "need ID parameter" << ENDL; + return false; + } + crypto::hash id = currency::null_hash; + if (!parse_hash256(args[0], id)) + { + std::cout << "specified ID parameter '"<< args[0] << "' is wrong" << ENDL; + return false; + } + std::list res_list; + m_srv.get_payload_object().get_core().get_blockchain_storage().search_by_id(id, res_list); + std::string joined = boost::algorithm::join(res_list, "|"); + LOG_PRINT_L0("Result of search: " << joined); + return true; + } + //-------------------------------------------------------------------------------- + bool find_key_image(const std::vector& args) + { + + if (!args.size()) + { + std::cout << "need key_image parameter" << ENDL; + return false; + } + crypto::key_image ki = currency::null_ki; + if (!epee::string_tools::parse_tpod_from_hex_string(args[0], ki)) + { + std::cout << "specified key_image parameter '" << args[0] << "' is wrong" << ENDL; + return false; + } + std::list res_list; + crypto::hash tx_id = currency::null_hash; + auto tx_chain_entry = m_srv.get_payload_object().get_core().get_blockchain_storage().find_key_image_and_related_tx(ki, tx_id); + + if (tx_chain_entry) + { + LOG_PRINT_L0("Found tx: " << ENDL << obj_to_json_str(tx_chain_entry->tx) << ENDL << "height: " << tx_chain_entry->m_keeper_block_height); + } + if (tx_id == currency::null_hash) + { + LOG_PRINT_L0("Not found any related tx."); + } + else + { + LOG_PRINT_L0("TxID: " << tx_id); + } + return true; + } + //-------------------------------------------------------------------------------- + bool rescan_aliases(const std::vector& args) + { + m_srv.get_payload_object().get_core().get_blockchain_storage().validate_all_aliases_for_new_median_mode(); + return true; + } + //-------------------------------------------------------------------------------- + bool print_bc_tx(const std::vector& args) + { + if (!args.size()) + { + std::cout << "need block index parameter" << ENDL; + return false; + } + uint64_t start_index = 0; + uint64_t end_block_parametr = m_srv.get_payload_object().get_core().get_current_blockchain_size(); + if (!string_tools::get_xtype_from_string(start_index, args[0])) + { + std::cout << "wrong starter block index parameter" << ENDL; + return false; + } + if (args.size() > 1 && !string_tools::get_xtype_from_string(end_block_parametr, args[1])) + { + std::cout << "wrong end block index parameter" << ENDL; + return false; + } + LOG_PRINT_GREEN("Storing text to blockchain_with_tx.txt....", LOG_LEVEL_0); + m_srv.get_payload_object().get_core().get_blockchain_storage().print_blockchain_with_tx(start_index, end_block_parametr); + LOG_PRINT_GREEN("Done", LOG_LEVEL_0); + return true; + } + //-------------------------------------------------------------------------------- + bool print_bci(const std::vector& args) + { + m_srv.get_payload_object().get_core().print_blockchain_index(); + return true; + } + //-------------------------------------------------------------------------------- + template + static bool print_as_json(T& obj) + { + std::cout << obj_to_json_str(obj) << ENDL; + return true; + } + //-------------------------------------------------------------------------------- + bool print_block_by_height(uint64_t height) + { + std::list blocks; + m_srv.get_payload_object().get_core().get_blocks(height, 1, blocks); + + if (1 == blocks.size()) + { + currency::block& block = blocks.front(); + LOG_PRINT_GREEN("------------------ block_id: " << get_block_hash(block) << " ------------------" << ENDL << currency::obj_to_json_str(block), LOG_LEVEL_0); + } + else + { + uint64_t current_height; + crypto::hash top_id; + m_srv.get_payload_object().get_core().get_blockchain_top(current_height, top_id); + LOG_PRINT_GREEN("block wasn't found. Current block chain height: " << current_height << ", requested: " << height, LOG_LEVEL_0); + return false; + } + + return true; + } + //-------------------------------------------------------------------------------- + bool print_block_by_hash(const std::string& arg) + { + crypto::hash block_hash; + if (!parse_hash256(arg, block_hash)) + { + return false; + } + + //std::list block_ids; + //block_ids.push_back(block_hash); + //std::list blocks; + //std::list missed_ids; + currency::block_extended_info bei = AUTO_VAL_INIT(bei); + bool r = m_srv.get_payload_object().get_core().get_blockchain_storage().get_block_extended_info_by_hash(block_hash, bei); + //m_srv.get_payload_object().get_core().get_blocks(block_ids, blocks, missed_ids); + + if (r) + { +// currency::block& block = bei.bl; + LOG_PRINT_GREEN("------------------ block_id: " << get_block_hash(bei.bl) << " ------------------" << ENDL << currency::obj_to_json_str(bei), LOG_LEVEL_0); + m_srv.get_payload_object().get_core().get_blockchain_storage().calc_tx_cummulative_blob(bei.bl); + } + else + { + LOG_PRINT_GREEN("block wasn't found: " << arg, LOG_LEVEL_0); + return false; + } + + return true; + } + //-------------------------------------------------------------------------------- + bool print_block(const std::vector& args) + { + if (args.empty()) + { + std::cout << "expected: print_block ( | )" << std::endl; + return true; + } + + const std::string& arg = args.front(); + try + { + uint64_t height = boost::lexical_cast(arg); + print_block_by_height(height); + } + catch (boost::bad_lexical_cast&) + { + print_block_by_hash(arg); + } + + return true; + } + //-------------------------------------------------------------------------------- + bool print_tx(const std::vector& args) + { + if (args.empty()) + { + std::cout << "expected: print_tx " << std::endl; + return true; + } + + const std::string& str_hash = args.front(); + crypto::hash tx_hash; + if (!parse_hash256(str_hash, tx_hash)) + { + return true; + } + +// std::vector tx_ids; +// tx_ids.push_back(tx_hash); +// std::list txs; +// std::list missed_ids; +// m_srv.get_payload_object().get_core().get_transactions(tx_ids, txs, missed_ids); + + currency::transaction_chain_entry tx_entry = AUTO_VAL_INIT(tx_entry); + + if (!m_srv.get_payload_object().get_core().get_blockchain_storage().get_tx_chain_entry(tx_hash, tx_entry)) + { + LOG_PRINT_RED("transaction wasn't found: " << tx_hash, LOG_LEVEL_0); + } + currency::block_extended_info bei = AUTO_VAL_INIT(bei); + m_srv.get_payload_object().get_core().get_blockchain_storage().get_block_extended_info_by_height(tx_entry.m_keeper_block_height, bei); + uint64_t timestamp = bei.bl.timestamp; + + const currency::transaction& tx = tx_entry.tx; + std::stringstream ss; + + ss << "------------------------------------------------------" + << ENDL << "tx_id: " << tx_hash + << ENDL << "keeper_block: " << tx_entry.m_keeper_block_height << ", timestamp (" << timestamp << ") " << epee::misc_utils::get_internet_time_str(timestamp) + << ENDL << currency::obj_to_json_str(tx) + << ENDL << "------------------------------------------------------" + << ENDL << epee::string_tools::buff_to_hex_nodelimer(t_serializable_object_to_blob(tx)) + << ENDL << "------------------------------------------------------"; + + + ss << "ATTACHMENTS: " << ENDL; + for (auto at : tx.attachment) + { + if (at.type() == typeid(currency::tx_service_attachment)) + { + const currency::tx_service_attachment& sa = boost::get(at); + ss << "++++++++++++++++++++++++++++++++ " << ENDL; + ss << "[SERVICE_ATTACHMENT]: ID = \'" << sa.service_id << "\', INSTRUCTION: \'" << sa.instruction << "\'" << ENDL; + + if (!(sa.flags&TX_SERVICE_ATTACHMENT_ENCRYPT_BODY)) + { + std::string body = sa.body; + if (sa.flags&TX_SERVICE_ATTACHMENT_DEFLATE_BODY) + { + bool r = epee::zlib_helper::unpack(sa.body, body); + CHECK_AND_ASSERT_MES(r, false, "Failed to unpack"); + } + ss << "BODY: " << body << ENDL; + } + } + } + + LOG_PRINT_GREEN(ss.str(), LOG_LEVEL_0); + return true; + } + //-------------------------------------------------------------------------------- + bool print_pool(const std::vector& args) + { + LOG_PRINT_L0("Pool state: " << ENDL << m_srv.get_payload_object().get_core().print_pool(false)); + return true; + } + //-------------------------------------------------------------------------------- + bool print_pool_sh(const std::vector& args) + { + LOG_PRINT_L0("Pool state: " << ENDL << m_srv.get_payload_object().get_core().print_pool(true)); + return true; + } //-------------------------------------------------------------------------------- + bool start_mining(const std::vector& args) + { + if(!args.size()) + { + std::cout << "Please, specify wallet address to mine for: start_mining [threads=1]" << std::endl; + return true; + } + + currency::account_public_address adr; + if(!currency::get_account_address_from_str(adr, args.front())) + { + std::cout << "target account address has wrong format" << std::endl; + return true; + } + size_t threads_count = 1; + if(args.size() > 1) + { + bool ok = string_tools::get_xtype_from_string(threads_count, args[1]); + threads_count = (ok && 0 < threads_count) ? threads_count : 1; + } + + m_srv.get_payload_object().get_core().get_miner().start(adr, threads_count); + return true; + } + //-------------------------------------------------------------------------------- + bool stop_mining(const std::vector& args) + { + m_srv.get_payload_object().get_core().get_miner().stop(); + return true; + } + //-------------------------------------------------------------------------------- + bool forecast_difficulty(const std::vector& args) + { + if (args.size() > 0) + { + LOG_ERROR("command requires no agruments"); + return false; + } + + std::vector> pow_diffs, pos_diffs; + + bool r = false; + r = m_srv.get_payload_object().get_core().get_blockchain_storage().forecast_difficulty(pow_diffs, false); + CHECK_AND_ASSERT_MES(r, false, "forecast_difficulty failed"); + + r = m_srv.get_payload_object().get_core().get_blockchain_storage().forecast_difficulty(pos_diffs, true); + CHECK_AND_ASSERT_MES(r, false, "forecast_difficulty failed"); + + CHECK_AND_ASSERT_MES(pow_diffs.size() == pow_diffs.size(), false, "mismatch in sizes: " << pow_diffs.size() << ", " << pow_diffs.size()); + + std::stringstream ss; + ss << " The next " << pow_diffs.size() - 1 << " PoW and PoS blocks will have the following difficulties:" << ENDL; + ss << " # aprox. PoW height PoW difficulty aprox. PoS height PoS difficulty" << ENDL; + for (size_t i = 0; i < pow_diffs.size(); ++i) + { + ss << std::right << std::setw(2) << i; + ss << " " << std::setw(6) << std::left << pow_diffs[i].first; + if (i == 0) + ss << " (last block) "; + else + ss << " "; + ss << std::setw(10) << std::left << pow_diffs[i].second; + + ss << " "; + ss << std::setw(6) << std::left << pos_diffs[i].first; + if (i == 0) + ss << " (last block) "; + else + ss << " "; + ss << pos_diffs[i].second; + ss << ENDL; + } + + LOG_PRINT_L0(ENDL << ss.str()); + return true; + } + //-------------------------------------------------------------------------------- + bool print_deadlock_guard(const std::vector& args) + { + LOG_PRINT_L0(ENDL << epee::deadlock_guard_singleton::get_dlg_state()); + return true; + } + + + + +}; +POP_WARNINGS diff --git a/src/gui/qt-daemon/.gitignore b/src/gui/qt-daemon/.gitignore new file mode 100644 index 00000000..8b95cebe --- /dev/null +++ b/src/gui/qt-daemon/.gitignore @@ -0,0 +1 @@ +*.user \ No newline at end of file diff --git a/src/gui/qt-daemon/Info.plist.in b/src/gui/qt-daemon/Info.plist.in new file mode 100644 index 00000000..24200075 --- /dev/null +++ b/src/gui/qt-daemon/Info.plist.in @@ -0,0 +1,56 @@ + + + + + LSEnvironment + + QTWEBENGINE_REMOTE_DEBUGGING + 11113 + + BuildMachineOSBuild + 14E46 + CFBundleDevelopmentRegion + English + CFBundleExecutable + Zano + CFBundleIconFile + app.icns + CFBundleInfoDictionaryVersion + 6.0 + CFBundleLongVersionString + + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleVersion + + CFBundleIdentifier + Zano + CSResourcesFileMapped + + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 6E35b + DTPlatformVersion + GM + DTSDKBuild + 14D125 + DTSDKName + macosx10.10 + DTXcode + 0640 + DTXcodeBuild + 6E35b + LSRequiresCarbon + + NSHumanReadableCopyright + + + NSHighResolutionCapable + True + + + + diff --git a/src/gui/qt-daemon/app.icns b/src/gui/qt-daemon/app.icns new file mode 100644 index 00000000..881e134c Binary files /dev/null and b/src/gui/qt-daemon/app.icns differ diff --git a/src/gui/qt-daemon/app.ico b/src/gui/qt-daemon/app.ico new file mode 100644 index 00000000..5d170210 Binary files /dev/null and b/src/gui/qt-daemon/app.ico differ diff --git a/src/gui/qt-daemon/app.qrc b/src/gui/qt-daemon/app.qrc new file mode 100644 index 00000000..b828a450 --- /dev/null +++ b/src/gui/qt-daemon/app.qrc @@ -0,0 +1,5 @@ + + + app.ico + + \ No newline at end of file diff --git a/src/gui/qt-daemon/app.rc b/src/gui/qt-daemon/app.rc new file mode 100644 index 00000000..05c8afbc --- /dev/null +++ b/src/gui/qt-daemon/app.rc @@ -0,0 +1,2 @@ + +IDI_ICON1 ICON DISCARDABLE "app.ico" \ No newline at end of file diff --git a/src/gui/qt-daemon/application/core_fast_rpc_proxy.h b/src/gui/qt-daemon/application/core_fast_rpc_proxy.h new file mode 100644 index 00000000..39f371e1 --- /dev/null +++ b/src/gui/qt-daemon/application/core_fast_rpc_proxy.h @@ -0,0 +1,146 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#pragma once +#include "rpc/core_rpc_server.h" +#include "wallet/core_rpc_proxy.h" +#include "currency_core/alias_helper.h" +namespace tools +{ + class core_fast_rpc_proxy: public i_core_proxy + { + public: + core_fast_rpc_proxy(currency::core_rpc_server& rpc_srv) :m_rpc(rpc_srv) + {} + //------------------------------------------------------------------------------------------------------------------------------ + virtual bool set_connection_addr(const std::string& url) override + { + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool call_COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES(const currency::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, currency::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res) override + { + return m_rpc.on_get_indexes(req, res, m_cntxt_stub); + } + //------------------------------------------------------------------------------------------------------------------------------ + bool call_COMMAND_RPC_GET_BLOCKS_FAST(const currency::COMMAND_RPC_GET_BLOCKS_FAST::request& req, currency::COMMAND_RPC_GET_BLOCKS_FAST::response& res) override + { + return m_rpc.on_get_blocks(req, res, m_cntxt_stub); + } + bool call_COMMAND_RPC_GET_BLOCKS_DIRECT(const currency::COMMAND_RPC_GET_BLOCKS_DIRECT::request& rqt, currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response& rsp) override + { + return m_rpc.on_get_blocks_direct(rqt, rsp, m_cntxt_stub); + } + //------------------------------------------------------------------------------------------------------------------------------ + bool call_COMMAND_RPC_GET_INFO(const currency::COMMAND_RPC_GET_INFO::request& req, currency::COMMAND_RPC_GET_INFO::response& res) override + { + return m_rpc.on_get_info(req, res, m_cntxt_stub); + } + //------------------------------------------------------------------------------------------------------------------------------ + bool call_COMMAND_RPC_GET_TX_POOL(const currency::COMMAND_RPC_GET_TX_POOL::request& req, currency::COMMAND_RPC_GET_TX_POOL::response& res) override + { + return m_rpc.on_get_tx_pool(req, res, m_cntxt_stub); + } + //------------------------------------------------------------------------------------------------------------------------------ + bool call_COMMAND_RPC_GET_ALIASES_BY_ADDRESS(const currency::COMMAND_RPC_GET_ALIASES_BY_ADDRESS::request& req, currency::COMMAND_RPC_GET_ALIASES_BY_ADDRESS::response& res) override + { + return m_rpc.on_alias_by_address(req, res, m_err_stub, m_cntxt_stub); + } + //------------------------------------------------------------------------------------------------------------------------------ + bool call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res) override + { + return m_rpc.on_get_random_outs(req, res, m_cntxt_stub); + } + //------------------------------------------------------------------------------------------------------------------------------ + bool call_COMMAND_RPC_SEND_RAW_TX(const currency::COMMAND_RPC_SEND_RAW_TX::request& req, currency::COMMAND_RPC_SEND_RAW_TX::response& res) override + { + return m_rpc.on_send_raw_tx(req, res, m_cntxt_stub); + } + bool call_COMMAND_RPC_FORCE_RELAY_RAW_TXS(const currency::COMMAND_RPC_FORCE_RELAY_RAW_TXS::request& req, currency::COMMAND_RPC_FORCE_RELAY_RAW_TXS::response& res ) override + { + return m_rpc.on_force_relaey_raw_txs(req, res, m_cntxt_stub); + } + //------------------------------------------------------------------------------------------------------------------------------ + virtual bool check_connection() override + { + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool call_COMMAND_RPC_GET_ALL_ALIASES(currency::COMMAND_RPC_GET_ALL_ALIASES::response& res) override + { + currency::COMMAND_RPC_GET_ALL_ALIASES::request req = AUTO_VAL_INIT(req); + return m_rpc.on_get_all_aliases(req, res, m_err_stub, m_cntxt_stub); + } + //------------------------------------------------------------------------------------------------------------------------------ + bool call_COMMAND_RPC_GET_ALIAS_DETAILS(const currency::COMMAND_RPC_GET_ALIAS_DETAILS::request& req, currency::COMMAND_RPC_GET_ALIAS_DETAILS::response& res) override + { + return m_rpc.on_get_alias_details(req, res, m_err_stub, m_cntxt_stub); + } + //------------------------------------------------------------------------------------------------------------------------------ + bool call_COMMAND_RPC_GET_ALIAS_REWARD(const currency::COMMAND_RPC_GET_ALIAS_REWARD::request& req, currency::COMMAND_RPC_GET_ALIAS_REWARD::response& res) override + { + return m_rpc.on_get_alias_reward(req, res, m_err_stub, m_cntxt_stub); + } + //------------------------------------------------------------------------------------------------------------------------------ + bool call_COMMAND_RPC_GET_TRANSACTIONS(const currency::COMMAND_RPC_GET_TRANSACTIONS::request& req, currency::COMMAND_RPC_GET_TRANSACTIONS::response& rsp) override + { + return m_rpc.on_get_transactions(req, rsp, m_cntxt_stub); + } + //------------------------------------------------------------------------------------------------------------------------------ + bool call_COMMAND_RPC_COMMAND_RPC_CHECK_KEYIMAGES(const currency::COMMAND_RPC_CHECK_KEYIMAGES::request& req, currency::COMMAND_RPC_CHECK_KEYIMAGES::response& rsp) override + { + return m_rpc.on_check_keyimages(req, rsp, m_cntxt_stub); + } + //------------------------------------------------------------------------------------------------------------------------------ + bool call_COMMAND_RPC_SCAN_POS(const currency::COMMAND_RPC_SCAN_POS::request& req, currency::COMMAND_RPC_SCAN_POS::response& rsp) override + { + return m_rpc.on_scan_pos(req, rsp, m_cntxt_stub); + } + //------------------------------------------------------------------------------------------------------------------------------ + bool call_COMMAND_RPC_GETBLOCKTEMPLATE(const currency::COMMAND_RPC_GETBLOCKTEMPLATE::request& req, currency::COMMAND_RPC_GETBLOCKTEMPLATE::response& rsp) override + { + return m_rpc.on_getblocktemplate(req, rsp, m_err_stub, m_cntxt_stub); + } + //------------------------------------------------------------------------------------------------------------------------------ + bool call_COMMAND_RPC_SUBMITBLOCK(const currency::COMMAND_RPC_SUBMITBLOCK::request& req, currency::COMMAND_RPC_SUBMITBLOCK::response& rsp) override + { + return m_rpc.on_submitblock(req, rsp, m_err_stub, m_cntxt_stub); + } + //------------------------------------------------------------------------------------------------------------------------------ + bool call_COMMAND_RPC_GET_POS_MINING_DETAILS(const currency::COMMAND_RPC_GET_POS_MINING_DETAILS::request& req, currency::COMMAND_RPC_GET_POS_MINING_DETAILS::response& rsp) override + { + return m_rpc.on_get_pos_mining_details(req, rsp, m_cntxt_stub); + } + //------------------------------------------------------------------------------------------------------------------------------ + bool call_COMMAND_RPC_GET_BLOCKS_DETAILS(const currency::COMMAND_RPC_GET_BLOCKS_DETAILS::request& req, currency::COMMAND_RPC_GET_BLOCKS_DETAILS::response& res) override + { + return m_rpc.on_rpc_get_blocks_details(req, res, m_cntxt_stub); + } + //------------------------------------------------------------------------------------------------------------------------------ + bool call_COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN(const currency::COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN::request& req, currency::COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN::response& res) override + { + return m_rpc.on_get_current_core_tx_expiration_median(req, res, m_cntxt_stub); + } + //------------------------------------------------------------------------------------------------------------------------------ + bool call_COMMAND_RPC_GET_POOL_INFO(const currency::COMMAND_RPC_GET_POOL_INFO::request& req, currency::COMMAND_RPC_GET_POOL_INFO::response& res) + { + return m_rpc.on_get_pool_info(req, res, m_cntxt_stub); + } + //------------------------------------------------------------------------------------------------------------------------------ + virtual bool get_transfer_address(const std::string& adr_str, currency::account_public_address& addr, std::string& payment_id) override + { + return tools::get_transfer_address(adr_str, addr, payment_id, this); + } + + private: + currency::core_rpc_server& m_rpc; + currency::core_rpc_server::connection_context m_cntxt_stub; + epee::json_rpc::error m_err_stub; + }; + +} + + + diff --git a/src/gui/qt-daemon/application/daemon_backend.cpp b/src/gui/qt-daemon/application/daemon_backend.cpp new file mode 100644 index 00000000..b5ae3a4b --- /dev/null +++ b/src/gui/qt-daemon/application/daemon_backend.cpp @@ -0,0 +1,1604 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "daemon_backend.h" +#include "currency_core/alias_helper.h" +#include "core_fast_rpc_proxy.h" +#include "string_coding.h" +#include "currency_core/core_tools.h" +//#include + +#define GET_WALLET_OPT_BY_ID(wallet_id, name) \ + CRITICAL_REGION_LOCAL(m_wallets_lock); \ + auto it = m_wallets.find(wallet_id); \ +if (it == m_wallets.end()) \ + return API_RETURN_CODE_WALLET_WRONG_ID; \ + auto& name = it->second; + +#define GET_WALLET_BY_ID(wallet_id, name) \ +CRITICAL_REGION_LOCAL(m_wallets_lock); \ +auto it = m_wallets.find(wallet_id); \ +if (it == m_wallets.end()) \ + return API_RETURN_CODE_WALLET_WRONG_ID; \ +auto& name = it->second.w; + + + +daemon_backend::daemon_backend():m_pview(&m_view_stub), + m_stop_singal_sent(false), + m_ccore(&m_cprotocol), + m_cprotocol(m_ccore, &m_p2psrv), + m_p2psrv(m_cprotocol), + m_rpc_server(m_ccore, m_p2psrv, m_offers_service), + m_rpc_proxy(new tools::core_fast_rpc_proxy(m_rpc_server)), + m_last_daemon_height(0), + m_last_daemon_is_disconnected(false), + m_wallet_id_counter(0), + m_offers_service(nullptr), + m_ui_opt(AUTO_VAL_INIT(m_ui_opt)), + m_remote_node_mode(false), + m_is_pos_allowed(false) +{ + m_ccore.get_blockchain_storage().get_attachment_services_manager().add_service(&m_offers_service); +} + +const command_line::arg_descriptor arg_alloc_win_console = {"alloc-win-console", "Allocates debug console with GUI", false}; +const command_line::arg_descriptor arg_html_folder = {"html-path", "Manually set GUI html folder path", "", true}; +const command_line::arg_descriptor arg_xcode_stub = {"-NSDocumentRevisionsDebugMode", "Substitute for xcode bug", "", true}; +const command_line::arg_descriptor arg_enable_gui_debug_mode = { "gui-debug-mode", "Enable debug options in GUI", false, true }; +const command_line::arg_descriptor arg_qt_remote_debugging_port = { "remote-debugging-port", "Specify port for Qt remote debugging", 30333, true }; +const command_line::arg_descriptor arg_remote_node = { "remote-node", "Switch GUI to work with remote node instead of local daemon", "", true }; + +void wallet_lock_time_watching_policy::watch_lock_time(uint64_t lock_time) +{ + if (lock_time > 500) + { + LOG_PRINT_RED_L0("[wallet_lock_time_watching_policy::watch_lock_time] LOCK_TIME: " << lock_time); + } +} + +daemon_backend::~daemon_backend() +{ + stop(); +} + +bool daemon_backend::init(int argc, char* argv[], view::i_view* pview_handler) +{ + m_stop_singal_sent = false; + if (pview_handler) + m_pview = pview_handler; + + view::daemon_status_info dsi = AUTO_VAL_INIT(dsi); + dsi.pos_difficulty = dsi.pow_difficulty = "---"; + pview_handler->update_daemon_status(dsi); + + log_space::get_set_log_detalisation_level(true, LOG_LEVEL_0); + log_space::get_set_need_thread_id(true, true); + log_space::log_singletone::enable_channels("core,currency_protocol,tx_pool,p2p,wallet"); + + tools::signal_handler::install_fatal([](int sig_number, void* address) { + LOG_ERROR("\n\nFATAL ERROR\nsig: " << sig_number << ", address: " << address); + std::fflush(nullptr); // all open output streams are flushed + }); + + + //#if !defined(NDEBUG) + // log_space::log_singletone::add_logger(LOGGER_DEBUGGER, nullptr, nullptr); + //#endif + LOG_PRINT_L0("Initing..."); + + TRY_ENTRY(); + po::options_description desc_cmd_only("Command line options"); + po::options_description desc_cmd_sett("Command line options and settings options"); + + command_line::add_arg(desc_cmd_only, command_line::arg_help); + command_line::add_arg(desc_cmd_only, command_line::arg_version); + command_line::add_arg(desc_cmd_only, command_line::arg_os_version); + // tools::get_default_data_dir() can't be called during static initialization + command_line::add_arg(desc_cmd_only, command_line::arg_data_dir, tools::get_default_data_dir()); + command_line::add_arg(desc_cmd_only, command_line::arg_config_file); + + command_line::add_arg(desc_cmd_sett, command_line::arg_log_dir); + command_line::add_arg(desc_cmd_sett, command_line::arg_log_level); + command_line::add_arg(desc_cmd_sett, command_line::arg_console); + command_line::add_arg(desc_cmd_sett, command_line::arg_show_details); + command_line::add_arg(desc_cmd_sett, arg_alloc_win_console); + command_line::add_arg(desc_cmd_sett, arg_html_folder); + command_line::add_arg(desc_cmd_sett, arg_xcode_stub); + command_line::add_arg(desc_cmd_sett, arg_enable_gui_debug_mode); + command_line::add_arg(desc_cmd_sett, arg_qt_remote_debugging_port); + command_line::add_arg(desc_cmd_sett, arg_remote_node); + + + + + + currency::core::init_options(desc_cmd_sett); + currency::core_rpc_server::init_options(desc_cmd_sett); + nodetool::node_server >::init_options(desc_cmd_sett); + currency::miner::init_options(desc_cmd_sett); + bc_services::bc_offers_service::init_options(desc_cmd_sett); + + po::options_description desc_options("Allowed options"); + desc_options.add(desc_cmd_only).add(desc_cmd_sett); + + + + bool coomand_line_parsed = command_line::handle_error_helper(desc_options, [&]() + { + po::store(po::parse_command_line(argc, argv, desc_options), m_vm); + + if (command_line::get_arg(m_vm, command_line::arg_help)) + { + std::cout << CURRENCY_NAME << " v" << PROJECT_VERSION_LONG << ENDL << ENDL; + std::cout << desc_options << std::endl; + return false; + } + + m_data_dir = command_line::get_arg(m_vm, command_line::arg_data_dir); + std::string config = command_line::get_arg(m_vm, command_line::arg_config_file); + + boost::filesystem::path data_dir_path(m_data_dir); + boost::filesystem::path config_path(config); + if (!config_path.has_parent_path()) + { + config_path = data_dir_path / config_path; + } + + boost::system::error_code ec; + if (boost::filesystem::exists(config_path, ec)) + { + po::store(po::parse_config_file(config_path.string().c_str(), desc_cmd_sett), m_vm); + } + po::notify(m_vm); + + return true; + }); + + //set up logging options + if (command_line::has_arg(m_vm, arg_alloc_win_console)) + { + log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL); + } + if (command_line::has_arg(m_vm, command_line::arg_log_level)) + { + log_space::log_singletone::get_set_log_detalisation_level(true, command_line::get_arg(m_vm, command_line::arg_log_level)); + } + if (command_line::has_arg(m_vm, arg_enable_gui_debug_mode)) + { + m_ui_opt.use_debug_mode = true; + } + + //set up logging options + std::string log_dir; + std::string log_file_name = log_space::log_singletone::get_default_log_file(); + //check if there was specific option + if (command_line::has_arg(m_vm, command_line::arg_log_dir)) + { + log_dir = command_line::get_arg(m_vm, command_line::arg_log_dir); + } + else + { + log_dir = command_line::get_arg(m_vm, command_line::arg_data_dir); + } + + log_space::log_singletone::set_default_log_folder(log_dir); + + //setting html path + std::string path_to_html; + if (!command_line::has_arg(m_vm, arg_html_folder)) + { + path_to_html = string_tools::get_current_module_folder() + "/html"; + } + else + { + path_to_html = command_line::get_arg(m_vm, arg_html_folder); + } + + log_space::log_singletone::add_logger(LOGGER_FILE, log_file_name.c_str(), log_dir.c_str()); + LOG_PRINT_L0(CURRENCY_NAME << " v" << PROJECT_VERSION_LONG); + LOG_PRINT("Module folder: " << argv[0], LOG_LEVEL_0); + + if (command_line::has_arg(m_vm, arg_remote_node)) + { + bool r = configure_for_remote_node(command_line::get_arg(m_vm, arg_remote_node)); + CHECK_AND_ASSERT_MES(r, false, "Failed to configure_for_remote_node"); + } + + m_pview->init(path_to_html); + + if (!coomand_line_parsed) + { + std::stringstream ss; + for (int i = 0; i != argc; i++) + ss << "[" << i << "] " << argv[i] << std::endl; + + LOG_PRINT_L0("Command line has wrong arguments: " << std::endl << ss.str()); + } + return true; + CATCH_ENTRY_L0("init", false); +} + +bool daemon_backend::configure_for_remote_node(const std::string& remote_host) +{ + //parse node + tools::default_http_core_proxy* proxy = new tools::default_http_core_proxy(); + m_rpc_proxy.reset(proxy); + bool r = proxy->set_connection_addr(remote_host); + CHECK_AND_ASSERT_MES(r, false, "Failed to assign remote node address"); + proxy->set_plast_daemon_is_disconnected(&m_last_daemon_is_disconnected); + m_remote_node_mode = true; + return true; +} + +bool daemon_backend::start() +{ + TRY_ENTRY(); + + m_main_worker_thread = std::thread([this](){main_worker(this->m_vm);}); + + return true; + CATCH_ENTRY_L0("main", false); + } + + + +bool daemon_backend::send_stop_signal() +{ + m_stop_singal_sent = true; + return true; +} + + +bool daemon_backend::stop() +{ + send_stop_signal(); + if (m_main_worker_thread.joinable()) + { + LOG_PRINT_L0("Waiting for backend main worker thread: " << m_main_worker_thread.get_id()); + m_main_worker_thread.join(); + } + + + + return true; +} + +std::string daemon_backend::get_config_folder() +{ + return m_data_dir; +} +#define CHECK_AND_ASSERT_AND_SET_GUI(cond, mess) \ + if (!cond) \ + { \ + LOG_ERROR(mess); \ + dsi.daemon_network_state = currency::COMMAND_RPC_GET_INFO::daemon_network_state_internal_error; \ + m_pview->update_daemon_status(dsi); \ + m_pview->on_backend_stopped(); \ + return false; \ + } + +bool daemon_backend::init_local_daemon() +{ + view::daemon_status_info dsi = AUTO_VAL_INIT(dsi); + dsi.pos_difficulty = dsi.pos_difficulty = "---"; + dsi.daemon_network_state = currency::COMMAND_RPC_GET_INFO::daemon_network_state_loading_core; + m_pview->update_daemon_status(dsi); + + + //initialize core here + LOG_PRINT_L0("Initializing core..."); + //dsi.text_state = "Initializing core"; + m_pview->update_daemon_status(dsi); + bool res = m_ccore.init(m_vm); + CHECK_AND_ASSERT_AND_SET_GUI(res, "Failed to initialize core"); + LOG_PRINT_L0("Core initialized OK"); + + + //check if offers module synchronized with blockchaine storage + auto& bcs = m_ccore.get_blockchain_storage(); + if (!m_offers_service.is_disabled() && bcs.get_current_blockchain_size() > 1 && bcs.get_top_block_id() != m_offers_service.get_last_seen_block_id()) + { + res = resync_market(bcs, m_offers_service); + CHECK_AND_ASSERT_AND_SET_GUI(res, "Failed to initialize core: resync_market"); + //clear events that came after resync market + currency::i_core_event_handler* ph = m_ccore.get_blockchain_storage().get_event_handler(); + if (ph) ph->on_clear_events(); + } + + currency::checkpoints checkpoints; + res = currency::create_checkpoints(checkpoints); + CHECK_AND_ASSERT_MES(res, false, "Failed to initialize checkpoints"); + res = m_ccore.set_checkpoints(std::move(checkpoints)); + CHECK_AND_ASSERT_AND_SET_GUI(res, "Failed to initialize core: set_checkpoints failed"); + + //initialize objects + LOG_PRINT_L0("Initializing p2p server..."); + m_pview->update_daemon_status(dsi); + res = m_p2psrv.init(m_vm); + CHECK_AND_ASSERT_AND_SET_GUI(res, "Failed to initialize p2p server."); + LOG_PRINT_L0("P2p server initialized OK on port: " << m_p2psrv.get_this_peer_port()); + + //LOG_PRINT_L0("Starting UPnP"); + //upnp_helper.run_port_mapping_loop(p2psrv.get_this_peer_port(), p2psrv.get_this_peer_port(), 20*60*1000); + + LOG_PRINT_L0("Initializing currency protocol..."); + m_pview->update_daemon_status(dsi); + res = m_cprotocol.init(m_vm); + CHECK_AND_ASSERT_AND_SET_GUI(res, "Failed to initialize currency protocol."); + LOG_PRINT_L0("Currency protocol initialized OK"); + + LOG_PRINT_L0("Initializing core rpc server..."); + //dsi.text_state = "Initializing core rpc server"; + m_pview->update_daemon_status(dsi); + res = m_rpc_server.init(m_vm); + CHECK_AND_ASSERT_AND_SET_GUI(res, "Failed to initialize core rpc server."); + LOG_PRINT_GREEN("Core rpc server initialized OK on port: " << m_rpc_server.get_binded_port(), LOG_LEVEL_0); + + LOG_PRINT_L0("Starting core rpc server..."); + //dsi.text_state = "Starting core rpc server"; + m_pview->update_daemon_status(dsi); + res = m_rpc_server.run(2, false); + CHECK_AND_ASSERT_AND_SET_GUI(res, "Failed to initialize core rpc server."); + LOG_PRINT_L0("Core rpc server started ok"); + + LOG_PRINT_L0("Starting p2p net loop..."); + //dsi.text_state = "Starting network loop"; + m_pview->update_daemon_status(dsi); + res = m_p2psrv.run(false); + CHECK_AND_ASSERT_AND_SET_GUI(res, "Failed to run p2p loop."); + LOG_PRINT_L0("p2p net loop stopped"); + + return true; +} + +bool daemon_backend::deinit_local_daemon() +{ + view::daemon_status_info dsi = AUTO_VAL_INIT(dsi); + dsi.daemon_network_state = currency::COMMAND_RPC_GET_INFO::daemon_network_state_unloading_core; + m_pview->update_daemon_status(dsi); + + LOG_PRINT_L0("Stopping core p2p server..."); + //dsi.text_state = "Stopping p2p network server"; + m_pview->update_daemon_status(dsi); + m_p2psrv.send_stop_signal(); + m_p2psrv.timed_wait_server_stop(1000 * 60); + + //stop components + LOG_PRINT_L0("Stopping core rpc server..."); + //dsi.text_state = "Stopping rpc network server"; + m_pview->update_daemon_status(dsi); + + m_rpc_server.send_stop_signal(); + m_rpc_server.timed_wait_server_stop(5000); + + //deinitialize components + + + LOG_PRINT_L0("Deinitializing rpc server ..."); + //dsi.text_state = "Deinitializing rpc server"; + m_pview->update_daemon_status(dsi); + m_rpc_server.deinit(); + + + LOG_PRINT_L0("Deinitializing currency_protocol..."); + //dsi.text_state = "Deinitializing currency_protocol"; + m_pview->update_daemon_status(dsi); + m_cprotocol.deinit(); + + + LOG_PRINT_L0("Deinitializing p2p..."); + //dsi.text_state = "Deinitializing p2p"; + m_pview->update_daemon_status(dsi); + + m_ccore.set_currency_protocol(NULL); + m_cprotocol.set_p2p_endpoint(NULL); + + LOG_PRINT("Node stopped.", LOG_LEVEL_0); + //dsi.text_state = "Node stopped"; + m_pview->update_daemon_status(dsi); + + + m_pview->update_daemon_status(dsi); + LOG_PRINT_L0("Deinitializing market..."); + m_offers_service.set_last_seen_block_id(m_ccore.get_blockchain_storage().get_top_block_id()); + (static_cast(m_offers_service)).deinit(); + + LOG_PRINT_L0("Deinitializing core..."); + //dsi.text_state = "Deinitializing core"; + m_pview->update_daemon_status(dsi); + m_ccore.deinit(); + + return true; +} + +void daemon_backend::main_worker(const po::variables_map& m_vm) +{ + log_space::log_singletone::set_thread_log_prefix("[BACKEND_M]"); + TRY_ENTRY(); + + if (!m_remote_node_mode) + { + bool r = init_local_daemon(); + if (!r) + return; + } + + //go to monitoring view loop + loop(); + + + CRITICAL_REGION_BEGIN(m_wallets_lock); + for (auto& wo : m_wallets) + { + LOG_PRINT_L0("Storing wallet data..."); + //dsi.text_state = "Storing wallets data..."; + //m_pview->update_daemon_status(dsi); + try + { + wo.second.stop = true; + wo.second.w.unlocked_get()->stop(); + + wo.second.w->get()->store(); + } + catch (const std::exception& e) + { + LOG_ERROR("Exception rised at storing wallet: " << e.what()); + continue; + } + catch (...) + { + LOG_ERROR("Exception rised at storing wallet"); + continue; + } + + } + CRITICAL_REGION_END(); + + if (!m_remote_node_mode) + { + bool r = deinit_local_daemon(); + if (!r) + return; + } + + m_pview->on_backend_stopped(); + CATCH_ENTRY_L0("daemon_backend::main_worker", void()); +} + +bool daemon_backend::update_state_info() +{ + view::daemon_status_info dsi = AUTO_VAL_INIT(dsi); + currency::COMMAND_RPC_GET_INFO::request req = AUTO_VAL_INIT(req); + req.flags = COMMAND_RPC_GET_INFO_FLAG_EXPIRATIONS_MEDIAN; + currency::COMMAND_RPC_GET_INFO::response inf = AUTO_VAL_INIT(inf); + if (!m_rpc_proxy->call_COMMAND_RPC_GET_INFO(req, inf)) + { + //dsi.text_state = "get_info failed"; + dsi.is_disconnected = true; + m_last_daemon_network_state = dsi.daemon_network_state; + m_pview->update_daemon_status(dsi); + LOG_ERROR("Failed to call get_info"); + return false; + } + + m_is_pos_allowed = inf.pos_allowed; + dsi.alias_count = inf.alias_count; + dsi.pow_difficulty = std::to_string(inf.pow_difficulty); + dsi.pos_difficulty = inf.pos_difficulty; +// dsi.hashrate = inf.current_network_hashrate_350; + dsi.inc_connections_count = inf.incoming_connections_count; + dsi.out_connections_count = inf.outgoing_connections_count; + dsi.daemon_network_state = inf.daemon_network_state; + dsi.synchronization_start_height = inf.synchronization_start_height; + dsi.max_net_seen_height = inf.max_net_seen_height; + dsi.net_time_delta_median = inf.net_time_delta_median; + dsi.synchronized_connections_count = inf.synchronized_connections_count; + dsi.is_pos_allowed = inf.pos_allowed; + dsi.expiration_median_timestamp = inf.expiration_median_timestamp; + + dsi.last_build_available = std::to_string(inf.mi.ver_major) + + "." + std::to_string(inf.mi.ver_minor) + + "." + std::to_string(inf.mi.ver_revision) + + "." + std::to_string(inf.mi.build_no); + + if (inf.mi.mode) + { + dsi.last_build_displaymode = inf.mi.mode + 1; + } + else + { + if (inf.mi.build_no > PROJECT_VERSION_BUILD_NO) + dsi.last_build_displaymode = view::ui_last_build_displaymode::ui_lb_dm_new; + else + { + dsi.last_build_displaymode = view::ui_last_build_displaymode::ui_lb_dm_actual; + } + } + + get_last_blocks(dsi); + m_last_daemon_network_state = dsi.daemon_network_state; + m_last_daemon_height = dsi.height = inf.height; + m_pview->update_daemon_status(dsi); + return true; +} + +bool daemon_backend::get_last_blocks(view::daemon_status_info& dsi) +{ + + return true; +} + + + +void daemon_backend::toggle_pos_mining() +{ + //m_do_mint = !m_do_mint; + //update_wallets_info(); +} + +void daemon_backend::loop() +{ + while(!m_stop_singal_sent) + { + update_state_info(); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + } +} + +void daemon_backend::init_wallet_entry(wallet_vs_options& wo, uint64_t id) +{ + wo.wallet_id = id; + wo.do_mining = false; + wo.stop = false; + wo.plast_daemon_height = &m_last_daemon_height; + wo.plast_daemon_network_state = &m_last_daemon_network_state; + wo.plast_daemon_is_disconnected = &m_last_daemon_is_disconnected; + wo.pview = m_pview; + wo.has_related_alias_in_unconfirmed = false; + if (m_remote_node_mode) + wo.core_conf = currency::get_default_core_runtime_config(); + else + wo.core_conf = m_ccore.get_blockchain_storage().get_core_runtime_config(); +} + + + +std::string daemon_backend::get_tx_pool_info(currency::COMMAND_RPC_GET_POOL_INFO::response& res) +{ + currency::COMMAND_RPC_GET_POOL_INFO::request req = AUTO_VAL_INIT(req); + res = AUTO_VAL_INIT_T(currency::COMMAND_RPC_GET_POOL_INFO::response); + if (!m_rpc_proxy->call_COMMAND_RPC_GET_POOL_INFO(req, res)) + { + return API_RETURN_CODE_FAIL; + } + return API_RETURN_CODE_OK; +} + + +uint64_t daemon_backend::get_default_fee() +{ + return TX_DEFAULT_FEE; +} +std::string daemon_backend::get_fav_offers(const std::list& hashes, const bc_services::core_offers_filter& filter, std::list& offers) +{ + if (m_remote_node_mode) + return API_RETURN_CODE_FAIL; + + currency::blockchain_storage& bcs = m_ccore.get_blockchain_storage(); + + m_offers_service.get_offers_by_id(hashes, offers); + filter_offers_list(offers, filter, bcs.get_core_runtime_config().get_core_time()); + return API_RETURN_CODE_OK; +} + +std::string daemon_backend::get_my_offers(const bc_services::core_offers_filter& filter, std::list& offers) +{ + if (m_remote_node_mode) + return API_RETURN_CODE_FAIL; + + CRITICAL_REGION_LOCAL(m_wallets_lock); + while (true) + { + try + { + size_t wallet_index = 0; + for (auto& w : m_wallets) + { + auto offers_list_proxy = *w.second.offers; // obtain exclusive access to w.second.offers + size_t offers_count_before = offers.size(); + offers.insert(offers.end(), offers_list_proxy->begin(), offers_list_proxy->end()); + size_t offers_count_after = offers.size(); + + std::string wallet_title = "#" + epee::string_tools::num_to_string_fast(wallet_index); //(*(*w_ptr))->get_account().get_public_address_str() + " @ " + std::wstring_convert>().to_bytes((*(*w_ptr))->get_wallet_path()); + CHECK_AND_ASSERT_MES(offers_count_after >= offers_count_before, API_RETURN_CODE_INTERNAL_ERROR, "Invalid offers count after calling get_actual_offers: before: " << offers_count_before << ", after: " << offers_count_after << ", wallet: " << wallet_title); + size_t offers_added = offers_count_after - offers_count_before; + if (offers_added > 0) + { + LOG_PRINT("get_my_offers(): " << offers_added << " offers added from wallet " << wallet_title, LOG_LEVEL_2); + } + + ++wallet_index; + } + break; + } + catch (const tools::error::file_not_found& /**/) + { + return API_RETURN_CODE_FILE_NOT_FOUND; + } + catch (const std::exception& e) + { + return std::string(API_RETURN_CODE_WRONG_PASSWORD) + ":" + e.what(); + } + + } + + size_t offers_count_before_filtering = offers.size(); + bc_services::filter_offers_list(offers, filter, m_ccore.get_blockchain_storage().get_core_runtime_config().get_core_time()); + LOG_PRINT("get_my_offers(): " << offers.size() << " offers returned (" << offers_count_before_filtering << " was before filter)", LOG_LEVEL_1); + + return API_RETURN_CODE_OK; +} + +std::string daemon_backend::open_wallet(const std::wstring& path, const std::string& password, view::open_wallet_response& owr) +{ + std::shared_ptr w(new tools::wallet2()); + owr.wallet_id = m_wallet_id_counter++; + + w->callback(std::shared_ptr(new i_wallet_to_i_backend_adapter(this, owr.wallet_id))); + if (m_remote_node_mode) + { + w->set_core_proxy(m_rpc_proxy); + } + else + { + w->set_core_proxy(std::shared_ptr(new tools::core_fast_rpc_proxy(m_rpc_server))); + } + + std::string return_code = API_RETURN_CODE_OK; + CRITICAL_REGION_LOCAL(m_wallets_lock); + while (true) + { + try + { + w->load(path, password); + w->get_recent_transfers_history(owr.recent_history.history, 0, 0); + owr.recent_history.total_history_items = w->get_recent_transfers_total_count(); + //w->get_unconfirmed_transfers(owr.recent_history.unconfirmed); + w->get_unconfirmed_transfers(owr.recent_history.history); + //workaround for missed fee + break; + } + catch (const tools::error::file_not_found& /**/) + { + return API_RETURN_CODE_FILE_NOT_FOUND; + } + catch (const tools::error::wallet_load_notice_wallet_restored& /**/) + { + return_code = API_RETURN_CODE_FILE_RESTORED; + break; + } + catch (const std::exception& e) + { + return std::string(API_RETURN_CODE_WRONG_PASSWORD) + ":" + e.what(); + } + } + + wallet_vs_options& wo = m_wallets[owr.wallet_id]; + **wo.w = w; + get_wallet_info(wo, owr.wi); + init_wallet_entry(wo, owr.wallet_id); + //update_wallets_info(); + return return_code; +} + +std::string daemon_backend::get_recent_transfers(size_t wallet_id, uint64_t offset, uint64_t count, view::transfers_array& tr_hist) +{ + GET_WALLET_BY_ID(wallet_id, w); + auto wallet_locked = w.try_lock(); + if (!wallet_locked.get()) + { + return API_RETURN_CODE_CORE_BUSY; + } + + w->get()->get_recent_transfers_history(tr_hist.history, offset, count); + //workaround for missed fee + for (auto & he : tr_hist.history) + { + he.show_sender = currency::is_showing_sender_addres(he.tx); + if (!he.fee && !currency::is_coinbase(he.tx)) + { + he.fee = currency::get_tx_fee(he.tx); + } + } + + return API_RETURN_CODE_OK; +} + +std::string daemon_backend::generate_wallet(const std::wstring& path, const std::string& password, view::open_wallet_response& owr) +{ + std::shared_ptr w(new tools::wallet2()); + owr.wallet_id = m_wallet_id_counter++; + w->callback(std::shared_ptr(new i_wallet_to_i_backend_adapter(this, owr.wallet_id))); + if (m_remote_node_mode) + { + w->set_core_proxy(m_rpc_proxy); + } + else + { + w->set_core_proxy(std::shared_ptr(new tools::core_fast_rpc_proxy(m_rpc_server))); + } + + + CRITICAL_REGION_LOCAL(m_wallets_lock); + + try + { + w->generate(path, password); + } + catch (const tools::error::file_exists/*& e*/) + { + return API_RETURN_CODE_ALREADY_EXISTS; + } + + catch (const std::exception& e) + { + return std::string(API_RETURN_CODE_FAIL) + ":" + e.what(); + } + wallet_vs_options& wo = m_wallets[owr.wallet_id]; + **wo.w = w; + init_wallet_entry(wo, owr.wallet_id); + get_wallet_info(wo, owr.wi); + return API_RETURN_CODE_OK; +} + +std::string daemon_backend::get_mining_estimate(uint64_t amuont_coins, + uint64_t time, + uint64_t& estimate_result, + uint64_t& pos_coins_and_pos_diff_rate, + std::vector& days) +{ + if (m_remote_node_mode) + return API_RETURN_CODE_FAIL; + + m_ccore.get_blockchain_storage().get_pos_mining_estimate(amuont_coins, time, estimate_result, pos_coins_and_pos_diff_rate, days); + return API_RETURN_CODE_OK; +} + +std::string daemon_backend::is_pos_allowed() +{ + if (m_is_pos_allowed) + return API_RETURN_CODE_TRUE; + else + return API_RETURN_CODE_FALSE; +} +std::string daemon_backend::is_valid_brain_restore_data(const std::string& brain_text) +{ + currency::account_base acc; + if (acc.restore_keys_from_braindata(brain_text)) + return API_RETURN_CODE_TRUE; + else + return API_RETURN_CODE_FALSE; +} +void daemon_backend::subscribe_to_core_events(currency::i_core_event_handler* pevents_handler) +{ + if(!m_remote_node_mode) + m_ccore.get_blockchain_storage().set_event_handler(pevents_handler); +} +void daemon_backend::get_gui_options(view::gui_options& opt) +{ + opt = m_ui_opt; +} +std::string daemon_backend::restore_wallet(const std::wstring& path, const std::string& password, const std::string& restore_key, view::open_wallet_response& owr) +{ + std::shared_ptr w(new tools::wallet2()); + owr.wallet_id = m_wallet_id_counter++; + w->callback(std::shared_ptr(new i_wallet_to_i_backend_adapter(this, owr.wallet_id))); + if (m_remote_node_mode) + { + w->set_core_proxy(m_rpc_proxy); + } + else + { + w->set_core_proxy(std::shared_ptr(new tools::core_fast_rpc_proxy(m_rpc_server))); + } + + currency::account_base acc; + + CRITICAL_REGION_LOCAL(m_wallets_lock); + + try + { + w->restore(path, password, restore_key); + } + catch (const tools::error::file_exists/*& e*/) + { + return API_RETURN_CODE_ALREADY_EXISTS; + } + + catch (const std::exception& e) + { + return std::string(API_RETURN_CODE_FAIL) + ":" + e.what(); + } + wallet_vs_options& wo = m_wallets[owr.wallet_id]; + **wo.w = w; + init_wallet_entry(wo, owr.wallet_id); + get_wallet_info(wo, owr.wi); + return API_RETURN_CODE_OK; +} +std::string daemon_backend::close_wallet(size_t wallet_id) +{ + CRITICAL_REGION_LOCAL(m_wallets_lock); + + auto it = m_wallets.find(wallet_id); + if (it == m_wallets.end()) + return API_RETURN_CODE_WALLET_WRONG_ID; + + + try + { + it->second.stop = true; + it->second.w.unlocked_get()->stop(); + + it->second.w->get()->store(); + m_wallets.erase(it); + } + + catch (const std::exception& e) + { + return std::string(API_RETURN_CODE_FAIL) + ":" + e.what(); + } + //m_pview->hide_wallet(); + return API_RETURN_CODE_OK; +} + +std::string daemon_backend::get_aliases(view::alias_set& al_set) +{ + if (m_remote_node_mode) + return API_RETURN_CODE_OVERFLOW; + + if (m_ccore.get_blockchain_storage().get_aliases_count() > API_MAX_ALIASES_COUNT) + return API_RETURN_CODE_OVERFLOW; + + + currency::COMMAND_RPC_GET_ALL_ALIASES::response aliases = AUTO_VAL_INIT(aliases); + if (m_rpc_proxy->call_COMMAND_RPC_GET_ALL_ALIASES(aliases) && aliases.status == CORE_RPC_STATUS_OK) + { + al_set.aliases = aliases.aliases; + return API_RETURN_CODE_OK; + } + + return API_RETURN_CODE_FAIL; +} +std::string daemon_backend::get_alias_info_by_address(const std::string& addr, currency::alias_rpc_details& res_details) +{ + if (addr.empty()) + return API_RETURN_CODE_NOT_FOUND; + + currency::COMMAND_RPC_GET_ALIASES_BY_ADDRESS::request req = AUTO_VAL_INIT(req); + currency::COMMAND_RPC_GET_ALIASES_BY_ADDRESS::response res = AUTO_VAL_INIT(res); + + req = addr; + bool r = m_rpc_proxy->call_COMMAND_RPC_GET_ALIASES_BY_ADDRESS(req, res); + if (!r) + return API_RETURN_CODE_FAIL; + if (res.status != API_RETURN_CODE_OK) + return res.status; + + res_details = res.alias_info; + return res.status; +} + +std::string daemon_backend::get_alias_info_by_name(const std::string& name, currency::alias_rpc_details& res_details) +{ + if(name.empty()) + return API_RETURN_CODE_FILE_NOT_FOUND; + + currency::COMMAND_RPC_GET_ALIAS_DETAILS::request req = AUTO_VAL_INIT(req); + currency::COMMAND_RPC_GET_ALIAS_DETAILS::response res = AUTO_VAL_INIT(res); + + req.alias = name; + + bool r = m_rpc_proxy->call_COMMAND_RPC_GET_ALIAS_DETAILS(req, res); + if (!r) + return API_RETURN_CODE_FAIL; + + + res_details.alias = name; + res_details.details = res.alias_details; + return res.status; +} + +std::string daemon_backend::get_alias_coast(const std::string& a, uint64_t& coast) +{ + currency::COMMAND_RPC_GET_ALIAS_REWARD::request req = AUTO_VAL_INIT(req); + currency::COMMAND_RPC_GET_ALIAS_REWARD::response rsp = AUTO_VAL_INIT(rsp); + req.alias = a; + if (!m_rpc_proxy->call_COMMAND_RPC_GET_ALIAS_REWARD(req, rsp)) + return API_RETURN_CODE_BAD_ARG; + + coast = rsp.reward + rsp.reward/10; //add 10% of price to be sure + return rsp.status; + +} +std::string daemon_backend::request_alias_registration(const currency::alias_rpc_details& al, uint64_t wallet_id, uint64_t fee, currency::transaction& res_tx, uint64_t reward) +{ + currency::extra_alias_entry ai = AUTO_VAL_INIT(ai); + if (!currency::alias_rpc_details_to_alias_info(al, ai)) + return API_RETURN_CODE_BAD_ARG; + + if (!currency::validate_alias_name(ai.m_alias)) + { + return API_RETURN_CODE_BAD_ARG; + } + + currency::COMMAND_RPC_GET_ALIAS_DETAILS::request req = AUTO_VAL_INIT(req); + req.alias = ai.m_alias; + currency::COMMAND_RPC_GET_ALIAS_DETAILS::response rsp = AUTO_VAL_INIT(rsp); + if (m_rpc_proxy->call_COMMAND_RPC_GET_ALIAS_DETAILS(req, rsp) && rsp.status == CORE_RPC_STATUS_NOT_FOUND) + { + GET_WALLET_BY_ID(wallet_id, w); + try + { + w->get()->request_alias_registration(ai, res_tx, fee, reward); + return API_RETURN_CODE_OK; + } + catch (const std::exception& e) + { + LOG_ERROR("request_alias_registration error: " << e.what()); + std::string err_code = API_RETURN_CODE_INTERNAL_ERROR; + err_code += std::string(":") + e.what(); + return err_code; + } + catch (...) + { + LOG_ERROR("request_alias_registration error: unknown error"); + return API_RETURN_CODE_INTERNAL_ERROR; + } + } + + return API_RETURN_CODE_ALREADY_EXISTS; +} + +std::string daemon_backend::request_alias_update(const currency::alias_rpc_details& al, uint64_t wallet_id, uint64_t fee, currency::transaction& res_tx, uint64_t reward) +{ + currency::extra_alias_entry ai = AUTO_VAL_INIT(ai); + if (!currency::alias_rpc_details_to_alias_info(al, ai)) + return API_RETURN_CODE_BAD_ARG; + + if (!currency::validate_alias_name(ai.m_alias)) + { + return API_RETURN_CODE_BAD_ARG; + } + + currency::COMMAND_RPC_GET_ALIAS_DETAILS::request req; + req.alias = ai.m_alias; + currency::COMMAND_RPC_GET_ALIAS_DETAILS::response rsp = AUTO_VAL_INIT(rsp); + if (m_rpc_proxy->call_COMMAND_RPC_GET_ALIAS_DETAILS(req, rsp) && rsp.status == CORE_RPC_STATUS_OK) + { + GET_WALLET_BY_ID(wallet_id, w); + try + { + w->get()->request_alias_update(ai, res_tx, fee, reward); + return API_RETURN_CODE_OK; + } + catch (const std::exception& e) + { + LOG_ERROR("request_alias_update error: " << e.what()); + std::string err_code = API_RETURN_CODE_INTERNAL_ERROR; + err_code += std::string(":") + e.what(); + return err_code; + } + catch (...) + { + LOG_ERROR("request_alias_update error: unknown error"); + return API_RETURN_CODE_INTERNAL_ERROR; + } + } + + return API_RETURN_CODE_FILE_NOT_FOUND; +} + + +std::string daemon_backend::transfer(size_t wallet_id, const view::transfer_params& tp, currency::transaction& res_tx) +{ + + std::vector dsts; + if(!tp.destinations.size()) + return API_RETURN_CODE_BAD_ARG_EMPTY_DESTINATIONS; + + uint64_t fee = tp.fee; +// if (!currency::parse_amount(fee, tp.fee)) +// return API_RETURN_CODE_BAD_ARG_WRONG_FEE; + + std::string payment_id = tp.payment_id; + for(auto& d: tp.destinations) + { + dsts.push_back(currency::tx_destination_entry()); + dsts.back().addr.resize(1); + std::string embedded_payment_id; + if (!tools::get_transfer_address(d.address, dsts.back().addr.back(), embedded_payment_id, m_rpc_proxy.get())) + { + return API_RETURN_CODE_BAD_ARG_INVALID_ADDRESS; + } + if(!currency::parse_amount(dsts.back().amount, d.amount)) + { + return API_RETURN_CODE_BAD_ARG_WRONG_AMOUNT; + } + if (embedded_payment_id.size() != 0) + { + if (payment_id.size() != 0) + return API_RETURN_CODE_BAD_ARG_WRONG_PAYMENT_ID; // payment id is specified more than once + payment_id = embedded_payment_id; + } + } + //payment_id + std::vector attachments; + std::vector extra; + if (payment_id.size()) + { + if (!currency::is_payment_id_size_ok(payment_id)) + return API_RETURN_CODE_BAD_ARG_WRONG_PAYMENT_ID; // payment id is too big + + if (!currency::set_payment_id_to_tx(attachments, payment_id)) + return API_RETURN_CODE_INTERNAL_ERROR; + } + + GET_WALLET_BY_ID(wallet_id, w); + + + + try + { + //set transaction unlock time if it was specified by user + uint64_t unlock_time = 0; + if (tp.lock_time) + { + if (tp.lock_time > CURRENCY_MAX_BLOCK_NUMBER) + unlock_time = tp.lock_time; + else + unlock_time = w->get()->get_blockchain_current_height() + tp.lock_time; + } + + + //proces attachments + if (tp.comment.size()) + { + currency::tx_comment tc = AUTO_VAL_INIT(tc); + tc.comment = tp.comment; + extra.push_back(tc); + } + if (tp.push_payer) + { + currency::tx_payer txp = AUTO_VAL_INIT(txp); + txp.acc_addr = w->get()->get_account().get_keys().m_account_address; + extra.push_back(txp); + } + if (!tp.hide_receiver) + { + for (auto& d : dsts) + { + for (auto& a : d.addr) + { + currency::tx_receiver txr = AUTO_VAL_INIT(txr); + txr.acc_addr = a; + extra.push_back(txr); + } + } + } + w->get()->transfer(dsts, tp.mixin_count, unlock_time ? unlock_time + 1 : 0, fee, extra, attachments, res_tx); + //update_wallets_info(); + } + catch (const std::exception& e) + { + LOG_ERROR("Transfer error: " << e.what()); + std::string err_code = API_RETURN_CODE_INTERNAL_ERROR; + err_code += std::string(":") + e.what(); + return err_code; + } + catch (...) + { + LOG_ERROR("Transfer error: unknown error"); + return API_RETURN_CODE_INTERNAL_ERROR; + } + + return API_RETURN_CODE_OK; +} + +std::string daemon_backend::get_wallet_info(size_t wallet_id, view::wallet_info& wi) +{ + GET_WALLET_OPT_BY_ID(wallet_id, w); + return get_wallet_info(w, wi); +} +std::string daemon_backend::get_contracts(size_t wallet_id, std::vector& contracts) +{ + tools::wallet2::escrow_contracts_container cc; + GET_WALLET_OPT_BY_ID(wallet_id, w); + try + { + w.w->get()->get_contracts(cc); + } + catch (...) + { + return API_RETURN_CODE_FAIL; + } + + contracts.resize(cc.size()); + size_t i = 0; + for (auto& c: cc) + { + static_cast(contracts[i]) = c.second; + contracts[i].contract_id = c.first; + i++; + } + + return API_RETURN_CODE_OK; +} +std::string daemon_backend::create_proposal(size_t wallet_id, + const bc_services::contract_private_details& escrow_details, + const std::string& payment_id, + uint64_t expiration_period, + uint64_t fee, + uint64_t b_fee) +{ + tools::wallet2::escrow_contracts_container cc; + GET_WALLET_OPT_BY_ID(wallet_id, w); + try + { + currency::transaction tx = AUTO_VAL_INIT(tx); + currency::transaction template_tx = AUTO_VAL_INIT(template_tx); + w.w->get()->send_escrow_proposal(escrow_details, 0, 0, expiration_period, fee, b_fee, payment_id, tx, template_tx); + //TODO: add some + return API_RETURN_CODE_OK; + } + catch (const tools::error::not_enough_money& e) + { + LOG_ERROR("send_escrow_proposal error: API_RETURN_CODE_NOT_ENOUGH_MONEY: " << e.what()); + std::string err_code = API_RETURN_CODE_NOT_ENOUGH_MONEY; + return err_code; + } + catch (const std::exception& e) + { + LOG_ERROR("send_escrow_proposal error: " << e.what()); + std::string err_code = API_RETURN_CODE_INTERNAL_ERROR; + err_code += std::string(":") + e.what(); + return err_code; + } + catch (...) + { + LOG_ERROR("send_escrow_proposal error: unknown error"); + return API_RETURN_CODE_INTERNAL_ERROR; + } +} +std::string daemon_backend::accept_proposal(size_t wallet_id, const crypto::hash& contract_id) +{ + GET_WALLET_OPT_BY_ID(wallet_id, w); + try + { + w.w->get()->accept_proposal(contract_id, TX_DEFAULT_FEE); + //TODO: add some + return API_RETURN_CODE_OK; + } + catch (...) + { + return API_RETURN_CODE_FAIL; + } +} +std::string daemon_backend::release_contract(size_t wallet_id, const crypto::hash& contract_id, const std::string& contract_over_type) +{ + GET_WALLET_OPT_BY_ID(wallet_id, w); + try + { + w.w->get()->finish_contract(contract_id, contract_over_type); + //TODO: add some + return API_RETURN_CODE_OK; + } + catch (...) + { + return API_RETURN_CODE_FAIL; + } +} +std::string daemon_backend::request_cancel_contract(size_t wallet_id, const crypto::hash& contract_id, uint64_t fee, uint64_t expiration_period) +{ + GET_WALLET_OPT_BY_ID(wallet_id, w); + try + { + w.w->get()->request_cancel_contract(contract_id, fee, expiration_period); + //TODO: add some + return API_RETURN_CODE_OK; + } + catch (...) + { + return API_RETURN_CODE_FAIL; + } +} +std::string daemon_backend::accept_cancel_contract(size_t wallet_id, const crypto::hash& contract_id) +{ + GET_WALLET_OPT_BY_ID(wallet_id, w); + try + { + TIME_MEASURE_START_MS(timing1); + w.w->get()->accept_cancel_contract(contract_id); + //TODO: add some + TIME_MEASURE_FINISH_MS(timing1); + if (timing1 > 500) + LOG_PRINT_RED_L0("[daemon_backend::accept_cancel_contract] LOW PERFORMANCE: " << timing1 ); + + return API_RETURN_CODE_OK; + } + catch (...) + { + return API_RETURN_CODE_FAIL; + } +} +std::string daemon_backend::backup_wallet(uint64_t wallet_id, const std::wstring& path) +{ + GET_WALLET_OPT_BY_ID(wallet_id, w); + try + { + w.w->get()->store(path); + } + catch (...) + { + return API_RETURN_CODE_FAIL; + } + return API_RETURN_CODE_OK; +} +std::string daemon_backend::reset_wallet_password(uint64_t wallet_id, const std::string& pass) +{ + GET_WALLET_OPT_BY_ID(wallet_id, w); + if (w.w->get()->reset_password(pass)) + return API_RETURN_CODE_OK; + else + return API_RETURN_CODE_FAIL; +} +std::string daemon_backend::is_wallet_password_valid(uint64_t wallet_id, const std::string& pass) +{ + GET_WALLET_OPT_BY_ID(wallet_id, w); + if (w.w->get()->is_password_valid(pass)) + return API_RETURN_CODE_OK; + else + return API_RETURN_CODE_FAIL; +} +std::string daemon_backend::resync_wallet(uint64_t wallet_id) +{ + GET_WALLET_OPT_BY_ID(wallet_id, w); + w.w->get()->reset_history(); + w.last_wallet_synch_height = 0; + return API_RETURN_CODE_OK; +} +std::string daemon_backend::start_pos_mining(uint64_t wallet_id) +{ + GET_WALLET_OPT_BY_ID(wallet_id, wo); + wo.do_mining = true; + wo.need_to_update_wallet_info = true; + return API_RETURN_CODE_OK; +} +std::string daemon_backend::get_mining_history(uint64_t wallet_id, tools::wallet_rpc::mining_history& mh) +{ + GET_WALLET_OPT_BY_ID(wallet_id, wo); + + if (wo.wallet_state != view::wallet_status_info::wallet_state_ready) + return API_RETURN_CODE_CORE_BUSY; + + wo.w->get()->get_mining_history(mh); + return API_RETURN_CODE_OK; +} +std::string daemon_backend::get_wallet_restore_info(uint64_t wallet_id, std::string& restore_key) +{ + GET_WALLET_OPT_BY_ID(wallet_id, wo); + restore_key = wo.w->get()->get_account().get_restore_braindata(); +// restore_key = tools::base58::encode(rst_data); + return API_RETURN_CODE_OK; +} +void daemon_backend::prepare_wallet_status_info(wallet_vs_options& wo, view::wallet_status_info& wsi) +{ + wsi.is_mining = wo.do_mining; + wsi.wallet_id = wo.wallet_id; + wsi.is_alias_operations_available = !wo.has_related_alias_in_unconfirmed; + wsi.balance = wo.w->get()->balance(wsi.unlocked_balance, wsi.awaiting_in, wsi.awaiting_out, wsi.minied_total); +} +std::string daemon_backend::check_available_sources(uint64_t wallet_id, std::list& amounts) +{ + GET_WALLET_OPT_BY_ID(wallet_id, wo); + if (wo.w->get()->check_available_sources(amounts)) + return API_RETURN_CODE_TRUE; + else + return API_RETURN_CODE_FALSE; +} +std::string daemon_backend::stop_pos_mining(uint64_t wallet_id) +{ + GET_WALLET_OPT_BY_ID(wallet_id, wo); + wo.do_mining = false; + wo.need_to_update_wallet_info = true; + return API_RETURN_CODE_OK; +} +std::string daemon_backend::run_wallet(uint64_t wallet_id) +{ + GET_WALLET_OPT_BY_ID(wallet_id, wo); + wo.miner_thread = std::thread(boost::bind(&daemon_backend::wallet_vs_options::worker_func, &wo)); + return API_RETURN_CODE_OK; +} +std::string daemon_backend::get_wallet_info(wallet_vs_options& wo, view::wallet_info& wi) +{ + wi = view::wallet_info(); + wi.address = wo.w->get()->get_account().get_public_address_str(); + wi.tracking_hey = string_tools::pod_to_hex(wo.w->get()->get_account().get_keys().m_view_secret_key); + uint64_t fake = 0; + wi.balance = wo.w->get()->balance(wi.unlocked_balance, fake, fake, wi.mined_total); + wi.path = epee::string_encoding::wstring_to_utf8(wo.w->get()->get_wallet_path()); + return API_RETURN_CODE_OK; +} + +std::string daemon_backend::push_offer(size_t wallet_id, const bc_services::offer_details_ex& od, currency::transaction& res_tx) +{ + GET_WALLET_BY_ID(wallet_id, w); + + try + { + w->get()->push_offer(od, res_tx); + return API_RETURN_CODE_OK; + } + catch (const std::exception& e) + { + LOG_ERROR("push_offer error: " << e.what()); + std::string err_code = API_RETURN_CODE_INTERNAL_ERROR; + err_code += std::string(":") + e.what(); + return err_code; + } + catch (...) + { + LOG_ERROR("push_offer error: unknown error"); + return API_RETURN_CODE_INTERNAL_ERROR; + } +} +std::string daemon_backend::cancel_offer(const view::cancel_offer_param& co, currency::transaction& res_tx) +{ + GET_WALLET_BY_ID(co.wallet_id, w); + try + { + w->get()->cancel_offer_by_id(co.tx_id, co.no, res_tx); + return API_RETURN_CODE_OK; + } + catch (const std::exception& e) + { + LOG_ERROR("cancel_offer error: " << e.what()); + std::string err_code = API_RETURN_CODE_INTERNAL_ERROR; + err_code += std::string(":") + e.what(); + return err_code; + } + catch (...) + { + LOG_ERROR("cancel_offer error: unknown error"); + return API_RETURN_CODE_INTERNAL_ERROR; + } +} + +std::string daemon_backend::push_update_offer(const bc_services::update_offer_details& uo, currency::transaction& res_tx) +{ + GET_WALLET_BY_ID(uo.wallet_id, w); + + try + { + w->get()->update_offer_by_id(uo.tx_id, uo.no, uo.od, res_tx); + return API_RETURN_CODE_OK; + } + catch (const std::exception& e) + { + LOG_ERROR("cancel_offer error: " << e.what()); + std::string err_code = API_RETURN_CODE_INTERNAL_ERROR; + err_code += std::string(":") + e.what(); + return err_code; + } + catch (...) + { + LOG_ERROR("cancel_offer error: unknown error"); + return API_RETURN_CODE_INTERNAL_ERROR; + } +} + +// std::string daemon_backend::get_all_offers(currency::COMMAND_RPC_GET_ALL_OFFERS::response& od) +// { +// currency::COMMAND_RPC_GET_ALL_OFFERS::request rq = AUTO_VAL_INIT(rq); +// m_rpc_proxy->call_COMMAND_RPC_GET_ALL_OFFERS(rq, od); +// return API_RETURN_CODE_OK; +// } + + +std::string daemon_backend::get_offers_ex(const bc_services::core_offers_filter& cof, std::list& offers, uint64_t& total_count) +{ + if (m_remote_node_mode) + return API_RETURN_CODE_FAIL; + //TODO: make it proxy-like call + //m_ccore.get_blockchain_storage().get_offers_ex(cof, offers, total_count); + m_offers_service.get_offers_ex(cof, offers, total_count, m_ccore.get_blockchain_storage().get_core_runtime_config().get_core_time()); + return API_RETURN_CODE_OK; +} + + +std::string daemon_backend::validate_address(const std::string& addr_str, std::string& payment_id) +{ + currency::account_public_address acc = AUTO_VAL_INIT(acc); + if (currency::get_account_address_and_payment_id_from_str(acc, payment_id, addr_str)) + return API_RETURN_CODE_TRUE; + else + return API_RETURN_CODE_FALSE; +} + +void daemon_backend::on_new_block(size_t wallet_id, uint64_t /*height*/, const currency::block& /*block*/) +{ + +} + +void daemon_backend::on_transfer2(size_t wallet_id, const tools::wallet_rpc::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) +{ + view::transfer_event_info tei = AUTO_VAL_INIT(tei); + tei.ti = wti; + tei.balance = balance; + tei.unlocked_balance = unlocked_balance; + tei.wallet_id = wallet_id; + m_pview->money_transfer(tei); +} +void daemon_backend::on_pos_block_found(size_t wallet_id, const currency::block& b) +{ + m_pview->pos_block_found(b); +} +void daemon_backend::on_sync_progress(size_t wallet_id, const uint64_t& percents) +{ + view::wallet_sync_progres_param wspp = AUTO_VAL_INIT(wspp); + wspp.progress = percents; + wspp.wallet_id = wallet_id; + m_pview->wallet_sync_progress(wspp); +} +void daemon_backend::on_transfer_canceled(size_t wallet_id, const tools::wallet_rpc::wallet_transfer_info& wti) +{ + view::transfer_event_info tei = AUTO_VAL_INIT(tei); + tei.ti = wti; + + CRITICAL_REGION_LOCAL(m_wallets_lock); + auto& w = m_wallets[wallet_id].w; + if (w->get() != nullptr) + { + tei.balance = w->get()->balance(); + tei.unlocked_balance = w->get()->unlocked_balance(); + tei.wallet_id = wallet_id; + } + else + { + LOG_ERROR("on_transfer() wallet with id = " << wallet_id << " not found"); + } + m_pview->money_transfer_cancel(tei); +} +void daemon_backend::wallet_vs_options::worker_func() +{ + LOG_PRINT_GREEN("[WALLET_HANDLER] Wallet handler thread started, addr: " << w->get()->get_account().get_public_address_str(), LOG_LEVEL_0); + epee::math_helper::once_a_time_seconds<1> scan_pool_interval; + epee::math_helper::once_a_time_seconds pos_minin_interval; + view::wallet_status_info wsi = AUTO_VAL_INIT(wsi); + while (!stop) + { + try + { + wsi.wallet_state = view::wallet_status_info::wallet_state_ready; + if (plast_daemon_is_disconnected && plast_daemon_is_disconnected->load()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + continue; + } + + //****************************************************************************************** + //sync zone + if (*plast_daemon_network_state == currency::COMMAND_RPC_GET_INFO::daemon_network_state_online) + { + if (*plast_daemon_height != last_wallet_synch_height) + { + wsi.is_mining = do_mining; + bool show_progress = true; + if (last_wallet_synch_height && *plast_daemon_height - last_wallet_synch_height < 3) + show_progress = false; + + if (show_progress) + { + wallet_state = wsi.wallet_state = view::wallet_status_info::wallet_state_synchronizing; + prepare_wallet_status_info(*this, wsi); + pview->update_wallet_status(wsi); + } + w->get()->refresh(stop); + w->get()->resend_unconfirmed(); + { + auto w_ptr = *w; // get locked exclusive access to the wallet first (it's more likely that wallet is locked for a long time than 'offers') + auto offers_list_proxy = *offers; // than get locked exclusive access to offers + offers_list_proxy->clear(); + (*w_ptr)->get_actual_offers(*offers_list_proxy, false); + } + + wallet_state = wsi.wallet_state = view::wallet_status_info::wallet_state_ready; + prepare_wallet_status_info(*this, wsi); + pview->update_wallet_status(wsi); + //do refresh + last_wallet_synch_height = static_cast(*plast_daemon_height); + } + + scan_pool_interval.do_call([&](){ + bool has_related_alias = false; + w->get()->scan_tx_pool(has_related_alias); + if (has_related_alias_in_unconfirmed != has_related_alias) + { + // notify gui about alias operations locked for this wallet + has_related_alias_in_unconfirmed = has_related_alias; + wsi.wallet_state = view::wallet_status_info::wallet_state_ready; + prepare_wallet_status_info(*this, wsi); + pview->update_wallet_status(wsi); + } + + return true; + }); + } + + if (stop) + break; + //****************************************************************************************** + //mining zone + if (do_mining) + { + pos_minin_interval.do_call([this](){ + tools::wallet2::mining_context ctx = AUTO_VAL_INIT(ctx); + LOG_PRINT_L1("Starting PoS mint iteration"); + if (!w->get()->fill_mining_context(ctx) || ctx.rsp.status != CORE_RPC_STATUS_OK) + return true; + LOG_PRINT_L1("POS_ENTRIES: " << ctx.sp.pos_entries.size()); + tools::wallet2::scan_pos(ctx, break_mining_loop, [this](){ + return *plast_daemon_network_state == currency::COMMAND_RPC_GET_INFO::daemon_network_state_online && *plast_daemon_height == last_wallet_synch_height; + }, core_conf); + + if (ctx.rsp.status == CORE_RPC_STATUS_OK) + { + w->get()->build_minted_block(ctx.sp, ctx.rsp); + } + LOG_PRINT_L1("PoS mint iteration finished(" << ctx.rsp.status << ")"); + return true; + }); + } + } + catch (const tools::error::daemon_busy& /*e*/) + { + boost::this_thread::sleep_for(boost::chrono::milliseconds(100)); + continue; + } + + catch (const tools::error::no_connection_to_daemon& /*e*/) + { + boost::this_thread::sleep_for(boost::chrono::milliseconds(100)); + continue; + } + + catch (const std::exception& e) + { + LOG_PRINT_L0("Failed to refresh wallet: " << e.what()); + wallet_state = wsi.wallet_state = view::wallet_status_info::wallet_state_error; + pview->update_wallet_status(wsi); + return; + } + + catch (...) + { + LOG_PRINT_L0("Failed to refresh wallet, unknownk exception"); + wallet_state = wsi.wallet_state = view::wallet_status_info::wallet_state_error; + pview->update_wallet_status(wsi); + return; + } + boost::this_thread::sleep_for(boost::chrono::milliseconds(100)); + } + LOG_PRINT_GREEN("[WALLET_HANDLER] Wallet thread thread stopped", LOG_LEVEL_0); +} +daemon_backend::wallet_vs_options::~wallet_vs_options() +{ + do_mining = false; + stop = true; + break_mining_loop = true; + if (miner_thread.joinable()) + miner_thread.join(); +} diff --git a/src/gui/qt-daemon/application/daemon_backend.h b/src/gui/qt-daemon/application/daemon_backend.h new file mode 100644 index 00000000..5b23b895 --- /dev/null +++ b/src/gui/qt-daemon/application/daemon_backend.h @@ -0,0 +1,194 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include "warnings.h" +PUSH_WARNINGS +DISABLE_VS_WARNINGS(4100) +DISABLE_VS_WARNINGS(4503) +#include "include_base_utils.h" +#include "version.h" + +using namespace epee; + +#include "console_handler.h" +#include "p2p/net_node.h" +#include "currency_core/checkpoints_create.h" +#include "currency_core/currency_core.h" +#include "currency_core/bc_offers_service.h" +#include "rpc/core_rpc_server.h" +#include "currency_protocol/currency_protocol_handler.h" +#include "daemon/daemon_commands_handler.h" +//#include "common/miniupnp_helper.h" +#include "view_iface.h" +#include "core_fast_rpc_proxy.h" +#include "wallet/wallet2.h" +#include "wallet_id_adapter.h" + +POP_WARNINGS + +namespace po = boost::program_options; + +#if defined(WIN32) +#include +#endif + +//TODO: need refactoring here. (template classes can't be used in BOOST_CLASS_VERSION) +BOOST_CLASS_VERSION(nodetool::node_server >, CURRENT_P2P_STORAGE_ARCHIVE_VER); + +struct wallet_lock_time_watching_policy +{ + static void watch_lock_time(uint64_t lock_time); +}; + + +class daemon_backend : public i_backend_wallet_callback +{ + +public: + struct wallet_vs_options + { + currency::core_runtime_config core_conf; + epee::locked_object, wallet_lock_time_watching_policy> w; + std::atomic do_mining; + std::atomic stop; + std::atomic break_mining_loop; + std::atomic wallet_state; + std::atomic last_wallet_synch_height; + std::atomic* plast_daemon_height; + std::atomic* plast_daemon_network_state; + std::atomic* plast_daemon_is_disconnected; + std::atomic has_related_alias_in_unconfirmed; + std::atomic need_to_update_wallet_info; + view::i_view* pview; + uint64_t wallet_id; + epee::locked_object> offers; + + std::thread miner_thread; + void worker_func(); + ~wallet_vs_options(); + }; + + daemon_backend(); + ~daemon_backend(); + bool init(int argc, char* argv[], view::i_view* pview_handler); + bool start(); + bool stop(); + bool send_stop_signal(); + std::string open_wallet(const std::wstring& path, const std::string& password, view::open_wallet_response& owr); + std::string generate_wallet(const std::wstring& path, const std::string& password, view::open_wallet_response& owr); + std::string restore_wallet(const std::wstring& path, const std::string& password, const std::string& restore_key, view::open_wallet_response& owr); + std::string run_wallet(uint64_t wallet_id); + std::string get_recent_transfers(size_t wallet_id, uint64_t offset, uint64_t count, view::transfers_array& tr_hist); + std::string get_wallet_info(size_t wallet_id, view::wallet_info& wi); + std::string get_contracts(size_t wallet_id, std::vector& contracts); + std::string create_proposal(size_t wallet_id, const bc_services::contract_private_details& escrow, const std::string& payment_id, + uint64_t expiration_period, + uint64_t fee, + uint64_t b_fee); + std::string accept_proposal(size_t wallet_id, const crypto::hash& contract_id); + std::string release_contract(size_t wallet_id, const crypto::hash& contract_id, const std::string& contract_over_type); + std::string request_cancel_contract(size_t wallet_id, const crypto::hash& contract_id, uint64_t fee, uint64_t expiration_period); + std::string accept_cancel_contract(size_t wallet_id, const crypto::hash& contract_id); + + + std::string get_wallet_info(wallet_vs_options& w, view::wallet_info& wi); + std::string close_wallet(size_t wallet_id); + std::string push_offer(size_t wallet_id, const bc_services::offer_details_ex& od, currency::transaction& res_tx); + std::string cancel_offer(const view::cancel_offer_param& co, currency::transaction& res_tx); + std::string push_update_offer(const bc_services::update_offer_details& uo, currency::transaction& res_tx); + //std::string get_all_offers(currency::COMMAND_RPC_GET_ALL_OFFERS::response& od); + std::string get_offers_ex(const bc_services::core_offers_filter& cof, std::list& offers, uint64_t& total_count); + std::string get_aliases(view::alias_set& al_set); + std::string get_alias_info_by_address(const std::string& addr, currency::alias_rpc_details& res_details); + std::string get_alias_info_by_name(const std::string& name, currency::alias_rpc_details& res_details); + std::string request_alias_registration(const currency::alias_rpc_details& al, uint64_t wallet_id, uint64_t fee, currency::transaction& res_tx, uint64_t reward); + std::string request_alias_update(const currency::alias_rpc_details& al, uint64_t wallet_id, uint64_t fee, currency::transaction& res_tx, uint64_t reward); + std::string get_alias_coast(const std::string& a, uint64_t& coast); + std::string validate_address(const std::string& addr, std::string& payment_id); + std::string resync_wallet(uint64_t wallet_id); + std::string start_pos_mining(uint64_t wallet_id); + std::string stop_pos_mining(uint64_t wallet_id); + std::string check_available_sources(uint64_t wallet_id, std::list& amounts); + std::string get_mining_history(uint64_t wallet_id, tools::wallet_rpc::mining_history& wrpc); + std::string get_wallet_restore_info(uint64_t wallet_id, std::string& restore_key); + std::string backup_wallet(uint64_t wallet_id, const std::wstring& path); + std::string reset_wallet_password(uint64_t wallet_id, const std::string& pass); + std::string is_wallet_password_valid(uint64_t wallet_id, const std::string& pass); + std::string get_my_offers(const bc_services::core_offers_filter& filter, std::list& offers); + std::string get_fav_offers(const std::list& hashes, const bc_services::core_offers_filter& filter, std::list& offers); + std::string get_tx_pool_info(currency::COMMAND_RPC_GET_POOL_INFO::response& res); + uint64_t get_default_fee(); + std::string get_mining_estimate(uint64_t amuont_coins, + uint64_t time, + uint64_t& estimate_result, + uint64_t& all_coins_and_pos_diff_rate, + std::vector& days); + std::string is_pos_allowed(); + void toggle_pos_mining(); + std::string transfer(size_t wallet_id, const view::transfer_params& tp, currency::transaction& res_tx); + std::string get_config_folder(); + std::string is_valid_brain_restore_data(const std::string& brain_text); + void subscribe_to_core_events(currency::i_core_event_handler* pevents_handler); + void unsubscribe_to_core_events(); + void get_gui_options(view::gui_options& opt); + bool is_remote_node_mode() { return m_remote_node_mode; } + bool configure_for_remote_node(const std::string& remote_host); +private: + void main_worker(const po::variables_map& vm); + bool init_local_daemon(); + bool deinit_local_daemon(); + bool update_state_info(); + bool update_wallets(); + void loop(); + //bool get_transfer_address(const std::string& adr_str, currency::account_public_address& addr, std::string& payment_id); + bool get_last_blocks(view::daemon_status_info& dsi); + void update_wallets_info(); + void init_wallet_entry(wallet_vs_options& wo, uint64_t id); + static void prepare_wallet_status_info(wallet_vs_options& wo, view::wallet_status_info& wsi); + //----- i_backend_wallet_callback ------ + virtual void on_new_block(size_t wallet_id, uint64_t height, const currency::block& block); + virtual void on_transfer2(size_t wallet_id, const tools::wallet_rpc::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined); + virtual void on_pos_block_found(size_t wallet_id, const currency::block& /*block*/); + virtual void on_sync_progress(size_t wallet_id, const uint64_t& /*percents*/); + virtual void on_transfer_canceled(size_t wallet_id, const tools::wallet_rpc::wallet_transfer_info& wti); + + std::thread m_main_worker_thread; + std::atomic m_stop_singal_sent; + view::i_view m_view_stub; + view::i_view* m_pview; + std::shared_ptr m_rpc_proxy; + critical_section m_wallets_lock; + po::variables_map m_vm; + + std::atomic m_last_daemon_height; + std::atomic m_last_daemon_network_state; + std::atomic m_last_daemon_is_disconnected; +// std::atomic m_last_wallet_synch_height; + std::atomic m_wallet_id_counter; + + std::string m_data_dir; + view::gui_options m_ui_opt; + + //daemon stuff + bc_services::bc_offers_service m_offers_service; + currency::core m_ccore; + currency::t_currency_protocol_handler m_cprotocol; + nodetool::node_server > m_p2psrv; + currency::core_rpc_server m_rpc_server; + + bool m_remote_node_mode; + std::atomic m_is_pos_allowed; + + + std::map m_wallets; +}; + + + + diff --git a/src/gui/qt-daemon/application/gui_utils.cpp b/src/gui/qt-daemon/application/gui_utils.cpp new file mode 100644 index 00000000..7ccfdb1e --- /dev/null +++ b/src/gui/qt-daemon/application/gui_utils.cpp @@ -0,0 +1,320 @@ +// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2015 Boolberry developers +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "gui_utils.h" + +// #include +#include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +#include +// #include // for Qt::mightBeRichText +// #include + +// #if QT_VERSION < 0x050000 +// #include +// #else +// #include +// #endif +#include +#include +#include "currency_core/currency_config.h" +#define GUI_LINK_NAME "Zano" + +#ifdef WIN32 +#ifdef _WIN32_WINNT +#undef _WIN32_WINNT +#endif +#define _WIN32_WINNT 0x0501 +#ifdef _WIN32_IE +#undef _WIN32_IE +#endif +#define _WIN32_IE 0x0501 +#define WIN32_LEAN_AND_MEAN 1 +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include +#include +#include +#include +#endif + +#include +#include +#if BOOST_FILESYSTEM_VERSION >= 3 +#include +#endif +#include + +#ifndef MAX_PATH +#define MAX_PATH 1000 +#endif + +#if BOOST_FILESYSTEM_VERSION >= 3 +static boost::filesystem::detail::utf8_codecvt_facet utf8; +#endif + + + +namespace gui_tools +{ + +#ifdef WIN32 + boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true) + { + namespace fs = boost::filesystem; + + char pszPath[MAX_PATH] = ""; + + if (SHGetSpecialFolderPathA(NULL, pszPath, nFolder, fCreate)) + { + return fs::path(pszPath); + } + + //LogPrintf("SHGetSpecialFolderPathA() failed, could not obtain requested path.\n"); + return fs::path(""); + } +#endif +#ifdef WIN32 + boost::filesystem::path static StartupShortcutPath() + { + return GetSpecialFolderPath(CSIDL_STARTUP) / GUI_LINK_NAME ".lnk"; + } + + bool GetStartOnSystemStartup() + { + // check for Bitcoin*.lnk + return boost::filesystem::exists(StartupShortcutPath()); + } + + bool SetStartOnSystemStartup(bool fAutoStart) + { + // If the shortcut exists already, remove it for updating + boost::system::error_code ec; + std::wstring shrtcut_path = StartupShortcutPath().c_str(); + boost::filesystem::remove(shrtcut_path.c_str(), ec); + if (ec) + { + //LOG_ERROR("Autostart disable failed: " << ec.message()); + } + + if (fAutoStart) + { + CoInitialize(NULL); + + // Get a pointer to the IShellLink interface. + IShellLink* psl = NULL; + HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, + CLSCTX_INPROC_SERVER, IID_IShellLink, + reinterpret_cast(&psl)); + + if (SUCCEEDED(hres)) + { + // Get the current executable path + TCHAR pszExePath[MAX_PATH]; + GetModuleFileName(NULL, pszExePath, sizeof(pszExePath)); + + // Start client minimized + //QString strArgs = "-min"; + // Set -testnet /-regtest options + //strArgs += QString::fromStdString(strprintf(" -testnet=%d -regtest=%d", GetBoolArg("-testnet", false), GetBoolArg("-regtest", false))); + +//#ifdef UNICODE +// boost::scoped_array args(new TCHAR[strArgs.length() + 1]); + // Convert the QString to TCHAR* +// strArgs.toWCharArray(args.get()); + // Add missing '\0'-termination to string +// args[strArgs.length()] = '\0'; +//#endif + + // Set the path to the shortcut target + psl->SetPath(pszExePath); + PathRemoveFileSpec(pszExePath); + psl->SetWorkingDirectory(pszExePath); + psl->SetShowCmd(SW_SHOWMINNOACTIVE); +//#ifndef UNICODE +// psl->SetArguments(strArgs.toStdString().c_str()); +//#else +// psl->SetArguments(args.get()); +//#endif + + // Query IShellLink for the IPersistFile interface for + // saving the shortcut in persistent storage. + IPersistFile* ppf = NULL; + hres = psl->QueryInterface(IID_IPersistFile, reinterpret_cast(&ppf)); + if (SUCCEEDED(hres)) + { + WCHAR pwsz[MAX_PATH]; + // Ensure that the string is ANSI. + MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().string().c_str(), -1, pwsz, MAX_PATH); + // Save the link by calling IPersistFile::Save. + hres = ppf->Save(pwsz, TRUE); + ppf->Release(); + psl->Release(); + CoUninitialize(); + return true; + } + psl->Release(); + } + CoUninitialize(); + return false; + } + return true; + } +#elif defined(Q_OS_LINUX) + + // Follow the Desktop Application Autostart Spec: + // http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html + + boost::filesystem::path static GetAutostartDir() + { + namespace fs = boost::filesystem; + + char* pszConfigHome = getenv("XDG_CONFIG_HOME"); + if (pszConfigHome) return fs::path(pszConfigHome) / "autostart"; + char* pszHome = getenv("HOME"); + if (pszHome) return fs::path(pszHome) / ".config" / "autostart"; + return fs::path(); + } + + boost::filesystem::path static GetAutostartFilePath() + { + return GetAutostartDir() / GUI_LINK_NAME ".desktop"; + } + + bool GetStartOnSystemStartup() + { + boost::filesystem::ifstream optionFile(GetAutostartFilePath()); + if (!optionFile.good()) + return false; + // Scan through file for "Hidden=true": + std::string line; + while (!optionFile.eof()) + { + getline(optionFile, line); + if (line.find("Hidden") != std::string::npos && + line.find("true") != std::string::npos) + return false; + } + optionFile.close(); + + return true; + } + + bool SetStartOnSystemStartup(bool fAutoStart) + { + if (!fAutoStart) + boost::filesystem::remove(GetAutostartFilePath()); + else + { + char pszExePath[MAX_PATH + 1]; + memset(pszExePath, 0, sizeof(pszExePath)); + if (readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1) == -1) + return false; + + boost::filesystem::create_directories(GetAutostartDir()); + + boost::filesystem::ofstream optionFile(GetAutostartFilePath(), std::ios_base::out | std::ios_base::trunc); + if (!optionFile.good()) + return false; + // Write a bitcoin.desktop file to the autostart directory: + optionFile << "[Desktop Entry]\n"; + optionFile << "Type=Application\n"; + optionFile << "Name=" << CURRENCY_NAME_BASE << "\n"; + optionFile << "Exec=" << pszExePath << "\n"; + optionFile << "Terminal=false\n"; + optionFile << "Hidden=false\n"; + optionFile.close(); + } + return true; + } + + +#elif defined(Q_OS_MAC) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + // based on: https://github.com/Mozketo/LaunchAtLoginController/blob/master/LaunchAtLoginController.m + +#include +#include + + LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl); + LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl) + { + SInt32 macos_ver_maj, macos_ver_min; + Gestalt(gestaltSystemVersionMajor, &macos_ver_maj); // very old and deprecated, consider change + Gestalt(gestaltSystemVersionMinor, &macos_ver_min); // very old and deprecated, consider change + + // loop through the list of startup items and try to find the bitcoin app + CFArrayRef listSnapshot = LSSharedFileListCopySnapshot(list, NULL); + for(int i = 0; i < CFArrayGetCount(listSnapshot); i++) { + LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(listSnapshot, i); + UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes; + CFURLRef currentItemURL = NULL; + +#if defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED >= 10100 + if (&LSSharedFileListItemCopyResolvedURL != NULL && (macos_ver_maj > 10 || (macos_ver_maj == 10 && macos_ver_min >= 10))) + currentItemURL = LSSharedFileListItemCopyResolvedURL(item, resolutionFlags, NULL); // this is available only on macOS 10.10-10.11 (then deprecated) +#if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && MAC_OS_X_VERSION_MIN_REQUIRED < 10100 + else + LSSharedFileListItemResolve(item, resolutionFlags, ¤tItemURL, NULL); +#endif +#else + LSSharedFileListItemResolve(item, resolutionFlags, ¤tItemURL, NULL); +#endif + + if(currentItemURL && CFEqual(currentItemURL, findUrl)) { + // found + CFRelease(currentItemURL); + return item; + } + if(currentItemURL) { + CFRelease(currentItemURL); + } + } + return NULL; + } + + bool GetStartOnSystemStartup() + { + CFURLRef bitcoinAppUrl = CFBundleCopyBundleURL(CFBundleGetMainBundle()); + LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); + LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, bitcoinAppUrl); + return !!foundItem; // return boolified object + } + + bool SetStartOnSystemStartup(bool fAutoStart) + { + CFURLRef bitcoinAppUrl = CFBundleCopyBundleURL(CFBundleGetMainBundle()); + LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); + LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, bitcoinAppUrl); + + if(fAutoStart && !foundItem) { + // add bitcoin app to startup item list + LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemBeforeFirst, NULL, NULL, bitcoinAppUrl, NULL, NULL); + } + else if(!fAutoStart && foundItem) { + // remove item + LSSharedFileListItemRemove(loginItems, foundItem); + } + return true; + } +#pragma GCC diagnostic pop +#else + + bool GetStartOnSystemStartup() { return false; } + bool SetStartOnSystemStartup(bool fAutoStart) { return false; } + +#endif +} diff --git a/src/gui/qt-daemon/application/gui_utils.h b/src/gui/qt-daemon/application/gui_utils.h new file mode 100644 index 00000000..0350cb16 --- /dev/null +++ b/src/gui/qt-daemon/application/gui_utils.h @@ -0,0 +1,14 @@ +// Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2015 Boolberry developers +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +namespace gui_tools +{ + bool GetStartOnSystemStartup(); + bool SetStartOnSystemStartup(bool fAutoStart); +} \ No newline at end of file diff --git a/src/gui/qt-daemon/application/mainwindow.cpp b/src/gui/qt-daemon/application/mainwindow.cpp new file mode 100644 index 00000000..3cc645c2 --- /dev/null +++ b/src/gui/qt-daemon/application/mainwindow.cpp @@ -0,0 +1,1616 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include + +#include "string_coding.h" +#include "gui_utils.h" +#include "notification_helper.h" + +#define PREPARE_ARG_FROM_JSON(arg_type, var_name) \ + arg_type var_name = AUTO_VAL_INIT(var_name); \ + view::api_response default_ar = AUTO_VAL_INIT(default_ar); \ +if (!epee::serialization::load_t_from_json(var_name, param.toStdString())) \ +{ \ + default_ar.error_code = API_RETURN_CODE_BAD_ARG; \ + return MAKE_RESPONSE(default_ar); \ +} + +#define PREPARE_RESPONSE(rsp_type, var_name) view::api_response_t var_name = AUTO_VAL_INIT(var_name); +#define MAKE_RESPONSE(r) epee::serialization::store_t_to_json(r).c_str(); + +#define LOG_API_TIMING() const char* pfunc_call_name = LOCAL_FUNCTION_DEF__; LOG_PRINT_BLUE("[API:" << pfunc_call_name << "]-->>", LOG_LEVEL_0); uint64_t ticks_before_start = epee::misc_utils::get_tick_count(); \ + auto cb_leave = epee::misc_utils::create_scope_leave_handler([&ticks_before_start, &pfunc_call_name](){ \ + LOG_PRINT_BLUE("[API:" << pfunc_call_name << "]<<-- (" << epee::misc_utils::get_tick_count() - ticks_before_start << "ms)" << (epee::misc_utils::get_tick_count() - ticks_before_start > 1000 ? "[!!!LONG CALL!!!]":""), LOG_LEVEL_0); \ + }); + +#define LOG_API_PARAMS(log_level) LOG_PRINT_BLUE(LOCAL_FUNCTION_DEF__ << "(" << param.toStdString() << ")", log_level) + + +#include "mainwindow.h" +// +// void MediatorObject::from_html_to_c(const QString &text) +// { +// from_c_to_html(text); +// } +// +// template +// struct InvokeWrapper { +// R *receiver; +// void (C::*memberFun)(Arg); +// void operator()(Arg result) { +// (receiver->*memberFun)(result); +// } +// }; +// +// template +// InvokeWrapper invoke(R *receiver, void (C::*memberFun)(Arg)) +// { +// InvokeWrapper wrapper = { receiver, memberFun }; +// return wrapper; +// } + + +std::wstring convert_to_lower_via_qt(const std::wstring& w) +{ + std::wstring r; + return QString().fromStdWString(w).toLower().toStdWString(); +} + + +MainWindow::MainWindow(): + //m_quit_requested(false), + m_gui_deinitialize_done_1(false), + m_backend_stopped_2(false), + m_system_shutdown(false) +{ + m_view = new QWebEngineView(this); + m_channel = new QWebChannel(m_view->page()); + m_view->page()->setWebChannel(m_channel); + + // register QObjects to be exposed to JavaScript + m_channel->registerObject(QStringLiteral("mediator_object"), this); + + connect(m_view, SIGNAL(loadFinished(bool)), SLOT(on_load_finished(bool))); + + setCentralWidget(m_view); + //this->setMouseTracking(true); + + m_view->page()->settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls, true); + m_view->page()->settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls, true); + m_view->page()->settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true); + + m_view->settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls, true); + m_view->settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls, true); + m_view->settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true); + + m_localization.resize(localization_id_couter); + m_localization[localization_id_quit] = "Quit"; + m_localization[localization_id_is_received] = " is received"; + m_localization[localization_id_is_confirmed] = " is confirmed"; + m_localization[localization_id_income_transfer_unconfirmed] = "Income transfer (unconfirmed)"; + m_localization[localization_id_income_transfer_confirmed] = "Income transfer confirmed"; + m_localization[localization_id_locked] = "(locked)"; + m_localization[localization_id_mined] = "(mined)"; + m_localization[localization_id_minimized_title] = "Zano app is minimized to tray"; + m_localization[localization_id_minimized_text] = "You can restore it with double-click or context menu"; + m_localization[localization_id_tray_menu_show] = "localization_id_tray_menu_show"; + m_localization[localization_id_tray_menu_minimize] = "localization_id_tray_menu_minimize"; + +#ifndef _MSC_VER + //workaround for macos broken tolower from std, very dirty hack + bc_services::set_external_to_low_converter(convert_to_lower_via_qt); +#endif + +} + +MainWindow::~MainWindow() +{ + m_backend.subscribe_to_core_events(nullptr); + m_view->page()->setWebChannel(nullptr); + m_channel->deregisterObject(this); + delete m_channel; +} + +void MainWindow::on_load_finished(bool ok) +{ + LOG_PRINT("MainWindow::on_load_finished(ok = " << (ok ? "true" : "false") << ")", LOG_LEVEL_0); +} + + + +//------------- +QString MainWindow::get_default_user_dir(const QString& param) +{ + return tools::get_default_user_dir().c_str(); +} + + +bool MainWindow::toggle_mining() +{ + m_backend.toggle_pos_mining(); + return true; +} +QString MainWindow::get_exchange_last_top(const QString& params) +{ + return QString(); +} + +QString MainWindow::get_tx_pool_info() +{ + LOG_API_TIMING(); + PREPARE_RESPONSE(currency::COMMAND_RPC_GET_POOL_INFO::response, ar); + ar.error_code = m_backend.get_tx_pool_info(ar.response_data); + return MAKE_RESPONSE(ar); +} +// bool MainWindow::store_config() +// { +// return true; +// } + +QString MainWindow::get_default_fee() +{ + return QString(std::to_string(m_backend.get_default_fee()).c_str()); +} + +QString MainWindow::get_options() +{ + LOG_API_TIMING(); + PREPARE_RESPONSE(view::gui_options, ar); + m_backend.get_gui_options(ar.response_data); + ar.error_code = API_RETURN_CODE_OK; + return MAKE_RESPONSE(ar); +} + +void MainWindow::tray_quit_requested() +{ + LOG_PRINT_MAGENTA("[GUI]->[HTML] tray_quit_requested", LOG_LEVEL_0); + emit quit_requested("{}"); +} + +void MainWindow::closeEvent(QCloseEvent *event) +{ + LOG_PRINT_L0("[GUI] CLOSE EVENT"); + CHECK_AND_ASSERT_MES(m_gui_deinitialize_done_1 == m_backend_stopped_2, void(), "m_gui_deinitialize_done_1 != m_backend_stopped_2, m_gui_deinitialize_done_1 = " << m_gui_deinitialize_done_1 + << "m_backend_stopped_2 = " << m_backend_stopped_2); + + + if (m_system_shutdown && !m_gui_deinitialize_done_1) + { + LOG_PRINT_MAGENTA("Shutting down without waiting response from html", LOG_LEVEL_0); + //Usually QtWebEngineProcess.exe already killed at this moment, so we won't get response from html. + m_gui_deinitialize_done_1 = true; + m_backend.send_stop_signal(); + } + else if (m_gui_deinitialize_done_1 && m_backend_stopped_2) + { + store_pos(true); + store_app_config(); + event->accept(); + } + else + { + //m_quit_requested = true; + LOG_PRINT_L0("[GUI]->[HTML] quit_requested"); + emit quit_requested("{}"); + event->ignore(); + } +} + +std::string state_to_text(int s) +{ + std::string res = epee::string_tools::int_to_hex(s); + res += "("; + if (s & Qt::WindowMinimized) + res += " WindowMinimized"; + if (s & Qt::WindowMaximized) + res += " WindowMaximized"; + if (s & Qt::WindowFullScreen) + res += " WindowFullScreen"; + if (s & Qt::WindowActive) + res += " WindowActive"; + res += ")"; + + return res; +} + +void MainWindow::changeEvent(QEvent *e) +{ + switch (e->type()) + { + case QEvent::WindowStateChange: + { + QWindowStateChangeEvent* event = static_cast< QWindowStateChangeEvent* >(e); + qDebug() << "Old state: " << state_to_text(event->oldState()).c_str() << ", new state: " << state_to_text(this->windowState()).c_str(); + + if (event->oldState() & Qt::WindowMinimized && !(this->windowState() & Qt::WindowMinimized)) + { + qDebug() << "Window restored (to normal or maximized state)!"; + if (m_tray_icon) + { + //QTimer::singleShot(250, this, SLOT(show())); + } + restore_pos(); + } + else if (!(event->oldState() & Qt::WindowMinimized) && (this->windowState() & Qt::WindowMinimized)) + { + store_pos(); + qDebug() << "Window minimized"; + show_notification(m_localization[localization_id_minimized_title], m_localization[localization_id_minimized_text]); + } + else if (!(event->oldState() & Qt::WindowFullScreen) && (this->windowState() & Qt::WindowFullScreen)) + { + //maximize + store_window_pos(); + this->update(); + } + else if ((event->oldState() & Qt::WindowFullScreen) && !(this->windowState() & Qt::WindowFullScreen)) + { + //restore + this->update(); + } + + break; + } + default: + break; + } + + QWidget::changeEvent(e); +} + +bool MainWindow::store_app_config() +{ + std::string conf_path = m_backend.get_config_folder() + "/" + GUI_INTERNAL_CONFIG; + return tools::serialize_obj_to_file(m_config, conf_path); +} + +bool MainWindow::load_app_config() +{ + std::string conf_path = m_backend.get_config_folder() + "/" + GUI_INTERNAL_CONFIG; + return tools::unserialize_obj_from_file(m_config, conf_path); +} + +bool MainWindow::init(const std::string& htmlPath) +{ + //QtWebEngine::initialize(); + init_tray_icon(htmlPath); + set_html_path(htmlPath); + + + + m_backend.subscribe_to_core_events(this); + + bool r = QSslSocket::supportsSsl(); + if (r) + { + LOG_PRINT_GREEN("[Support SSL]: YES", LOG_LEVEL_0); + } + else + { +// QMessageBox::question(this, "OpenSSL support disabled.", "OpenSSL support disabled.", +// QMessageBox::Ok); + LOG_PRINT_RED("[Support SSL]: NO", LOG_LEVEL_0); + } + + //---- + this->setContextMenuPolicy(Qt::ContextMenuPolicy::NoContextMenu); + m_view->setContextMenuPolicy(Qt::ContextMenuPolicy::NoContextMenu); + + return true; +} + +void MainWindow::on_menu_show() +{ + qDebug() << "Context menu: show()"; + this->show(); + this->activateWindow(); +} + +void MainWindow::init_tray_icon(const std::string& htmlPath) +{ + if (!QSystemTrayIcon::isSystemTrayAvailable()) + { + LOG_PRINT_L0("System tray is unavailable"); + return; + } + + + m_restore_action = std::unique_ptr(new QAction(tr("&Restore"), this)); + connect(m_restore_action.get(), SIGNAL(triggered()), this, SLOT(on_menu_show())); + + m_quit_action = std::unique_ptr(new QAction(tr("&Quit"), this)); + connect(m_quit_action.get(), SIGNAL(triggered()), this, SLOT(tray_quit_requested())); + + m_minimize_action = std::unique_ptr(new QAction(tr("minimizeAction"), this)); + connect(m_minimize_action.get(), SIGNAL(triggered()), this, SLOT(showMinimized())); + + m_tray_icon_menu = std::unique_ptr(new QMenu(this)); + m_tray_icon_menu->addAction(m_minimize_action.get()); + //m_tray_icon_menu->addAction(m_restore_action.get()); + m_tray_icon_menu->addSeparator(); + m_tray_icon_menu->addAction(m_quit_action.get()); + + m_tray_icon = std::unique_ptr(new QSystemTrayIcon(this)); + m_tray_icon->setContextMenu(m_tray_icon_menu.get()); + + //setup icon +#ifdef TARGET_OS_MAC + m_normal_icon_path = htmlPath + "/files/app22macos.png"; // X11 tray icon size is 22x22 + m_blocked_icon_path = htmlPath + "/files/app22macos_blocked.png"; // X11 tray icon size is 22x22 +#else + m_normal_icon_path = htmlPath + "/files/app22windows.png"; // X11 tray icon size is 22x22 + m_blocked_icon_path = htmlPath + "/files/app22windows_blocked.png"; // X11 tray icon size +#endif + //setWindowIcon(QIcon(iconPath.c_str())); + QIcon qi(m_normal_icon_path.c_str()); + qi.setIsMask(true); + m_tray_icon->setIcon(qi); + m_tray_icon->setToolTip(CURRENCY_NAME_BASE); + connect(m_tray_icon.get(), SIGNAL(activated(QSystemTrayIcon::ActivationReason)), + this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason))); + m_tray_icon->show(); +} + +void MainWindow::bool_toggle_icon(const QString& param) +{ + std::string path; + + if (param == "blocked") + path = m_blocked_icon_path; + else + path = m_normal_icon_path; + + QIcon qi(path.c_str()); + qi.setIsMask(true); + m_tray_icon->setIcon(qi); +} + +QString MainWindow::get_log_file() +{ + std::string buff; + epee::file_io_utils::load_last_n_from_file_to_string(log_space::log_singletone::get_actual_log_file_path(), 1000000, buff); + return QString::fromStdString(buff); +} + +void MainWindow::store_window_pos() +{ + QPoint pos = this->pos(); + QSize sz = this->size(); + m_config.m_window_position.first = pos.x(); + m_config.m_window_position.second = pos.y(); + m_config.m_window_size.first = sz.height(); + m_config.m_window_size.second = sz.width(); + +} +void MainWindow::store_pos(bool consider_showed) +{ + m_config.is_maximazed = this->isMaximized(); + //here position supposed to be filled from last unserialize or filled on maximize handler + if (!m_config.is_maximazed) + store_window_pos(); + if (consider_showed) + m_config.is_showed = this->isVisible(); + +} +void MainWindow::restore_pos(bool consider_showed) +{ + if (m_config.is_maximazed) + { + this->setWindowState(windowState() | Qt::WindowMaximized); + } + else + { + + QPoint pos; + QSize sz; + pos.setX(m_config.m_window_position.first); + pos.setY(m_config.m_window_position.second); + sz.setHeight(m_config.m_window_size.first); + sz.setWidth(m_config.m_window_size.second); + this->move(pos); + this->resize(sz); + } + + if (consider_showed) + { + if (m_config.is_showed) + this->showNormal(); + else + this->showMinimized(); + } + +} +void MainWindow::trayIconActivated(QSystemTrayIcon::ActivationReason reason) +{ + if (reason == QSystemTrayIcon::ActivationReason::Trigger) + { + if ( !(this->windowState() & Qt::WindowMinimized)) + { + showMinimized(); + } + else + { + showNormal(); + activateWindow(); + } + + + } +} + +void MainWindow::load_file(const QString &fileName) +{ + LOG_PRINT_L0("Loading html from path: " << fileName.toStdString()); + m_view->load(QUrl::fromLocalFile(QFileInfo(fileName).absoluteFilePath())); +} + +QString MainWindow::set_clipboard(const QString& param) +{ + LOG_API_TIMING(); + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setText(param); + return "OK"; +} + +QString MainWindow::get_clipboard() +{ + LOG_API_TIMING(); + QClipboard *clipboard = QApplication::clipboard(); + return clipboard->text(); +} + +QString MainWindow::on_request_quit() +{ + LOG_PRINT_MAGENTA("[HTML]->[GUI] on_request_quit", LOG_LEVEL_0); + m_gui_deinitialize_done_1 = true; + m_backend.send_stop_signal(); + + return "OK"; +} + +bool MainWindow::do_close() +{ + this->close(); + return true; +} + +bool MainWindow::show_inital() +{ + if (load_app_config()) + restore_pos(true); + else + { + this->show(); + QSize sz; + sz.setHeight(770); + sz.setWidth(1200); + this->resize(sz); + store_window_pos(); + m_config.is_maximazed = false; + m_config.is_showed = true; + } + return true; +} + +bool MainWindow::on_backend_stopped() +{ + LOG_PRINT_L0("[BACKEND]->[GUI] on_backend_stopped"); + m_backend_stopped_2 = true; + //m_deinitialize_done = true; +// if (m_quit_requested) +// { + + /*bool r = */QMetaObject::invokeMethod(this, "do_close", Qt::QueuedConnection); +// } + return true; +} + +bool MainWindow::update_daemon_status(const view::daemon_status_info& info) +{ + //this->update_daemon_state(info); + std::string json_str; + epee::serialization::store_t_to_json(info, json_str); + + //lifehack + if (m_last_update_daemon_status_json == json_str) + return true; + + LOG_PRINT_L0("SENDING SIGNAL -> [update_daemon_state] " << info.daemon_network_state); + //this->update_daemon_state(json_str.c_str()); + QMetaObject::invokeMethod(this, "update_daemon_state", Qt::QueuedConnection, Q_ARG(QString, json_str.c_str())); + m_last_update_daemon_status_json = json_str; + return true; +} + + +bool MainWindow::show_msg_box(const std::string& message) +{ + QMessageBox::information(this, "Error", message.c_str(), QMessageBox::Ok); + return true; +} +bool MainWindow::init_backend(int argc, char* argv[]) +{ + return m_backend.init(argc, argv, this); +} + +QString MainWindow::is_remnotenode_mode_preconfigured() +{ + return m_backend.is_remote_node_mode() ? "TRUE":"FALSE"; +} + +QString MainWindow::start_backend(const QString& params) +{ + view::start_backend_params sbp = AUTO_VAL_INIT(sbp); + view::api_response ar = AUTO_VAL_INIT(ar); + + if (!epee::serialization::load_t_from_json(sbp, params.toStdString())) + { + ar.error_code = API_RETURN_CODE_BAD_ARG; + return MAKE_RESPONSE(ar); + } + if (sbp.configure_for_remote_node) + { + //@#@ + sbp.remote_node_host = "88.198.50.112"; + sbp.remote_node_port = 11512; + + bool r = m_backend.configure_for_remote_node(sbp.remote_node_host + ":" + std::to_string(sbp.remote_node_port)); + if (!r) + { + ar.error_code = API_RETURN_CODE_BAD_ARG; + return MAKE_RESPONSE(ar); + } + } + + bool r = m_backend.start(); + if (!r) + { + ar.error_code = API_RETURN_CODE_INTERNAL_ERROR; + return MAKE_RESPONSE(ar); + } + ar.error_code = API_RETURN_CODE_OK; + return MAKE_RESPONSE(ar); +} + +bool MainWindow::update_wallet_status(const view::wallet_status_info& wsi) +{ + m_wallet_states->operator [](wsi.wallet_id) = wsi.wallet_state; + std::string json_str; + epee::serialization::store_t_to_json(wsi, json_str); + LOG_PRINT_L0("SENDING SIGNAL -> [update_wallet_status]:" << std::endl << json_str ); + QMetaObject::invokeMethod(this, "update_wallet_status", Qt::QueuedConnection, Q_ARG(QString, json_str.c_str())); + return true; +} +bool MainWindow::set_options(const view::gui_options& opt) +{ + std::string json_str; + epee::serialization::store_t_to_json(opt, json_str); + LOG_PRINT_L0("SENDING SIGNAL -> [set_options]:" << std::endl << json_str); + QMetaObject::invokeMethod(this, "set_options", Qt::QueuedConnection, Q_ARG(QString, json_str.c_str())); + return true; +} + +bool MainWindow::nativeEventFilter(const QByteArray &eventType, void *message, long *result) +{ +#ifdef WIN32 + MSG *msg = static_cast< MSG * >(message); + if (msg->message == WM_QUERYENDSESSION) + { + m_system_shutdown = true; + LOG_PRINT_MAGENTA("SYSTEM SHUTDOWN", LOG_LEVEL_0); + } +#endif + return false; +} + + + +bool MainWindow::update_wallets_info(const view::wallets_summary_info& wsi) +{ + std::string json_str; + epee::serialization::store_t_to_json(wsi, json_str); + LOG_PRINT_L0("SENDING SIGNAL -> [update_wallets_info]"<< std::endl << json_str ); + + QMetaObject::invokeMethod(this, "update_wallets_info", Qt::QueuedConnection, Q_ARG(QString, json_str.c_str())); + return true; +} + +bool MainWindow::money_transfer(const view::transfer_event_info& tei) +{ + std::string json_str; + epee::serialization::store_t_to_json(tei, json_str); + + LOG_PRINT_L0("SENDING SIGNAL -> [money_transfer]" << std::endl << json_str); + //this->money_transfer(json_str.c_str()); + QMetaObject::invokeMethod(this, "money_transfer", Qt::QueuedConnection, Q_ARG(QString, json_str.c_str())); + if (!m_tray_icon) + return true; + if (!tei.ti.is_income) + return true; + if (!tei.ti.amount) + return true; +// if (tei.ti.is_mining && m_wallet_states->operator [](tei.wallet_id) != view::wallet_status_info::wallet_state_ready) +// return true; + +//don't show unconfirmed tx + if (tei.ti.height == 0) + return true; + + auto amount_str = currency::print_money(tei.ti.amount); + std::string title, msg; + if (tei.ti.height == 0) // unconfirmed trx + { + msg = amount_str + " " + CURRENCY_NAME_ABR + " " + m_localization[localization_id_is_received]; + title = m_localization[localization_id_income_transfer_unconfirmed]; + } + else + { + msg = amount_str + " " + CURRENCY_NAME_ABR + " " + m_localization[localization_id_is_confirmed]; + title = m_localization[localization_id_income_transfer_confirmed]; + } + if (tei.ti.is_mining) + msg += m_localization[localization_id_mined]; + else if (tei.ti.unlock_time) + msg += m_localization[localization_id_locked]; + + show_notification(title, msg); + + return true; +} + +bool MainWindow::money_transfer_cancel(const view::transfer_event_info& tei) +{ + std::string json_str; + epee::serialization::store_t_to_json(tei, json_str); + + LOG_PRINT_L0("SENDING SIGNAL -> [money_transfer_cancel]"); + //this->money_transfer_cancel(json_str.c_str()); + QMetaObject::invokeMethod(this, "money_transfer_cancel", Qt::QueuedConnection, Q_ARG(QString, json_str.c_str())); + + return true; + +} +bool MainWindow::wallet_sync_progress(const view::wallet_sync_progres_param& p) +{ + LOG_PRINT_L2("SENDING SIGNAL -> [wallet_sync_progress]" << " wallet_id: " << p.wallet_id << ": " << p.progress << "%"); + //this->wallet_sync_progress(epee::serialization::store_t_to_json(p).c_str()); + QMetaObject::invokeMethod(this, "wallet_sync_progress", Qt::QueuedConnection, Q_ARG(QString, epee::serialization::store_t_to_json(p).c_str())); + return true; +} + +bool MainWindow::set_html_path(const std::string& path) +{ + //init_tray_icon(path); +#ifdef _MSC_VER + load_file(std::string(path + "/index.html").c_str()); +#else +// load_file(QString((std::string("file://") + path + "/index.html").c_str())); + load_file(QString((std::string("") + path + "/index.html").c_str())); +#endif + return true; +} +bool MainWindow::pos_block_found(const currency::block& block_found) +{ + std::stringstream ss; + ss << "Found Block h = " << currency::get_block_height(block_found); + LOG_PRINT_L0("SENDING SIGNAL -> [update_pos_mining_text]"); + //this->update_pos_mining_text(ss.str().c_str()); + QMetaObject::invokeMethod(this, "update_pos_mining_text", Qt::QueuedConnection, Q_ARG(QString, ss.str().c_str())); + return true; +} + +QString MainWindow::get_version() +{ + return PROJECT_VERSION_LONG; +} + +QString MainWindow::get_os_version() +{ + return tools::get_os_version_string().c_str(); +} + +QString MainWindow::get_alias_coast(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::struct_with_one_t_type, lvl); + view::get_alias_coast_response resp; + resp.error_code = m_backend.get_alias_coast(lvl.v, resp.coast); + return epee::serialization::store_t_to_json(resp).c_str(); +} + +QString MainWindow::set_localization_strings(const QString param) +{ + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::set_localization_request, lr); + view::api_response resp; + + if (lr.strings.size() < localization_id_couter) + { + LOG_ERROR("Wrong localization size: " << lr.strings.size() << ", expected size at least " << localization_id_couter); + resp.error_code = API_RETURN_CODE_FAIL; + } + else + { + m_localization = lr.strings; + m_quit_action->setText(QString().fromUtf8(m_localization[localization_id_quit].c_str())); + m_restore_action->setText(QString().fromUtf8(m_localization[localization_id_tray_menu_show].c_str())); + m_minimize_action->setText(QString().fromUtf8(m_localization[localization_id_tray_menu_minimize].c_str())); + resp.error_code = API_RETURN_CODE_OK; + LOG_PRINT_L0("New localization set, language title: " << lr.language_title << ", strings " << lr.strings.size()); + } + return epee::serialization::store_t_to_json(resp).c_str(); +} + +QString MainWindow::request_alias_registration(const QString& param) +{ + LOG_API_TIMING(); + //return que_call2("request_alias_registration", param, [this](const view::request_alias_param& tp, view::api_response& ar){ + PREPARE_ARG_FROM_JSON(view::request_alias_param, tp); + PREPARE_RESPONSE(view::transfer_response, ar); + + // view::transfer_response tr = AUTO_VAL_INIT(tr); + currency::transaction res_tx = AUTO_VAL_INIT(res_tx); + ar.error_code = m_backend.request_alias_registration(tp.alias, tp.wallet_id, tp.fee, res_tx, tp.reward); + if (ar.error_code != API_RETURN_CODE_OK) + return MAKE_RESPONSE(ar); + + + ar.response_data.success = true; + ar.response_data.tx_hash = string_tools::pod_to_hex(currency::get_transaction_hash(res_tx)); + ar.response_data.tx_blob_size = currency::get_object_blobsize(res_tx); + ar.error_code = API_RETURN_CODE_OK; + return MAKE_RESPONSE(ar); +} +QString MainWindow::request_alias_update(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::request_alias_param, tp); + PREPARE_RESPONSE(view::transfer_response, ar); + + // view::transfer_response tr = AUTO_VAL_INIT(tr); + currency::transaction res_tx = AUTO_VAL_INIT(res_tx); + ar.error_code = m_backend.request_alias_update(tp.alias, tp.wallet_id, tp.fee, res_tx, tp.reward); + if (ar.error_code != API_RETURN_CODE_OK) + return MAKE_RESPONSE(ar); + + + ar.response_data.success = true; + ar.response_data.tx_hash = string_tools::pod_to_hex(currency::get_transaction_hash(res_tx)); + ar.response_data.tx_blob_size = currency::get_object_blobsize(res_tx); + ar.error_code = API_RETURN_CODE_OK; + return MAKE_RESPONSE(ar); +} +QString MainWindow::transfer(const QString& param) +{ + LOG_API_TIMING(); + //return que_call2("transfer", json_transfer_object, [this](const view::transfer_params& tp, view::api_response& ar){ + PREPARE_ARG_FROM_JSON(view::transfer_params, tp); + PREPARE_RESPONSE(view::transfer_response, ar); + + if (!tp.destinations.size()) + { + ar.error_code = API_RETURN_CODE_BAD_ARG; + return MAKE_RESPONSE(ar); + } + + currency::transaction res_tx = AUTO_VAL_INIT(res_tx); + ar.error_code = m_backend.transfer(tp.wallet_id, tp, res_tx); + if (ar.error_code != API_RETURN_CODE_OK) + return MAKE_RESPONSE(ar); + + ar.response_data.success = true; + ar.response_data.tx_hash = string_tools::pod_to_hex(currency::get_transaction_hash(res_tx)); + ar.response_data.tx_blob_size = currency::get_object_blobsize(res_tx); + return MAKE_RESPONSE(ar); +} + +void MainWindow::message_box(const QString& msg) +{ + show_msg_box(msg.toStdString()); +} + +struct serialize_variant_visitor : public boost::static_visitor +{ + template + std::string operator()(const t_type& v) const + { + return epee::serialization::store_t_to_json(v); + } +}; + +template +std::string serialize_variant(const t_variant& v) +{ + return boost::apply_visitor(serialize_variant_visitor(), v); +} + + +void MainWindow::on_core_event(const std::string event_name, const currency::core_event_v& e) +{ + //at the moment we don't forward CORE_EVENT_BLOCK_ADDEDevent to GUI + if (CORE_EVENT_BLOCK_ADDED == event_name) + return; + + m_events.m_que.push_back(currency::core_event()); + m_events.m_que.back().details = currency::core_event_v(e); + m_events.m_que.back().method = event_name; +} + +std::string get_events_que_json_string(const std::list& eq, std::string& methods_list) +{ + //t the moment portable_storage is not supporting polymorphic objects lists, so + //there is no hope to make serialization with variant list, lets handle it manual + std::stringstream ss; + ss << "{ \"events\" : ["; + uint64_t need_coma = false; + for (const auto& e : eq) + { + if (need_coma) + { + ss << ","; + methods_list += "|"; + } + methods_list += e.method; + ss << "{ \"method\": \"" << e.method << "\"," << ENDL; + ss << "\"details\": " << serialize_variant(e.details) << ENDL << "}"; + need_coma = true; + } + ss << "]}"; + return ss.str(); +} + +void MainWindow::on_complete_events() +{ + if (m_events.m_que.size()) + { + std::string methods_list; + TIME_MEASURE_START_MS(core_events_handl_time); + TIME_MEASURE_START_MS(json_buff_generate_time); + std::string json_buff = get_events_que_json_string(m_events.m_que, methods_list); + TIME_MEASURE_FINISH_MS(json_buff_generate_time); + + + QMetaObject::invokeMethod(this, "on_core_event", + Qt::QueuedConnection, + Q_ARG(QString, QString(json_buff.c_str()))); + TIME_MEASURE_FINISH_MS(core_events_handl_time); + LOG_PRINT_L0("SENT SIGNAL -> [CORE_EVENTS]: " << m_events.m_que.size() + << ", handle_time: " << core_events_handl_time << "(json: " << json_buff_generate_time << ")ms, json_buff size = " << json_buff.size() << ", methods: " << methods_list); + LOG_PRINT_L2("CORE_EVENTS sent signal details: " << ENDL << json_buff); + m_events.m_que.clear(); + + } +} +void MainWindow::on_clear_events() +{ + m_events.m_que.clear(); +} + +QString MainWindow::get_secure_app_data(const QString& param) +{ + LOG_API_TIMING(); + view::password_data pwd = AUTO_VAL_INIT(pwd); + + if (!epee::serialization::load_t_from_json(pwd, param.toStdString())) + { + view::api_response ar; + ar.error_code = API_RETURN_CODE_BAD_ARG; + return MAKE_RESPONSE(ar); + } + + std::string app_data_buff; + bool r = file_io_utils::load_file_to_string(m_backend.get_config_folder() + "/" + GUI_SECURE_CONFIG_FILENAME, app_data_buff); + if (!r) + return ""; + + if (app_data_buff.size() < sizeof(app_data_file_binary_header)) + { + LOG_ERROR("app_data_buff.size() < sizeof(app_data_file_binary_header) check failed"); + view::api_response ar; + ar.error_code = API_RETURN_CODE_FAIL; + return MAKE_RESPONSE(ar); + } + + crypto::chacha_crypt(app_data_buff, pwd.pass); + + const app_data_file_binary_header* phdr = reinterpret_cast(app_data_buff.data()); + if (phdr->m_signature != APP_DATA_FILE_BINARY_SIGNATURE) + { + LOG_ERROR("password missmatch: provided pass: " << pwd.pass); + view::api_response ar; + ar.error_code = API_RETURN_CODE_WRONG_PASSWORD; + return MAKE_RESPONSE(ar); + } + + return app_data_buff.substr(sizeof(app_data_file_binary_header)).c_str(); +} + +QString MainWindow::store_app_data(const QString& param) +{ + LOG_API_TIMING(); + view::api_response ar; + ar.error_code = API_RETURN_CODE_FAIL; + if (!tools::create_directories_if_necessary(m_backend.get_config_folder())) + { + LOG_PRINT_L0("Failed to create data directory: " << m_backend.get_config_folder()); + return MAKE_RESPONSE(ar); + } + + //bool r = file_io_utils::save_string_to_file(m_backend.get_config_folder() + "/" + GUI_CONFIG_FILENAME, param.toStdString()); + bool r = file_io_utils::save_string_to_file(m_backend.get_config_folder() + "/" + GUI_CONFIG_FILENAME, param.toStdString()); + //view::api_response ar; + if (r) + ar.error_code = API_RETURN_CODE_OK; + else + ar.error_code = API_RETURN_CODE_FAIL; + + //ar.error_code = store_to_file((m_backend.get_config_folder() + "/" + GUI_CONFIG_FILENAME).c_str(), param).toStdString(); + return MAKE_RESPONSE(ar); +} +QString MainWindow::is_file_exist(const QString& path) +{ + try{ + bool r = file_io_utils::is_file_exist(path.toStdWString()); + if (r) + return API_RETURN_CODE_ALREADY_EXISTS; + else + return API_RETURN_CODE_FILE_NOT_FOUND; + } + catch (const std::exception& ex) + { + LOG_ERROR("FILED TO STORE TO FILE: " << path.toStdString() << " ERROR:" << ex.what()); + return QString(API_RETURN_CODE_ALREADY_EXISTS) + ": " + ex.what(); + } + + catch (...) + { + return API_RETURN_CODE_ALREADY_EXISTS; + } +} +QString MainWindow::store_to_file(const QString& path, const QString& buff) +{ + try{ + bool r = file_io_utils::save_string_to_file_throw(path.toStdWString(), buff.toStdString()); + if (r) + return API_RETURN_CODE_OK; + else + return API_RETURN_CODE_ACCESS_DENIED; + } + catch (const std::exception& ex) + { + LOG_ERROR("FILED TO STORE TO FILE: " << path.toStdString() << " ERROR:" << ex.what()); + return QString(API_RETURN_CODE_ACCESS_DENIED) + ": " + ex.what(); + } + + catch (...) + { + return API_RETURN_CODE_ACCESS_DENIED; + } + + +} + +QString MainWindow::get_app_data() +{ + LOG_API_TIMING(); + std::string app_data_buff; + file_io_utils::load_file_to_string(m_backend.get_config_folder() + "/" + GUI_CONFIG_FILENAME, app_data_buff); + return app_data_buff.c_str(); +} + +QString MainWindow::store_secure_app_data(const QString& param, const QString& pass) +{ + LOG_API_TIMING(); + if (!tools::create_directories_if_necessary(m_backend.get_config_folder())) + { + view::api_response ar; + LOG_PRINT_L0("Failed to create data directory: " << m_backend.get_config_folder()); + return MAKE_RESPONSE(ar); + } + + std::string buff(sizeof(app_data_file_binary_header), 0); + app_data_file_binary_header* phdr = (app_data_file_binary_header*)buff.data(); + phdr->m_signature = APP_DATA_FILE_BINARY_SIGNATURE; + phdr->m_cb_body = 0; // for future use + + buff.append(param.toStdString()); + crypto::chacha_crypt(buff, pass.toStdString()); + + bool r = file_io_utils::save_string_to_file(m_backend.get_config_folder() + "/" + GUI_SECURE_CONFIG_FILENAME, buff); + view::api_response ar; + if (r) + ar.error_code = API_RETURN_CODE_OK; + else + ar.error_code = API_RETURN_CODE_FAIL; + + return MAKE_RESPONSE(ar); +} + +QString MainWindow::have_secure_app_data() +{ + LOG_API_TIMING(); + view::api_response ar = AUTO_VAL_INIT(ar); + + boost::system::error_code ec; + if (boost::filesystem::exists(m_backend.get_config_folder() + "/" + GUI_SECURE_CONFIG_FILENAME, ec)) + ar.error_code = API_RETURN_CODE_TRUE; + else + ar.error_code = API_RETURN_CODE_FALSE; + + return MAKE_RESPONSE(ar); +} +QString MainWindow::drop_secure_app_data() +{ + LOG_API_TIMING(); + view::api_response ar = AUTO_VAL_INIT(ar); + + boost::system::error_code ec; + if (boost::filesystem::remove(m_backend.get_config_folder() + "/" + GUI_SECURE_CONFIG_FILENAME, ec)) + ar.error_code = API_RETURN_CODE_TRUE; + else + ar.error_code = API_RETURN_CODE_FALSE; + return MAKE_RESPONSE(ar); +} +QString MainWindow::get_all_aliases() +{ + LOG_API_TIMING(); + //PREPARE_ARG_FROM_JSON(view::struct_with_one_t_type, param); + PREPARE_RESPONSE(view::alias_set, rsp); + + rsp.error_code = m_backend.get_aliases(rsp.response_data); + QString res = MAKE_RESPONSE(rsp); + LOG_PRINT_GREEN("GET_ALL_ALIASES: res: " << rsp.error_code << ", count: " << rsp.response_data.aliases.size() << ", string buff size: " << res.size(), LOG_LEVEL_1); + return res; +} +QString MainWindow::get_alias_info_by_address(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_RESPONSE(currency::alias_rpc_details, rsp); + rsp.error_code = m_backend.get_alias_info_by_address(param.toStdString(), rsp.response_data); + return MAKE_RESPONSE(rsp); +} +QString MainWindow::get_alias_info_by_name(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_RESPONSE(currency::alias_rpc_details, rsp); + rsp.error_code = m_backend.get_alias_info_by_name(param.toStdString(), rsp.response_data); + return MAKE_RESPONSE(rsp); +} +QString MainWindow::validate_address(const QString& param) +{ + LOG_API_TIMING(); + view::address_validation_response ar = AUTO_VAL_INIT(ar); + ar.error_code = m_backend.validate_address(param.toStdString(), ar.payment_id); + return MAKE_RESPONSE(ar); +} +QString MainWindow::set_log_level(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::struct_with_one_t_type, lvl); + epee::log_space::get_set_log_detalisation_level(true, lvl.v); + default_ar.error_code = API_RETURN_CODE_OK; + LOG_PRINT("[LOG LEVEL]: set to " << lvl.v, LOG_LEVEL_MIN); + + return MAKE_RESPONSE(default_ar); +} +QString MainWindow::get_log_level(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_RESPONSE(view::struct_with_one_t_type, ar); + ar.response_data.v = epee::log_space::get_set_log_detalisation_level(); + ar.error_code = API_RETURN_CODE_OK; + return MAKE_RESPONSE(ar); +} + +// QString MainWindow::dump_all_offers() +// { +// LOG_API_TIMING(); +// //return que_call2("dump_all_offers", "{}", [this](const view::api_void& owd, view::api_response& ar){ +// PREPARE_RESPONSE(view::api_void, ar); +// //view::api_void av; +// QString path = QFileDialog::getOpenFileName(this, "Select file", +// "", +// ""); +// +// if (!path.length()) +// { +// ar.error_code = API_RETURN_CODE_CANCELED; +// return MAKE_RESPONSE(ar); +// } +// +// currency::COMMAND_RPC_GET_ALL_OFFERS::response rp = AUTO_VAL_INIT(rp); +// ar.error_code = m_backend.get_all_offers(rp); +// +// std::string buff = epee::serialization::store_t_to_json(rp); +// bool r = file_io_utils::save_string_to_file(path.toStdString(), buff); +// if (!r) +// ar.error_code = API_RETURN_CODE_FAIL; +// else +// ar.error_code = API_RETURN_CODE_OK; +// +// return MAKE_RESPONSE(ar); +// } + +QString MainWindow::webkit_launched_script() +{ + m_last_update_daemon_status_json.clear(); + return ""; +} +//////////////////// +QString MainWindow::show_openfile_dialog(const QString& param) +{ + view::system_filedialog_request ofdr = AUTO_VAL_INIT(ofdr); + view::system_filedialog_response ofdres = AUTO_VAL_INIT(ofdres); + if (!epee::serialization::load_t_from_json(ofdr, param.toStdString())) + { + ofdres.error_code = API_RETURN_CODE_BAD_ARG; + return epee::serialization::store_t_to_json(ofdres).c_str(); + } + + QString path = QFileDialog::getOpenFileName(this, ofdr.caption.c_str(), + ofdr.default_dir.c_str(), + ofdr.filemask.c_str()); + + if (!path.length()) + { + ofdres.error_code = API_RETURN_CODE_CANCELED; + return epee::serialization::store_t_to_json(ofdres).c_str(); + } + + ofdres.error_code = API_RETURN_CODE_OK; + ofdres.path = path.toStdString(); + return MAKE_RESPONSE(ofdres); +} + + +QString MainWindow::show_savefile_dialog(const QString& param) +{ + PREPARE_ARG_FROM_JSON(view::system_filedialog_request, ofdr); + view::system_filedialog_response ofdres = AUTO_VAL_INIT(ofdres); + + QString path = QFileDialog::getSaveFileName(this, ofdr.caption.c_str(), + ofdr.default_dir.c_str(), + ofdr.filemask.c_str()); + + if (!path.length()) + { + ofdres.error_code = API_RETURN_CODE_CANCELED; + return epee::serialization::store_t_to_json(ofdres).c_str(); + } + + ofdres.error_code = API_RETURN_CODE_OK; + ofdres.path = path.toStdString(); + return MAKE_RESPONSE(ofdres); +} + +QString MainWindow::close_wallet(const QString& param) +{ + LOG_API_TIMING(); + //return que_call2("close_wallet", param, [this](const view::wallet_id_obj& owd, view::api_response& ar){ + PREPARE_ARG_FROM_JSON(view::wallet_id_obj, owd); + PREPARE_RESPONSE(view::api_void, ar); + ar.error_code = m_backend.close_wallet(owd.wallet_id); + + return MAKE_RESPONSE(ar); +} + +QString MainWindow::get_contracts(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::wallet_id_obj, owd); + PREPARE_RESPONSE(view::contracts_array, ar); + ar.error_code = m_backend.get_contracts(owd.wallet_id, ar.response_data.contracts); + + return MAKE_RESPONSE(ar); +} + +QString MainWindow::create_proposal(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::create_proposal_param, cpp); + PREPARE_RESPONSE(view::contracts_array, ar); + ar.error_code = m_backend.create_proposal(cpp.wallet_id, cpp.details, cpp.payment_id, cpp.expiration_period, cpp.fee, cpp.b_fee); + return MAKE_RESPONSE(ar); +} + + + + +QString MainWindow::accept_proposal(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::wallet_and_contract_id_param, waip); + PREPARE_RESPONSE(view::api_void, ar); + + ar.error_code = m_backend.accept_proposal(waip.wallet_id, waip.contract_id); + return MAKE_RESPONSE(ar); +} + +QString MainWindow::release_contract(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::accept_proposal_param, rcp); + PREPARE_RESPONSE(view::api_void, ar); + + ar.error_code = m_backend.release_contract(rcp.wallet_id, rcp.contract_id, rcp.release_type); + + return MAKE_RESPONSE(ar); +} + +QString MainWindow::request_cancel_contract(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::crequest_cancel_contract_param, rcp); + PREPARE_RESPONSE(view::api_void, ar); + + ar.error_code = m_backend.request_cancel_contract(rcp.wallet_id, rcp.contract_id, rcp.fee, rcp.expiration_period); + + return MAKE_RESPONSE(ar); +} + +QString MainWindow::accept_cancel_contract(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::wallet_and_contract_id_param, wci); + PREPARE_RESPONSE(view::api_void, ar); + + ar.error_code = m_backend.accept_cancel_contract(wci.wallet_id, wci.contract_id); + + return MAKE_RESPONSE(ar); + +} + +QString MainWindow::generate_wallet(const QString& param) +{ + LOG_API_TIMING(); + //return que_call2("generate_wallet", param, [this](const view::open_wallet_request& owd, view::api_response& ar){ + PREPARE_ARG_FROM_JSON(view::open_wallet_request, owd); + PREPARE_RESPONSE(view::open_wallet_response, ar); + ar.error_code = m_backend.generate_wallet(epee::string_encoding::utf8_to_wstring(owd.path), owd.pass, ar.response_data); + return MAKE_RESPONSE(ar); +} + + +QString MainWindow::restore_wallet(const QString& param) +{ + LOG_API_TIMING(); + //return que_call2("restore_wallet", param, [this](const view::restore_wallet_request& owd, view::api_response& ar){ + PREPARE_ARG_FROM_JSON(view::restore_wallet_request, owd); + PREPARE_RESPONSE(view::open_wallet_response, ar); + ar.error_code = m_backend.restore_wallet(epee::string_encoding::utf8_to_wstring(owd.path), owd.pass, owd.restore_key, ar.response_data); + return MAKE_RESPONSE(ar); +} +QString MainWindow::open_wallet(const QString& param) +{ + LOG_API_TIMING(); + + //return que_call2("open_wallet", param, [this](const view::open_wallet_request& owd, view::api_response& ar){ + PREPARE_ARG_FROM_JSON(view::open_wallet_request, owd); + PREPARE_RESPONSE(view::open_wallet_response, ar); + ar.error_code = m_backend.open_wallet(epee::string_encoding::utf8_to_wstring(owd.path), owd.pass, ar.response_data); + return MAKE_RESPONSE(ar); +} +QString MainWindow::get_my_offers(const QString& param) +{ + LOG_API_TIMING(); + //return que_call2("open_wallet", param, [this](const view::open_wallet_request& owd, view::api_response& ar){ + PREPARE_ARG_FROM_JSON(bc_services::core_offers_filter, f); + PREPARE_RESPONSE(currency::COMMAND_RPC_GET_ALL_OFFERS::response, ar); + ar.error_code = m_backend.get_my_offers(f, ar.response_data.offers); + return MAKE_RESPONSE(ar); +} +QString MainWindow::get_fav_offers(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::get_fav_offers_request, f); + PREPARE_RESPONSE(currency::COMMAND_RPC_GET_ALL_OFFERS::response, ar); + ar.error_code = m_backend.get_fav_offers(f.ids, f.filter, ar.response_data.offers); + return MAKE_RESPONSE(ar); + +} +QString MainWindow::is_pos_allowed() +{ + LOG_API_TIMING(); + return m_backend.is_pos_allowed().c_str(); +} + +QString MainWindow::run_wallet(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::wallet_id_obj, wio); + + default_ar.error_code = m_backend.run_wallet(wio.wallet_id); + return MAKE_RESPONSE(default_ar); +} + +QString MainWindow::resync_wallet(const QString& param) +{ + LOG_API_TIMING(); + //return que_call2("get_wallet_info", param, [this](const view::wallet_id_obj& a, view::api_response& ar){ + PREPARE_ARG_FROM_JSON(view::wallet_id_obj, a); + PREPARE_RESPONSE(view::api_void, ar); + + ar.error_code = m_backend.resync_wallet(a.wallet_id); + return MAKE_RESPONSE(ar); +} + +// QString MainWindow::get_all_offers(const QString& param) +// { +// LOG_API_TIMING(); +// //return que_call2("get_all_offers", param, [this](const view::api_void& a, view::api_response& ar){ +// // PREPARE_ARG_FROM_JSON(view::api_void, a); +// PREPARE_RESPONSE(currency::COMMAND_RPC_GET_ALL_OFFERS::response, ar); +// ar.error_code = m_backend.get_all_offers(ar.response_data); +// return MAKE_RESPONSE(ar); +// } + + +QString MainWindow::get_offers_ex(const QString& param) +{ + LOG_API_TIMING(); + //return que_call2("get_offers_ex", param, [this](const bc_services::core_offers_filter& f, view::api_response& ar){ + PREPARE_ARG_FROM_JSON(bc_services::core_offers_filter, f); + PREPARE_RESPONSE(currency::COMMAND_RPC_GET_ALL_OFFERS::response, ar); + ar.error_code = m_backend.get_offers_ex(f, ar.response_data.offers, ar.response_data.total_offers); + return MAKE_RESPONSE(ar); +} + +QString MainWindow::push_offer(const QString& param) +{ + LOG_API_TIMING(); + LOG_API_PARAMS(LOG_LEVEL_2); + //return que_call2("push_offer", param, [this](const view::push_offer_param& a, view::api_response& ar){ + PREPARE_ARG_FROM_JSON(view::push_offer_param, a); + PREPARE_RESPONSE(view::transfer_response, ar); + + + currency::transaction res_tx = AUTO_VAL_INIT(res_tx); + + ar.error_code = m_backend.push_offer(a.wallet_id, a.od, res_tx); + if (ar.error_code != API_RETURN_CODE_OK) + return MAKE_RESPONSE(ar); + + ar.response_data.success = true; + ar.response_data.tx_hash = string_tools::pod_to_hex(currency::get_transaction_hash(res_tx)); + ar.response_data.tx_blob_size = currency::get_object_blobsize(res_tx); + ar.error_code = API_RETURN_CODE_OK; + return MAKE_RESPONSE(ar); +} + +QString MainWindow::cancel_offer(const QString& param) +{ + LOG_API_TIMING(); + LOG_API_PARAMS(LOG_LEVEL_2); + // return que_call2("cancel_offer", param, [this](const view::cancel_offer_param& a, view::api_response& ar){ + PREPARE_ARG_FROM_JSON(view::cancel_offer_param, a); + PREPARE_RESPONSE(view::transfer_response, ar); + + currency::transaction res_tx = AUTO_VAL_INIT(res_tx); + + ar.error_code = m_backend.cancel_offer(a, res_tx); + if (ar.error_code != API_RETURN_CODE_OK) + return MAKE_RESPONSE(ar); + + ar.response_data.success = true; + ar.response_data.tx_hash = string_tools::pod_to_hex(currency::get_transaction_hash(res_tx)); + ar.response_data.tx_blob_size = currency::get_object_blobsize(res_tx); + ar.error_code = API_RETURN_CODE_OK; + return MAKE_RESPONSE(ar); +} + +QString MainWindow::push_update_offer(const QString& param) +{ + LOG_API_TIMING(); + LOG_API_PARAMS(LOG_LEVEL_2); + //return que_call2("cancel_offer", param, [this](const bc_services::update_offer_details& a, view::api_response& ar){ + PREPARE_ARG_FROM_JSON(bc_services::update_offer_details, a); + PREPARE_RESPONSE(view::transfer_response, ar); + + currency::transaction res_tx = AUTO_VAL_INIT(res_tx); + + ar.error_code = m_backend.push_update_offer(a, res_tx); + if (ar.error_code != API_RETURN_CODE_OK) + return MAKE_RESPONSE(ar); + + ar.response_data.success = true; + ar.response_data.tx_hash = string_tools::pod_to_hex(currency::get_transaction_hash(res_tx)); + ar.response_data.tx_blob_size = currency::get_object_blobsize(res_tx); + ar.error_code = API_RETURN_CODE_OK; + return MAKE_RESPONSE(ar); +} + +QString MainWindow::get_recent_transfers(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::get_recent_transfers_request, a); + PREPARE_RESPONSE(view::transfers_array, ar); + ar.error_code = m_backend.get_recent_transfers(a.wallet_id, a.offest, a.count, ar.response_data); + return MAKE_RESPONSE(ar); +} + + +QString MainWindow::get_mining_history(const QString& param) +{ + LOG_API_TIMING(); + //return prepare_call("get_mining_history", param, [this](const view::wallet_id_obj& a, view::api_response& ar) { + PREPARE_ARG_FROM_JSON(view::wallet_id_obj, a); + PREPARE_RESPONSE(tools::wallet_rpc::mining_history, ar); + + ar.error_code = m_backend.get_mining_history(a.wallet_id, ar.response_data); + if (ar.error_code != API_RETURN_CODE_OK) + return MAKE_RESPONSE(ar); + + ar.error_code = API_RETURN_CODE_OK; + return MAKE_RESPONSE(ar); +} +QString MainWindow::start_pos_mining(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::wallet_id_obj, wo); + default_ar.error_code = m_backend.start_pos_mining(wo.wallet_id); + return MAKE_RESPONSE(default_ar); +} +QString MainWindow::stop_pos_mining(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::wallet_id_obj, wo); + default_ar.error_code = m_backend.stop_pos_mining(wo.wallet_id); + return MAKE_RESPONSE(default_ar); +} + +QString MainWindow::get_smart_safe_info(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::wallet_id_obj, wo); + PREPARE_RESPONSE(view::get_restore_info_response, ar); + ar.error_code = m_backend.get_wallet_restore_info(wo.wallet_id, ar.response_data.restore_key); + return MAKE_RESPONSE(ar); +} +QString MainWindow::get_mining_estimate(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::request_mining_estimate, me); + PREPARE_RESPONSE(view::response_mining_estimate, ar); + ar.error_code = m_backend.get_mining_estimate(me.amount_coins, me.time, ar.response_data.final_amount, ar.response_data.all_coins_and_pos_diff_rate, ar.response_data.days_estimate); + return MAKE_RESPONSE(ar); +} +QString MainWindow::backup_wallet_keys(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::backup_keys_request, me); + default_ar.error_code = m_backend.backup_wallet(me.wallet_id, epee::string_encoding::utf8_to_wstring(me.path)); + return MAKE_RESPONSE(default_ar); +} +QString MainWindow::reset_wallet_password(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::reset_pass_request, me); + default_ar.error_code = m_backend.reset_wallet_password(me.wallet_id, me.pass); + return MAKE_RESPONSE(default_ar); +} +QString MainWindow::is_wallet_password_valid(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::reset_pass_request, me); + default_ar.error_code = m_backend.is_wallet_password_valid(me.wallet_id, me.pass); + return MAKE_RESPONSE(default_ar); +} + +QString MainWindow::is_autostart_enabled() +{ + LOG_API_TIMING(); + view::api_response ar; + + if (gui_tools::GetStartOnSystemStartup()) + ar.error_code = API_RETURN_CODE_TRUE; + else + ar.error_code = API_RETURN_CODE_FALSE; + + return MAKE_RESPONSE(ar); +} + +QString MainWindow::toggle_autostart(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::struct_with_one_t_type, as); + + if (gui_tools::SetStartOnSystemStartup(as.v)) + default_ar.error_code = API_RETURN_CODE_OK; + else + default_ar.error_code = API_RETURN_CODE_FAIL; + + return MAKE_RESPONSE(default_ar); +} +QString MainWindow::check_available_sources(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::api_request_t >, sources); + return m_backend.check_available_sources(sources.wallet_id, sources.req_data).c_str(); +} + +QString MainWindow::open_url_in_browser(const QString& param) +{ + QString prefix = "https://"; + if (!QDesktopServices::openUrl(QUrl(prefix + param))) + { + LOG_ERROR("Failed top open URL: " << param.toStdString()); + return API_RETURN_CODE_FAIL; + } + LOG_PRINT_L0("[Open URL]: " << param.toStdString()); + return API_RETURN_CODE_OK; +} + + +QString MainWindow::is_valid_restore_wallet_text(const QString& param) +{ + LOG_API_TIMING(); + return m_backend.is_valid_brain_restore_data(param.toStdString()).c_str(); +} +void MainWindow::contextMenuEvent(QContextMenuEvent * event) +{ + +} +QString MainWindow::print_text(const QString& param) +{ + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::print_text_param, ptp); + + //in >> htmlContent; + + QTextDocument *document = new QTextDocument(); + document->setHtml(ptp.html_text.c_str()); + + QPrinter printer; + default_ar.error_code = API_RETURN_CODE_CANCELED; + + QPrintDialog *dialog = new QPrintDialog(&printer, this); + dialog->setOptions(QAbstractPrintDialog::PrintToFile); + auto res = dialog->exec(); + if (res != QDialog::Accepted) + { + LOG_PRINT_L0("[PRINT_TEXT] exec != QDialog::Accepted, res=" << res); + return MAKE_RESPONSE(default_ar); + } + + document->print(&printer); + + delete document; + default_ar.error_code = API_RETURN_CODE_OK; + LOG_PRINT_L0("[PRINT_TEXT] default_ar.error_code = " << default_ar.error_code); + return MAKE_RESPONSE(default_ar); +} + +QString MainWindow::print_log(const QString& param) +{ + PREPARE_ARG_FROM_JSON(view::print_log_params, plp); + + LOG_PRINT("[GUI_LOG]" << plp.msg, plp.log_level); + + default_ar.error_code = API_RETURN_CODE_OK; + return MAKE_RESPONSE(default_ar); +} + +void MainWindow::show_notification(const std::string& title, const std::string& message) +{ + LOG_PRINT_L1("system notification: \"" << title << "\", \"" << message << "\""); + + // it's expected that title and message are utf-8 encoded! + +#if !defined(__APPLE__) + // use Qt tray icon to show messages on Windows and Linux + CHECK_AND_ASSERT_MES(m_tray_icon != nullptr, (void)(0), "m_tray_icon is null!"); + m_tray_icon->showMessage(QString().fromUtf8(title.c_str()), QString().fromUtf8(message.c_str())); +#else + // use native notification system on macOS + notification_helper::show(title, message); +#endif +} + + diff --git a/src/gui/qt-daemon/application/mainwindow.h b/src/gui/qt-daemon/application/mainwindow.h new file mode 100644 index 00000000..432b8a40 --- /dev/null +++ b/src/gui/qt-daemon/application/mainwindow.h @@ -0,0 +1,307 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include + +#include "view_iface.h" +#ifndef Q_MOC_RUN +#include "daemon_backend.h" +#include "currency_core/offers_services_helpers.h" +#endif + +QT_BEGIN_NAMESPACE +class QWebEngineView; +class QLineEdit; +QT_END_NAMESPACE + +#pragma pack(push, 1) +struct app_data_file_binary_header +{ + uint64_t m_signature; + uint64_t m_cb_body; +}; +#pragma pack (pop) +#define APP_DATA_FILE_BINARY_SIGNATURE 0x1000111101101021LL + + +// class MediatorObject : public QObject +// { +// Q_OBJECT +// +// public: +// +// signals : +// /*! +// This signal is emitted from the C++ side and the text displayed on the HTML client side. +// */ +// void from_c_to_html(const QString &text); +// +// public slots: +// /*! +// This slot is invoked from the HTML client side and the text displayed on the server side. +// */ +// void from_html_to_c(const QString &text); +// }; + +// +class MainWindow : public QMainWindow, + public currency::i_core_event_handler, + public view::i_view, + public QAbstractNativeEventFilter +{ + Q_OBJECT + +public: + MainWindow(); + ~MainWindow(); + + bool init_backend(int argc, char* argv[]); + bool show_inital(); + void show_notification(const std::string& title, const std::string& message); + + struct app_config + { + std::pair m_window_position; + std::pair m_window_size; + bool is_maximazed; + bool is_showed; + }; + + protected slots: + + void on_load_finished(bool ok); + bool do_close(); + + + public slots: + QString show_openfile_dialog(const QString& param); + QString show_savefile_dialog(const QString& param); + QString open_wallet(const QString& param); + QString get_my_offers(const QString& param); + QString get_fav_offers(const QString& param); + QString generate_wallet(const QString& param); + QString run_wallet(const QString& param); + QString close_wallet(const QString& wallet_id); + QString get_contracts(const QString& wallet_id); + QString create_proposal(const QString& param); + QString accept_proposal(const QString& param); + QString release_contract(const QString& param); + QString request_cancel_contract(const QString& param); + QString accept_cancel_contract(const QString& param); + + + QString get_version(); + QString get_os_version(); + QString transfer(const QString& json_transfer_object); + QString have_secure_app_data(); + QString drop_secure_app_data(); + QString get_secure_app_data(const QString& param); + QString store_secure_app_data(const QString& param, const QString& pass); + QString get_app_data(); + QString store_app_data(const QString& param); + QString get_default_user_dir(const QString& param); +// QString get_all_offers(const QString& param); + QString get_offers_ex(const QString& param); + QString push_offer(const QString& param); + QString cancel_offer(const QString& param); + QString push_update_offer(const QString& param); + QString get_alias_info_by_address(const QString& param); + QString get_alias_info_by_name(const QString& param); + QString get_all_aliases(); + QString request_alias_registration(const QString& param); + QString request_alias_update(const QString& param); + QString get_alias_coast(const QString& param); + QString validate_address(const QString& param); + QString on_request_quit(); + QString resync_wallet(const QString& param); + QString get_recent_transfers(const QString& param); + QString get_mining_history(const QString& param); + QString start_pos_mining(const QString& param); + QString stop_pos_mining(const QString& param); + QString set_log_level(const QString& param); + QString get_log_level(const QString& param); +// QString dump_all_offers(); + QString webkit_launched_script(); + QString get_smart_safe_info(const QString& param); + QString restore_wallet(const QString& param); + QString is_pos_allowed(); + QString store_to_file(const QString& path, const QString& buff); + QString is_file_exist(const QString& path); + QString get_mining_estimate(const QString& obj); + QString backup_wallet_keys(const QString& obj); + QString reset_wallet_password(const QString& param); + QString is_wallet_password_valid(const QString& param); + QString is_autostart_enabled(); + QString toggle_autostart(const QString& param); + QString is_valid_restore_wallet_text(const QString& param); + QString print_text(const QString& param); + QString print_log(const QString& param); + QString set_clipboard(const QString& param); + QString set_localization_strings(const QString str); + QString get_clipboard(); + void message_box(const QString& msg); + bool toggle_mining(); + QString get_exchange_last_top(const QString& params); + QString get_tx_pool_info(); + QString get_default_fee(); + QString get_options(); + void bool_toggle_icon(const QString& param); + QString get_log_file(); + QString check_available_sources(const QString& param); + QString open_url_in_browser(const QString& param); + + void trayIconActivated(QSystemTrayIcon::ActivationReason reason); + void tray_quit_requested(); + void on_menu_show(); + QString is_remnotenode_mode_preconfigured(); + QString start_backend(const QString& params); + +signals: + void quit_requested(const QString str); + void update_daemon_state(const QString str); + void update_wallet_status(const QString str); + void update_wallet_info(const QString str); + void money_transfer(const QString str); + void money_transfer_cancel(const QString str); + void wallet_sync_progress(const QString str); + void handle_internal_callback(const QString str, const QString callback_name); + void update_pos_mining_text(const QString str); + void do_dispatch(const QString status, const QString params); //general function + void on_core_event(const QString method_name); //general function + void set_options(const QString str); //general function + +private: + //-------------------- i_core_event_handler -------------------- + virtual void on_core_event(const std::string event_name, const currency::core_event_v& e); + virtual void on_complete_events(); + virtual void on_clear_events(); + + //------- i_view --------- + virtual bool update_daemon_status(const view::daemon_status_info& info); + virtual bool on_backend_stopped(); + virtual bool show_msg_box(const std::string& message); + virtual bool update_wallet_status(const view::wallet_status_info& wsi); + virtual bool update_wallets_info(const view::wallets_summary_info& wsi); + virtual bool money_transfer(const view::transfer_event_info& tei); + virtual bool wallet_sync_progress(const view::wallet_sync_progres_param& p); + virtual bool money_transfer_cancel(const view::transfer_event_info& wsi); + virtual bool init(const std::string& path); + virtual bool pos_block_found(const currency::block& block_found); + virtual bool set_options(const view::gui_options& opt); + //--------- QAbstractNativeEventFilter --------------------------- + virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *result); + //---------------------------------------------- + + + void closeEvent(QCloseEvent *event); + void contextMenuEvent(QContextMenuEvent * event); + void changeEvent(QEvent *e); + void on_maximized(); + + //void setOrientation(Qt::ScreenOrientation orientation); + + + + void init_tray_icon(const std::string& htmlPath); + bool set_html_path(const std::string& path); + void load_file(const QString &fileName); + void store_pos(bool consider_showed = false); + void store_window_pos(); + void restore_pos(bool consider_showed = false); + bool store_app_config(); + bool load_app_config(); + + + + //MediatorObject mo; + // UI + QWebEngineView *m_view; + QWebChannel* m_channel; + + // DATA + daemon_backend m_backend; + //std::atomic m_quit_requested; + std::atomic m_gui_deinitialize_done_1; + std::atomic m_backend_stopped_2; + std::atomic m_system_shutdown; + + + + app_config m_config; + + epee::locked_object> m_wallet_states; + struct events_que_struct + { + std::list m_que; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(m_que) + END_KV_SERIALIZE_MAP() + }; + events_que_struct m_events; + + std::vector m_localization; + + enum localization_string_indices + { + // order is surprizingly important here! (see also updateLocalisation in AppController.js) + localization_id_quit = 0, + localization_id_is_received, + localization_id_is_confirmed, + localization_id_income_transfer_unconfirmed, + localization_id_income_transfer_confirmed, + localization_id_mined, + localization_id_locked, + localization_id_minimized_text, + localization_id_minimized_title, + localization_id_tray_menu_show, + localization_id_tray_menu_minimize, + + localization_id_couter // keep it at the end of list + }; + + std::string m_normal_icon_path; + std::string m_blocked_icon_path; + + std::unique_ptr m_tray_icon; + std::unique_ptr m_tray_icon_menu; + std::unique_ptr m_restore_action; + std::unique_ptr m_quit_action; + std::unique_ptr m_minimize_action; + + std::string m_last_update_daemon_status_json; + + template + QString prepare_call(const char* name, const QString& param, callback_t cb) + { + LOG_PRINT_L0("que_call: [" << name << "]"); + view::api_response_t ar; + argument_type wio = AUTO_VAL_INIT(wio); + if (!epee::serialization::load_t_from_json(wio, param.toStdString())) + { + ar.error_code = API_RETURN_CODE_BAD_ARG; + return epee::serialization::store_t_to_json(ar).c_str(); + } + cb(wio, ar); + return epee::serialization::store_t_to_json(ar).c_str(); + } +}; + +namespace boost +{ + namespace serialization + { + template + void serialize(archive_t & ar, MainWindow::app_config& ac, const unsigned int version) + { + ar & ac.is_maximazed; + ar & ac.is_showed; + ar & ac.m_window_position; + ar & ac.m_window_size; + } + } +} diff --git a/src/gui/qt-daemon/application/notification_helper.h b/src/gui/qt-daemon/application/notification_helper.h new file mode 100644 index 00000000..c00ccc88 --- /dev/null +++ b/src/gui/qt-daemon/application/notification_helper.h @@ -0,0 +1,21 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + + +#pragma once +#include +#include "epee/include/misc_log_ex.h" + +struct notification_helper +{ + static void show(const std::string& title, const std::string& message) +#if !defined(__APPLE__) + { + // just a stub, implemented for macOS only, see .mm + LOG_PRINT_RED("system notifications are supported only for macOS!", LOG_LEVEL_0); + } +#endif + ; +}; diff --git a/src/gui/qt-daemon/application/notification_helper.mm b/src/gui/qt-daemon/application/notification_helper.mm new file mode 100644 index 00000000..0c2a51f5 --- /dev/null +++ b/src/gui/qt-daemon/application/notification_helper.mm @@ -0,0 +1,14 @@ +#include "notification_helper.h" +#include +#include + +void notification_helper::show(const std::string& title, const std::string& message) +{ + NSUserNotification *userNotification = [[[NSUserNotification alloc] init] autorelease]; + userNotification.title = [NSString stringWithUTF8String:title.c_str()]; + userNotification.informativeText = [NSString stringWithUTF8String:message.c_str()]; + + NSUserNotificationCenter* center = [NSUserNotificationCenter defaultUserNotificationCenter]; + [center deliverNotification:userNotification]; +} + diff --git a/src/gui/qt-daemon/application/view_iface.h b/src/gui/qt-daemon/application/view_iface.h new file mode 100644 index 00000000..3a20ccf4 --- /dev/null +++ b/src/gui/qt-daemon/application/view_iface.h @@ -0,0 +1,788 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include +#ifndef Q_MOC_RUN +#include "warnings.h" + +PUSH_WARNINGS +DISABLE_VS_WARNINGS(4100) +DISABLE_VS_WARNINGS(4503) +#include "serialization/keyvalue_serialization.h" +#include "storages/portable_storage_template_helper.h" +#include "rpc/core_rpc_server_commands_defs.h" +#include "wallet/wallet_rpc_server_commans_defs.h" +#include "currency_core/offers_services_helpers.h" +#include "currency_core/basic_api_response_codes.h" +POP_WARNINGS + +#endif + +namespace view +{ + + /*slots structures*/ + struct transfer_destination + { + std::string address; + std::string amount; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(address) + KV_SERIALIZE(amount) + END_KV_SERIALIZE_MAP() + }; + + struct transfer_params + { + uint64_t wallet_id; + std::list destinations; + uint64_t mixin_count; + uint64_t lock_time; + std::string payment_id; + std::string comment; + uint64_t fee; + bool push_payer; + bool hide_receiver; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(wallet_id) + KV_SERIALIZE(destinations) + KV_SERIALIZE(mixin_count) + KV_SERIALIZE(lock_time) + KV_SERIALIZE(payment_id) + KV_SERIALIZE(comment) + KV_SERIALIZE(fee) + KV_SERIALIZE(push_payer) + KV_SERIALIZE(hide_receiver) + END_KV_SERIALIZE_MAP() + }; + + struct transfer_response + { + bool success; + std::string tx_hash; + uint64_t tx_blob_size; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(success) + KV_SERIALIZE(tx_hash) + KV_SERIALIZE(tx_blob_size) + END_KV_SERIALIZE_MAP() + }; + + + enum ui_last_build_displaymode + { + ui_lb_dm_actual = 0, + ui_lb_dm_new = 1, + ui_lb_dm_new_alert_calm = 2, + ui_lb_dm_new_alert_urgent = 3, + ui_lb_dm_new_alert_critical = 4 + }; + + + + + struct block_info + { + uint64_t date; + uint64_t h; + std::string type; + std::string diff; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(date) + KV_SERIALIZE(h) + KV_SERIALIZE(type) + KV_SERIALIZE(diff) + END_KV_SERIALIZE_MAP() + }; + + + struct switch_view_info + { + enum ui_views + { + ui_view_dashboard = 1, + ui_view_wallet = 2 + }; + + int view; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(view) + END_KV_SERIALIZE_MAP() + }; + + /*signal structures*/ + struct daemon_status_info + { +public: + + uint64_t daemon_network_state; + uint64_t synchronization_start_height; + uint64_t max_net_seen_height; + uint64_t height; + uint64_t out_connections_count; + uint64_t inc_connections_count; + int64_t net_time_delta_median; + int64_t synchronized_connections_count; + std::string pos_difficulty; + std::string pow_difficulty; + uint64_t hashrate; + uint64_t last_build_displaymode; + uint64_t alias_count; + std::string last_build_available; + //std::list last_blocks; + bool is_pos_allowed; + uint64_t expiration_median_timestamp; + bool is_disconnected; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(daemon_network_state) + KV_SERIALIZE(synchronization_start_height) + KV_SERIALIZE(synchronized_connections_count) + KV_SERIALIZE(max_net_seen_height) + KV_SERIALIZE(height) + KV_SERIALIZE(out_connections_count) + KV_SERIALIZE(inc_connections_count) + KV_SERIALIZE(net_time_delta_median) + KV_SERIALIZE(pos_difficulty) + KV_SERIALIZE(pow_difficulty) + KV_SERIALIZE(hashrate) + KV_SERIALIZE(last_build_displaymode) + KV_SERIALIZE(last_build_available) + //KV_SERIALIZE(last_blocks) + KV_SERIALIZE(alias_count) + KV_SERIALIZE(is_pos_allowed) + KV_SERIALIZE(expiration_median_timestamp) + KV_SERIALIZE(is_disconnected) + END_KV_SERIALIZE_MAP() + }; + + + + + struct wallet_status_info + { + enum state + { + wallet_state_synchronizing = 1, + wallet_state_ready = 2, + wallet_state_error = 3 + }; + + + uint64_t wallet_id; + uint64_t wallet_state; + bool is_mining; + bool is_alias_operations_available; + uint64_t balance; + uint64_t unlocked_balance; + uint64_t awaiting_in; + uint64_t awaiting_out; + uint64_t minied_total; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(wallet_id) + KV_SERIALIZE(wallet_state) + KV_SERIALIZE(is_mining) + KV_SERIALIZE(is_alias_operations_available) + KV_SERIALIZE(balance) + KV_SERIALIZE(unlocked_balance) + KV_SERIALIZE(awaiting_in) + KV_SERIALIZE(awaiting_out) + KV_SERIALIZE(minied_total) + END_KV_SERIALIZE_MAP() + }; + + struct wallet_info + { + uint64_t unlocked_balance; + uint64_t balance; + uint64_t mined_total; + std::string address; + std::string tracking_hey; + std::string path; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(unlocked_balance) + KV_SERIALIZE(balance) + KV_SERIALIZE(mined_total) + KV_SERIALIZE(address) + KV_SERIALIZE(tracking_hey) + KV_SERIALIZE(path) + END_KV_SERIALIZE_MAP() + }; + + + + struct wallet_entry_info + { + wallet_info wi; + uint64_t wallet_id; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(wi) + KV_SERIALIZE(wallet_id) + END_KV_SERIALIZE_MAP() + + }; + + + + struct wallet_id_obj + { + uint64_t wallet_id; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(wallet_id) + END_KV_SERIALIZE_MAP() + }; + + struct request_mining_estimate + { + uint64_t amount_coins; + uint64_t time; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(amount_coins) + KV_SERIALIZE(time) + END_KV_SERIALIZE_MAP() + }; + + struct response_mining_estimate + { + uint64_t final_amount; + uint64_t all_coins_and_pos_diff_rate; + std::vector days_estimate; + std::string error_code; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(final_amount) + KV_SERIALIZE(all_coins_and_pos_diff_rate) + KV_SERIALIZE(days_estimate) + KV_SERIALIZE(error_code) + END_KV_SERIALIZE_MAP() + }; + + struct backup_keys_request + { + + uint64_t wallet_id; + std::string path; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(wallet_id) + KV_SERIALIZE(path) + END_KV_SERIALIZE_MAP() + }; + + struct system_filedialog_request + { + std::string default_dir; + std::string caption; + std::string filemask; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(caption) + KV_SERIALIZE(filemask) + KV_SERIALIZE(default_dir) + END_KV_SERIALIZE_MAP() + }; + + struct system_filedialog_response + { + std::string error_code; + std::string path; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(error_code) + KV_SERIALIZE(path) + END_KV_SERIALIZE_MAP() + }; + + + + + struct push_offer_param + { + uint64_t wallet_id; + bc_services::offer_details_ex od; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(wallet_id) + KV_SERIALIZE(od) + END_KV_SERIALIZE_MAP() + }; + + + struct cancel_offer_param + { + uint64_t wallet_id; + crypto::hash tx_id; + uint64_t no; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(wallet_id) + KV_SERIALIZE_POD_AS_HEX_STRING_N(tx_id, "id") + KV_SERIALIZE_N(no, "oi") + END_KV_SERIALIZE_MAP() + }; + + + + struct transfer_event_info + { + tools::wallet_rpc::wallet_transfer_info ti; + uint64_t unlocked_balance; + uint64_t balance; + uint64_t total_mined; + uint64_t wallet_id; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(ti) + KV_SERIALIZE(unlocked_balance) + KV_SERIALIZE(balance) + KV_SERIALIZE(total_mined) + KV_SERIALIZE(wallet_id) + END_KV_SERIALIZE_MAP() + }; + + struct transfers_array + { + std::vector unconfirmed; + std::vector history; + uint64_t total_history_items; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(unconfirmed) + KV_SERIALIZE(history) + KV_SERIALIZE(total_history_items) + END_KV_SERIALIZE_MAP() + + }; + + struct open_wallet_request + { + std::string pass; + std::string path; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(pass) + KV_SERIALIZE(path) + END_KV_SERIALIZE_MAP() + }; + + struct get_recent_transfers_request + { + uint64_t wallet_id; + uint64_t offest; + uint64_t count; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(wallet_id) + KV_SERIALIZE(offest) + KV_SERIALIZE(count) + END_KV_SERIALIZE_MAP() + }; + + struct reset_pass_request + { + uint64_t wallet_id; + std::string pass; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(wallet_id) + KV_SERIALIZE(pass) + END_KV_SERIALIZE_MAP() + }; + + struct restore_wallet_request + { + std::string pass; + std::string path; + std::string restore_key; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(pass) + KV_SERIALIZE(path) + KV_SERIALIZE(restore_key) + END_KV_SERIALIZE_MAP() + }; + + struct open_wallet_response + { + uint64_t wallet_id; + transfers_array recent_history; + wallet_info wi; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(wallet_id) + KV_SERIALIZE(recent_history) + KV_SERIALIZE(wi) + END_KV_SERIALIZE_MAP() + }; + + struct wallets_summary_info + { + std::list wallets; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(wallets) + END_KV_SERIALIZE_MAP() + }; + + + struct contracts_array + { + std::vector contracts; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(contracts) + END_KV_SERIALIZE_MAP() + }; + + + struct header_entry + { + std::string field; + std::string val; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(field) + KV_SERIALIZE(val) + END_KV_SERIALIZE_MAP() + }; + + struct request_uri_params + { + std::string method; + std::string data; + std::vector headers; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(method) + KV_SERIALIZE(data) + KV_SERIALIZE(headers) + END_KV_SERIALIZE_MAP() + }; + + struct password_data + { + std::string pass; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(pass) + END_KV_SERIALIZE_MAP() + }; + + + struct alias_set + { + std::list aliases; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(aliases) + END_KV_SERIALIZE_MAP() + }; + + struct request_alias_param + { + currency::alias_rpc_details alias; + uint64_t wallet_id; + uint64_t fee; + uint64_t reward; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(alias) + KV_SERIALIZE(wallet_id) + KV_SERIALIZE(fee) + KV_SERIALIZE(reward) + END_KV_SERIALIZE_MAP() + }; + + + struct start_backend_params + { + bool configure_for_remote_node; + std::string remote_node_host; + uint64_t remote_node_port; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(configure_for_remote_node) + KV_SERIALIZE(remote_node_host) + KV_SERIALIZE(remote_node_port) + END_KV_SERIALIZE_MAP() + }; + + + struct wallet_sync_progres_param + { + uint64_t wallet_id; + uint64_t progress; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(wallet_id) + KV_SERIALIZE(progress) + END_KV_SERIALIZE_MAP() + }; + + struct get_restore_info_response + { + std::string restore_key; + std::string error_code; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(restore_key) + KV_SERIALIZE(error_code) + END_KV_SERIALIZE_MAP() + }; + + struct get_alias_coast_response + { + std::string error_code; + uint64_t coast; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(coast) + KV_SERIALIZE(error_code) + END_KV_SERIALIZE_MAP() + }; + + + struct print_text_param + { + std::string html_text; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(html_text) + END_KV_SERIALIZE_MAP() + }; + + + struct get_fav_offers_request + { + std::list ids; + bc_services::core_offers_filter filter; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(ids) + KV_SERIALIZE(filter) + END_KV_SERIALIZE_MAP() + }; + + struct set_localization_request + { + std::vector strings; + std::string language_title; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(strings) + KV_SERIALIZE(language_title) + END_KV_SERIALIZE_MAP() + + }; + + + struct create_proposal_param + { + uint64_t wallet_id; + bc_services::contract_private_details details; + std::string payment_id; + uint64_t expiration_period; + uint64_t fee; + uint64_t b_fee; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(wallet_id) + KV_SERIALIZE(details) + KV_SERIALIZE(payment_id) + KV_SERIALIZE(expiration_period) + KV_SERIALIZE(fee) + KV_SERIALIZE(b_fee) + END_KV_SERIALIZE_MAP() + }; + + struct wallet_and_contract_id_param + { + uint64_t wallet_id; + crypto::hash contract_id; + + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(wallet_id) + KV_SERIALIZE_POD_AS_HEX_STRING(contract_id) + END_KV_SERIALIZE_MAP() + }; + + struct accept_proposal_param : public wallet_and_contract_id_param + { + std::string release_type; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(release_type) + KV_CHAIN_BASE(wallet_and_contract_id_param) + END_KV_SERIALIZE_MAP() + + }; + + struct contract_and_fee_param : public wallet_and_contract_id_param + { + uint64_t fee; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(fee) + KV_CHAIN_BASE(wallet_and_contract_id_param) + END_KV_SERIALIZE_MAP() + + }; + + struct crequest_cancel_contract_param : public contract_and_fee_param + { + uint64_t expiration_period; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(expiration_period) + KV_CHAIN_BASE(contract_and_fee_param) + END_KV_SERIALIZE_MAP() + + }; + + struct address_validation_response + { + std::string error_code; + std::string payment_id; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(error_code) + KV_SERIALIZE(payment_id) + END_KV_SERIALIZE_MAP() + }; + + + struct gui_options + { + bool use_debug_mode; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(use_debug_mode) + END_KV_SERIALIZE_MAP() + + }; + + struct print_log_params + { + std::string msg; + int log_level; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(msg) + KV_SERIALIZE(log_level) + END_KV_SERIALIZE_MAP() + }; + + + struct api_response + { +// std::string request_id; + std::string error_code; + + BEGIN_KV_SERIALIZE_MAP() +// KV_SERIALIZE(request_id) + KV_SERIALIZE(error_code) + END_KV_SERIALIZE_MAP() + }; + + template + struct api_response_t + { + std::string error_code; + t_type response_data; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(error_code) + KV_SERIALIZE(response_data) + END_KV_SERIALIZE_MAP() + }; + + template + struct api_request_t + { + uint64_t wallet_id; + t_type req_data; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(wallet_id) + KV_SERIALIZE(req_data) + END_KV_SERIALIZE_MAP() + }; + + + + + struct api_void + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + template + struct struct_with_one_t_type + { + t_type v; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(v) + END_KV_SERIALIZE_MAP() + }; + + + + +#define API_RETURN_CODE_OK BASIC_RESPONSE_STATUS_OK +#define API_RETURN_CODE_FAIL BASIC_RESPONSE_STATUS_FAILED +#define API_RETURN_CODE_NOT_FOUND BASIC_RESPONSE_STATUS_NOT_FOUND +#define API_RETURN_CODE_ACCESS_DENIED "ACCESS_DENIED" +#define API_RETURN_CODE_INTERNAL_ERROR "INTERNAL_ERROR" +#define API_RETURN_CODE_NOT_ENOUGH_MONEY "NOT_ENOUGH_MONEY" +#define API_RETURN_CODE_INTERNAL_ERROR_QUE_FULL "INTERNAL_ERROR_QUE_FULL" +#define API_RETURN_CODE_BAD_ARG "BAD_ARG" +#define API_RETURN_CODE_BAD_ARG_EMPTY_DESTINATIONS "BAD_ARG_EMPTY_DESTINATIONS" +#define API_RETURN_CODE_BAD_ARG_WRONG_FEE "BAD_ARG_WRONG_FEE" +#define API_RETURN_CODE_BAD_ARG_INVALID_ADDRESS "BAD_ARG_INVALID_ADDRESS" +#define API_RETURN_CODE_BAD_ARG_WRONG_AMOUNT "BAD_ARG_WRONG_AMOUNT" +#define API_RETURN_CODE_BAD_ARG_WRONG_PAYMENT_ID "BAD_ARG_WRONG_PAYMENT_ID" +#define API_RETURN_CODE_WRONG_PASSWORD "WRONG_PASSWORD" +#define API_RETURN_CODE_WALLET_WRONG_ID "WALLET_WRONG_ID" +#define API_RETURN_CODE_FILE_NOT_FOUND "FILE_NOT_FOUND" +#define API_RETURN_CODE_ALREADY_EXISTS "ALREADY_EXISTS" +#define API_RETURN_CODE_CANCELED "CANCELED" +#define API_RETURN_CODE_FILE_RESTORED "FILE_RESTORED" +#define API_RETURN_CODE_TRUE "TRUE" +#define API_RETURN_CODE_FALSE "FALSE" +#define API_RETURN_CODE_CORE_BUSY "CORE_BUSY" +#define API_RETURN_CODE_OVERFLOW "OVERFLOW" + +#define API_MAX_ALIASES_COUNT 10000 + + struct i_view + { + virtual bool update_daemon_status(const daemon_status_info& info){ return true; } + virtual bool on_backend_stopped(){ return true; } + virtual bool show_msg_box(const std::string& message){ return true; } + virtual bool update_wallet_status(const wallet_status_info& wsi){ return true; } + virtual bool update_wallets_info(const wallets_summary_info& wsi){ return true; } + virtual bool money_transfer(const transfer_event_info& wsi){ return true; } + virtual bool wallet_sync_progress(const view::wallet_sync_progres_param& p){ return true; } + virtual bool init(const std::string& path){ return true; } + virtual bool pos_block_found(const currency::block& block_found){ return true; } + virtual bool money_transfer_cancel(const transfer_event_info& wsi){ return true; } + virtual bool set_options(const gui_options& opt){ return true; } + }; + +} diff --git a/src/gui/qt-daemon/application/wallet_id_adapter.h b/src/gui/qt-daemon/application/wallet_id_adapter.h new file mode 100644 index 00000000..766cbf1f --- /dev/null +++ b/src/gui/qt-daemon/application/wallet_id_adapter.h @@ -0,0 +1,45 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include "wallet/wallet2.h" + +class i_backend_wallet_callback +{ +public: + virtual void on_new_block(size_t wallet_id, uint64_t /*height*/, const currency::block& /*block*/) {} + virtual void on_transfer2(size_t wallet_id, const tools::wallet_rpc::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) {} + virtual void on_pos_block_found(size_t wallet_id, const currency::block& /*block*/) {} + virtual void on_sync_progress(size_t wallet_id, const uint64_t& /*percents*/) {} + virtual void on_transfer_canceled(size_t wallet_id, const tools::wallet_rpc::wallet_transfer_info& wti) {} +}; + +struct i_wallet_to_i_backend_adapter: public tools::i_wallet2_callback +{ + i_wallet_to_i_backend_adapter(i_backend_wallet_callback* pbackend, size_t wallet_id) :m_pbackend(pbackend), + m_wallet_id(wallet_id) + {} + + virtual void on_new_block(uint64_t height, const currency::block& block) { + m_pbackend->on_new_block(m_wallet_id, height, block); + } + virtual void on_transfer2(const tools::wallet_rpc::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) { + m_pbackend->on_transfer2(m_wallet_id, wti, balance, unlocked_balance, total_mined); + } + virtual void on_pos_block_found(const currency::block& wti) { + m_pbackend->on_pos_block_found(m_wallet_id, wti); + } + virtual void on_sync_progress(const uint64_t& progress) { + m_pbackend->on_sync_progress(m_wallet_id, progress); + } + virtual void on_transfer_canceled(const tools::wallet_rpc::wallet_transfer_info& wti) { + m_pbackend->on_transfer_canceled(m_wallet_id, wti); + } +private: + i_backend_wallet_callback* m_pbackend; + size_t m_wallet_id; +}; diff --git a/src/gui/qt-daemon/html/account.svg b/src/gui/qt-daemon/html/account.svg new file mode 100644 index 00000000..b7b746fa --- /dev/null +++ b/src/gui/qt-daemon/html/account.svg @@ -0,0 +1,15 @@ + + + + + + diff --git a/src/gui/qt-daemon/html/alert.svg b/src/gui/qt-daemon/html/alert.svg new file mode 100644 index 00000000..b549fd95 --- /dev/null +++ b/src/gui/qt-daemon/html/alert.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/gui/qt-daemon/html/arrow-down.svg b/src/gui/qt-daemon/html/arrow-down.svg new file mode 100644 index 00000000..d24a3aeb --- /dev/null +++ b/src/gui/qt-daemon/html/arrow-down.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/gui/qt-daemon/html/arrow-right.svg b/src/gui/qt-daemon/html/arrow-right.svg new file mode 100644 index 00000000..bd4269b3 --- /dev/null +++ b/src/gui/qt-daemon/html/arrow-right.svg @@ -0,0 +1,9 @@ + + + + + diff --git a/src/gui/qt-daemon/html/arrow-up.svg b/src/gui/qt-daemon/html/arrow-up.svg new file mode 100644 index 00000000..f6515fdd --- /dev/null +++ b/src/gui/qt-daemon/html/arrow-up.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/gui/qt-daemon/html/assets/i18n/en.json b/src/gui/qt-daemon/html/assets/i18n/en.json new file mode 100644 index 00000000..bebd6a13 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/i18n/en.json @@ -0,0 +1,174 @@ +{ + "LOGIN" : { + "SETUP_MASTER_PASS": "Setup master password", + "SETUP_CONFIRM_PASS": "Confirm the password", + "MASTER_PASS": "Master password", + "BUTTON_NEXT": "Next" + }, + "COMMON": { + "BACK": "Go back" + }, + "BREADCRUMBS": { + "ADD_WALLET": "Add new wallet", + "CREATE_WALLET": "Create new wallet", + "SAVE_PHRASE": "Save your seed phrase", + "OPEN_WALLET": "Open existing wallet", + "RESTORE_WALLET": "Restore from backup", + "WALLET_DETAILS": "Wallet details", + "CONTRACTS": "Contracts", + "NEW_PURCHASE": "New purchase", + "OLD_PURCHASE": "Purchase" + }, + "SIDEBAR": { + "TITLE": "Accounts", + "ADD_NEW": "+ Add new", + "ACCOUNT": { + "STAKING": "Staking", + "MESSAGES": "New offers/Messages" + }, + "SETTINGS": "Settings", + "LOG_OUT": "Log out", + "SYNCHRONIZATION": { + "OFFLINE": "Offline", + "ONLINE": "Online", + "ERROR": "System error", + "COMPLETE": "Completion", + "SYNCING": "Syncing blockchain", + "LOADING": "Loading blockchain data" + } + }, + "MAIN": { + "TITLE": "Create or open the wallet to start using Zano", + "BUTTON_NEW_WALLET": "Create new wallet", + "BUTTON_OPEN_WALLET": "Open existing wallet", + "BUTTON_RESTORE_BACKUP": "Restore from backup", + "HELP": "How to create wallet?" + }, + "CREATE_WALLET": { + "NAME": "Wallet name", + "PASS": "Set wallet password", + "CONFIRM": "Confirm wallet password", + "BUTTON_SELECT": "Select wallet location", + "BUTTON_CREATE": "Create wallet" + }, + "OPEN_WALLET": { + "NAME": "Wallet name", + "PASS": "Wallet password", + "BUTTON": "Open wallet" + }, + "RESTORE_WALLET": { + "LABEL_NAME": "Wallet name", + "LABEL_PHRASE_KEY": "Seed phrase / private key", + "PASS": "Wallet password", + "CONFIRM": "Confirm wallet password", + "BUTTON_SELECT": "Select wallet location", + "BUTTON_CREATE": "Create wallet" + }, + "SEED_PHRASE": { + "TITLE": "Make sure to keep your seed phrase in a safe place. If you forget your seed phrase you will not be able to recover your account.", + "BUTTON_CREATE_ACCOUNT" : "Create account" + }, + "SETTINGS": { + "TITLE": "Settings", + "DARK_THEME": "Dark theme", + "WHITE_THEME": "White theme", + "GRAY_THEME": "Gray theme", + "MASTER_PASSWORD": { + "TITLE": "Update master password", + "OLD": "Old password", + "NEW": "New password", + "CONFIRM": "New password confirmation", + "BUTTON": "Save" + } + }, + "WALLET": { + "REGISTER_ALIAS": "Register an alias", + "DETAILS": "Details", + "LOCK": "Lock", + "TABS": { + "SEND": "Send", + "RECEIVE": "Receive", + "HISTORY": "History", + "CONTRACTS": "Contracts", + "MESSAGES": "Messages", + "STAKING": "Staking" + } + }, + "WALLET_DETAILS": { + "LABEL_NAME": "Wallet name", + "LABEL_FILE_LOCATION": "Wallet file location", + "LABEL_SEED_PHRASE": "Seed phrase", + "SEED_PHRASE_HINT": "Click to reveal the seed phrase", + "BUTTON_SAVE": "Save", + "BUTTON_REMOVE": "Remove wallet" + }, + "SEND": { + "ADDRESS": "Address", + "AMOUNT": "Amount", + "COMMENT": "Comment", + "DETAILS": "Additional details", + "MIXIN": "Mixin", + "FEE": "Fee", + "BUTTON": "Send" + }, + "HISTORY": { + "STATUS": "Status", + "STATUS_TOOLTIP": "Approved {{current}}/{{total}}", + "SEND": "Send", + "RECEIVED": "Received", + "DATE": "Date", + "AMOUNT": "Amount", + "FEE": "Fee", + "ADDRESS": "Address" + }, + "CONTRACTS": { + "EMPTY": "No active contracts.", + "CONTRACTS": "Contracts", + "PURCHASE": "Purchase", + "SELL": "Sell", + "DATE": "Date", + "AMOUNT": "Amount", + "STATUS": "Status", + "COMMENTS": "Comments", + "PURCHASE_BUTTON": "New Purchase", + "LISTING_BUTTON": "Create listing", + "TIME_LEFT": { + "REMAINING_LESS_ONE": "Less than an hour to respond", + "REMAINING_ONE": "Remaining {{time}} hour", + "REMAINING_MANY": "Remaining {{time}} hours", + "REMAINING_MANY_ALT": "Remaining {{time}} hours", + "REMAINING_ONE_RESPONSE": "Remaining {{time}} hour for response", + "REMAINING_MANY_RESPONSE": "Remaining {{time}} hours for response", + "REMAINING_MANY_ALT_RESPONSE": "Remaining {{time}} hours for response", + "REMAINING_ONE_WAITING": "Remaining {{time}} hour waiting", + "REMAINING_MANY_WAITING": "Remaining {{time}} hours waiting", + "REMAINING_MANY_ALT_WAITING": "Remaining {{time}} hours waiting" + } + }, + "PURCHASE": { + "DESCRIPTION": "Description", + "SELLER": "Seller", + "AMOUNT": "Amount", + "YOUR_DEPOSIT": "Your deposit", + "SELLER_DEPOSIT": "Seller deposit", + "COMMENT": "Comment", + "DETAILS": "Additional details", + "SEND_BUTTON": "Send", + "CANCEL_BUTTON": "Cancel and return deposits", + "TERMINATE_BUTTON": "Terminate and burn deposits", + "COMPLETE_BUTTON": "Complete and release deposits", + "PROGRESS_NEW": "New purchase", + "PROGRESS_WAIT": "Awaiting reply", + "PROGRESS_RECEIVE": "Reply received", + "PROGRESS_COMPLETE": "Completed", + "FEE": "Fee", + "PAYMENT": "Payment ID" + + }, + "MESSAGES": { + "ADDRESS": "Address", + "MESSAGE": "Message", + "SEND_PLACEHOLDER": "Type a message...", + "SEND_BUTTON": "Send" + } +} diff --git a/src/gui/qt-daemon/html/assets/i18n/fr.json b/src/gui/qt-daemon/html/assets/i18n/fr.json new file mode 100644 index 00000000..63275d82 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/i18n/fr.json @@ -0,0 +1,15 @@ +{ + "SIDEBAR": { + "TITLE": "Accounts2", + "ADD_NEW": "+ Add new2", + "SETTINGS": "Settings2", + "LOG_OUT": "Log out2" + }, + "MAIN": { + "TITLE": "Create or open the wallet to start using Zano2", + "BUTTON_NEW_WALLET": "Create new wallet2", + "BUTTON_OPEN_WALLET": "Open existing wallet2", + "BUTTON_RESTORE_BACKUP": "Restore from backup2", + "HELP": "How to create wallet?2" + } +} diff --git a/src/gui/qt-daemon/html/assets/icons/account.svg b/src/gui/qt-daemon/html/assets/icons/account.svg new file mode 100644 index 00000000..b7b746fa --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/account.svg @@ -0,0 +1,15 @@ + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/addnew.svg b/src/gui/qt-daemon/html/assets/icons/addnew.svg new file mode 100644 index 00000000..89bc1ca5 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/addnew.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/alert.svg b/src/gui/qt-daemon/html/assets/icons/alert.svg new file mode 100644 index 00000000..b549fd95 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/alert.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/arrow-down.svg b/src/gui/qt-daemon/html/assets/icons/arrow-down.svg new file mode 100644 index 00000000..d24a3aeb --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/arrow-down.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/arrow-right.svg b/src/gui/qt-daemon/html/assets/icons/arrow-right.svg new file mode 100644 index 00000000..bd4269b3 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/arrow-right.svg @@ -0,0 +1,9 @@ + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/arrow-up.svg b/src/gui/qt-daemon/html/assets/icons/arrow-up.svg new file mode 100644 index 00000000..f6515fdd --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/arrow-up.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/back.svg b/src/gui/qt-daemon/html/assets/icons/back.svg new file mode 100644 index 00000000..0b00a610 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/back.svg @@ -0,0 +1,10 @@ + + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/complete-testwallet.svg b/src/gui/qt-daemon/html/assets/icons/complete-testwallet.svg new file mode 100644 index 00000000..b5d04868 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/complete-testwallet.svg @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/contracts.svg b/src/gui/qt-daemon/html/assets/icons/contracts.svg new file mode 100644 index 00000000..aa985ac7 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/contracts.svg @@ -0,0 +1,13 @@ + + + + + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/copy.svg b/src/gui/qt-daemon/html/assets/icons/copy.svg new file mode 100644 index 00000000..4ec2ff7d --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/copy.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/details.svg b/src/gui/qt-daemon/html/assets/icons/details.svg new file mode 100644 index 00000000..eb12cde2 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/details.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/history.svg b/src/gui/qt-daemon/html/assets/icons/history.svg new file mode 100644 index 00000000..c9945561 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/history.svg @@ -0,0 +1,12 @@ + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/howto.svg b/src/gui/qt-daemon/html/assets/icons/howto.svg new file mode 100644 index 00000000..92362f78 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/howto.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/lock.svg b/src/gui/qt-daemon/html/assets/icons/lock.svg new file mode 100644 index 00000000..021aae19 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/lock.svg @@ -0,0 +1,12 @@ + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/logout.svg b/src/gui/qt-daemon/html/assets/icons/logout.svg new file mode 100644 index 00000000..ef77f2cc --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/logout.svg @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/message.svg b/src/gui/qt-daemon/html/assets/icons/message.svg new file mode 100644 index 00000000..544888cc --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/message.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/modal/alert.svg b/src/gui/qt-daemon/html/assets/icons/modal/alert.svg new file mode 100644 index 00000000..bb5c7d02 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/modal/alert.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/modal/close.svg b/src/gui/qt-daemon/html/assets/icons/modal/close.svg new file mode 100644 index 00000000..d39bed6d --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/modal/close.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/modal/info.svg b/src/gui/qt-daemon/html/assets/icons/modal/info.svg new file mode 100644 index 00000000..0119fcc7 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/modal/info.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/modal/success.svg b/src/gui/qt-daemon/html/assets/icons/modal/success.svg new file mode 100644 index 00000000..60ad5a5d --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/modal/success.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/new.svg b/src/gui/qt-daemon/html/assets/icons/new.svg new file mode 100644 index 00000000..89622385 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/new.svg @@ -0,0 +1,17 @@ + + + + + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/purchase.svg b/src/gui/qt-daemon/html/assets/icons/purchase.svg new file mode 100644 index 00000000..46e904fc --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/purchase.svg @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/receive.svg b/src/gui/qt-daemon/html/assets/icons/receive.svg new file mode 100644 index 00000000..fd7e85a9 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/receive.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/sell.svg b/src/gui/qt-daemon/html/assets/icons/sell.svg new file mode 100644 index 00000000..f28f0a20 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/sell.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/send.svg b/src/gui/qt-daemon/html/assets/icons/send.svg new file mode 100644 index 00000000..0c7e6136 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/send.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/settings.svg b/src/gui/qt-daemon/html/assets/icons/settings.svg new file mode 100644 index 00000000..105d2282 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/settings.svg @@ -0,0 +1,17 @@ + + + + + + + + + diff --git a/src/gui/qt-daemon/html/assets/icons/staking.svg b/src/gui/qt-daemon/html/assets/icons/staking.svg new file mode 100644 index 00000000..2f4337f6 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/icons/staking.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/src/gui/qt-daemon/html/assets/images/Loading.png b/src/gui/qt-daemon/html/assets/images/Loading.png new file mode 100644 index 00000000..694d2330 Binary files /dev/null and b/src/gui/qt-daemon/html/assets/images/Loading.png differ diff --git a/src/gui/qt-daemon/html/assets/images/background-dark.png b/src/gui/qt-daemon/html/assets/images/background-dark.png new file mode 100644 index 00000000..83290ff9 Binary files /dev/null and b/src/gui/qt-daemon/html/assets/images/background-dark.png differ diff --git a/src/gui/qt-daemon/html/assets/images/background-gray.png b/src/gui/qt-daemon/html/assets/images/background-gray.png new file mode 100644 index 00000000..f3361431 Binary files /dev/null and b/src/gui/qt-daemon/html/assets/images/background-gray.png differ diff --git a/src/gui/qt-daemon/html/assets/images/background-white.png b/src/gui/qt-daemon/html/assets/images/background-white.png new file mode 100644 index 00000000..4eda5cac Binary files /dev/null and b/src/gui/qt-daemon/html/assets/images/background-white.png differ diff --git a/src/gui/qt-daemon/html/assets/images/logo.png b/src/gui/qt-daemon/html/assets/images/logo.png new file mode 100644 index 00000000..3ca30b1b Binary files /dev/null and b/src/gui/qt-daemon/html/assets/images/logo.png differ diff --git a/src/gui/qt-daemon/html/assets/images/qr-code.png b/src/gui/qt-daemon/html/assets/images/qr-code.png new file mode 100644 index 00000000..4827e329 Binary files /dev/null and b/src/gui/qt-daemon/html/assets/images/qr-code.png differ diff --git a/src/gui/qt-daemon/html/assets/scss/base/_base.scss b/src/gui/qt-daemon/html/assets/scss/base/_base.scss new file mode 100644 index 00000000..2f60619f --- /dev/null +++ b/src/gui/qt-daemon/html/assets/scss/base/_base.scss @@ -0,0 +1,382 @@ +button { + border: none; + font-family: 'Open Sans', sans-serif; + font-size: 1.5rem; + font-weight: 600; + outline: none; + padding: 0 1rem; + height: 4.2rem; + + &:disabled:not(.transparent-button) { + + @include themify($themes) { + background-color: themed(disabledButtonBackgroundColor); + color: themed(alternativeTextColor); + } + + &:hover { + + @include themify($themes) { + background-color: themed(disabledButtonHoverColor); + } + } + } + + &.blue-button:not(:disabled) { + + @include themify($themes) { + background-color: themed(blueButtonBackgroundColor); + color: themed(alternativeTextColor); + } + + &:hover { + + @include themify($themes) { + background-color: themed(blueButtonHoverColor); + } + } + } + + &.green-button:not(:disabled) { + + @include themify($themes) { + background-color: themed(greenButtonBackgroundColor); + color: themed(alternativeTextColor); + } + + &:hover { + + @include themify($themes) { + background-color: themed(greenButtonHoverColor); + } + } + } + + &.turquoise-button:not(:disabled) { + + @include themify($themes) { + background-color: themed(turquoiseButtonBackgroundColor); + color: themed(alternativeTextColor); + } + + &:hover { + + @include themify($themes) { + background-color: themed(turquoiseButtonHoverColor); + } + } + } + + &.transparent-button { + display: flex; + align-items: center; + justify-content: center; + + @include themify($themes) { + background-color: transparent; + border: 0.2rem solid themed(transparentButtonBorderColor); + color: themed(mainTextColor); + } + + .icon { + + @include themify($themes) { + background-color: themed(mainTextColor); + } + + margin-right: 1rem; + mask: url(~src/assets/icons/complete-testwallet.svg) no-repeat center; + width: 1.7rem; + height: 1.7rem; + } + } + +} + +.input-block { + display: flex; + flex-direction: column; + align-items: flex-start; + margin-bottom: 0.4rem; + height: 6.6rem; + + .wrap-label { + display: flex; + align-items: center; + justify-content: flex-start; + min-height: 2.4rem; + } + + label { + font-size: 1.3rem; + line-height: 2.4rem; + + @include themify($themes) { + color: themed(optionalTextColor); + } + } + + input[type='text'], input[type='password'] { + border: none; + font-size: 1.4rem; + outline: none; + padding: 0 1rem; + width: 100%; + height: 100%; + + @include themify($themes) { + background-color: themed(inputBackgroundColor); + color: themed(mainTextColor); + } + } + + &.textarea { + height: auto; + + textarea { + font-family: 'Open Sans', sans-serif; + border: none; + font-size: 1.4rem; + outline: none; + padding: 1rem; + width: 100%; + min-width: 100%; + height: 100%; + min-height: 7rem; + max-height: 7rem; + overflow: hidden; + resize: none; + + @include themify($themes) { + background-color: themed(inputBackgroundColor); + color: themed(mainTextColor); + } + } + } +} + +input[type='radio'].style-radio { + + & + label { + display: flex; + align-items: center; + cursor: pointer; + font-weight: 400; + padding-left: 2.4rem; + + @include themify($themes) { + color: themed(optionalTextColor); + } + + @include unSelect; + } + + &:not(checked) { + position: absolute; + opacity: 0; + + & + label { + position: relative; + } + + & + label:before { + content: ''; + position: absolute; + top: 0.7rem; + left: 0; + background: transparent; + border-radius: 50%; + width: 1.4rem; + height: 1.4rem; + + @include themify($themes) { + border: 0.1rem solid themed(blueTextColor); + } + } + + & + label:after { + content: ''; + position: absolute; + top: 1rem; + left: 0.3rem; + border-radius: 50%; + opacity: 0; + width: 0.8rem; + height: 0.8rem; + + @include themify($themes) { + background-color: themed(blueTextColor); + } + } + } + + &:checked { + + & + label:after { + opacity: 1; + } + } +} + +input[type='checkbox'].style-checkbox { + + & + label { + display: flex; + align-items: center; + cursor: pointer; + font-weight: 400; + padding-left: 3.6rem; + + @include themify($themes) { + color: themed(optionalTextColor); + } + + @include unSelect; + } + + &:not(checked) { + position: absolute; + top: 50%; + left: 1.6rem; + transform: translateY(-50%); + visibility: hidden; + + & + label { + position: relative; + } + + & + label:before { + content: ''; + position: absolute; + top: 50%; + left: 1.6rem; + transform: translateY(-50%); + background: transparent; + width: 1.4rem; + height: 1.4rem; + + @include themify($themes) { + border: 0.1rem solid themed(blueTextColor); + } + } + } + + &:checked { + + & + label:before { + background: url(~src/assets/icons/complete-testwallet.svg); + + @include themify($themes) { + background-color: themed(blueTextColor); + } + } + } +} + +.error-block { + font-size: 1.2rem; + text-align: right; + + @include themify($themes) { + color: themed(redTextColor); + } +} + +.history-tooltip { + font-size: 1.3rem; + padding: 1rem 2rem; + + @include themify($themes) { + background: themed(tooltipBackgroundColor); + box-shadow: themed(tooltipShadow); + color: themed(mainTextColor); + } + + &.ng-tooltip-top { + margin-top: -1rem; + + &:before { + content: ""; + position: absolute; + bottom: -1rem; + left: 0.7rem; + border-width: 1rem 1rem 0 0; + border-style: solid; + + @include themify($themes) { + border-color: themed(tooltipBackgroundColor) transparent transparent transparent; + } + } + } + + &.ng-tooltip-bottom { + margin-top: 1rem; + + &:before { + content: ""; + position: absolute; + top: -1rem; + left: 0.7rem; + border-width: 1rem 0 0 1rem; + border-style: solid; + + @include themify($themes) { + border-color: transparent transparent transparent themed(tooltipBackgroundColor); + } + } + } + + &.ng-tooltip-left { + margin-left: -1rem; + + &:before { + content: ""; + position: absolute; + top: 0; + right: -1rem; + border-width: 1rem 1rem 0 0; + border-style: solid; + + @include themify($themes) { + border-color: themed(tooltipBackgroundColor) transparent transparent transparent; + } + } + } + + &.ng-tooltip-right { + margin-left: 1rem; + + &:before { + content: ""; + position: absolute; + top: 0; + left: -1rem; + border-width: 1rem 0 0 1rem; + border-style: solid; + + @include themify($themes) { + border-color: themed(tooltipBackgroundColor) transparent transparent transparent; + } + } + } +} + +.modal { + + @include themify($themes) { + background: themed(tooltipBackgroundColor); + color: themed(mainTextColor); + } + + .content { + + } + + .action-button { + + @include themify($themes) { + background-color: themed(blueTextColor); + color: themed(alternativeTextColor); + } + } +} diff --git a/src/gui/qt-daemon/html/assets/scss/base/_mixins.scss b/src/gui/qt-daemon/html/assets/scss/base/_mixins.scss new file mode 100644 index 00000000..9b355f0f --- /dev/null +++ b/src/gui/qt-daemon/html/assets/scss/base/_mixins.scss @@ -0,0 +1,98 @@ +@mixin text-truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +@mixin textWrap { + white-space: normal; + overflow-wrap: break-word; + word-wrap: break-word; + word-break: break-all; + line-break: strict; + -webkit-hyphens: auto; + -ms-hyphens: auto; + hyphens: auto; +} +@mixin coverBox { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} +@mixin abs ($top: auto, $right: auto, $bottom: auto, $left: auto) { + top: $top; + right: $right; + bottom: $bottom; + left: $left; + position: absolute; +} +@mixin coverImg { + background-repeat: no-repeat; + -webkit-background-size: cover; + -o-background-size: cover; + background-size: cover; + background-position: 50% 50%; +} +@mixin valingBox { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} +@mixin unSelect { + -webkit-touch-collout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +@mixin max1199 { // maket 1171 + @media (max-width: 1199px) { @content; } +} +@mixin max1170 { // makets 992 + @media (max-width: 1170px) { @content; } +} +@mixin max991 { // makets 762 + @media (max-width: 991px) { @content; } +} +@mixin max761 { // makets 576 + @media (max-width: 761px) { @content; } +} +@mixin max575 { // makets 400 + @media (max-width: 575px) { @content; } +} +@mixin mobile { + @media (max-width: 399px) { @content; } +} +@mixin icoCenter { + background-repeat: no-repeat; + background-position: center center; +} +@mixin pseudo ($display: block, $pos: absolute, $content: ''){ + content: $content; + display: $display; + position: $pos; +} + +/* +* Implementation of themes +*/ +@mixin themify($themes: $themes) { + @each $theme, $map in $themes { + .theme-#{$theme} & { + $theme-map: () !global; + @each $key, $submap in $map { + $value: map-get(map-get($themes, $theme), '#{$key}'); + $theme-map: map-merge($theme-map, ($key: $value)) !global; + } + @content; + $theme-map: null !global; + } + } +} + +@function themed($key) { + @return map-get($theme-map, $key); +} diff --git a/src/gui/qt-daemon/html/assets/scss/base/_null.scss b/src/gui/qt-daemon/html/assets/scss/base/_null.scss new file mode 100644 index 00000000..9c476f5d --- /dev/null +++ b/src/gui/qt-daemon/html/assets/scss/base/_null.scss @@ -0,0 +1,128 @@ +//* ******* reset & normalize ******* *// + +// box-sizing the same for all elements +html { + box-sizing: border-box; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; +} +*, *:before, *:after { + box-sizing: inherit; + -webkit-box-sizing: inherit; + -moz-box-sizing: inherit; + margin: 0; + padding: 0; + @include unSelect; +} + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} + +body { + line-height: 1; + font-style: normal; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: none; +} + +//table +table { + border-collapse: collapse; + border-spacing: 0; +} +td, +th { + padding: 0; +} + +//forms element +input { + outline: none; + &:-webkit-autofill { + -webkit-box-shadow: 0 0 0 1000px white inset; + } +} + +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; + cursor: pointer; + outline: none; +} +button[disabled], +html input[disabled] { + cursor: default; +} +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} +input { + line-height: normal; +} +input[type="search"] { + -webkit-appearance: textfield; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + + +//link +a { + text-decoration: none; + &:active, + &:hover, + &:focus { + outline: 0; + } +} + +i { font-style: italic; } +b, strong { font-weight: 700; } + +// images +img { + width: auto; + max-width: 100%; + height: auto; + vertical-align: top; + border: 0; +} + +.hidden { + display: none !important; +} diff --git a/src/gui/qt-daemon/html/assets/scss/base/_theme.scss b/src/gui/qt-daemon/html/assets/scss/base/_theme.scss new file mode 100644 index 00000000..1532c72d --- /dev/null +++ b/src/gui/qt-daemon/html/assets/scss/base/_theme.scss @@ -0,0 +1,130 @@ +$themes: ( + dark: ( + bodyBackgroundColor: #131921, + sidebarBackgroundColor: rgba(23, 31, 39, 0.5), + sidebarBorderColor: #1f2833, + onlineColor: #5cda9d, + offlineColor: #fe5252, + contentBackgroundColor: rgba(43, 54, 68, 0.5), + mainTextColor: #e0e0e0, + alternativeTextColor: #111921, + optionalTextColor: #556576, + blueTextColor: #4db1ff, + redTextColor: #ff5252, + blueButtonBackgroundColor: #4db1ff, + blueButtonHoverColor: #60b9ff, + disabledButtonBackgroundColor: #90a4ae, + disabledButtonHoverColor: #9bb0ba, + greenButtonBackgroundColor: #5cda9d, + greenButtonHoverColor: #5ce2a1, + turquoiseButtonBackgroundColor: #4dd0e1, + turquoiseButtonHoverColor: #52d9ea, + transparentButtonBorderColor: #2b3644, + inputBackgroundColor: #171e27, + switchBackgroundColor: #000000, + accountBackgroundColor: rgba(43, 54, 68, 0.5), + accountHoverBackgroundColor: rgba(58, 72, 90, 0.5), + accountMainTextColor: #e0e0e0, + accountOptionalTextColor: #556576, + accountIndicatorTextColor: #111921, + accountSwitchBackgroundColor: #000000, + accountIndicatorBackgroundColor: #4db1ff, + tabInactiveBackgroundColor: rgba(23, 31, 39, 0.5), + tableBackgroundColor: #18202a, + messageMyBackgroundColor: #2a3544, + messageBuddyBackgroundColor: #18202a, + progressBarBackgroundColor: #343f4a, + progressBarFullBackgroundColor: #5cda9d, + chartOptionsBackgroundColor: #2b3644, + chartOptionsHoverColor: #556576, + tooltipBackgroundColor: #42505f, + tooltipShadow: 0 0 1rem rgba(0, 0, 0, 0.5) + ), + gray: ( + bodyBackgroundColor: #101417, + sidebarBackgroundColor: rgba(23, 25, 27, 0.5), + sidebarBorderColor: #2e3337, + onlineColor: #47cf8d, + offlineColor: #ff5252, + contentBackgroundColor: rgba(37, 40, 43, 0.5), + mainTextColor: #e0e0e0, + alternativeTextColor: #1a1a1a, + optionalTextColor: #565c62, + blueTextColor: #42a5f5, + redTextColor: #ff5252, + blueButtonBackgroundColor: #42a5f5, + blueButtonHoverColor: #4dafff, + disabledButtonBackgroundColor: #79848f, + disabledButtonHoverColor: #85909b, + greenButtonBackgroundColor: #47cf8d, + greenButtonHoverColor: #49d993, + turquoiseButtonBackgroundColor: #3ec5d7, + turquoiseButtonHoverColor: #43cee0, + transparentButtonBorderColor: #2f3438, + inputBackgroundColor: #292d31, + switchBackgroundColor: #000000, + accountBackgroundColor: rgba(37, 40, 43, 0.5), + accountHoverBackgroundColor: rgba(70, 76, 81, 0.5), + accountMainTextColor: #e0e0e0, + accountOptionalTextColor: #565c62, + accountIndicatorTextColor: #1a1a1a, + accountSwitchBackgroundColor: #000000, + accountIndicatorBackgroundColor: #42a5f5, + tabInactiveBackgroundColor: rgba(23, 25, 27, 0.5), + tableBackgroundColor: #25292d, + messageMyBackgroundColor: #30363c, + messageBuddyBackgroundColor: #25292d, + progressBarBackgroundColor: #363a3e, + progressBarFullBackgroundColor: #47cf8d, + chartOptionsBackgroundColor: #292d31, + chartOptionsHoverColor: #515960, + tooltipBackgroundColor: #3e464c, + tooltipShadow: 0 0 1rem rgba(0, 0, 0, 0.5) + ), + white: ( + bodyBackgroundColor: #eeeeee, + sidebarBackgroundColor: rgba(255, 255, 255, 0.5), + sidebarBorderColor: #ebebeb, + onlineColor: #46c172, + offlineColor: #ff5252, + contentBackgroundColor: rgba(255, 255, 255, 0.5), + mainTextColor: #43454b, + alternativeTextColor: #fefefe, + optionalTextColor: #a0a5ab, + blueTextColor: #2c95f1, + redTextColor: #ff5252, + blueButtonBackgroundColor: #2c95f1, + blueButtonHoverColor: #379ffa, + disabledButtonBackgroundColor: #90a4ae, + disabledButtonHoverColor: #9baeb7, + greenButtonBackgroundColor: #46c172, + greenButtonHoverColor: #46ca75, + turquoiseButtonBackgroundColor: #26b6c7, + turquoiseButtonHoverColor: #2bbdcf, + transparentButtonBorderColor: #ebebeb, + inputBackgroundColor: #e6e6e6, + switchBackgroundColor: #e0e0e0, + accountBackgroundColor: rgba(30, 136, 229, 1), + accountHoverBackgroundColor: rgba(240, 240, 240, 0.5), + accountMainTextColor: #ffffff, + accountOptionalTextColor: #91baf1, + accountIndicatorTextColor: #43454b, + accountSwitchBackgroundColor: #ffffff, + accountIndicatorBackgroundColor: #ffffff, + tabInactiveBackgroundColor: rgba(224, 224, 224, 0.5), + tableBackgroundColor: #ffffff, + messageMyBackgroundColor: #fff, + messageBuddyBackgroundColor: #ededed, + progressBarBackgroundColor: #dcdcdc, + progressBarFullBackgroundColor: #46c172, + chartOptionsBackgroundColor: #e0e0e0, + chartOptionsHoverColor: #ffffff, + tooltipBackgroundColor: #ffffff, + tooltipShadow: 0 0 1rem rgba(120, 120, 120, 0.5) + ) +); + + + + + diff --git a/src/gui/qt-daemon/html/assets/scss/layout/_main.scss b/src/gui/qt-daemon/html/assets/scss/layout/_main.scss new file mode 100644 index 00000000..b33887e5 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/scss/layout/_main.scss @@ -0,0 +1,107 @@ +app-main, app-create-wallet, app-open-wallet, app-restore-wallet, app-seed-phrase, app-wallet-details, app-settings, app-login { + flex: 1 1 auto; + padding: 3rem; + min-width: 85rem; + + .content { + position: relative; + padding: 3rem; + min-height: 100%; + + @include themify($themes) { + background-color: themed(contentBackgroundColor); + color: themed(mainTextColor); + } + + .head { + position: absolute; + top: 0; + left: 0; + } + } +} + +app-main { + + .content { + + .add-wallet { + + .add-wallet-help { + + @include themify($themes) { + color: themed(blueTextColor); + } + + .icon { + + @include themify($themes) { + background-color: themed(blueTextColor); + } + } + } + } + } +} + +app-seed-phrase { + + .seed-phrase-content { + + @include themify($themes) { + background-color: themed(inputBackgroundColor); + color: themed(mainTextColor) + } + } +} + +app-wallet-details { + + .seed-phrase { + + @include themify($themes) { + background-color: themed(inputBackgroundColor); + } + } +} + +app-settings { + + .content { + + .theme-selection { + + @include themify($themes) { + color: themed(optionalTextColor); + } + } + } +} + +app-login { + min-width: inherit; +} + +.switch { + + @include themify($themes) { + background-color: themed(switchBackgroundColor); + } + + .circle { + + &.on { + + @include themify($themes) { + background-color: themed(blueTextColor); + } + } + + &.off { + + @include themify($themes) { + background-color: themed(optionalTextColor); + } + } + } +} diff --git a/src/gui/qt-daemon/html/assets/scss/layout/_settings.scss b/src/gui/qt-daemon/html/assets/scss/layout/_settings.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/gui/qt-daemon/html/assets/scss/layout/_sidebar.scss b/src/gui/qt-daemon/html/assets/scss/layout/_sidebar.scss new file mode 100644 index 00000000..e9b5b442 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/scss/layout/_sidebar.scss @@ -0,0 +1,199 @@ +app-sidebar { + + @include themify($themes) { + background-color: themed(sidebarBackgroundColor); + } + + .sidebar-accounts { + + .sidebar-accounts-header { + + h3 { + + @include themify($themes) { + color: themed(mainTextColor); + } + } + + button { + + @include themify($themes) { + color: themed(blueTextColor); + } + } + } + + .sidebar-accounts-list { + + .sidebar-account { + + @include themify($themes) { + background-color: transparent; + color: themed(mainTextColor); + } + + .sidebar-account-row { + + .text { + + @include themify($themes) { + color: themed(optionalTextColor); + } + } + + .indicator { + + @include themify($themes) { + background-color: themed(blueButtonBackgroundColor); + color: themed(alternativeTextColor); + } + } + + .progress-bar-container { + + .progress-bar { + + @include themify($themes) { + background-color: themed(progressBarBackgroundColor); + } + + .fill { + + @include themify($themes) { + background-color: themed(progressBarFullBackgroundColor); + } + } + } + } + + &.account-synchronization { + + @include themify($themes) { + color: themed(optionalTextColor); + } + } + } + + &.active { + + @include themify($themes) { + background-color: themed(accountBackgroundColor); + color: themed(accountMainTextColor); + } + + .sidebar-account-row { + + .text { + + @include themify($themes) { + color: themed(accountOptionalTextColor); + } + } + + .indicator { + + @include themify($themes) { + background-color: themed(accountIndicatorBackgroundColor); + color: themed(accountIndicatorTextColor); + } + } + + .switch { + + @include themify($themes) { + background-color: themed(accountSwitchBackgroundColor); + color: themed(mainTextColor); + } + } + + &.account-synchronization { + + @include themify($themes) { + color: themed(accountOptionalTextColor); + } + } + } + } + + &:hover:not(.active) { + + @include themify($themes) { + background-color: themed(accountHoverBackgroundColor); + } + } + } + } + } + + .sidebar-settings { + + @include themify($themes) { + border-bottom: 0.2rem solid themed(sidebarBorderColor); + } + + button { + + @include themify($themes) { + color: themed(mainTextColor); + } + + .icon { + + @include themify($themes) { + background-color: themed(blueTextColor); + } + } + } + } + + .sidebar-synchronization-status { + + @include themify($themes) { + color: themed(optionalTextColor); + } + + .status-container { + + .offline:before { + + @include themify($themes) { + background-color: themed(offlineColor); + } + } + + .online:before { + + @include themify($themes) { + background-color: themed(onlineColor); + } + } + } + + .progress-bar-container { + + .syncing { + + .progress-bar { + + @include themify($themes) { + background-color: themed(progressBarBackgroundColor); + } + + .fill { + + @include themify($themes) { + background-color: themed(progressBarFullBackgroundColor); + } + } + } + } + + .loading { + + @include themify($themes) { + background-color: themed(progressBarFullBackgroundColor); + } + } + } + } +} diff --git a/src/gui/qt-daemon/html/assets/scss/layout/_wallet.scss b/src/gui/qt-daemon/html/assets/scss/layout/_wallet.scss new file mode 100644 index 00000000..b9e59dd9 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/scss/layout/_wallet.scss @@ -0,0 +1,388 @@ +app-wallet { + + @include themify($themes) { + color: themed(mainTextColor); + } + + .header { + + button { + + @include themify($themes) { + color: themed(mainTextColor); + } + + .icon { + + @include themify($themes) { + background-color: themed(blueTextColor); + } + } + } + } + + .address { + + @include themify($themes) { + color: themed(blueTextColor); + } + + .icon { + + @include themify($themes) { + background-color: themed(blueTextColor); + } + } + } + + .tabs { + + .tabs-header { + + .tab { + + @include themify($themes) { + background-color: themed(tabInactiveBackgroundColor); + } + + .icon { + + @include themify($themes) { + background-color: themed(blueTextColor); + } + } + + .indicator { + + @include themify($themes) { + background-color: themed(accountIndicatorBackgroundColor); + color: themed(accountIndicatorTextColor); + } + } + + &.active { + + @include themify($themes) { + background-color: themed(contentBackgroundColor); + } + } + } + } + + .tabs-content { + + @include themify($themes) { + background-color: themed(contentBackgroundColor); + } + } + } +} + +app-send { + + .form-send { + + .send-select { + + @include themify($themes) { + color: themed(mainTextColor); + } + + .icon { + + @include themify($themes) { + background-color: themed(blueTextColor); + } + } + } + + .additional-details { + + @include themify($themes) { + border: 0.2rem solid themed(transparentButtonBorderColor); + } + } + } +} + +app-receive { + + .btn-copy-address { + + @include themify($themes) { + background-color: themed(blueTextColor); + } + } +} + +app-history { + + table { + + tbody { + + tr { + + .status { + + .confirmation { + + @include themify($themes) { + background-color: themed(progressBarBackgroundColor); + } + + .fill { + + @include themify($themes) { + background-color: themed(progressBarFullBackgroundColor); + } + } + } + } + + .status.send { + + .icon { + background-color: #ff5252; + } + } + + .status.received { + + .icon { + background-color: #00c853; + } + } + } + } + } +} + +app-contracts { + + .wrap-table { + + .contract { + + .icon { + + &.new, &.alert { + + @include themify($themes) { + background-color: themed(redTextColor); + } + } + + &.purchase, &.sell { + + @include themify($themes) { + background-color: themed(blueTextColor); + } + } + } + } + } +} + +app-purchase { + + .form-purchase { + + .purchase-select { + + @include themify($themes) { + color: themed(mainTextColor); + } + + .icon { + + @include themify($themes) { + background-color: themed(blueTextColor); + } + } + } + + .purchase-states { + + @include themify($themes) { + color: themed(blueTextColor); + } + } + + .additional-details { + + @include themify($themes) { + border: 0.2rem solid themed(transparentButtonBorderColor); + } + } + } + + .progress-bar-container { + + .progress-bar { + + @include themify($themes) { + background-color: themed(progressBarBackgroundColor); + } + + .progress-bar-full { + + @include themify($themes) { + background-color: themed(progressBarFullBackgroundColor); + } + } + } + } +} + +app-messages { + + table { + + tbody { + + tr { + + td:first-child { + + span { + @include text-truncate; + } + + .icon { + + @include themify($themes) { + background-color: themed(redTextColor); + } + } + } + } + } + } +} + +app-typing-message { + + .head { + + .interlocutor { + + @include themify($themes) { + color: themed(blueTextColor); + } + } + } + + .messages-content { + + .messages-list { + + div { + + &.date { + + @include themify($themes) { + color: themed(optionalTextColor); + } + } + + &.my { + + @include themify($themes) { + background-color: themed(messageMyBackgroundColor); + } + + &:before { + + @include pseudo; + top: 0; + left: -1.1rem; + border: 1.2rem solid transparent; + + @include themify($themes) { + border-top-color: themed(messageMyBackgroundColor); + } + } + } + + &.buddy { + + @include themify($themes) { + background-color: themed(messageBuddyBackgroundColor); + } + + &:after { + + @include pseudo; + right: -1.1rem; + top: 0; + border: 1.2rem solid transparent; + + @include themify($themes) { + border-top-color: themed(messageBuddyBackgroundColor); + } + } + } + } + } + } +} + +app-staking { + + .chart-header { + + .general { + + .label { + + @include themify($themes) { + color: themed(optionalTextColor); + } + } + + .options { + + @include themify($themes) { + color: themed(mainTextColor); + } + } + } + + .selected { + display: flex; + align-items: center; + justify-content: flex-end; + flex-grow: 1; + font-size: 1.6rem; + } + } + + .chart-options { + + .title { + + @include themify($themes) { + color: themed(optionalTextColor); + } + } + + .options { + + button { + + @include themify($themes) { + color: themed(mainTextColor); + background-color: themed(chartOptionsBackgroundColor); + } + + &.active { + + @include themify($themes) { + background-color: themed(chartOptionsHoverColor); + } + } + } + } + } +} diff --git a/src/gui/qt-daemon/html/assets/scss/modules/_head.scss b/src/gui/qt-daemon/html/assets/scss/modules/_head.scss new file mode 100644 index 00000000..25c527a5 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/scss/modules/_head.scss @@ -0,0 +1,62 @@ +.head { + display: flex; + align-items: flex-end; + justify-content: space-between; + font-size: 1.3rem; + padding: 0 3rem; + width: 100%; + height: 3rem; + + @include themify($themes) { + color: themed(blueTextColor); + } + + .breadcrumbs { + + > span, a { + + &:not(:last-child) { + position: relative; + margin-right: 20px; + + &:after { + + @include pseudo; + top: 0.5rem; + right: -1.5rem; + width: 0.9rem; + height: 0.9rem; + mask: url(~src/assets/icons/arrow-right.svg) no-repeat center; + mask-size: cover; + + @include themify($themes) { + background-color: themed(blueTextColor); + } + } + } + } + } + + .back-btn { + display: flex; + align-items: center; + background-color: transparent; + color: #4db1ff; + font-size: inherit; + font-weight: 400; + line-height: 1.3rem; + padding: 0; + height: auto; + + .icon { + margin-right: 0.7rem; + mask: url(~src/assets/icons/back.svg) no-repeat center; + width: 0.9rem; + height: 0.9rem; + + @include themify($themes) { + background-color: themed(blueTextColor); + } + } + } +} diff --git a/src/gui/qt-daemon/html/assets/scss/modules/_scroll.scss b/src/gui/qt-daemon/html/assets/scss/modules/_scroll.scss new file mode 100644 index 00000000..bbd97645 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/scss/modules/_scroll.scss @@ -0,0 +1,24 @@ +.scrolled-content { + + &::-webkit-scrollbar { + background-color: transparent; + cursor: default; + width: 1rem; + height: 1rem; + } + + &::-webkit-scrollbar-track { + background: transparent; + } + + &::-webkit-scrollbar-thumb { + background-color: #556576; + background-clip: padding-box; + border: 0.25rem solid transparent; + border-radius: 0.5rem; + } + + &::-webkit-scrollbar-thumb:hover { + background-color: #556576; + } +} diff --git a/src/gui/qt-daemon/html/assets/scss/modules/_table.scss b/src/gui/qt-daemon/html/assets/scss/modules/_table.scss new file mode 100644 index 00000000..2ae0e147 --- /dev/null +++ b/src/gui/qt-daemon/html/assets/scss/modules/_table.scss @@ -0,0 +1,63 @@ +table { + font-size: 1.3rem; + width: 100%; + + thead { + text-align: left; + + @include themify($themes) { + color: themed(optionalTextColor); + } + + tr { + height: 4rem; + + th { + padding: 1rem; + vertical-align: bottom; + + &:first-child { + padding-left: 3rem; + } + + &:last-child { + padding-right: 3rem; + } + } + } + } + + tbody { + text-align: left; + + @include themify($themes) { + color: themed(mainTextColor); + } + + tr { + height: 3.5rem; + + &:nth-child(odd) { + + @include themify($themes) { + background-color: themed(tableBackgroundColor); + } + } + + td { + line-height: 1.7rem; + padding: 0 1rem; + vertical-align: middle; + white-space: nowrap; + + &:first-child { + padding-left: 3rem; + } + + &:last-child { + padding-right: 3rem; + } + } + } + } +} diff --git a/src/gui/qt-daemon/html/back.svg b/src/gui/qt-daemon/html/back.svg new file mode 100644 index 00000000..0b00a610 --- /dev/null +++ b/src/gui/qt-daemon/html/back.svg @@ -0,0 +1,10 @@ + + + + + + + diff --git a/src/gui/qt-daemon/html/background-dark.png b/src/gui/qt-daemon/html/background-dark.png new file mode 100644 index 00000000..83290ff9 Binary files /dev/null and b/src/gui/qt-daemon/html/background-dark.png differ diff --git a/src/gui/qt-daemon/html/background-gray.png b/src/gui/qt-daemon/html/background-gray.png new file mode 100644 index 00000000..f3361431 Binary files /dev/null and b/src/gui/qt-daemon/html/background-gray.png differ diff --git a/src/gui/qt-daemon/html/background-white.png b/src/gui/qt-daemon/html/background-white.png new file mode 100644 index 00000000..4eda5cac Binary files /dev/null and b/src/gui/qt-daemon/html/background-white.png differ diff --git a/src/gui/qt-daemon/html/complete-testwallet.svg b/src/gui/qt-daemon/html/complete-testwallet.svg new file mode 100644 index 00000000..b5d04868 --- /dev/null +++ b/src/gui/qt-daemon/html/complete-testwallet.svg @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/src/gui/qt-daemon/html/contracts.svg b/src/gui/qt-daemon/html/contracts.svg new file mode 100644 index 00000000..aa985ac7 --- /dev/null +++ b/src/gui/qt-daemon/html/contracts.svg @@ -0,0 +1,13 @@ + + + + + + + + + + diff --git a/src/gui/qt-daemon/html/copy.svg b/src/gui/qt-daemon/html/copy.svg new file mode 100644 index 00000000..4ec2ff7d --- /dev/null +++ b/src/gui/qt-daemon/html/copy.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/src/gui/qt-daemon/html/details.svg b/src/gui/qt-daemon/html/details.svg new file mode 100644 index 00000000..eb12cde2 --- /dev/null +++ b/src/gui/qt-daemon/html/details.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/src/gui/qt-daemon/html/favicon.ico b/src/gui/qt-daemon/html/favicon.ico new file mode 100644 index 00000000..5d170210 Binary files /dev/null and b/src/gui/qt-daemon/html/favicon.ico differ diff --git a/src/gui/qt-daemon/html/files/Zano.desktop b/src/gui/qt-daemon/html/files/Zano.desktop new file mode 100644 index 00000000..8f26e0b9 --- /dev/null +++ b/src/gui/qt-daemon/html/files/Zano.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Version=1.0 +Name=Zano +Exec=Zano +Icon=/usr/share/pixmaps/desktop_linux_icon.png +MimeType=application/x-desktop +Terminal=true +Type=Application \ No newline at end of file diff --git a/src/gui/qt-daemon/html/files/app22macos.png b/src/gui/qt-daemon/html/files/app22macos.png new file mode 100644 index 00000000..450317e7 Binary files /dev/null and b/src/gui/qt-daemon/html/files/app22macos.png differ diff --git a/src/gui/qt-daemon/html/files/app22macos_blocked.png b/src/gui/qt-daemon/html/files/app22macos_blocked.png new file mode 100644 index 00000000..d4ebb03f Binary files /dev/null and b/src/gui/qt-daemon/html/files/app22macos_blocked.png differ diff --git a/src/gui/qt-daemon/html/files/app22windows.png b/src/gui/qt-daemon/html/files/app22windows.png new file mode 100644 index 00000000..aed73ef5 Binary files /dev/null and b/src/gui/qt-daemon/html/files/app22windows.png differ diff --git a/src/gui/qt-daemon/html/files/app22windows_blocked.png b/src/gui/qt-daemon/html/files/app22windows_blocked.png new file mode 100644 index 00000000..1e309a5b Binary files /dev/null and b/src/gui/qt-daemon/html/files/app22windows_blocked.png differ diff --git a/src/gui/qt-daemon/html/files/desktop_linux_icon.png b/src/gui/qt-daemon/html/files/desktop_linux_icon.png new file mode 100644 index 00000000..c48284bf Binary files /dev/null and b/src/gui/qt-daemon/html/files/desktop_linux_icon.png differ diff --git a/src/gui/qt-daemon/html/history.svg b/src/gui/qt-daemon/html/history.svg new file mode 100644 index 00000000..c9945561 --- /dev/null +++ b/src/gui/qt-daemon/html/history.svg @@ -0,0 +1,12 @@ + + + + + + diff --git a/src/gui/qt-daemon/html/howto.svg b/src/gui/qt-daemon/html/howto.svg new file mode 100644 index 00000000..92362f78 --- /dev/null +++ b/src/gui/qt-daemon/html/howto.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + diff --git a/src/gui/qt-daemon/html/index.html b/src/gui/qt-daemon/html/index.html new file mode 100644 index 00000000..c9f7ef84 --- /dev/null +++ b/src/gui/qt-daemon/html/index.html @@ -0,0 +1,16 @@ + + + + + Zano + + + + + + + + + + + diff --git a/src/gui/qt-daemon/html/less/css/source/contacts.less b/src/gui/qt-daemon/html/less/css/source/contacts.less new file mode 100644 index 00000000..de70a28d --- /dev/null +++ b/src/gui/qt-daemon/html/less/css/source/contacts.less @@ -0,0 +1,474 @@ +@import "../variables"; +@import "mixins"; + +#contacts { + padding: 2.5rem 8rem; + + .main-options-wrapper { + + .contacts-options { + .flex-container-direction(row); + .flex-container-alignment(center, space-between); + margin-bottom: 7rem; + + .contacts-options-left { + .flex-container-direction(row); + + .contacts-groups { + + .dropdown-toggle { + .flex-container; + .flex-container-alignment(center, space-between); + background-color: white !important; + border: 1px solid @contacts-groups-border-color; + border-radius: 4rem; + box-shadow: none; + color: @program-dark-color; + font-size: 3.75rem; + height: 8.25rem; + padding: 0 4rem; + outline-style: none !important; + width: 62.5rem; + z-index: 0; + + .filter-option { + text-overflow: ellipsis; + white-space: nowrap; + } + + .caret { + position: relative; + margin: 0; + } + } + + .dropdown-menu.open { + top: 10.5rem; + border-radius: 2rem; + box-shadow: @box-shadow; + margin: 0; + + li { + + a { + min-height: 8.25rem; + word-break: break-word; + } + + &.divider { + display: block; + background-color: @program-divider-color; + margin: 0 auto; + width: 90%; + } + + .edit-groups-item { + .flex-container; + .flex-container-alignment(center, flex-start); + + .base-icon { + .icon-sizing(5rem, 5rem, -3.5rem, -4.5rem); + margin-right: 1.5rem; + flex-shrink: 0; + + &:before { + content: '#'; + } + } + } + } + } + } + + .contacts-search { + margin-left: 3.25rem; + } + } + + .contacts-buttons { + .flex-container; + + .main-options-btn { + + .add-contact-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + margin-right: 2rem; + } + + &:not(:first-child) { + margin-left: 6rem; + } + } + } + } + } + + .contacts-table { + margin-bottom: 3rem; + + .contacts-name { + display: inline-flex; + min-width: 22rem; + .flex-container-alignment(center, flex-start); + font-size: 3.75rem; + word-break: break-word; + + .base-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + color: @program-table-icon-color; + margin-right: 1rem; + flex-shrink: 0; + } + + &:hover { + color: @program-hover-color; + cursor: pointer; + + .base-icon { + color: @program-hover-color; + } + } + } + + .contacts-account { + .flex-container; + + .safe-address { + font-size: 3.25rem; + margin-top: 0.75rem; + margin-bottom: 0.75rem; + + .safe-address-wrap { + width: 40rem; + } + + .safe-address-inner { + left: inherit; + right: 0; + width: 150%; + + .contact-address { + + .safe-address-inner-additional { + .flex-container-direction(row-reverse); + .flex-container-alignment(flex-start, space-between); + margin-top: 2rem; + + .copy-icon { + cursor: pointer; + float: none; + margin-right: -1rem; + margin-top: 0; + margin-bottom: 0; + + &:hover, &.hovered { + color: @program-exuding-color; + } + + &.hovered:before { + content: 'A'; + } + } + } + + &:not(:first-child) { + border-top: 1px solid @program-divider-color; + margin-top: 4rem; + padding-top: 3rem; + } + } + } + } + + alias-display:not(.safe-address-inner-alias) { + display: inline-flex; + + .safe-alias { + margin-top: 0.75rem; + margin-bottom: 0.75rem; + } + } + } + + .contacts-location, .contacts-groups { + max-width: 32.5rem; + } + + .contacts-communication-method { + max-width: 43rem; + } + + .contacts-note { + .flex-container; + .flex-container-alignment(center, flex-start); + position: relative; + + .base-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + cursor: pointer; + } + } + + .contacts-menu { + line-height: 0; + visibility: hidden; + + .contacts-menu-btn { + background: transparent; + border: none; + padding: 0; + margin: 0; + + .base-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + } + } + + .contacts-menu-list { + .menu-list(-10.5rem, inherit, -3rem, 38rem); + } + } + + tr { + font-size: 3.25rem; + + .table-long-item-wrapper { + + .table-long-item { + + .table-long-item-text { + font-size: 3.25rem; + } + } + } + + th:last-child, td:last-child { + width: 10rem; + } + + &:hover { + + .contacts-menu { + visibility: visible; + } + } + } + } + + .export-import-contacts-wrapper { + .flex-container; + color: @export-import-contacts-text-color; + + .export-import-contacts-btn { + .flex-container; + .flex-container-alignment(center, center); + background-color: fade(white, 20%); + border: 1px solid @export-import-contacts-border-color; + font-size: 3.5rem; + height: 6rem; + padding: 0; + + .base-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + } + + &.left-btn { + border-radius: 3rem 0 0 3rem; + border-right: none; + width: 32.5rem; + } + + &.right-btn { + border-radius: 0 3rem 3rem 0; + width: 8.5rem; + } + + &:hover { + background-color: fade(white, 40%); + color: @program-dark-color; + cursor: pointer; + } + } + + .export-import-contacts-menu{ + .menu-list(-1rem, inherit, 0, 42.5rem); + } + } +} + +#contact-details { + padding: 2.5rem 8rem; + + .contact-details-options { + .flex-container-direction(row); + .flex-container-alignment(center, space-between); + margin-bottom: 5.5rem; + + .back-btn { + margin: 0 0 1rem; + } + + .contact-name { + color: @program-dark-color; + font-size: 7.75rem; + font-weight: 300; + line-height: 7.5rem; + margin-top: 0; + margin-bottom: 5.5rem; + text-align: center; + width: 100%; + } + } + + .contacts-data { + margin-top: 11rem; + margin-bottom: 5rem; + + .adaptive-form-field-group { + padding-bottom: 7.5rem; + + .field-group-label { + min-width: 42rem; + max-width: 42rem; + } + + .safe-address-wrapper { + width: 100%; + + .general-input-wrapper { + + .contact-option-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + min-width: 4rem; + visibility: hidden; + align-self: flex-end; + margin: 1.5rem 0 1.5rem 2rem; + + &:hover { + color: @program-hover-color; + } + + &.hovered:before { + content: 'A'; + } + } + + &:hover { + + .contact-option-icon { + cursor: pointer; + visibility: visible; + } + } + } + + .safe-alias-modal { + margin-top: 4rem; + } + + .contacts-data-btn-wrapper { + .flex-container; + flex-wrap: wrap; + + .contacts-data-btn { + .flex-container-direction(row); + .flex-container-alignment(center, center); + background: transparent; + border: none; + color: @contacts-accounts-btn-text-color; + font-size: 3rem; + margin: 3rem 13rem 0 0; + padding: 0; + + .base-icon { + .icon-sizing(6rem, 6rem, -3rem, -4rem); + margin-right: 1.5rem; + margin-left: -0.5rem; + } + + &:hover { + color: @program-hover-color; + } + } + } + } + + .contact-connection-wrapper { + .flex-container; + width: 100%; + + .messenger-type, angucomplete-alt { + margin-right: 6.5rem; + min-width: 37%; + width: 37%; + } + } + + .add-contact-btn { + .flex-container-direction(row); + .flex-container-alignment(center, center); + background: transparent; + border: none; + color: @contacts-accounts-btn-text-color; + font-size: 3rem; + line-height: 7rem; + margin: 0 0 0.25rem; + padding: 0; + + .base-icon { + .icon-sizing(6rem, 6rem, -3rem, -4rem); + margin-right: 1.5rem; + margin-left: -0.5rem; + } + + &:hover { + color: @program-hover-color; + } + } + + .edit-groups-field { + .flex-container; + .flex-container-alignment(center, flex-start); + + .edit-groups-icon { + .icon-sizing(5rem, 5rem, -3.5rem, -4.5rem); + margin-right: 1.5rem; + flex-shrink: 0; + + &:before { + content: '#'; + } + } + } + + } + } + + .contact-payment-history { + padding: 7rem 2.5rem 6rem; + } + + .contact-empty-payments { + color: @program-empty-color; + font-size: 3.75rem; + line-height: 5.5rem; + padding: 12.5rem 0; + text-align: center; + } + + .delete-contact-btn { + .flex-container; + .flex-container-alignment(center, center); + background: transparent; + border: none; + color: @program-dark-color; + font-size: 4.25rem; + margin: 1rem auto 0; + padding: 0; + + .base-icon { + .icon-sizing(5rem, 4rem, -3.5rem, -5rem); + margin-right: 3rem; + } + } +} \ No newline at end of file diff --git a/src/gui/qt-daemon/html/less/css/source/dashboard.less b/src/gui/qt-daemon/html/less/css/source/dashboard.less new file mode 100644 index 00000000..643a0f1b --- /dev/null +++ b/src/gui/qt-daemon/html/less/css/source/dashboard.less @@ -0,0 +1,221 @@ +@import "../variables"; +@import "mixins"; + +#dashboard { + padding: 0 8rem 2.5rem; + + .main-options-wrapper { + + .dashboard-options { + .flex-container; + .flex-container-alignment(center, space-between); + margin-bottom: 7rem; + + .top-options-list { + .flex-container; + justify-content: space-between; + flex-grow: 1; + + .top-options-item { + background: rgba(255, 255, 255, 0.4); + padding: 2.5rem 0; + flex-basis: 25%; + + .top-options-link { + .flex-container-direction(row); + .flex-container-alignment(center, center); + height: 12rem; + color: @dashboard-indicator-text-color; + cursor: pointer; + + .base-icon { + .icon-sizing(12rem, 12rem, 0, -1rem); + color: @dashboard-indicator-icon-color; + margin-right: 1rem; + } + + .top-options-number { + font-size: 8rem; + font-weight: 200; + line-height: 6rem; + } + + &:hover { + color: @program-main-color; + + .base-icon { + color: @program-main-color; + } + } + } + + &:first-child { + border-radius: 3rem 0 0 3rem; + + .top-options-link { + border-radius: 2.75rem 0 0 2.75rem; + } + } + + &:not(:first-child) { + border-left: none; + } + + &:last-child { + border-radius: 0 3rem 3rem 0; + + .top-options-link { + border-radius: 0 2.75rem 2.75rem 0; + } + } + } + } + + .dashboard-buttons { + margin-top: 3rem; + } + } + } + + .dashboard-slider-wrapper { + margin: 0 -3.5rem; + overflow: hidden; + + .dashboard-slider { + .flex-container; + padding-top: 3rem; + width: 200%; + transition: 1s; + + .dashboard-slider-item { + max-width: 25%; + min-width: 25%; + padding: 0 3.5rem; + transition: 1s; + } + } + } + + .slider-control-wrapper { + .flex-container; + .flex-container-alignment(center, space-between); + padding-top: 2.75rem; + + .slider-control-btn { + .flex-container; + .flex-container-alignment(center, center); + background: rgba(255, 255, 255, 0.7); + border: 1px solid @dashboard-slider-border-color; + border-radius: 100%; + color: @dashboard-slider-icon-color; + padding: 0; + height: 7rem; + width: 7rem; + + .base-icon { + .icon-sizing(4rem, 4rem, -3rem, -3.75rem); + font-size: 12rem; + } + + &.prev-btn { + transform: rotate(180deg); + } + + &:hover { + background: white; + color: @program-main-color; + } + } + + .slider-status-wrapper { + .flex-container; + .flex-container-alignment(center, center); + line-height: 0; + list-style-type: none; + padding: 0; + margin: 0; + + li { + + .slider-status-btn { + background: rgba(255, 255, 255, 0.5); + border: none; + border-radius: 100%; + margin: 0 1rem; + padding: 0; + height: 2rem; + width: 2rem; + } + + &.active-slide { + + .slider-status-btn{ + background: white; + border: 1px solid @dashboard-slider-border-color; + height: 2.5rem; + width: 2.5rem; + } + } + } + } + } + + .add-widget-btn-wrapper { + .flex-container; + .flex-container-alignment(center, center); + margin: 5rem auto; + + .add-widget-btn { + position: relative; + + button { + .flex-container; + .flex-container-alignment(center, center); + background: transparent; + border: none; + color: @program-dark-color; + font-size: 4.25rem; + padding: 0; + + .base-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + margin-top: 0.5rem; + margin-right: 1.5rem; + z-index: -1; + } + } + + .dropdown-menu { + .menu-list(inherit, 50%, inherit, 88rem); + .flex-container-direction(row); + flex-wrap: wrap; + bottom: 0; + transform: translateX(-50%) translateY(-2em); + + li { + flex-basis: 50%; + flex-shrink: 0; + + button { + border-radius: 0 !important; + } + + &.last-element { + flex-basis: 100%; + + button { + -webkit-justify-content: center; + justify-content: center; + } + } + } + } + + &.open { + .dropdown-menu { + transform: translateX(-50%) translateY(0); + } + } + } + } +} diff --git a/src/gui/qt-daemon/html/less/css/source/datepicker.less b/src/gui/qt-daemon/html/less/css/source/datepicker.less new file mode 100644 index 00000000..404a2235 --- /dev/null +++ b/src/gui/qt-daemon/html/less/css/source/datepicker.less @@ -0,0 +1,134 @@ +@import "../variables"; + +.datepicker { + border: none !important; + border-radius: 2.5rem !important; + -webkit-box-shadow: @box-shadow !important; + box-shadow: @box-shadow !important; + font-family: 'Titillium Web', 'AgoraSansPro', sans-serif; + width: 65rem !important; + + .datepicker--pointer { + display: none; + } + + .datepicker--nav { + border-bottom: none; + + .datepicker--nav-action { + + path { + stroke: @datepicker-nav-action-color; + stroke-width: 1px; + } + + &:hover { + background: none; + } + } + + .datepicker--nav-title { + color: @datepicker-nav-title-color; + font-size: 4rem; + text-transform: uppercase; + font-style: normal !important; + + i { + color: @datepicker-nav-title-color; + } + + &:hover { + background: none; + } + } + } + + .datepicker--content { + color: @program-dark-color; + font-size: 3.25rem; + + .datepicker--body { + + .datepicker--days-names { + + .datepicker--day-name { + color: @datepicker-day-name-color; + font-size: 3.25rem; + text-transform: uppercase; + } + } + + .datepicker--cells { + justify-content: space-between; + + .datepicker--cell { + height: 7rem !important; + width: 7rem !important; + margin: 0.5rem; + + &.-selected- { + color: @program-dark-color; + border-radius: 100%; + background: @datepicker-cell-selected-color; + + &:hover { + color: @program-dark-color; + background: @datepicker-cell-selected-color; + } + } + + &.-focus- { + border-radius: 100%; + border: 1px solid @datepicker-cell-border-color; + background: transparent; + } + + &.-disabled- { + color: @program-dark-color; + + &:hover { + border: none !important; + } + } + + &.-other-month- { + color: @datepicker-day-other-month-color; + + &.-selected- { + + &:hover { + color: @datepicker-day-other-month-color; + } + } + + &:hover { + border-radius: 100%; + border: 1px solid @datepicker-cell-border-color; + } + } + + &.-current- { + color: @program-dark-color; + border-radius: 100%; + border: 1px solid @datepicker-cell-border-color; + + &.-selected- { + + &:hover { + color: @program-dark-color; + background: @datepicker-cell-selected-color; + } + } + + &:hover { + border-radius: 100%; + border: 1px solid @datepicker-cell-border-color; + color: @program-dark-color; + background: transparent; + } + } + } + } + } + } +} \ No newline at end of file diff --git a/src/gui/qt-daemon/html/less/css/source/form-elements.less b/src/gui/qt-daemon/html/less/css/source/form-elements.less new file mode 100644 index 00000000..26ffe466 --- /dev/null +++ b/src/gui/qt-daemon/html/less/css/source/form-elements.less @@ -0,0 +1,1061 @@ +@import "../variables"; +@import "mixins"; + +.general-button { + background: @program-button-bg-color; + border: 1px solid @program-button-border-color; + border-radius: 10rem; + color: @program-button-text-color; + font-size: 3.5rem; + margin: 0; + padding: 0; + + &:hover { + background: @program-button-hover-bg-color; + } + + &:active { + background: @program-button-active-bg-color; + border-color: @program-button-border-hover-color; + } +} + +.general-input { + background: transparent; + border: none; + border-bottom: 1px solid @program-input-border-color; + box-sizing: content-box; + color: @program-input-text-color; + font-size: 3.5rem; + height: 5rem; + padding: 1rem 0; + width: 100%; + + &::-webkit-input-placeholder { + color: @program-input-placeholder-color; + } + + &::selection { + background: @program-selection-bg-color; + } + + &::-webkit-selection { + background: @program-selection-bg-color; + } + + &:hover, &:focus, &:active { + + &:not(.no-hover) { + border-bottom-color: @program-hover-color; + color: @program-hover-color; + + &.gradient-text-input { + background: -webkit-linear-gradient(left, @program-hover-color 0, @program-hover-color 75%, transparent 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + } + + &::-webkit-input-placeholder { + color: @program-input-placeholder-hover-color; + } + } + } +} + +.general-input-wrapper { + .flex-container; + .flex-container-alignment(center, space-between); + border-bottom: 1px solid @program-input-border-color; + color: @program-input-text-color; + width: 100%; + + .general-input { + border-bottom: none; + margin-top: 0 !important; + } + + .general-textarea { + border-bottom: none; + } + + .general-select { + + .dropdown-toggle { + border-bottom: none; + } + } + + .success-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + color: @success-color; + margin-left: 2rem; + } + + .error-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + color: @error-color; + margin-left: 2rem; + } + + .input-addon { + font-size: 3.5rem; + + &.pre-input { + color: @program-input-text-color; + margin-right: 2rem; + white-space: nowrap; + } + + &.post-input { + color: @program-light-color; + margin-left: 2rem; + } + } + + .eye-icon { + .icon-sizing(4rem, 5rem, -4rem, -4.5rem); + color: @program-input-icon-color; + cursor: pointer; + margin-left: 2rem; + + &.open { + color: @program-input-text-color; + + &:hover { + color: @program-hover-color; + } + } + + &:hover { + color: @program-input-placeholder-hover-color; + } + } + + .option-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + margin-left: 2rem; + min-width: 4rem; + visibility: hidden; + + &:hover { + color: @program-hover-color; + } + + &.hovered:before { + content: 'A'; + } + } + + &.autocomplete-wrapper { + position: relative; + + angucomplete-alt { + z-index: 3; + } + + .autocomplete-caret { + .icon-sizing(2rem, 2rem, -5rem, -6rem); + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); + z-index: 2; + color: @program-light-color; + margin-left: 2rem; + } + + &:hover { + + .autocomplete-caret { + color: @program-hover-color; + } + } + } + + &:hover { + + .eye-icon { + color: @program-input-placeholder-hover-color; + + &.open { + color: @program-hover-color; + } + } + + .option-icon:not(.disabled) { + cursor: pointer; + visibility: visible; + } + + &:not(.no-hover) { + border-bottom-color: @program-hover-color; + + .general-input { + color: @program-hover-color; + + &.gradient-text-input { + background: -webkit-linear-gradient(left, @program-hover-color 0, @program-hover-color 75%, transparent 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + } + } + + ::-webkit-input-placeholder { + color: @program-input-placeholder-hover-color; + } + } + } +} + +.general-textarea { + background-color: transparent; + border: none; + border-bottom: 1px solid @program-input-border-color; + color: @program-input-text-color; + font-size: 3.5rem; + line-height: 5rem; + padding: 1rem 0; + overflow: hidden; + outline-style: none; + resize: none; + height: auto; + width: 100%; + + &::-webkit-input-placeholder { + color: @program-input-placeholder-color; + } + + &::selection { + background: @program-selection-bg-color; + } + + &::-webkit-selection { + background: @program-selection-bg-color; + } + + &:hover, &:focus, &:active { + + &:not(.no-hover) { + border-bottom-color: @program-hover-color; + color: @program-hover-color; + + &::-webkit-input-placeholder { + color: @program-input-placeholder-hover-color; + } + } + } +} + +.general-select { + width: 100% !important; + + .dropdown-toggle { + background: transparent !important; + border: none; + border-radius: 0; + border-bottom: 1px solid @program-input-border-color; + color: @program-input-text-color; + font-size: 3.5rem; + line-height: 5rem; + padding: 1rem 3rem 1rem 0; + + .filter-option { + white-space: normal; + } + + .caret { + border: none; + color: @program-light-color; + font-size: 14rem; + margin: 0; + right: 0 !important; + overflow: hidden; + height: 2rem; + width: 2rem; + + &:before { + position: absolute; + top: -5rem; + left: -6rem; + + font-family: "untitled-font-1" !important; + content: "a"; + font-style: normal !important; + font-weight: normal !important; + font-variant: normal !important; + text-transform: none !important; + speak: none; + display: block; + line-height: 1; + -webkit-font-smoothing: antialiased; + } + } + + &:hover { + box-shadow: none; + } + + &:focus, &:active { + outline-style: none !important; + } + } + + .dropdown-menu { + border: none; + border-radius: 2rem; + margin-top: 1rem; + min-height: 0 !important; + padding: 0; + width: 100%; + + li { + min-height: 0 !important; + overflow: hidden; + + a { + color: @program-exuding-color; + font-size: 3.5rem; + padding: 1.5rem 3rem; + + .text { + display: block; + margin-right: auto; + white-space: normal; + width: 100%; + } + + &.selectLevel1 { + .flex-container; + align-items: center; + font-size: 3.5rem; + padding: 0 0 0 3rem; + text-transform: uppercase; + + .text { + border-bottom: 1px solid fade(#7d9689, 25%); + padding: 1.5rem 0; + } + } + + &.selectLevel2 { + .flex-container; + align-items: center; + color: @program-dark-color; + padding: 0 0 0 2.25em; + + .text { + padding: 1.5rem 0; + } + } + + &.selectLevel3 { + .flex-container; + align-items: center; + color: @program-dark-color; + padding: 0 0 0 4em; + + .text { + padding: 1.5rem 0; + } + } + + &.dont-show-tick { + + .check-mark { + display: none !important; + } + } + + &:focus { + outline: none !important; + } + } + + &.dropdown-header { + color: @program-dark-color; + font-size: 3.5rem; + padding: 1.5rem 0; + margin: 0 3rem; + border-bottom: 1px solid rgba(125, 150, 137, 0.25); + } + + &.divider { + display: none; + } + + &.selected { + + a { + color: @program-main-color; + background: @program-select-selected-color; + + .text { + //width: calc(~'100% - 5rem'); + word-break: break-all; + } + + span.check-mark { + font-size: 14rem; + margin-top: 0 !important; + right: 2rem !important; + height: 5rem; + width: 5rem; + + &:before { + position: absolute; + top: -3.5rem; + left: -4.5rem; + + font-family: "untitled-font-1" !important; + content: "A"; + font-style: normal !important; + font-weight: normal !important; + font-variant: normal !important; + text-transform: none !important; + speak: none; + display: block; + line-height: 1; + -webkit-font-smoothing: antialiased; + } + } + } + } + + &.disabled { + + a { + color: @program-light-color; + } + } + + &:hover { + + &:not([class]) { + + a { + background: @program-select-hover-color; + } + } + } + + &:first-child { + &:hover { + border-top-left-radius: 2rem; + border-top-right-radius: 2rem; + } + &.selected { + border-top-left-radius: 2rem; + border-top-right-radius: 2rem; + } + } + + &:last-child { + &:hover { + border-bottom-left-radius: 2rem; + border-bottom-right-radius: 2rem; + } + &.selected { + border-bottom-left-radius: 2rem; + border-bottom-right-radius: 2rem; + } + } + } + + &.haveScroll { + + li { + + &:first-child { + + &:hover { + border-top-right-radius: 0; + } + + &.selected { + border-top-right-radius: 0; + } + } + + &:last-child { + + &:hover { + border-bottom-right-radius: 0; + } + + &.selected { + border-bottom-right-radius: 0; + } + } + } + } + + &.inner { + margin-top: 0 !important; + border-radius: 2rem !important; + } + + &::-webkit-scrollbar { + cursor: default; + height: 1.75rem; + width: 1.75rem; + } + + &::-webkit-scrollbar-thumb { + background-clip: padding-box; + background-color: @scroll-dark-color; + border: 0.5rem solid transparent; + border-radius: 1rem; + + &:hover { + background-color: @scroll-dark-color; + } + } + + &::-webkit-scrollbar-corner { + background-color: transparent; + } + } + + &.open { + + .dropdown-toggle { + box-shadow: none; + } + } + + &.show-tick { + .dropdown-menu { + li { + &.selected { + a { + .text { + width: calc(~'100% - 5rem'); + } + } + } + } + } + } + + &.selectpicker { + width: 0 !important; + max-width: 0 !important; + min-width: 0 !important; + } + + &:hover { + + .dropdown-toggle { + color: @program-hover-color; + border-bottom-color: @program-hover-color; + } + } +} + +.general-checkbox { + .flex-container; + .flex-container-alignment(flex-start, flex-start); + color: @program-light-color; + cursor: pointer; + + .check-border { + display: inline-flex; + border: 1px solid @program-checkbox-border-color; + border-radius: 1rem; + min-height: 4rem; + min-width: 4rem; + float: left; + overflow: hidden; + + .base-icon { + .icon-sizing(3.5rem, 3.5rem, -4.25rem, -5.25rem); + display: none; + animation: checkbox-animation linear 0.3s; + animation-iteration-count: 1; + } + } + + .additional-icon { + .icon-sizing(4rem, 6rem, -4rem, -4rem); + margin-left: 2rem; + } + + .general-checkbox-text { + font-size: 3.5rem; + line-height: 4rem; + margin-left: 2rem; + text-align: left; + white-space: nowrap; + } + + &.active { + color: @program-main-color; + + .check-border { + + .base-icon { + display: block; + } + } + } +} + +.general-switch { + .flex-container; + position: relative; + font-size: 3.5rem; + line-height: 7rem; + height: 7.25rem; + + .switch-option { + .flex-container; + .flex-container-alignment(center, center); + padding: 0 5.5rem; + color: @program-switch-text-color; + + &.active { + color: @program-dark-color; + } + + &:hover { + color: @program-dark-color; + cursor: pointer; + } + } + + .switch-marker { + position: absolute; + left: 0; + bottom: -0.5rem; + background: @program-dark-color; + height: 2px; + width: 0; + transition: all 0.3s linear; + } +} + +.general-range-wrapper { + .flex-container-direction(column); + position: relative; + width: 100%; + + .general-range-value { + align-self: flex-start; + position: relative; + height: 4rem; + transform: translateX(-50%); + + output { + color: @program-dark-color; + font-size: 3.5rem; + line-height: 3.5rem; + padding: 0 0 0.5rem; + } + } + + .general-range { + -webkit-appearance: none; + background-color: transparent; + height: 4rem; + + &::-webkit-slider-thumb { + position: relative; + background-size: 1.75rem 1.5rem; + border: 1px solid @program-range-border-color; + border-radius: 4rem; + cursor: pointer; + height: 3rem; + width: 6rem; + margin-top: -1.25rem; + -webkit-appearance: none; + z-index: 2; + background: white url('../img/range_lines.svg') no-repeat center; + } + + &::-webkit-slider-runnable-track { + background: fade(@program-dark-color, 20%); + border-radius: 0.25rem; + cursor: pointer; + height: 0.5rem; + width: 100%; + } + } + + .general-range-selected { + position: absolute; + top: 50%; + left: 0; + background: @program-range-selected-color; + border-radius: 4rem; + height: 0.5rem; + margin-top: -0.25rem; + width: 0; + } + + .general-range-list { + .flex-container; + .flex-container-alignment(center, space-between); + height: 4rem; + margin: 0 2rem; + padding-top:2rem; + + option { + color: @program-range-selected-color; + font-size: 2.75rem; + text-align: center; + } + } +} + +.ui-slider-wrapper { + + .ui-slider { + position: relative; + background: fade(@program-dark-color, 20%); + border-radius: 0.25rem; + cursor: pointer; + height: 0.5rem; + margin: 1.75rem auto; + + &.ui-slider-time { + margin-left: 10%; + margin-right: 10%; + } + + &.ui-slider-font-size { + margin-left: 12.5%; + margin-right: 12.5%; + } + + &.ui-slider-log { + margin-left: 8.333%; + margin-right: 8.333%; + } + + .ui-slider-range { + position: absolute; + background: @program-range-selected-color; + border-radius: 4rem; + height: 0.5rem; + width: 0; + } + + .ui-slider-handle { + top: -1.5rem; + margin-left: -3rem; + position: absolute; + background-size: 1.75rem 1.5rem; + border: 1px solid @program-range-border-color; + border-radius: 4rem; + cursor: pointer; + height: 3.25rem; + width: 6.25rem; + z-index: 2; + background: white url('../img/range_lines.svg') no-repeat center; + outline-style: none; + + .ui-slider-tip { + color: @program-dark-color; + font-size: 3.5rem; + line-height: 3.5rem; + padding: 0 0 1rem; + -webkit-transform: translateY(-100%); + transform: translateY(-100%); + display: flex; + align-items: center; + justify-content: center; + white-space: nowrap; + } + } + } + + .general-range-list { + + option { + flex: 1 0 0; + align-items: center; + justify-content: center; + display: flex; + } + + &.ui-slider-tip-list{ + margin: 0; + transform: translateY(-50%); + + option { + color: @program-dark-color; + font-size: 3.5rem; + line-height: 3.5rem; + padding: 0 0 0.5rem; + display: flex; + align-items: center; + justify-content: center; + white-space: nowrap; + } + } + + } + +} + + +angucomplete-alt { + width: 100%; + + &.alias-autocomplete { + + .angucomplete-dropdown { + width: calc(~'100% + 6rem'); + } + } +} + +.angucomplete-dropdown { + position: absolute; + background-color: white; + border: none; + border-radius: 2rem; + box-shadow: @box-shadow; + cursor: pointer; + margin-top: 2rem; + padding: 0; + max-height: 73rem; + overflow-y: auto; + width: 100%; + z-index: 9999; + + //opacity: 0; + //visibility: hidden; + //transform: translateY(-2em); + //transition: all 0.3s ease-in-out 0s, visibility 0s linear 0.3s, z-index 0s linear 0.01s; + + .angucomplete-searching { + background: transparent; + border: none; + color: @program-light-color; + font-size: 3.5rem; + text-align: left; + min-height: 8.25rem; + line-height: 8.25rem; + padding-left: 2rem; + } + + .angucomplete-row { + .flex-container-direction(column); + .flex-container-alignment(flex-start, center); + background: transparent; + border: none; + text-align: left; + line-height: 4.5rem; + padding: 1.5rem 0 1.5rem 3rem; + min-height: 8.25rem; + width: 100%; + clear: both; + + .angucomplete-title { + color: @program-exuding-color; + font-size: 3.5rem; + } + + .angucomplete-description { + color: @program-light-color; + font-size: 3rem; + word-break: break-word; + } + + &.angucomplete-selected-row { + background: @program-select-hover-color; + } + + &:hover { + + &:not(.angucomplete-selected-row) { + background: rgba(241, 241, 234, 0.5); + } + } + } + + &::-webkit-scrollbar { + cursor: default; + height: 1.75rem; + width: 1.75rem; + } + + &::-webkit-scrollbar-thumb { + background-clip: padding-box; + background-color: @scroll-dark-color; + border: 0.5rem solid transparent; + border-radius: 1rem; + + &:hover { + background-color: @scroll-dark-color; + } + } + + &::-webkit-scrollbar-corner { + background-color: transparent; + } +} + + +#waitAnswerOutput{ + width: 6rem; + text-align: center; +} + +#wait-answer-list{ + margin: 0 1rem; + + option{ + &:nth-child(2){ + margin-left: -3rem; + } + } +} + + +.dropdown-animation { + position: relative; + + .dropdown-menu { + display: block; + visibility: hidden; + opacity: 0; + transform: translateY(-2em); + transition: all 0.3s ease-in-out 0s, visibility 0s linear 0.3s, z-index 0s linear 0.01s; + } + + &.bootstrap-select { + + .dropdown-menu { + max-height: 25rem; + overflow-y: auto; + } + } + + &.open { + + .dropdown-menu { + visibility: visible; + max-height: 111rem !important; + opacity: 1; + transform: translateY(0%); + transition-delay: 0s, 0s, 0.3s; + } + } +} + +.uib-dropdown-animation { + display: block; + border: none; + border-radius: 2rem; + box-shadow: @box-shadow; + margin-top: 2rem; + padding: 0; + + visibility: hidden; + opacity: 0; + transform: translateY(-2em); + transition: all 0.3s ease-in-out 0s, visibility 0s linear 0.3s, z-index 0s linear 0.01s; + + li { + width: 100%; + + button { + .flex-container; + .flex-container-alignment(center, flex-start); + background: transparent; + border: none; + color: @program-exuding-color; + font-size: 3.5rem; + text-align: left; + padding-left: 3rem; + height: 8.25rem; + width: 100%; + white-space: nowrap; + + &:disabled { + color: @program-light-color; + } + + &:hover { + + &:not(:disabled) { + background: @program-select-hover-color; + cursor: pointer; + } + } + } + + &:first-child { + + button { + border-top-left-radius: 2rem; + border-top-right-radius: 2rem; + } + } + + &:last-child { + + button { + border-bottom-left-radius: 2rem; + border-bottom-right-radius: 2rem; + } + } + } + + &.safe-block-menu { + margin-top: -15rem; + margin-left: -15rem; + } + + &.open-slider-dropdown { + visibility: visible; + opacity: 1; + transform: translateY(0%); + transition-delay: 0s, 0s, 0.3s; + } + +} + +.dropdown.open { + + .uib-dropdown-animation { + visibility: visible; + opacity: 1; + transform: translateY(0%); + transition-delay: 0s, 0s, 0.3s; + } +} + +.dropdown-toggle[aria-expanded=true] { + color: @program-hover-color; +} + +.angucomplete-holder { + position: relative; +} + +//ToDo angucomplete +.angucomplete-image-holder { + padding-top: 2px; + float: left; + margin-right: 10px; + margin-left: 5px; +} + +.angucomplete-image { + height: 34px; + width: 34px; + border-radius: 50%; + border-color: #ececec; + border-style: solid; + border-width: 1px; +} + +.angucomplete-image-default { + background-position: center; + background-size: contain; + height: 34px; + width: 34px; +} \ No newline at end of file diff --git a/src/gui/qt-daemon/html/less/css/source/global.less b/src/gui/qt-daemon/html/less/css/source/global.less new file mode 100644 index 00000000..b35650d2 --- /dev/null +++ b/src/gui/qt-daemon/html/less/css/source/global.less @@ -0,0 +1,1281 @@ +@import "../variables"; +@import "mixins"; + +@font-face { + font-family: "untitled-font-1"; + src: url("../fonts/untitled-font-1.eot"); + src: url("../fonts/untitled-font-1.eot?#iefix") format("embedded-opentype"), + url("../fonts/untitled-font-1.woff") format("woff"), + url("../fonts/untitled-font-1.ttf") format("truetype"), + url("../fonts/untitled-font-1.svg#untitled-font-1") format("svg"); + font-weight: normal; + font-style: normal; +} + +/* titillium-web-200 - latin-ext_latin */ +@font-face { + font-family: 'Titillium Web'; + font-style: normal; + font-weight: 200; + src: url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-200.eot'); /* IE9 Compat Modes */ + src: local('Titillium WebThin'), local('TitilliumWeb-Thin'), + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-200.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-200.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-200.woff') format('woff'), /* Modern Browsers */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-200.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-200.svg#TitilliumWeb') format('svg'); /* Legacy iOS */ +} +/* titillium-web-200italic - latin-ext_latin */ +@font-face { + font-family: 'Titillium Web'; + font-style: italic; + font-weight: 200; + src: url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-200italic.eot'); /* IE9 Compat Modes */ + src: local('Titillium WebThin Italic'), local('TitilliumWeb-ThinItalic'), + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-200italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-200italic.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-200italic.woff') format('woff'), /* Modern Browsers */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-200italic.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-200italic.svg#TitilliumWeb') format('svg'); /* Legacy iOS */ +} +/* titillium-web-300 - latin-ext_latin */ +@font-face { + font-family: 'Titillium Web'; + font-style: normal; + font-weight: 300; + src: url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-300.eot'); /* IE9 Compat Modes */ + src: local('Titillium WebLight'), local('TitilliumWeb-Light'), + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-300.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-300.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-300.woff') format('woff'), /* Modern Browsers */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-300.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-300.svg#TitilliumWeb') format('svg'); /* Legacy iOS */ +} +/* titillium-web-300italic - latin-ext_latin */ +@font-face { + font-family: 'Titillium Web'; + font-style: italic; + font-weight: 300; + src: url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-300italic.eot'); /* IE9 Compat Modes */ + src: local('Titillium WebLight Italic'), local('TitilliumWeb-LightItalic'), + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-300italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-300italic.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-300italic.woff') format('woff'), /* Modern Browsers */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-300italic.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-300italic.svg#TitilliumWeb') format('svg'); /* Legacy iOS */ +} +/* titillium-web-regular - latin-ext_latin */ +@font-face { + font-family: 'Titillium Web'; + font-style: normal; + font-weight: 400; + src: url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-regular.eot'); /* IE9 Compat Modes */ + src: local('Titillium Web'), local('TitilliumWeb-Regular'), + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-regular.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-regular.woff') format('woff'), /* Modern Browsers */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-regular.svg#TitilliumWeb') format('svg'); /* Legacy iOS */ +} +/* titillium-web-italic - latin-ext_latin */ +@font-face { + font-family: 'Titillium Web'; + font-style: italic; + font-weight: 400; + src: url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-italic.eot'); /* IE9 Compat Modes */ + src: local('Titillium WebItalic'), local('TitilliumWeb-Italic'), + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-italic.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-italic.woff') format('woff'), /* Modern Browsers */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-italic.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-italic.svg#TitilliumWeb') format('svg'); /* Legacy iOS */ +} +/* titillium-web-600 - latin-ext_latin */ +@font-face { + font-family: 'Titillium Web'; + font-style: normal; + font-weight: 600; + src: url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-600.eot'); /* IE9 Compat Modes */ + src: local('Titillium WebSemiBold'), local('TitilliumWeb-SemiBold'), + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-600.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-600.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-600.woff') format('woff'), /* Modern Browsers */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-600.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-600.svg#TitilliumWeb') format('svg'); /* Legacy iOS */ +} +/* titillium-web-600italic - latin-ext_latin */ +@font-face { + font-family: 'Titillium Web'; + font-style: italic; + font-weight: 600; + src: url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-600italic.eot'); /* IE9 Compat Modes */ + src: local('Titillium WebSemiBold Italic'), local('TitilliumWeb-SemiBoldItalic'), + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-600italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-600italic.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-600italic.woff') format('woff'), /* Modern Browsers */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-600italic.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-600italic.svg#TitilliumWeb') format('svg'); /* Legacy iOS */ +} +/* titillium-web-700 - latin-ext_latin */ +@font-face { + font-family: 'Titillium Web'; + font-style: normal; + font-weight: 700; + src: url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-700.eot'); /* IE9 Compat Modes */ + src: local('Titillium WebBold'), local('TitilliumWeb-Bold'), + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-700.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-700.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-700.woff') format('woff'), /* Modern Browsers */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-700.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-700.svg#TitilliumWeb') format('svg'); /* Legacy iOS */ +} +/* titillium-web-700italic - latin-ext_latin */ +@font-face { + font-family: 'Titillium Web'; + font-style: italic; + font-weight: 700; + src: url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-700italic.eot'); /* IE9 Compat Modes */ + src: local('Titillium WebBold Italic'), local('TitilliumWeb-BoldItalic'), + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-700italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-700italic.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-700italic.woff') format('woff'), /* Modern Browsers */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-700italic.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/TitilliumWeb/titillium-web-v4-latin-ext_latin-700italic.svg#TitilliumWeb') format('svg'); /* Legacy iOS */ +} + +/* font-family: "AgoraSansProThin"; */ +@font-face { + font-family: "AgoraSansPro"; + src: url("../fonts/AgoraSansPro/AgoraSansProThin.woff") format("woff"); + font-style: normal; + font-weight: 200; +} +/* font-family: "AgoraSansProThinItalic"; */ +@font-face { + font-family: "AgoraSansPro"; + src: url("../fonts/AgoraSansPro/AgoraSansProThinItalic.woff") format("woff"); + font-style: italic; + font-weight: 200; +} +/* font-family: "AgoraSansProLight"; */ +@font-face { + font-family: "AgoraSansPro"; + src: url("../fonts/AgoraSansPro/AgoraSansProLight.woff") format("woff"); + font-style: normal; + font-weight: 300; +} +/* font-family: "AgoraSansProLightItalic"; */ +@font-face { + font-family: "AgoraSansPro"; + src: url("../fonts/AgoraSansPro/AgoraSansProLightItalic.woff") format("woff"); + font-style: italic; + font-weight: 300; +} +/* font-family: "AgoraSansProRegular"; */ +@font-face { + font-family: "AgoraSansPro"; + src: url("../fonts/AgoraSansPro/AgoraSansProRegular.woff") format("woff"); + font-style: normal; + font-weight: 400; +} +/* font-family: "AgoraSansProItalic"; */ +@font-face { + font-family: "AgoraSansPro"; + src: url("../fonts/AgoraSansPro/AgoraSansProItalic.woff") format("woff"); + font-style: italic; + font-weight: 400; +} +/* font-family: "AgoraSansProMedium"; */ +@font-face { + font-family: "AgoraSansPro"; + src: url("../fonts/AgoraSansPro/AgoraSansProMedium.woff") format("woff"); + font-style: normal; + font-weight: 600; +} +/* font-family: "AgoraSansProMediumItalic"; */ +@font-face { + font-family: "AgoraSansPro"; + src: url("../fonts/AgoraSansPro/AgoraSansProMediumItalic.woff") format("woff"); + font-style: italic; + font-weight: 600; +} +/* font-family: "AgoraSansProBold"; */ +@font-face { + font-family: "AgoraSansPro"; + src: url("../fonts/AgoraSansPro/AgoraSansProBold.woff") format("woff"); + font-style: normal; + font-weight: 700; +} +/* font-family: "AgoraSansProBoldItalic"; */ +@font-face { + font-family: "AgoraSansPro"; + src: url("../fonts/AgoraSansPro/AgoraSansProBoldItalic.woff") format("woff"); + font-style: italic; + font-weight: 700; +} + +/* font-family: "KozGoPr6N"; */ +@font-face { + font-family: "KozGoPr6N"; + src: url("../fonts/KozGoPr6N/KozGoPr6N-ExtraLight.otf") format("opentype"); + font-style: normal; + font-weight: 200; +} +/* font-family: "KozGoPr6N"; */ +@font-face { + font-family: "KozGoPr6N"; + src: url("../fonts/KozGoPr6N/KozGoPr6N-Light.otf") format("opentype"); + font-style: normal; + font-weight: 300; +} + +/* font-family: "NotoSansCJKkr"; */ +@font-face { + font-family: "NotoSansCJKkr"; + src: url("../fonts/NotoSansCJKkr/NotoSansCJKkr-Thin.otf") format("opentype"); + font-style: normal; + font-weight: 200; +} +/* font-family: "NotoSansCJKkr"; */ +@font-face { + font-family: "NotoSansCJKkr"; + src: url("../fonts/NotoSansCJKkr/NotoSansCJKkr-Light.otf") format("opentype"); + font-style: normal; + font-weight: 300; +} + +body, html { + height: 100vh; + max-height: 100vh; + min-height: 100vh; + overflow: hidden; +} + +html { + font-size: 4px; +} + +body { + background-image: @background-image; + background-size: cover; + font-family: 'Titillium Web', 'AgoraSansPro', 'KozGoPr6N', 'NotoSansCJKkr', sans-serif; + font-size: 4rem; + overflow-x: auto; + overflow-y: hidden; + -webkit-user-select: none; + user-select: none; + cursor: default; +} + +input, textarea { + + &:not(:read-only) { + -webkit-user-select: text; + user-select: text; + } + + &:read-only { + -webkit-user-select: none; + user-select: none; + cursor: default; + } +} + +a { + + &:hover, &:focus, &:active { + outline-style: none; + text-decoration: none; + } +} + +button, input { + + &:focus { + outline: none; + } +} + +.gradient-text-input { + background: -webkit-linear-gradient(left, @program-main-color 0, @program-main-color 75%, transparent 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; +} + +.content-wrapper { + position: relative; + height: calc(~'100vh - 37.5rem'); + min-width: @min-width; + overflow-x: hidden; + overflow-y: auto; + width: 100vw; + + .content-section { + min-width: @min-width; + width: 100vw; + } +} + +.base-scroll { + + &::-webkit-scrollbar { + cursor: default; + } + + &::-webkit-scrollbar-thumb { + background-clip: padding-box; + border: 0.5rem solid transparent; + border-radius: 1rem; + } + + &::-webkit-scrollbar-corner { + background-color: transparent; + } + + &.light-scroll { + + &::-webkit-scrollbar { + height: 2rem; + width: 2rem; + } + } + + &.dark-scroll { + + &::-webkit-scrollbar { + height: 1.75rem; + width: 1.75rem; + } + } + + &:hover { + + &.light-scroll { + + &::-webkit-scrollbar-thumb { + background-color: @scroll-light-color; + + &:hover { + background-color: @scroll-light-color; + } + } + } + + &.dark-scroll { + + &::-webkit-scrollbar-thumb { + background-color: @scroll-dark-color; + + &:hover { + background-color: @scroll-dark-color; + } + } + } + } +} + +.text-pre{ + white-space: pre-wrap; +} + +.base-icon { + display: inline-block; + font-size: 14rem; + overflow: hidden; + position: relative; + + &:before { + content: attr(data-icon); + font-family: "untitled-font-1"; + font-style: normal; + font-weight: normal; + line-height: 1; + text-transform: none; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + position: absolute; + } +} + +.contextMenu { + position: absolute; + z-index: 999999; + background-color: white; + border-radius: 2rem; + box-shadow: @box-shadow; + + ul { + margin: 0; + padding: 0; + + li { + color: @program-exuding-color; + cursor: pointer; + font-size: 3.5rem; + list-style-type: none; + padding: 1.5rem 3rem; + text-align: left; + + &:first-child { + border-top-left-radius: 2rem; + border-top-right-radius: 2rem; + } + + &:last-child { + border-bottom-left-radius: 2rem; + border-bottom-right-radius: 2rem; + } + + &[disabled="disabled"] { + background: none; + color: @program-light-color; + cursor: auto; + } + + &:hover { + + &:not(:disabled) { + background: rgba(241, 241, 234, 0.5); + } + } + } + } + + &:active, &:focus { + outline: none; + } +} + +.bug-report-btn { + .flex-container-direction(column); + .flex-container-alignment(center, center); + position: fixed; + bottom: 3rem; + right: 3rem; + background: transparent; + border: none; + color: @bug-report-button-color; + height: 4rem; + padding: 0; + width: 4rem; + + .base-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + font-size: 14rem; + } +} + +.informer-window-wrapper { + .flex-container; + .flex-container-alignment(center, center); + position: absolute; + top: 0; + left: 0; + z-index: 9999999999; + background-image: url("../img/bg_blue.jpg"); + background-size: cover; + height: 100%; + width: 100%; + outline: none; + + .informer-window { + .flex-container-direction(column); + .flex-container-alignment(center, center); + color: @program-dark-color; + font-weight: 200; + + .base-icon { + .icon-sizing(25rem, 25rem, 0, 0); + font-size: 25rem; + margin-bottom: -3rem; + } + + .informer-message { + font-size: 8rem; + text-align: center; + width: 120rem; + } + + .informer-details { + font-size: 6.25rem; + text-align: center; + } + + &.success { + + .base-icon { + .icon-sizing(16rem, 16rem, 0, 0); + -webkit-animation-name: errorAnimation; + animation-name: errorAnimation; + -webkit-animation-duration: 1s; + animation-duration: 1s; + font-size: 16rem; + margin-bottom: 0; + } + } + + &.error { + color: #d02412; + + .base-icon { + -webkit-animation-name: errorAnimation; + animation-name: errorAnimation; + -webkit-animation-duration: 1s; + animation-duration: 1s; + } + + .informer-details { + padding: 0 10rem; + } + } + + &.warning { + color: #d02412; + + .informer-message { + padding-top: 1.75rem; + padding-bottom: 1.75rem; + } + + .informer-details { + padding: 0 10rem; + } + } + + &.info { + + .informer-message { + padding-top: 1.75rem; + padding-bottom: 1.75rem; + } + } + + &.file-not-found { + color: #d02412; + + .base-icon { + -webkit-animation-name: errorAnimation; + animation-name: errorAnimation; + -webkit-animation-duration: 1s; + animation-duration: 1s; + } + + .informer-details { + font-size: 4rem; + margin-top: 5rem; + } + } + } +} + +@keyframes errorAnimation { + 0% { + display: block; + -webkit-transform: scale(0, 0); + -moz-transform: scale(0, 0); + -ms-transform: scale(0, 0); + -o-transform: scale(0, 0); + transform: scale(0, 0); + } + 50% { + -webkit-transform: scale(1.5, 1.5); + -moz-transform: scale(1.5, 1.5); + -ms-transform: scale(1.5, 1.5); + -o-transform: scale(1.5, 1.5); + transform: scale(1.5, 1.5); + } + 100% { + -webkit-transform: scale(1, 1); + -moz-transform: scale(1, 1); + -ms-transform: scale(1, 1); + -o-transform: scale(1, 1); + transform: scale(1, 1); + } +} + +::-webkit-input-placeholder { + color: @program-input-placeholder-color; +} + +@keyframes checkbox-animation { + 0% { + display: block; + -webkit-transform: scale(0, 0); + -moz-transform: scale(0, 0); + -ms-transform: scale(0, 0); + -o-transform: scale(0, 0); + transform: scale(0, 0); + } + 50% { + -webkit-transform: scale(1.5, 1.5); + -moz-transform: scale(1.5, 1.5); + -ms-transform: scale(1.5, 1.5); + -o-transform: scale(1.5, 1.5); + transform: scale(1.5, 1.5); + } + 100% { + -webkit-transform: scale(1, 1); + -moz-transform: scale(1, 1); + -ms-transform: scale(1, 1); + -o-transform: scale(1, 1); + transform: scale(1, 1); + } +} + +.tooltip { + font-family: inherit; + + &.tr-blocked-tooltip { + + .tooltip-inner { + .flex-container-direction(column); + background-color: #fcfdf8; + border: 1px solid @history-transaction-blocked-border-color; + border-radius: 2rem; + box-shadow: @box-shadow; + color: #e9301d; + max-width: initial; + padding: 1rem 3rem 2.5rem; + + .tr-blocked { + font-size: 3rem; + font-weight: 600; + line-height: 6rem; + white-space: nowrap; + } + + .tr-message { + font-size: 3.25rem; + font-weight: 300; + line-height: 3.5rem; + white-space: nowrap; + } + + .tr-date { + font-size: 3.5rem; + font-weight: 400; + line-height: 3.5rem; + white-space: nowrap; + } + } + + .tooltip-arrow { + position: absolute; + width: 2.5rem; + height: 2.5rem; + background-color: white; + border: 1px solid @history-transaction-blocked-border-color; + border-radius: 0.5rem; + transform: rotateZ(45deg); + } + + &.top { + margin-top: -1.5rem; + + .tooltip-arrow { + bottom: 0; + left: 50%; + border-top-color: transparent; + border-left-color: transparent; + margin-left: -5px; + } + } + } + + &.general-tooltip { + padding: 0; + margin-bottom: 0.5rem; + + &.dashboard-tooltip { + margin-bottom: 0; + + .tooltip-inner { + transform: translateY(50%); + } + } + + &.safes-tooltip { + .tooltip-inner { + max-width: 35rem; + text-align: center; + } + } + + &.market-tooltip { + margin-top: -2rem; + + .tooltip-inner { + text-align: center !important; + } + } + + &.history-tooltip { + .tooltip-inner { + margin-right: -12rem; + } + } + + &.test-network-tooltip { + .tooltip-inner { + color: @program-light-color; + } + } + + .tooltip-inner { + background: white; + border-radius: 2rem; + box-shadow: @box-shadow; + color: @program-exuding-color; + font-size: 2.75rem; + line-height: 3.5rem; + padding: 1rem 2.5rem; + text-align: left; + word-break: break-word; + //white-space: nowrap; + max-width: 100rem; + font-weight: 500; + } + + .tooltip-arrow { + display: none; + } + } + + &.network-info-tooltip { + margin-bottom: 0.5rem; + padding: 0; + + .tooltip-inner { + background: white; + border-radius: 2.5rem; + box-shadow: @box-shadow; + color: @program-exuding-color; + font-size: 3.25rem; + line-height: 4rem; + max-width: 72rem; + padding: 2.5rem 3.5rem; + word-break: break-word; + + .network-info-tooltip-wrapper { + padding: 0.5rem; + + .network-info-item { + padding: 2.5rem 0; + + &:first-child { + padding-top: 0; + } + + &:last-child { + padding-bottom: 0; + } + } + } + } + + .tooltip-arrow { + display: none; + } + } + + &.safe-alias-tooltip { + padding: 0; + margin-top: -2rem; + margin-left: 5.5rem; + + .tooltip-inner { + background: white; + border-radius: 3rem; + box-shadow: @box-shadow; + color: @program-exuding-color; + font-size: 3rem; + line-height: 4rem; + text-align: left; + padding: 2rem 3rem; + white-space: normal; + word-break: break-word; + max-width: 50rem; + min-width: 10rem; + } + + .tooltip-arrow { + bottom: -2.5rem !important; + right: 5rem !important; + left: initial !important; + width: 0; + height: 0; + border: none; + border-top: 2.5rem solid white; + border-right: 2.5rem solid transparent; + } + } + + + + &.password-info-window { + left: 50% !important; + transform: translateX(-50%); + + .tooltip-inner { + background-color: white; + box-shadow: @box-shadow; + max-width: inherit; + padding: 9rem 1rem 7rem; + width: 170rem; + + .master-pass-tooltip-header { + + h2 { + color: @program-exuding-color; + font-size: 5rem; + font-weight: 300; + line-height: 5rem; + margin: 0 0 9rem; + } + } + + .master-pass-tooltip-content { + .flex-container; + .flex-container-alignment(flex-start, space-between); + color: @program-exuding-color; + + .master-pass-tooltip-icon-wrapper { + .flex-container-direction(column); + .flex-container-alignment(center, flex-start); + flex: 1; + padding: 0 7.5rem; + + .master-pass-tooltip-icon { + .icon-sizing(20rem, 20rem, 0, -2rem); + font-size: 24rem; + } + + span { + font-size: 3rem; + line-height: 3.5rem; + } + } + } + + .master-pass-tooltip-footer { + color: @program-light-color; + margin-top: 6.5rem; + + span { + display: block; + font-size: 2.75rem; + line-height: 3.5rem; + } + } + } + + .tooltip-arrow { + display: none; + } + } + + &.in { + opacity: 1; + } +} + +.indicator-number { + display: inline-flex; + align-self: center; + justify-content: center; + border-radius: 2.5rem; + border: 1px solid; + font-size: 3rem; + line-height: 4rem; + height: 4.5rem; + min-width: 6rem; + padding: 0 1rem; + + &.attention { + padding: 0; + max-width: 4.5rem; + min-width: 4.5rem; + + .base-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + } + } +} + +.transaction-status-indicator { + position: relative; + height: 6rem; + width: 6rem; + + .status-svg { + transform: rotate(-90deg); + overflow: visible; + z-index: 10; + + .circle-blank { + stroke: @program-transaction-status-inner-color; + } + + .status-graph { + transition: stroke-dashoffset 400ms ease-in-out; + stroke-dasharray: 15.70796327rem; + stroke-dashoffset: 10rem; + + &.income { + stroke: @program-transaction-status-pending-inner-color; + } + + &.outgoing { + stroke: @program-transaction-status-sending-inner-color; + } + } + } + + .status-inner { + .flex-container; + .flex-container-alignment(center, center); + position: absolute; + top: 0; + left: 0; + color: @program-transaction-status-inner-color; + height: 100%; + width: 100%; + + .status-icon { + .icon-sizing(6rem, 6rem, -3rem, -4rem); + + &.income { + color: @program-transaction-status-pending-inner-color; + } + + &.outgoing { + color: @program-transaction-status-sending-inner-color; + } + + &.rotate-icon { + transform: rotateX(180deg); + } + } + } + + .mined-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + position: absolute; + top: -1.5rem; + left: -2rem; + color: @program-mined-icon-color; + } +} + +.filter-wrapper-parent{ + min-height: 8.25rem; +} + +.filter-wrapper { + .flex-container; + background: rgba(255, 255, 255, 0.6); + border: 1px solid @program-tab-border-color; + border-radius: 3rem; + padding: 0 8rem 9rem; + min-height: 8.25rem; + height: auto; + max-width: inherit; + min-width: 28rem; + width: 100%; + + @media screen and (max-width: 1160px) { + padding: 0 10rem 9rem; + } + + @media screen and (min-width: 1161px) and (max-width: 1340px) { + padding: 0 17rem 9rem; + } + + @media screen and (min-width: 1341px) { + padding: 0 25rem 9rem; + } + + .filter-inner-block { + text-align: center; + width: 50%; + + .filter-field-group { + .flex-container-direction(row); + .flex-container-alignment(flex-start, flex-start); + margin-top: 8rem; + + .filter-label { + .flex-container; + .flex-container-alignment(center, flex-end); + flex-shrink: 0; + color: @program-dark-color; + font-size: 3.5rem; + font-weight: 600; + height: 7rem; + line-height: 3.5rem; + margin: 0; + padding-right: 3rem; + text-align: right; + width: 29rem; + } + + .filter-field, .filter-field-wrapper { + + &.general-select { + width: calc(~'100% - 29rem') !important; + } + + @media screen and (max-width: 1160px) { + max-width: 82rem; + } + + @media screen and (min-width: 1161px) and (max-width: 1340px) { + max-width: 99rem; + } + + @media screen and (min-width: 1341px) { + max-width: 125rem; + } + } + + .filter-field-wrapper { + .flex-container; + width: 100%; + + .filter-field:not(:last-child) { + margin-right: 5rem; + } + } + + &:hover, .focused-line, &.focused-line { + + &:not(.no-hover) { + + .filter-label { + color: @program-hover-color; + } + + .filter-field { + border-bottom-color: @program-hover-color; + color: @program-hover-color; + + .dropdown-toggle { + border-bottom-color: @program-hover-color; + color: @program-hover-color; + } + + input::-webkit-input-placeholder, &::-webkit-input-placeholder { + color: @program-input-placeholder-hover-color; + } + } + + .general-input-wrapper, &.general-input-wrapper { + border-bottom-color: @program-hover-color; + color: @program-hover-color; + + .input-addon { + color: @program-hover-color; + } + + .autocomplete-caret { + color: @program-hover-color; + } + } + } + } + } + + .filter-buttons { + .flex-container-direction(row); + .flex-container-alignment(center, flex-start); + margin-left: 29rem; + margin-top: 10.5rem; + + .filter-clear-btn { + .general-button(25rem, 6rem); + background-color: white; + border: 1px solid @program-filter-button-border-color; + color: @program-label-color; + font-size: 3.5rem; + margin-right: 5rem; + + .base-icon { + .icon-sizing(4rem, 4rem, -4rem, -5.5rem); + margin-right: 1rem; + } + } + + .filter-close-btn { + .general-button(25rem, 6rem); + background-color: white; + border: 1px solid @program-filter-button-border-color; + color: @program-label-color; + font-size: 3.5rem; + } + } + + &:first-child { + padding-right: 15rem; + } + + &:last-child { + padding-right: 10rem; + padding-left: 5rem; + } + } +} + +.general-search-wrapper-parent { + display: flex; + + &.open { + + .search-input { + padding-left: 1rem; + width: 42rem; + } + } +} + +.general-filter-btn { + .flex-container-direction(row); + .flex-container-alignment(center, center); + background: white; + border: 1px solid @program-tab-border-color; + border-radius: 4rem; + color: @program-dark-color; + font-size: 3.5rem; + height: 8.25rem; + width: 28rem; + + &:hover, &:active { + background: @program-options-bg-hover-color; + cursor: pointer; + } +} + +.general-filter-clear { + .flex-container-direction(row); + .flex-container-alignment(center, center); + background: white; + border: 1px solid @program-tab-border-color; + border-radius: 4rem; + color: @program-clear-button-color; + font-size: 3.5rem; + height: 8.25rem; + margin-left: 3.25rem; + padding: 0 3rem; + + .base-icon { + .icon-sizing(5rem, 5rem, -3.25rem, -4.75rem); + margin-bottom: 0.5rem; + } + + &:hover, &:active, &.open { + background: @program-options-bg-hover-color; + cursor: pointer; + + .base-icon { + color: @program-clear-button-hover-color; + } + } +} + +.general-search-wrapper { + .flex-container-direction(row); + .flex-container-alignment(center, center); + background: white; + border: 1px solid @program-tab-border-color; + border-radius: 4rem; + color: @program-main-color; + font-size: 3.5rem; + font-weight: 300; + height: 8.25rem; + padding: 0 3rem; + + .search-icon { + .icon-sizing(7rem, 7rem, -2.25rem, -3.75rem); + } + + .search-input { + display: block; + background: transparent; + border: none; + padding: 0; + width: 0; + transition: all 0.5s linear; + } + + &:hover:not(.open) { + background: @program-options-bg-hover-color; + cursor: pointer; + } + + &.open { + + .search-input { + padding-left: 1rem; + width: 42rem; + } + } +} + +.label-hint { + position: relative; + padding-right: 4.5rem !important; + + .label-hint-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + position: absolute; + top: 0; + right: 1rem; + color: @program-label-info-color; + cursor: pointer; + } +} + +text-dropdown, place-dropdown, contacts-dropdown, circle-show { + display: flex; +} + +.contact-btn { + .flex-container-direction(row); + .flex-container-alignment(center, center); + align-self: flex-start; + background: transparent; + border: 1px solid @program-table-button-border-color; + border-radius: 16rem; + color: @program-main-color; + font-size: 3rem; + height: 4.5rem; + + .base-icon { + .icon-sizing(4rem, 4rem, -3rem, -4rem); + color: @program-table-icon-color; + font-size: 12rem; + } + + .contact-btn-text { + font-size: 3rem; + line-height: 4rem; + padding: 0 0.5rem; + } + + &:hover { + border-color: @program-table-button-border-hover-color; + cursor: pointer; + color: @program-hover-color; + + .base-icon { + color: @program-table-button-icon-hover-color; + } + } +} + +.sLongLoading > span{ + opacity: 0; +} + +.general-select.bootstrap-select > select { + display: none !important; +} \ No newline at end of file diff --git a/src/gui/qt-daemon/html/less/css/source/header.less b/src/gui/qt-daemon/html/less/css/source/header.less new file mode 100644 index 00000000..b232f2f6 --- /dev/null +++ b/src/gui/qt-daemon/html/less/css/source/header.less @@ -0,0 +1,177 @@ +@import "../variables"; +@import "mixins"; + +header { + min-height: 36.5rem; + min-width: @min-width; + padding: 0 8rem 5.5rem; + + .header-top-wrapper { + .flex-container; + .flex-container-alignment(center, space-between); + min-height: 22rem; + max-height: 22rem; + + .header-options-wrapper { + .flex-container; + .flex-container-alignment(center, flex-start); + height: 6rem; + + .header-lock-btn { + .icon-sizing(5rem, 8rem, -3.5rem, -3rem); + color: @program-dark-color; + cursor: pointer; + margin-right: 10.5rem; + } + + .header-test-network { + color: @program-light-color; + font-size: 3.5rem; + font-weight: 300; + line-height: 6rem; + margin-right: 9.5rem; + .base-icon { + color: @program-light-color; + } + } + + .header-status { + font-size: 3.5rem; + font-weight: 300; + line-height: 6rem; + + &.online { + color: @program-online-color; + } + + &.offline { + color: @program-offline-color; + } + + &.loading { + color: @program-light-color; + } + + &.sync-wrapper { + .flex-container; + .flex-container-alignment(center, center); + color: @program-online-color; + + .sync { + padding-right: 4rem; + } + + progress[value] { + -webkit-appearance: none; + appearance: none; + width: 36.5rem; + height: 0.75rem; + + &::-webkit-progress-bar{ + background-color: @program-progress-bar-bg-color; + border-radius: 1rem; + } + + &::-webkit-progress-value{ + background-color: @program-progress-bar-fill-color; + border-radius: 1rem; + } + } + + .sync-percent { + padding-left: 2.5rem; + opacity: 0.5; + } + } + } + } + + .header-logo-wrapper { + + .header-logo { + display: block; + background: url("../img/logo.svg") center no-repeat; + background-size: 100%; + height: 7.5rem; + width: 50rem; + } + } + } + + .header-nav-wrapper { + .flex-container; + min-height: 10rem; + max-height: 10rem; + + .sidebar-nav { + .flex-container; + flex-grow: 1; + + .nav-item { + border-top: 1px solid @program-header-border-color; + border-bottom: 1px solid @program-header-border-color; + border-right: 1px solid @program-header-border-color; + flex-grow: 1; + text-align: center; + height: 9rem; + box-sizing: content-box; + + .nav-item-link { + display: flex; + justify-content: center; + background: white; + border: none; + color: @program-header-text-color; + margin: 0; + padding: 1.5rem 0; + font-size: 4.25rem; + line-height: 6rem; + width: 100%; + + .indicator-number { + border-color: @program-header-indicator-border-color; + color: @program-header-indicator-text-color; + margin-left: 2.5rem; + margin-right: -2rem; + } + + &:disabled { + color: @program-header-text-blocked-color; + } + } + + &:first-child { + border-left: 1px solid @program-header-border-color; + border-radius: 10rem 0 0 10rem; + + .nav-item-link { + border-radius: 9.75rem 0 0 9.75rem; + } + } + + &:last-child { + border-radius: 0 10rem 10rem 0; + + .nav-item-link { + border-radius: 0 9.75rem 9.75rem 0; + } + } + + &:hover:not(.active) { + + .nav-item-link:not(:disabled) { + background: @program-header-bg-hover-color; + } + } + + &.active { + + .nav-item-link { + background: @program-header-bg-active-color; + border-color: @program-header-bg-active-color; + } + } + } + } + } +} diff --git a/src/gui/qt-daemon/html/less/css/source/highcharts.less b/src/gui/qt-daemon/html/less/css/source/highcharts.less new file mode 100644 index 00000000..3bc7ffe7 --- /dev/null +++ b/src/gui/qt-daemon/html/less/css/source/highcharts.less @@ -0,0 +1,83 @@ +@import "../variables"; + +.highcharts-container{ + width: 100%!important; +} + +.highcharts-background { + fill-opacity: 0; +} + +.highcharts-tooltip { + + span { + display: flex; + flex-direction: column; + justify-content: center; + text-align: center; + + b { + text-align: center; + } + } +} + +.highcharts-input-group { + display: none; +} + +.highcharts-range-selector-buttons { + visibility: hidden; +} + +.highcharts-scrollbar-thumb{ + opacity: 1; + stroke: @highcharts-scrollbar-color; +} + +.highcharts-scrollbar-arrow{ + display: none; +} + +.highcharts-scrollbar-rifles{ + stroke: @highcharts-scrollbar-color; +} + +.highcharts-axis.highcharts-xaxis { + stroke: @highcharts-axis-line-color; + + .highcharts-tick { + stroke: @highcharts-axis-line-color; + } + + .highcharts-axis-line { + stroke: @highcharts-axis-line-color; + } +} + +.highcharts-grid.highcharts-xaxis-grid.highcharts-navigator-xaxis{ + stroke-opacity: 0; +} + +.highcharts-label-box.highcharts-tooltip-box { + filter: url("#dropShadow"); + + &:nth-child(1) { + fill-opacity: 0; + stroke-opacity: 0; + } + + &:nth-child(2) { + fill-opacity: 0; + stroke-opacity: 0; + } + + &:nth-child(3) { + fill-opacity: 0; + stroke-opacity: 0; + } +} + +feFlood { + flood-color: #1f360b; +} \ No newline at end of file diff --git a/src/gui/qt-daemon/html/less/css/source/history.less b/src/gui/qt-daemon/html/less/css/source/history.less new file mode 100644 index 00000000..047b2bc9 --- /dev/null +++ b/src/gui/qt-daemon/html/less/css/source/history.less @@ -0,0 +1,239 @@ +@import "../variables"; +@import "mixins"; + +#history { + padding: 2.5rem 8rem; +} + +.history-options { + .flex-container-direction(row); + .flex-container-alignment(center, flex-start); + position: relative; + margin-bottom: 7rem; + + .history-search { + margin-left: 3.25rem; + } +} + +.history-table { + margin-bottom: 3rem; + + table { + + thead { + + tr { + font-size: 3.25rem; + } + } + + tr { + + th:first-child { + padding-left: 0; + padding-right: 10rem; + text-align: center; + } + + td:first-child { + position: relative; + padding-left: 0; + padding-right: 10rem; + + &::after { + content: ""; + position: absolute; + top: 0; + bottom: 0; + left: 0; + } + + &.history-marker::after { + border-left: 1rem solid @marker-light-green; + } + } + + td:last-child { + width: 14rem; + } + + &.transaction-blocked { + background-color: @history-transaction-blocked-border-color !important; + color: @history-transaction-blocked-text-color; + + .transaction-status-indicator { + + .status-graph { + + &.income { + stroke: @history-transaction-blocked-status-income-color !important; + } + + &.outgoing { + stroke: @history-transaction-blocked-status-outgoing-color !important; + } + } + + .status-inner { + + .base-icon.income { + color: @history-transaction-blocked-status-income-color !important; + } + + .base-icon.outgoing { + color: @history-transaction-blocked-status-outgoing-color !important; + } + } + } + + .safe-address { + + .safe-address-wrap { + color: @history-transaction-blocked-text-color; + + .safe-address-text { + background: -webkit-linear-gradient(left, @history-transaction-blocked-text-color 0, @history-transaction-blocked-text-color 75%, transparent 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + } + } + } + + .safe-alias { + + .safe-alias-btn { + background-color: fade(@history-transaction-blocked-text-color, 20%); + border-color: @history-transaction-blocked-alias-color; + color: @history-transaction-blocked-text-color; + } + } + + .history-date { + + &:hover { + color: @history-transaction-blocked-hover-color; + + .base-icon { + color: @history-transaction-blocked-hover-color; + } + } + } + + .history-safe { + + &:hover { + color: @history-transaction-blocked-hover-color; + } + } + + &:hover { + + .history-date { + + .base-icon { + opacity: 0.6; + } + } + } + } + + &:hover { + + .history-date { + + .base-icon { + opacity: 0.3; + } + } + } + } + } + + .transaction-status-indicator { + margin: 0 auto; + } + + .history-safe { + .flex-container; + .flex-container-alignment(center, flex-start); + + .history-anonym-icon { + .icon-sizing(4rem, 5rem, -4rem, -4.5rem); + margin-right: 2rem; + } + + &:hover { + color: @program-hover-color; + cursor: pointer; + } + } + + .history-date { + .flex-container-alignment(center, flex-start); + display: inline-flex; + + .base-icon { + .icon-sizing(5rem, 5rem, -3.5rem, -4.5rem); + margin-left: 2rem; + opacity: 0; + } + + &:hover { + color: @program-hover-color; + cursor: pointer; + + .base-icon { + color: @program-hover-color; + opacity: 0.3; + } + } + } + + .history-counterparty { + .flex-container-direction(column); + max-width: 75rem; + + .safe-address { + font-size: 3.25rem; + margin-top: 0.75rem; + margin-bottom: 0.75rem; + + .safe-address-wrap { + width: 40rem; + } + + .safe-address-inner { + left: inherit; + right: 0; + width: 150%; + } + } + + alias-display:not(.safe-address-inner-alias) { + display: inline-flex; + + .safe-alias { + margin-top: 0.75rem; + margin-bottom: 0.75rem; + } + } + } + + .history-comment-wrapper { + .flex-container; + + .base-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + + &:hover { + cursor: pointer; + } + } + } + + .contact-btn { + margin-top: 1.5rem; + padding: 0 1rem; + } +} \ No newline at end of file diff --git a/src/gui/qt-daemon/html/less/css/source/mining.less b/src/gui/qt-daemon/html/less/css/source/mining.less new file mode 100644 index 00000000..3ed54522 --- /dev/null +++ b/src/gui/qt-daemon/html/less/css/source/mining.less @@ -0,0 +1,296 @@ +@import "../variables"; +@import "mixins"; + +#mining { + padding: 2.5rem 8rem; + + .main-options-wrapper { + + .mining-options { + margin-bottom: 8rem; + } + } + + .calculate-options { + .flex-container; + .flex-container-alignment(center, space-between); + color: @program-main-color; + height: 30.5rem; + padding: 2.5rem 11rem 0; + + .calculate-tile { + .flex-container; + font-size: 3.5rem; + + label { + .flex-container; + .flex-container-alignment(center, flex-end); + font-weight: 600; + height: 7rem; + line-height: 4.5rem; + margin-bottom: 0; + max-width: 45rem; + padding-right: 3rem; + text-align: end; + } + + .general-input-wrapper { + width: 42rem; + } + + .calculate-mining-btn { + border: 1px solid @mining-range-border-color; + height: 8rem; + width: 44rem; + font-size: 4rem; + margin-left: 3rem; + } + + &:hover, &.focused-line { + + label { + color: @program-hover-color; + } + + .general-input-wrapper { + border-bottom-color: @program-hover-color; + + .general-input { + color: @program-hover-color; + } + + ::-webkit-input-placeholder { + color: @program-input-placeholder-hover-color; + } + } + } + } + } + + .chart-wrapper { + padding-top: 1rem; + padding-bottom: 5rem; + transition: all 0.5s linear; + overflow: hidden; + + .chart-label { + .flex-container; + .flex-container-alignment(center, center); + position: relative; + color: @program-dark-color; + font-size: 5rem; + font-style: italic; + font-weight: 300; + padding-top: 5rem; + padding-bottom: 1rem; + + .base-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + top: -1rem; + right: -1rem; + color: @program-label-info-color; + } + } + } + + .mining-select-wrapper { + .flex-container; + .flex-container-alignment(center, space-between); + flex-grow: 1; + + .mining-select { + .flex-container; + + .dropdown-toggle { + border-bottom: none; + color: @program-hover-color; + font-size: 5rem; + line-height: 6rem; + padding: 0 3rem 0 0; + + .caret { + color: @program-hover-color; + } + } + + .dropdown-menu { + border-radius: 2rem; + min-width: 44rem; + width: 100%; + } + + &.mining-safe { + padding-left: 5rem; + } + + &.mining-view { + padding-left: 5rem; + padding-right: 6rem; + + .dropdown-menu { + right: 0; + left: auto; + } + } + } + } + + .mined-empty { + .flex-container; + .flex-container-alignment(center, center); + color: @program-empty-color; + font-size: 3.75rem; + height: 35rem; + } + + .mined-statistics { + padding: 3rem 0; + + .mined-statistics-options { + .flex-container; + .flex-container-alignment(flex-start, space-between); + padding: 7rem 7rem 0; + + .chart-range-wrapper { + .flex-container; + .flex-container-alignment(center, space-between); + margin-top: 1rem; + + .chart-range-group { + .flex-container; + .flex-container-alignment(center, center); + color: @program-dark-color; + font-size: 3rem; + + .chart-range-selector { + .flex-container; + margin: 0 2.5rem; + padding: 0; + + li { + border: 1px solid @mining-range-border-color; + color: @mining-range-text-color; + line-height: 5.5rem; + height: 6rem; + width: 13rem; + text-align: center; + list-style-type: none; + + &:first-child { + border-radius: 3rem 0 0 3rem; + width: 13.5rem; + } + + &:not(:first-child) { + border-left: none; + } + + &:last-child { + border-radius: 0 3rem 3rem 0; + width: 13.5rem; + } + } + + .active { + background: white; + color: @program-dark-color; + } + } + + &:first-child { + margin-right: 8.5rem; + + @media screen and (max-width: 1150px) { + margin-right: 2.5rem; + } + } + } + } + + .total-mined-chart { + color: @program-dark-color; + font-size: 5rem; + font-style: italic; + font-weight: 300; + line-height: 7rem; + white-space: nowrap; + text-align: right; + } + + .total-mined-table { + color: @program-dark-color; + font-size: 5rem; + font-style: italic; + font-weight: 300; + line-height: 7rem; + text-align: right; + width: 100%; + } + } + } + + .statistics-table { + margin: 8rem 2.5rem 2.5rem; + overflow: hidden; + transition: height 1s; + + table { + + tbody { + + tr { + + td { + width: 33.33%; + + .order-icon { + opacity: 0.6; + } + + &:first-child { + position: relative; + padding-left: 8rem; + + &::after { + content: ""; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + border-left: 1rem solid @marker-light-green; + } + } + } + } + } + } + } + + .pagination-wrapper { + margin: 5rem 2.5rem 3rem; + + .pagination { + + .pages { + color: @program-pagination-text-inactive-color; + } + + .next-page, .prev-page { + background-color: transparent; + border-color: @program-main-color; + color: @program-main-color; + } + } + } + + #chart-calculate { + width: 100%; + height: 70rem; + } + + #chart-statistics{ + width: 100%; + height: 142rem; + } +} \ No newline at end of file diff --git a/src/gui/qt-daemon/html/less/css/source/mixins.less b/src/gui/qt-daemon/html/less/css/source/mixins.less new file mode 100644 index 00000000..7066c54e --- /dev/null +++ b/src/gui/qt-daemon/html/less/css/source/mixins.less @@ -0,0 +1,113 @@ +@import "../variables"; + +.flex-container { + display: -webkit-flex; + display: flex; +} + +.flex-container-direction(@direction) { + .flex-container; + -webkit-flex-direction: @direction; + flex-direction: @direction; +} + +.flex-container-alignment(@align-items, @justify-content) { + -webkit-align-items: @align-items; + align-items: @align-items; + -webkit-justify-content: @justify-content; + justify-content: @justify-content; +} + +.general-button(@width, @height) { + .flex-container; + .flex-container-alignment(center, center); + background: fade(white, 40%); + border: none; + border-radius: 10rem; + padding: 0 3rem; + height: @height; + width: @width; + + &:hover { + background: fade(white, 55%); + } + + &:active { + background: fade(white, 55%); + } +} + +.icon-sizing(@height, @width, @top, @left) { + width: @width; + height: @height; + + &:before { + top: @top; + left: @left; + } +} + +.menu-list(@top, @left, @right, @width) { + position: absolute; + top: @top; + left: @left; + right: @right; + min-width: @width; + padding: 0; + margin: 0; + border: none; + box-shadow: @box-shadow; + border-radius: 2rem; + overflow: hidden; + + li { + width: 100%; + + button { + .flex-container; + .flex-container-alignment(center, flex-start); + background: transparent; + border: none; + color: @program-exuding-color; + font-size: 3.5rem; + height: 8.25rem; + padding-left: 3rem; + text-align: left; + width: 100%; + white-space: nowrap; + + &:disabled { + color: @program-light-color; + } + + &:hover { + + &:not(:disabled) { + background: @program-select-hover-color; + cursor: pointer; + } + } + } + + &:first-child { + + button { + border-top-left-radius: 2rem; + border-top-right-radius: 2rem; + } + } + + &:last-child { + + button { + border-bottom-left-radius: 2rem; + border-bottom-right-radius: 2rem; + } + } + } + + .menu-divider { + border-top: 1px solid @program-divider-color; + margin: 0 3.5rem; + } +} \ No newline at end of file diff --git a/src/gui/qt-daemon/html/less/css/source/modal-forms.less b/src/gui/qt-daemon/html/less/css/source/modal-forms.less new file mode 100644 index 00000000..4242e998 --- /dev/null +++ b/src/gui/qt-daemon/html/less/css/source/modal-forms.less @@ -0,0 +1,2330 @@ +@import "../variables"; +@import "mixins"; + +.modal-main-wrapper { + position: absolute; + top: 0; + left: 0; + background-image: url("../img/bg_blue.jpg"); + background-size: cover; + opacity: 0; + height: 100%; + width: 100%; + transition: 1s; + z-index: 2; + + .modal-dialog { + .flex-container; + .flex-container-alignment(center, center); + margin: 0; + min-height: 100%; + transform: translate(0,0) !important; + transition: 0s !important; + width: auto; + + .modal-content { + box-shadow: none; + background-color: transparent; + border: none; + } + } + + .modal-form-wrapper { + .flex-container-direction(column); + position: relative; + background: fade(white, 60%); + border-radius: 3rem; + box-shadow: @modal-form-shadow; + transition: opacity 1s; + + .modal-form-header { + position: relative; + background: @program-modal-header-color; + border-radius: 3rem 3rem 0 0; + height: 10rem; + + .modal-form-header-icon { + position: absolute; + top: -8.5rem; + left: 50%; + transform: translateX(-50%); + background: @program-modal-header-color; + border-top-left-radius: 16rem; + border-top-right-radius: 16rem; + text-align: center; + width: 32rem; + height: 16rem; + z-index: 1; + + .base-icon { + .icon-sizing(7rem, 7rem, -2.5rem, -3.5rem); + color: @program-dark-color; + top: 2.5rem; + + &.wider-icon { + .icon-sizing(7rem, 10rem, -2.5rem, -2rem); + } + } + } + + .modal-form-header-title { + position: relative; + color: @program-dark-color; + font-size: 4.75rem; + font-weight: 300; + line-height: 10rem; + text-align: center; + width: 100%; + z-index: 2; + + .modal-form-header-arrow { + .icon-sizing(2rem, 2rem, -5rem, -6rem); + margin-left: 2rem; + margin-bottom: 1rem; + } + } + + .modal-form-header-close { + .flex-container; + position: absolute; + top: 50%; + transform: translateY(-50%); + right: 4rem; + height: 4rem; + width: 4rem; + margin-top: 0.5rem; + z-index: 3; + + button { + .flex-container; + background: transparent; + border: none; + color: @program-modal-header-close-color; + padding: 0; + + .base-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + } + } + } + + &.modal-form-header-transparent { + background: transparent; + } + + &.closed-panel { + border-radius: 3rem; + + .modal-form-header-title { + + .modal-form-header-arrow { + transform: rotateX(180deg); + } + } + } + } + + &:first-child { + margin-top: 10rem; + } + + &:not(:first-child) { + margin-top: 1rem; + } + + &:last-child { + margin-bottom: 10rem; + } + } + + &.in-remove { + transition: 0.5s !important; + } + + &.ng-leave { + display: none !important; + } +} + +.modalTopClassBackground { + + .modal-form-wrapper { + opacity: 0.2; + } +} + +.general-form { + .flex-container-direction(column); + .flex-container-alignment(center, center); + + .general-form-header { + color: @program-dark-color; + font-size: 4.75rem; + text-align: center; + } + + .general-form-progress-bar-wrapper { + margin: 6rem 0; + width: 100%; + + .general-form-progress-bar { + background-color: @create-safe-progress-bar-bg-color; + border-radius: 1rem; + height: 1rem; + width: 100%; + + .progress-bar-fill { + background-color: @create-safe-progress-bar-fill-color; + border-radius: 1rem; + height: 1rem; + width: 25%; + transition: all 0.5s linear; + } + } + + .general-form-step-container { + .flex-container; + .flex-container-alignment(center, space-between); + height: 15rem; + width: 100%; + + .general-form-step { + color: @create-safe-progress-bar-step-color; + flex-grow: 1; + font-size: 3.5rem; + text-align: center; + + &.active { + color: @program-label-color; + font-weight: 600; + } + + &.passed { + color: @program-label-color; + } + } + } + } + + .general-form-field-group { + width: 100%; + + &.field-group-vertical { + .flex-container-direction(column); + .flex-container-alignment(center, center); + margin-top: 5rem; + + &:first-child { + margin-top: 0; + } + + .general-input, .general-input-wrapper, .general-textarea { + margin-top: 4rem; + + &.bigger-indent { + margin-top: 7rem; + } + } + + .general-range-wrapper { + margin-top: 5rem; + } + + .field-group-error { + display: block; + align-self: flex-start; + color: @error-color; + font-size: 3.25rem; + font-style: italic; + margin-top: 2rem; + } + } + + &.field-group-horizontal { + .flex-container-direction(row); + .flex-container-alignment(flex-start, flex-start); + margin-top: 7rem; + + .field-group-label { + .flex-container-direction(column); + .flex-container-alignment(flex-end, center); + height: 7rem; + line-height: 3.5rem; + padding-right: 3rem; + text-align: right; + } + + &:hover { + + &:not(.no-hover) { + + .field-group-label { + color: @program-hover-color; + + .field-group-label-info { + color: @program-input-placeholder-hover-color + } + } + + .general-input, .general-textarea { + border-bottom-color: @program-hover-color; + color: @program-hover-color; + + &::-webkit-input-placeholder { + color: @program-input-placeholder-hover-color; + } + } + + .general-input-wrapper { + border-bottom-color: @program-hover-color; + color: @program-hover-color; + + .eye-icon { + color: @program-input-placeholder-hover-color; + + &.open { + color: @program-hover-color; + } + } + + .autocomplete-caret { + color: @program-hover-color; + } + } + + .general-select { + + .dropdown-toggle { + border-bottom-color: @program-hover-color; + color: @program-hover-color; + + .caret { + color: @program-hover-color; + } + } + } + } + } + } + + &.field-group-review { + .flex-container-direction(row); + .flex-container-alignment(flex-start, center); + border-bottom: 1px solid @program-modal-divider-color; + font-size: 3.5rem; + padding: 2rem 0; + line-height: 5.5rem; + + .field-group-label { + color: @program-dark-color; + font-weight: 600; + padding-right: 10rem; + text-align: left; + min-width: 50%; + width: 50%; + } + + .field-group-description { + color: @program-main-color; + padding-right: 2rem; + min-width: 50%; + width: 50%; + word-break: break-word; + } + + .field-group-error { + display: block; + align-self: flex-start; + color: @error-color; + font-size: 3.25rem; + font-style: italic; + margin-top: 2rem; + } + + &.active-line { + background: fade(@program-modal-active-line-color, 20%); + } + + &:last-child { + border-bottom: none!important; + } + } + + &.field-group-review-full { + .flex-container-direction(column); + .flex-container-alignment(center, center); + color: @program-dark-color; + font-size: 4rem; + margin-top: 10rem; + + .review-description { + color: @program-hover-color; + font-size: 3.5rem; + } + } + + &.field-group-review-full-second { + .flex-container-direction(row); + .flex-container-alignment(center, center); + color: @program-dark-color; + font-size: 4rem; + + .transaction-status-indicator{ + margin-right: 3rem; + } + } + + &.need-master-password { + margin-top: 13rem; + margin-bottom: 4rem; + max-width: 95rem; + } + + &.field-group-buttons-wrapper { + margin-top: 3.5rem; + + .field-group-dropdown { + margin-right: 3rem; + + & > button { + .flex-container; + .flex-container-alignment(center, center); + background: white; + border: 1px solid @program-button-border-color; + border-radius: 1rem; + color: @program-main-color; + height: 7rem; + min-width: 12rem; + overflow: hidden; + + .dropdown-arrow-icon { + .icon-sizing(2rem, 2rem, -5rem, -6rem); + } + + &:hover { + background: @program-button-hover-bg-color; + } + + &:active { + background: @program-button-active-bg-color; + } + } + + &.open { + + & > button { + background: @program-button-active-bg-color !important; + } + } + } + } + + &.field-group-checkbox-wrapper { + margin-top: 3.5rem; + } + + &.field-group-range-wrapper { + margin-top: 9.5rem; + margin-bottom: 1rem; + + .field-group-label { + margin-top: 2.5rem; + } + } + + &.field-group-extra-icons { + position: relative; + align-self: flex-end; + + .extra-icon-wrapper { + position: absolute; + right: -8.5rem; + margin-top: 7rem; + display: inline-flex; + color: @program-light-color; + + .base-icon { + .icon-sizing(6rem, 6rem, -3rem, -4rem); + cursor: pointer; + } + + &.active { + color: @program-dark-color; + } + + &:hover { + color: @program-dark-color; + } + } + } + + &.bigger-indent { + margin-top: 10rem; + } + + .field-group-label { + color: @program-dark-color; + font-size: 3.5rem; + font-weight: 400; + margin: 0; + text-align: center; + + &.bolder-label { + font-weight: 600; + } + + .field-group-label-info { + color: @program-label-subtext-color; + font-size: 2.75rem; + font-style: italic; + font-weight: 400; + } + } + + .field-group-subgroup { + display: flex; + } + + .field-group-error-wrapper { + .flex-container-direction(column); + width: 100%; + + .field-group-error { + display: block; + color: @error-color; + font-size: 3.25rem; + line-height: 2.75rem; + font-style: italic; + margin-top: 1.5rem; + } + } + } + + .general-form-control-buttons { + .flex-container; + border-radius: 5rem; + margin-top: 7rem; + + .control-button { + background-color: white; + border: 1px solid @program-button-border-color; + color: @program-button-text-color; + font-size: 4rem; + padding: 1.25rem 2.5rem; + min-width: 32.5rem; + + .control-button-info { + display: block; + color: @program-button-subtext-color; + font-size: 2.75rem; + } + + &.larger-button { + min-width: 37.5rem !important; + } + + &.large-button { + min-width: 48rem !important; + } + + &.extra-large-button { + min-width: 65rem !important; + } + + &:first-child { + border-bottom-left-radius: 5rem; + border-top-left-radius: 5rem; + } + + &:not(:last-child) { + border-right: none; + } + + &:last-child { + border-bottom-right-radius: 5rem; + border-top-right-radius: 5rem; + } + + &:hover { + background: @program-button-hover-bg-color; + } + + &:active { + background: @program-button-active-bg-color; + } + + &:disabled { + background: fade(white, 20%); + color: @program-light-color; + } + + &.inactive { + background: fade(white, 20%) !important; + color: @program-light-color; + } + } + } + + .general-form-review-wrapper { + width: 100%; + } + + .general-form-price-description { + .flex-container-direction(column); + .flex-container-alignment(center, center); + margin-top: 12rem; + + .price-text { + color: @program-hover-color; + font-size: 3.5rem; + } + + .price-error { + display: block; + color: @error-color; + font-size: 3.25rem; + font-style: italic; + margin-top: 2rem; + } + } + + .general-form-warning { + .flex-container-direction(column); + .flex-container-alignment(center, center); + color: @error-color; + margin-top: 9rem; + max-width: 77rem; + + .warning-title { + font-size: 4rem; + margin: 1.75rem 0; + text-align: center; + } + + .warning-description { + font-size: 3.25rem; + line-height: 3.75rem; + text-align: center; + } + } + + .focused-line { + + .field-group-label { + color: @program-hover-color; + + .field-group-label-info { + color: @program-input-placeholder-hover-color; + } + } + + .general-input, .general-textarea { + border-bottom-color: @program-hover-color; + color: @program-hover-color; + + &::-webkit-input-placeholder { + color: @program-input-placeholder-hover-color; + } + } + + .general-input-wrapper, &.general-input-wrapper { + border-bottom-color: @program-hover-color; + color: @program-hover-color; + + .eye-icon { + color: @program-input-placeholder-hover-color; + + &.open { + color: @program-hover-color; + } + } + + .autocomplete-caret { + color: @program-hover-color; + } + } + + .general-select { + + .dropdown-toggle { + border-bottom-color: @program-hover-color; + color: @program-hover-color; + + .caret { + color: @program-hover-color; + } + } + } + } +} + +.modal-unlock-app { + + .unlock-app { + .flex-container; + + .unlock-app-btn { + .flex-container-direction(column); + .flex-container-alignment(center, center); + background: transparent; + border: none; + color: @program-exuding-color; + font-size: 8.25rem; + font-weight: 200; + line-height: 20rem; + margin: 0; + padding: 0; + + .base-icon { + .icon-sizing(20rem, 20rem, 0, -2rem); + font-size: 24rem; + } + } + } +} + +.modal-app-blocked { + + .modal-form-wrapper { + width: 114rem; + + .modal-form-body { + padding: 11.5rem 9.5rem 5rem; + } + } + + .general-form { + + .general-form-field-group { + margin-bottom: 9.5rem; + + .field-group-label { + font-size: 4rem; + line-height: 4rem; + } + + .general-input-wrapper { + margin-top: 9rem; + } + } + + .general-form-control-buttons { + margin-top: 3rem; + } + } +} + +.modal-use-master-password { + + .modal-form-wrapper { + width: 114rem; + + .modal-form-body { + padding: 2.5rem 9.5rem 5rem; + } + } + + .general-form { + + .general-form-field-group { + + .general-input-wrapper { + margin-top: 10rem; + } + } + + .use-master-password-description { + position: relative; + color: @program-dark-color; + font-size: 3.5rem; + margin: 10rem auto 5rem; + text-align: center; + + .base-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + position: absolute; + top: -2rem; + right: -4rem; + color: @program-label-info-color; + cursor: pointer; + } + } + + .general-form-control-buttons { + margin-top: 3rem; + } + } +} + +.modal-cancel-master-password { + + .modal-form-wrapper { + width: 156.5rem; + + .modal-form-body { + padding: 1.5rem 9.5rem 6rem; + } + } + + .general-form { + + .general-form-control-buttons { + + .control-button { + max-width: 37.5rem; + } + } + } +} + +.modal-change-master-password { + + .modal-form-wrapper { + width: 114rem; + + .modal-form-body { + padding: 7rem 9.5rem 5rem; + } + } + + .general-form { + + .general-form-field-group.new-password { + margin-top: 7rem; + } + } +} + +.modal-error-report { + + .modal-form-wrapper { + width: 124rem; + + .modal-form-body { + padding: 11rem 9rem 8rem; + } + } + + .general-form { + + .general-form-field-group { + + .error-report-field-wrapper { + .flex-container; + width: 100%; + + .general-select { + margin-right: 3.25rem; + } + + .general-input { + margin-top: 0; + margin-left: 3.25rem; + } + } + + .error-report-indent { + margin-top: 6rem; + } + + &.error-report-indent { + margin-top: 6rem; + } + } + + .error-report-sending { + color: @success-color; + font-size: 3.5rem; + } + + .error-report-success { + color: @success-color; + font-size: 3.5rem; + } + + .error-report-fail { + color: @error-color; + font-size: 3.5rem; + } + + .general-form-control-buttons { + margin-top: 5.5rem; + } + } +} + +.general-form-safe-backup { + .flex-container-direction(column); + .flex-container-alignment(center, center); + + .general-form-safe-description { + .flex-container-direction(column); + color: @program-dark-color; + padding: 0 8rem; + + span { + text-align: center; + } + + .first-description { + font-size: 4.75rem; + line-height: 10rem; + margin-top: 3rem; + } + + .second-description { + font-size: 3.25rem; + line-height: 5rem; + } + + .third-description { + font-size: 4.75rem; + line-height: 7rem; + margin-top: 9rem; + } + } + + .general-form-control-buttons { + margin-top: 4rem; + margin-bottom: 2rem; + + .control-button { + min-width: 75rem; + } + } +} + +.modal-create-safe, .modal-open-smartsafe { + + .modal-form-wrapper { + + .modal-form-body { + padding: 7rem 12rem 9.5rem; + } + + .modal-form-body.start-use-safe { + padding: 6rem 9rem 7rem; + + .general-form { + + .general-form-control-buttons { + margin-top: 0; + + .control-button { + min-width: 75rem; + } + } + } + } + } + + .general-form { + + .general-form-field-group { + margin-top: 4.5rem; + padding-left: 8rem; + padding-right: 8rem; + + .field-group-label { + font-size: 4rem; + line-height: 4rem; + margin-bottom: 1.5rem; + } + + .general-input-wrapper { + margin-top: 7.5rem; + } + } + + .general-form-warning { + margin-top: 2.5rem; + margin-bottom: 6.5rem; + } + + .general-form-control-buttons { + margin-top: 4.5rem; + + .base-icon { + .icon-sizing(5rem, 5rem, -3.5rem, -4.5rem); + animation: checkbox-animation linear 0.3s; + animation-iteration-count: 1; + color: @program-button-done-icon-color; + margin-left: 1.5rem; + margin-bottom: -1rem; + } + } + } +} + +.modal-create-safe { + + .modal-form-wrapper { + width: 136rem; + } +} + +.modal-create-smartsafe { + + .modal-form-wrapper { + width: 220rem; + + .modal-form-body { + padding: 7rem 8.5rem; + } + } + + .general-form { + + .smartsafe-header { + color: @program-dark-color; + font-size: 4rem; + line-height: 12.5rem; + text-align: center; + } + + .smartsafe-description { + color: @program-dark-color; + font-size: 3.25rem; + line-height: 4.25rem; + padding: 0 10rem; + text-align: center; + } + + .smartsafe-phrase { + .flex-container; + .flex-container-alignment(center, space-between); + border-bottom: 1px solid @program-input-border-color; + color: @program-input-text-color; + font-size: 3rem; + padding: 1rem 0; + margin-top: 9rem; + width: 100%; + } + + .smartsafe-buttons { + .flex-container; + margin: 8rem auto; + + .smartsafe-button { + .general-button(auto, 5.75rem); + border: 1px solid @program-button-border-color; + color: @program-button-text-color; + font-size: 3.5rem; + margin: 0 2.5rem; + padding: 0 2.5rem; + min-width: 25rem; + + &:hover { + background: rgba(255, 255, 255, 0.8); + } + + .base-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + margin-right: 1.5rem; + } + + .copied-icon { + animation: checkbox-animation linear 0.5s; + + &:before { + content: 'A' !important; + } + } + } + } + + .smartsafe-checkbox { + margin-top: 4rem; + + .general-checkbox { + + .general-checkbox-text { + font-size: 3.25rem; + } + } + } + + .general-form-control-buttons { + margin-top: 9rem; + + .control-button { + min-width: 60rem; + } + } + } +} + +.modal-open-safe { + + .modal-form-wrapper { + width: 114rem; + + .modal-form-body { + padding: 7rem 9.5rem 9.5rem; + } + } +} + +.modal-open-smartsafe { + + .modal-form-wrapper { + width: 196.5rem; + } + + .general-form { + + .general-form-field-group:not(.phrase-group) { + max-width: 112rem; + } + } +} + +.modal-restore-safe { + + .modal-form-wrapper { + width: 114rem; + + .modal-form-body { + padding: 7rem 9.5rem 9.5rem; + } + } + + .general-form { + + .restored-safe-name { + color: @program-hover-color; + font-size: 6.25rem; + font-weight: 300; + line-height: 6rem; + margin-top: 8rem; + } + + .restored-safe-path { + color: @program-dark-color; + font-size: 3.5rem; + line-height: 3.5rem; + margin-top: 4.5rem; + text-align: center; + word-break: break-word; + } + + .general-form-field-group { + margin-top: 13.5rem; + + .field-group-label { + font-size: 4rem; + line-height: 4rem; + } + + .general-input-wrapper { + margin-top: 9rem; + } + } + + .general-form-control-buttons { + margin-top: 11rem; + } + } +} + +.modal-safe-backup { + + .modal-form-wrapper { + width: 136rem; + + .modal-form-body { + padding: 0 12rem 6.5rem; + } + } +} + +.modal-change-safe-password { + + .modal-form-wrapper { + width: 106.5rem; + + .modal-form-body { + padding: 11rem 9.5rem 5rem; + } + } + + .general-form { + + .general-form-field-group.new-password { + margin-top: 7rem; + } + + .general-form-control-buttons { + margin-top: 2rem; + } + } +} + +.modal-disable-safe { + + .modal-form-wrapper { + width: 101rem; + + .modal-form-body { + padding: 1.5rem 9.5rem 6rem; + } + } + + .general-form { + + .general-form-field-group { + + .field-group-label { + font-size: 4.75rem; + line-height: 5rem; + } + } + + .general-form-control-buttons { + margin-top: 11rem; + } + } +} + +.modal-create-alias { + + .modal-form-wrapper { + width: 106.5rem; + + .modal-form-body { + padding: 7.5rem 9.5rem 5rem; + } + } + + .general-form { + + .general-form-field-group { + + .create-alias-description { + color: @program-dark-color; + font-size: 3.25rem; + line-height: 4rem; + padding: 0 5rem; + margin-top: 0.5rem; + text-align: center; + } + + &.smaller-indent { + margin-top: 3.5rem; + } + } + + .general-input-wrapper { + + .alias-character { + color: @program-dark-color; + font-size: 3.5rem; + margin-right: 1rem; + padding: 1rem 0; + } + + &:hover, &.focused-line { + + .alias-character { + color: @program-hover-color; + } + } + } + + .general-form-price-description { + margin-top: 6rem; + } + } +} + +.modal-transfer-alias { + + .modal-form-wrapper { + width: 106.5rem; + + .modal-form-body { + padding: 10rem 9.5rem 5rem; + } + } +} + +.modal-edit-alias-comment { + + .modal-form-wrapper { + width: 106.5rem; + + .modal-form-body { + padding: 10.5rem 9.5rem 5rem; + } + + .general-form-price-description { + margin-top: 6rem; + } + } +} + +.modal-send-money { + + .modal-form-wrapper { + width: 166.5rem; + + .modal-form-body { + padding: 7rem 18.5rem 8rem 0; + } + } + + .general-form { + @left-padding: 42rem; + + .general-form-field-group { + + .field-group-label { + padding-left: 6rem; + min-width: @left-padding; + width: @left-padding; + } + + &.field-group-checkbox-wrapper { + padding-left: @left-padding; + } + + &.field-group-buttons-wrapper { + padding-left: @left-padding; + + .field-group-dropdown { + + .dropdown-menu { + min-width: 48rem; + } + } + + .dropdown-clock-icon { + .icon-sizing(6rem, 6rem, -3rem, -4rem); + } + + .dropdown-contact-icon { + .icon-sizing(6rem, 6rem, -2.5rem, -3rem); + font-size: 12rem; + } + } + + .send-money-subgroup-left, .send-money-subgroup-right { + .flex-container; + + &:hover { + + &:not(.no-hover) { + + .field-group-label { + color: @program-hover-color; + } + } + } + } + + .send-money-subgroup-left { + + .general-input-wrapper { + width: 45.5rem; + } + } + + .send-money-subgroup-right { + + .field-group-label { + padding-left: 0; + min-width: 38.5rem; + width: 38.5rem; + } + + .general-input-wrapper { + width: 22rem; + } + } + } + + .safe-alias-modal-wrapper { + margin-top: 3.5rem; + padding-left: @left-padding; + width: 100%; + } + + .recent-transaction-table-wrapper { + align-self: flex-start; + margin-top: 3.5rem; + } + + .recent-transactions-table { + max-height: 45.25rem; + width: 100%; + overflow-y: auto; + + table { + color: @program-main-color; + font-size: 3.5rem; + width: 100%; + + tbody { + + tr { + height: 9rem; + + .transaction-status-indicator { + margin-left: 2rem; + } + + &:nth-child(odd) { + background-color: @program-table-header-bg-color; + } + } + } + } + + .no-recent-transactions { + display: block; + color: @program-empty-color; + font-size: 3.5rem; + line-height: 7rem; + text-align: center; + } + } + + .general-form-control-buttons { + margin-top: 10.5rem; + margin-left: 18.5rem; + } + } +} + +.modal-select-contact { + + .modal-form-wrapper { + width: 119rem; + + .modal-form-body { + padding: 8rem 7rem; + } + } + + .general-form { + + .select-contact-options { + .flex-container; + .flex-container-alignment(center, space-between); + margin-bottom: 3rem; + width: 100%; + + .select-contact-groups { + position: relative; + + .groups-btn { + .flex-container; + .flex-container-alignment(center, space-between); + background: fade(white, 40%); + border: 1px solid @program-button-border-color; + border-radius: 4rem; + color: @program-exuding-color; + font-size: 3.75rem; + height: 8.25rem; + padding: 0 4rem; + width: 50rem; + + .general-select { + .dropdown-toggle{ + border-bottom: 0; + } + .dropdown-menu.open { + width: 50rem; + margin-left: -4rem; + margin-top: 2.5rem; + } + } + + .base-icon { + .icon-sizing(2rem, 2rem, -5rem, -6rem); + } + } + + .groups-menu { + .menu-list(10.5rem, 0, 0, 100%); + } + } + + .select-contact-search { + .flex-container-direction(row); + .flex-container-alignment(center, center); + background: fade(white, 40%); + border: 1px solid @program-button-border-color; + border-radius: 4rem; + color: @program-dark-color; + font-size: 3.5rem; + height: 8.25rem; + padding: 0 3rem; + width: 50rem; + + .search-icon { + .icon-sizing(6rem, 8rem, -3rem, -4rem); + } + + .search-input { + display: block; + background: transparent; + border: none; + padding-left: 2rem; + width: 100%; + } + } + } + + .select-contact-list { + max-height: 69rem; + min-height:25.75rem; + overflow-y: auto; + width: 100%; + + .select-contact-item { + .flex-container-direction(row); + .flex-container-alignment(center, center); + border-bottom: 1px solid @program-modal-divider-color; + min-height: 11.5rem; + width: 100%; + + .contact-name { + .flex-container; + .flex-container-alignment(center, flex-start); + color: @program-main-color; + font-size: 3.5rem; + line-height: 3.5rem; + width: 72.5%; + word-break: break-word; + + .base-icon { + .icon-sizing(3.5rem, 3.5rem, -4.25rem, -5.25rem); + flex-shrink: 0; + color: @program-table-icon-color; + margin: 0 1.5rem; + } + } + + .contact-address { + color: @program-input-icon-color; + font-size: 3rem; + font-style: italic; + line-height: 3rem; + margin-top: 0.5rem; + width: 27.5%; + word-break: break-word; + } + + &:last-child { + border-bottom: none; + } + + &:hover, &.active-contact { + cursor: pointer; + + .contact-name { + color: @program-hover-color; + + .base-icon { + color: @send-money-contacts-icon-hover-color; + } + } + + .contact-address { + color: @send-money-contacts-address-hover-color; + } + } + + &.active-contact { + background: fade(@send-money-contacts-hover-color, 50%); + } + } + + .empty-contacts-groups { + .flex-container-direction(column); + .flex-container-alignment(center, center); + color: @program-empty-color; + margin: 3.5rem 0 1rem; + + .empty-contacts-groups-icon { + .icon-sizing(14rem, 14rem, 1rem, 0); + } + + .empty-contacts-groups-text { + font-size: 3.75rem; + font-weight: 300; + margin-top: 2rem; + } + } + } + } +} + +.modal-select-contact-address { + + .modal-form-wrapper { + width: 119rem; + + .modal-form-body { + padding: 12rem 7rem 9rem 7rem; + } + } + + .general-form { + + .select-contact-options { + .flex-container; + .flex-container-alignment(center, space-between); + margin-bottom: 3rem; + width: 100%; + } + + .select-contact-list { + height: 66rem; + overflow-y: auto; + + .select-contact-item { + .flex-container-direction(column); + border-bottom: 1px solid @program-modal-divider-color; + height: 16.5rem; + padding: 2rem; + + .safe-address { + + .safe-address-wrap { + width: 100rem; + } + } + + alias-display { + + .safe-alias { + margin: 1.5rem 0; + } + } + + &:last-child { + border-bottom: none; + } + + &:hover, &.active-contact { + cursor: pointer; + + .safe-address { + + .safe-address-wrap { + + .safe-address-text { + background: -webkit-linear-gradient(left, @program-hover-color 0, @program-hover-color 75%, transparent 100%); + -webkit-background-clip: text; + } + } + } + + alias-display { + + .safe-alias { + + .safe-alias-btn { + border-color: @safes-alias-border-hover-color; + color: @program-hover-color; + } + } + } + } + + &.active-contact { + background: fade(@send-money-contacts-hover-color, 50%); + } + } + } + } +} + +.modal-confirm-transaction { + background-image: none; + + .modal-form-wrapper { + background: white; + width: 136rem; + + .modal-form-body { + padding: 7rem 8.5rem 8rem; + } + } + + .general-form { + + .general-form-field-group.field-group-review { + + .field-group-label { + min-width: 35%; + width: 35%; + } + + .field-group-description { + min-width: 65%; + width: 65%; + + .safe-address { + + .safe-address-wrap { + width: 76rem; + } + } + } + } + + .general-form-control-buttons { + margin-top: 6rem; + } + } +} + +.modal-transaction-details { + + .modal-form-wrapper { + width: 136rem; + + .modal-form-body { + padding: 7rem 9.5rem 0; + } + } + + .general-form { + + .general-form-field-group { + + .safe-address { + + .safe-address-wrap { + width: 54rem; + } + } + + .field-group-description.transaction-details { + max-height: 41.75rem; + overflow: auto; + + .transaction-status-wrapper { + .flex-container; + padding: 0.75rem 0; + margin-bottom: 3rem; + + .transaction-status { + position: relative; + height: 6rem; + width: 6rem; + margin-right: 2.5rem; + + .status-blank { + stroke: @program-transaction-status-inner-color; + } + + .status-graph { + + &.income { + stroke: @program-payments-income-color; + } + + &.outgoing { + stroke: @program-payments-outgoing-color; + } + } + + .status-inner { + .flex-container; + .flex-container-alignment(center, center); + position: absolute; + top: 0; + left: 0; + color: @program-transaction-status-inner-color; + height: 100%; + width: 100%; + + &.income { + color: @program-payments-income-color; + } + + &.outgoing { + color: @program-payments-outgoing-color; + + .base-icon { + transform: rotateX(180deg); + } + } + + .base-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + } + } + } + + &:last-child { + margin-bottom: 0.75rem; + } + } + } + } + } +} + + + + +.modal-complete-transaction { + + .modal-form-wrapper { + width: 116.5rem; + + .modal-form-body { + padding: 0 9.5rem 6.5rem; + } + } +} + +.modal-return-pledges { + + .modal-form-wrapper { + width: 156.5rem; + + .modal-form-body { + padding: 0 9.5rem 6.5rem; + } + } + + .general-form { + + .general-form-header.attention { + color: @error-color; + } + + .general-form-field-group { + + .field-group-label.attention { + color: @error-color; + } + } + + .general-form-price-description { + margin-top: 10rem; + } + + .general-form-control-buttons { + margin-top: 10rem; + } + } +} + +.modal-cancel-transaction { + + .modal-form-wrapper { + width: 156.5rem; + + .modal-form-body { + padding: 0 26rem 6.5rem; + } + } + + .general-form { + + .general-form-field-group { + + &.special-indent { + margin-top: 16rem; + } + } + + .general-form-price-description { + margin-top: 14rem; + } + + .general-form-control-buttons { + margin-top: 10rem; + } + } +} + +.modal-new-contact { + + .modal-form-wrapper { + width: 166.5rem; + + .modal-form-body { + padding: 3rem 18rem 8rem 0; + + .general-form-control-buttons { + margin-left: 18rem; + } + } + } + + .general-form { + + .general-form-field-group { + + .field-group-label { + padding-left: 7rem; + min-width: 49rem; + width: 49rem; + } + + .contact-connection-wrapper { + .flex-container; + width: 100%; + + .messenger-type, angucomplete-alt { + margin-right: 6.5rem; + min-width: 37%; + width: 37%; + } + } + } + + .safe-alias-modal { + align-self: flex-start; + margin-top: 5rem; + } + + .add-contact-btn { + .flex-container-direction(row); + .flex-container-alignment(center, center); + background: transparent; + border: none; + color: @contacts-accounts-btn-text-color; + font-size: 3rem; + line-height: 7rem; + margin: 0 0 0.25rem; + padding: 0; + + .base-icon { + .icon-sizing(6rem, 6rem, -3rem, -4rem); + margin-right: 1.5rem; + margin-left: -0.5rem; + } + + &:hover { + color: @program-hover-color; + } + } + + .contact-account-btn-wrapper { + .flex-container; + .flex-container-alignment(flex-start, flex-start); + margin-top: 6.5rem; + margin-bottom: 2rem; + width: 100%; + + .contact-account-btn { + .flex-container-direction(row); + .flex-container-alignment(center, center); + background: transparent; + border: none; + color: @contacts-accounts-btn-text-color; + font-size: 3rem; + margin: 0 13rem 0 0; + padding: 0; + + .base-icon { + .icon-sizing(6rem, 6rem, -3rem, -4rem); + margin-right: 1.5rem; + margin-left: -0.5rem; + min-width: 6rem; + } + + &:hover { + color: @program-hover-color; + } + } + } + + .edit-groups-field { + .flex-container; + .flex-container-alignment(center, flex-start); + + .edit-groups-icon { + .icon-sizing(5rem, 5rem, -3.5rem, -4.55rem); + margin-right: 1.5rem; + flex-shrink: 0; + + &:before { + content: '#'; + } + } + } + } +} + +.modal-contacts-groups { + + .modal-form-wrapper { + width: 106.5rem; + + .modal-form-body { + padding: 4.5rem 6.5rem 9rem; + } + } + + .general-form { + + .empty-contacts-groups { + .flex-container-direction(column); + .flex-container-alignment(center, center); + color: @program-empty-color; + margin: 3.5rem 0 1rem; + + .empty-contacts-groups-icon { + .icon-sizing(14rem, 14rem, 1rem, 0); + } + + .empty-contacts-groups-text { + font-size: 3.75rem; + font-weight: 300; + margin-top: 2rem; + } + } + + .contacts-groups-list { + color: @program-dark-color; + font-size: 3.75rem; + margin-top: 0.25rem; + width: 100%; + + #groups-list-items { + max-height: 92rem; + overflow-x: auto; + padding-right: 3rem; + margin-right: -3rem; + } + + .contacts-groups-list-item { + .flex-container-direction(row); + .flex-container-alignment(center, space-between); + border-bottom: 1px solid @program-modal-divider-color; + height: 11.5rem; + width: 100%; + + .group-icons { + visibility: hidden; + + .base-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + margin-left: 3rem; + } + } + + &:hover { + color: @program-hover-color; + cursor: pointer; + + .group-icons { + visibility: visible; + } + } + } + + .create-new-group-btn { + .flex-container-direction(row); + .flex-container-alignment(center, center); + background: transparent; + border: none; + color: @program-light-color; + font-size: 3.75rem; + font-weight: 300; + height: 11.5rem; + margin: 0 0 2.5rem; + padding: 0; + + .base-icon { + .icon-sizing(4rem, 4rem, -2.25rem, -3rem); + font-size: 10rem; + margin-right: 2rem; + margin-top: 1rem; + } + + &:hover { + color: @program-hover-color; + cursor: pointer; + } + } + } + } +} + +.modal-add-group { + background-image: none; + + .modal-form-wrapper { + background: white; + width: 101rem; + + .modal-form-body { + padding: 7.5rem 9rem 3rem; + } + } + + .general-form { + + .general-form-field-group { + + .add-group-wrapper { + .flex-container; + .flex-container-alignment(center, space-between); + width: 100%; + + .general-input { + border: none; + font-size: 4rem; + margin-top: 0; + } + + .add-group-btn { + border-radius: 5rem; + color: @program-dark-color; + height: 5.5rem; + line-height: 5rem; + min-width: 21rem; + width: 21rem; + } + } + + .field-group-error { + margin-top: 0; + } + } + } +} + +.modal-delete-group { + background-image: none; + + .modal-form-wrapper { + background: white; + min-width: 101rem; + + .modal-form-body { + padding: 0 9rem 5rem; + } + } + + .general-form { + + .general-form-field-group { + + .field-group-label { + font-size: 4.75rem; + font-weight: 300; + } + } + } +} + +.modal-edit-group { + + .modal-form-wrapper { + width: 106.5rem; + + .modal-form-body { + padding: 4.5rem 6.5rem 9rem; + } + + .general-form { + + .general-form-field-group { + margin: 2.5rem 0 4.5rem; + + .field-group-label { + white-space: nowrap; + min-width: initial; + width: auto; + } + } + + .editing-group-search { + .flex-container-direction(row); + .flex-container-alignment(center, center); + background: fade(white, 40%); + border: 1px solid @program-tab-border-color; + border-radius: 4rem; + color: @program-dark-color; + font-size: 3.5rem; + font-weight: 300; + height: 8.25rem; + margin-top: 2.5rem; + padding: 0 3rem; + width: 100%; + + .base-icon { + .icon-sizing(6rem, 6rem, -3rem, -4rem); + } + + .search-input { + display: block; + background: transparent; + border: none; + padding-left: 2rem; + width: 100%; + } + } + + .editing-group-empty-contacts { + .flex-container-direction(column); + .flex-container-alignment(center, center); + color: @program-empty-color; + height: 28rem; + padding: 5rem 0 1rem; + + .editing-group-empty-contacts-icon { + .icon-sizing(14rem, 14rem, 1rem, 0); + } + + .editing-group-empty-contacts-text { + font-size: 3.75rem; + font-weight: 300; + } + } + + .editing-group-contacts-list { + color: @program-main-color; + font-size: 3.5rem; + margin: 2.5rem 0; + min-height: 23rem; + width: 100%; + max-height: 92rem; + overflow-x: auto; + + .editing-group-contact-item { + .flex-container-direction(row); + .flex-container-alignment(center, space-between); + border-bottom: 1px solid @program-modal-divider-color; + height: 11.5rem; + width: 100%; + + .editing-group-contact-name { + .flex-container-direction(row); + .flex-container-alignment(center, center); + + .editing-group-contact-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + color: @program-table-icon-color; + margin-right: 2rem; + } + } + + .delete-group-contact-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + margin-left: 3rem; + visibility: hidden; + } + + &:last-child { + border: none; + } + + &:hover { + color: @program-hover-color; + cursor: pointer; + + .editing-group-contact-icon { + color: @program-hover-color; + } + + .delete-group-contact-icon { + visibility: visible; + } + } + } + } + } + } +} + +.modal-update { + + .modal-form-wrapper { + width: 106.5rem; + + .modal-form-header { + + .modal-form-header-title { + color: @modal-update-text-color; + } + + .modal-form-header-icon { + + .base-icon { + color: @modal-update-text-color; + } + } + + .modal-form-header-close { + + button { + color: @modal-update-text-color; + } + } + } + + .modal-form-body { + height: 45rem; + padding: 7rem 9.5rem 5rem; + } + + &.update-green { + + .modal-form-header { + background: @modal-update-green-color; + + .modal-form-header-icon { + background: @modal-update-green-color; + } + } + } + + &.update-yellow { + + .modal-form-header { + background: @modal-update-yellow-color; + + .modal-form-header-icon { + background: @modal-update-yellow-color; + } + } + } + + &.update-red { + + .modal-form-header { + background: @modal-update-red-color; + + .modal-form-header-icon { + background: @modal-update-red-color; + } + } + } + } + + .general-form { + + .general-form-field-group { + + .field-group-label { + font-size: 3.75rem; + } + + &:first-child { + margin-top: 2.5rem; + line-height: 6rem; + } + } + + .general-form-control-buttons { + margin-top: 7.75rem; + + .control-button { + min-width: 40rem; + } + } + } +} \ No newline at end of file diff --git a/src/gui/qt-daemon/html/less/css/source/page-empty.less b/src/gui/qt-daemon/html/less/css/source/page-empty.less new file mode 100644 index 00000000..272e6763 --- /dev/null +++ b/src/gui/qt-daemon/html/less/css/source/page-empty.less @@ -0,0 +1,125 @@ +@import "../variables"; +@import "mixins"; + +.page-empty { + .flex-container; + .flex-container-alignment(center, center); + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: -1; + color: @program-exuding-color; + text-align: center; + min-height: 150rem; + + .one-block { + display: inline-block; + width: 112rem; + + &.wider-block { + width: 140rem; + } + + h1 { + font-size: 10.75rem; + font-weight: 200; + margin-top:6.5rem; + } + + span { + font-size: 6.25rem; + margin-top: 5.5rem; + font-weight: 200; + line-height: 9.5rem; + text-align: center; + } + } +} + +.dashboard-empty { + z-index: 0; + margin: 18rem 8rem; + min-height: 100rem; + + .main-block { + display: block; + height: 100%; + padding: 0 30rem; + overflow: hidden; + + .main-block-row { + .flex-container; + .flex-container-alignment(center, space-between); + width: 155rem; + height: 100%; + transition: transform 0.5s ease-in-out; + + .main-block-col { + .flex-container-direction(column); + .flex-container-alignment(center, center); + position: relative; + margin-bottom: 0; + width: 55rem; + transition: all 0.2s ease-in-out; + + .main-block-icon { + + &.dashboard-create-safe { + background: url('../img/createsafe.svg') no-repeat center; + background-size: 100%; + width: 50rem; + height: 16rem; + } + + &.dashboard-open-safe { + background: url('../img/opensafe.svg') no-repeat center; + background-size: 100%; + width: 50rem; + height: 20rem; + margin-top: -4rem; + } + + &.dashboard-open-file-safe { + background: url('../img/openfilesafe.svg') no-repeat center; + background-size: 100%; + width: 50rem; + height: 16rem; + margin-top: -1.5rem; + margin-bottom: 1.5rem; + } + + &.dashboard-open-smartsafe { + background: url('../img/opensmartsafe.svg') no-repeat center; + background-size: 100%; + width: 50rem; + height: 16rem; + margin-top: -1.5rem; + margin-bottom: 1.5rem; + } + } + + .main-block-title { + font-size: 9.5rem; + font-weight: 200; + line-height: 24rem; + margin-bottom: 3rem; + white-space: nowrap; + + &.smaller-size { + font-size: 8rem; + } + } + + &:hover { + margin-top: -3rem; + } + } + } + + .slide-up { + transform: translateY(-100%); + } + } +} \ No newline at end of file diff --git a/src/gui/qt-daemon/html/less/css/source/page-options.less b/src/gui/qt-daemon/html/less/css/source/page-options.less new file mode 100644 index 00000000..c0c5bcae --- /dev/null +++ b/src/gui/qt-daemon/html/less/css/source/page-options.less @@ -0,0 +1,118 @@ +@import "../variables"; +@import "mixins"; + +.main-options-wrapper { + + .page-title { + color: @program-dark-color; + font-size: 8rem; + font-weight: 300; + line-height: 9rem; + margin: 0; + } + + .back-btn { + .flex-container; + .flex-container-alignment(center, center); + background: transparent; + border: none; + color: @program-dark-color; + font-size: 3.75rem; + padding: 0; + margin: 0; + + .base-icon { + .icon-sizing(3rem, 2rem, -4.5rem, -6rem); + margin-right: 2rem; + margin-bottom: -0.5rem; + } + } + + .main-options-btn { + .general-button(auto, 8.25rem); + color: @program-button-text-color; + font-size: 4.25rem; + min-width: 45rem; + + &.disabled { + color: @program-light-color; + cursor: default; + + &:hover { + background: fade(white, 55%); + } + + &:active { + background: fade(white, 55%); + } + } + } + + .main-options-btn-group { + .flex-container-direction(row); + border-radius: 10rem; + + .main-options-btn { + border-radius: 0; + min-width: 33rem; + + &.button-in-group { + border-right: 1px solid @program-button-divider-color; + + &:first-child { + border-top-left-radius: 10rem; + border-bottom-left-radius: 10rem; + } + + &:last-child { + border-top-right-radius: 10rem; + border-bottom-right-radius: 10rem; + margin-right: 0; + } + } + + &.button-in-dropdown { + border-top-right-radius: 10rem; + border-bottom-right-radius: 10rem; + + .base-icon { + .icon-sizing(2rem, 2rem, -4rem, -5rem); + margin-top: 0.5rem; + margin-left: 2rem; + font-size: 12rem; + } + } + } + + .dropdown.open { + + .button-in-dropdown { + background: rgba(255, 255, 255, 0.55)!important; + } + } + + .dropdown-menu { + .menu-list(10.5rem, inherit, -0.75rem, 47rem); + border-radius: 3rem; + + li { + height: auto; + + button { + font-size: 3.75rem; + padding: 1.5rem 4rem; + } + + &:first-child { + border-top-left-radius: 3rem; + border-top-right-radius: 3rem; + } + + &:last-child { + border-bottom-left-radius: 3rem; + border-bottom-right-radius: 3rem; + } + } + } + } +} diff --git a/src/gui/qt-daemon/html/less/css/source/pagination.less b/src/gui/qt-daemon/html/less/css/source/pagination.less new file mode 100644 index 00000000..916c85aa --- /dev/null +++ b/src/gui/qt-daemon/html/less/css/source/pagination.less @@ -0,0 +1,119 @@ +@import "../variables"; +@import "mixins"; + +.pagination-wrapper { + .flex-container-direction(row); + .flex-container-alignment(center, space-between); + + .display { + .flex-container-direction(row); + .flex-container-alignment(center, space-between); + font-size: 3.75rem; + + .display-text { + color: @program-pagination-text-color; + margin-right: 2rem; + } + + .display-values { + .flex-container-direction(row); + color: @program-pagination-text-inactive-color; + padding: 0; + margin: 0; + + li { + display: inline-block; + margin: 0 2rem; + width: 4rem; + + &:hover { + color: @program-pagination-text-color; + cursor: pointer; + } + + &.active { + color: @program-pagination-text-color; + } + } + } + } + + .show-all { + .flex-container; + color: @program-pagination-text-color; + cursor: pointer; + + .base-icon { + .icon-sizing(6rem, 6rem, -3rem, -4rem); + margin-right: 2rem; + + &.rotate-icon { + transform: rotate(180deg); + } + } + + .show-all-text { + font-size: 3.75rem; + line-height: 6rem; + } + } + + .pagination { + .flex-container-direction(row); + .flex-container-alignment(center, space-between); + margin: 0; + + .prev-page, .next-page { + .flex-container; + .flex-container-alignment(center, center); + background-color: fade(white, 30%); + border: 1px solid @program-pagination-border-color; + border-radius: 3rem; + color: white; + height: 6rem; + width: 7.5rem; + + .pagination-arrow { + .icon-sizing(4rem, 4rem, -3rem, -3.75rem); + font-size: 12rem; + } + + &:hover { + background-color: fade(white, 45%); + cursor: pointer; + } + } + + .prev-page { + + .pagination-arrow { + transform: rotate(180deg); + } + } + + .pages { + + .flex-container; + + color: @program-pagination-pages-color; + font-size: 3.75rem; + margin: 0 2.5rem; + + span { + margin: 0 0.5rem; + } + + .active-page { + width: 6rem; + + .general-input{ + border-bottom: none; + color: white; + padding: 0; + text-align: center; + } + + } + } + } +} \ No newline at end of file diff --git a/src/gui/qt-daemon/html/less/css/source/panels.less b/src/gui/qt-daemon/html/less/css/source/panels.less new file mode 100644 index 00000000..22055ab6 --- /dev/null +++ b/src/gui/qt-daemon/html/less/css/source/panels.less @@ -0,0 +1,212 @@ +@import "../variables"; +@import "mixins"; + +.general-panel { + background: @program-panel-bg-color; + border: 1px solid @program-panel-border-color; + border-radius: 3rem; + margin-bottom: 6rem; + + .general-panel-header { + .flex-container-direction(row); + .flex-container-alignment(center, flex-start); + background-color: @program-panel-header-bg-color; + border-top-left-radius: 2.75rem; + border-top-right-radius: 2.75rem; + color: @program-dark-color; + font-size: 5rem; + height: 13rem; + padding-left: 4rem; + + .general-panel-header-arrow { + .icon-sizing(2rem, 2rem, -5rem, -6rem); + cursor: pointer; + margin-left: 2rem; + } + + &.closed-panel { + border-bottom: none; + border-bottom-left-radius: 2.75rem; + border-bottom-right-radius: 2.75rem; + + .general-panel-header-arrow { + transform: rotate(180deg); + } + } + } + + .general-panel-body { + border-bottom-left-radius: 2.75rem; + border-bottom-right-radius: 2.75rem; + + .adaptive-form { + .flex-container-direction(column); + color: @program-exuding-color; + padding-left: 32rem; + padding-right: 37rem; + + i { + display: flex; + + &.option-icon { + align-self: flex-end; + margin: 1.5rem 0 1.5rem 2rem; + } + } + + .adaptive-form-column { + width: 100%; + + .adaptive-form-field-group { + .flex-container-direction(row); + + .field-group-label { + .flex-container; + .flex-container-alignment(center, flex-end); + position: relative; + color: @program-label-color; + font-size: 3.5rem; + font-weight: 600; + line-height: 3.5rem; + height: 7rem; + padding-right: 2.5rem; + margin: 0; + min-width: 31rem; + max-width: 31rem; + text-align: right; + } + + .field-group-error-wrapper { + .flex-container-direction(column); + width: 100%; + + .field-group-error { + display: block; + color: @error-color; + font-size: 3.25rem; + line-height: 2.75rem; + font-style: italic; + margin-top: 1.5rem; + } + } + + .general-input { + + &:hover, &:focus, &:active { + + &:read-only:not(.no-hover) { + cursor: pointer; + } + } + } + + &:hover, &.focused-line { + + &:not(.no-hover) { + color: @program-hover-color; + + .general-input { + border-bottom-color: @program-hover-color; + color: @program-hover-color; + + &::-webkit-input-placeholder { + color: @program-input-placeholder-hover-color; + } + } + + .general-input-wrapper { + border-bottom-color: @program-hover-color; + color: @program-hover-color; + + ::-webkit-input-placeholder { + color: @program-input-placeholder-hover-color; + } + } + + .general-textarea { + border-bottom-color: @program-hover-color; + color: @program-hover-color; + + &::-webkit-input-placeholder { + color: @program-input-placeholder-hover-color; + } + } + + .general-select { + + .dropdown-toggle { + color: @program-hover-color; + border-bottom-color: @program-hover-color; + } + } + } + + .option-icon { + cursor: pointer; + visibility: visible; + } + } + } + } + + @media screen and (min-width: 1085px) and (max-width: 1164px) { + padding-left: 47rem; + padding-right: 52rem; + } + + @media screen and (min-width: 1165px) and (max-width: 1334px) { + .flex-container-direction(row); + padding-left: 9.5rem; + padding-right: 21.5rem; + + .adaptive-form-column { + width: 50%; + + &:first-child { + margin-right: 9.5rem; + } + + &:last-child { + margin-left: 9.5rem; + } + } + } + + @media screen and (min-width: 1335px) and (max-width: 1614px) { + .flex-container-direction(row); + padding-left: 16.5rem; + padding-right: 23.5rem; + + .adaptive-form-column { + width: 50%; + + &:first-child { + margin-right: 9.5rem; + } + + &:last-child { + margin-left: 9.5rem; + } + } + } + + @media screen and (min-width: 1615px) { + .flex-container-direction(row); + padding-left: 25rem; + padding-right: 31rem; + + .adaptive-form-column { + width: 50%; + + &:first-child { + margin-right: 9.5rem; + } + + &:last-child { + margin-left: 9.5rem; + } + } + } + } + } +} \ No newline at end of file diff --git a/src/gui/qt-daemon/html/less/css/source/safes.less b/src/gui/qt-daemon/html/less/css/source/safes.less new file mode 100644 index 00000000..91d709b1 --- /dev/null +++ b/src/gui/qt-daemon/html/less/css/source/safes.less @@ -0,0 +1,1200 @@ +@import "../variables"; +@import "mixins"; + +#safes { + padding: 2.5rem 8rem 10rem; + + .main-options-wrapper { + + .safes-options { + .flex-container; + .flex-container-alignment(center, space-between); + margin-bottom: 7rem; + + .safes-info-wrapper { + .flex-container; + .flex-container-alignment(flex-start, center); + color: @safes-indicator-color; + font-size: 3.75rem; + font-weight: 300; + + .safes-info { + .flex-container; + cursor: pointer; + margin-left: 9rem; + + .base-icon { + .icon-sizing(6rem, 6rem, -3rem, -4rem); + color: @safes-indicator-color; + margin-right: 1rem; + } + } + } + + .safes-tab { + .flex-container; + border-radius: 10rem; + height: 8.25rem; + margin: 0; + padding: 0; + + .safes-tab-item { + .flex-container-direction(row); + .flex-container-alignment(center, center); + background-color: white; + border: 1px solid @program-tab-border-color; + font-size: 3.5rem; + font-weight: 300; + padding: 0; + + button { + .flex-container; + .flex-container-alignment(center, center); + -webkit-flex-grow: 1; + flex-grow: 1; + background: transparent; + border: none; + color: @program-light-color; + margin: 0; + padding: 2rem 6rem; + + .base-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + margin-right: 2rem; + } + } + + &:first-child { + border-top-left-radius: 4rem; + border-bottom-left-radius: 4rem; + } + + &:last-child { + border-top-right-radius: 4rem; + border-bottom-right-radius: 4rem; + border-left: none; + } + + &.active { + + &:not(.disabled) { + + button { + color: @program-main-color; + } + } + } + + &:hover { + + &:not(.disabled):not(.active) { + background: @program-options-bg-hover-color; + cursor: pointer; + + button { + color: @program-main-color; + } + } + } + } + } + + .safes-search { + margin-left: 3.25rem; + } + + .safes-buttons { + .flex-container-direction(row); + } + } + } + + .safes-table { + margin-bottom: 3rem; + + .safes-name { + .flex-container; + .flex-container-alignment(center, flex-start); + + .safe-link { + .flex-container; + .flex-container-alignment(center, flex-start); + color: @program-main-color; + font-size: 3.75rem; + line-height: 8rem; + + .lock-icon { + .icon-sizing(8rem, 4rem, -2.25rem, -5rem); + color: @program-table-icon-color; + margin-right: 1rem; + + &.open { + transform: rotateY(180deg); + margin-left: -0.5rem; + margin-right: 1.5rem; + } + } + + &:hover { + color: @program-hover-color; + cursor: pointer; + + .lock-icon { + color: @program-hover-color; + } + } + } + + .mining-icon { + .icon-sizing(4rem, 4rem, -7.5rem, -10rem); + color: @program-mined-icon-color; + font-size: 24rem; + margin-left: 3rem; + } + } + + .safe-account { + .flex-container-direction(column); + + .safe-address { + font-size: 3.25rem; + margin-top: 0.75rem; + margin-bottom: 0.75rem; + + .safe-address-wrap { + width: 40rem; + } + + .safe-address-inner { + left: inherit; + right: 0; + width: 150%; + } + } + + alias-display:not(.safe-address-inner-alias) { + display: inline-flex; + + .safe-alias { + margin-top: 0.75rem; + margin-bottom: 0.75rem; + } + } + } + + .safe-status { + width: 45rem; + } + + .safe-menu { + line-height: 0; + visibility: hidden; + + .safe-menu-btn { + background: transparent; + border: none; + padding: 0; + margin: 0; + + .base-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + } + } + + .safes-menu-list { + .menu-list(-20rem, inherit, -3rem, 38rem); + } + } + + .safe-table-offline { + color: @program-offline-color; + } + + tr { + + th:last-child, td:last-child { + width: 10rem; + } + + &:hover { + + .safe-menu { + visibility: visible; + } + } + } + } + + .safes-blocks { + .flex-container-direction(row); + flex-wrap: wrap; + margin: 0 -3.5rem; + + .safes-blocks-item { + padding: 0 3.5rem 7rem; + width: 50%; + } + } +} + +#safe-details { + padding: 1.5rem 8rem 2.5rem; + + .safe-details-options { + .flex-container-direction(row); + .flex-container-alignment(center, space-between); + margin-bottom: 5.5rem; + + .safe-details-switch { + .flex-container; + .flex-container-alignment(center, center); + color: @program-dark-color; + font-size: 3.75rem; + + .safe-details-switch-text { + margin-right: 4rem; + } + + .safe-details-switch-btn-group { + .flex-container; + + .safe-details-switch-btn { + background-color: @safe-pages-switch-bg-color; + border: 1px solid @safe-pages-switch-border-color; + color: @safe-pages-switch-text-color; + line-height: 0; + padding: 1.5rem 2.5rem; + margin: 0; + + .base-icon { + .icon-sizing(3rem, 2rem, -4.5rem, -6rem); + + &.rotate-icon { + transform: rotateY(180deg); + } + } + + &:first-child { + border-top-left-radius: 3rem; + border-bottom-left-radius: 3rem; + border-right: none; + } + + &:last-child { + border-top-right-radius: 3rem; + border-bottom-right-radius: 3rem; + } + + &:hover { + background-color: @safe-pages-switch-bg-hover-color; + color: @program-dark-color; + } + } + } + } + } + + .general-panel { + + .general-panel-header { + background-color: fade(@program-panel-header-bg-color, 30%); + border-bottom: 1px solid @program-panel-divider-color; + } + } + + .safe-name { + height: 18rem !important; + position: relative; + + h1 { + font-size: 5.75rem; + margin: 0 0 0 2rem; + } + + .lock-icon { + .icon-sizing(5rem, 5rem, -5.5rem, -7rem); + font-size: 19rem; + + &.open { + transform: rotateY(180deg); + } + } + + .safe-menu { + position: absolute; + top: 50%; + right: 5rem; + line-height: 0; + margin-top: -2rem; + + .safe-menu-btn { + background: transparent; + border: none; + padding: 0; + margin: 0; + + .base-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + color: @program-main-color; + } + } + + .safes-menu-list { + .menu-list(5rem, inherit, -3rem, 46rem); + } + } + } + + .safe-general-info { + .flex-container-direction(row); + .flex-container-alignment(center, space-around); + padding: 6.5rem 0; + + .safe-details-balance { + .flex-container-direction(column); + .flex-container-alignment(center, flex-start); + color: @program-dark-color; + height: 40rem; + width: 40rem; + + .safe-details-balance-title { + font-size: 3rem; + line-height: 3rem; + margin-top: 5rem; + } + + .safe-details-balance-text { + font-size: 4rem; + line-height: 4rem; + margin-top: 2rem; + } + + .coins-icon { + background-size: 100%; + height: 30rem; + width: 30rem; + margin-bottom: -2.5rem; + margin-top: -2.5rem; + + &.coins-empty { + background: url('../img/safe_coins/coins-empty.svg') no-repeat center center; + background-size: 100%; + } + + &.coins1 { + background: url('../img/safe_coins/coins1.svg') no-repeat center center; + background-size: 100%; + } + + &.coins2 { + background: url('../img/safe_coins/coins2.svg') no-repeat center center; + background-size: 100%; + } + + &.coins3 { + background: url('../img/safe_coins/coins3.svg') no-repeat center center; + background-size: 100%; + } + + &.coins4 { + background: url('../img/safe_coins/coins4.svg') no-repeat center center; + background-size: 100%; + } + + &.coins5 { + background: url('../img/safe_coins/coins5.svg') no-repeat center center; + background-size: 100%; + } + + &.coins6 { + background: url('../img/safe_coins/coins6.svg') no-repeat center center; + background-size: 100%; + } + + &.coins7 { + background: url('../img/safe_coins/coins7.svg') no-repeat center center; + background-size: 100%; + } + + &.coins8 { + background: url('../img/safe_coins/coins8.svg') no-repeat center center; + background-size: 100%; + } + + &.coins9 { + background: url('../img/safe_coins/coins9.svg') no-repeat center center; + background-size: 100%; + } + + &.coins10 { + background: url('../img/safe_coins/coins10.svg') no-repeat center center; + background-size: 100%; + } + + &.coins11 { + background: url('../img/safe_coins/coins11.svg') no-repeat center center; + background-size: 100%; + } + } + + svg.balance-svg { + transform: rotate(-90deg); + } + circle.circle-blank { + stroke: @program-transaction-status-inner-color; + } + circle.balance-graph { + transition: stroke-dashoffset 400ms ease-in-out; + stroke-dasharray: 67.5442rem; + stroke-dashoffset: 67.5442rem; + } + + .balance-graph-inner { + position: absolute!important; + top: 50%; + left: 50%; + transform: translateX(-50%) translateY(-50%); + } + + .available-balance-graph { + height: 25rem; + width: 25rem; + position: relative; + + circle.balance-graph { + stroke: @safe-balance-indicator-color; + } + + .balance-graph-inner { + font-size: 5rem; + font-weight: 200; + color: @safe-balance-indicator-color; + + &.unavailable { + color: @program-transaction-status-inner-color; + } + } + } + + .expected-balance-graph { + height: 25rem; + width: 25rem; + position: relative; + + circle.balance-graph { + stroke: @program-transaction-status-pending-inner-color; + } + + .balance-graph-inner { + .icon-sizing(12rem, 12rem, 0, -1rem); + color: @program-transaction-status-inner-color; + + &.completed { + color: @program-transaction-status-pending-inner-color; + } + } + } + + .transmit-balance-graph { + height: 25rem; + width: 25rem; + position: relative; + + circle.balance-graph { + stroke: @program-transaction-status-sending-inner-color; + } + + .balance-graph-inner { + .icon-sizing(12rem, 12rem, 0, -1rem); + color: @program-transaction-status-inner-color; + transform: translateX(-50%) translateY(-50%) rotateX(180deg); + + &.completed { + color: @program-transaction-status-sending-inner-color; + } + } + } + + .mined-balance-graph { + height: 25rem; + width: 25rem; + position: relative; + + circle.circle-blank { + stroke: @safe-mined-indicator-color; + } + + circle.balance-graph { + stroke: @safe-mined-completed-indicator-color; + } + + .balance-graph-inner { + .icon-sizing(12rem, 12rem, -4rem, -6.5rem); + color: @safe-mined-indicator-color; + font-size: 24rem; + margin-left: 1rem; + + &.completed { + color: @safe-mined-completed-indicator-color; + } + } + } + } + } + + .safe-information { + margin-top: 12rem; + margin-bottom: 6rem; + + .adaptive-form-field-group { + margin-bottom: 7.5rem; + + .general-textarea { + padding-right: 5rem; + + &:hover { + cursor: pointer; + } + } + + .add-alias-btn { + .flex-container; + .flex-container-alignment(center, center); + background: transparent; + border: 1px solid @safes-alias-border-color; + border-radius: 16rem; + color: @program-main-color; + font-size: 3rem; + height: 4.5rem; + margin-top: 1.25rem; + padding: 0 2.5rem; + + .base-icon { + .icon-sizing(2rem, 2rem, -5rem, -6rem); + } + + .btn-text { + font-size: 3.25rem; + line-height: 4rem; + padding: 0 0.5rem; + } + + &:hover { + + &:not(:disabled) { + border: 1px solid @safe-button-border-hover-color; + color: @program-hover-color; + cursor: pointer; + + } + } + } + + &.safe-password { + + input[type=text] { + color: @error-color; + } + + input[type=password] { + -webkit-text-security: disc; + } + } + + &.alias-actions-wrapper { + position: relative; + + .alias-actions { + position: absolute; + top: 0; + right: 0; + transform: translateX(100%); + padding: 0 2rem; + + .alias-action { + display: inline-flex; + margin-left: 1rem; + position: relative; + + .base-icon { + .icon-sizing(6rem, 6rem, -3rem, -4rem); + color: @safe-alias-icon-color; + + &:hover { + + &:not(.disabled) { + color: @safe-alias-icon-hover-color; + cursor: pointer; + } + } + } + } + } + } + } + } + + .safe-backup { + .flex-container-direction(row); + .flex-container-alignment(center, center); + margin-top: 8.5rem; + margin-bottom: 10.5rem; + + .safe-backup-btn { + background: @program-button-bg-color; + border: 1px solid @program-button-border-color; + border-radius: 10rem; + color: @program-button-text-color; + font-size: 4rem; + height: 8rem; + margin: 0 2.5rem; + min-width: 80.5rem; + + &:hover { + background: @program-button-hover-bg-color; + } + + &:active { + background-color: @program-button-active-bg-color; + } + } + } + + .safe-payment-history { + padding: 7rem 2.5rem 0; + } + + .safe-empty-payments { + color: @program-empty-color; + font-size: 3.75rem; + line-height: 5.5rem; + padding: 12.5rem 0; + text-align: center; + } + + .pagination-wrapper { + padding: 0 2.5rem 3rem; + } +} + +.safe-block-wrapper { + background: fade(white, 60%); + border: 1px solid @program-panel-border-color; + border-radius: 3rem; + height: 57rem; + + .safe-empty { + .flex-container; + .flex-container-alignment(center, center); + height: 100%; + width: 100%; + + &.safe-main-buttons { + + &.transformed { + top: -100%; + } + } + + &.safe-additional-buttons { + + &.transformed { + top: 100%; + } + + .safe-block-btn { + + .safe-block-btn-text { + font-size: 3.5rem; + } + } + } + + .safe-block-btn { + .flex-container-direction(column); + .flex-container-alignment(center, center); + border: none; + background: transparent; + color: @program-button-text-color; + margin: 0; + padding: 0; + width: 22.5rem; + transition: all 0.2s ease-in-out; + + .safe-block-btn-icon { + .icon-sizing(13rem, 13rem, 0rem, -0.5rem); + margin-left: 2rem; + } + + .safe-block-btn-text { + font-size: 4.5rem; + font-weight: 300; + padding-top: 3.5rem; + opacity: 0.8; + white-space: nowrap; + } + + &:first-child { + margin-right: 10rem; + } + + &:last-child { + margin-left: 10rem; + } + + &:hover { + color: @program-hover-color; + margin-top: -3rem; + } + } + } + + .safe-block { + + .safe-block-header { + .flex-container-direction(column); + .flex-container-alignment(center, flex-start); + background: fade(@program-header-bg-active-color, 30%); + border-bottom: 1px solid @program-panel-border-color; + border-radius: 2.75rem 2.75rem 0 0; + height: 20rem; + position: relative; + + .safe-block-title { + color: @program-exuding-color; + font-size: 5.5rem; + font-weight: 300; + line-height: 10rem; + margin-top: 2rem; + + &:hover { + color: @program-hover-color; + cursor: pointer; + } + } + + .safe-alias { + color: @safes-block-text-color; + + .safe-alias-btn { + border-color: @dashboard-alias-border-color; + + &.safe-alias-long-name { + + .safe-alias-text { + background: -webkit-linear-gradient(left, @safes-block-text-color 0, @safes-block-text-color 75%, transparent 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + } + } + + &:hover { + + &.safe-alias-comment { + color: fade(@safes-block-text-color, 50%); + } + } + } + } + + .safe-address { + + .safe-address-wrap { + color: @safes-block-text-color; + width: 67.5rem; + + .safe-address-text { + background: -webkit-linear-gradient(left, @safes-block-text-color 0, @safes-block-text-color 75%, transparent 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + font-size: 3.5rem; + } + } + + &.open { + + .safe-address-wrap { + color: @safes-block-text-open-color; + + .safe-address-text { + background: -webkit-linear-gradient(left, @safes-block-text-open-color 0, @safes-block-text-open-color 75%, transparent 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + } + } + } + } + + .safe-mined { + .flex-container; + .flex-container-alignment(center, center); + position: absolute; + top: 0; + right: 4rem; + width: 5rem; + height: 6rem; + background-color: @safes-block-mined-bg-color; + border-top: none; + border-bottom-left-radius: 2rem; + border-bottom-right-radius: 2rem; + + .base-icon { + .icon-sizing(4rem, 4rem, -7rem, -9rem); + color: @safes-block-mined-icon-color; + font-size: 22rem; + } + } + } + + .safe-block-body { + padding: 5rem 0 6.5rem; + + .safe-block-balance { + .flex-container; + .flex-container-alignment(center, center); + font-size: 7.5rem; + font-weight: 200; + line-height: 8rem; + + .unlocked-balance-value { + color: @program-exuding-color; + } + + .balance-value { + .flex-container; + color: @safes-balance-text-color; + } + } + + .safe-block-status { + .flex-container; + .flex-container-alignment(center, center); + color: @program-exuding-color; + font-size: 3.25rem; + height: 10rem; + + .transaction-status-indicator { + + .status-inner { + + .status-icon { + font-size: 12rem; + + &:before { + top: -2rem; + left: -3rem; + } + } + } + + .mined-icon { + font-size: 11rem; + top: -1rem; + left: -1.5rem; + + &:before { + top: -2.5rem; + left: -3.5rem; + } + } + } + } + + .safe-block-buttons { + .flex-container; + .flex-container-alignment(center, center); + margin-top: 1rem; + + .safe-block-btn-wrapper { + margin: 0 3rem; + + .safe-block-btn { + height: 6.5rem; + width: 28rem; + } + + .safe-block-menu { + .menu-list(-10rem, initial, -3rem, 40rem) + } + } + } + + .safe-block-offline { + color: @program-offline-color; + font-size: 3.75rem; + line-height: 5.5rem; + margin-top: 1rem; + text-align: center; + } + } + } +} + +.safe-sync { + .flex-container-direction(column); + .flex-container-alignment(center, center); + height: 100%; + width: 100%; + + .safe-sync-text { + color: @program-online-color; + font-size: 5rem; + line-height: 8.5rem; + } + + progress[value] { + -webkit-appearance: none; + appearance: none; + width: 61rem; + height: 1rem; + margin: 4rem 0; + + &::-webkit-progress-bar { + background-color: @program-progress-bar-bg-color; + border-radius: 1rem; + } + + &::-webkit-progress-value { + background-color: @program-progress-bar-fill-color; + border-radius: 1rem; + } + } + + &.safe-table { + + .safe-sync-text { + font-size: inherit; + line-height: 4.5rem; + } + + progress[value] { + margin: 1rem 0; + width: 100%; + } + } +} + +.safe-alias { + .flex-container; + position: relative; + color: @program-main-color; + + .safe-alias-btn { + display: flex; + align-items: center; + background-color: transparent; + border: 1px solid @safes-alias-border-color; + font-size: 3.25rem; + height: 4.5rem; + padding: 0 2rem; + + span { + line-height: 3.75rem; + margin-bottom: 0.25rem; + white-space: nowrap; + } + + &.safe-alias-name { + border-radius: 10rem 0 0 10rem; + max-width: 29rem; + } + + &.safe-alias-long-name { + + .safe-alias-text { + overflow: hidden; + background: -webkit-linear-gradient(left, @program-main-color 0, @program-main-color 75%, transparent 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + cursor: pointer; + white-space: nowrap; + } + + .base-icon { + .icon-sizing(2rem, 2rem, -5rem, -6rem); + min-width: 2rem; + min-height: 2rem; + } + } + + &.safe-alias-comment { + border-left: none; + border-radius: 0 10rem 10rem 0; + position: relative; + + .base-icon { + .icon-sizing(4rem, 4rem, -3.75rem, -5rem); + } + } + + &:hover { + + &.safe-alias-comment { + color: fade(@program-main-color, 50%); + cursor: pointer; + } + } + } + + &.safe-alias-without-comment { + + .safe-alias-name { + max-width: 36.5rem; + border-radius: 10rem; + } + } +} +.safe-alias-modal { + display: inline-block; + border: 1px solid @safes-alias-border-color; + border-radius: 2rem; + color: @program-main-color; + font-size: 3.25rem; + margin: 0; + width: 100%; + + .safe-alias-modal-name { + border-radius: 1.75rem 1.75rem 0 0; + background-color: fade(@program-panel-header-bg-color, 30%); + border-bottom: 1px solid @safes-alias-border-color; + line-height: 3.75rem; + height: 4.25rem; + padding: 0 2rem; + } + + .safe-alias-modal-comment { + position: relative; + padding: 1.5rem 6rem 1.5rem 2rem; + word-break: break-word; + + .safe-alias-modal-copy { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + position: absolute; + bottom: 1.5rem; + right: 2rem; + color: @program-copy-icon-color; + cursor: pointer; + visibility: hidden; + + &:hover, &.hovered { + color: @program-exuding-color; + } + + &.hovered:before { + content: 'A'; + } + } + } + + &.safe-alias-modal-no-comment { + width: auto; + + .safe-alias-modal-name { + background-color: transparent; + border-bottom: none; + border-radius: 3rem; + padding: 0 3rem; + } + } + + &:hover { + + .safe-alias-modal-copy { + visibility: visible; + } + } +} + +.safe-address { + position: relative; + + .safe-address-wrap { + .flex-container; + .flex-container-alignment(center, center); + color: @program-main-color; + width: 67.5rem; + + .safe-address-text { + overflow: hidden; + background: -webkit-linear-gradient(left, @program-main-color 0, @program-main-color 75%, transparent 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + cursor: pointer; + font-size: 3.25rem; + height: 4.5rem; + line-height: 4.5rem; + } + + .safe-address-icon { + .icon-sizing(2rem, 2rem, -5rem, -6rem); + min-width: 2rem; + min-height: 2rem; + } + } +} +.safe-address-inner { + background: white; + border: none; + border-radius: 2rem; + box-shadow: @box-shadow; + color: @program-main-color; + font-size: 3.25rem; + line-height: 4rem; + padding: 2.5rem 3.75rem; + margin-top: 1.5rem; + overflow: auto; + width: 67.5rem; + + .safe-address-inner-text { + word-break: break-all; + white-space: normal; + } + + .safe-address-inner-alias { + .flex-container; + } + + .copy-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + color: @program-copy-icon-color; + cursor: pointer; + float: right; + margin-right: -2rem; + margin-top: 5rem; + margin-bottom: -1rem; + + &:hover, &.hovered { + color: @program-exuding-color; + } + + &.hovered:before { + content: 'A'; + } + } + + &::-webkit-scrollbar { + cursor: default; + height: 1.75rem; + width: 1.75rem; + } + + &::-webkit-scrollbar-thumb { + background-clip: padding-box; + background-color: @scroll-dark-color; + border: 0.5rem solid transparent; + border-radius: 1rem; + } + + &::-webkit-scrollbar-corner { + background-color: @scroll-dark-color; + } +} + +.safe-status-wrapper { + .flex-container; + .flex-container-alignment(center, flex-start); + + .safe-status-amount { + margin-left: 2rem; + } +} \ No newline at end of file diff --git a/src/gui/qt-daemon/html/less/css/source/settings.less b/src/gui/qt-daemon/html/less/css/source/settings.less new file mode 100644 index 00000000..231b3178 --- /dev/null +++ b/src/gui/qt-daemon/html/less/css/source/settings.less @@ -0,0 +1,84 @@ +@import "../variables"; +@import "mixins"; + +#settings { + padding: 2.5rem 8rem; + + .main-options-wrapper { + + .settings-options { + .flex-container-direction(row); + .flex-container-alignment(center, space-between); + } + } + + .settings-panel { + background: @program-panel-bg-color; + border: 1px solid @program-panel-border-color; + border-radius: 3rem; + width: 100%; + + .settings-panel-header { + background-color: fade(@program-panel-border-color, 30%); + border-top-left-radius: 2.75rem; + border-top-right-radius: 2.75rem; + color: @program-dark-color; + height: 21rem; + padding-left: 6rem; + + h3 { + font-size: 5rem; + line-height: 21rem; + margin: 0; + } + } + + .settings-panel-body { + + .settings-panel-body-item { + .flex-container; + .flex-container-alignment(center, space-between); + color: @program-main-color; + font-size: 4rem; + height: 21rem; + padding-left: 6rem; + padding-right: 7rem; + + .general-select { + max-width: 51.5rem; + .dropdown-menu { + &.open { + max-height: 32rem !important; + .inner{ + max-height: inherit !important; + } + } + } + } + + .general-range-wrapper { + width: 76rem; + } + + .settings-btn { + font-size: 4rem; + height: 8.5rem; + width: 32rem; + } + + &:nth-child(even) { + background-color: fade(@program-panel-border-color, 30%); + } + + &:first-child { + border-top: none; + } + + &:last-child { + border-bottom-left-radius: 2.75rem; + border-bottom-right-radius: 2.75rem; + } + } + } + } +} \ No newline at end of file diff --git a/src/gui/qt-daemon/html/less/css/source/tables.less b/src/gui/qt-daemon/html/less/css/source/tables.less new file mode 100644 index 00000000..53f9a794 --- /dev/null +++ b/src/gui/qt-daemon/html/less/css/source/tables.less @@ -0,0 +1,228 @@ +@import "../variables"; +@import "mixins"; + +.table-wrapper { + background: @program-table-bg-color; + border: 1px solid @program-table-border-color; + border-radius: 3rem; + -webkit-transform: translateZ(0); + transform: translateZ(0); + + table { + border-radius: 3rem; + width: 100%; + + thead { + + tr { + background-color: @program-table-header-bg-color; + border: none; + border-top-left-radius: 2.75rem; + border-top-right-radius: 2.75rem; + color: @program-exuding-color; + font-size: 3.5rem; + height: 18rem; + + th { + font-weight: 400; + padding: 0 1rem; + text-transform: uppercase; + white-space: nowrap; + + .ordered-cell { + .flex-container-direction(row); + .flex-container-alignment(center, flex-start); + + .order-icon { + .icon-sizing(2rem, 2rem, -5rem, -6rem); + color: @program-light-color; + cursor: pointer; + margin-left: 2rem; + + &.rotate-icon { + transform: rotate(180deg); + } + + &.active { + color: @program-exuding-color; + } + } + } + + &:first-child { + border-top-left-radius: 2.75rem; + padding-left: 4rem; + } + + &:last-child { + border-top-right-radius: 2.75rem; + } + } + } + } + + tbody { + + tr { + border: none; + color: @program-main-color; + font-size: 3.5rem; + height: 18rem; + overflow: hidden; + + td { + padding: 3rem 1rem; + + safe-address-copy { + align-self: flex-start; + } + + &:first-child { + padding-left: 4rem; + overflow: hidden; + } + } + + &:nth-child(even) { + background-color: @program-table-header-bg-color; + } + + &:last-child { + border-bottom: none; + border-bottom-left-radius: 2.75rem; + border-bottom-right-radius: 2.75rem; + + td:first-child { + border-bottom-left-radius: 2.75rem; + } + + td:last-child { + border-bottom-right-radius: 2.75rem; + } + } + } + } + } +} + +.table-long-item-wrapper { + display: inline-block; + color: @program-main-color; + max-width: 100%; + position: relative; + + .table-long-item { + .flex-container; + .flex-container-alignment(center, center); + cursor: pointer; + + .table-long-item-text { + overflow: hidden; + white-space: nowrap; + background: -webkit-linear-gradient(left, @program-main-color 0, @program-main-color 75%, transparent 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + font-size: 3.5rem; + height: 4.5rem; + line-height: 4.5rem; + } + + .separator { + color: #a1b2a2; + } + + .base-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + min-width: 4rem; + min-height: 4rem; + } + + &:hover { + color: @program-hover-color; + + .table-long-item-text { + background: -webkit-linear-gradient(left, @program-hover-color 0, @program-hover-color 75%, transparent 100%); + -webkit-background-clip: text; + } + + .separator { + color: #cdb495; + } + } + } + + &.open { + color: @program-hover-color; + + .table-long-item-text { + background: -webkit-linear-gradient(left, @program-hover-color 0, @program-hover-color 75%, transparent 100%); + -webkit-background-clip: text; + + span { + color: #cdb495; + } + } + } +} +.table-long-item-inner { + position: absolute; + top: 6.5rem; + left: 0; + background-color: white; + border: none; + border-radius: 2rem; + -webkit-box-shadow: @table-item-shadow; + box-shadow: @table-item-shadow; + color: @program-exuding-color; + font-size: 3.25rem; + padding: 0 3rem; + margin-left: -3rem; + margin-top: 0; + max-height: 90vh; + white-space: nowrap; + z-index: 1; + outline: none; + overflow-y: auto; + + + + + display: none; + visibility: hidden; + opacity: 0; + transform: translateY(-2em); + transition: all 0.3s ease-in-out 0s, visibility 0s linear 0.3s, z-index 0s linear 0.01s; + + &.open { + visibility: visible; + max-height: 90vh; + opacity: 1; + transform: translateY(0%); + transition-delay: 0s, 0s, 0.3s; + } + + div { + .flex-container; + .flex-container-alignment(center, space-between); + height: 8rem; + + &:not(:last-child) { + border-bottom: 1px solid #f3f5f4; + } + } + + .copy-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + color: @program-copy-icon-color; + cursor: pointer; + margin-left: 5rem; + + &:hover, &.hovered { + color: @program-exuding-color; + } + + &.hovered:before { + content: 'A'; + } + } +} \ No newline at end of file diff --git a/src/gui/qt-daemon/html/less/css/source/tabs.less b/src/gui/qt-daemon/html/less/css/source/tabs.less new file mode 100644 index 00000000..878e4ea7 --- /dev/null +++ b/src/gui/qt-daemon/html/less/css/source/tabs.less @@ -0,0 +1,85 @@ +@import "../variables"; +@import "mixins"; + +.general-tabs { + .flex-container; + margin: 7.5rem auto 5rem; + padding: 0; + + .general-tab { + .flex-container; + .flex-container-alignment(center, space-between); + flex: 1 0 0; + background-color: @program-tab-bg-color; + border: 1px solid @program-tab-border-color; + font-size: 6rem; + font-weight: 200; + line-height: 10rem; + + button { + .flex-container; + .flex-container-alignment(center, center); + background-color: transparent; + border: none; + color: @program-tab-text-color; + height: 17rem; + line-height: 6rem; + margin: 0; + padding: 0 2rem; + width: 100%; + + .base-icon { + .icon-sizing(8rem, 8rem, -2rem, -3rem); + margin-right: 2rem; + + &.bigger-indent { + margin-right: 3rem; + } + + &.wider-icon { + .icon-sizing(8rem, 10rem, -2rem, -2rem); + } + } + + .indicator-number { + font-weight: 400; + margin-top: 1rem; + margin-left: 2.5rem; + } + + &:hover, &:active { + background-color: @program-tab-hover-bg-color; + color: @program-dark-color; + cursor: pointer; + } + } + + &:first-child { + border-radius: 2rem 0 0 2rem; + + button { + border-radius: 1.75rem 0 0 1.75rem; + } + } + + &:not(:last-child) { + border-right: none; + } + + &:last-child { + border-radius: 0 2rem 2rem 0; + + button { + border-radius: 0 1.75rem 1.75rem 0; + } + } + + &.tab-active { + + button { + background-color: @program-tab-hover-bg-color; + color: @program-dark-color; + } + } + } +} \ No newline at end of file diff --git a/src/gui/qt-daemon/html/less/css/source/widgets.less b/src/gui/qt-daemon/html/less/css/source/widgets.less new file mode 100644 index 00000000..23da9498 --- /dev/null +++ b/src/gui/qt-daemon/html/less/css/source/widgets.less @@ -0,0 +1,466 @@ +@import "../variables"; +@import "mixins"; + +.widgets { + .flex-container; + flex-wrap: wrap; + margin: 3.5rem -3.5rem 3.5rem; + + .widget-wrapper { + //padding: 0 3.5rem 7rem; + //-webkit-transform: translateZ(0); + //transform: translateZ(0); + padding: 3.5rem 3.5rem; + transition: 0.1s; + + .widget-block { + background: fade(white, 60%); + border: 1px solid @program-panel-border-color; + border-radius: 3rem; + + .widget-header { + .flex-container; + .flex-container-alignment(center, space-between); + height: 13rem; + padding: 0 5rem; + + h3 { + color: @program-exuding-color; + font-size: 5.75rem; + font-weight: 300; + margin: 0; + + &.widget-select-wrapper { + .flex-container; + line-height: 6rem; + + .widget-select { + .flex-container; + margin-left: 5rem; + + .dropdown-toggle { + border-bottom: none; + color: @program-hover-color; + font-size: 5rem; + line-height: 6rem; + margin-bottom: -1rem; + padding: 0 3rem 0 0; + + .caret { + color: @program-input-placeholder-hover-color; + } + } + + .dropdown-menu { + min-width: 44rem; + } + } + } + } + + .widget-menu { + + .widget-menu-btn { + .flex-container; + background: transparent; + border: none; + margin: 0; + padding: 0; + + .base-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + color: @program-main-color; + } + } + + .widget-menu-list { + .menu-list(6.5rem, inherit, -2rem, 46rem); + } + } + } + + .widget-body-wrapper { + -webkit-transform: translateZ(0); + transform: translateZ(0); + border-bottom-left-radius: 3rem; + border-bottom-right-radius: 3rem; + overflow: hidden; + + .widget-body { + border-bottom-left-radius: 3rem; + border-bottom-right-radius: 3rem; + height: 53rem; + overflow-y: auto; + + table { + width: 100%; + + thead { + + tr { + background-color: fade(white, 40%); + color: @program-exuding-color; + font-size: 3.5rem; + height: 9rem; + + th { + font-weight: 400; + padding: 0 1rem; + text-transform: uppercase; + white-space: nowrap; + + .ordered-cell { + .flex-container; + .flex-container-alignment(center, flex-start); + + .order-icon { + .icon-sizing(2rem, 2rem, -5rem, -6rem); + color: @program-light-color; + cursor: pointer; + margin-left: 2rem; + margin-top: 0.25rem; + + &.active { + color: @program-exuding-color; + } + + &.rotate-icon { + transform: rotate(180deg); + } + } + } + + &:first-child { + padding-left: 5rem; + } + } + } + } + + tbody { + + tr { + color: @program-main-color; + font-size: 3.25rem; + height: 9rem; + + td { + padding: 0 1rem; + + .empty-table { + color: @program-empty-color; + text-align: center; + } + + &:first-child { + padding-left: 5rem; + position: relative; + } + + } + + &:nth-child(even) { + background-color: fade(white, 40%); + } + } + } + } + + .widget-loading { + .flex-container; + .flex-container-alignment(center, center); + color: @program-empty-color; + height: 100%; + } + } + } + } + + &.widget-small { + width: 50%; + } + + &.widget-big { + width: 100%; + } + + &.drag-not-possible { + + .widget-block { + box-shadow: 0 0 10px 3px rgb(255, 95, 95); + background-color: rgba(255, 95, 95, 0.6); + } + } + } + + .widget-long-item-wrapper { + max-width: 32rem; + + .table-long-item { + + .table-long-item-text { + font-size: 3.25rem; + } + } + } +} + + + +.payments-widget { + + tr.transaction-blocked { + background-color: @history-transaction-blocked-border-color !important; + color: @history-transaction-blocked-text-color !important; + + .transaction-status-indicator { + + .status-graph { + + &.income { + stroke: @history-transaction-blocked-status-income-color !important; + } + + &.outgoing { + stroke: @history-transaction-blocked-status-outgoing-color !important; + } + } + + .status-inner { + + .base-icon.income { + color: @history-transaction-blocked-status-income-color !important; + } + + .base-icon.outgoing { + color: @history-transaction-blocked-status-outgoing-color !important; + } + } + } + } + + .payments-marker { + + &::after { + content: ""; + position: absolute; + top: 0; + bottom: 0; + left: 0; + border-left: 1rem solid @marker-light-green; + } + } + + .transaction-status-indicator { + + .mined-icon { + font-size: 11rem; + + &:before { + top: -2.5rem; + left: -3.5rem; + } + } + } + + .payments-comment-wrapper { + .flex-container; + .flex-container-alignment(center, flex-start); + max-width: 9rem; + + .base-icon { + .icon-sizing(5rem, 5rem, -3.5rem, -4.5rem); + + &:hover { + color: @program-hover-color; + cursor: pointer; + } + } + } +} + +.contacts-widget { + + tr { + + td:last-child { + width: 20rem; + } + + &:hover { + + .contact-options-btn-wrapper { + visibility: visible; + } + } + } + + .contact-name { + .flex-container; + .flex-container-alignment(center, flex-start); + font-size: 3.25rem; + white-space: nowrap; + + .base-icon { + .icon-sizing(4rem, 4rem, -4rem, -5rem); + color: @program-table-icon-color; + margin-right: 1rem; + } + + &:hover { + color: @program-hover-color; + cursor: pointer; + + .base-icon { + color: @program-hover-color; + } + } + } + + .contact-connections { + max-width: 36rem; + } + + .contact-options-btn-wrapper { + .flex-container; + .flex-container-alignment(center, space-between); + visibility: hidden; + + .contact-options-btn { + .flex-container; + background: transparent; + border: none; + margin: 0; + padding: 0; + color: @program-main-color; + + .send-money-icon { + .icon-sizing(5rem, 5rem, -3.5rem, -4.5rem); + } + + .payments-icon { + .icon-sizing(5rem, 5rem, -3.5rem, -4.5rem); + } + + .delete-icon { + .icon-sizing(5rem, 5rem, -3.5rem, -4.5rem); + } + + &:disabled { + color: @program-light-color; + } + + &:hover { + + &:not(:disabled) { + color: @program-hover-color; + } + } + } + } +} + +.network-info-widget { + + .network-text-wrapper { + display: inline-block; + + .base-icon { + .icon-sizing(2rem, 2rem, -5rem, -6rem); + margin-left: 1rem; + } + + &:hover { + color: @program-hover-color; + cursor: pointer; + } + } +} + +.mining-widget { + border-top: none !important; + height: 58rem !important; + + .mining-widget-empty { + .flex-container; + .flex-container-alignment(center, center); + color: @program-empty-color; + font-size: 3.75rem; + height: 100%; + } + + .mining-widget-chart { + + .chart-range-wrapper { + .flex-container; + .flex-container-alignment(center, space-between); + padding: 2.5rem 7rem; + + .chart-range-group { + .flex-container; + .flex-container-alignment(center, center); + color: @program-dark-color; + font-size: 3rem; + + .chart-range-selector { + .flex-container; + margin: 0 2.5rem; + padding: 0; + + li { + border: 1px solid @mining-range-border-color; + color: @mining-range-text-color; + line-height: 5.5rem; + height: 6rem; + width: 14rem; + text-align: center; + list-style-type: none; + + &:first-child { + border-radius: 3rem 0 0 3rem; + width: 14.5rem; + } + + &:not(:first-child) { + border-left: none; + } + + &:last-child { + border-radius: 0 3rem 3rem 0; + width: 14.5rem; + } + } + + .active { + background: white; + color: @program-dark-color; + } + } + } + } + + .chart-graph { + height: 47rem; + width: 100%; + } + } +} + +//TODO active line when tooltip clicked +/*.active-widget-tr { + background: #dce4d3 !important; + color: #062f1b !important; + + .comment { + .icon { + color: #062f1b !important; + } + } +}*/ + +.red-row{ + background-color: #e95145 !important; + color: #FFFFFF; +} + + diff --git a/src/gui/qt-daemon/html/less/css/variables.less b/src/gui/qt-daemon/html/less/css/variables.less new file mode 100644 index 00000000..ec125087 --- /dev/null +++ b/src/gui/qt-daemon/html/less/css/variables.less @@ -0,0 +1,173 @@ +@xs: ~"(max-width: 767px)"; +@sm: ~"(min-width: 768px)"; +@md: ~"(min-width: 992px)"; +@lg: ~"(min-width: 1200px)"; + +@min-width: 250rem; + +@background-image: url('../img/bg_blue.jpg'); +@program-online-color: #5d6c78; +@program-offline-color: #cd5044; +@scroll-light-color: fade(white, 70%); +@scroll-dark-color: #7b919e; +@error-color: #e9301d; +@success-color: #1d9f5f; +@box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.25); +@modal-form-shadow: 0 0.5rem 0.75rem 0 rgba(0, 0, 0, 0.15); +@table-item-shadow: 0 1.5rem 3rem rgba(0, 0, 0, 0.175); +@market-details-shadow: 0 2.5rem 6rem 0 rgba(0, 0, 0, 0.45); + +@program-header-text-color: #004d73; +@program-header-text-blocked-color: #aaafb4; +@program-header-border-color: #edf2f4; +@program-header-bg-hover-color: #f4f9fb; +@program-header-bg-active-color: #d5e6f0; +@program-header-indicator-text-color: #b83a2d; +@program-header-indicator-border-color: #d48279; + +@program-table-bg-color: fade(white, 60%); +@program-table-header-bg-color: fade(white, 40%); +@program-table-border-color: #e1e8eb; +@program-table-icon-color: #5a7388; +@program-table-button-border-color: #adbbbe; +@program-table-button-border-hover-color: #b3ac90; +@program-table-button-icon-hover-color: #7d5d1f; + +@program-tab-bg-color: fade(white, 50%); +@program-tab-hover-bg-color: white; +@program-tab-border-color: #e1e8eb; +@program-tab-text-color: #4d7a92; + +@program-filter-button-border-color: #e1e8eb; +@program-options-bg-hover-color: #f1f6f9; + +@program-panel-bg-color: fade(white, 60%); +@program-panel-header-bg-color: #d5e6ef; +@program-panel-border-color: #e1e8eb; +@program-panel-divider-color: #e1e8eb; + +@program-pagination-text-color: #1f415d; +@program-pagination-text-inactive-color: #83919d; +@program-pagination-border-color: #e3eaec; +@program-pagination-pages-color: #a2bac9; + +@marker-red: #f1b2b2; +@marker-yellow: #fce493; +@marker-grey: #aaafb4; +@marker-escrow: #65a9de; +@marker-light-green: #a7c790; + +@program-exuding-color: #142839; +@program-main-color: #1f415d; +@program-dark-color: #004d73; +@program-light-color: #929ca4; +@program-empty-color: #7190a1; +@program-hover-color: #74520f; +@program-label-color: #004d73; +@program-label-subtext-color: #417b96; +@program-label-info-color: #548ca8; + +@program-modal-header-color: #d5e6ef; +@program-modal-header-close-color: #88a1b5; +@program-modal-divider-color: #dae1e2; +@program-modal-active-line-color: #61de11; + +@program-select-hover-color: #eef3f6; +@program-select-selected-color: #e3ecf1; +@program-input-text-color: #142839; +@program-input-border-color: #828d97; +@program-input-placeholder-color: #aaafb4; +@program-input-placeholder-hover-color: #bca577; +@program-input-icon-color: #787f86; +@program-checkbox-border-color: #718ea7; +@program-switch-text-color: #5888a1; +@program-range-border-color: #a2b9c5; +@program-range-selected-color: #4d7a92; +@program-button-bg-color: white; +@program-button-hover-bg-color: #f5f8f9; +@program-button-active-bg-color: #f1f6f9; +@program-button-text-color: #004d73; +@program-button-border-color: #e2eaed; +@program-button-border-hover-color: #e1e2d9; +@program-button-divider-color: #c3ced4; +@program-button-done-icon-color: #60d22d; +@program-button-subtext-color: #709bb1; +@program-clear-button-color: #a64833; +@program-clear-button-hover-color: #a64833; +@program-progress-bar-bg-color: #e1e3e4; +@program-progress-bar-fill-color: #95a2ac; +@program-mined-icon-color: #81be55; +@program-payments-income-color: #67aa3b; +@program-payments-outgoing-color: #e27078; +@program-transaction-status-inner-color: #b4bcc1; +@program-transaction-status-pending-inner-color: #57b85f; +@program-transaction-status-sending-inner-color: #e47661; +@program-copy-icon-color: fade(@program-exuding-color, 50%); +@program-divider-color: #f3f5f4; +@program-selection-bg-color: #e8cca8; + +@dashboard-indicator-text-color: #004d73; +@dashboard-indicator-icon-color: #004d73; +@dashboard-slider-border-color: #c6d4dc; +@dashboard-slider-icon-color: #578aa2; +@dashboard-alias-border-color: #c9d4d9; +@safes-indicator-color: #3c7592; +@safes-block-text-color: #8b96a0; +@safes-block-text-open-color: #1f415d; +@safes-block-mined-bg-color: #95b5c7; +@safes-block-mined-icon-color: #ecf1f2; +@safes-alias-border-color: #adbbbe; +@safes-alias-border-hover-color: #d5cab9; +@safes-balance-text-color: #8b96a0; +@safe-pages-switch-bg-color: white; +@safe-pages-switch-bg-hover-color: #f1f6f9; +@safe-pages-switch-border-color: #e9eef2; +@safe-pages-switch-text-color: #9ab1c4; +@safe-pages-switch-text-hover-color: #1f415d; +@safe-balance-indicator-color: #f5b81b; +@safe-mined-indicator-color: #aab5ba; +@safe-mined-completed-indicator-color: #539f42; +@safe-button-border-hover-color: #97835c; +@safe-alias-icon-color: #87929b; +@safe-alias-icon-hover-color: #828d97; +@safe-button-bg-color: fade(white, 80%); +@market-header-icon-color: #6a9cb6; +@market-favorite-color: #cd5044; +@market-detail-divider-color: #ebeeec; +@escrow-transaction-status-color: #338dd4; +@history-transaction-blocked-border-color: #e95145; +@history-transaction-blocked-text-color: #fbe3e2; +@history-transaction-blocked-status-income-color: #a2be7e; +@history-transaction-blocked-status-outgoing-color: #c51616; +@history-transaction-blocked-alias-color: #f2a09b; +@history-transaction-blocked-hover-color: #e7c48e; +@contacts-groups-border-color: #e9eef2; +@contacts-accounts-btn-text-color: #7e858c; +@export-import-contacts-text-color: #004d73; +@export-import-contacts-border-color: #e1e8eb; +@mining-range-text-color: #7190a1; +@mining-range-border-color: #e0e7ed; +@bug-report-button-color: white; + +@send-money-contacts-hover-color: #f4f0d7; +@send-money-contacts-icon-hover-color: #97835c; +@send-money-contacts-address-hover-color: #bca577; + +@create-safe-progress-bar-step-color: #95b5c7; +@create-safe-progress-bar-bg-color: fade(@create-safe-progress-bar-step-color, 25%); +@create-safe-progress-bar-fill-color: #89b0c6; + +@modal-update-text-color: #f4f6e9; +@modal-update-green-color: #61a75b; +@modal-update-yellow-color: #cdb912; +@modal-update-red-color: #e95145; + +@datepicker-nav-action-color: #004d73; +@datepicker-nav-title-color: #142839; +@datepicker-day-name-color: #a8b2b9; +@datepicker-day-other-month-color: #5888a1; +@datepicker-cell-border-color: #83a7b9; +@datepicker-cell-selected-color: #d5e6f0; + +@highcharts-scrollbar-color: #a5adb5; +@highcharts-axis-line-color: fade(#a5adb5, 75%); \ No newline at end of file diff --git a/src/gui/qt-daemon/html/loading.png b/src/gui/qt-daemon/html/loading.png new file mode 100644 index 00000000..694d2330 Binary files /dev/null and b/src/gui/qt-daemon/html/loading.png differ diff --git a/src/gui/qt-daemon/html/lock.svg b/src/gui/qt-daemon/html/lock.svg new file mode 100644 index 00000000..021aae19 --- /dev/null +++ b/src/gui/qt-daemon/html/lock.svg @@ -0,0 +1,12 @@ + + + + + + diff --git a/src/gui/qt-daemon/html/logo.png b/src/gui/qt-daemon/html/logo.png new file mode 100644 index 00000000..3ca30b1b Binary files /dev/null and b/src/gui/qt-daemon/html/logo.png differ diff --git a/src/gui/qt-daemon/html/logout.svg b/src/gui/qt-daemon/html/logout.svg new file mode 100644 index 00000000..ef77f2cc --- /dev/null +++ b/src/gui/qt-daemon/html/logout.svg @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/src/gui/qt-daemon/html/main.js b/src/gui/qt-daemon/html/main.js new file mode 100644 index 00000000..bb7c2e38 --- /dev/null +++ b/src/gui/qt-daemon/html/main.js @@ -0,0 +1,5329 @@ +(window["webpackJsonp"] = window["webpackJsonp"] || []).push([["main"],{ + +/***/ "./src/$$_lazy_route_resource lazy recursive": +/*!**********************************************************!*\ + !*** ./src/$$_lazy_route_resource lazy namespace object ***! + \**********************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +function webpackEmptyAsyncContext(req) { + // Here Promise.resolve().then() is used instead of new Promise() to prevent + // uncaught exception popping up in devtools + return Promise.resolve().then(function() { + var e = new Error("Cannot find module '" + req + "'"); + e.code = 'MODULE_NOT_FOUND'; + throw e; + }); +} +webpackEmptyAsyncContext.keys = function() { return []; }; +webpackEmptyAsyncContext.resolve = webpackEmptyAsyncContext; +module.exports = webpackEmptyAsyncContext; +webpackEmptyAsyncContext.id = "./src/$$_lazy_route_resource lazy recursive"; + +/***/ }), + +/***/ "./src/app/_helpers/directives/input-validate/input-validate.directive.ts": +/*!********************************************************************************!*\ + !*** ./src/app/_helpers/directives/input-validate/input-validate.directive.ts ***! + \********************************************************************************/ +/*! exports provided: InputValidateDirective */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InputValidateDirective", function() { return InputValidateDirective; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var inputmask__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! inputmask */ "./node_modules/inputmask/index.js"); +/* harmony import */ var inputmask__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(inputmask__WEBPACK_IMPORTED_MODULE_1__); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + + +var InputValidateDirective = /** @class */ (function () { + function InputValidateDirective(el) { + this.el = el; + this.regexMap = { + integer: { + regex: '^[0-9]*$', + placeholder: '' + }, + // float: '^[+-]?([0-9]*[.])?[0-9]+$', + // words: '([A-z]*\\s)*', + // point25: '^\-?[0-9]*(?:\\.25|\\.50|\\.75|)$', + money: { + alias: 'decimal', + digits: 8, + max: 999999999999, + rightAlign: false, + allowMinus: false, + onBeforeMask: function (value) { return value; } + } + }; + } + Object.defineProperty(InputValidateDirective.prototype, "defineInputType", { + set: function (type) { + inputmask__WEBPACK_IMPORTED_MODULE_1__(this.regexMap[type]).mask(this.el.nativeElement); + }, + enumerable: true, + configurable: true + }); + __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Input"])('appInputValidate'), + __metadata("design:type", String), + __metadata("design:paramtypes", [String]) + ], InputValidateDirective.prototype, "defineInputType", null); + InputValidateDirective = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Directive"])({ + selector: '[appInputValidate]' + }), + __metadata("design:paramtypes", [_angular_core__WEBPACK_IMPORTED_MODULE_0__["ElementRef"]]) + ], InputValidateDirective); + return InputValidateDirective; +}()); + + + +/***/ }), + +/***/ "./src/app/_helpers/directives/modal-container/modal-container.component.html": +/*!************************************************************************************!*\ + !*** ./src/app/_helpers/directives/modal-container/modal-container.component.html ***! + \************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = "
\r\n
\r\n \r\n
\r\n Success\r\n Successfully\r\n
\r\n
\r\n \r\n \r\n
\r\n" + +/***/ }), + +/***/ "./src/app/_helpers/directives/modal-container/modal-container.component.scss": +/*!************************************************************************************!*\ + !*** ./src/app/_helpers/directives/modal-container/modal-container.component.scss ***! + \************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = ":host {\n position: fixed;\n top: 0;\n bottom: 0;\n left: 0;\n right: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgba(255, 255, 255, 0.25); }\n\n.modal {\n position: relative;\n display: flex;\n flex-direction: column;\n padding: 2rem;\n width: 34rem;\n background: #1a1a1a; }\n\n.modal .content {\n display: flex;\n margin: 1.2rem 0; }\n\n.modal .content .icon {\n width: 4.4rem;\n height: 4.4rem; }\n\n.modal .content .message {\n display: flex;\n flex-direction: column;\n margin-left: 2rem; }\n\n.modal .action-button {\n background: #2c95f1;\n margin: 1.2rem auto 0.6rem;\n width: 10rem;\n height: 2.4rem; }\n\n.modal .close-button {\n position: absolute;\n top: 0.5rem;\n right: 0.5rem;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n margin: 0;\n padding: 0;\n width: 1.5rem;\n height: 1.5rem; }\n\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvX2hlbHBlcnMvZGlyZWN0aXZlcy9tb2RhbC1jb250YWluZXIvRDpcXHphbm8vc3JjXFxhcHBcXF9oZWxwZXJzXFxkaXJlY3RpdmVzXFxtb2RhbC1jb250YWluZXJcXG1vZGFsLWNvbnRhaW5lci5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLGdCQUFlO0VBQ2YsT0FBTTtFQUNOLFVBQVM7RUFDVCxRQUFPO0VBQ1AsU0FBUTtFQUNSLGNBQWE7RUFDYixvQkFBbUI7RUFDbkIsd0JBQXVCO0VBQ3ZCLHNDQUFxQyxFQUN0Qzs7QUFDRDtFQUNFLG1CQUFrQjtFQUNsQixjQUFhO0VBQ2IsdUJBQXNCO0VBQ3RCLGNBQWE7RUFDYixhQUFZO0VBQ1osb0JBQW1CLEVBc0NwQjs7QUE1Q0Q7SUFTSSxjQUFhO0lBQ2IsaUJBQWdCLEVBWWpCOztBQXRCSDtNQWFNLGNBQWE7TUFDYixlQUFjLEVBQ2Y7O0FBZkw7TUFrQk0sY0FBYTtNQUNiLHVCQUFzQjtNQUN0QixrQkFBaUIsRUFDbEI7O0FBckJMO0lBeUJJLG9CQUFtQjtJQUNuQiwyQkFBMEI7SUFDMUIsYUFBWTtJQUNaLGVBQWMsRUFDZjs7QUE3Qkg7SUFnQ0ksbUJBQWtCO0lBQ2xCLFlBQVc7SUFDWCxjQUFhO0lBQ2IsY0FBYTtJQUNiLG9CQUFtQjtJQUNuQix3QkFBdUI7SUFDdkIsd0JBQXVCO0lBQ3ZCLFVBQVM7SUFDVCxXQUFVO0lBQ1YsY0FBYTtJQUNiLGVBQWMsRUFDZiIsImZpbGUiOiJzcmMvYXBwL19oZWxwZXJzL2RpcmVjdGl2ZXMvbW9kYWwtY29udGFpbmVyL21vZGFsLWNvbnRhaW5lci5jb21wb25lbnQuc2NzcyIsInNvdXJjZXNDb250ZW50IjpbIjpob3N0IHtcclxuICBwb3NpdGlvbjogZml4ZWQ7XHJcbiAgdG9wOiAwO1xyXG4gIGJvdHRvbTogMDtcclxuICBsZWZ0OiAwO1xyXG4gIHJpZ2h0OiAwO1xyXG4gIGRpc3BsYXk6IGZsZXg7XHJcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcclxuICBiYWNrZ3JvdW5kOiByZ2JhKDI1NSwgMjU1LCAyNTUsIDAuMjUpO1xyXG59XHJcbi5tb2RhbCB7XHJcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xyXG4gIGRpc3BsYXk6IGZsZXg7XHJcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICBwYWRkaW5nOiAycmVtO1xyXG4gIHdpZHRoOiAzNHJlbTtcclxuICBiYWNrZ3JvdW5kOiAjMWExYTFhO1xyXG5cclxuICAuY29udGVudCB7XHJcbiAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgbWFyZ2luOiAxLjJyZW0gMDtcclxuXHJcbiAgICAuaWNvbiB7XHJcbiAgICAgIHdpZHRoOiA0LjRyZW07XHJcbiAgICAgIGhlaWdodDogNC40cmVtO1xyXG4gICAgfVxyXG5cclxuICAgIC5tZXNzYWdlIHtcclxuICAgICAgZGlzcGxheTogZmxleDtcclxuICAgICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICAgICAgbWFyZ2luLWxlZnQ6IDJyZW07XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAuYWN0aW9uLWJ1dHRvbiB7XHJcbiAgICBiYWNrZ3JvdW5kOiAjMmM5NWYxO1xyXG4gICAgbWFyZ2luOiAxLjJyZW0gYXV0byAwLjZyZW07XHJcbiAgICB3aWR0aDogMTByZW07XHJcbiAgICBoZWlnaHQ6IDIuNHJlbTtcclxuICB9XHJcblxyXG4gIC5jbG9zZS1idXR0b24ge1xyXG4gICAgcG9zaXRpb246IGFic29sdXRlO1xyXG4gICAgdG9wOiAwLjVyZW07XHJcbiAgICByaWdodDogMC41cmVtO1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAgICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcclxuICAgIGJhY2tncm91bmQ6IHRyYW5zcGFyZW50O1xyXG4gICAgbWFyZ2luOiAwO1xyXG4gICAgcGFkZGluZzogMDtcclxuICAgIHdpZHRoOiAxLjVyZW07XHJcbiAgICBoZWlnaHQ6IDEuNXJlbTtcclxuICB9XHJcbn1cclxuIl19 */" + +/***/ }), + +/***/ "./src/app/_helpers/directives/modal-container/modal-container.component.ts": +/*!**********************************************************************************!*\ + !*** ./src/app/_helpers/directives/modal-container/modal-container.component.ts ***! + \**********************************************************************************/ +/*! exports provided: ModalContainerComponent */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ModalContainerComponent", function() { return ModalContainerComponent; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + +var ModalContainerComponent = /** @class */ (function () { + function ModalContainerComponent() { + } + ModalContainerComponent.prototype.ngOnInit = function () { + }; + ModalContainerComponent = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Component"])({ + selector: 'app-modal-container', + template: __webpack_require__(/*! ./modal-container.component.html */ "./src/app/_helpers/directives/modal-container/modal-container.component.html"), + styles: [__webpack_require__(/*! ./modal-container.component.scss */ "./src/app/_helpers/directives/modal-container/modal-container.component.scss")] + }), + __metadata("design:paramtypes", []) + ], ModalContainerComponent); + return ModalContainerComponent; +}()); + + + +/***/ }), + +/***/ "./src/app/_helpers/directives/staking-switch/staking-switch.component.html": +/*!**********************************************************************************!*\ + !*** ./src/app/_helpers/directives/staking-switch/staking-switch.component.html ***! + \**********************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = "
\r\n ON\r\n \r\n OFF\r\n
\r\n" + +/***/ }), + +/***/ "./src/app/_helpers/directives/staking-switch/staking-switch.component.scss": +/*!**********************************************************************************!*\ + !*** ./src/app/_helpers/directives/staking-switch/staking-switch.component.scss ***! + \**********************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = ".switch {\n display: flex;\n align-items: center;\n justify-content: space-between;\n border-radius: 1rem;\n cursor: pointer;\n font-size: 1rem;\n padding: 0.5rem;\n width: 5rem;\n height: 2rem; }\n .switch .circle {\n border-radius: 1rem;\n width: 1.2rem;\n height: 1.2rem; }\n .switch .option {\n margin: 0 0.2rem;\n line-height: 1.2rem; }\n\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvX2hlbHBlcnMvZGlyZWN0aXZlcy9zdGFraW5nLXN3aXRjaC9EOlxcemFuby9zcmNcXGFwcFxcX2hlbHBlcnNcXGRpcmVjdGl2ZXNcXHN0YWtpbmctc3dpdGNoXFxzdGFraW5nLXN3aXRjaC5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLGNBQWE7RUFDYixvQkFBbUI7RUFDbkIsK0JBQThCO0VBQzlCLG9CQUFtQjtFQUNuQixnQkFBZTtFQUNmLGdCQUFlO0VBQ2YsZ0JBQWU7RUFDZixZQUFXO0VBQ1gsYUFBWSxFQVliO0VBckJEO0lBWUksb0JBQW1CO0lBQ25CLGNBQWE7SUFDYixlQUFjLEVBQ2Y7RUFmSDtJQWtCSSxpQkFBZ0I7SUFDaEIsb0JBQW1CLEVBQ3BCIiwiZmlsZSI6InNyYy9hcHAvX2hlbHBlcnMvZGlyZWN0aXZlcy9zdGFraW5nLXN3aXRjaC9zdGFraW5nLXN3aXRjaC5jb21wb25lbnQuc2NzcyIsInNvdXJjZXNDb250ZW50IjpbIi5zd2l0Y2gge1xyXG4gIGRpc3BsYXk6IGZsZXg7XHJcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XHJcbiAgYm9yZGVyLXJhZGl1czogMXJlbTtcclxuICBjdXJzb3I6IHBvaW50ZXI7XHJcbiAgZm9udC1zaXplOiAxcmVtO1xyXG4gIHBhZGRpbmc6IDAuNXJlbTtcclxuICB3aWR0aDogNXJlbTtcclxuICBoZWlnaHQ6IDJyZW07XHJcblxyXG4gIC5jaXJjbGUge1xyXG4gICAgYm9yZGVyLXJhZGl1czogMXJlbTtcclxuICAgIHdpZHRoOiAxLjJyZW07XHJcbiAgICBoZWlnaHQ6IDEuMnJlbTtcclxuICB9XHJcblxyXG4gIC5vcHRpb24ge1xyXG4gICAgbWFyZ2luOiAwIDAuMnJlbTtcclxuICAgIGxpbmUtaGVpZ2h0OiAxLjJyZW07XHJcbiAgfVxyXG59XHJcbiJdfQ== */" + +/***/ }), + +/***/ "./src/app/_helpers/directives/staking-switch/staking-switch.component.ts": +/*!********************************************************************************!*\ + !*** ./src/app/_helpers/directives/staking-switch/staking-switch.component.ts ***! + \********************************************************************************/ +/*! exports provided: StakingSwitchComponent */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StakingSwitchComponent", function() { return StakingSwitchComponent; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var _services_backend_service__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../services/backend.service */ "./src/app/_helpers/services/backend.service.ts"); +/* harmony import */ var _services_variables_service__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../services/variables.service */ "./src/app/_helpers/services/variables.service.ts"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + + + +var StakingSwitchComponent = /** @class */ (function () { + function StakingSwitchComponent(backend, variablesService) { + this.backend = backend; + this.variablesService = variablesService; + this.stakingChange = new _angular_core__WEBPACK_IMPORTED_MODULE_0__["EventEmitter"](); + } + StakingSwitchComponent.prototype.ngOnInit = function () { + }; + StakingSwitchComponent.prototype.toggleStaking = function () { + var wallet = this.variablesService.getWallet(this.wallet_id); + if (wallet && wallet.loaded) { + this.stakingChange.emit(!this.staking); + if (!this.staking) { + this.backend.startPosMining(this.wallet_id); + } + else { + this.backend.stopPosMining(this.wallet_id); + } + } + }; + __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Input"])(), + __metadata("design:type", Boolean) + ], StakingSwitchComponent.prototype, "wallet_id", void 0); + __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Input"])(), + __metadata("design:type", Boolean) + ], StakingSwitchComponent.prototype, "staking", void 0); + __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Output"])(), + __metadata("design:type", Object) + ], StakingSwitchComponent.prototype, "stakingChange", void 0); + StakingSwitchComponent = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Component"])({ + selector: 'app-staking-switch', + template: __webpack_require__(/*! ./staking-switch.component.html */ "./src/app/_helpers/directives/staking-switch/staking-switch.component.html"), + styles: [__webpack_require__(/*! ./staking-switch.component.scss */ "./src/app/_helpers/directives/staking-switch/staking-switch.component.scss")] + }), + __metadata("design:paramtypes", [_services_backend_service__WEBPACK_IMPORTED_MODULE_1__["BackendService"], _services_variables_service__WEBPACK_IMPORTED_MODULE_2__["VariablesService"]]) + ], StakingSwitchComponent); + return StakingSwitchComponent; +}()); + + + +/***/ }), + +/***/ "./src/app/_helpers/directives/tooltip.directive.ts": +/*!**********************************************************!*\ + !*** ./src/app/_helpers/directives/tooltip.directive.ts ***! + \**********************************************************/ +/*! exports provided: TooltipDirective */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TooltipDirective", function() { return TooltipDirective; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + +var TooltipDirective = /** @class */ (function () { + function TooltipDirective(el, renderer) { + this.el = el; + this.renderer = renderer; + this.offset = 10; + } + TooltipDirective.prototype.onMouseEnter = function () { + if (!this.tooltip) { + this.show(); + } + }; + TooltipDirective.prototype.onMouseLeave = function () { + if (this.tooltip) { + this.hide(); + } + }; + TooltipDirective.prototype.show = function () { + this.create(); + this.setPosition(); + }; + TooltipDirective.prototype.hide = function () { + var _this = this; + this.renderer.setStyle(this.tooltip, 'opacity', '0'); + window.setTimeout(function () { + _this.renderer.removeChild(document.body, _this.tooltip); + _this.tooltip = null; + }, this.delay); + }; + TooltipDirective.prototype.create = function () { + var _this = this; + this.tooltip = this.renderer.createElement('span'); + this.renderer.appendChild(this.tooltip, this.renderer.createText(this.tooltipTitle)); + this.renderer.appendChild(document.body, this.tooltip); + this.renderer.setStyle(document.body, 'position', 'relative'); + this.renderer.setStyle(this.tooltip, 'position', 'absolute'); + if (this.tooltipClass !== null) { + this.renderer.addClass(this.tooltip, this.tooltipClass); + } + if (this.placement !== null) { + this.renderer.addClass(this.tooltip, 'ng-tooltip-' + this.placement); + } + else { + this.placement = 'top'; + this.renderer.addClass(this.tooltip, 'ng-tooltip-top'); + } + if (this.delay !== null) { + this.renderer.setStyle(this.tooltip, 'opacity', '0'); + this.renderer.setStyle(this.tooltip, '-webkit-transition', "opacity " + this.delay + "ms"); + this.renderer.setStyle(this.tooltip, '-moz-transition', "opacity " + this.delay + "ms"); + this.renderer.setStyle(this.tooltip, '-o-transition', "opacity " + this.delay + "ms"); + this.renderer.setStyle(this.tooltip, 'transition', "opacity " + this.delay + "ms"); + window.setTimeout(function () { + _this.renderer.setStyle(_this.tooltip, 'opacity', '1'); + }, 0); + } + }; + TooltipDirective.prototype.setPosition = function () { + var hostPos = this.el.nativeElement.getBoundingClientRect(); + var tooltipPos = this.tooltip.getBoundingClientRect(); + // const scrollPos = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0; + if (this.placement === 'top') { + this.renderer.setStyle(this.tooltip, 'top', hostPos.top - tooltipPos.height + 'px'); + this.renderer.setStyle(this.tooltip, 'left', hostPos.left + 'px'); + } + if (this.placement === 'bottom') { + this.renderer.setStyle(this.tooltip, 'top', hostPos.bottom + 'px'); + this.renderer.setStyle(this.tooltip, 'left', hostPos.left + 'px'); + } + if (this.placement === 'left') { + this.renderer.setStyle(this.tooltip, 'top', hostPos.top + 'px'); + this.renderer.setStyle(this.tooltip, 'left', hostPos.left - tooltipPos.width + 'px'); + } + if (this.placement === 'right') { + this.renderer.setStyle(this.tooltip, 'top', hostPos.top + 'px'); + this.renderer.setStyle(this.tooltip, 'left', hostPos.right + 'px'); + } + }; + __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Input"])('tooltip'), + __metadata("design:type", String) + ], TooltipDirective.prototype, "tooltipTitle", void 0); + __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Input"])(), + __metadata("design:type", String) + ], TooltipDirective.prototype, "placement", void 0); + __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Input"])(), + __metadata("design:type", String) + ], TooltipDirective.prototype, "tooltipClass", void 0); + __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Input"])(), + __metadata("design:type", Number) + ], TooltipDirective.prototype, "delay", void 0); + __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["HostListener"])('mouseenter'), + __metadata("design:type", Function), + __metadata("design:paramtypes", []), + __metadata("design:returntype", void 0) + ], TooltipDirective.prototype, "onMouseEnter", null); + __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["HostListener"])('mouseleave'), + __metadata("design:type", Function), + __metadata("design:paramtypes", []), + __metadata("design:returntype", void 0) + ], TooltipDirective.prototype, "onMouseLeave", null); + TooltipDirective = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Directive"])({ + selector: '[tooltip]', + host: { + '[style.cursor]': '"pointer"' + } + }), + __metadata("design:paramtypes", [_angular_core__WEBPACK_IMPORTED_MODULE_0__["ElementRef"], _angular_core__WEBPACK_IMPORTED_MODULE_0__["Renderer2"]]) + ], TooltipDirective); + return TooltipDirective; +}()); + + + +/***/ }), + +/***/ "./src/app/_helpers/models/wallet.model.ts": +/*!*************************************************!*\ + !*** ./src/app/_helpers/models/wallet.model.ts ***! + \*************************************************/ +/*! exports provided: Wallet */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Wallet", function() { return Wallet; }); +var Wallet = /** @class */ (function () { + function Wallet(id, name, pass, path, address, balance, unlocked_balance, mined, tracking) { + if (balance === void 0) { balance = 0; } + if (unlocked_balance === void 0) { unlocked_balance = 0; } + if (mined === void 0) { mined = 0; } + if (tracking === void 0) { tracking = ''; } + this.contracts = []; + this.wallet_id = id; + this.name = name; + this.pass = pass; + this.path = path; + this.address = address; + this.balance = balance; + this.unlocked_balance = unlocked_balance; + this.mined_total = mined; + this.tracking_hey = tracking; + this.alias = ''; + this.staking = false; + this.new_messages = 0; + this.new_contracts = 0; + this.history = []; + this.excluded_history = []; + this.progress = 0; + this.loaded = false; + } + Wallet.prototype.getMoneyEquivalent = function (equivalent) { + return this.balance * equivalent; + }; + Wallet.prototype.havePass = function () { + return (this.pass !== '' && this.pass !== null); + }; + Wallet.prototype.isActive = function (id) { + return this.wallet_id === id; + }; + Wallet.prototype.prepareHistoryItem = function (item) { + if (item.tx_type === 4) { + item.sortFee = -(item.amount + item.fee); + item.sortAmount = 0; + } + else if (item.tx_type === 3) { + item.sortFee = 0; + } + else if ((item.hasOwnProperty('contract') && (item.contract[0].state === 3 || item.contract[0].state === 6 || item.contract[0].state === 601) && !item.contract[0].is_a)) { + item.sortFee = -item.fee; + item.sortAmount = item.amount; + } + else { + if (!item.is_income) { + item.sortFee = -item.fee; + item.sortAmount = -item.amount; + } + else { + item.sortAmount = item.amount; + } + } + return item; + }; + Wallet.prototype.prepareHistory = function (items) { + for (var i = 0; i < items.length; i++) { + if ((items[i].tx_type === 7 && items[i].is_income) || (items[i].tx_type === 11 && items[i].is_income) || (items[i].amount === 0 && items[i].fee === 0)) { + var exists = false; + for (var j = 0; j < this.excluded_history.length; j++) { + if (this.excluded_history[j].tx_hash === items[i].tx_hash) { + exists = true; + if (this.excluded_history[j].height !== items[i].height) { + this.excluded_history[j] = items[i]; + } + break; + } + } + if (!exists) { + this.excluded_history.push(items[i]); + } + } + else { + var exists = false; + for (var j = 0; j < this.history.length; j++) { + if (this.history[j].tx_hash === items[i].tx_hash) { + exists = true; + if (this.history[j].height !== items[i].height) { + this.history[j] = this.prepareHistoryItem(items[i]); + } + break; + } + } + if (!exists) { + if (this.history.length && items[i].timestamp > this.history[0].timestamp) { + this.history.unshift(this.prepareHistoryItem(items[i])); + } + else { + this.history.push(this.prepareHistoryItem(items[i])); + } + } + } + } + }; + Wallet.prototype.prepareContractsAfterOpen = function (items, exp_med_ts, height_app, viewedContracts, notViewedContracts) { + var safe = this; + var _loop_1 = function (i) { + var contract = items[i]; + var contractTransactionExist = false; + if (safe && safe.history) { + contractTransactionExist = safe.history.some(function (elem) { return elem.contract && elem.contract.length && elem.contract[0].contract_id === contract.contract_id; }); + } + if (!contractTransactionExist && safe && safe.excluded_history) { + contractTransactionExist = safe.excluded_history.some(function (elem) { return elem.contract && elem.contract.length && elem.contract[0].contract_id === contract.contract_id; }); + } + if (!contractTransactionExist) { + contract.state = 140; + } + else if (contract.state === 1 && contract.expiration_time < exp_med_ts) { + contract.state = 110; + } + else if (contract.state === 2 && contract.cancel_expiration_time !== 0 && contract.cancel_expiration_time < exp_med_ts && contract.height === 0) { + var searchResult1 = viewedContracts.some(function (elem) { return elem.state === 2 && elem.is_a === contract.is_a && elem.contract_id === contract.contract_id; }); + if (!searchResult1) { + contract.state = 130; + contract.is_new = true; + } + } + else if (contract.state === 1) { + var searchResult2 = notViewedContracts.find(function (elem) { return elem.state === 110 && elem.is_a === contract.is_a && elem.contract_id === contract.contract_id; }); + if (searchResult2) { + if (searchResult2.time === contract.expiration_time) { + contract.state = 110; + } + else { + for (var j = 0; j < notViewedContracts.length; j++) { + if (notViewedContracts[j].contract_id === contract.contract_id && notViewedContracts[j].is_a === contract.is_a) { + notViewedContracts.splice(j, 1); + break; + } + } + for (var j = 0; j < viewedContracts.length; j++) { + if (viewedContracts[j].contract_id === contract.contract_id && viewedContracts[j].is_a === contract.is_a) { + viewedContracts.splice(j, 1); + break; + } + } + } + } + } + else if (contract.state === 2 && (contract.height === 0 || (height_app - contract.height) < 10)) { + contract.state = 201; + } + else if (contract.state === 2) { + var searchResult3 = viewedContracts.some(function (elem) { return elem.state === 120 && elem.is_a === contract.is_a && elem.contract_id === contract.contract_id; }); + if (searchResult3) { + contract.state = 120; + } + } + else if (contract.state === 5) { + var searchResult4 = notViewedContracts.find(function (elem) { return elem.state === 130 && elem.is_a === contract.is_a && elem.contract_id === contract.contract_id; }); + if (searchResult4) { + if (searchResult4.time === contract.cancel_expiration_time) { + contract.state = 130; + } + else { + for (var j = 0; j < notViewedContracts.length; j++) { + if (notViewedContracts[j].contract_id === contract.contract_id && notViewedContracts[j].is_a === contract.is_a) { + notViewedContracts.splice(j, 1); + break; + } + } + for (var j = 0; j < viewedContracts.length; j++) { + if (viewedContracts[j].contract_id === contract.contract_id && viewedContracts[j].is_a === contract.is_a) { + viewedContracts.splice(j, 1); + break; + } + } + } + } + } + else if (contract.state === 6 && (contract.height === 0 || (height_app - contract.height) < 10)) { + contract.state = 601; + } + var searchResult = viewedContracts.some(function (elem) { return elem.state === contract.state && elem.is_a === contract.is_a && elem.contract_id === contract.contract_id; }); + contract.is_new = !searchResult; + contract['private_detailes'].a_pledge += contract['private_detailes'].to_pay; + safe.contracts.push(contract); + }; + for (var i = 0; i < items.length; i++) { + _loop_1(i); + } + this.recountNewContracts(); + }; + Wallet.prototype.recountNewContracts = function () { + this.new_contracts = (this.contracts.filter(function (item) { return item.is_new === true; })).length; + }; + Wallet.prototype.getContract = function (id) { + for (var i = 0; i < this.contracts.length; i++) { + if (this.contracts[i].contract_id === id) { + return this.contracts[i]; + } + } + return null; + }; + return Wallet; +}()); + + + +/***/ }), + +/***/ "./src/app/_helpers/pipes/contract-status-messages.pipe.ts": +/*!*****************************************************************!*\ + !*** ./src/app/_helpers/pipes/contract-status-messages.pipe.ts ***! + \*****************************************************************/ +/*! exports provided: ContractStatusMessagesPipe */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ContractStatusMessagesPipe", function() { return ContractStatusMessagesPipe; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; + +var ContractStatusMessagesPipe = /** @class */ (function () { + function ContractStatusMessagesPipe() { + } + ContractStatusMessagesPipe.prototype.getStateSeller = function (stateNum) { + var state = { part1: '', part2: '' }; + switch (stateNum) { + case 1: + state.part1 = 'New contract proposal'; + break; + case 110: + state.part1 = 'You ignored the contract proposal'; + break; + case 201: + state.part1 = 'You have accepted the contract proposal'; + state.part2 = 'Please wait for the pledges to be made'; + break; + case 2: + state.part1 = 'The buyer is waiting for the item to be delivered'; + state.part2 = 'Pledges made'; + break; + case 3: + state.part1 = 'Contract completed successfully'; + state.part2 = 'Item received, payment transferred, pledges returned'; + break; + case 4: + state.part1 = 'Item not received'; + state.part2 = 'All pledges nullified'; + break; + case 5: + state.part1 = 'New proposal to cancel contract and return pledges'; + break; + case 601: + state.part1 = 'The contract is being cancelled. Please wait for the pledge to be returned'; + break; + case 6: + state.part1 = 'Contract canceled'; + state.part2 = 'Pledges returned'; + break; + case 130: + state.part1 = 'You ignored the proposal to cancel the contract'; + break; + case 140: + state.part1 = 'The contract proposal has expired'; + break; + } + return state.part1 + ' ' + state.part2; + }; + ContractStatusMessagesPipe.prototype.getStateCustomer = function (stateNum) { + var state = { part1: '', part2: '' }; + switch (stateNum) { + case 1: + state.part1 = 'Waiting for seller respond to contract proposal'; + state.part2 = 'Pledge amount reserved'; + break; + case 110: + state.part1 = 'The seller ignored your contract proposal'; + state.part2 = 'Pledge amount unblocked'; + break; + case 201: + state.part1 = 'The seller accepted your contract proposal'; + state.part2 = 'Please wait for the pledges to be made'; + break; + case 2: + state.part1 = 'The seller accepted your contract proposal'; + state.part2 = 'Pledges made'; + break; + case 120: + state.part1 = 'Waiting for seller to ship item'; + state.part2 = 'Pledges made'; + break; + case 3: + state.part1 = 'Contract completed successfully'; + state.part2 = 'Item received, payment transferred, pledges returned'; + break; + case 4: + state.part1 = 'Item not received'; + state.part2 = 'All pledges nullified'; + break; + case 5: + state.part1 = 'Waiting for seller to respond to proposal to cancel contract and return pledges'; + break; + case 601: + state.part1 = 'The contract is being cancelled. Please wait for the pledge to be returned'; + break; + case 6: + state.part1 = 'Contract canceled'; + state.part2 = 'Pledges returned'; + break; + case 130: + state.part1 = 'The seller ignored your proposal to cancel the contract'; + break; + case 140: + state.part1 = 'The contract proposal has expired'; + break; + } + return state.part1 + ' ' + state.part2; + }; + ContractStatusMessagesPipe.prototype.transform = function (item, args) { + if (item.is_a) { + return this.getStateCustomer(item.state); + } + else { + return this.getStateSeller(item.state); + } + }; + ContractStatusMessagesPipe = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Pipe"])({ + name: 'contractStatusMessages' + }) + ], ContractStatusMessagesPipe); + return ContractStatusMessagesPipe; +}()); + + + +/***/ }), + +/***/ "./src/app/_helpers/pipes/contract-time-left.pipe.ts": +/*!***********************************************************!*\ + !*** ./src/app/_helpers/pipes/contract-time-left.pipe.ts ***! + \***********************************************************/ +/*! exports provided: ContractTimeLeftPipe */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ContractTimeLeftPipe", function() { return ContractTimeLeftPipe; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var _services_variables_service__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../services/variables.service */ "./src/app/_helpers/services/variables.service.ts"); +/* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @ngx-translate/core */ "./node_modules/@ngx-translate/core/fesm5/ngx-translate-core.js"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + + + +var ContractTimeLeftPipe = /** @class */ (function () { + function ContractTimeLeftPipe(service, translate) { + this.service = service; + this.translate = translate; + } + ContractTimeLeftPipe.prototype.transform = function (value, arg) { + var time = parseInt(((parseInt(value, 10) - this.service.exp_med_ts) / 3600).toFixed(0), 10); + var type = arg || 0; + if (time === 0) { + return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_LESS_ONE'); + } + if (this.service.settings.language === 'en') { + if (type === 0) { + if (time === 1) { + return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_ONE', { time: time }); + } + else { + return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_MANY', { time: time }); + } + } + else if (type === 1) { + if (time === 1) { + return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_ONE_RESPONSE', { time: time }); + } + else { + return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_MANY_RESPONSE', { time: time }); + } + } + else if (type === 2) { + if (time === 1) { + return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_ONE_WAITING', { time: time }); + } + else { + return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_MANY_WAITING', { time: time }); + } + } + } + else { + var rest = time % 10; + if (type === 0) { + if (((time > 20) && (rest === 1)) || time === 1) { + return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_ONE', { time: time }); + } + else if ((time > 1) && (time < 5) || ((time > 20) && (rest === 2 || rest === 3 || rest === 4))) { + return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_MANY', { time: time }); + } + else { + return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_MANY_ALT', { time: time }); + } + } + else if (type === 1) { + if (((time > 20) && (rest === 1)) || time === 1) { + return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_ONE_RESPONSE', { time: time }); + } + else if ((time > 1) && (time < 5) || ((time > 20) && (rest === 2 || rest === 3 || rest === 4))) { + return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_MANY_RESPONSE', { time: time }); + } + else { + return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_MANY_ALT_RESPONSE', { time: time }); + } + } + else if (type === 2) { + if (((time > 20) && (rest === 1)) || time === 1) { + return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_ONE_WAITING', { time: time }); + } + else if ((time > 1) && (time < 5) || ((time > 20) && (rest === 2 || rest === 3 || rest === 4))) { + return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_MANY_WAITING', { time: time }); + } + else { + return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_MANY_ALT_WAITING', { time: time }); + } + } + } + return null; + }; + ContractTimeLeftPipe = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Pipe"])({ + name: 'contractTimeLeft' + }), + __metadata("design:paramtypes", [_services_variables_service__WEBPACK_IMPORTED_MODULE_1__["VariablesService"], _ngx_translate_core__WEBPACK_IMPORTED_MODULE_2__["TranslateService"]]) + ], ContractTimeLeftPipe); + return ContractTimeLeftPipe; +}()); + + + +/***/ }), + +/***/ "./src/app/_helpers/pipes/history-type-messages.pipe.ts": +/*!**************************************************************!*\ + !*** ./src/app/_helpers/pipes/history-type-messages.pipe.ts ***! + \**************************************************************/ +/*! exports provided: HistoryTypeMessagesPipe */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HistoryTypeMessagesPipe", function() { return HistoryTypeMessagesPipe; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; + +var HistoryTypeMessagesPipe = /** @class */ (function () { + function HistoryTypeMessagesPipe() { + } + HistoryTypeMessagesPipe.prototype.transform = function (item, args) { + if (item.tx_type === 0) { + if (item.remote_addresses && item.remote_addresses[0]) { + return item.remote_addresses[0]; + } + else { + if (item.is_income) { + return 'hidden'; + } + else { + return 'Undefined'; + } + } + } + else if (item.tx_type === 6 && item.height === 0) { + return 'unknown'; + } + else if (item.tx_type === 9) { + if (item.hasOwnProperty('contract') && item.contract[0].is_a) { + return 'Successfully complete contract, return remaining pledge'; + } + else { + return 'Successfully complete contract, receive payment on contract, and return pledge'; + } + } + else { + switch (item.tx_type) { + // case 0: + // return $filter('translate')('GUI_TX_TYPE_NORMAL'); + // break; + // case 1: + // return $filter('translate')('GUI_TX_TYPE_PUSH_OFFER'); + // case 2: + // return $filter('translate')('GUI_TX_TYPE_UPDATE_OFFER'); + // case 3: + // return $filter('translate')('GUI_TX_TYPE_CANCEL_OFFER'); + // case 4: + // return $filter('translate')('GUI_TX_TYPE_NEW_ALIAS'); + // case 5: + // return $filter('translate')('GUI_TX_TYPE_UPDATE_ALIAS'); + case 6: + return 'Mined funds'; + case 7: + return 'Send contract offer'; + case 8: + return 'Make pledge on offer'; + // case 9: + // return $filter('translate')('GUI_TX_TYPE_ESCROW_RELEASE_NORMAL'); + // break; + case 10: + return 'Nullify pledges for contract'; + case 11: + return 'Send proposal to cancel contract'; + case 12: + return 'Cancel contract, return pledges'; + } + } + return 'Undefined'; + }; + HistoryTypeMessagesPipe = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Pipe"])({ + name: 'historyTypeMessages' + }) + ], HistoryTypeMessagesPipe); + return HistoryTypeMessagesPipe; +}()); + + + +/***/ }), + +/***/ "./src/app/_helpers/pipes/int-to-money.pipe.ts": +/*!*****************************************************!*\ + !*** ./src/app/_helpers/pipes/int-to-money.pipe.ts ***! + \*****************************************************/ +/*! exports provided: IntToMoneyPipe */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "IntToMoneyPipe", function() { return IntToMoneyPipe; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; + +var IntToMoneyPipe = /** @class */ (function () { + function IntToMoneyPipe() { + } + IntToMoneyPipe.prototype.transform = function (value, args) { + if (value === 0 || value === undefined) { + return '0'; + } + var power = Math.pow(10, 8); + var str = (value / power).toFixed(8); + for (var i = str.length - 1; i >= 0; i--) { + if (str[i] !== '0') { + str = str.substr(0, i + 1); + break; + } + } + if (str[str.length - 1] === '.') { + str = str.substr(0, str.length - 1); + } + return str; + }; + IntToMoneyPipe = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Pipe"])({ + name: 'intToMoney' + }) + ], IntToMoneyPipe); + return IntToMoneyPipe; +}()); + + + +/***/ }), + +/***/ "./src/app/_helpers/pipes/money-to-int.pipe.ts": +/*!*****************************************************!*\ + !*** ./src/app/_helpers/pipes/money-to-int.pipe.ts ***! + \*****************************************************/ +/*! exports provided: MoneyToIntPipe */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MoneyToIntPipe", function() { return MoneyToIntPipe; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; + +var MoneyToIntPipe = /** @class */ (function () { + function MoneyToIntPipe() { + } + MoneyToIntPipe.prototype.transform = function (value, args) { + var CURRENCY_DISPLAY_DECIMAL_POINT = 8; + var result; + if (value) { + var am_str = value.toString().trim(); + var point_index = am_str.indexOf('.'); + var fraction_size = 0; + if (-1 !== point_index) { + fraction_size = am_str.length - point_index - 1; + while (CURRENCY_DISPLAY_DECIMAL_POINT < fraction_size && '0' === am_str[am_str.length - 1]) { + am_str = am_str.slice(0, am_str.length - 1); + --fraction_size; + } + if (CURRENCY_DISPLAY_DECIMAL_POINT < fraction_size) { + return undefined; + } + am_str = am_str.slice(0, point_index) + am_str.slice(point_index + 1, am_str.length); + } + else { + fraction_size = 0; + } + if (!am_str.length) { + return undefined; + } + if (fraction_size < CURRENCY_DISPLAY_DECIMAL_POINT) { + for (var i = 0; i !== CURRENCY_DISPLAY_DECIMAL_POINT - fraction_size; i++) { + am_str = am_str + '0'; + } + } + result = parseInt(am_str, 10); + } + return result; + }; + MoneyToIntPipe = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Pipe"])({ + name: 'moneyToInt' + }) + ], MoneyToIntPipe); + return MoneyToIntPipe; +}()); + + + +/***/ }), + +/***/ "./src/app/_helpers/services/backend.service.ts": +/*!******************************************************!*\ + !*** ./src/app/_helpers/services/backend.service.ts ***! + \******************************************************/ +/*! exports provided: BackendService */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BackendService", function() { return BackendService; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! rxjs */ "./node_modules/rxjs/_esm5/index.js"); +/* harmony import */ var _variables_service__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./variables.service */ "./src/app/_helpers/services/variables.service.ts"); +/* harmony import */ var _pipes_money_to_int_pipe__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../pipes/money-to-int.pipe */ "./src/app/_helpers/pipes/money-to-int.pipe.ts"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + + + + +var BackendService = /** @class */ (function () { + function BackendService(variablesService, moneyToIntPipe) { + this.variablesService = variablesService; + this.moneyToIntPipe = moneyToIntPipe; + this.backendLoaded = false; + } + BackendService.prototype.Debug = function (type, message) { + switch (type) { + case 0: + console.error(message); + break; + case 1: + console.warn(message); + break; + case 2: + console.log(message); + break; + default: + console.log(message); + break; + } + }; + BackendService.prototype.informerRun = function (error, params, command) { + var error_translate = ''; + switch (error) { + case 'NOT_ENOUGH_MONEY': + error_translate = 'ERROR.NOT_ENOUGH_MONEY'; + break; + case 'CORE_BUSY': + if (command !== 'get_all_aliases') { + error_translate = 'INFORMER.CORE_BUSY'; + } + break; + case 'OVERFLOW': + if (command !== 'get_all_aliases') { + error_translate = ''; + } + break; + case 'INTERNAL_ERROR:daemon is busy': + error_translate = 'INFORMER.DAEMON_BUSY'; + break; + case 'INTERNAL_ERROR:not enough money': + case 'INTERNAL_ERROR:NOT_ENOUGH_MONEY': + if (command === 'cancel_offer') { + // error_translate = $filter('translate')('INFORMER.NO_MONEY_REMOVE_OFFER', { + // 'fee': CONFIG.standart_fee, + // 'currency': CONFIG.currency_symbol + // }); + } + else { + error_translate = 'INFORMER.NO_MONEY'; + } + break; + case 'INTERNAL_ERROR:not enough outputs to mix': + error_translate = 'MESSAGE.NOT_ENOUGH_OUTPUTS_TO_MIX'; + break; + case 'INTERNAL_ERROR:transaction is too big': + error_translate = 'MESSAGE.TRANSACTION_IS_TO_BIG'; + break; + case 'INTERNAL_ERROR:Transfer attempt while daemon offline': + error_translate = 'MESSAGE.TRANSFER_ATTEMPT'; + break; + case 'ACCESS_DENIED': + error_translate = 'INFORMER.ACCESS_DENIED'; + break; + case 'INTERNAL_ERROR:transaction was rejected by daemon': + if (command === 'request_alias_registration') { + error_translate = 'INFORMER.ALIAS_IN_REGISTER'; + } + else { + error_translate = 'INFORMER.TRANSACTION_ERROR'; + } + break; + case 'INTERNAL_ERROR': + error_translate = 'INFORMER.TRANSACTION_ERROR'; + break; + case 'BAD_ARG': + error_translate = 'INFORMER.BAD_ARG'; + break; + case 'WALLET_WRONG_ID': + error_translate = 'INFORMER.WALLET_WRONG_ID'; + break; + case 'WRONG_PASSWORD': + case 'WRONG_PASSWORD:invalid password': + params = JSON.parse(params); + if (!params.testEmpty) { + error_translate = 'INFORMER.WRONG_PASSWORD'; + } + break; + case 'FILE_RESTORED': + if (command === 'open_wallet') { + // error_translate = $filter('translate')('INFORMER.FILE_RESTORED'); + } + break; + case 'FILE_NOT_FOUND': + if (command !== 'open_wallet' && command !== 'get_alias_info_by_name' && command !== 'get_alias_info_by_address') { + // error_translate = $filter('translate')('INFORMER.FILE_NOT_FOUND'); + params = JSON.parse(params); + if (params.path) { + error_translate += ': ' + params.path; + } + } + break; + case 'CANCELED': + case '': + break; + case 'FAIL': + if (command === 'create_proposal' || command === 'accept_proposal' || command === 'release_contract' || command === 'request_cancel_contract' || command === 'accept_cancel_contract') { + error_translate = ' '; + } + break; + case 'ALREADY_EXISTS': + error_translate = 'INFORMER.FILE_EXIST'; + break; + default: + error_translate = error; + } + if (error.indexOf('FAIL:failed to save file') > -1) { + error_translate = 'INFORMER.FILE_NOT_SAVED'; + } + if (error_translate !== '') { + alert(error_translate); + } + }; + BackendService.prototype.commandDebug = function (command, params, result) { + this.Debug(2, '----------------- ' + command + ' -----------------'); + var debug = { + _send_params: params, + _result: result + }; + this.Debug(2, debug); + try { + this.Debug(2, JSON.parse(result)); + } + catch (e) { + this.Debug(2, { response_data: result, error_code: 'OK' }); + } + }; + BackendService.prototype.asVal = function (data) { + return { v: data }; + }; + BackendService.prototype.backendCallback = function (resultStr, params, callback, command) { + var Result = resultStr; + if (command !== 'get_clipboard') { + if (!resultStr || resultStr === '') { + Result = {}; + } + else { + try { + Result = JSON.parse(resultStr); + } + catch (e) { + Result = { response_data: resultStr, error_code: 'OK' }; + } + } + } + else { + Result = { + error_code: 'OK', + response_data: Result + }; + } + var Status = (Result.error_code === 'OK' || Result.error_code === 'TRUE'); + if (!Status && Status !== undefined && Result.error_code !== undefined) { + this.Debug(1, 'API error for command: "' + command + '". Error code: ' + Result.error_code); + } + var data = ((typeof Result === 'object') && 'response_data' in Result) ? Result.response_data : Result; + var res_error_code = false; + if (typeof Result === 'object' && 'error_code' in Result && Result.error_code !== 'OK' && Result.error_code !== 'TRUE' && Result.error_code !== 'FALSE') { + this.informerRun(Result.error_code, params, command); + res_error_code = Result.error_code; + } + // if ( command === 'get_offers_ex' ){ + // Service.printLog( "get_offers_ex offers count "+((data.offers)?data.offers.length:0) ); + // } + if (typeof callback === 'function') { + callback(Status, data, res_error_code); + } + else { + return data; + } + }; + BackendService.prototype.runCommand = function (command, params, callback) { + if (this.backendObject) { + var Action = this.backendObject[command]; + if (!Action) { + this.Debug(0, 'Run Command Error! Command "' + command + '" don\'t found in backendObject'); + } + else { + var that_1 = this; + params = (typeof params === 'string') ? params : JSON.stringify(params); + if (params === undefined || params === '{}') { + Action(function (resultStr) { + that_1.commandDebug(command, params, resultStr); + return that_1.backendCallback(resultStr, params, callback, command); + }); + } + else { + Action(params, function (resultStr) { + that_1.commandDebug(command, params, resultStr); + return that_1.backendCallback(resultStr, params, callback, command); + }); + } + } + } + }; + BackendService.prototype.eventSubscribe = function (command, callback) { + if (command === 'on_core_event') { + this.backendObject[command].connect(callback); + } + else { + this.backendObject[command].connect(function (str) { + callback(JSON.parse(str)); + }); + } + }; + BackendService.prototype.initService = function () { + var _this = this; + return new rxjs__WEBPACK_IMPORTED_MODULE_1__["Observable"](function (observer) { + if (!_this.backendLoaded) { + _this.backendLoaded = true; + var that_2 = _this; + window.QWebChannel(window.qt.webChannelTransport, function (channel) { + that_2.backendObject = channel.objects.mediator_object; + observer.next('ok'); + }); + } + else { + if (!_this.backendObject) { + observer.error('error'); + observer.error('error'); + } + } + }); + }; + BackendService.prototype.webkitLaunchedScript = function () { + return this.runCommand('webkit_launched_script'); + }; + BackendService.prototype.quitRequest = function () { + return this.runCommand('on_request_quit'); + }; + BackendService.prototype.getAppData = function (callback) { + this.runCommand('get_app_data', {}, callback); + }; + BackendService.prototype.storeAppData = function (callback) { + this.runCommand('store_app_data', this.variablesService.settings, callback); + }; + BackendService.prototype.getSecureAppData = function (pass, callback) { + this.runCommand('get_secure_app_data', pass, callback); + }; + BackendService.prototype.storeSecureAppData = function (callback) { + var _this = this; + if (this.variablesService.appPass === '') { + return callback(false); + } + var wallets = []; + this.variablesService.wallets.forEach(function (wallet) { + wallets.push({ name: wallet.name, pass: wallet.pass, path: wallet.path }); + }); + this.backendObject['store_secure_app_data'](JSON.stringify(wallets), this.variablesService.appPass, function (dataStore) { + _this.backendCallback(dataStore, {}, callback, 'store_secure_app_data'); + }); + }; + BackendService.prototype.haveSecureAppData = function (callback) { + this.runCommand('have_secure_app_data', {}, callback); + }; + BackendService.prototype.saveFileDialog = function (caption, fileMask, default_path, callback) { + var dir = default_path ? default_path : '/'; + var params = { + caption: caption, + filemask: fileMask, + default_dir: dir + }; + this.runCommand('show_savefile_dialog', params, callback); + }; + BackendService.prototype.openFileDialog = function (caption, fileMask, default_path, callback) { + var dir = default_path ? default_path : '/'; + var params = { + caption: caption, + filemask: fileMask, + default_dir: dir + }; + this.runCommand('show_openfile_dialog', params, callback); + }; + BackendService.prototype.generateWallet = function (path, pass, callback) { + var params = { + path: path, + pass: pass + }; + this.runCommand('generate_wallet', params, callback); + }; + BackendService.prototype.openWallet = function (path, pass, testEmpty, callback) { + var params = { + path: path, + pass: pass + }; + params['testEmpty'] = !!(testEmpty); + this.runCommand('open_wallet', params, callback); + }; + BackendService.prototype.closeWallet = function (wallet_id, callback) { + this.runCommand('close_wallet', { wallet_id: wallet_id }, callback); + }; + BackendService.prototype.getSmartSafeInfo = function (wallet_id, callback) { + this.runCommand('get_smart_safe_info', { wallet_id: +wallet_id }, callback); + }; + BackendService.prototype.runWallet = function (wallet_id, callback) { + this.runCommand('run_wallet', { wallet_id: +wallet_id }, callback); + }; + BackendService.prototype.isValidRestoreWalletText = function (text, callback) { + this.runCommand('is_valid_restore_wallet_text', text, callback); + }; + BackendService.prototype.restoreWallet = function (path, pass, restore_key, callback) { + var params = { + restore_key: restore_key, + path: path, + pass: pass + }; + this.runCommand('restore_wallet', params, callback); + }; + BackendService.prototype.sendMoney = function (from_wallet_id, to_address, amount, fee, mixin, comment, callback) { + var params = { + wallet_id: parseInt(from_wallet_id, 10), + destinations: [ + { + address: to_address, + amount: amount + } + ], + mixin_count: (mixin) ? parseInt(mixin, 10) : 0, + lock_time: 0, + fee: this.moneyToIntPipe.transform(fee), + comment: comment, + push_payer: true + }; + this.runCommand('transfer', params, callback); + }; + BackendService.prototype.validateAddress = function (address, callback) { + this.runCommand('validate_address', address, callback); + }; + BackendService.prototype.setClipboard = function (str, callback) { + return this.runCommand('set_clipboard', str, callback); + }; + BackendService.prototype.getClipboard = function (callback) { + return this.runCommand('get_clipboard', {}, callback); + }; + BackendService.prototype.createProposal = function (wallet_id, title, comment, a_addr, b_addr, to_pay, a_pledge, b_pledge, time, payment_id, callback) { + var params = { + wallet_id: parseInt(wallet_id, 10), + details: { + t: title, + c: comment, + a_addr: a_addr, + b_addr: b_addr, + to_pay: this.moneyToIntPipe.transform(to_pay), + a_pledge: this.moneyToIntPipe.transform(a_pledge) - this.moneyToIntPipe.transform(to_pay), + b_pledge: this.moneyToIntPipe.transform(b_pledge) + }, + payment_id: payment_id, + expiration_period: parseInt(time, 10) * 60 * 60, + fee: this.moneyToIntPipe.transform('0.01'), + b_fee: this.moneyToIntPipe.transform('0.01') + }; + this.Debug(1, params); + this.runCommand('create_proposal', params, callback); + }; + BackendService.prototype.getContracts = function (wallet_id, callback) { + var params = { + wallet_id: parseInt(wallet_id, 10) + }; + this.Debug(1, params); + this.runCommand('get_contracts', params, callback); + }; + BackendService.prototype.acceptProposal = function (wallet_id, contract_id, callback) { + var params = { + wallet_id: parseInt(wallet_id, 10), + contract_id: contract_id + }; + this.Debug(1, params); + this.runCommand('accept_proposal', params, callback); + }; + BackendService.prototype.releaseProposal = function (wallet_id, contract_id, release_type, callback) { + var params = { + wallet_id: parseInt(wallet_id, 10), + contract_id: contract_id, + release_type: release_type // "normal" or "burn" + }; + this.Debug(1, params); + this.runCommand('release_contract', params, callback); + }; + BackendService.prototype.requestCancelContract = function (wallet_id, contract_id, time, callback) { + var params = { + wallet_id: parseInt(wallet_id, 10), + contract_id: contract_id, + fee: this.moneyToIntPipe.transform('0.01'), + expiration_period: parseInt(time, 10) * 60 * 60 + }; + this.Debug(1, params); + this.runCommand('request_cancel_contract', params, callback); + }; + BackendService.prototype.acceptCancelContract = function (wallet_id, contract_id, callback) { + var params = { + wallet_id: parseInt(wallet_id, 10), + contract_id: contract_id + }; + this.Debug(1, params); + this.runCommand('accept_cancel_contract', params, callback); + }; + BackendService.prototype.getMiningHistory = function (wallet_id, callback) { + this.runCommand('get_mining_history', { wallet_id: parseInt(wallet_id, 10) }, callback); + }; + BackendService.prototype.startPosMining = function (wallet_id, callback) { + this.runCommand('start_pos_mining', { wallet_id: parseInt(wallet_id, 10) }, callback); + }; + BackendService.prototype.stopPosMining = function (wallet_id, callback) { + this.runCommand('stop_pos_mining', { wallet_id: parseInt(wallet_id, 10) }, callback); + }; + BackendService = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Injectable"])(), + __metadata("design:paramtypes", [_variables_service__WEBPACK_IMPORTED_MODULE_2__["VariablesService"], _pipes_money_to_int_pipe__WEBPACK_IMPORTED_MODULE_3__["MoneyToIntPipe"]]) + ], BackendService); + return BackendService; +}()); + +/* + + var deferred = null; + + var Service = { + + + + + + + + /!* API *!/ + + toggleAutoStart: function (value) { + return this.runCommand('toggle_autostart', asVal(value)); + }, + + + + getDefaultFee: function (callback) { + return this.runCommand('get_default_fee', {}, callback); + }, + + getOptions: function (callback) { + return this.runCommand('get_options', {}, callback); + }, + + isFileExist: function (path, callback) { + return this.runCommand('is_file_exist', path, callback); + }, + + + + isAutoStartEnabled: function (callback) { + this.runCommand('is_autostart_enabled', {}, function (status, data) { + if (angular.isFunction(callback)) { + callback('error_code' in data && data.error_code !== 'FALSE') + } + }); + }, + + + + setLogLevel: function (level) { + return this.runCommand('set_log_level', asVal(level)) + }, + + resetWalletPass: function (wallet_id, pass, callback) { + this.runCommand('reset_wallet_password', {wallet_id: wallet_id, pass: pass}, callback); + }, + + getVersion: function (callback) { + this.runCommand('get_version', {}, function (status, version) { + callback(version) + }) + }, + + getOsVersion: function (callback) { + this.runCommand('get_os_version', {}, function (status, version) { + callback(version) + }) + }, + + getLogFile: function (callback) { + this.runCommand('get_log_file', {}, function (status, version) { + callback(version) + }) + }, + + + resync_wallet: function (wallet_id, callback) { + this.runCommand('resync_wallet', {wallet_id: wallet_id}, callback); + }, + + + + + + registerAlias: function (wallet_id, alias, address, fee, comment, reward, callback) { + var params = { + "wallet_id": wallet_id, + "alias": { + "alias": alias, + "address": address, + "tracking_key": "", + "comment": comment + }, + "fee": $filter('money_to_int')(fee), + "reward": $filter('money_to_int')(reward) + }; + this.runCommand('request_alias_registration', params, callback); + }, + + updateAlias: function (wallet_id, alias, fee, callback) { + var params = { + wallet_id: wallet_id, + alias: { + "alias": alias.name.replace("@", ""), + "address": alias.address, + "tracking_key": "", + "comment": alias.comment + }, + fee: $filter('money_to_int')(fee) + }; + this.runCommand('request_alias_update', params, callback); + }, + + getAllAliases: function (callback) { + this.runCommand('get_all_aliases', {}, callback); + }, + + getAliasByName: function (value, callback) { + return this.runCommand('get_alias_info_by_name', value, callback); + }, + + getAliasByAddress: function (value, callback) { + return this.runCommand('get_alias_info_by_address', value, callback); + }, + + getPoolInfo: function (callback) { + this.runCommand('get_tx_pool_info', {}, callback); + }, + + localization: function (stringsArray, title, callback) { + var data = { + strings: stringsArray, + language_title: title + }; + this.runCommand('set_localization_strings', data, callback); + }, + + storeFile: function (path, buff, callback) { + this.backendObject['store_to_file'](path, (typeof buff === 'string' ? buff : JSON.stringify(buff)), function (data) { + backendCallback(data, {}, callback, 'store_to_file'); + }); + }, + + + + + + getMiningEstimate: function (amount_coins, time, callback) { + var params = { + "amount_coins": $filter('money_to_int')(amount_coins), + "time": parseInt(time) + }; + this.runCommand('get_mining_estimate', params, callback); + }, + + backupWalletKeys: function (wallet_id, path, callback) { + var params = { + "wallet_id": wallet_id, + "path": path + }; + this.runCommand('backup_wallet_keys', params, callback); + }, + + + getAliasCoast: function (alias, callback) { + this.runCommand('get_alias_coast', asVal(alias), callback); + }, + + + + + setBlockedIcon: function (enabled, callback) { + var mode = (enabled) ? "blocked" : "normal"; + Service.runCommand('bool_toggle_icon', mode, callback); + }, + + + + + + getWalletInfo: function (wallet_id, callback) { + this.runCommand('get_wallet_info', {wallet_id: wallet_id}, callback); + }, + + + + printText: function (content) { + return this.runCommand('print_text', {html_text: content}); + }, + + printLog: function (msg, log_level) { + return this.runCommand('print_log', {msg: msg, log_level: log_level}); + }, + + openUrlInBrowser: function (url, callback) { + return this.runCommand('open_url_in_browser', url, callback); + }, + + + + /!* API END *!/ + + }; + return Service; + }]); + +})(); + +*/ + + +/***/ }), + +/***/ "./src/app/_helpers/services/variables.service.ts": +/*!********************************************************!*\ + !*** ./src/app/_helpers/services/variables.service.ts ***! + \********************************************************/ +/*! exports provided: VariablesService */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VariablesService", function() { return VariablesService; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! rxjs */ "./node_modules/rxjs/_esm5/index.js"); +/* harmony import */ var idlejs_dist__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! idlejs/dist */ "./node_modules/idlejs/dist/index.js"); +/* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/router */ "./node_modules/@angular/router/fesm5/router.js"); +/* harmony import */ var ngx_contextmenu__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ngx-contextmenu */ "./node_modules/ngx-contextmenu/fesm5/ngx-contextmenu.js"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + + + + + +var VariablesService = /** @class */ (function () { + function VariablesService(router, ngZone, contextMenuService) { + var _this = this; + this.router = router; + this.ngZone = ngZone; + this.contextMenuService = contextMenuService; + this.appPass = ''; + this.moneyEquivalent = 0; + this.defaultTheme = 'dark'; + this.defaultCurrency = 'ZAN'; + this.exp_med_ts = 0; + this.height_app = 0; + this.daemon_state = 0; + this.sync = { + progress_value: 0, + progress_value_text: '0' + }; + this.settings = { + theme: '', + language: 'en', + default_path: '/', + viewedContracts: [], + notViewedContracts: [] + }; + this.wallets = []; + this.getHeightAppEvent = new rxjs__WEBPACK_IMPORTED_MODULE_1__["BehaviorSubject"](null); + this.getRefreshStackingEvent = new rxjs__WEBPACK_IMPORTED_MODULE_1__["BehaviorSubject"](null); + this.idle = new idlejs_dist__WEBPACK_IMPORTED_MODULE_2__["Idle"]() + .whenNotInteractive() + .within(15) + .do(function () { + _this.ngZone.run(function () { + _this.idle.stop(); + _this.appPass = ''; + _this.router.navigate(['/login'], { queryParams: { type: 'auth' } }); + }); + }); + } + VariablesService.prototype.setHeightApp = function (height) { + if (height !== this.height_app) { + this.height_app = height; + this.getHeightAppEvent.next(height); + } + }; + VariablesService.prototype.setRefreshStacking = function (wallet_id) { + this.getHeightAppEvent.next(wallet_id); + }; + VariablesService.prototype.setCurrentWallet = function (id) { + var _this = this; + this.wallets.forEach(function (wallet) { + if (wallet.wallet_id === id) { + _this.currentWallet = wallet; + } + }); + }; + VariablesService.prototype.getWallet = function (id) { + for (var i = 0; i < this.wallets.length; i++) { + if (this.wallets[i].wallet_id === id) { + return this.wallets[i]; + } + } + return null; + }; + VariablesService.prototype.startCountdown = function () { + this.idle.restart(); + }; + VariablesService.prototype.stopCountdown = function () { + this.idle.stop(); + }; + VariablesService.prototype.onContextMenu = function ($event) { + $event.target['contextSelectionStart'] = $event.target['selectionStart']; + $event.target['contextSelectionEnd'] = $event.target['selectionEnd']; + if ($event.target && ($event.target['nodeName'].toUpperCase() === 'TEXTAREA' || $event.target['nodeName'].toUpperCase() === 'INPUT') && !$event.target['readOnly']) { + this.contextMenuService.show.next({ + contextMenu: this.contextMenu, + event: $event, + item: $event.target, + }); + $event.preventDefault(); + $event.stopPropagation(); + } + }; + __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Input"])(), + __metadata("design:type", ngx_contextmenu__WEBPACK_IMPORTED_MODULE_4__["ContextMenuComponent"]) + ], VariablesService.prototype, "contextMenu", void 0); + VariablesService = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Injectable"])({ + providedIn: 'root' + }), + __metadata("design:paramtypes", [_angular_router__WEBPACK_IMPORTED_MODULE_3__["Router"], _angular_core__WEBPACK_IMPORTED_MODULE_0__["NgZone"], ngx_contextmenu__WEBPACK_IMPORTED_MODULE_4__["ContextMenuService"]]) + ], VariablesService); + return VariablesService; +}()); + + + +/***/ }), + +/***/ "./src/app/app-routing.module.ts": +/*!***************************************!*\ + !*** ./src/app/app-routing.module.ts ***! + \***************************************/ +/*! exports provided: AppRoutingModule */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AppRoutingModule", function() { return AppRoutingModule; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/router */ "./node_modules/@angular/router/fesm5/router.js"); +/* harmony import */ var _main_main_component__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./main/main.component */ "./src/app/main/main.component.ts"); +/* harmony import */ var _login_login_component__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./login/login.component */ "./src/app/login/login.component.ts"); +/* harmony import */ var _wallet_wallet_component__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./wallet/wallet.component */ "./src/app/wallet/wallet.component.ts"); +/* harmony import */ var _send_send_component__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./send/send.component */ "./src/app/send/send.component.ts"); +/* harmony import */ var _receive_receive_component__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./receive/receive.component */ "./src/app/receive/receive.component.ts"); +/* harmony import */ var _history_history_component__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./history/history.component */ "./src/app/history/history.component.ts"); +/* harmony import */ var _contracts_contracts_component__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./contracts/contracts.component */ "./src/app/contracts/contracts.component.ts"); +/* harmony import */ var _purchase_purchase_component__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./purchase/purchase.component */ "./src/app/purchase/purchase.component.ts"); +/* harmony import */ var _messages_messages_component__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./messages/messages.component */ "./src/app/messages/messages.component.ts"); +/* harmony import */ var _typing_message_typing_message_component__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./typing-message/typing-message.component */ "./src/app/typing-message/typing-message.component.ts"); +/* harmony import */ var _staking_staking_component__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./staking/staking.component */ "./src/app/staking/staking.component.ts"); +/* harmony import */ var _settings_settings_component__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./settings/settings.component */ "./src/app/settings/settings.component.ts"); +/* harmony import */ var _create_wallet_create_wallet_component__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./create-wallet/create-wallet.component */ "./src/app/create-wallet/create-wallet.component.ts"); +/* harmony import */ var _open_wallet_open_wallet_component__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./open-wallet/open-wallet.component */ "./src/app/open-wallet/open-wallet.component.ts"); +/* harmony import */ var _restore_wallet_restore_wallet_component__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./restore-wallet/restore-wallet.component */ "./src/app/restore-wallet/restore-wallet.component.ts"); +/* harmony import */ var _seed_phrase_seed_phrase_component__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./seed-phrase/seed-phrase.component */ "./src/app/seed-phrase/seed-phrase.component.ts"); +/* harmony import */ var _wallet_details_wallet_details_component__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./wallet-details/wallet-details.component */ "./src/app/wallet-details/wallet-details.component.ts"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; + + +// Components + + + + + + + + + + + + + + + + + +var routes = [ + { + path: '', + component: _main_main_component__WEBPACK_IMPORTED_MODULE_2__["MainComponent"] + }, + { + path: 'main', + component: _main_main_component__WEBPACK_IMPORTED_MODULE_2__["MainComponent"] + }, + { + path: 'login', + component: _login_login_component__WEBPACK_IMPORTED_MODULE_3__["LoginComponent"] + }, + { + path: 'wallet/:id', + component: _wallet_wallet_component__WEBPACK_IMPORTED_MODULE_4__["WalletComponent"], + children: [ + { + path: 'send', + component: _send_send_component__WEBPACK_IMPORTED_MODULE_5__["SendComponent"] + }, + { + path: 'receive', + component: _receive_receive_component__WEBPACK_IMPORTED_MODULE_6__["ReceiveComponent"] + }, + { + path: 'history', + component: _history_history_component__WEBPACK_IMPORTED_MODULE_7__["HistoryComponent"] + }, + { + path: 'contracts', + component: _contracts_contracts_component__WEBPACK_IMPORTED_MODULE_8__["ContractsComponent"], + }, + { + path: 'purchase', + component: _purchase_purchase_component__WEBPACK_IMPORTED_MODULE_9__["PurchaseComponent"] + }, + { + path: 'purchase/:id', + component: _purchase_purchase_component__WEBPACK_IMPORTED_MODULE_9__["PurchaseComponent"] + }, + { + path: 'messages', + component: _messages_messages_component__WEBPACK_IMPORTED_MODULE_10__["MessagesComponent"], + }, + { + path: 'messages/:id', + component: _typing_message_typing_message_component__WEBPACK_IMPORTED_MODULE_11__["TypingMessageComponent"], + }, + { + path: 'staking', + component: _staking_staking_component__WEBPACK_IMPORTED_MODULE_12__["StakingComponent"] + }, + { + path: '', + redirectTo: 'send', + pathMatch: 'full' + } + ] + }, + { + path: 'create', + component: _create_wallet_create_wallet_component__WEBPACK_IMPORTED_MODULE_14__["CreateWalletComponent"] + }, + { + path: 'open', + component: _open_wallet_open_wallet_component__WEBPACK_IMPORTED_MODULE_15__["OpenWalletComponent"] + }, + { + path: 'restore', + component: _restore_wallet_restore_wallet_component__WEBPACK_IMPORTED_MODULE_16__["RestoreWalletComponent"] + }, + { + path: 'seed-phrase', + component: _seed_phrase_seed_phrase_component__WEBPACK_IMPORTED_MODULE_17__["SeedPhraseComponent"] + }, + { + path: 'details', + component: _wallet_details_wallet_details_component__WEBPACK_IMPORTED_MODULE_18__["WalletDetailsComponent"] + }, + { + path: 'settings', + component: _settings_settings_component__WEBPACK_IMPORTED_MODULE_13__["SettingsComponent"] + }, + { + path: '', + redirectTo: '/', + pathMatch: 'full' + } +]; +var AppRoutingModule = /** @class */ (function () { + function AppRoutingModule() { + } + AppRoutingModule = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["NgModule"])({ + imports: [_angular_router__WEBPACK_IMPORTED_MODULE_1__["RouterModule"].forRoot(routes)], + exports: [_angular_router__WEBPACK_IMPORTED_MODULE_1__["RouterModule"]] + }) + ], AppRoutingModule); + return AppRoutingModule; +}()); + + + +/***/ }), + +/***/ "./src/app/app.component.html": +/*!************************************!*\ + !*** ./src/app/app.component.html ***! + \************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = "\r\n\r\n
\r\n \r\n
\r\n\r\n\r\n copy\r\n paste\r\n select all\r\n\r\n" + +/***/ }), + +/***/ "./src/app/app.component.scss": +/*!************************************!*\ + !*** ./src/app/app.component.scss ***! + \************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = "/*\r\n* Implementation of themes\r\n*/\n.app-content {\n display: flex;\n overflow-x: overlay;\n overflow-y: hidden;\n width: 100%; }\n\r\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvRDpcXHphbm8vc3JjXFxhc3NldHNcXHNjc3NcXGJhc2VcXF9taXhpbnMuc2NzcyIsInNyYy9hcHAvRDpcXHphbm8vc3JjXFxhcHBcXGFwcC5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUE4RUE7O0VBRUU7QUM5RUY7RUFDRSxjQUFhO0VBQ2Isb0JBQW1CO0VBQ25CLG1CQUFrQjtFQUNsQixZQUFXLEVBQ1oiLCJmaWxlIjoic3JjL2FwcC9hcHAuY29tcG9uZW50LnNjc3MiLCJzb3VyY2VzQ29udGVudCI6WyJAbWl4aW4gdGV4dC10cnVuY2F0ZSB7XHJcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcclxuICB0ZXh0LW92ZXJmbG93OiBlbGxpcHNpcztcclxuICB3aGl0ZS1zcGFjZTogbm93cmFwO1xyXG59XHJcbkBtaXhpbiB0ZXh0V3JhcCB7XHJcbiAgd2hpdGUtc3BhY2U6IG5vcm1hbDtcclxuICBvdmVyZmxvdy13cmFwOiBicmVhay13b3JkO1xyXG4gIHdvcmQtd3JhcDogYnJlYWstd29yZDtcclxuICB3b3JkLWJyZWFrOiBicmVhay1hbGw7XHJcbiAgbGluZS1icmVhazogc3RyaWN0O1xyXG4gIC13ZWJraXQtaHlwaGVuczogYXV0bztcclxuICAtbXMtaHlwaGVuczogYXV0bztcclxuICBoeXBoZW5zOiBhdXRvO1xyXG59XHJcbkBtaXhpbiBjb3ZlckJveCB7XHJcblx0cG9zaXRpb246IGFic29sdXRlO1xyXG5cdHRvcDogMDtcclxuXHRsZWZ0OiAwO1xyXG5cdHdpZHRoOiAxMDAlO1xyXG5cdGhlaWdodDogMTAwJTtcclxufVxyXG5AbWl4aW4gYWJzICgkdG9wOiBhdXRvLCAkcmlnaHQ6IGF1dG8sICRib3R0b206IGF1dG8sICRsZWZ0OiBhdXRvKSB7XHJcbiAgdG9wOiAkdG9wO1xyXG4gIHJpZ2h0OiAkcmlnaHQ7XHJcbiAgYm90dG9tOiAkYm90dG9tO1xyXG4gIGxlZnQ6ICRsZWZ0O1xyXG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcclxufVxyXG5AbWl4aW4gY292ZXJJbWcge1xyXG5cdGJhY2tncm91bmQtcmVwZWF0OiBuby1yZXBlYXQ7XHJcblx0LXdlYmtpdC1iYWNrZ3JvdW5kLXNpemU6IGNvdmVyO1xyXG5cdC1vLWJhY2tncm91bmQtc2l6ZTogY292ZXI7XHJcblx0YmFja2dyb3VuZC1zaXplOiBjb3ZlcjtcclxuXHRiYWNrZ3JvdW5kLXBvc2l0aW9uOiA1MCUgNTAlO1xyXG59XHJcbkBtaXhpbiB2YWxpbmdCb3gge1xyXG5cdHBvc2l0aW9uOiBhYnNvbHV0ZTtcclxuXHR0b3A6ICA1MCU7XHJcblx0bGVmdDogNTAlO1xyXG5cdHRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUsIC01MCUpO1xyXG59XHJcbkBtaXhpbiB1blNlbGVjdCB7XHJcblx0LXdlYmtpdC10b3VjaC1jb2xsb3V0OiBub25lO1xyXG4gIC13ZWJraXQtdXNlci1zZWxlY3Q6IG5vbmU7XHJcbiAgLWtodG1sLXVzZXItc2VsZWN0OiBub25lO1xyXG4gIC1tb3otdXNlci1zZWxlY3Q6IG5vbmU7XHJcbiAgLW1zLXVzZXItc2VsZWN0OiBub25lO1xyXG4gIHVzZXItc2VsZWN0OiBub25lO1xyXG59XHJcbkBtaXhpbiBtYXgxMTk5IHsgLy8gbWFrZXQgMTE3MVxyXG4gIEBtZWRpYSAobWF4LXdpZHRoOiAxMTk5cHgpIHsgQGNvbnRlbnQ7IH1cclxufVxyXG5AbWl4aW4gbWF4MTE3MCB7IC8vIG1ha2V0cyA5OTJcclxuICBAbWVkaWEgKG1heC13aWR0aDogMTE3MHB4KSB7IEBjb250ZW50OyB9XHJcbn1cclxuQG1peGluIG1heDk5MSB7IC8vIG1ha2V0cyA3NjJcclxuICBAbWVkaWEgKG1heC13aWR0aDogOTkxcHgpIHsgQGNvbnRlbnQ7IH1cclxufVxyXG5AbWl4aW4gbWF4NzYxIHsgLy8gbWFrZXRzIDU3NlxyXG4gIEBtZWRpYSAobWF4LXdpZHRoOiA3NjFweCkgeyBAY29udGVudDsgfVxyXG59XHJcbkBtaXhpbiBtYXg1NzUgeyAvLyBtYWtldHMgNDAwXHJcbiAgQG1lZGlhIChtYXgtd2lkdGg6IDU3NXB4KSB7IEBjb250ZW50OyB9XHJcbn1cclxuQG1peGluIG1vYmlsZSB7XHJcbiAgQG1lZGlhIChtYXgtd2lkdGg6IDM5OXB4KSB7IEBjb250ZW50OyB9XHJcbn1cclxuQG1peGluIGljb0NlbnRlciB7XHJcbiAgICBiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0O1xyXG4gICAgYmFja2dyb3VuZC1wb3NpdGlvbjogY2VudGVyIGNlbnRlcjtcclxufVxyXG5AbWl4aW4gcHNldWRvICgkZGlzcGxheTogYmxvY2ssICRwb3M6IGFic29sdXRlLCAkY29udGVudDogJycpe1xyXG4gIGNvbnRlbnQ6ICRjb250ZW50O1xyXG4gIGRpc3BsYXk6ICRkaXNwbGF5O1xyXG4gIHBvc2l0aW9uOiAkcG9zO1xyXG59XHJcblxyXG4vKlxyXG4qIEltcGxlbWVudGF0aW9uIG9mIHRoZW1lc1xyXG4qL1xyXG5AbWl4aW4gdGhlbWlmeSgkdGhlbWVzOiAkdGhlbWVzKSB7XHJcbiAgQGVhY2ggJHRoZW1lLCAkbWFwIGluICR0aGVtZXMge1xyXG4gICAgLnRoZW1lLSN7JHRoZW1lfSAmIHtcclxuICAgICAgJHRoZW1lLW1hcDogKCkgIWdsb2JhbDtcclxuICAgICAgQGVhY2ggJGtleSwgJHN1Ym1hcCBpbiAkbWFwIHtcclxuICAgICAgICAkdmFsdWU6IG1hcC1nZXQobWFwLWdldCgkdGhlbWVzLCAkdGhlbWUpLCAnI3ska2V5fScpO1xyXG4gICAgICAgICR0aGVtZS1tYXA6IG1hcC1tZXJnZSgkdGhlbWUtbWFwLCAoJGtleTogJHZhbHVlKSkgIWdsb2JhbDtcclxuICAgICAgfVxyXG4gICAgICBAY29udGVudDtcclxuICAgICAgJHRoZW1lLW1hcDogbnVsbCAhZ2xvYmFsO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuQGZ1bmN0aW9uIHRoZW1lZCgka2V5KSB7XHJcbiAgQHJldHVybiBtYXAtZ2V0KCR0aGVtZS1tYXAsICRrZXkpO1xyXG59XHJcbiIsIkBpbXBvcnQgJ35zcmMvYXNzZXRzL3Njc3MvYmFzZS9taXhpbnMnO1xyXG5cclxuLmFwcC1jb250ZW50IHtcclxuICBkaXNwbGF5OiBmbGV4O1xyXG4gIG92ZXJmbG93LXg6IG92ZXJsYXk7XHJcbiAgb3ZlcmZsb3cteTogaGlkZGVuO1xyXG4gIHdpZHRoOiAxMDAlO1xyXG59XHJcbiJdfQ== */" + +/***/ }), + +/***/ "./src/app/app.component.ts": +/*!**********************************!*\ + !*** ./src/app/app.component.ts ***! + \**********************************/ +/*! exports provided: AppComponent */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AppComponent", function() { return AppComponent; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var _angular_common_http__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/common/http */ "./node_modules/@angular/common/fesm5/http.js"); +/* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @ngx-translate/core */ "./node_modules/@ngx-translate/core/fesm5/ngx-translate-core.js"); +/* harmony import */ var _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./_helpers/services/backend.service */ "./src/app/_helpers/services/backend.service.ts"); +/* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/router */ "./node_modules/@angular/router/fesm5/router.js"); +/* harmony import */ var _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./_helpers/services/variables.service */ "./src/app/_helpers/services/variables.service.ts"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + + + + + + +var AppComponent = /** @class */ (function () { + function AppComponent(http, renderer, translate, backend, router, variablesService, ngZone) { + this.http = http; + this.renderer = renderer; + this.translate = translate; + this.backend = backend; + this.router = router; + this.variablesService = variablesService; + this.ngZone = ngZone; + this.onQuitRequest = false; + translate.addLangs(['en', 'fr']); + translate.setDefaultLang('en'); + // const browserLang = translate.getBrowserLang(); + // translate.use(browserLang.match(/en|fr/) ? browserLang : 'en'); + } + AppComponent.prototype.ngOnInit = function () { + var _this = this; + this.backend.initService().subscribe(function (initMessage) { + console.log('Init message: ', initMessage); + _this.backend.webkitLaunchedScript(); + _this.backend.eventSubscribe('quit_requested', function () { + if (!_this.onQuitRequest) { + _this.backend.storeSecureAppData(function () { + _this.backend.storeAppData(function () { + var recursionCloseWallets = function () { + if (_this.variablesService.wallets.length) { + var lastIndex_1 = _this.variablesService.wallets.length - 1; + _this.backend.closeWallet(_this.variablesService.wallets[lastIndex_1].wallet_id, function () { + _this.variablesService.wallets.splice(lastIndex_1, 1); + recursionCloseWallets(); + }); + } + else { + _this.backend.quitRequest(); + } + }; + recursionCloseWallets(); + }); + }); + } + _this.onQuitRequest = true; + }); + _this.backend.eventSubscribe('update_wallet_status', function (data) { + console.log('----------------- update_wallet_status -----------------'); + console.log(data); + var wallet_state = data.wallet_state; + var is_mining = data.is_mining; + var wallet = _this.variablesService.getWallet(data.wallet_id); + // 1-synch, 2-ready, 3 - error + if (wallet) { + _this.ngZone.run(function () { + wallet.loaded = false; + wallet.staking = is_mining; + if (wallet_state === 2) { // ready + wallet.loaded = true; + } + if (wallet_state === 3) { // error + // safe.error = true; + } + wallet.balance = data.balance; + wallet.unlocked_balance = data.unlocked_balance; + wallet.mined_total = data.minied_total; + }); + } + }); + _this.backend.eventSubscribe('wallet_sync_progress', function (data) { + console.log('----------------- wallet_sync_progress -----------------'); + console.log(data); + var wallet = _this.variablesService.getWallet(data.wallet_id); + if (wallet) { + _this.ngZone.run(function () { + wallet.progress = data.progress; + if (wallet.progress === 0) { + wallet.loaded = false; + } + else if (wallet.progress === 100) { + wallet.loaded = true; + } + }); + } + }); + _this.backend.eventSubscribe('update_daemon_state', function (data) { + console.log('----------------- update_daemon_state -----------------'); + console.log('DAEMON:' + data.daemon_network_state); + console.log(data); + _this.variablesService.exp_med_ts = data['expiration_median_timestamp'] + 600 + 1; + // this.variablesService.height_app = data.height; + _this.variablesService.setHeightApp(data.height); + _this.ngZone.run(function () { + _this.variablesService.daemon_state = data.daemon_network_state; + if (data.daemon_network_state === 1) { + var max = data.max_net_seen_height - data.synchronization_start_height; + var current = data.height - data.synchronization_start_height; + var return_val = Math.floor((current * 100 / max) * 100) / 100; + if (max === 0 || return_val < 0) { + _this.variablesService.sync.progress_value = 0; + _this.variablesService.sync.progress_value_text = '0.00'; + } + else if (return_val >= 100) { + _this.variablesService.sync.progress_value = 100; + _this.variablesService.sync.progress_value_text = '99.99'; + } + else { + _this.variablesService.sync.progress_value = return_val; + _this.variablesService.sync.progress_value_text = return_val.toFixed(2); + } + } + }); + }); + _this.backend.eventSubscribe('money_transfer', function (data) { + console.log('----------------- money_transfer -----------------'); + console.log(data); + if (!data.ti) { + return; + } + var wallet_id = data.wallet_id; + var tr_info = data.ti; + var safe = _this.variablesService.getWallet(wallet_id); + if (safe) { + _this.ngZone.run(function () { + if (!safe.loaded) { + safe.balance = data.balance; + safe.unlocked_balance = data.unlocked_balance; + } + else { + safe.balance = data.balance; + safe.unlocked_balance = data.unlocked_balance; + } + if (tr_info.tx_type === 6) { + _this.variablesService.setRefreshStacking(wallet_id); + } + var tr_exists = safe.excluded_history.some(function (elem) { return elem.tx_hash === tr_info.tx_hash; }); + tr_exists = (!tr_exists) ? safe.history.some(function (elem) { return elem.tx_hash === tr_info.tx_hash; }) : tr_exists; + safe.prepareHistory([tr_info]); + if (tr_info.hasOwnProperty('contract')) { + var exp_med_ts = _this.variablesService.exp_med_ts; + var height_app = _this.variablesService.height_app; + var contract_1 = tr_info.contract[0]; + if (tr_exists) { + for (var i = 0; i < safe.contracts.length; i++) { + if (safe.contracts[i].contract_id === contract_1.contract_id && safe.contracts[i].is_a === contract_1.is_a) { + safe.contracts[i].cancel_expiration_time = contract_1.cancel_expiration_time; + safe.contracts[i].expiration_time = contract_1.expiration_time; + safe.contracts[i].height = contract_1.height; + safe.contracts[i].timestamp = contract_1.timestamp; + break; + } + } + // $rootScope.getContractsRecount(); + return; + } + if (contract_1.state === 1 && contract_1.expiration_time < exp_med_ts) { + contract_1.state = 110; + } + else if (contract_1.state === 5 && contract_1.cancel_expiration_time < exp_med_ts) { + contract_1.state = 130; + } + else if (contract_1.state === 1) { + var searchResult2 = _this.variablesService.settings.notViewedContracts.find(function (elem) { return elem.state === 110 && elem.is_a === contract_1.is_a && elem.contract_id === contract_1.contract_id; }); + if (searchResult2) { + if (searchResult2.time === contract_1.expiration_time) { + contract_1.state = 110; + } + else { + for (var j = 0; j < _this.variablesService.settings.notViewedContracts.length; j++) { + if (_this.variablesService.settings.notViewedContracts[j].contract_id === contract_1.contract_id && _this.variablesService.settings.notViewedContracts[j].is_a === contract_1.is_a) { + _this.variablesService.settings.notViewedContracts.splice(j, 1); + break; + } + } + for (var j = 0; j < _this.variablesService.settings.viewedContracts.length; j++) { + if (_this.variablesService.settings.viewedContracts[j].contract_id === contract_1.contract_id && _this.variablesService.settings.viewedContracts[j].is_a === contract_1.is_a) { + _this.variablesService.settings.viewedContracts.splice(j, 1); + break; + } + } + } + } + } + else if (contract_1.state === 2 && (contract_1.height === 0 || (height_app - contract_1.height) < 10)) { + contract_1.state = 201; + } + else if (contract_1.state === 2) { + var searchResult3 = _this.variablesService.settings.viewedContracts.some(function (elem) { return elem.state === 120 && elem.is_a === contract_1.is_a && elem.contract_id === contract_1.contract_id; }); + if (searchResult3) { + contract_1.state = 120; + } + } + else if (contract_1.state === 5) { + var searchResult4 = _this.variablesService.settings.notViewedContracts.find(function (elem) { return elem.state === 130 && elem.is_a === contract_1.is_a && elem.contract_id === contract_1.contract_id; }); + if (searchResult4) { + if (searchResult4.time === contract_1.cancel_expiration_time) { + contract_1.state = 130; + } + else { + for (var j = 0; j < _this.variablesService.settings.notViewedContracts.length; j++) { + if (_this.variablesService.settings.notViewedContracts[j].contract_id === contract_1.contract_id && _this.variablesService.settings.notViewedContracts[j].is_a === contract_1.is_a) { + _this.variablesService.settings.notViewedContracts.splice(j, 1); + break; + } + } + for (var j = 0; j < _this.variablesService.settings.viewedContracts.length; j++) { + if (_this.variablesService.settings.viewedContracts[j].contract_id === contract_1.contract_id && _this.variablesService.settings.viewedContracts[j].is_a === contract_1.is_a) { + _this.variablesService.settings.viewedContracts.splice(j, 1); + break; + } + } + } + } + } + else if (contract_1.state === 6 && (contract_1.height === 0 || (height_app - contract_1.height) < 10)) { + contract_1.state = 601; + } + var searchResult = _this.variablesService.settings.viewedContracts.some(function (elem) { return elem.state === contract_1.state && elem.is_a === contract_1.is_a && elem.contract_id === contract_1.contract_id; }); + contract_1.is_new = !searchResult; + contract_1['private_detailes'].a_pledge += contract_1['private_detailes'].to_pay; + var findContract = false; + for (var i = 0; i < safe.contracts.length; i++) { + if (safe.contracts[i].contract_id === contract_1.contract_id && safe.contracts[i].is_a === contract_1.is_a) { + for (var prop in contract_1) { + if (contract_1.hasOwnProperty(prop)) { + safe.contracts[i][prop] = contract_1[prop]; + } + } + findContract = true; + break; + } + } + if (findContract === false) { + safe.contracts.push(contract_1); + } + safe.recountNewContracts(); + } + }); + } + }); + _this.backend.eventSubscribe('money_transfer_cancel', function (data) { + console.log('----------------- money_transfer_cancel -----------------'); + console.log(data); + // if (!data.ti) { + // return; + // } + // + // var wallet_id = data.wallet_id; + // var tr_info = data.ti; + // var safe = $rootScope.getSafeById(wallet_id); + // if (safe) { + // if ( tr_info.hasOwnProperty("contract") ){ + // for (var i = 0; i < $rootScope.contracts.length; i++) { + // if ($rootScope.contracts[i].contract_id === tr_info.contract[0].contract_id && $rootScope.contracts[i].is_a === tr_info.contract[0].is_a) { + // if ($rootScope.contracts[i].state === 1 || $rootScope.contracts[i].state === 110) { + // $rootScope.contracts[i].isNew = true; + // $rootScope.contracts[i].state = 140; + // $rootScope.getContractsRecount(); //escrow_code + // } + // break; + // } + // } + // } + // angular.forEach(safe.history, function (tr_item, key) { + // if (tr_item.tx_hash === tr_info.tx_hash) { + // safe.history.splice(key, 1); + // } + // }); + // + // var error_tr = ''; + // switch (tr_info.tx_type) { + // case 0: + // error_tr = $filter('translate')('ERROR_GUI_TX_TYPE_NORMAL') + '
' + + // tr_info.tx_hash + '
' + safe.name + '
' + safe.address + '
' + + // $filter('translate')('ERROR_GUI_TX_TYPE_NORMAL_TO') + ' ' + $rootScope.moneyParse(tr_info.amount) + ' ' + + // $filter('translate')('ERROR_GUI_TX_TYPE_NORMAL_END'); + // informer.error(error_tr); + // break; + // case 1: + // informer.error('ERROR_GUI_TX_TYPE_PUSH_OFFER'); + // break; + // case 2: + // informer.error('ERROR_GUI_TX_TYPE_UPDATE_OFFER'); + // break; + // case 3: + // informer.error('ERROR_GUI_TX_TYPE_CANCEL_OFFER'); + // break; + // case 4: + // error_tr = $filter('translate')('ERROR_GUI_TX_TYPE_NEW_ALIAS') + '
' + + // tr_info.tx_hash + '
' + safe.name + '
' + safe.address + '
' + + // $filter('translate')('ERROR_GUI_TX_TYPE_NEW_ALIAS_END'); + // informer.error(error_tr); + // break; + // case 5: + // error_tr = $filter('translate')('ERROR_GUI_TX_TYPE_UPDATE_ALIAS') + '
' + + // tr_info.tx_hash + '
' + safe.name + '
' + safe.address + '
' + + // $filter('translate')('ERROR_GUI_TX_TYPE_NEW_ALIAS_END'); + // informer.error(error_tr); + // break; + // case 6: + // informer.error('ERROR_GUI_TX_TYPE_COIN_BASE'); + // break; + // } + // } + }); + _this.intervalUpdateContractsState = setInterval(function () { + _this.variablesService.wallets.forEach(function (wallet) { + wallet.contracts.forEach(function (contract) { + if (contract.state === 201 && contract.height !== 0 && (_this.variablesService.height_app - contract.height) >= 10) { + contract.state = 2; + contract.is_new = true; + console.warn('need check state in contracts'); + } + else if (contract.state === 601 && contract.height !== 0 && (_this.variablesService.height_app - contract.height) >= 10) { + contract.state = 6; + contract.is_new = true; + } + }); + }); + }, 30000); + _this.backend.getAppData(function (status, data) { + if (data && Object.keys(data).length > 0) { + _this.variablesService.settings = data; + if (_this.variablesService.settings.hasOwnProperty('theme') && ['dark', 'white', 'gray'].indexOf(_this.variablesService.settings.theme) !== -1) { + _this.renderer.addClass(document.body, 'theme-' + _this.variablesService.settings.theme); + } + else { + _this.renderer.addClass(document.body, 'theme-' + _this.variablesService.defaultTheme); + } + } + else { + _this.variablesService.settings.theme = _this.variablesService.defaultTheme; + _this.renderer.addClass(document.body, 'theme-' + _this.variablesService.settings.theme); + } + if (_this.router.url !== '/login') { + _this.backend.haveSecureAppData(function (statusPass) { + if (statusPass) { + _this.ngZone.run(function () { + _this.router.navigate(['/login'], { queryParams: { type: 'auth' } }); + }); + } + else { + _this.ngZone.run(function () { + _this.router.navigate(['/login'], { queryParams: { type: 'reg' } }); + }); + } + }); + } + }); + }, function (error) { + console.log(error); + }); + this.getMoneyEquivalent(); + }; + AppComponent.prototype.getMoneyEquivalent = function () { + var _this = this; + // todo now start only once, need check daemon state and re-init + this.http.get('https://api.coinmarketcap.com/v2/ticker/2').subscribe(function (result) { + if (result.hasOwnProperty('data')) { + _this.variablesService.moneyEquivalent = result['data']['quotes']['USD']['price']; + } + }, function (error) { + console.warn('Error coinmarketcap', error); + }); + }; + AppComponent.prototype.contextMenuCopy = function (target) { + if (target && (target['nodeName'].toUpperCase() === 'TEXTAREA' || target['nodeName'].toUpperCase() === 'INPUT')) { + var start = (target['contextSelectionStart']) ? 'contextSelectionStart' : 'selectionStart'; + var end = (target['contextSelectionEnd']) ? 'contextSelectionEnd' : 'selectionEnd'; + var canUseSelection = ((target[start]) || (target[start] === '0')); + var SelectedText = (canUseSelection) ? target['value'].substring(target[start], target[end]) : target['value']; + this.backend.setClipboard(String(SelectedText)); + } + }; + AppComponent.prototype.contextMenuPaste = function (target) { + if (target && (target['nodeName'].toUpperCase() === 'TEXTAREA' || target['nodeName'].toUpperCase() === 'INPUT')) { + this.backend.getClipboard(function (status, clipboard) { + clipboard = String(clipboard); + if (typeof clipboard !== 'string' || clipboard.length) { + var start = (target['contextSelectionStart']) ? 'contextSelectionStart' : 'selectionStart'; + var end = (target['contextSelectionEnd']) ? 'contextSelectionEnd' : 'selectionEnd'; + var canUseSelection = ((target[start]) || (target[start] === '0')); + var _pre = ''; + var _aft = ''; + if (canUseSelection) { + _pre = target['value'].substring(0, target[start]); + _aft = target['value'].substring(target[end], target['value'].length); + } + var text = (!canUseSelection) ? clipboard : _pre + clipboard + _aft; + if (target['maxLength'] && parseInt(target['maxLength'], 10) > 0) { + text = text.substr(0, parseInt(target['maxLength'], 10)); + } + target['value'] = text; + target['focus'](); + } + }); + } + }; + AppComponent.prototype.contextMenuSelect = function (target) { + if (target && (target['nodeName'].toUpperCase() === 'TEXTAREA' || target['nodeName'].toUpperCase() === 'INPUT')) { + target['focus'](); + setTimeout(function () { + target['select'](); + }); + } + }; + AppComponent.prototype.ngOnDestroy = function () { + if (this.intervalUpdateContractsState) { + clearInterval(this.intervalUpdateContractsState); + } + }; + AppComponent = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Component"])({ + selector: 'app-root', + template: __webpack_require__(/*! ./app.component.html */ "./src/app/app.component.html"), + styles: [__webpack_require__(/*! ./app.component.scss */ "./src/app/app.component.scss")] + }), + __metadata("design:paramtypes", [_angular_common_http__WEBPACK_IMPORTED_MODULE_1__["HttpClient"], + _angular_core__WEBPACK_IMPORTED_MODULE_0__["Renderer2"], + _ngx_translate_core__WEBPACK_IMPORTED_MODULE_2__["TranslateService"], + _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_3__["BackendService"], + _angular_router__WEBPACK_IMPORTED_MODULE_4__["Router"], + _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_5__["VariablesService"], + _angular_core__WEBPACK_IMPORTED_MODULE_0__["NgZone"]]) + ], AppComponent); + return AppComponent; +}()); + + + +/***/ }), + +/***/ "./src/app/app.module.ts": +/*!*******************************!*\ + !*** ./src/app/app.module.ts ***! + \*******************************/ +/*! exports provided: HttpLoaderFactory, AppModule */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HttpLoaderFactory", function() { return HttpLoaderFactory; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AppModule", function() { return AppModule; }); +/* harmony import */ var _angular_platform_browser__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/platform-browser */ "./node_modules/@angular/platform-browser/fesm5/platform-browser.js"); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var _app_routing_module__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./app-routing.module */ "./src/app/app-routing.module.ts"); +/* harmony import */ var _app_component__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./app.component */ "./src/app/app.component.ts"); +/* harmony import */ var _login_login_component__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./login/login.component */ "./src/app/login/login.component.ts"); +/* harmony import */ var _settings_settings_component__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./settings/settings.component */ "./src/app/settings/settings.component.ts"); +/* harmony import */ var _sidebar_sidebar_component__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./sidebar/sidebar.component */ "./src/app/sidebar/sidebar.component.ts"); +/* harmony import */ var _main_main_component__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./main/main.component */ "./src/app/main/main.component.ts"); +/* harmony import */ var _create_wallet_create_wallet_component__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./create-wallet/create-wallet.component */ "./src/app/create-wallet/create-wallet.component.ts"); +/* harmony import */ var _open_wallet_open_wallet_component__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./open-wallet/open-wallet.component */ "./src/app/open-wallet/open-wallet.component.ts"); +/* harmony import */ var _restore_wallet_restore_wallet_component__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./restore-wallet/restore-wallet.component */ "./src/app/restore-wallet/restore-wallet.component.ts"); +/* harmony import */ var _seed_phrase_seed_phrase_component__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./seed-phrase/seed-phrase.component */ "./src/app/seed-phrase/seed-phrase.component.ts"); +/* harmony import */ var _wallet_details_wallet_details_component__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./wallet-details/wallet-details.component */ "./src/app/wallet-details/wallet-details.component.ts"); +/* harmony import */ var _wallet_wallet_component__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./wallet/wallet.component */ "./src/app/wallet/wallet.component.ts"); +/* harmony import */ var _send_send_component__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./send/send.component */ "./src/app/send/send.component.ts"); +/* harmony import */ var _receive_receive_component__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./receive/receive.component */ "./src/app/receive/receive.component.ts"); +/* harmony import */ var _history_history_component__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./history/history.component */ "./src/app/history/history.component.ts"); +/* harmony import */ var _contracts_contracts_component__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./contracts/contracts.component */ "./src/app/contracts/contracts.component.ts"); +/* harmony import */ var _purchase_purchase_component__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./purchase/purchase.component */ "./src/app/purchase/purchase.component.ts"); +/* harmony import */ var _messages_messages_component__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./messages/messages.component */ "./src/app/messages/messages.component.ts"); +/* harmony import */ var _staking_staking_component__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ./staking/staking.component */ "./src/app/staking/staking.component.ts"); +/* harmony import */ var _angular_common_http__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! @angular/common/http */ "./node_modules/@angular/common/fesm5/http.js"); +/* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! @ngx-translate/core */ "./node_modules/@ngx-translate/core/fesm5/ngx-translate-core.js"); +/* harmony import */ var _ngx_translate_http_loader__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! @ngx-translate/http-loader */ "./node_modules/@ngx-translate/http-loader/fesm5/ngx-translate-http-loader.js"); +/* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! @angular/forms */ "./node_modules/@angular/forms/fesm5/forms.js"); +/* harmony import */ var _typing_message_typing_message_component__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! ./typing-message/typing-message.component */ "./src/app/typing-message/typing-message.component.ts"); +/* harmony import */ var _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! ./_helpers/services/backend.service */ "./src/app/_helpers/services/backend.service.ts"); +/* harmony import */ var _helpers_pipes_money_to_int_pipe__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(/*! ./_helpers/pipes/money-to-int.pipe */ "./src/app/_helpers/pipes/money-to-int.pipe.ts"); +/* harmony import */ var _helpers_pipes_int_to_money_pipe__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(/*! ./_helpers/pipes/int-to-money.pipe */ "./src/app/_helpers/pipes/int-to-money.pipe.ts"); +/* harmony import */ var _helpers_directives_staking_switch_staking_switch_component__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(/*! ./_helpers/directives/staking-switch/staking-switch.component */ "./src/app/_helpers/directives/staking-switch/staking-switch.component.ts"); +/* harmony import */ var _helpers_directives_tooltip_directive__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(/*! ./_helpers/directives/tooltip.directive */ "./src/app/_helpers/directives/tooltip.directive.ts"); +/* harmony import */ var _helpers_pipes_history_type_messages_pipe__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(/*! ./_helpers/pipes/history-type-messages.pipe */ "./src/app/_helpers/pipes/history-type-messages.pipe.ts"); +/* harmony import */ var _helpers_pipes_contract_status_messages_pipe__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(/*! ./_helpers/pipes/contract-status-messages.pipe */ "./src/app/_helpers/pipes/contract-status-messages.pipe.ts"); +/* harmony import */ var _helpers_pipes_contract_time_left_pipe__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(/*! ./_helpers/pipes/contract-time-left.pipe */ "./src/app/_helpers/pipes/contract-time-left.pipe.ts"); +/* harmony import */ var ngx_contextmenu__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(/*! ngx-contextmenu */ "./node_modules/ngx-contextmenu/fesm5/ngx-contextmenu.js"); +/* harmony import */ var angular_highcharts__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(/*! angular-highcharts */ "./node_modules/angular-highcharts/fesm5/angular-highcharts.js"); +/* harmony import */ var _helpers_directives_input_validate_input_validate_directive__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(/*! ./_helpers/directives/input-validate/input-validate.directive */ "./src/app/_helpers/directives/input-validate/input-validate.directive.ts"); +/* harmony import */ var _helpers_directives_modal_container_modal_container_component__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(/*! ./_helpers/directives/modal-container/modal-container.component */ "./src/app/_helpers/directives/modal-container/modal-container.component.ts"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +function HttpLoaderFactory(httpClient) { + return new _ngx_translate_http_loader__WEBPACK_IMPORTED_MODULE_23__["TranslateHttpLoader"](httpClient, './assets/i18n/', '.json'); +} + + + +// import * as more from 'highcharts/highcharts-more.src'; +// import * as exporting from 'highcharts/modules/exporting.src'; +// import * as highstock from 'highcharts/modules/stock.src'; +angular_highcharts__WEBPACK_IMPORTED_MODULE_35__["Highcharts"].setOptions({ +// global: { +// useUTC: false +// } +}); +var AppModule = /** @class */ (function () { + function AppModule() { + } + AppModule = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_1__["NgModule"])({ + declarations: [ + _app_component__WEBPACK_IMPORTED_MODULE_3__["AppComponent"], + _login_login_component__WEBPACK_IMPORTED_MODULE_4__["LoginComponent"], + _settings_settings_component__WEBPACK_IMPORTED_MODULE_5__["SettingsComponent"], + _sidebar_sidebar_component__WEBPACK_IMPORTED_MODULE_6__["SidebarComponent"], + _main_main_component__WEBPACK_IMPORTED_MODULE_7__["MainComponent"], + _create_wallet_create_wallet_component__WEBPACK_IMPORTED_MODULE_8__["CreateWalletComponent"], + _open_wallet_open_wallet_component__WEBPACK_IMPORTED_MODULE_9__["OpenWalletComponent"], + _restore_wallet_restore_wallet_component__WEBPACK_IMPORTED_MODULE_10__["RestoreWalletComponent"], + _seed_phrase_seed_phrase_component__WEBPACK_IMPORTED_MODULE_11__["SeedPhraseComponent"], + _wallet_details_wallet_details_component__WEBPACK_IMPORTED_MODULE_12__["WalletDetailsComponent"], + _wallet_wallet_component__WEBPACK_IMPORTED_MODULE_13__["WalletComponent"], + _send_send_component__WEBPACK_IMPORTED_MODULE_14__["SendComponent"], + _receive_receive_component__WEBPACK_IMPORTED_MODULE_15__["ReceiveComponent"], + _history_history_component__WEBPACK_IMPORTED_MODULE_16__["HistoryComponent"], + _contracts_contracts_component__WEBPACK_IMPORTED_MODULE_17__["ContractsComponent"], + _purchase_purchase_component__WEBPACK_IMPORTED_MODULE_18__["PurchaseComponent"], + _messages_messages_component__WEBPACK_IMPORTED_MODULE_19__["MessagesComponent"], + _staking_staking_component__WEBPACK_IMPORTED_MODULE_20__["StakingComponent"], + _typing_message_typing_message_component__WEBPACK_IMPORTED_MODULE_25__["TypingMessageComponent"], + _helpers_pipes_money_to_int_pipe__WEBPACK_IMPORTED_MODULE_27__["MoneyToIntPipe"], + _helpers_pipes_int_to_money_pipe__WEBPACK_IMPORTED_MODULE_28__["IntToMoneyPipe"], + _helpers_directives_staking_switch_staking_switch_component__WEBPACK_IMPORTED_MODULE_29__["StakingSwitchComponent"], + _helpers_pipes_history_type_messages_pipe__WEBPACK_IMPORTED_MODULE_31__["HistoryTypeMessagesPipe"], + _helpers_pipes_contract_status_messages_pipe__WEBPACK_IMPORTED_MODULE_32__["ContractStatusMessagesPipe"], + _helpers_pipes_contract_time_left_pipe__WEBPACK_IMPORTED_MODULE_33__["ContractTimeLeftPipe"], + _helpers_directives_tooltip_directive__WEBPACK_IMPORTED_MODULE_30__["TooltipDirective"], + _helpers_directives_input_validate_input_validate_directive__WEBPACK_IMPORTED_MODULE_36__["InputValidateDirective"], + _helpers_directives_modal_container_modal_container_component__WEBPACK_IMPORTED_MODULE_37__["ModalContainerComponent"] + ], + imports: [ + _angular_platform_browser__WEBPACK_IMPORTED_MODULE_0__["BrowserModule"], + _app_routing_module__WEBPACK_IMPORTED_MODULE_2__["AppRoutingModule"], + _angular_common_http__WEBPACK_IMPORTED_MODULE_21__["HttpClientModule"], + _ngx_translate_core__WEBPACK_IMPORTED_MODULE_22__["TranslateModule"].forRoot({ + loader: { + provide: _ngx_translate_core__WEBPACK_IMPORTED_MODULE_22__["TranslateLoader"], + useFactory: HttpLoaderFactory, + deps: [_angular_common_http__WEBPACK_IMPORTED_MODULE_21__["HttpClient"]] + } + }), + _angular_forms__WEBPACK_IMPORTED_MODULE_24__["FormsModule"], + _angular_forms__WEBPACK_IMPORTED_MODULE_24__["ReactiveFormsModule"], + angular_highcharts__WEBPACK_IMPORTED_MODULE_35__["ChartModule"], + ngx_contextmenu__WEBPACK_IMPORTED_MODULE_34__["ContextMenuModule"].forRoot() + ], + providers: [ + _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_26__["BackendService"], + _helpers_pipes_money_to_int_pipe__WEBPACK_IMPORTED_MODULE_27__["MoneyToIntPipe"], + _helpers_pipes_int_to_money_pipe__WEBPACK_IMPORTED_MODULE_28__["IntToMoneyPipe"], + ], + bootstrap: [_app_component__WEBPACK_IMPORTED_MODULE_3__["AppComponent"]] + }) + ], AppModule); + return AppModule; +}()); + + + +/***/ }), + +/***/ "./src/app/contracts/contracts.component.html": +/*!****************************************************!*\ + !*** ./src/app/contracts/contracts.component.html ***! + \****************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = "
\r\n {{ 'CONTRACTS.EMPTY' | translate }}\r\n
\r\n\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
{{ 'CONTRACTS.CONTRACTS' | translate }}{{ 'CONTRACTS.DATE' | translate }}{{ 'CONTRACTS.AMOUNT' | translate }}{{ 'CONTRACTS.STATUS' | translate }}{{ 'CONTRACTS.COMMENTS' | translate }}
\r\n
\r\n \r\n \r\n \r\n {{item.private_detailes.t}}\r\n
\r\n
{{item.timestamp * 1000 | date : 'dd-MM-yyyy HH:mm'}}{{item.private_detailes.to_pay | intToMoney}} {{variablesService.defaultCurrency}}\r\n
\r\n {{item | contractStatusMessages}}\r\n
\r\n
\r\n
\r\n {{item.private_detailes.c}}\r\n
\r\n
\r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n" + +/***/ }), + +/***/ "./src/app/contracts/contracts.component.scss": +/*!****************************************************!*\ + !*** ./src/app/contracts/contracts.component.scss ***! + \****************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = ":host {\n width: 100%; }\n\n.empty-contracts {\n font-size: 1.5rem; }\n\n.wrap-table {\n margin: -3rem -3rem 0 -3rem;\n overflow-x: auto; }\n\n.wrap-table .contract {\n position: relative;\n display: flex;\n align-items: center; }\n\n.wrap-table .contract .icon {\n flex-shrink: 0; }\n\n.wrap-table .contract .icon.new, .wrap-table .contract .icon.alert {\n position: absolute;\n top: 0; }\n\n.wrap-table .contract .icon.new {\n left: -2.3rem;\n -webkit-mask: url('new.svg') no-repeat center;\n mask: url('new.svg') no-repeat center;\n width: 1.7rem;\n height: 1.7rem; }\n\n.wrap-table .contract .icon.alert {\n top: 0.2rem;\n left: -2.1rem;\n -webkit-mask: url('alert.svg') no-repeat center;\n mask: url('alert.svg') no-repeat center;\n width: 1.2rem;\n height: 1.2rem; }\n\n.wrap-table .contract .icon.purchase, .wrap-table .contract .icon.sell {\n margin-right: 1rem;\n width: 1.5rem;\n height: 1.5rem; }\n\n.wrap-table .contract .icon.purchase {\n -webkit-mask: url('purchase.svg') no-repeat center;\n mask: url('purchase.svg') no-repeat center; }\n\n.wrap-table .contract .icon.sell {\n -webkit-mask: url('sell.svg') no-repeat center;\n mask: url('sell.svg') no-repeat center; }\n\n.wrap-table .contract span {\n text-overflow: ellipsis;\n overflow: hidden;\n max-width: 20vw; }\n\n.wrap-table .status, .wrap-table .comment {\n text-overflow: ellipsis;\n overflow: hidden;\n max-width: 20vw; }\n\n.contracts-buttons {\n display: flex;\n margin: 3rem 0;\n width: 50%; }\n\n.contracts-buttons button {\n flex: 0 1 50%;\n margin-right: 1.5rem; }\n\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvY29udHJhY3RzL0Q6XFx6YW5vL3NyY1xcYXBwXFxjb250cmFjdHNcXGNvbnRyYWN0cy5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLFlBQVcsRUFDWjs7QUFFRDtFQUNFLGtCQUFpQixFQUNsQjs7QUFFRDtFQUNFLDRCQUEyQjtFQUMzQixpQkFBZ0IsRUF5RGpCOztBQTNERDtJQUtJLG1CQUFrQjtJQUNsQixjQUFhO0lBQ2Isb0JBQW1CLEVBNkNwQjs7QUFwREg7TUFVTSxlQUFjLEVBbUNmOztBQTdDTDtRQWFRLG1CQUFrQjtRQUNsQixPQUFNLEVBQ1A7O0FBZlA7UUFrQlEsY0FBYTtRQUNiLDhDQUFzRDtnQkFBdEQsc0NBQXNEO1FBQ3RELGNBQWE7UUFDYixlQUFjLEVBQ2Y7O0FBdEJQO1FBeUJRLFlBQVc7UUFDWCxjQUFhO1FBQ2IsZ0RBQXdEO2dCQUF4RCx3Q0FBd0Q7UUFDeEQsY0FBYTtRQUNiLGVBQWMsRUFDZjs7QUE5QlA7UUFpQ1EsbUJBQWtCO1FBQ2xCLGNBQWE7UUFDYixlQUFjLEVBQ2Y7O0FBcENQO1FBdUNRLG1EQUEyRDtnQkFBM0QsMkNBQTJELEVBQzVEOztBQXhDUDtRQTJDUSwrQ0FBdUQ7Z0JBQXZELHVDQUF1RCxFQUN4RDs7QUE1Q1A7TUFnRE0sd0JBQXVCO01BQ3ZCLGlCQUFnQjtNQUNoQixnQkFBZSxFQUNoQjs7QUFuREw7SUF1REksd0JBQXVCO0lBQ3ZCLGlCQUFnQjtJQUNoQixnQkFBZSxFQUNoQjs7QUFHSDtFQUNFLGNBQWE7RUFDYixlQUFjO0VBQ2QsV0FBVSxFQU1YOztBQVREO0lBTUksY0FBYTtJQUNiLHFCQUFvQixFQUNyQiIsImZpbGUiOiJzcmMvYXBwL2NvbnRyYWN0cy9jb250cmFjdHMuY29tcG9uZW50LnNjc3MiLCJzb3VyY2VzQ29udGVudCI6WyI6aG9zdCB7XHJcbiAgd2lkdGg6IDEwMCU7XHJcbn1cclxuXHJcbi5lbXB0eS1jb250cmFjdHMge1xyXG4gIGZvbnQtc2l6ZTogMS41cmVtO1xyXG59XHJcblxyXG4ud3JhcC10YWJsZSB7XHJcbiAgbWFyZ2luOiAtM3JlbSAtM3JlbSAwIC0zcmVtO1xyXG4gIG92ZXJmbG93LXg6IGF1dG87XHJcblxyXG4gIC5jb250cmFjdCB7XHJcbiAgICBwb3NpdGlvbjogcmVsYXRpdmU7XHJcbiAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuXHJcbiAgICAuaWNvbiB7XHJcbiAgICAgIGZsZXgtc2hyaW5rOiAwO1xyXG5cclxuICAgICAgJi5uZXcsICYuYWxlcnQge1xyXG4gICAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcclxuICAgICAgICB0b3A6IDA7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICYubmV3IHtcclxuICAgICAgICBsZWZ0OiAtMi4zcmVtO1xyXG4gICAgICAgIG1hc2s6IHVybCguLi8uLi9hc3NldHMvaWNvbnMvbmV3LnN2Zykgbm8tcmVwZWF0IGNlbnRlcjtcclxuICAgICAgICB3aWR0aDogMS43cmVtO1xyXG4gICAgICAgIGhlaWdodDogMS43cmVtO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAmLmFsZXJ0IHtcclxuICAgICAgICB0b3A6IDAuMnJlbTtcclxuICAgICAgICBsZWZ0OiAtMi4xcmVtO1xyXG4gICAgICAgIG1hc2s6IHVybCguLi8uLi9hc3NldHMvaWNvbnMvYWxlcnQuc3ZnKSBuby1yZXBlYXQgY2VudGVyO1xyXG4gICAgICAgIHdpZHRoOiAxLjJyZW07XHJcbiAgICAgICAgaGVpZ2h0OiAxLjJyZW07XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICYucHVyY2hhc2UsICYuc2VsbCB7XHJcbiAgICAgICAgbWFyZ2luLXJpZ2h0OiAxcmVtO1xyXG4gICAgICAgIHdpZHRoOiAxLjVyZW07XHJcbiAgICAgICAgaGVpZ2h0OiAxLjVyZW07XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICYucHVyY2hhc2Uge1xyXG4gICAgICAgIG1hc2s6IHVybCguLi8uLi9hc3NldHMvaWNvbnMvcHVyY2hhc2Uuc3ZnKSBuby1yZXBlYXQgY2VudGVyO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAmLnNlbGwge1xyXG4gICAgICAgIG1hc2s6IHVybCguLi8uLi9hc3NldHMvaWNvbnMvc2VsbC5zdmcpIG5vLXJlcGVhdCBjZW50ZXI7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBzcGFuIHtcclxuICAgICAgdGV4dC1vdmVyZmxvdzogZWxsaXBzaXM7XHJcbiAgICAgIG92ZXJmbG93OiBoaWRkZW47XHJcbiAgICAgIG1heC13aWR0aDogMjB2dztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC5zdGF0dXMsIC5jb21tZW50IHtcclxuICAgIHRleHQtb3ZlcmZsb3c6IGVsbGlwc2lzO1xyXG4gICAgb3ZlcmZsb3c6IGhpZGRlbjtcclxuICAgIG1heC13aWR0aDogMjB2dztcclxuICB9XHJcbn1cclxuXHJcbi5jb250cmFjdHMtYnV0dG9ucyB7XHJcbiAgZGlzcGxheTogZmxleDtcclxuICBtYXJnaW46IDNyZW0gMDtcclxuICB3aWR0aDogNTAlO1xyXG5cclxuICBidXR0b24ge1xyXG4gICAgZmxleDogMCAxIDUwJTtcclxuICAgIG1hcmdpbi1yaWdodDogMS41cmVtO1xyXG4gIH1cclxufVxyXG4iXX0= */" + +/***/ }), + +/***/ "./src/app/contracts/contracts.component.ts": +/*!**************************************************!*\ + !*** ./src/app/contracts/contracts.component.ts ***! + \**************************************************/ +/*! exports provided: ContractsComponent */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ContractsComponent", function() { return ContractsComponent; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/router */ "./node_modules/@angular/router/fesm5/router.js"); +/* harmony import */ var _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../_helpers/services/variables.service */ "./src/app/_helpers/services/variables.service.ts"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + + + +var ContractsComponent = /** @class */ (function () { + function ContractsComponent(route, router, variablesService) { + this.route = route; + this.router = router; + this.variablesService = variablesService; + } + ContractsComponent.prototype.ngOnInit = function () { + var _this = this; + this.parentRouting = this.route.parent.params.subscribe(function (params) { + if (params.hasOwnProperty('id')) { + _this.walletId = params['id']; + } + }); + }; + ContractsComponent.prototype.ngOnDestroy = function () { + this.parentRouting.unsubscribe(); + }; + ContractsComponent = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Component"])({ + selector: 'app-contracts', + template: __webpack_require__(/*! ./contracts.component.html */ "./src/app/contracts/contracts.component.html"), + styles: [__webpack_require__(/*! ./contracts.component.scss */ "./src/app/contracts/contracts.component.scss")] + }), + __metadata("design:paramtypes", [_angular_router__WEBPACK_IMPORTED_MODULE_1__["ActivatedRoute"], + _angular_router__WEBPACK_IMPORTED_MODULE_1__["Router"], + _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_2__["VariablesService"]]) + ], ContractsComponent); + return ContractsComponent; +}()); + + + +/***/ }), + +/***/ "./src/app/create-wallet/create-wallet.component.html": +/*!************************************************************!*\ + !*** ./src/app/create-wallet/create-wallet.component.html ***! + \************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = "
\r\n\r\n \r\n\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n Name is required.\r\n
\r\n
\r\n Name is duplicate.\r\n
\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n Confirm password not match.\r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n
\r\n\r\n
\r\n" + +/***/ }), + +/***/ "./src/app/create-wallet/create-wallet.component.scss": +/*!************************************************************!*\ + !*** ./src/app/create-wallet/create-wallet.component.scss ***! + \************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = ".form-create {\n margin: 2.4rem 0;\n width: 50%; }\n .form-create .wrap-buttons {\n display: flex;\n margin: 2.5rem -0.7rem; }\n .form-create .wrap-buttons button {\n margin: 0 0.7rem; }\n .form-create .wrap-buttons button.transparent-button {\n flex-basis: 50%; }\n .form-create .wrap-buttons button.select-button {\n flex-basis: 60%; }\n .form-create .wrap-buttons button.create-button {\n flex: 1 1 50%; }\n\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvY3JlYXRlLXdhbGxldC9EOlxcemFuby9zcmNcXGFwcFxcY3JlYXRlLXdhbGxldFxcY3JlYXRlLXdhbGxldC5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLGlCQUFnQjtFQUNoQixXQUFVLEVBc0JYO0VBeEJEO0lBS0ksY0FBYTtJQUNiLHVCQUFzQixFQWlCdkI7RUF2Qkg7TUFTTSxpQkFBZ0IsRUFhakI7RUF0Qkw7UUFZUSxnQkFBZSxFQUNoQjtFQWJQO1FBZ0JRLGdCQUFlLEVBQ2hCO0VBakJQO1FBb0JRLGNBQWEsRUFDZCIsImZpbGUiOiJzcmMvYXBwL2NyZWF0ZS13YWxsZXQvY3JlYXRlLXdhbGxldC5jb21wb25lbnQuc2NzcyIsInNvdXJjZXNDb250ZW50IjpbIi5mb3JtLWNyZWF0ZSB7XHJcbiAgbWFyZ2luOiAyLjRyZW0gMDtcclxuICB3aWR0aDogNTAlO1xyXG5cclxuICAud3JhcC1idXR0b25zIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBtYXJnaW46IDIuNXJlbSAtMC43cmVtO1xyXG5cclxuICAgIGJ1dHRvbiB7XHJcbiAgICAgIG1hcmdpbjogMCAwLjdyZW07XHJcblxyXG4gICAgICAmLnRyYW5zcGFyZW50LWJ1dHRvbiB7XHJcbiAgICAgICAgZmxleC1iYXNpczogNTAlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAmLnNlbGVjdC1idXR0b24ge1xyXG4gICAgICAgIGZsZXgtYmFzaXM6IDYwJTtcclxuICAgICAgfVxyXG5cclxuICAgICAgJi5jcmVhdGUtYnV0dG9uIHtcclxuICAgICAgICBmbGV4OiAxIDEgNTAlO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcbiJdfQ== */" + +/***/ }), + +/***/ "./src/app/create-wallet/create-wallet.component.ts": +/*!**********************************************************!*\ + !*** ./src/app/create-wallet/create-wallet.component.ts ***! + \**********************************************************/ +/*! exports provided: CreateWalletComponent */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CreateWalletComponent", function() { return CreateWalletComponent; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/forms */ "./node_modules/@angular/forms/fesm5/forms.js"); +/* harmony import */ var _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../_helpers/services/backend.service */ "./src/app/_helpers/services/backend.service.ts"); +/* harmony import */ var _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../_helpers/services/variables.service */ "./src/app/_helpers/services/variables.service.ts"); +/* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/router */ "./node_modules/@angular/router/fesm5/router.js"); +/* harmony import */ var _helpers_models_wallet_model__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../_helpers/models/wallet.model */ "./src/app/_helpers/models/wallet.model.ts"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + + + + + + +var CreateWalletComponent = /** @class */ (function () { + function CreateWalletComponent(router, backend, variablesService, ngZone) { + var _this = this; + this.router = router; + this.backend = backend; + this.variablesService = variablesService; + this.ngZone = ngZone; + this.createForm = new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormGroup"]({ + name: new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormControl"]('', [_angular_forms__WEBPACK_IMPORTED_MODULE_1__["Validators"].required, function (g) { + for (var i = 0; i < _this.variablesService.wallets.length; i++) { + if (g.value === _this.variablesService.wallets[i].name) { + return { 'duplicate': true }; + } + } + return null; + }]), + password: new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormControl"](''), + confirm: new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormControl"]('') + }, function (g) { + return g.get('password').value === g.get('confirm').value ? null : { 'confirm_mismatch': true }; + }); + this.wallet = { + id: '' + }; + this.walletSaved = false; + } + CreateWalletComponent.prototype.ngOnInit = function () { + }; + CreateWalletComponent.prototype.createWallet = function () { + this.router.navigate(['/seed-phrase'], { queryParams: { wallet_id: this.wallet.id } }); + }; + CreateWalletComponent.prototype.saveWallet = function () { + var _this = this; + if (this.createForm.valid) { + this.backend.saveFileDialog('Save the wallet file.', '*', this.variablesService.settings.default_path, function (file_status, file_data) { + if (file_status) { + _this.variablesService.settings.default_path = file_data.path.substr(0, file_data.path.lastIndexOf('/')); + _this.backend.generateWallet(file_data.path, _this.createForm.get('password').value, function (generate_status, generate_data, errorCode) { + if (generate_status) { + _this.wallet.id = generate_data.wallet_id; + _this.variablesService.opening_wallet = new _helpers_models_wallet_model__WEBPACK_IMPORTED_MODULE_5__["Wallet"](generate_data.wallet_id, _this.createForm.get('name').value, _this.createForm.get('password').value, generate_data['wi'].path, generate_data['wi'].address, generate_data['wi'].balance, generate_data['wi'].unlocked_balance, generate_data['wi'].mined_total, generate_data['wi'].tracking_hey); + _this.ngZone.run(function () { + _this.walletSaved = true; + }); + } + else { + if (errorCode && errorCode === 'ALREADY_EXISTS') { + alert('You cannot record a file on top of another file'); + } + else { + alert('You cannot save a safe file to the system partition'); + } + } + }); + } + }); + } + }; + CreateWalletComponent = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Component"])({ + selector: 'app-create-wallet', + template: __webpack_require__(/*! ./create-wallet.component.html */ "./src/app/create-wallet/create-wallet.component.html"), + styles: [__webpack_require__(/*! ./create-wallet.component.scss */ "./src/app/create-wallet/create-wallet.component.scss")] + }), + __metadata("design:paramtypes", [_angular_router__WEBPACK_IMPORTED_MODULE_4__["Router"], + _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_2__["BackendService"], + _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_3__["VariablesService"], + _angular_core__WEBPACK_IMPORTED_MODULE_0__["NgZone"]]) + ], CreateWalletComponent); + return CreateWalletComponent; +}()); + + + +/***/ }), + +/***/ "./src/app/history/history.component.html": +/*!************************************************!*\ + !*** ./src/app/history/history.component.html ***! + \************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = "
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
{{ 'HISTORY.STATUS' | translate }}{{ 'HISTORY.DATE' | translate }}{{ 'HISTORY.AMOUNT' | translate }}{{ 'HISTORY.FEE' | translate }}{{ 'HISTORY.ADDRESS' | translate }}
\r\n
\r\n
\r\n
\r\n
\r\n \r\n {{ (item.is_income ? 'HISTORY.RECEIVED' : 'HISTORY.SEND') | translate }}\r\n
\r\n
{{item.timestamp * 1000 | date : 'dd-MM-yyyy HH:mm'}}{{item.sortAmount | intToMoney}} {{variablesService.defaultCurrency}}\r\n {{item.sortFee | intToMoney}} {{variablesService.defaultCurrency}}\r\n \r\n {{item | historyTypeMessages}}\r\n
\r\n
\r\n" + +/***/ }), + +/***/ "./src/app/history/history.component.scss": +/*!************************************************!*\ + !*** ./src/app/history/history.component.scss ***! + \************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = ":host {\n width: 100%; }\n\n.wrap-table {\n margin: -3rem; }\n\n.wrap-table table tbody tr .status {\n position: relative;\n display: flex;\n align-items: center; }\n\n.wrap-table table tbody tr .status .confirmation {\n position: absolute;\n top: 50%;\n left: -2rem;\n -webkit-transform: translateY(-50%);\n transform: translateY(-50%);\n display: flex;\n align-items: flex-end;\n width: 0.7rem;\n height: 1.5rem; }\n\n.wrap-table table tbody tr .status .confirmation .fill {\n width: 100%; }\n\n.wrap-table table tbody tr .status .icon {\n margin-right: 1rem;\n width: 1.7rem;\n height: 1.7rem; }\n\n.wrap-table table tbody tr .status.send .icon {\n -webkit-mask: url('send.svg') no-repeat center;\n mask: url('send.svg') no-repeat center; }\n\n.wrap-table table tbody tr .status.received .icon {\n -webkit-mask: url('receive.svg') no-repeat center;\n mask: url('receive.svg') no-repeat center; }\n\n.wrap-table table tbody tr .remote-address {\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 25vw; }\n\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvaGlzdG9yeS9EOlxcemFuby9zcmNcXGFwcFxcaGlzdG9yeVxcaGlzdG9yeS5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLFlBQVcsRUFDWjs7QUFFRDtFQUNFLGNBQWEsRUF5RGQ7O0FBMUREO0lBVVUsbUJBQWtCO0lBQ2xCLGNBQWE7SUFDYixvQkFBbUIsRUFvQ3BCOztBQWhEVDtNQWVZLG1CQUFrQjtNQUNsQixTQUFRO01BQ1IsWUFBVztNQUNYLG9DQUEyQjtjQUEzQiw0QkFBMkI7TUFDM0IsY0FBYTtNQUNiLHNCQUFxQjtNQUNyQixjQUFhO01BQ2IsZUFBYyxFQUtmOztBQTNCWDtRQXlCYyxZQUFXLEVBQ1o7O0FBMUJiO01BOEJZLG1CQUFrQjtNQUNsQixjQUFhO01BQ2IsZUFBYyxFQUNmOztBQWpDWDtNQXNDYywrQ0FBdUQ7Y0FBdkQsdUNBQXVELEVBQ3hEOztBQXZDYjtNQTZDYyxrREFBMEQ7Y0FBMUQsMENBQTBELEVBQzNEOztBQTlDYjtJQW1EVSxpQkFBZ0I7SUFDaEIsd0JBQXVCO0lBQ3ZCLGdCQUFlLEVBQ2hCIiwiZmlsZSI6InNyYy9hcHAvaGlzdG9yeS9oaXN0b3J5LmNvbXBvbmVudC5zY3NzIiwic291cmNlc0NvbnRlbnQiOlsiOmhvc3Qge1xyXG4gIHdpZHRoOiAxMDAlO1xyXG59XHJcblxyXG4ud3JhcC10YWJsZSB7XHJcbiAgbWFyZ2luOiAtM3JlbTtcclxuXHJcbiAgdGFibGUge1xyXG5cclxuICAgIHRib2R5IHtcclxuXHJcbiAgICAgIHRyIHtcclxuXHJcbiAgICAgICAgLnN0YXR1cyB7XHJcbiAgICAgICAgICBwb3NpdGlvbjogcmVsYXRpdmU7XHJcbiAgICAgICAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuXHJcbiAgICAgICAgICAuY29uZmlybWF0aW9uIHtcclxuICAgICAgICAgICAgcG9zaXRpb246IGFic29sdXRlO1xyXG4gICAgICAgICAgICB0b3A6IDUwJTtcclxuICAgICAgICAgICAgbGVmdDogLTJyZW07XHJcbiAgICAgICAgICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlWSgtNTAlKTtcclxuICAgICAgICAgICAgZGlzcGxheTogZmxleDtcclxuICAgICAgICAgICAgYWxpZ24taXRlbXM6IGZsZXgtZW5kO1xyXG4gICAgICAgICAgICB3aWR0aDogMC43cmVtO1xyXG4gICAgICAgICAgICBoZWlnaHQ6IDEuNXJlbTtcclxuXHJcbiAgICAgICAgICAgIC5maWxsIHtcclxuICAgICAgICAgICAgICB3aWR0aDogMTAwJTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIC5pY29uIHtcclxuICAgICAgICAgICAgbWFyZ2luLXJpZ2h0OiAxcmVtO1xyXG4gICAgICAgICAgICB3aWR0aDogMS43cmVtO1xyXG4gICAgICAgICAgICBoZWlnaHQ6IDEuN3JlbTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAmLnNlbmQgIHtcclxuXHJcbiAgICAgICAgICAgIC5pY29uIHtcclxuICAgICAgICAgICAgICBtYXNrOiB1cmwoLi4vLi4vYXNzZXRzL2ljb25zL3NlbmQuc3ZnKSBuby1yZXBlYXQgY2VudGVyO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgJi5yZWNlaXZlZCB7XHJcblxyXG4gICAgICAgICAgICAuaWNvbiB7XHJcbiAgICAgICAgICAgICAgbWFzazogdXJsKC4uLy4uL2Fzc2V0cy9pY29ucy9yZWNlaXZlLnN2Zykgbm8tcmVwZWF0IGNlbnRlcjtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLnJlbW90ZS1hZGRyZXNzIHtcclxuICAgICAgICAgIG92ZXJmbG93OiBoaWRkZW47XHJcbiAgICAgICAgICB0ZXh0LW92ZXJmbG93OiBlbGxpcHNpcztcclxuICAgICAgICAgIG1heC13aWR0aDogMjV2dztcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbn1cclxuIl19 */" + +/***/ }), + +/***/ "./src/app/history/history.component.ts": +/*!**********************************************!*\ + !*** ./src/app/history/history.component.ts ***! + \**********************************************/ +/*! exports provided: HistoryComponent */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HistoryComponent", function() { return HistoryComponent; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/router */ "./node_modules/@angular/router/fesm5/router.js"); +/* harmony import */ var _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../_helpers/services/backend.service */ "./src/app/_helpers/services/backend.service.ts"); +/* harmony import */ var _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../_helpers/services/variables.service */ "./src/app/_helpers/services/variables.service.ts"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + + + + +var HistoryComponent = /** @class */ (function () { + function HistoryComponent(route, backend, variablesService) { + this.route = route; + this.backend = backend; + this.variablesService = variablesService; + } + HistoryComponent.prototype.ngOnInit = function () { + var _this = this; + this.parentRouting = this.route.parent.params.subscribe(function () { + console.log(_this.variablesService.currentWallet.history); + }); + }; + HistoryComponent.prototype.getHeight = function (item) { + if ((this.variablesService.height_app - item.height >= 10 && item.height !== 0) || (item.is_mining === true && item.height === 0)) { + return 100; + } + else { + if (item.height === 0 || this.variablesService.height_app - item.height < 0) { + return 0; + } + else { + return (this.variablesService.height_app - item.height) * 10; + } + } + }; + HistoryComponent.prototype.ngOnDestroy = function () { + this.parentRouting.unsubscribe(); + }; + HistoryComponent = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Component"])({ + selector: 'app-history', + template: __webpack_require__(/*! ./history.component.html */ "./src/app/history/history.component.html"), + styles: [__webpack_require__(/*! ./history.component.scss */ "./src/app/history/history.component.scss")] + }), + __metadata("design:paramtypes", [_angular_router__WEBPACK_IMPORTED_MODULE_1__["ActivatedRoute"], + _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_2__["BackendService"], + _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_3__["VariablesService"]]) + ], HistoryComponent); + return HistoryComponent; +}()); + + + +/***/ }), + +/***/ "./src/app/login/login.component.html": +/*!********************************************!*\ + !*** ./src/app/login/login.component.html ***! + \********************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = "
\r\n
\r\n\r\n
\r\n\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n Password is required.\r\n
\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n Confirmation is required.\r\n
\r\n
\r\n
\r\n
\r\n Mismatch.\r\n
\r\n
\r\n \r\n
\r\n\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n Password is required.\r\n
\r\n
\r\n \r\n
\r\n\r\n
\r\n
\r\n" + +/***/ }), + +/***/ "./src/app/login/login.component.scss": +/*!********************************************!*\ + !*** ./src/app/login/login.component.scss ***! + \********************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = ":host {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%; }\n :host .content {\n display: flex; }\n :host .content .wrap-login {\n margin: auto;\n width: 100%;\n max-width: 40rem; }\n :host .content .wrap-login .logo {\n background: url('logo.png') no-repeat center top;\n width: 100%;\n height: 14rem; }\n :host .content .wrap-login .form-login {\n display: flex;\n flex-direction: column; }\n :host .content .wrap-login .form-login button {\n margin: 2.5rem auto;\n width: 100%;\n max-width: 15rem; }\n\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvbG9naW4vRDpcXHphbm8vc3JjXFxhcHBcXGxvZ2luXFxsb2dpbi5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLGdCQUFlO0VBQ2YsT0FBTTtFQUNOLFFBQU87RUFDUCxZQUFXO0VBQ1gsYUFBWSxFQTRCYjtFQWpDRDtJQVFJLGNBQWEsRUF3QmQ7RUFoQ0g7TUFXTSxhQUFZO01BQ1osWUFBVztNQUNYLGlCQUFnQixFQWtCakI7RUEvQkw7UUFnQlEsaURBQW9FO1FBQ3BFLFlBQVc7UUFDWCxjQUFhLEVBQ2Q7RUFuQlA7UUFzQlEsY0FBYTtRQUNiLHVCQUFzQixFQU92QjtFQTlCUDtVQTBCVSxvQkFBbUI7VUFDbkIsWUFBVztVQUNYLGlCQUFnQixFQUNqQiIsImZpbGUiOiJzcmMvYXBwL2xvZ2luL2xvZ2luLmNvbXBvbmVudC5zY3NzIiwic291cmNlc0NvbnRlbnQiOlsiOmhvc3Qge1xyXG4gIHBvc2l0aW9uOiBmaXhlZDtcclxuICB0b3A6IDA7XHJcbiAgbGVmdDogMDtcclxuICB3aWR0aDogMTAwJTtcclxuICBoZWlnaHQ6IDEwMCU7XHJcblxyXG4gIC5jb250ZW50IHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcblxyXG4gICAgLndyYXAtbG9naW4ge1xyXG4gICAgICBtYXJnaW46IGF1dG87XHJcbiAgICAgIHdpZHRoOiAxMDAlO1xyXG4gICAgICBtYXgtd2lkdGg6IDQwcmVtO1xyXG5cclxuICAgICAgLmxvZ28ge1xyXG4gICAgICAgIGJhY2tncm91bmQ6IHVybChcIi4uLy4uL2Fzc2V0cy9pbWFnZXMvbG9nby5wbmdcIikgbm8tcmVwZWF0IGNlbnRlciB0b3A7XHJcbiAgICAgICAgd2lkdGg6IDEwMCU7XHJcbiAgICAgICAgaGVpZ2h0OiAxNHJlbTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLmZvcm0tbG9naW4ge1xyXG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICAgICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuXHJcbiAgICAgICAgYnV0dG9uIHtcclxuICAgICAgICAgIG1hcmdpbjogMi41cmVtIGF1dG87XHJcbiAgICAgICAgICB3aWR0aDogMTAwJTtcclxuICAgICAgICAgIG1heC13aWR0aDogMTVyZW07XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcbiJdfQ== */" + +/***/ }), + +/***/ "./src/app/login/login.component.ts": +/*!******************************************!*\ + !*** ./src/app/login/login.component.ts ***! + \******************************************/ +/*! exports provided: LoginComponent */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LoginComponent", function() { return LoginComponent; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/forms */ "./node_modules/@angular/forms/fesm5/forms.js"); +/* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/router */ "./node_modules/@angular/router/fesm5/router.js"); +/* harmony import */ var _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../_helpers/services/backend.service */ "./src/app/_helpers/services/backend.service.ts"); +/* harmony import */ var _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../_helpers/services/variables.service */ "./src/app/_helpers/services/variables.service.ts"); +/* harmony import */ var _helpers_models_wallet_model__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../_helpers/models/wallet.model */ "./src/app/_helpers/models/wallet.model.ts"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + + + + + + +var LoginComponent = /** @class */ (function () { + function LoginComponent(route, router, backend, variablesService, ngZone) { + this.route = route; + this.router = router; + this.backend = backend; + this.variablesService = variablesService; + this.ngZone = ngZone; + this.regForm = new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormGroup"]({ + password: new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormControl"]('', _angular_forms__WEBPACK_IMPORTED_MODULE_1__["Validators"].required), + confirmation: new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormControl"]('', _angular_forms__WEBPACK_IMPORTED_MODULE_1__["Validators"].required) + }, function (g) { + return g.get('password').value === g.get('confirmation').value ? null : { 'mismatch': true }; + }); + this.authForm = new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormGroup"]({ + password: new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormControl"]('', _angular_forms__WEBPACK_IMPORTED_MODULE_1__["Validators"].required) + }); + this.type = 'reg'; + } + LoginComponent.prototype.ngOnInit = function () { + var _this = this; + this.route.queryParams.subscribe(function (params) { + if (params.type) { + _this.type = params.type; + } + }); + }; + LoginComponent.prototype.onSubmitCreatePass = function () { + var _this = this; + if (this.regForm.valid) { + this.variablesService.appPass = this.regForm.get('password').value; + this.backend.storeSecureAppData(function (status, data) { + if (status) { + _this.ngZone.run(function () { + _this.router.navigate(['/']); + }); + } + else { + // TODO error sign in + console.log(data['error_code']); + } + }); + } + }; + LoginComponent.prototype.onSubmitAuthPass = function () { + var _this = this; + if (this.authForm.valid) { + var appPass_1 = this.authForm.get('password').value; + this.backend.getSecureAppData({ pass: appPass_1 }, function (status, data) { + if (data.error_code && data.error_code === 'WRONG_PASSWORD') { + // TODO error log in informer.error('MESSAGE.INCORRECT_PASSWORD'); + console.log('WRONG_PASSWORD'); + } + else { + _this.variablesService.startCountdown(); + _this.variablesService.appPass = appPass_1; + if (_this.variablesService.wallets.length) { + _this.ngZone.run(function () { + _this.router.navigate(['/wallet/' + _this.variablesService.wallets[0].wallet_id]); + }); + return; + } + if (Object.keys(data).length !== 0) { + var openWallets_1 = 0; + var runWallets_1 = 0; + data.forEach(function (wallet, wallet_index) { + _this.backend.openWallet(wallet.path, wallet.pass, true, function (open_status, open_data) { + if (open_status) { + openWallets_1++; + _this.backend.runWallet(open_data.wallet_id, function (run_status) { + if (run_status) { + runWallets_1++; + _this.ngZone.run(function () { + var new_wallet = new _helpers_models_wallet_model__WEBPACK_IMPORTED_MODULE_5__["Wallet"](open_data.wallet_id, wallet.name, wallet.pass, open_data['wi'].path, open_data['wi'].address, open_data['wi'].balance, open_data['wi'].unlocked_balance, open_data['wi'].mined_total, open_data['wi'].tracking_hey); + if (open_data.recent_history && open_data.recent_history.history) { + new_wallet.prepareHistory(open_data.recent_history.history); + } + _this.backend.getContracts(open_data.wallet_id, function (contracts_status, contracts_data) { + if (contracts_status && contracts_data.hasOwnProperty('contracts')) { + _this.ngZone.run(function () { + new_wallet.prepareContractsAfterOpen(contracts_data.contracts, _this.variablesService.exp_med_ts, _this.variablesService.height_app, _this.variablesService.settings.viewedContracts, _this.variablesService.settings.notViewedContracts); + }); + } + }); + _this.variablesService.wallets.push(new_wallet); + if (_this.variablesService.wallets.length === 1) { + _this.router.navigate(['/wallet/' + _this.variablesService.wallets[0].wallet_id]); + } + }); + } + else { + if (wallet_index === data.length - 1 && runWallets_1 === 0) { + _this.ngZone.run(function () { + _this.router.navigate(['/']); + }); + } + // console.log(run_data['error_code']); + } + }); + } + else { + if (wallet_index === data.length - 1 && openWallets_1 === 0) { + _this.ngZone.run(function () { + _this.router.navigate(['/']); + }); + } + } + }); + }); + } + else { + _this.ngZone.run(function () { + _this.router.navigate(['/']); + }); + } + } + }); + } + }; + LoginComponent = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Component"])({ + selector: 'app-login', + template: __webpack_require__(/*! ./login.component.html */ "./src/app/login/login.component.html"), + styles: [__webpack_require__(/*! ./login.component.scss */ "./src/app/login/login.component.scss")] + }), + __metadata("design:paramtypes", [_angular_router__WEBPACK_IMPORTED_MODULE_2__["ActivatedRoute"], + _angular_router__WEBPACK_IMPORTED_MODULE_2__["Router"], + _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_3__["BackendService"], + _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_4__["VariablesService"], + _angular_core__WEBPACK_IMPORTED_MODULE_0__["NgZone"]]) + ], LoginComponent); + return LoginComponent; +}()); + + + +/***/ }), + +/***/ "./src/app/main/main.component.html": +/*!******************************************!*\ + !*** ./src/app/main/main.component.html ***! + \******************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = "
\r\n
\r\n

{{ 'MAIN.TITLE' | translate }}

\r\n
\r\n \r\n \r\n \r\n
\r\n
\r\n {{ 'MAIN.HELP' | translate }}\r\n
\r\n
\r\n
\r\n" + +/***/ }), + +/***/ "./src/app/main/main.component.scss": +/*!******************************************!*\ + !*** ./src/app/main/main.component.scss ***! + \******************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = ":host {\n flex: 1 0 auto;\n padding: 3rem; }\n\n.content {\n padding: 3rem;\n min-height: 100%; }\n\n.add-wallet .add-wallet-title {\n margin-bottom: 1rem; }\n\n.add-wallet .add-wallet-buttons {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin: 0 -0.5rem;\n padding: 1.5rem 0; }\n\n.add-wallet .add-wallet-buttons button {\n flex: 1 0 auto;\n margin: 0 0.5rem; }\n\n.add-wallet .add-wallet-help {\n display: flex;\n font-size: 1.3rem;\n line-height: 1.4rem; }\n\n.add-wallet .add-wallet-help .icon {\n -webkit-mask: url('howto.svg') no-repeat center;\n mask: url('howto.svg') no-repeat center;\n margin-right: 0.8rem;\n width: 1.4rem;\n height: 1.4rem; }\n\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvbWFpbi9EOlxcemFuby9zcmNcXGFwcFxcbWFpblxcbWFpbi5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLGVBQWM7RUFDZCxjQUFhLEVBQ2Q7O0FBRUQ7RUFDRSxjQUFhO0VBQ2IsaUJBQWdCLEVBQ2pCOztBQUVEO0VBR0ksb0JBQW1CLEVBQ3BCOztBQUpIO0VBT0ksY0FBYTtFQUNiLG9CQUFtQjtFQUNuQiwrQkFBOEI7RUFDOUIsa0JBQWlCO0VBQ2pCLGtCQUFpQixFQU1sQjs7QUFqQkg7SUFjTSxlQUFjO0lBQ2QsaUJBQWdCLEVBQ2pCOztBQWhCTDtFQW9CSSxjQUFhO0VBQ2Isa0JBQWlCO0VBQ2pCLG9CQUFtQixFQVFwQjs7QUE5Qkg7SUF5Qk0sZ0RBQXdEO1lBQXhELHdDQUF3RDtJQUN4RCxxQkFBb0I7SUFDcEIsY0FBYTtJQUNiLGVBQWMsRUFDZiIsImZpbGUiOiJzcmMvYXBwL21haW4vbWFpbi5jb21wb25lbnQuc2NzcyIsInNvdXJjZXNDb250ZW50IjpbIjpob3N0IHtcclxuICBmbGV4OiAxIDAgYXV0bztcclxuICBwYWRkaW5nOiAzcmVtO1xyXG59XHJcblxyXG4uY29udGVudCB7XHJcbiAgcGFkZGluZzogM3JlbTtcclxuICBtaW4taGVpZ2h0OiAxMDAlO1xyXG59XHJcblxyXG4uYWRkLXdhbGxldCB7XHJcblxyXG4gIC5hZGQtd2FsbGV0LXRpdGxlIHtcclxuICAgIG1hcmdpbi1ib3R0b206IDFyZW07XHJcbiAgfVxyXG5cclxuICAuYWRkLXdhbGxldC1idXR0b25zIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xyXG4gICAgbWFyZ2luOiAwIC0wLjVyZW07XHJcbiAgICBwYWRkaW5nOiAxLjVyZW0gMDtcclxuXHJcbiAgICBidXR0b24ge1xyXG4gICAgICBmbGV4OiAxIDAgYXV0bztcclxuICAgICAgbWFyZ2luOiAwIDAuNXJlbTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC5hZGQtd2FsbGV0LWhlbHAge1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuICAgIGZvbnQtc2l6ZTogMS4zcmVtO1xyXG4gICAgbGluZS1oZWlnaHQ6IDEuNHJlbTtcclxuXHJcbiAgICAuaWNvbiB7XHJcbiAgICAgIG1hc2s6IHVybCguLi8uLi9hc3NldHMvaWNvbnMvaG93dG8uc3ZnKSBuby1yZXBlYXQgY2VudGVyO1xyXG4gICAgICBtYXJnaW4tcmlnaHQ6IDAuOHJlbTtcclxuICAgICAgd2lkdGg6IDEuNHJlbTtcclxuICAgICAgaGVpZ2h0OiAxLjRyZW07XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcbiJdfQ== */" + +/***/ }), + +/***/ "./src/app/main/main.component.ts": +/*!****************************************!*\ + !*** ./src/app/main/main.component.ts ***! + \****************************************/ +/*! exports provided: MainComponent */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MainComponent", function() { return MainComponent; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../_helpers/services/backend.service */ "./src/app/_helpers/services/backend.service.ts"); +/* harmony import */ var _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../_helpers/services/variables.service */ "./src/app/_helpers/services/variables.service.ts"); +/* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/router */ "./node_modules/@angular/router/fesm5/router.js"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + + + + +var MainComponent = /** @class */ (function () { + function MainComponent(router, backend, variablesService, ngZone) { + this.router = router; + this.backend = backend; + this.variablesService = variablesService; + this.ngZone = ngZone; + } + MainComponent.prototype.ngOnInit = function () { }; + MainComponent.prototype.openWallet = function () { + var _this = this; + this.backend.openFileDialog('Open the wallet file.', '*', this.variablesService.settings.default_path, function (file_status, file_data) { + if (file_status) { + _this.variablesService.settings.default_path = file_data.path.substr(0, file_data.path.lastIndexOf('/')); + _this.ngZone.run(function () { + _this.router.navigate(['/open'], { queryParams: { path: file_data.path } }); + }); + } + else { + console.log(file_data['error_code']); + } + }); + }; + MainComponent = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Component"])({ + selector: 'app-main', + template: __webpack_require__(/*! ./main.component.html */ "./src/app/main/main.component.html"), + styles: [__webpack_require__(/*! ./main.component.scss */ "./src/app/main/main.component.scss")] + }), + __metadata("design:paramtypes", [_angular_router__WEBPACK_IMPORTED_MODULE_3__["Router"], + _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_1__["BackendService"], + _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_2__["VariablesService"], + _angular_core__WEBPACK_IMPORTED_MODULE_0__["NgZone"]]) + ], MainComponent); + return MainComponent; +}()); + + + +/***/ }), + +/***/ "./src/app/messages/messages.component.html": +/*!**************************************************!*\ + !*** ./src/app/messages/messages.component.html ***! + \**************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = "
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
{{ 'MESSAGES.ADDRESS' | translate }}{{ 'MESSAGES.MESSAGE' | translate }}
\r\n {{message.address}}\r\n \r\n \r\n {{message.message}}\r\n
\r\n
\r\n" + +/***/ }), + +/***/ "./src/app/messages/messages.component.scss": +/*!**************************************************!*\ + !*** ./src/app/messages/messages.component.scss ***! + \**************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = ":host {\n width: 100%; }\n\n.wrap-table {\n margin: -3rem; }\n\n.wrap-table table tbody tr td:first-child {\n position: relative;\n padding-right: 5rem;\n width: 18rem; }\n\n.wrap-table table tbody tr td:first-child span {\n display: block;\n line-height: 3.5rem;\n max-width: 10rem; }\n\n.wrap-table table tbody tr td:first-child .icon {\n position: absolute;\n top: 50%;\n right: 1rem;\n -webkit-transform: translateY(-50%);\n transform: translateY(-50%);\n display: block;\n -webkit-mask: url('alert.svg') no-repeat 0;\n mask: url('alert.svg') no-repeat 0;\n width: 1.2rem;\n height: 1.2rem; }\n\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvbWVzc2FnZXMvRDpcXHphbm8vc3JjXFxhcHBcXG1lc3NhZ2VzXFxtZXNzYWdlcy5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLFlBQVcsRUFDWjs7QUFFRDtFQUNFLGNBQWEsRUFvQ2Q7O0FBckNEO0lBWVksbUJBQWtCO0lBQ2xCLG9CQUFtQjtJQUNuQixhQUFZLEVBa0JiOztBQWhDWDtNQWlCYyxlQUFjO01BQ2Qsb0JBQW1CO01BQ25CLGlCQUFnQixFQUNqQjs7QUFwQmI7TUF1QmMsbUJBQWtCO01BQ2xCLFNBQVE7TUFDUixZQUFXO01BQ1gsb0NBQTJCO2NBQTNCLDRCQUEyQjtNQUMzQixlQUFjO01BQ2QsMkNBQW1EO2NBQW5ELG1DQUFtRDtNQUNuRCxjQUFhO01BQ2IsZUFBYyxFQUNmIiwiZmlsZSI6InNyYy9hcHAvbWVzc2FnZXMvbWVzc2FnZXMuY29tcG9uZW50LnNjc3MiLCJzb3VyY2VzQ29udGVudCI6WyI6aG9zdCB7XHJcbiAgd2lkdGg6IDEwMCU7XHJcbn1cclxuXHJcbi53cmFwLXRhYmxlIHtcclxuICBtYXJnaW46IC0zcmVtO1xyXG5cclxuICB0YWJsZSB7XHJcblxyXG4gICAgdGJvZHkge1xyXG5cclxuICAgICAgdHIge1xyXG5cclxuICAgICAgICB0ZCB7XHJcblxyXG4gICAgICAgICAgJjpmaXJzdC1jaGlsZCB7XHJcbiAgICAgICAgICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcclxuICAgICAgICAgICAgcGFkZGluZy1yaWdodDogNXJlbTtcclxuICAgICAgICAgICAgd2lkdGg6IDE4cmVtO1xyXG5cclxuICAgICAgICAgICAgc3BhbiB7XHJcbiAgICAgICAgICAgICAgZGlzcGxheTogYmxvY2s7XHJcbiAgICAgICAgICAgICAgbGluZS1oZWlnaHQ6IDMuNXJlbTtcclxuICAgICAgICAgICAgICBtYXgtd2lkdGg6IDEwcmVtO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAuaWNvbiB7XHJcbiAgICAgICAgICAgICAgcG9zaXRpb246IGFic29sdXRlO1xyXG4gICAgICAgICAgICAgIHRvcDogNTAlO1xyXG4gICAgICAgICAgICAgIHJpZ2h0OiAxcmVtO1xyXG4gICAgICAgICAgICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlWSgtNTAlKTtcclxuICAgICAgICAgICAgICBkaXNwbGF5OiBibG9jaztcclxuICAgICAgICAgICAgICBtYXNrOiB1cmwoLi4vLi4vYXNzZXRzL2ljb25zL2FsZXJ0LnN2Zykgbm8tcmVwZWF0IDA7XHJcbiAgICAgICAgICAgICAgd2lkdGg6IDEuMnJlbTtcclxuICAgICAgICAgICAgICBoZWlnaHQ6IDEuMnJlbTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxufVxyXG4iXX0= */" + +/***/ }), + +/***/ "./src/app/messages/messages.component.ts": +/*!************************************************!*\ + !*** ./src/app/messages/messages.component.ts ***! + \************************************************/ +/*! exports provided: MessagesComponent */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MessagesComponent", function() { return MessagesComponent; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + +var MessagesComponent = /** @class */ (function () { + function MessagesComponent() { + this.messages = [ + { + is_new: true, + address: '@bitmap', + message: 'No more miners for you!' + }, + { + is_new: false, + address: 'Hjkwey36gHasdhkajshd4bxnb5mcvowyefb2633FdsFGGWbb', + message: 'Hey! What’s with our BBR deal?' + }, + { + is_new: false, + address: '@john', + message: 'I’m coming!' + } + ]; + } + MessagesComponent.prototype.ngOnInit = function () { }; + MessagesComponent = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Component"])({ + selector: 'app-messages', + template: __webpack_require__(/*! ./messages.component.html */ "./src/app/messages/messages.component.html"), + styles: [__webpack_require__(/*! ./messages.component.scss */ "./src/app/messages/messages.component.scss")] + }), + __metadata("design:paramtypes", []) + ], MessagesComponent); + return MessagesComponent; +}()); + + + +/***/ }), + +/***/ "./src/app/open-wallet/open-wallet.component.html": +/*!********************************************************!*\ + !*** ./src/app/open-wallet/open-wallet.component.html ***! + \********************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = "
\r\n\r\n
\r\n
\r\n {{ 'BREADCRUMBS.ADD_WALLET' | translate }}\r\n {{ 'BREADCRUMBS.OPEN_WALLET' | translate }}\r\n
\r\n \r\n \r\n {{ 'COMMON.BACK' | translate }}\r\n \r\n
\r\n\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n Name is required.\r\n
\r\n
\r\n Name is duplicate.\r\n
\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n \r\n
\r\n
\r\n\r\n
\r\n\r\n" + +/***/ }), + +/***/ "./src/app/open-wallet/open-wallet.component.scss": +/*!********************************************************!*\ + !*** ./src/app/open-wallet/open-wallet.component.scss ***! + \********************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = ".form-open {\n margin: 2.4rem 0;\n width: 50%; }\n .form-open .wrap-buttons {\n display: flex;\n margin: 2.5rem -0.7rem; }\n .form-open .wrap-buttons button {\n margin: 0 0.7rem; }\n .form-open .wrap-buttons button.create-button {\n flex: 1 1 50%; }\n\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvb3Blbi13YWxsZXQvRDpcXHphbm8vc3JjXFxhcHBcXG9wZW4td2FsbGV0XFxvcGVuLXdhbGxldC5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLGlCQUFnQjtFQUNoQixXQUFVLEVBY1g7RUFoQkQ7SUFLSSxjQUFhO0lBQ2IsdUJBQXNCLEVBU3ZCO0VBZkg7TUFTTSxpQkFBZ0IsRUFLakI7RUFkTDtRQVlRLGNBQWEsRUFDZCIsImZpbGUiOiJzcmMvYXBwL29wZW4td2FsbGV0L29wZW4td2FsbGV0LmNvbXBvbmVudC5zY3NzIiwic291cmNlc0NvbnRlbnQiOlsiLmZvcm0tb3BlbiB7XHJcbiAgbWFyZ2luOiAyLjRyZW0gMDtcclxuICB3aWR0aDogNTAlO1xyXG5cclxuICAud3JhcC1idXR0b25zIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBtYXJnaW46IDIuNXJlbSAtMC43cmVtO1xyXG5cclxuICAgIGJ1dHRvbiB7XHJcbiAgICAgIG1hcmdpbjogMCAwLjdyZW07XHJcblxyXG4gICAgICAmLmNyZWF0ZS1idXR0b24ge1xyXG4gICAgICAgIGZsZXg6IDEgMSA1MCU7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbn1cclxuIl19 */" + +/***/ }), + +/***/ "./src/app/open-wallet/open-wallet.component.ts": +/*!******************************************************!*\ + !*** ./src/app/open-wallet/open-wallet.component.ts ***! + \******************************************************/ +/*! exports provided: OpenWalletComponent */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OpenWalletComponent", function() { return OpenWalletComponent; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/forms */ "./node_modules/@angular/forms/fesm5/forms.js"); +/* harmony import */ var _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../_helpers/services/backend.service */ "./src/app/_helpers/services/backend.service.ts"); +/* harmony import */ var _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../_helpers/services/variables.service */ "./src/app/_helpers/services/variables.service.ts"); +/* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/router */ "./node_modules/@angular/router/fesm5/router.js"); +/* harmony import */ var _helpers_models_wallet_model__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../_helpers/models/wallet.model */ "./src/app/_helpers/models/wallet.model.ts"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + + + + + + +var OpenWalletComponent = /** @class */ (function () { + function OpenWalletComponent(route, router, backend, variablesService, ngZone) { + var _this = this; + this.route = route; + this.router = router; + this.backend = backend; + this.variablesService = variablesService; + this.ngZone = ngZone; + this.openForm = new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormGroup"]({ + name: new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormControl"]('', [_angular_forms__WEBPACK_IMPORTED_MODULE_1__["Validators"].required, function (g) { + for (var i = 0; i < _this.variablesService.wallets.length; i++) { + if (g.value === _this.variablesService.wallets[i].name) { + return { 'duplicate': true }; + } + } + return null; + }]), + password: new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormControl"]('') + }); + } + OpenWalletComponent.prototype.ngOnInit = function () { + var _this = this; + this.route.queryParams.subscribe(function (params) { + if (params.path) { + _this.filePath = params.path; + var filename = ''; + if (params.path.lastIndexOf('.') === -1) { + filename = params.path.substr(params.path.lastIndexOf('/') + 1); + } + else { + filename = params.path.substr(params.path.lastIndexOf('/') + 1, params.path.lastIndexOf('.') - 1 - params.path.lastIndexOf('/')); + } + if (filename.length > 25) { + filename = filename.slice(0, 25); + } + _this.openForm.get('name').setValue(filename); + } + }); + }; + OpenWalletComponent.prototype.openWallet = function () { + var _this = this; + if (this.openForm.valid) { + this.backend.openWallet(this.filePath, this.openForm.get('password').value, false, function (open_status, open_data, open_error) { + if (open_error && open_error === 'FILE_NOT_FOUND') { + // var error_translate = $filter('translate')('INFORMER.SAFE_FILE_NOT_FOUND1'); + // error_translate += ':
' + $scope.safe.path; + // error_translate += $filter('translate')('INFORMER.SAFE_FILE_NOT_FOUND2'); + // informer.fileNotFound(error_translate); + alert('FILE_NOT_FOUND'); + } + else { + if (open_status || open_error === 'FILE_RESTORED') { + var exists_1 = false; + _this.variablesService.wallets.forEach(function (wallet) { + if (wallet.address === open_data['wi'].address) { + exists_1 = true; + } + }); + if (exists_1) { + alert('SAFES.WITH_ADDRESS_ALREADY_OPEN'); + _this.backend.closeWallet(open_data.wallet_id, function (close_status, close_data) { + console.log(close_status, close_data); + _this.ngZone.run(function () { + _this.router.navigate(['/']); + }); + }); + } + else { + _this.backend.runWallet(open_data.wallet_id, function (run_status, run_data) { + if (run_status) { + var new_wallet_1 = new _helpers_models_wallet_model__WEBPACK_IMPORTED_MODULE_5__["Wallet"](open_data.wallet_id, _this.openForm.get('name').value, _this.openForm.get('password').value, open_data['wi'].path, open_data['wi'].address, open_data['wi'].balance, open_data['wi'].unlocked_balance, open_data['wi'].mined_total, open_data['wi'].tracking_hey); + if (open_data.recent_history && open_data.recent_history.history) { + new_wallet_1.prepareHistory(open_data.recent_history.history); + } + _this.backend.getContracts(open_data.wallet_id, function (contracts_status, contracts_data) { + if (contracts_status && contracts_data.hasOwnProperty('contracts')) { + _this.ngZone.run(function () { + new_wallet_1.prepareContractsAfterOpen(contracts_data.contracts, _this.variablesService.exp_med_ts, _this.variablesService.height_app, _this.variablesService.settings.viewedContracts, _this.variablesService.settings.notViewedContracts); + }); + } + }); + _this.variablesService.wallets.push(new_wallet_1); + _this.backend.storeSecureAppData(function (status, data) { + console.log('Store App Data', status, data); + }); + _this.ngZone.run(function () { + _this.router.navigate(['/wallet/' + open_data.wallet_id]); + }); + } + else { + console.log(run_data['error_code']); + } + }); + } + } + } + }); + } + }; + OpenWalletComponent = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Component"])({ + selector: 'app-open-wallet', + template: __webpack_require__(/*! ./open-wallet.component.html */ "./src/app/open-wallet/open-wallet.component.html"), + styles: [__webpack_require__(/*! ./open-wallet.component.scss */ "./src/app/open-wallet/open-wallet.component.scss")] + }), + __metadata("design:paramtypes", [_angular_router__WEBPACK_IMPORTED_MODULE_4__["ActivatedRoute"], + _angular_router__WEBPACK_IMPORTED_MODULE_4__["Router"], + _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_2__["BackendService"], + _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_3__["VariablesService"], + _angular_core__WEBPACK_IMPORTED_MODULE_0__["NgZone"]]) + ], OpenWalletComponent); + return OpenWalletComponent; +}()); + + + +/***/ }), + +/***/ "./src/app/purchase/purchase.component.html": +/*!**************************************************!*\ + !*** ./src/app/purchase/purchase.component.html ***! + \**************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = "
\r\n
\r\n {{ 'BREADCRUMBS.CONTRACTS' | translate }}\r\n {{ 'BREADCRUMBS.NEW_PURCHASE' | translate }}\r\n {{ 'BREADCRUMBS.OLD_PURCHASE' | translate }}\r\n
\r\n \r\n
\r\n\r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n Description is required.\r\n
\r\n
\r\n\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n Seller is required.\r\n
\r\n
\r\n Seller not valid.\r\n
\r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n Amount is required.\r\n
\r\n
\r\n
\r\n\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n Your deposit is required.\r\n
\r\n
\r\n\r\n
\r\n
\r\n \r\n
\r\n \r\n \r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n Seller deposit is required.\r\n
\r\n
\r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n\r\n \r\n\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n\r\n \r\n\r\n
\r\n\r\n variablesService.currentWallet.unlocked_balance\">\r\n {{ 'There are insufficient funds in the safe. Add funds to the safe to continue' | translate }}\r\n \r\n\r\n \r\n {{ 'DEALS.CUSTOMER_WAITING_ANSWER' | translate }}\r\n \r\n\r\n {{ 'The seller ignored your contract proposal' | translate }}\r\n {{ 'Pledge amount unblocked' | translate }}\r\n\r\n {{ 'Waiting for seller to ship item' | translate }}\r\n\r\n {{ 'The seller ignored your proposal to cancel the contract' | translate }}\r\n\r\n {{ 'The contract proposal has expired' | translate }}\r\n\r\n {{ 'Please wait for the pledges to be made' | translate }}\r\n\r\n {{ 'Waiting for seller to ship item' | translate }}\r\n\r\n {{ 'Contract completed successfully' | translate }}\r\n {{ 'Item received, payment transferred, pledges returned' | translate }}\r\n\r\n {{ 'Item not received' | translate }}\r\n {{ 'All pledges nullified' | translate }}\r\n\r\n {{ 'You have made a proposal to cancel the contract' | translate }}\r\n \r\n\r\n {{ 'The contract is being cancelled. Please wait for the pledge to be returned' | translate }}\r\n\r\n {{ 'Contract canceled' | translate }}\r\n {{ 'Pledges returned' | translate }}\r\n \r\n\r\n \r\n {{ 'The buyer is proposing a contract' | translate }}\r\n \r\n\r\n {{ 'You ignored the contract proposal' | translate }}\r\n\r\n {{ 'You ignored the proposal to cancel the contract' | translate }}\r\n\r\n {{ 'The contract proposal has expired' | translate }}\r\n\r\n {{ 'Please wait for the pledges to be made' | translate }}\r\n\r\n {{ 'The buyer is waiting for the item to be delivered' | translate }}\r\n {{ 'Pledges made' | translate }}\r\n\r\n {{ 'Contract completed successfully' | translate }}\r\n {{ 'Item received, payment transferred, pledges returned' | translate }}\r\n\r\n {{ 'Item not received' | translate }}\r\n {{ 'All pledges nullified' | translate }}\r\n\r\n {{ 'The buyer is offering to cancel the contract and return the pledge' | translate }}\r\n \r\n\r\n {{ 'The contract is being cancelled. Please wait for the pledge to be returned' | translate }}\r\n\r\n {{ 'Contract canceled' | translate }}\r\n {{ 'Pledges returned' | translate }}\r\n \r\n\r\n \r\n {{variablesService.height_app - currentContract.height}}/10\r\n {{(historyBlock.is_income ? '+' : '') + (historyBlock.sortAmount | intToMoney)}}\r\n \r\n\r\n
\r\n\r\n
\r\n \r\n \r\n \r\n\r\n \r\n \r\n \r\n \r\n\r\n \r\n \r\n \r\n \r\n \r\n\r\n \r\n \r\n \r\n \r\n\r\n
\r\n\r\n
\r\n\r\n
\r\n
\r\n
\r\n
\r\n
\r\n {{ 'PURCHASE.PROGRESS_NEW' | translate }}\r\n {{ 'PURCHASE.PROGRESS_WAIT' | translate }}\r\n {{ 'PURCHASE.PROGRESS_COMPLETE' | translate }}\r\n
\r\n
\r\n {{currentContract.expiration_time | contractTimeLeft: 0}}\r\n {{currentContract.cancel_expiration_time | contractTimeLeft: 2}}\r\n {{currentContract.expiration_time | contractTimeLeft: 1}}\r\n {{currentContract.cancel_expiration_time | contractTimeLeft: 1}}\r\n
\r\n
\r\n" + +/***/ }), + +/***/ "./src/app/purchase/purchase.component.scss": +/*!**************************************************!*\ + !*** ./src/app/purchase/purchase.component.scss ***! + \**************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = ":host {\n display: flex;\n flex-direction: column;\n width: 100%; }\n\n.head {\n flex: 0 0 auto;\n box-sizing: content-box;\n margin: -3rem -3rem 0; }\n\n.form-purchase {\n flex: 1 1 auto;\n margin: 1.5rem -3rem 0;\n padding: 0 3rem;\n overflow-y: overlay; }\n\n.form-purchase .input-blocks-row {\n display: flex; }\n\n.form-purchase .input-blocks-row .input-block {\n flex-basis: 50%; }\n\n.form-purchase .input-blocks-row .input-block:first-child {\n margin-right: 1.5rem; }\n\n.form-purchase .input-blocks-row .input-block:last-child {\n margin-left: 1.5rem; }\n\n.form-purchase .input-blocks-row .input-block .checkbox-block {\n display: flex; }\n\n.form-purchase .purchase-select {\n display: flex;\n align-items: center;\n background: transparent;\n border: none;\n font-size: 1.3rem;\n line-height: 1.3rem;\n margin: 1.5rem 0 0;\n padding: 0;\n width: 100%;\n max-width: 15rem;\n height: 1.3rem; }\n\n.form-purchase .purchase-select .arrow {\n margin-left: 1rem;\n width: 0.8rem;\n height: 0.8rem; }\n\n.form-purchase .purchase-select .arrow.down {\n -webkit-mask: url('arrow-down.svg') no-repeat center;\n mask: url('arrow-down.svg') no-repeat center; }\n\n.form-purchase .purchase-select .arrow.up {\n -webkit-mask: url('arrow-up.svg') no-repeat center;\n mask: url('arrow-up.svg') no-repeat center; }\n\n.form-purchase .additional-details {\n display: flex;\n margin-top: 1.5rem;\n padding: 0.5rem 0 2rem; }\n\n.form-purchase .additional-details > div {\n flex-basis: 25%; }\n\n.form-purchase .additional-details > div:first-child {\n padding-left: 1.5rem;\n padding-right: 1rem; }\n\n.form-purchase .additional-details > div:last-child {\n padding-left: 1rem;\n padding-right: 1.5rem; }\n\n.form-purchase .purchase-states {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n font-size: 1.2rem;\n line-height: 2.9rem; }\n\n.form-purchase .send-button {\n margin: 2.4rem 0;\n width: 100%;\n max-width: 15rem; }\n\n.form-purchase .purchase-buttons {\n display: flex;\n justify-content: space-between;\n margin: 2.4rem -0.5rem;\n width: calc(100% + 1rem); }\n\n.form-purchase .purchase-buttons button {\n flex: 0 1 33%;\n margin: 0 0.5rem; }\n\n.progress-bar-container {\n position: absolute;\n bottom: 0;\n left: 0;\n padding: 0 3rem;\n width: 100%;\n height: 3rem; }\n\n.progress-bar-container .progress-bar {\n position: absolute;\n top: -0.7rem;\n left: 0;\n margin: 0 3rem;\n width: calc(100% - 6rem);\n height: 0.7rem; }\n\n.progress-bar-container .progress-bar .progress-bar-full {\n height: 0.7rem; }\n\n.progress-bar-container .progress-labels {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 1.2rem;\n height: 100%; }\n\n.progress-bar-container .progress-labels span {\n flex: 1 0 0;\n text-align: center; }\n\n.progress-bar-container .progress-labels span:first-child {\n text-align: left; }\n\n.progress-bar-container .progress-labels span:last-child {\n text-align: right; }\n\n.progress-bar-container .progress-time {\n position: absolute;\n top: -3rem;\n left: 50%;\n -webkit-transform: translateX(-50%);\n transform: translateX(-50%);\n font-size: 1.2rem; }\n\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvcHVyY2hhc2UvRDpcXHphbm8vc3JjXFxhcHBcXHB1cmNoYXNlXFxwdXJjaGFzZS5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLGNBQWE7RUFDYix1QkFBc0I7RUFDdEIsWUFBVyxFQUNaOztBQUVEO0VBQ0UsZUFBYztFQUNkLHdCQUF1QjtFQUN2QixzQkFBcUIsRUFDdEI7O0FBRUQ7RUFDRSxlQUFjO0VBQ2QsdUJBQXNCO0VBQ3RCLGdCQUFlO0VBQ2Ysb0JBQW1CLEVBZ0dwQjs7QUFwR0Q7SUFPSSxjQUFhLEVBaUJkOztBQXhCSDtNQVVNLGdCQUFlLEVBYWhCOztBQXZCTDtRQWFRLHFCQUFvQixFQUNyQjs7QUFkUDtRQWlCUSxvQkFBbUIsRUFDcEI7O0FBbEJQO1FBcUJRLGNBQWEsRUFDZDs7QUF0QlA7SUEyQkksY0FBYTtJQUNiLG9CQUFtQjtJQUNuQix3QkFBdUI7SUFDdkIsYUFBWTtJQUNaLGtCQUFpQjtJQUNqQixvQkFBbUI7SUFDbkIsbUJBQWtCO0lBQ2xCLFdBQVU7SUFDVixZQUFXO0lBQ1gsaUJBQWdCO0lBQ2hCLGVBQWMsRUFlZjs7QUFwREg7TUF3Q00sa0JBQWlCO01BQ2pCLGNBQWE7TUFDYixlQUFjLEVBU2Y7O0FBbkRMO1FBNkNRLHFEQUE0RDtnQkFBNUQsNkNBQTRELEVBQzdEOztBQTlDUDtRQWlEUSxtREFBMEQ7Z0JBQTFELDJDQUEwRCxFQUMzRDs7QUFsRFA7SUF1REksY0FBYTtJQUNiLG1CQUFrQjtJQUNsQix1QkFBc0IsRUFldkI7O0FBeEVIO01BNERNLGdCQUFlLEVBV2hCOztBQXZFTDtRQStEUSxxQkFBb0I7UUFDcEIsb0JBQW1CLEVBQ3BCOztBQWpFUDtRQW9FUSxtQkFBa0I7UUFDbEIsc0JBQXFCLEVBQ3RCOztBQXRFUDtJQTJFSSxjQUFhO0lBQ2IsdUJBQXNCO0lBQ3RCLG9CQUFtQjtJQUNuQix3QkFBdUI7SUFDdkIsa0JBQWlCO0lBQ2pCLG9CQUFtQixFQUNwQjs7QUFqRkg7SUFvRkksaUJBQWdCO0lBQ2hCLFlBQVc7SUFDWCxpQkFBZ0IsRUFDakI7O0FBdkZIO0lBMEZJLGNBQWE7SUFDYiwrQkFBOEI7SUFDOUIsdUJBQXNCO0lBQ3RCLHlCQUF3QixFQU16Qjs7QUFuR0g7TUFnR00sY0FBYTtNQUNiLGlCQUFnQixFQUNqQjs7QUFJTDtFQUNFLG1CQUFrQjtFQUNsQixVQUFTO0VBQ1QsUUFBTztFQUNQLGdCQUFlO0VBQ2YsWUFBVztFQUNYLGFBQVksRUEyQ2I7O0FBakREO0lBU0ksbUJBQWtCO0lBQ2xCLGFBQVk7SUFDWixRQUFPO0lBQ1AsZUFBYztJQUNkLHlCQUF3QjtJQUN4QixlQUFjLEVBS2Y7O0FBbkJIO01BaUJNLGVBQWMsRUFDZjs7QUFsQkw7SUFzQkksY0FBYTtJQUNiLG9CQUFtQjtJQUNuQiwrQkFBOEI7SUFDOUIsa0JBQWlCO0lBQ2pCLGFBQVksRUFjYjs7QUF4Q0g7TUE2Qk0sWUFBVztNQUNYLG1CQUFrQixFQVNuQjs7QUF2Q0w7UUFpQ1EsaUJBQWdCLEVBQ2pCOztBQWxDUDtRQXFDUSxrQkFBaUIsRUFDbEI7O0FBdENQO0lBMkNJLG1CQUFrQjtJQUNsQixXQUFVO0lBQ1YsVUFBUztJQUNULG9DQUEyQjtZQUEzQiw0QkFBMkI7SUFDM0Isa0JBQWlCLEVBQ2xCIiwiZmlsZSI6InNyYy9hcHAvcHVyY2hhc2UvcHVyY2hhc2UuY29tcG9uZW50LnNjc3MiLCJzb3VyY2VzQ29udGVudCI6WyI6aG9zdCB7XHJcbiAgZGlzcGxheTogZmxleDtcclxuICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xyXG4gIHdpZHRoOiAxMDAlO1xyXG59XHJcblxyXG4uaGVhZCB7XHJcbiAgZmxleDogMCAwIGF1dG87XHJcbiAgYm94LXNpemluZzogY29udGVudC1ib3g7XHJcbiAgbWFyZ2luOiAtM3JlbSAtM3JlbSAwO1xyXG59XHJcblxyXG4uZm9ybS1wdXJjaGFzZSB7XHJcbiAgZmxleDogMSAxIGF1dG87XHJcbiAgbWFyZ2luOiAxLjVyZW0gLTNyZW0gMDtcclxuICBwYWRkaW5nOiAwIDNyZW07XHJcbiAgb3ZlcmZsb3cteTogb3ZlcmxheTtcclxuXHJcbiAgLmlucHV0LWJsb2Nrcy1yb3cge1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuXHJcbiAgICAuaW5wdXQtYmxvY2sge1xyXG4gICAgICBmbGV4LWJhc2lzOiA1MCU7XHJcblxyXG4gICAgICAmOmZpcnN0LWNoaWxkIHtcclxuICAgICAgICBtYXJnaW4tcmlnaHQ6IDEuNXJlbTtcclxuICAgICAgfVxyXG5cclxuICAgICAgJjpsYXN0LWNoaWxkIHtcclxuICAgICAgICBtYXJnaW4tbGVmdDogMS41cmVtO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAuY2hlY2tib3gtYmxvY2sge1xyXG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIC5wdXJjaGFzZS1zZWxlY3Qge1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAgICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudDtcclxuICAgIGJvcmRlcjogbm9uZTtcclxuICAgIGZvbnQtc2l6ZTogMS4zcmVtO1xyXG4gICAgbGluZS1oZWlnaHQ6IDEuM3JlbTtcclxuICAgIG1hcmdpbjogMS41cmVtIDAgMDtcclxuICAgIHBhZGRpbmc6IDA7XHJcbiAgICB3aWR0aDogMTAwJTtcclxuICAgIG1heC13aWR0aDogMTVyZW07XHJcbiAgICBoZWlnaHQ6IDEuM3JlbTtcclxuXHJcbiAgICAuYXJyb3cge1xyXG4gICAgICBtYXJnaW4tbGVmdDogMXJlbTtcclxuICAgICAgd2lkdGg6IDAuOHJlbTtcclxuICAgICAgaGVpZ2h0OiAwLjhyZW07XHJcblxyXG4gICAgICAmLmRvd24ge1xyXG4gICAgICAgIG1hc2s6IHVybCh+c3JjL2Fzc2V0cy9pY29ucy9hcnJvdy1kb3duLnN2Zykgbm8tcmVwZWF0IGNlbnRlcjtcclxuICAgICAgfVxyXG5cclxuICAgICAgJi51cCB7XHJcbiAgICAgICAgbWFzazogdXJsKH5zcmMvYXNzZXRzL2ljb25zL2Fycm93LXVwLnN2Zykgbm8tcmVwZWF0IGNlbnRlcjtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLmFkZGl0aW9uYWwtZGV0YWlscyB7XHJcbiAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgbWFyZ2luLXRvcDogMS41cmVtO1xyXG4gICAgcGFkZGluZzogMC41cmVtIDAgMnJlbTtcclxuXHJcbiAgICA+IGRpdiB7XHJcbiAgICAgIGZsZXgtYmFzaXM6IDI1JTtcclxuXHJcbiAgICAgICY6Zmlyc3QtY2hpbGQge1xyXG4gICAgICAgIHBhZGRpbmctbGVmdDogMS41cmVtO1xyXG4gICAgICAgIHBhZGRpbmctcmlnaHQ6IDFyZW07XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICY6bGFzdC1jaGlsZCB7XHJcbiAgICAgICAgcGFkZGluZy1sZWZ0OiAxcmVtO1xyXG4gICAgICAgIHBhZGRpbmctcmlnaHQ6IDEuNXJlbTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLnB1cmNoYXNlLXN0YXRlcyB7XHJcbiAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAgICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcclxuICAgIGZvbnQtc2l6ZTogMS4ycmVtO1xyXG4gICAgbGluZS1oZWlnaHQ6IDIuOXJlbTtcclxuICB9XHJcblxyXG4gIC5zZW5kLWJ1dHRvbiB7XHJcbiAgICBtYXJnaW46IDIuNHJlbSAwO1xyXG4gICAgd2lkdGg6IDEwMCU7XHJcbiAgICBtYXgtd2lkdGg6IDE1cmVtO1xyXG4gIH1cclxuXHJcbiAgLnB1cmNoYXNlLWJ1dHRvbnMge1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuICAgIGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjtcclxuICAgIG1hcmdpbjogMi40cmVtIC0wLjVyZW07XHJcbiAgICB3aWR0aDogY2FsYygxMDAlICsgMXJlbSk7XHJcblxyXG4gICAgYnV0dG9uIHtcclxuICAgICAgZmxleDogMCAxIDMzJTtcclxuICAgICAgbWFyZ2luOiAwIDAuNXJlbTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbi5wcm9ncmVzcy1iYXItY29udGFpbmVyIHtcclxuICBwb3NpdGlvbjogYWJzb2x1dGU7XHJcbiAgYm90dG9tOiAwO1xyXG4gIGxlZnQ6IDA7XHJcbiAgcGFkZGluZzogMCAzcmVtO1xyXG4gIHdpZHRoOiAxMDAlO1xyXG4gIGhlaWdodDogM3JlbTtcclxuXHJcbiAgLnByb2dyZXNzLWJhciB7XHJcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XHJcbiAgICB0b3A6IC0wLjdyZW07XHJcbiAgICBsZWZ0OiAwO1xyXG4gICAgbWFyZ2luOiAwIDNyZW07XHJcbiAgICB3aWR0aDogY2FsYygxMDAlIC0gNnJlbSk7XHJcbiAgICBoZWlnaHQ6IDAuN3JlbTtcclxuXHJcbiAgICAucHJvZ3Jlc3MtYmFyLWZ1bGwge1xyXG4gICAgICBoZWlnaHQ6IDAuN3JlbTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC5wcm9ncmVzcy1sYWJlbHMge1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAgICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XHJcbiAgICBmb250LXNpemU6IDEuMnJlbTtcclxuICAgIGhlaWdodDogMTAwJTtcclxuXHJcbiAgICBzcGFuIHtcclxuICAgICAgZmxleDogMSAwIDA7XHJcbiAgICAgIHRleHQtYWxpZ246IGNlbnRlcjtcclxuXHJcbiAgICAgICY6Zmlyc3QtY2hpbGQge1xyXG4gICAgICAgIHRleHQtYWxpZ246IGxlZnQ7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICY6bGFzdC1jaGlsZCB7XHJcbiAgICAgICAgdGV4dC1hbGlnbjogcmlnaHQ7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIC5wcm9ncmVzcy10aW1lIHtcclxuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcclxuICAgIHRvcDogLTNyZW07XHJcbiAgICBsZWZ0OiA1MCU7XHJcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZVgoLTUwJSk7XHJcbiAgICBmb250LXNpemU6IDEuMnJlbTtcclxuICB9XHJcbn1cclxuIl19 */" + +/***/ }), + +/***/ "./src/app/purchase/purchase.component.ts": +/*!************************************************!*\ + !*** ./src/app/purchase/purchase.component.ts ***! + \************************************************/ +/*! exports provided: PurchaseComponent */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PurchaseComponent", function() { return PurchaseComponent; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/router */ "./node_modules/@angular/router/fesm5/router.js"); +/* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/forms */ "./node_modules/@angular/forms/fesm5/forms.js"); +/* harmony import */ var _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../_helpers/services/backend.service */ "./src/app/_helpers/services/backend.service.ts"); +/* harmony import */ var _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../_helpers/services/variables.service */ "./src/app/_helpers/services/variables.service.ts"); +/* harmony import */ var _angular_common__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @angular/common */ "./node_modules/@angular/common/fesm5/common.js"); +/* harmony import */ var _helpers_pipes_int_to_money_pipe__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../_helpers/pipes/int-to-money.pipe */ "./src/app/_helpers/pipes/int-to-money.pipe.ts"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + + + + + + + +var PurchaseComponent = /** @class */ (function () { + function PurchaseComponent(route, backend, variablesService, ngZone, location, intToMoneyPipe) { + this.route = route; + this.backend = backend; + this.variablesService = variablesService; + this.ngZone = ngZone; + this.location = location; + this.intToMoneyPipe = intToMoneyPipe; + this.newPurchase = false; + this.purchaseForm = new _angular_forms__WEBPACK_IMPORTED_MODULE_2__["FormGroup"]({ + description: new _angular_forms__WEBPACK_IMPORTED_MODULE_2__["FormControl"]('', _angular_forms__WEBPACK_IMPORTED_MODULE_2__["Validators"].required), + seller: new _angular_forms__WEBPACK_IMPORTED_MODULE_2__["FormControl"]('', _angular_forms__WEBPACK_IMPORTED_MODULE_2__["Validators"].required), + amount: new _angular_forms__WEBPACK_IMPORTED_MODULE_2__["FormControl"](null, _angular_forms__WEBPACK_IMPORTED_MODULE_2__["Validators"].required), + yourDeposit: new _angular_forms__WEBPACK_IMPORTED_MODULE_2__["FormControl"](null, _angular_forms__WEBPACK_IMPORTED_MODULE_2__["Validators"].required), + sellerDeposit: new _angular_forms__WEBPACK_IMPORTED_MODULE_2__["FormControl"](null, _angular_forms__WEBPACK_IMPORTED_MODULE_2__["Validators"].required), + sameAmount: new _angular_forms__WEBPACK_IMPORTED_MODULE_2__["FormControl"](false), + comment: new _angular_forms__WEBPACK_IMPORTED_MODULE_2__["FormControl"](''), + fee: new _angular_forms__WEBPACK_IMPORTED_MODULE_2__["FormControl"]('0.01'), + payment: new _angular_forms__WEBPACK_IMPORTED_MODULE_2__["FormControl"]('') + }); + this.additionalOptions = false; + this.currentContract = null; + } + PurchaseComponent.prototype.checkAndChangeHistory = function () { + var _this = this; + if (this.currentContract.state === 201) { + this.historyBlock = this.variablesService.currentWallet.history.find(function (item) { return item.tx_type === 8 && item.contract[0].contract_id === _this.currentContract.contract_id && item.contract[0].is_a === _this.currentContract.is_a; }); + } + else if (this.currentContract.state === 601) { + this.historyBlock = this.variablesService.currentWallet.history.find(function (item) { return item.tx_type === 12 && item.contract[0].contract_id === _this.currentContract.contract_id && item.contract[0].is_a === _this.currentContract.is_a; }); + } + }; + PurchaseComponent.prototype.ngOnInit = function () { + var _this = this; + this.parentRouting = this.route.parent.params.subscribe(function (params) { + _this.currentWalletId = params['id']; + }); + this.route.params.subscribe(function (params) { + if (params.hasOwnProperty('id')) { + _this.currentContract = _this.variablesService.currentWallet.getContract(params['id']); + _this.purchaseForm.setValue({ + description: _this.currentContract.private_detailes.t, + seller: _this.currentContract.private_detailes.b_addr, + amount: _this.intToMoneyPipe.transform(_this.currentContract.private_detailes.to_pay), + yourDeposit: _this.intToMoneyPipe.transform(_this.currentContract.private_detailes.a_pledge), + sellerDeposit: _this.intToMoneyPipe.transform(_this.currentContract.private_detailes.b_pledge), + sameAmount: false, + comment: _this.currentContract.private_detailes.c, + fee: '0.01', + payment: _this.currentContract.payment_id + }); + _this.newPurchase = false; + // todo original code watch height_v + if (_this.currentContract.state === 201 && _this.currentContract.height !== 0 && (_this.variablesService.height_app - _this.currentContract.height) >= 10) { + _this.currentContract.state = 2; + _this.currentContract.is_new = true; + _this.variablesService.currentWallet.recountNewContracts(); + } + else if (_this.currentContract.state === 601 && _this.currentContract.height !== 0 && (_this.variablesService.height_app - _this.currentContract.height) >= 10) { + _this.currentContract.state = 6; + _this.currentContract.is_new = true; + _this.variablesService.currentWallet.recountNewContracts(); + } + if (_this.currentContract.is_new) { + if (_this.currentContract.is_a && _this.currentContract.state === 2) { + _this.currentContract.state = 120; + } + if (_this.currentContract.state === 130 && _this.currentContract.cancel_expiration_time !== 0 && _this.currentContract.cancel_expiration_time < _this.variablesService.exp_med_ts) { + _this.currentContract.state = 2; + } + _this.variablesService.settings.viewedContracts = (_this.variablesService.settings.viewedContracts) ? _this.variablesService.settings.viewedContracts : []; + var findViewedCont = false; + for (var j = 0; j < _this.variablesService.settings.viewedContracts.length; j++) { + if (_this.variablesService.settings.viewedContracts[j].contract_id === _this.currentContract.contract_id && _this.variablesService.settings.viewedContracts[j].is_a === _this.currentContract.is_a) { + _this.variablesService.settings.viewedContracts[j].state = _this.currentContract.state; + findViewedCont = true; + break; + } + } + if (!findViewedCont) { + _this.variablesService.settings.viewedContracts.push({ + contract_id: _this.currentContract.contract_id, + is_a: _this.currentContract.is_a, + state: _this.currentContract.state + }); + } + _this.currentContract.is_new = false; + // todo need remove timeout + setTimeout(function () { + _this.variablesService.currentWallet.recountNewContracts(); + }, 0); + _this.checkAndChangeHistory(); + } + } + else { + _this.newPurchase = true; + } + }); + }; + PurchaseComponent.prototype.toggleOptions = function () { + this.additionalOptions = !this.additionalOptions; + }; + PurchaseComponent.prototype.getProgressBarWidth = function () { + if (this.newPurchase) { + return '9rem'; + } + else { + return '50%'; + } + }; + PurchaseComponent.prototype.sameAmountChange = function () { + if (this.purchaseForm.get('sameAmount').value) { + this.purchaseForm.get('sellerDeposit').clearValidators(); + this.purchaseForm.get('sellerDeposit').updateValueAndValidity(); + } + else { + this.purchaseForm.get('sellerDeposit').setValidators([_angular_forms__WEBPACK_IMPORTED_MODULE_2__["Validators"].required]); + this.purchaseForm.get('sellerDeposit').updateValueAndValidity(); + } + }; + PurchaseComponent.prototype.checkAddressValidation = function () { + var _this = this; + if (this.purchaseForm.get('seller').value) { + this.backend.validateAddress(this.purchaseForm.get('seller').value, function (valid_status) { + if (valid_status === false) { + _this.ngZone.run(function () { + _this.purchaseForm.get('seller').setErrors({ address_not_valid: true }); + }); + } + }); + } + }; + PurchaseComponent.prototype.createPurchase = function () { + var _this = this; + if (this.purchaseForm.valid) { + if (this.purchaseForm.get('sameAmount').value) { + this.purchaseForm.get('sellerDeposit').setValue(this.purchaseForm.get('amount').value); + } + this.backend.createProposal(this.variablesService.currentWallet.wallet_id, this.purchaseForm.get('description').value, this.purchaseForm.get('comment').value, this.variablesService.currentWallet.address, this.purchaseForm.get('seller').value, this.purchaseForm.get('amount').value, this.purchaseForm.get('yourDeposit').value, this.purchaseForm.get('sellerDeposit').value, 12, this.purchaseForm.get('payment').value, function () { + _this.back(); + }); + } + }; + PurchaseComponent.prototype.back = function () { + this.location.back(); + }; + PurchaseComponent.prototype.acceptState = function () { + var _this = this; + this.backend.acceptProposal(this.currentWalletId, this.currentContract.contract_id, function (accept_status) { + if (accept_status) { + alert('You have accepted the contract proposal. Please wait for the pledges to be made'); + _this.back(); + } + }); + }; + PurchaseComponent.prototype.ignoredContract = function () { + this.variablesService.settings.notViewedContracts = (this.variablesService.settings.notViewedContracts) ? this.variablesService.settings.notViewedContracts : []; + var findViewedCont = false; + for (var j = 0; j < this.variablesService.settings.notViewedContracts.length; j++) { + if (this.variablesService.settings.notViewedContracts[j].contract_id === this.currentContract.contract_id && this.variablesService.settings.notViewedContracts[j].is_a === this.currentContract.is_a) { + this.variablesService.settings.notViewedContracts[j].state = 110; + this.variablesService.settings.notViewedContracts[j].time = this.currentContract.expiration_time; + findViewedCont = true; + break; + } + } + if (!findViewedCont) { + this.variablesService.settings.notViewedContracts.push({ + contract_id: this.currentContract.contract_id, + is_a: this.currentContract.is_a, + state: 110, + time: this.currentContract.expiration_time + }); + } + this.currentContract.is_new = true; + this.currentContract.state = 110; + this.currentContract.time = this.currentContract.expiration_time; + this.variablesService.currentWallet.recountNewContracts(); + alert('You have ignored the contract proposal'); + this.back(); + }; + PurchaseComponent.prototype.productNotGot = function () { + var _this = this; + this.backend.releaseProposal(this.currentWalletId, this.currentContract.contract_id, 'REL_B', function (release_status) { + if (release_status) { + alert('The pledges have been nullified.'); + _this.back(); + } + }); + }; + PurchaseComponent.prototype.dealsDetailsFinish = function () { + var _this = this; + this.backend.releaseProposal(this.currentWalletId, this.currentContract.contract_id, 'REL_N', function (release_status) { + if (release_status) { + alert('The contract is complete. The payment has been sent.'); + _this.back(); + } + }); + }; + PurchaseComponent.prototype.dealsDetailsCancel = function () { + var _this = this; + this.backend.requestCancelContract(this.currentWalletId, this.currentContract.contract_id, 12, function (cancel_status) { + if (cancel_status) { + alert('Proposal to cancel contract sent to seller'); + _this.back(); + } + }); + }; + PurchaseComponent.prototype.dealsDetailsDontCanceling = function () { + this.variablesService.settings.notViewedContracts = this.variablesService.settings.notViewedContracts ? this.variablesService.settings.notViewedContracts : []; + var findViewedCont = false; + for (var j = 0; j < this.variablesService.settings.notViewedContracts.length; j++) { + if (this.variablesService.settings.notViewedContracts[j].contract_id === this.currentContract.contract_id && this.variablesService.settings.notViewedContracts[j].is_a === this.currentContract.is_a) { + this.variablesService.settings.notViewedContracts[j].state = 130; + this.variablesService.settings.notViewedContracts[j].time = this.currentContract.cancel_expiration_time; + findViewedCont = true; + break; + } + } + if (!findViewedCont) { + this.variablesService.settings.notViewedContracts.push({ + contract_id: this.currentContract.contract_id, + is_a: this.currentContract.is_a, + state: 130, + time: this.currentContract.cancel_expiration_time + }); + } + this.currentContract.is_new = true; + this.currentContract.state = 130; + this.currentContract.time = this.currentContract.cancel_expiration_time; + this.variablesService.currentWallet.recountNewContracts(); + alert('You have ignored the proposal to cancel the contract'); + this.back(); + }; + PurchaseComponent.prototype.dealsDetailsSellerCancel = function () { + var _this = this; + this.backend.acceptCancelContract(this.currentWalletId, this.currentContract.contract_id, function (accept_status) { + if (accept_status) { + alert('The contract is being cancelled. Please wait for the pledge to be returned'); + _this.back(); + } + }); + }; + PurchaseComponent.prototype.ngOnDestroy = function () { + this.parentRouting.unsubscribe(); + }; + PurchaseComponent = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Component"])({ + selector: 'app-purchase', + template: __webpack_require__(/*! ./purchase.component.html */ "./src/app/purchase/purchase.component.html"), + styles: [__webpack_require__(/*! ./purchase.component.scss */ "./src/app/purchase/purchase.component.scss")] + }), + __metadata("design:paramtypes", [_angular_router__WEBPACK_IMPORTED_MODULE_1__["ActivatedRoute"], + _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_3__["BackendService"], + _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_4__["VariablesService"], + _angular_core__WEBPACK_IMPORTED_MODULE_0__["NgZone"], + _angular_common__WEBPACK_IMPORTED_MODULE_5__["Location"], + _helpers_pipes_int_to_money_pipe__WEBPACK_IMPORTED_MODULE_6__["IntToMoneyPipe"]]) + ], PurchaseComponent); + return PurchaseComponent; +}()); + + + +/***/ }), + +/***/ "./src/app/receive/receive.component.html": +/*!************************************************!*\ + !*** ./src/app/receive/receive.component.html ***! + \************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = "
\r\n \"qr-code\"\r\n
\r\n
{{variablesService.currentWallet.address}}
\r\n \r\n
\r\n
\r\n" + +/***/ }), + +/***/ "./src/app/receive/receive.component.scss": +/*!************************************************!*\ + !*** ./src/app/receive/receive.component.scss ***! + \************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = ":host {\n width: 100%; }\n\n.wrap-qr {\n display: flex;\n flex-direction: column;\n align-items: center; }\n\n.wrap-qr img {\n margin: 4rem 0; }\n\n.wrap-qr .wrap-address {\n display: flex;\n align-items: center;\n font-size: 1.4rem;\n line-height: 2.7rem; }\n\n.wrap-qr .wrap-address .btn-copy-address {\n -webkit-mask: url('copy.svg') no-repeat center;\n mask: url('copy.svg') no-repeat center;\n margin-left: 1.2rem;\n width: 1.7rem;\n height: 1.7rem; }\n\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvcmVjZWl2ZS9EOlxcemFuby9zcmNcXGFwcFxccmVjZWl2ZVxccmVjZWl2ZS5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLFlBQVcsRUFDWjs7QUFFRDtFQUNFLGNBQWE7RUFDYix1QkFBc0I7RUFDdEIsb0JBQW1CLEVBbUJwQjs7QUF0QkQ7SUFNSSxlQUFjLEVBQ2Y7O0FBUEg7SUFVSSxjQUFhO0lBQ2Isb0JBQW1CO0lBQ25CLGtCQUFpQjtJQUNqQixvQkFBbUIsRUFRcEI7O0FBckJIO01BZ0JNLCtDQUF1RDtjQUF2RCx1Q0FBdUQ7TUFDdkQsb0JBQW1CO01BQ25CLGNBQWE7TUFDYixlQUFjLEVBQ2YiLCJmaWxlIjoic3JjL2FwcC9yZWNlaXZlL3JlY2VpdmUuY29tcG9uZW50LnNjc3MiLCJzb3VyY2VzQ29udGVudCI6WyI6aG9zdCB7XHJcbiAgd2lkdGg6IDEwMCU7XHJcbn1cclxuXHJcbi53cmFwLXFyIHtcclxuICBkaXNwbGF5OiBmbGV4O1xyXG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XHJcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuXHJcbiAgaW1nIHtcclxuICAgIG1hcmdpbjogNHJlbSAwO1xyXG4gIH1cclxuXHJcbiAgLndyYXAtYWRkcmVzcyB7XHJcbiAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuICAgIGZvbnQtc2l6ZTogMS40cmVtO1xyXG4gICAgbGluZS1oZWlnaHQ6IDIuN3JlbTtcclxuXHJcbiAgICAuYnRuLWNvcHktYWRkcmVzcyB7XHJcbiAgICAgIG1hc2s6IHVybCguLi8uLi9hc3NldHMvaWNvbnMvY29weS5zdmcpIG5vLXJlcGVhdCBjZW50ZXI7XHJcbiAgICAgIG1hcmdpbi1sZWZ0OiAxLjJyZW07XHJcbiAgICAgIHdpZHRoOiAxLjdyZW07XHJcbiAgICAgIGhlaWdodDogMS43cmVtO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG4iXX0= */" + +/***/ }), + +/***/ "./src/app/receive/receive.component.ts": +/*!**********************************************!*\ + !*** ./src/app/receive/receive.component.ts ***! + \**********************************************/ +/*! exports provided: ReceiveComponent */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ReceiveComponent", function() { return ReceiveComponent; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var qrcode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! qrcode */ "./node_modules/qrcode/lib/browser.js"); +/* harmony import */ var qrcode__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(qrcode__WEBPACK_IMPORTED_MODULE_1__); +/* harmony import */ var _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../_helpers/services/backend.service */ "./src/app/_helpers/services/backend.service.ts"); +/* harmony import */ var _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../_helpers/services/variables.service */ "./src/app/_helpers/services/variables.service.ts"); +/* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/router */ "./node_modules/@angular/router/fesm5/router.js"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + + + + + +var ReceiveComponent = /** @class */ (function () { + function ReceiveComponent(route, backend, variablesService) { + this.route = route; + this.backend = backend; + this.variablesService = variablesService; + } + ReceiveComponent.prototype.ngOnInit = function () { + var _this = this; + this.parentRouting = this.route.parent.params.subscribe(function () { + qrcode__WEBPACK_IMPORTED_MODULE_1___default.a.toDataURL(_this.variablesService.currentWallet.address, { + width: 106, + height: 106 + }).then(function (url) { + _this.qrImageSrc = url; + }).catch(function (err) { + console.error(err); + }); + }); + }; + ReceiveComponent.prototype.copyAddress = function () { + this.backend.setClipboard(this.variablesService.currentWallet.address); + }; + ReceiveComponent.prototype.ngOnDestroy = function () { + this.parentRouting.unsubscribe(); + }; + ReceiveComponent = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Component"])({ + selector: 'app-receive', + template: __webpack_require__(/*! ./receive.component.html */ "./src/app/receive/receive.component.html"), + styles: [__webpack_require__(/*! ./receive.component.scss */ "./src/app/receive/receive.component.scss")] + }), + __metadata("design:paramtypes", [_angular_router__WEBPACK_IMPORTED_MODULE_4__["ActivatedRoute"], + _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_2__["BackendService"], + _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_3__["VariablesService"]]) + ], ReceiveComponent); + return ReceiveComponent; +}()); + + + +/***/ }), + +/***/ "./src/app/restore-wallet/restore-wallet.component.html": +/*!**************************************************************!*\ + !*** ./src/app/restore-wallet/restore-wallet.component.html ***! + \**************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = "
\r\n
\r\n
\r\n {{ 'BREADCRUMBS.ADD_WALLET' | translate }}\r\n {{ 'BREADCRUMBS.RESTORE_WALLET' | translate }}\r\n
\r\n \r\n \r\n {{ 'COMMON.BACK' | translate }}\r\n \r\n
\r\n\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n Name is required.\r\n
\r\n
\r\n Name is duplicate.\r\n
\r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n Confirm password not match.\r\n
\r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n Key is required.\r\n
\r\n
\r\n Key not valid.\r\n
\r\n
\r\n\r\n
\r\n \r\n \r\n \r\n
\r\n
\r\n\r\n
\r\n" + +/***/ }), + +/***/ "./src/app/restore-wallet/restore-wallet.component.scss": +/*!**************************************************************!*\ + !*** ./src/app/restore-wallet/restore-wallet.component.scss ***! + \**************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = ".form-restore {\n margin: 2.4rem 0;\n width: 100%; }\n .form-restore .input-block.half-block, .form-restore .error-block.half-block {\n width: 50%; }\n .form-restore .wrap-buttons {\n display: flex;\n margin: 2.5rem -0.7rem;\n width: 50%; }\n .form-restore .wrap-buttons button {\n margin: 0 0.7rem; }\n .form-restore .wrap-buttons button.transparent-button {\n flex-basis: 50%; }\n .form-restore .wrap-buttons button.select-button {\n flex-basis: 60%; }\n .form-restore .wrap-buttons button.create-button {\n flex: 1 1 50%; }\n\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvcmVzdG9yZS13YWxsZXQvRDpcXHphbm8vc3JjXFxhcHBcXHJlc3RvcmUtd2FsbGV0XFxyZXN0b3JlLXdhbGxldC5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLGlCQUFnQjtFQUNoQixZQUFXLEVBOEJaO0VBaENEO0lBT00sV0FBVSxFQUNYO0VBUkw7SUFZSSxjQUFhO0lBQ2IsdUJBQXNCO0lBQ3RCLFdBQVUsRUFpQlg7RUEvQkg7TUFpQk0saUJBQWdCLEVBYWpCO0VBOUJMO1FBb0JRLGdCQUFlLEVBQ2hCO0VBckJQO1FBd0JRLGdCQUFlLEVBQ2hCO0VBekJQO1FBNEJRLGNBQWEsRUFDZCIsImZpbGUiOiJzcmMvYXBwL3Jlc3RvcmUtd2FsbGV0L3Jlc3RvcmUtd2FsbGV0LmNvbXBvbmVudC5zY3NzIiwic291cmNlc0NvbnRlbnQiOlsiLmZvcm0tcmVzdG9yZSB7XHJcbiAgbWFyZ2luOiAyLjRyZW0gMDtcclxuICB3aWR0aDogMTAwJTtcclxuXHJcbiAgLmlucHV0LWJsb2NrLCAuZXJyb3ItYmxvY2sge1xyXG5cclxuICAgICYuaGFsZi1ibG9jayB7XHJcbiAgICAgIHdpZHRoOiA1MCU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAud3JhcC1idXR0b25zIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBtYXJnaW46IDIuNXJlbSAtMC43cmVtO1xyXG4gICAgd2lkdGg6IDUwJTtcclxuXHJcbiAgICBidXR0b24ge1xyXG4gICAgICBtYXJnaW46IDAgMC43cmVtO1xyXG5cclxuICAgICAgJi50cmFuc3BhcmVudC1idXR0b24ge1xyXG4gICAgICAgIGZsZXgtYmFzaXM6IDUwJTtcclxuICAgICAgfVxyXG5cclxuICAgICAgJi5zZWxlY3QtYnV0dG9uIHtcclxuICAgICAgICBmbGV4LWJhc2lzOiA2MCU7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICYuY3JlYXRlLWJ1dHRvbiB7XHJcbiAgICAgICAgZmxleDogMSAxIDUwJTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxufVxyXG4iXX0= */" + +/***/ }), + +/***/ "./src/app/restore-wallet/restore-wallet.component.ts": +/*!************************************************************!*\ + !*** ./src/app/restore-wallet/restore-wallet.component.ts ***! + \************************************************************/ +/*! exports provided: RestoreWalletComponent */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RestoreWalletComponent", function() { return RestoreWalletComponent; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/forms */ "./node_modules/@angular/forms/fesm5/forms.js"); +/* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/router */ "./node_modules/@angular/router/fesm5/router.js"); +/* harmony import */ var _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../_helpers/services/backend.service */ "./src/app/_helpers/services/backend.service.ts"); +/* harmony import */ var _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../_helpers/services/variables.service */ "./src/app/_helpers/services/variables.service.ts"); +/* harmony import */ var _helpers_models_wallet_model__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../_helpers/models/wallet.model */ "./src/app/_helpers/models/wallet.model.ts"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + + + + + + +var RestoreWalletComponent = /** @class */ (function () { + function RestoreWalletComponent(router, backend, variablesService, ngZone) { + var _this = this; + this.router = router; + this.backend = backend; + this.variablesService = variablesService; + this.ngZone = ngZone; + this.restoreForm = new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormGroup"]({ + name: new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormControl"]('', [_angular_forms__WEBPACK_IMPORTED_MODULE_1__["Validators"].required, function (g) { + for (var i = 0; i < _this.variablesService.wallets.length; i++) { + if (g.value === _this.variablesService.wallets[i].name) { + return { 'duplicate': true }; + } + } + return null; + }]), + key: new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormControl"]('', _angular_forms__WEBPACK_IMPORTED_MODULE_1__["Validators"].required), + password: new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormControl"](''), + confirm: new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormControl"]('') + }, function (g) { + return g.get('password').value === g.get('confirm').value ? null : { 'confirm_mismatch': true }; + }); + this.wallet = { + id: '' + }; + this.walletSaved = false; + } + RestoreWalletComponent.prototype.ngOnInit = function () { + }; + RestoreWalletComponent.prototype.createWallet = function () { + this.router.navigate(['/seed-phrase'], { queryParams: { wallet_id: this.wallet.id } }); + }; + RestoreWalletComponent.prototype.saveWallet = function () { + var _this = this; + if (this.restoreForm.valid) { + this.backend.isValidRestoreWalletText(this.restoreForm.get('key').value, function (valid_status, valid_data) { + if (valid_data === 'FALSE') { + _this.ngZone.run(function () { + _this.restoreForm.get('key').setErrors({ key_not_valid: true }); + }); + } + else { + _this.backend.saveFileDialog('Save the wallet file.', '*', _this.variablesService.settings.default_path, function (save_status, save_data) { + if (save_status) { + _this.variablesService.settings.default_path = save_data.path.substr(0, save_data.path.lastIndexOf('/')); + _this.backend.restoreWallet(save_data.path, _this.restoreForm.get('password').value, _this.restoreForm.get('key').value, function (restore_status, restore_data) { + if (restore_status) { + _this.wallet.id = restore_data.wallet_id; + _this.variablesService.opening_wallet = new _helpers_models_wallet_model__WEBPACK_IMPORTED_MODULE_5__["Wallet"](restore_data.wallet_id, _this.restoreForm.get('name').value, _this.restoreForm.get('password').value, restore_data['wi'].path, restore_data['wi'].address, restore_data['wi'].balance, restore_data['wi'].unlocked_balance, restore_data['wi'].mined_total, restore_data['wi'].tracking_hey); + if (restore_data.recent_history && restore_data.recent_history.history) { + _this.variablesService.opening_wallet.prepareHistory(restore_data.recent_history.history); + } + _this.backend.getContracts(_this.variablesService.opening_wallet.wallet_id, function (contracts_status, contracts_data) { + if (contracts_status && contracts_data.hasOwnProperty('contracts')) { + _this.ngZone.run(function () { + _this.variablesService.opening_wallet.prepareContractsAfterOpen(contracts_data.contracts, _this.variablesService.exp_med_ts, _this.variablesService.height_app, _this.variablesService.settings.viewedContracts, _this.variablesService.settings.notViewedContracts); + }); + } + }); + _this.ngZone.run(function () { + _this.walletSaved = true; + }); + } + else { + alert('SAFES.NOT_CORRECT_FILE_OR_PASSWORD'); + } + }); + } + }); + } + }); + } + }; + RestoreWalletComponent = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Component"])({ + selector: 'app-restore-wallet', + template: __webpack_require__(/*! ./restore-wallet.component.html */ "./src/app/restore-wallet/restore-wallet.component.html"), + styles: [__webpack_require__(/*! ./restore-wallet.component.scss */ "./src/app/restore-wallet/restore-wallet.component.scss")] + }), + __metadata("design:paramtypes", [_angular_router__WEBPACK_IMPORTED_MODULE_2__["Router"], + _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_3__["BackendService"], + _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_4__["VariablesService"], + _angular_core__WEBPACK_IMPORTED_MODULE_0__["NgZone"]]) + ], RestoreWalletComponent); + return RestoreWalletComponent; +}()); + + + +/***/ }), + +/***/ "./src/app/seed-phrase/seed-phrase.component.html": +/*!********************************************************!*\ + !*** ./src/app/seed-phrase/seed-phrase.component.html ***! + \********************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = "
\r\n
\r\n
\r\n {{ 'BREADCRUMBS.ADD_WALLET' | translate }}\r\n {{ 'BREADCRUMBS.SAVE_PHRASE' | translate }}\r\n
\r\n \r\n \r\n {{ 'COMMON.BACK' | translate }}\r\n \r\n
\r\n\r\n

{{ 'SEED_PHRASE.TITLE' | translate }}

\r\n\r\n
\r\n \r\n
{{(index + 1) + '. ' + word}}
\r\n
\r\n
\r\n\r\n \r\n
\r\n" + +/***/ }), + +/***/ "./src/app/seed-phrase/seed-phrase.component.scss": +/*!********************************************************!*\ + !*** ./src/app/seed-phrase/seed-phrase.component.scss ***! + \********************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = ".seed-phrase-title {\n line-height: 2.2rem;\n padding: 2.2rem 0; }\n\n.seed-phrase-content {\n display: flex;\n flex-direction: column;\n flex-wrap: wrap;\n padding: 1.4rem;\n width: 100%;\n height: 12rem; }\n\n.seed-phrase-content .word {\n line-height: 2.2rem;\n max-width: 13rem; }\n\nbutton {\n margin: 2.8rem 0;\n width: 25%;\n min-width: 1.5rem; }\n\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvc2VlZC1waHJhc2UvRDpcXHphbm8vc3JjXFxhcHBcXHNlZWQtcGhyYXNlXFxzZWVkLXBocmFzZS5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLG9CQUFtQjtFQUNuQixrQkFBaUIsRUFDbEI7O0FBRUQ7RUFDRSxjQUFhO0VBQ2IsdUJBQXNCO0VBQ3RCLGdCQUFlO0VBQ2YsZ0JBQWU7RUFDZixZQUFXO0VBQ1gsY0FBYSxFQU1kOztBQVpEO0lBU0ksb0JBQW1CO0lBQ25CLGlCQUFnQixFQUNqQjs7QUFHSDtFQUNFLGlCQUFnQjtFQUNoQixXQUFVO0VBQ1Ysa0JBQWlCLEVBQ2xCIiwiZmlsZSI6InNyYy9hcHAvc2VlZC1waHJhc2Uvc2VlZC1waHJhc2UuY29tcG9uZW50LnNjc3MiLCJzb3VyY2VzQ29udGVudCI6WyIuc2VlZC1waHJhc2UtdGl0bGUge1xyXG4gIGxpbmUtaGVpZ2h0OiAyLjJyZW07XHJcbiAgcGFkZGluZzogMi4ycmVtIDA7XHJcbn1cclxuXHJcbi5zZWVkLXBocmFzZS1jb250ZW50IHtcclxuICBkaXNwbGF5OiBmbGV4O1xyXG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XHJcbiAgZmxleC13cmFwOiB3cmFwO1xyXG4gIHBhZGRpbmc6IDEuNHJlbTtcclxuICB3aWR0aDogMTAwJTtcclxuICBoZWlnaHQ6IDEycmVtO1xyXG5cclxuICAud29yZCB7XHJcbiAgICBsaW5lLWhlaWdodDogMi4ycmVtO1xyXG4gICAgbWF4LXdpZHRoOiAxM3JlbTtcclxuICB9XHJcbn1cclxuXHJcbmJ1dHRvbiB7XHJcbiAgbWFyZ2luOiAyLjhyZW0gMDtcclxuICB3aWR0aDogMjUlO1xyXG4gIG1pbi13aWR0aDogMS41cmVtO1xyXG59XHJcbiJdfQ== */" + +/***/ }), + +/***/ "./src/app/seed-phrase/seed-phrase.component.ts": +/*!******************************************************!*\ + !*** ./src/app/seed-phrase/seed-phrase.component.ts ***! + \******************************************************/ +/*! exports provided: SeedPhraseComponent */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SeedPhraseComponent", function() { return SeedPhraseComponent; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../_helpers/services/backend.service */ "./src/app/_helpers/services/backend.service.ts"); +/* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/router */ "./node_modules/@angular/router/fesm5/router.js"); +/* harmony import */ var _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../_helpers/services/variables.service */ "./src/app/_helpers/services/variables.service.ts"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + + + + +var SeedPhraseComponent = /** @class */ (function () { + function SeedPhraseComponent(route, router, backend, variablesService, ngZone) { + this.route = route; + this.router = router; + this.backend = backend; + this.variablesService = variablesService; + this.ngZone = ngZone; + this.seedPhrase = ''; + } + SeedPhraseComponent.prototype.ngOnInit = function () { + var _this = this; + this.route.queryParams.subscribe(function (params) { + if (params.wallet_id) { + _this.wallet_id = params.wallet_id; + _this.backend.getSmartSafeInfo(params.wallet_id, function (status, data) { + if (data.hasOwnProperty('restore_key')) { + _this.ngZone.run(function () { + _this.seedPhrase = data['restore_key'].trim(); + }); + } + }); + } + }); + }; + SeedPhraseComponent.prototype.runWallet = function () { + var _this = this; + var exists = false; + this.variablesService.wallets.forEach(function (wallet) { + if (wallet.address === _this.variablesService.opening_wallet.address) { + exists = true; + } + }); + if (!exists) { + this.backend.runWallet(this.wallet_id, function (run_status, run_data) { + if (run_status) { + _this.variablesService.wallets.push(_this.variablesService.opening_wallet); + _this.backend.storeSecureAppData(function (status, data) { + console.log('Store App Data', status, data); + }); + _this.ngZone.run(function () { + _this.router.navigate(['/wallet/' + _this.wallet_id]); + }); + } + else { + console.log(run_data['error_code']); + } + // $rootScope.reloadCounters(); + // $rootScope.$broadcast('NEED_REFRESH_HISTORY'); + // $rootScope.saveSecureData(); + }); + } + else { + this.variablesService.opening_wallet = null; + this.backend.closeWallet(this.wallet_id, function (close_status, close_data) { + console.log(close_status, close_data); + _this.ngZone.run(function () { + _this.router.navigate(['/']); + }); + }); + } + }; + SeedPhraseComponent = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Component"])({ + selector: 'app-seed-phrase', + template: __webpack_require__(/*! ./seed-phrase.component.html */ "./src/app/seed-phrase/seed-phrase.component.html"), + styles: [__webpack_require__(/*! ./seed-phrase.component.scss */ "./src/app/seed-phrase/seed-phrase.component.scss")] + }), + __metadata("design:paramtypes", [_angular_router__WEBPACK_IMPORTED_MODULE_2__["ActivatedRoute"], + _angular_router__WEBPACK_IMPORTED_MODULE_2__["Router"], + _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_1__["BackendService"], + _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_3__["VariablesService"], + _angular_core__WEBPACK_IMPORTED_MODULE_0__["NgZone"]]) + ], SeedPhraseComponent); + return SeedPhraseComponent; +}()); + + + +/***/ }), + +/***/ "./src/app/send/send.component.html": +/*!******************************************!*\ + !*** ./src/app/send/send.component.html ***! + \******************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = "
\r\n\r\n
\r\n \r\n \r\n
\r\n\r\n
\r\n
\r\n Address is required.\r\n
\r\n
\r\n Address not valid.\r\n
\r\n
\r\n\r\n
\r\n
\r\n \r\n \r\n
\r\n\r\n
\r\n
\r\n Amount is required.\r\n
\r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n
\r\n\r\n \r\n\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n Amount is required.\r\n
\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n Amount is required.\r\n
\r\n
\r\n
\r\n \r\n
\r\n" + +/***/ }), + +/***/ "./src/app/send/send.component.scss": +/*!******************************************!*\ + !*** ./src/app/send/send.component.scss ***! + \******************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = ":host {\n width: 100%; }\n\n.form-send .input-blocks-row {\n display: flex; }\n\n.form-send .input-blocks-row > div {\n flex-basis: 50%; }\n\n.form-send .input-blocks-row > div:first-child {\n margin-right: 1.5rem; }\n\n.form-send .input-blocks-row > div:last-child {\n margin-left: 1.5rem; }\n\n.form-send .send-select {\n display: flex;\n align-items: center;\n background: transparent;\n border: none;\n font-size: 1.3rem;\n line-height: 1.3rem;\n margin: 1.5rem 0 0;\n padding: 0;\n width: 100%;\n max-width: 15rem;\n height: 1.3rem; }\n\n.form-send .send-select .arrow {\n margin-left: 1rem;\n width: 0.8rem;\n height: 0.8rem; }\n\n.form-send .send-select .arrow.down {\n -webkit-mask: url('arrow-down.svg') no-repeat center;\n mask: url('arrow-down.svg') no-repeat center; }\n\n.form-send .send-select .arrow.up {\n -webkit-mask: url('arrow-up.svg') no-repeat center;\n mask: url('arrow-up.svg') no-repeat center; }\n\n.form-send .additional-details {\n display: flex;\n margin-top: 1.5rem;\n padding: 0.5rem 0 2rem; }\n\n.form-send .additional-details > div {\n flex-basis: 25%; }\n\n.form-send .additional-details > div:first-child {\n padding-left: 1.5rem;\n padding-right: 1rem; }\n\n.form-send .additional-details > div:last-child {\n padding-left: 1rem;\n padding-right: 1.5rem; }\n\n.form-send button {\n margin: 2.4rem 0;\n width: 100%;\n max-width: 15rem; }\n\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvc2VuZC9EOlxcemFuby9zcmNcXGFwcFxcc2VuZFxcc2VuZC5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLFlBQVcsRUFDWjs7QUFFRDtFQUdJLGNBQWEsRUFhZDs7QUFoQkg7SUFNTSxnQkFBZSxFQVNoQjs7QUFmTDtNQVNRLHFCQUFvQixFQUNyQjs7QUFWUDtNQWFRLG9CQUFtQixFQUNwQjs7QUFkUDtFQW1CSSxjQUFhO0VBQ2Isb0JBQW1CO0VBQ25CLHdCQUF1QjtFQUN2QixhQUFZO0VBQ1osa0JBQWlCO0VBQ2pCLG9CQUFtQjtFQUNuQixtQkFBa0I7RUFDbEIsV0FBVTtFQUNWLFlBQVc7RUFDWCxpQkFBZ0I7RUFDaEIsZUFBYyxFQWVmOztBQTVDSDtJQWdDTSxrQkFBaUI7SUFDakIsY0FBYTtJQUNiLGVBQWMsRUFTZjs7QUEzQ0w7TUFxQ1EscURBQTREO2NBQTVELDZDQUE0RCxFQUM3RDs7QUF0Q1A7TUF5Q1EsbURBQTBEO2NBQTFELDJDQUEwRCxFQUMzRDs7QUExQ1A7RUErQ0ksY0FBYTtFQUNiLG1CQUFrQjtFQUNsQix1QkFBc0IsRUFldkI7O0FBaEVIO0lBb0RNLGdCQUFlLEVBV2hCOztBQS9ETDtNQXVEUSxxQkFBb0I7TUFDcEIsb0JBQW1CLEVBQ3BCOztBQXpEUDtNQTREUSxtQkFBa0I7TUFDbEIsc0JBQXFCLEVBQ3RCOztBQTlEUDtFQW1FSSxpQkFBZ0I7RUFDaEIsWUFBVztFQUNYLGlCQUFnQixFQUNqQiIsImZpbGUiOiJzcmMvYXBwL3NlbmQvc2VuZC5jb21wb25lbnQuc2NzcyIsInNvdXJjZXNDb250ZW50IjpbIjpob3N0IHtcclxuICB3aWR0aDogMTAwJTtcclxufVxyXG5cclxuLmZvcm0tc2VuZCB7XHJcblxyXG4gIC5pbnB1dC1ibG9ja3Mtcm93IHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcblxyXG4gICAgPiBkaXYge1xyXG4gICAgICBmbGV4LWJhc2lzOiA1MCU7XHJcblxyXG4gICAgICAmOmZpcnN0LWNoaWxkIHtcclxuICAgICAgICBtYXJnaW4tcmlnaHQ6IDEuNXJlbTtcclxuICAgICAgfVxyXG5cclxuICAgICAgJjpsYXN0LWNoaWxkIHtcclxuICAgICAgICBtYXJnaW4tbGVmdDogMS41cmVtO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAuc2VuZC1zZWxlY3Qge1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAgICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudDtcclxuICAgIGJvcmRlcjogbm9uZTtcclxuICAgIGZvbnQtc2l6ZTogMS4zcmVtO1xyXG4gICAgbGluZS1oZWlnaHQ6IDEuM3JlbTtcclxuICAgIG1hcmdpbjogMS41cmVtIDAgMDtcclxuICAgIHBhZGRpbmc6IDA7XHJcbiAgICB3aWR0aDogMTAwJTtcclxuICAgIG1heC13aWR0aDogMTVyZW07XHJcbiAgICBoZWlnaHQ6IDEuM3JlbTtcclxuXHJcbiAgICAuYXJyb3cge1xyXG4gICAgICBtYXJnaW4tbGVmdDogMXJlbTtcclxuICAgICAgd2lkdGg6IDAuOHJlbTtcclxuICAgICAgaGVpZ2h0OiAwLjhyZW07XHJcblxyXG4gICAgICAmLmRvd24ge1xyXG4gICAgICAgIG1hc2s6IHVybCh+c3JjL2Fzc2V0cy9pY29ucy9hcnJvdy1kb3duLnN2Zykgbm8tcmVwZWF0IGNlbnRlcjtcclxuICAgICAgfVxyXG5cclxuICAgICAgJi51cCB7XHJcbiAgICAgICAgbWFzazogdXJsKH5zcmMvYXNzZXRzL2ljb25zL2Fycm93LXVwLnN2Zykgbm8tcmVwZWF0IGNlbnRlcjtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLmFkZGl0aW9uYWwtZGV0YWlscyB7XHJcbiAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgbWFyZ2luLXRvcDogMS41cmVtO1xyXG4gICAgcGFkZGluZzogMC41cmVtIDAgMnJlbTtcclxuXHJcbiAgICA+IGRpdiB7XHJcbiAgICAgIGZsZXgtYmFzaXM6IDI1JTtcclxuXHJcbiAgICAgICY6Zmlyc3QtY2hpbGQge1xyXG4gICAgICAgIHBhZGRpbmctbGVmdDogMS41cmVtO1xyXG4gICAgICAgIHBhZGRpbmctcmlnaHQ6IDFyZW07XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICY6bGFzdC1jaGlsZCB7XHJcbiAgICAgICAgcGFkZGluZy1sZWZ0OiAxcmVtO1xyXG4gICAgICAgIHBhZGRpbmctcmlnaHQ6IDEuNXJlbTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgYnV0dG9uIHtcclxuICAgIG1hcmdpbjogMi40cmVtIDA7XHJcbiAgICB3aWR0aDogMTAwJTtcclxuICAgIG1heC13aWR0aDogMTVyZW07XHJcbiAgfVxyXG59XHJcbiJdfQ== */" + +/***/ }), + +/***/ "./src/app/send/send.component.ts": +/*!****************************************!*\ + !*** ./src/app/send/send.component.ts ***! + \****************************************/ +/*! exports provided: SendComponent */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SendComponent", function() { return SendComponent; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/forms */ "./node_modules/@angular/forms/fesm5/forms.js"); +/* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/router */ "./node_modules/@angular/router/fesm5/router.js"); +/* harmony import */ var _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../_helpers/services/backend.service */ "./src/app/_helpers/services/backend.service.ts"); +/* harmony import */ var _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../_helpers/services/variables.service */ "./src/app/_helpers/services/variables.service.ts"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + + + + + +var SendComponent = /** @class */ (function () { + function SendComponent(route, backend, variablesService, ngZone) { + this.route = route; + this.backend = backend; + this.variablesService = variablesService; + this.ngZone = ngZone; + this.currentWalletId = null; + this.sendForm = new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormGroup"]({ + address: new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormControl"]('', _angular_forms__WEBPACK_IMPORTED_MODULE_1__["Validators"].required), + amount: new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormControl"](null, _angular_forms__WEBPACK_IMPORTED_MODULE_1__["Validators"].required), + comment: new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormControl"](''), + mixin: new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormControl"](0, _angular_forms__WEBPACK_IMPORTED_MODULE_1__["Validators"].required), + fee: new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormControl"]('0.01', _angular_forms__WEBPACK_IMPORTED_MODULE_1__["Validators"].required) + }); + this.additionalOptions = false; + } + SendComponent.prototype.ngOnInit = function () { + var _this = this; + this.parentRouting = this.route.parent.params.subscribe(function (params) { + _this.currentWalletId = params['id']; + _this.sendForm.reset({ address: '', amount: null, comment: '', mixin: 0, fee: '0.01' }); + }); + }; + SendComponent.prototype.checkAddressValidation = function () { + var _this = this; + if (this.sendForm.get('address').value) { + this.backend.validateAddress(this.sendForm.get('address').value, function (valid_status) { + if (valid_status === false) { + _this.ngZone.run(function () { + _this.sendForm.get('address').setErrors({ address_not_valid: true }); + }); + } + }); + } + }; + SendComponent.prototype.onSend = function () { + var _this = this; + if (this.sendForm.valid) { + this.backend.validateAddress(this.sendForm.get('address').value, function (valid_status) { + if (valid_status === false) { + _this.ngZone.run(function () { + _this.sendForm.get('address').setErrors({ address_not_valid: true }); + }); + } + else { + _this.backend.sendMoney(_this.currentWalletId, _this.sendForm.get('address').value, _this.sendForm.get('amount').value, _this.sendForm.get('fee').value, _this.sendForm.get('mixin').value, _this.sendForm.get('comment').value, function (send_status, send_data) { + if (send_status) { + alert('SEND_MONEY.SUCCESS_SENT'); + _this.sendForm.reset({ address: '', amount: null, comment: '', mixin: 0, fee: '0.01' }); + } + }); + } + }); + } + }; + SendComponent.prototype.toggleOptions = function () { + this.additionalOptions = !this.additionalOptions; + }; + SendComponent.prototype.ngOnDestroy = function () { + this.parentRouting.unsubscribe(); + }; + SendComponent = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Component"])({ + selector: 'app-send', + template: __webpack_require__(/*! ./send.component.html */ "./src/app/send/send.component.html"), + styles: [__webpack_require__(/*! ./send.component.scss */ "./src/app/send/send.component.scss")] + }), + __metadata("design:paramtypes", [_angular_router__WEBPACK_IMPORTED_MODULE_2__["ActivatedRoute"], + _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_3__["BackendService"], + _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_4__["VariablesService"], + _angular_core__WEBPACK_IMPORTED_MODULE_0__["NgZone"]]) + ], SendComponent); + return SendComponent; +}()); + + + +/***/ }), + +/***/ "./src/app/settings/settings.component.html": +/*!**************************************************!*\ + !*** ./src/app/settings/settings.component.html ***! + \**************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = "
\r\n
\r\n \r\n
\r\n\r\n

{{ 'SETTINGS.TITLE' | translate }}

\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n\r\n
\r\n {{ 'SETTINGS.MASTER_PASSWORD.TITLE' | translate }}\r\n
\r\n \r\n \r\n
\r\n
\r\n Password is required.\r\n
\r\n
\r\n
\r\n Old password not match.\r\n
\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n Password is required.\r\n
\r\n
\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n Password is required.\r\n
\r\n
\r\n
\r\n Confirm password not match.\r\n
\r\n
\r\n \r\n
\r\n\r\n
\r\n" + +/***/ }), + +/***/ "./src/app/settings/settings.component.scss": +/*!**************************************************!*\ + !*** ./src/app/settings/settings.component.scss ***! + \**************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = ".head {\n justify-content: flex-end; }\n\n.settings-title {\n font-size: 1.7rem; }\n\n.theme-selection {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n margin: 2.4rem 0;\n width: 50%; }\n\n.theme-selection .radio-block {\n display: flex;\n align-items: center;\n justify-content: flex-start;\n font-size: 1.3rem;\n line-height: 2.7rem; }\n\n.master-password {\n width: 50%; }\n\n.master-password .master-password-title {\n display: flex;\n font-size: 1.5rem;\n line-height: 2.7rem;\n margin-bottom: 1rem; }\n\n.master-password button {\n margin: 2.5rem auto;\n width: 100%;\n max-width: 15rem; }\n\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvc2V0dGluZ3MvRDpcXHphbm8vc3JjXFxhcHBcXHNldHRpbmdzXFxzZXR0aW5ncy5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLDBCQUF5QixFQUMxQjs7QUFFRDtFQUNFLGtCQUFpQixFQUNsQjs7QUFFRDtFQUNFLGNBQWE7RUFDYix1QkFBc0I7RUFDdEIsd0JBQXVCO0VBQ3ZCLGlCQUFnQjtFQUNoQixXQUFVLEVBU1g7O0FBZEQ7SUFRSSxjQUFhO0lBQ2Isb0JBQW1CO0lBQ25CLDRCQUEyQjtJQUMzQixrQkFBaUI7SUFDakIsb0JBQW1CLEVBQ3BCOztBQUdIO0VBQ0UsV0FBVSxFQWNYOztBQWZEO0lBSUksY0FBYTtJQUNiLGtCQUFpQjtJQUNqQixvQkFBbUI7SUFDbkIsb0JBQW1CLEVBQ3BCOztBQVJIO0lBV0ksb0JBQW1CO0lBQ25CLFlBQVc7SUFDWCxpQkFBZ0IsRUFDakIiLCJmaWxlIjoic3JjL2FwcC9zZXR0aW5ncy9zZXR0aW5ncy5jb21wb25lbnQuc2NzcyIsInNvdXJjZXNDb250ZW50IjpbIi5oZWFkIHtcclxuICBqdXN0aWZ5LWNvbnRlbnQ6IGZsZXgtZW5kO1xyXG59XHJcblxyXG4uc2V0dGluZ3MtdGl0bGUge1xyXG4gIGZvbnQtc2l6ZTogMS43cmVtO1xyXG59XHJcblxyXG4udGhlbWUtc2VsZWN0aW9uIHtcclxuICBkaXNwbGF5OiBmbGV4O1xyXG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XHJcbiAgYWxpZ24taXRlbXM6IGZsZXgtc3RhcnQ7XHJcbiAgbWFyZ2luOiAyLjRyZW0gMDtcclxuICB3aWR0aDogNTAlO1xyXG5cclxuICAucmFkaW8tYmxvY2sge1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAgICBqdXN0aWZ5LWNvbnRlbnQ6IGZsZXgtc3RhcnQ7XHJcbiAgICBmb250LXNpemU6IDEuM3JlbTtcclxuICAgIGxpbmUtaGVpZ2h0OiAyLjdyZW07XHJcbiAgfVxyXG59XHJcblxyXG4ubWFzdGVyLXBhc3N3b3JkIHtcclxuICB3aWR0aDogNTAlO1xyXG5cclxuICAubWFzdGVyLXBhc3N3b3JkLXRpdGxlIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBmb250LXNpemU6IDEuNXJlbTtcclxuICAgIGxpbmUtaGVpZ2h0OiAyLjdyZW07XHJcbiAgICBtYXJnaW4tYm90dG9tOiAxcmVtO1xyXG4gIH1cclxuXHJcbiAgYnV0dG9uIHtcclxuICAgIG1hcmdpbjogMi41cmVtIGF1dG87XHJcbiAgICB3aWR0aDogMTAwJTtcclxuICAgIG1heC13aWR0aDogMTVyZW07XHJcbiAgfVxyXG59XHJcblxyXG4iXX0= */" + +/***/ }), + +/***/ "./src/app/settings/settings.component.ts": +/*!************************************************!*\ + !*** ./src/app/settings/settings.component.ts ***! + \************************************************/ +/*! exports provided: SettingsComponent */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SettingsComponent", function() { return SettingsComponent; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../_helpers/services/variables.service */ "./src/app/_helpers/services/variables.service.ts"); +/* harmony import */ var _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../_helpers/services/backend.service */ "./src/app/_helpers/services/backend.service.ts"); +/* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/forms */ "./node_modules/@angular/forms/fesm5/forms.js"); +/* harmony import */ var _angular_common__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/common */ "./node_modules/@angular/common/fesm5/common.js"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + + + + + +var SettingsComponent = /** @class */ (function () { + function SettingsComponent(renderer, variablesService, backend, location) { + var _this = this; + this.renderer = renderer; + this.variablesService = variablesService; + this.backend = backend; + this.location = location; + this.theme = this.variablesService.settings.theme; + this.changeForm = new _angular_forms__WEBPACK_IMPORTED_MODULE_3__["FormGroup"]({ + password: new _angular_forms__WEBPACK_IMPORTED_MODULE_3__["FormControl"]('', _angular_forms__WEBPACK_IMPORTED_MODULE_3__["Validators"].required), + new_password: new _angular_forms__WEBPACK_IMPORTED_MODULE_3__["FormControl"]('', _angular_forms__WEBPACK_IMPORTED_MODULE_3__["Validators"].required), + new_confirmation: new _angular_forms__WEBPACK_IMPORTED_MODULE_3__["FormControl"]('', _angular_forms__WEBPACK_IMPORTED_MODULE_3__["Validators"].required) + }, [function (g) { + return g.get('new_password').value === g.get('new_confirmation').value ? null : { 'confirm_mismatch': true }; + }, function (g) { + return g.get('password').value === _this.variablesService.appPass ? null : { 'pass_mismatch': true }; + }]); + } + SettingsComponent.prototype.ngOnInit = function () { }; + SettingsComponent.prototype.setTheme = function (theme) { + this.renderer.removeClass(document.body, 'theme-' + this.theme); + this.theme = theme; + this.variablesService.settings.theme = this.theme; + this.renderer.addClass(document.body, 'theme-' + this.theme); + this.backend.storeAppData(); + }; + SettingsComponent.prototype.onSubmitChangePass = function () { + var _this = this; + if (this.changeForm.valid) { + this.variablesService.appPass = this.changeForm.get('new_password').value; + this.backend.storeSecureAppData(function (status, data) { + if (status) { + _this.changeForm.reset(); + } + else { + console.log(data); + } + }); + } + }; + SettingsComponent.prototype.back = function () { + this.location.back(); + }; + SettingsComponent = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Component"])({ + selector: 'app-settings', + template: __webpack_require__(/*! ./settings.component.html */ "./src/app/settings/settings.component.html"), + styles: [__webpack_require__(/*! ./settings.component.scss */ "./src/app/settings/settings.component.scss")] + }), + __metadata("design:paramtypes", [_angular_core__WEBPACK_IMPORTED_MODULE_0__["Renderer2"], _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_1__["VariablesService"], _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_2__["BackendService"], _angular_common__WEBPACK_IMPORTED_MODULE_4__["Location"]]) + ], SettingsComponent); + return SettingsComponent; +}()); + + + +/***/ }), + +/***/ "./src/app/sidebar/sidebar.component.html": +/*!************************************************!*\ + !*** ./src/app/sidebar/sidebar.component.html ***! + \************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = "
\r\n
\r\n

{{ 'SIDEBAR.TITLE' | translate }}

\r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n
\r\n
\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n {{ 'SIDEBAR.SYNCHRONIZATION.OFFLINE' | translate }}\r\n {{ 'SIDEBAR.SYNCHRONIZATION.SYNCING' | translate }}\r\n {{ 'SIDEBAR.SYNCHRONIZATION.ONLINE' | translate }}\r\n {{ 'SIDEBAR.SYNCHRONIZATION.LOADING' | translate }}\r\n {{ 'SIDEBAR.SYNCHRONIZATION.ERROR' | translate }}\r\n {{ 'SIDEBAR.SYNCHRONIZATION.COMPLETE' | translate }}\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
{{ variablesService.sync.progress_value_text }}%
\r\n
\r\n
\r\n
\r\n
\r\n" + +/***/ }), + +/***/ "./src/app/sidebar/sidebar.component.scss": +/*!************************************************!*\ + !*** ./src/app/sidebar/sidebar.component.scss ***! + \************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = ":host {\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n flex: 0 0 25rem;\n padding: 0 3rem 3rem; }\n\n.sidebar-accounts {\n display: flex;\n flex-direction: column;\n flex: 1 1 auto; }\n\n.sidebar-accounts .sidebar-accounts-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex: 0 0 auto;\n height: 8rem;\n font-weight: 400; }\n\n.sidebar-accounts .sidebar-accounts-header h3 {\n font-size: 1.7rem; }\n\n.sidebar-accounts .sidebar-accounts-header button {\n background: transparent;\n border: none;\n outline: none; }\n\n.sidebar-accounts .sidebar-accounts-list {\n display: flex;\n flex-direction: column;\n flex: 1 1 auto;\n margin: 0 -3rem;\n overflow-y: overlay; }\n\n.sidebar-accounts .sidebar-accounts-list .sidebar-account {\n display: flex;\n flex-direction: column;\n flex-shrink: 0;\n cursor: pointer;\n padding: 2rem 3rem; }\n\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row {\n display: flex;\n align-items: center;\n justify-content: space-between; }\n\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-title-balance {\n line-height: 2.7rem; }\n\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-title-balance .title {\n font-size: 1.5rem; }\n\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-title-balance .balance {\n font-size: 1.8rem;\n font-weight: 600; }\n\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-alias {\n font-size: 1.3rem;\n line-height: 3.4rem;\n margin-bottom: 0.7rem; }\n\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-staking {\n line-height: 2.9rem; }\n\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-staking .text {\n font-size: 1.3rem; }\n\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-messages {\n line-height: 2.7rem; }\n\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-messages .text {\n font-size: 1.3rem; }\n\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-messages .indicator {\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 1rem;\n font-size: 1rem;\n min-width: 24px;\n height: 16px;\n padding: 0 5px; }\n\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-synchronization {\n flex-direction: column;\n height: 5.6rem; }\n\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-synchronization .status {\n align-self: flex-start;\n font-size: 1.3rem;\n line-height: 2.6rem; }\n\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-synchronization .progress-bar-container {\n display: flex;\n margin: 0.4rem 0;\n height: 0.7rem;\n width: 100%; }\n\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-synchronization .progress-bar-container .progress-bar {\n flex: 1 0 auto; }\n\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-synchronization .progress-bar-container .progress-bar .fill {\n height: 100%; }\n\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-synchronization .progress-bar-container .progress-percent {\n flex: 0 0 auto;\n font-size: 1.3rem;\n line-height: 0.7rem;\n padding-left: 0.7rem; }\n\n.sidebar-accounts .sidebar-accounts-list .sidebar-account:focus {\n outline: none; }\n\n.sidebar-settings {\n flex: 0 0 auto;\n padding-bottom: 1rem; }\n\n.sidebar-settings button {\n display: flex;\n align-items: center;\n background: transparent;\n border: none;\n line-height: 3rem;\n outline: none;\n padding: 0;\n font-weight: 400; }\n\n.sidebar-settings button .icon {\n margin-right: 1.2rem;\n width: 1.7rem;\n height: 1.7rem; }\n\n.sidebar-settings button .icon.settings {\n -webkit-mask: url('settings.svg') no-repeat center;\n mask: url('settings.svg') no-repeat center; }\n\n.sidebar-settings button .icon.logout {\n -webkit-mask: url('logout.svg') no-repeat center;\n mask: url('logout.svg') no-repeat center; }\n\n.sidebar-synchronization-status {\n position: relative;\n display: flex;\n align-items: flex-end;\n justify-content: flex-start;\n flex: 0 0 4rem;\n font-size: 1.3rem; }\n\n.sidebar-synchronization-status .status-container .offline, .sidebar-synchronization-status .status-container .online {\n position: relative;\n display: block;\n line-height: 1.2rem;\n padding-left: 2.2rem; }\n\n.sidebar-synchronization-status .status-container .offline:before, .sidebar-synchronization-status .status-container .online:before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n border-radius: 50%;\n width: 1.2rem;\n height: 1.2rem; }\n\n.sidebar-synchronization-status .status-container .syncing, .sidebar-synchronization-status .status-container .loading {\n line-height: 4rem; }\n\n.sidebar-synchronization-status .progress-bar-container {\n position: absolute;\n bottom: -0.7rem;\n left: 0;\n height: 0.7rem;\n width: 100%; }\n\n.sidebar-synchronization-status .progress-bar-container .syncing {\n display: flex; }\n\n.sidebar-synchronization-status .progress-bar-container .syncing .progress-bar {\n flex: 1 0 auto; }\n\n.sidebar-synchronization-status .progress-bar-container .syncing .progress-bar .fill {\n height: 100%; }\n\n.sidebar-synchronization-status .progress-bar-container .syncing .progress-percent {\n flex: 0 0 auto;\n font-size: 1.3rem;\n line-height: 0.7rem;\n padding-left: 0.7rem; }\n\n.sidebar-synchronization-status .progress-bar-container .loading {\n background-image: url('loading.png');\n height: 100%; }\n\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvc2lkZWJhci9EOlxcemFuby9zcmNcXGFwcFxcc2lkZWJhclxcc2lkZWJhci5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLGNBQWE7RUFDYix1QkFBc0I7RUFDdEIsK0JBQThCO0VBQzlCLGdCQUFlO0VBQ2YscUJBQW9CLEVBQ3JCOztBQUVEO0VBQ0UsY0FBYTtFQUNiLHVCQUFzQjtFQUN0QixlQUFjLEVBNkhmOztBQWhJRDtJQU1JLGNBQWE7SUFDYixvQkFBbUI7SUFDbkIsK0JBQThCO0lBQzlCLGVBQWM7SUFDZCxhQUFZO0lBQ1osaUJBQWdCLEVBV2pCOztBQXRCSDtNQWNNLGtCQUFpQixFQUNsQjs7QUFmTDtNQWtCTSx3QkFBdUI7TUFDdkIsYUFBWTtNQUNaLGNBQWEsRUFDZDs7QUFyQkw7SUF5QkksY0FBYTtJQUNiLHVCQUFzQjtJQUN0QixlQUFjO0lBQ2QsZ0JBQWU7SUFDZixvQkFBbUIsRUFrR3BCOztBQS9ISDtNQWdDTSxjQUFhO01BQ2IsdUJBQXNCO01BQ3RCLGVBQWM7TUFDZCxnQkFBZTtNQUNmLG1CQUFrQixFQTBGbkI7O0FBOUhMO1FBdUNRLGNBQWE7UUFDYixvQkFBbUI7UUFDbkIsK0JBQThCLEVBZ0YvQjs7QUF6SFA7VUE0Q1Usb0JBQW1CLEVBVXBCOztBQXREVDtZQStDWSxrQkFBaUIsRUFDbEI7O0FBaERYO1lBbURZLGtCQUFpQjtZQUNqQixpQkFBZ0IsRUFDakI7O0FBckRYO1VBeURVLGtCQUFpQjtVQUNqQixvQkFBbUI7VUFDbkIsc0JBQXFCLEVBQ3RCOztBQTVEVDtVQStEVSxvQkFBbUIsRUFLcEI7O0FBcEVUO1lBa0VZLGtCQUFpQixFQUNsQjs7QUFuRVg7VUF1RVUsb0JBQW1CLEVBZ0JwQjs7QUF2RlQ7WUEwRVksa0JBQWlCLEVBQ2xCOztBQTNFWDtZQThFWSxjQUFhO1lBQ2Isb0JBQW1CO1lBQ25CLHdCQUF1QjtZQUN2QixvQkFBbUI7WUFDbkIsZ0JBQWU7WUFDZixnQkFBZTtZQUNmLGFBQVk7WUFDWixlQUFjLEVBQ2Y7O0FBdEZYO1VBMEZVLHVCQUFzQjtVQUN0QixlQUFjLEVBNkJmOztBQXhIVDtZQThGWSx1QkFBc0I7WUFDdEIsa0JBQWlCO1lBQ2pCLG9CQUFtQixFQUNwQjs7QUFqR1g7WUFvR1ksY0FBYTtZQUNiLGlCQUFnQjtZQUNoQixlQUFjO1lBQ2QsWUFBVyxFQWdCWjs7QUF2SFg7Y0EwR2MsZUFBYyxFQUtmOztBQS9HYjtnQkE2R2dCLGFBQVksRUFDYjs7QUE5R2Y7Y0FrSGMsZUFBYztjQUNkLGtCQUFpQjtjQUNqQixvQkFBbUI7Y0FDbkIscUJBQW9CLEVBQ3JCOztBQXRIYjtRQTRIUSxjQUFhLEVBQ2Q7O0FBS1A7RUFDRSxlQUFjO0VBQ2QscUJBQW9CLEVBMEJyQjs7QUE1QkQ7SUFLSSxjQUFhO0lBQ2Isb0JBQW1CO0lBQ25CLHdCQUF1QjtJQUN2QixhQUFZO0lBQ1osa0JBQWlCO0lBQ2pCLGNBQWE7SUFDYixXQUFVO0lBQ1YsaUJBQWdCLEVBZWpCOztBQTNCSDtNQWVNLHFCQUFvQjtNQUNwQixjQUFhO01BQ2IsZUFBYyxFQVNmOztBQTFCTDtRQW9CUSxtREFBMkQ7Z0JBQTNELDJDQUEyRCxFQUM1RDs7QUFyQlA7UUF3QlEsaURBQXlEO2dCQUF6RCx5Q0FBeUQsRUFDMUQ7O0FBS1A7RUFDRSxtQkFBa0I7RUFDbEIsY0FBYTtFQUNiLHNCQUFxQjtFQUNyQiw0QkFBMkI7RUFDM0IsZUFBYztFQUNkLGtCQUFpQixFQXlEbEI7O0FBL0REO0lBV00sbUJBQWtCO0lBQ2xCLGVBQWM7SUFDZCxvQkFBbUI7SUFDbkIscUJBQW9CLEVBV3JCOztBQXpCTDtNQWlCUSxZQUFXO01BQ1gsbUJBQWtCO01BQ2xCLE9BQU07TUFDTixRQUFPO01BQ1AsbUJBQWtCO01BQ2xCLGNBQWE7TUFDYixlQUFjLEVBQ2Y7O0FBeEJQO0lBNEJNLGtCQUFpQixFQUNsQjs7QUE3Qkw7SUFpQ0ksbUJBQWtCO0lBQ2xCLGdCQUFlO0lBQ2YsUUFBTztJQUNQLGVBQWM7SUFDZCxZQUFXLEVBeUJaOztBQTlESDtNQXdDTSxjQUFhLEVBZ0JkOztBQXhETDtRQTJDUSxlQUFjLEVBS2Y7O0FBaERQO1VBOENVLGFBQVksRUFDYjs7QUEvQ1Q7UUFtRFEsZUFBYztRQUNkLGtCQUFpQjtRQUNqQixvQkFBbUI7UUFDbkIscUJBQW9CLEVBQ3JCOztBQXZEUDtNQTJETSxxQ0FBd0Q7TUFDeEQsYUFBWSxFQUNiIiwiZmlsZSI6InNyYy9hcHAvc2lkZWJhci9zaWRlYmFyLmNvbXBvbmVudC5zY3NzIiwic291cmNlc0NvbnRlbnQiOlsiOmhvc3Qge1xyXG4gIGRpc3BsYXk6IGZsZXg7XHJcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XHJcbiAgZmxleDogMCAwIDI1cmVtO1xyXG4gIHBhZGRpbmc6IDAgM3JlbSAzcmVtO1xyXG59XHJcblxyXG4uc2lkZWJhci1hY2NvdW50cyB7XHJcbiAgZGlzcGxheTogZmxleDtcclxuICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xyXG4gIGZsZXg6IDEgMSBhdXRvO1xyXG5cclxuICAuc2lkZWJhci1hY2NvdW50cy1oZWFkZXIge1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAgICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XHJcbiAgICBmbGV4OiAwIDAgYXV0bztcclxuICAgIGhlaWdodDogOHJlbTtcclxuICAgIGZvbnQtd2VpZ2h0OiA0MDA7XHJcblxyXG4gICAgaDMge1xyXG4gICAgICBmb250LXNpemU6IDEuN3JlbTtcclxuICAgIH1cclxuXHJcbiAgICBidXR0b24ge1xyXG4gICAgICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudDtcclxuICAgICAgYm9yZGVyOiBub25lO1xyXG4gICAgICBvdXRsaW5lOiBub25lO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLnNpZGViYXItYWNjb3VudHMtbGlzdCB7XHJcbiAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICAgIGZsZXg6IDEgMSBhdXRvO1xyXG4gICAgbWFyZ2luOiAwIC0zcmVtO1xyXG4gICAgb3ZlcmZsb3cteTogb3ZlcmxheTtcclxuXHJcbiAgICAuc2lkZWJhci1hY2NvdW50IHtcclxuICAgICAgZGlzcGxheTogZmxleDtcclxuICAgICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICAgICAgZmxleC1zaHJpbms6IDA7XHJcbiAgICAgIGN1cnNvcjogcG9pbnRlcjtcclxuICAgICAgcGFkZGluZzogMnJlbSAzcmVtO1xyXG5cclxuICAgICAgLnNpZGViYXItYWNjb3VudC1yb3cge1xyXG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuICAgICAgICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XHJcblxyXG4gICAgICAgICYuYWNjb3VudC10aXRsZS1iYWxhbmNlIHtcclxuICAgICAgICAgIGxpbmUtaGVpZ2h0OiAyLjdyZW07XHJcblxyXG4gICAgICAgICAgLnRpdGxlIHtcclxuICAgICAgICAgICAgZm9udC1zaXplOiAxLjVyZW07XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgLmJhbGFuY2Uge1xyXG4gICAgICAgICAgICBmb250LXNpemU6IDEuOHJlbTtcclxuICAgICAgICAgICAgZm9udC13ZWlnaHQ6IDYwMDtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgICYuYWNjb3VudC1hbGlhcyB7XHJcbiAgICAgICAgICBmb250LXNpemU6IDEuM3JlbTtcclxuICAgICAgICAgIGxpbmUtaGVpZ2h0OiAzLjRyZW07XHJcbiAgICAgICAgICBtYXJnaW4tYm90dG9tOiAwLjdyZW07XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAmLmFjY291bnQtc3Rha2luZyB7XHJcbiAgICAgICAgICBsaW5lLWhlaWdodDogMi45cmVtO1xyXG5cclxuICAgICAgICAgIC50ZXh0IHtcclxuICAgICAgICAgICAgZm9udC1zaXplOiAxLjNyZW07XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAmLmFjY291bnQtbWVzc2FnZXMge1xyXG4gICAgICAgICAgbGluZS1oZWlnaHQ6IDIuN3JlbTtcclxuXHJcbiAgICAgICAgICAudGV4dCB7XHJcbiAgICAgICAgICAgIGZvbnQtc2l6ZTogMS4zcmVtO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIC5pbmRpY2F0b3Ige1xyXG4gICAgICAgICAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgICAgICAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAgICAgICAgICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcclxuICAgICAgICAgICAgYm9yZGVyLXJhZGl1czogMXJlbTtcclxuICAgICAgICAgICAgZm9udC1zaXplOiAxcmVtO1xyXG4gICAgICAgICAgICBtaW4td2lkdGg6IDI0cHg7XHJcbiAgICAgICAgICAgIGhlaWdodDogMTZweDtcclxuICAgICAgICAgICAgcGFkZGluZzogMCA1cHg7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAmLmFjY291bnQtc3luY2hyb25pemF0aW9uIHtcclxuICAgICAgICAgIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XHJcbiAgICAgICAgICBoZWlnaHQ6IDUuNnJlbTtcclxuXHJcbiAgICAgICAgICAuc3RhdHVzIHtcclxuICAgICAgICAgICAgYWxpZ24tc2VsZjogZmxleC1zdGFydDtcclxuICAgICAgICAgICAgZm9udC1zaXplOiAxLjNyZW07XHJcbiAgICAgICAgICAgIGxpbmUtaGVpZ2h0OiAyLjZyZW07XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgLnByb2dyZXNzLWJhci1jb250YWluZXIge1xyXG4gICAgICAgICAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgICAgICAgICBtYXJnaW46IDAuNHJlbSAwO1xyXG4gICAgICAgICAgICBoZWlnaHQ6IDAuN3JlbTtcclxuICAgICAgICAgICAgd2lkdGg6IDEwMCU7XHJcblxyXG4gICAgICAgICAgICAucHJvZ3Jlc3MtYmFyIHtcclxuICAgICAgICAgICAgICBmbGV4OiAxIDAgYXV0bztcclxuXHJcbiAgICAgICAgICAgICAgLmZpbGwge1xyXG4gICAgICAgICAgICAgICAgaGVpZ2h0OiAxMDAlO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLnByb2dyZXNzLXBlcmNlbnQge1xyXG4gICAgICAgICAgICAgIGZsZXg6IDAgMCBhdXRvO1xyXG4gICAgICAgICAgICAgIGZvbnQtc2l6ZTogMS4zcmVtO1xyXG4gICAgICAgICAgICAgIGxpbmUtaGVpZ2h0OiAwLjdyZW07XHJcbiAgICAgICAgICAgICAgcGFkZGluZy1sZWZ0OiAwLjdyZW07XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICY6Zm9jdXMge1xyXG4gICAgICAgIG91dGxpbmU6IG5vbmU7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbi5zaWRlYmFyLXNldHRpbmdzIHtcclxuICBmbGV4OiAwIDAgYXV0bztcclxuICBwYWRkaW5nLWJvdHRvbTogMXJlbTtcclxuXHJcbiAgYnV0dG9uIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAgYmFja2dyb3VuZDogdHJhbnNwYXJlbnQ7XHJcbiAgICBib3JkZXI6IG5vbmU7XHJcbiAgICBsaW5lLWhlaWdodDogM3JlbTtcclxuICAgIG91dGxpbmU6IG5vbmU7XHJcbiAgICBwYWRkaW5nOiAwO1xyXG4gICAgZm9udC13ZWlnaHQ6IDQwMDtcclxuXHJcbiAgICAuaWNvbiB7XHJcbiAgICAgIG1hcmdpbi1yaWdodDogMS4ycmVtO1xyXG4gICAgICB3aWR0aDogMS43cmVtO1xyXG4gICAgICBoZWlnaHQ6IDEuN3JlbTtcclxuXHJcbiAgICAgICYuc2V0dGluZ3Mge1xyXG4gICAgICAgIG1hc2s6IHVybCguLi8uLi9hc3NldHMvaWNvbnMvc2V0dGluZ3Muc3ZnKSBuby1yZXBlYXQgY2VudGVyO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAmLmxvZ291dCB7XHJcbiAgICAgICAgbWFzazogdXJsKC4uLy4uL2Fzc2V0cy9pY29ucy9sb2dvdXQuc3ZnKSBuby1yZXBlYXQgY2VudGVyO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcblxyXG4uc2lkZWJhci1zeW5jaHJvbml6YXRpb24tc3RhdHVzIHtcclxuICBwb3NpdGlvbjogcmVsYXRpdmU7XHJcbiAgZGlzcGxheTogZmxleDtcclxuICBhbGlnbi1pdGVtczogZmxleC1lbmQ7XHJcbiAganVzdGlmeS1jb250ZW50OiBmbGV4LXN0YXJ0O1xyXG4gIGZsZXg6IDAgMCA0cmVtO1xyXG4gIGZvbnQtc2l6ZTogMS4zcmVtO1xyXG5cclxuICAuc3RhdHVzLWNvbnRhaW5lciB7XHJcblxyXG4gICAgLm9mZmxpbmUsIC5vbmxpbmUge1xyXG4gICAgICBwb3NpdGlvbjogcmVsYXRpdmU7XHJcbiAgICAgIGRpc3BsYXk6IGJsb2NrO1xyXG4gICAgICBsaW5lLWhlaWdodDogMS4ycmVtO1xyXG4gICAgICBwYWRkaW5nLWxlZnQ6IDIuMnJlbTtcclxuXHJcbiAgICAgICY6YmVmb3JlIHtcclxuICAgICAgICBjb250ZW50OiAnJztcclxuICAgICAgICBwb3NpdGlvbjogYWJzb2x1dGU7XHJcbiAgICAgICAgdG9wOiAwO1xyXG4gICAgICAgIGxlZnQ6IDA7XHJcbiAgICAgICAgYm9yZGVyLXJhZGl1czogNTAlO1xyXG4gICAgICAgIHdpZHRoOiAxLjJyZW07XHJcbiAgICAgICAgaGVpZ2h0OiAxLjJyZW07XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAuc3luY2luZywgLmxvYWRpbmcge1xyXG4gICAgICBsaW5lLWhlaWdodDogNHJlbTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC5wcm9ncmVzcy1iYXItY29udGFpbmVyIHtcclxuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcclxuICAgIGJvdHRvbTogLTAuN3JlbTtcclxuICAgIGxlZnQ6IDA7XHJcbiAgICBoZWlnaHQ6IDAuN3JlbTtcclxuICAgIHdpZHRoOiAxMDAlO1xyXG5cclxuICAgIC5zeW5jaW5nIHtcclxuICAgICAgZGlzcGxheTogZmxleDtcclxuXHJcbiAgICAgIC5wcm9ncmVzcy1iYXIge1xyXG4gICAgICAgIGZsZXg6IDEgMCBhdXRvO1xyXG5cclxuICAgICAgICAuZmlsbCB7XHJcbiAgICAgICAgICBoZWlnaHQ6IDEwMCU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICAucHJvZ3Jlc3MtcGVyY2VudCB7XHJcbiAgICAgICAgZmxleDogMCAwIGF1dG87XHJcbiAgICAgICAgZm9udC1zaXplOiAxLjNyZW07XHJcbiAgICAgICAgbGluZS1oZWlnaHQ6IDAuN3JlbTtcclxuICAgICAgICBwYWRkaW5nLWxlZnQ6IDAuN3JlbTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC5sb2FkaW5nIHtcclxuICAgICAgYmFja2dyb3VuZC1pbWFnZTogdXJsKFwiLi4vLi4vYXNzZXRzL2ltYWdlcy9sb2FkaW5nLnBuZ1wiKTtcclxuICAgICAgaGVpZ2h0OiAxMDAlO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG4iXX0= */" + +/***/ }), + +/***/ "./src/app/sidebar/sidebar.component.ts": +/*!**********************************************!*\ + !*** ./src/app/sidebar/sidebar.component.ts ***! + \**********************************************/ +/*! exports provided: SidebarComponent */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SidebarComponent", function() { return SidebarComponent; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/router */ "./node_modules/@angular/router/fesm5/router.js"); +/* harmony import */ var _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../_helpers/services/variables.service */ "./src/app/_helpers/services/variables.service.ts"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + + + +var SidebarComponent = /** @class */ (function () { + function SidebarComponent(route, router, variablesService) { + this.route = route; + this.router = router; + this.variablesService = variablesService; + this.walletActiveSubDirectory = ''; + } + SidebarComponent.prototype.ngOnInit = function () { + var _this = this; + if (this.router.url.indexOf('/wallet/') !== -1) { + var localPathArr = this.router.url.split('/'); + if (localPathArr.length >= 3) { + this.walletActive = parseInt(localPathArr[2], 10); + } + if (localPathArr.length >= 4) { + this.walletActiveSubDirectory = localPathArr[3]; + } + } + else if (this.router.url.indexOf('/details') !== -1) { + this.walletActive = this.variablesService.currentWallet.wallet_id; + } + else { + this.walletActive = null; + } + this.walletSubRouting = this.router.events.subscribe(function (event) { + if (event instanceof _angular_router__WEBPACK_IMPORTED_MODULE_1__["NavigationStart"]) { + if (event.url.indexOf('/wallet/') !== -1) { + var localPathArr = event.url.split('/'); + if (localPathArr.length >= 3) { + _this.walletActive = parseInt(localPathArr[2], 10); + } + if (localPathArr.length >= 4) { + _this.walletActiveSubDirectory = localPathArr[3]; + if (_this.walletActiveSubDirectory === 'purchase') { + _this.walletActiveSubDirectory = 'contracts'; + } + } + } + else if (event.url.indexOf('/details') !== -1) { + _this.walletActive = _this.variablesService.currentWallet.wallet_id; + } + else { + _this.walletActive = null; + } + } + }); + }; + SidebarComponent.prototype.ngOnDestroy = function () { + this.walletSubRouting.unsubscribe(); + }; + SidebarComponent.prototype.logOut = function () { + this.variablesService.stopCountdown(); + this.variablesService.appPass = ''; + this.router.navigate(['/login'], { queryParams: { type: 'auth' } }); + }; + SidebarComponent = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Component"])({ + selector: 'app-sidebar', + template: __webpack_require__(/*! ./sidebar.component.html */ "./src/app/sidebar/sidebar.component.html"), + styles: [__webpack_require__(/*! ./sidebar.component.scss */ "./src/app/sidebar/sidebar.component.scss")] + }), + __metadata("design:paramtypes", [_angular_router__WEBPACK_IMPORTED_MODULE_1__["ActivatedRoute"], + _angular_router__WEBPACK_IMPORTED_MODULE_1__["Router"], + _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_2__["VariablesService"]]) + ], SidebarComponent); + return SidebarComponent; +}()); + + + +/***/ }), + +/***/ "./src/app/staking/staking.component.html": +/*!************************************************!*\ + !*** ./src/app/staking/staking.component.html ***! + \************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = "
\r\n
\r\n
\r\n Staking\r\n \r\n \r\n \r\n
\r\n
\r\n Pending\r\n {{pending.total | intToMoney}} {{variablesService.defaultCurrency}}\r\n
\r\n
\r\n Total\r\n {{total | intToMoney}} {{variablesService.defaultCurrency}}\r\n
\r\n
\r\n
\r\n {{selectedDate.date | date : 'MMM. EEEE, dd, yyyy'}}\r\n {{selectedDate.amount}} {{variablesService.defaultCurrency}}\r\n
\r\n
\r\n\r\n
\r\n\r\n
\r\n\r\n
\r\n\r\n
\r\n
\r\n Time period:\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n
\r\n" + +/***/ }), + +/***/ "./src/app/staking/staking.component.scss": +/*!************************************************!*\ + !*** ./src/app/staking/staking.component.scss ***! + \************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = ":host {\n display: flex;\n flex-direction: column;\n width: 100%; }\n\n.chart-header {\n display: flex;\n flex: 0 0 auto; }\n\n.chart-header .general {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: center;\n flex-grow: 1;\n font-size: 1.3rem;\n margin: -0.5rem 0; }\n\n.chart-header .general > div {\n display: flex;\n align-items: center;\n margin: 0.5rem 0;\n height: 2rem; }\n\n.chart-header .general > div .label {\n display: inline-block;\n width: 9rem; }\n\n.chart-header .selected {\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n justify-content: center;\n flex-grow: 1;\n font-size: 1.8rem; }\n\n.chart-header .selected span {\n line-height: 2.9rem; }\n\n.chart {\n display: flex;\n align-items: center;\n flex: 1 1 auto;\n min-height: 40rem; }\n\n.chart > div {\n width: 100%;\n height: 100%; }\n\n.chart-options {\n display: flex;\n align-items: center;\n height: 2.4rem;\n flex: 0 0 auto; }\n\n.chart-options .title {\n font-size: 1.3rem;\n width: 9rem; }\n\n.chart-options .options {\n display: flex;\n justify-content: space-between;\n flex-grow: 1;\n height: 100%; }\n\n.chart-options .options button {\n display: flex;\n align-items: center;\n justify-content: center;\n flex: 1 1 auto;\n cursor: pointer;\n font-size: 1.3rem;\n margin: 0 0.1rem;\n padding: 0;\n height: 100%; }\n\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvc3Rha2luZy9EOlxcemFuby9zcmNcXGFwcFxcc3Rha2luZ1xcc3Rha2luZy5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLGNBQWE7RUFDYix1QkFBc0I7RUFDdEIsWUFBVyxFQUNaOztBQUVEO0VBQ0UsY0FBYTtFQUNiLGVBQWMsRUFvQ2Y7O0FBdENEO0lBS0ksY0FBYTtJQUNiLHVCQUFzQjtJQUN0Qix3QkFBdUI7SUFDdkIsd0JBQXVCO0lBQ3ZCLGFBQVk7SUFDWixrQkFBaUI7SUFDakIsa0JBQWlCLEVBYWxCOztBQXhCSDtNQWNNLGNBQWE7TUFDYixvQkFBbUI7TUFDbkIsaUJBQWdCO01BQ2hCLGFBQVksRUFNYjs7QUF2Qkw7UUFvQlEsc0JBQXFCO1FBQ3JCLFlBQVcsRUFDWjs7QUF0QlA7SUEyQkksY0FBYTtJQUNiLHVCQUFzQjtJQUN0QixzQkFBcUI7SUFDckIsd0JBQXVCO0lBQ3ZCLGFBQVk7SUFDWixrQkFBaUIsRUFLbEI7O0FBckNIO01BbUNNLG9CQUFtQixFQUNwQjs7QUFJTDtFQUNFLGNBQWE7RUFDYixvQkFBbUI7RUFDbkIsZUFBYztFQUNkLGtCQUFpQixFQU1sQjs7QUFWRDtJQU9JLFlBQVc7SUFDWCxhQUFZLEVBQ2I7O0FBR0g7RUFDRSxjQUFhO0VBQ2Isb0JBQW1CO0VBQ25CLGVBQWM7RUFDZCxlQUFjLEVBeUJmOztBQTdCRDtJQU9JLGtCQUFpQjtJQUNqQixZQUFXLEVBQ1o7O0FBVEg7SUFZSSxjQUFhO0lBQ2IsK0JBQThCO0lBQzlCLGFBQVk7SUFDWixhQUFZLEVBYWI7O0FBNUJIO01Ba0JNLGNBQWE7TUFDYixvQkFBbUI7TUFDbkIsd0JBQXVCO01BQ3ZCLGVBQWM7TUFDZCxnQkFBZTtNQUNmLGtCQUFpQjtNQUNqQixpQkFBZ0I7TUFDaEIsV0FBVTtNQUNWLGFBQVksRUFDYiIsImZpbGUiOiJzcmMvYXBwL3N0YWtpbmcvc3Rha2luZy5jb21wb25lbnQuc2NzcyIsInNvdXJjZXNDb250ZW50IjpbIjpob3N0IHtcclxuICBkaXNwbGF5OiBmbGV4O1xyXG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XHJcbiAgd2lkdGg6IDEwMCU7XHJcbn1cclxuXHJcbi5jaGFydC1oZWFkZXIge1xyXG4gIGRpc3BsYXk6IGZsZXg7XHJcbiAgZmxleDogMCAwIGF1dG87XHJcblxyXG4gIC5nZW5lcmFsIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xyXG4gICAgYWxpZ24taXRlbXM6IGZsZXgtc3RhcnQ7XHJcbiAgICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcclxuICAgIGZsZXgtZ3JvdzogMTtcclxuICAgIGZvbnQtc2l6ZTogMS4zcmVtO1xyXG4gICAgbWFyZ2luOiAtMC41cmVtIDA7XHJcblxyXG4gICAgPiBkaXYge1xyXG4gICAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAgICBtYXJnaW46IDAuNXJlbSAwO1xyXG4gICAgICBoZWlnaHQ6IDJyZW07XHJcblxyXG4gICAgICAubGFiZWwge1xyXG4gICAgICAgIGRpc3BsYXk6IGlubGluZS1ibG9jaztcclxuICAgICAgICB3aWR0aDogOXJlbTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLnNlbGVjdGVkIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xyXG4gICAgYWxpZ24taXRlbXM6IGZsZXgtZW5kO1xyXG4gICAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XHJcbiAgICBmbGV4LWdyb3c6IDE7XHJcbiAgICBmb250LXNpemU6IDEuOHJlbTtcclxuXHJcbiAgICBzcGFuIHtcclxuICAgICAgbGluZS1oZWlnaHQ6IDIuOXJlbTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbi5jaGFydCB7XHJcbiAgZGlzcGxheTogZmxleDtcclxuICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gIGZsZXg6IDEgMSBhdXRvO1xyXG4gIG1pbi1oZWlnaHQ6IDQwcmVtO1xyXG5cclxuICA+IGRpdiB7XHJcbiAgICB3aWR0aDogMTAwJTtcclxuICAgIGhlaWdodDogMTAwJTtcclxuICB9XHJcbn1cclxuXHJcbi5jaGFydC1vcHRpb25zIHtcclxuICBkaXNwbGF5OiBmbGV4O1xyXG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAgaGVpZ2h0OiAyLjRyZW07XHJcbiAgZmxleDogMCAwIGF1dG87XHJcblxyXG4gIC50aXRsZSB7XHJcbiAgICBmb250LXNpemU6IDEuM3JlbTtcclxuICAgIHdpZHRoOiA5cmVtO1xyXG4gIH1cclxuXHJcbiAgLm9wdGlvbnMge1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuICAgIGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjtcclxuICAgIGZsZXgtZ3JvdzogMTtcclxuICAgIGhlaWdodDogMTAwJTtcclxuXHJcbiAgICBidXR0b24ge1xyXG4gICAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAgICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcclxuICAgICAgZmxleDogMSAxIGF1dG87XHJcbiAgICAgIGN1cnNvcjogcG9pbnRlcjtcclxuICAgICAgZm9udC1zaXplOiAxLjNyZW07XHJcbiAgICAgIG1hcmdpbjogMCAwLjFyZW07XHJcbiAgICAgIHBhZGRpbmc6IDA7XHJcbiAgICAgIGhlaWdodDogMTAwJTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuIl19 */" + +/***/ }), + +/***/ "./src/app/staking/staking.component.ts": +/*!**********************************************!*\ + !*** ./src/app/staking/staking.component.ts ***! + \**********************************************/ +/*! exports provided: StakingComponent */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StakingComponent", function() { return StakingComponent; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../_helpers/services/variables.service */ "./src/app/_helpers/services/variables.service.ts"); +/* harmony import */ var angular_highcharts__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! angular-highcharts */ "./node_modules/angular-highcharts/fesm5/angular-highcharts.js"); +/* harmony import */ var _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../_helpers/services/backend.service */ "./src/app/_helpers/services/backend.service.ts"); +/* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/router */ "./node_modules/@angular/router/fesm5/router.js"); +/* harmony import */ var _helpers_pipes_int_to_money_pipe__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../_helpers/pipes/int-to-money.pipe */ "./src/app/_helpers/pipes/int-to-money.pipe.ts"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + + + + + + +var StakingComponent = /** @class */ (function () { + function StakingComponent(route, variablesService, backend, ngZone, intToMoneyPipe) { + this.route = route; + this.variablesService = variablesService; + this.backend = backend; + this.ngZone = ngZone; + this.intToMoneyPipe = intToMoneyPipe; + this.periods = [ + { + title: '1 day', + active: false + }, + { + title: '1 week', + active: false + }, + { + title: '1 month', + active: false + }, + { + title: '1 year', + active: false + }, + { + title: 'All', + active: true + } + ]; + this.selectedDate = { + date: null, + amount: null + }; + this.originalData = []; + this.total = 0; + this.pending = { + list: [], + total: 0 + }; + } + StakingComponent.prototype.ngOnInit = function () { + var _this = this; + this.parentRouting = this.route.parent.params.subscribe(function () { + _this.getMiningHistory(); + }); + this.heightAppEvent = this.variablesService.getHeightAppEvent.subscribe(function (newHeight) { + if (_this.pending.total) { + var pendingCount = _this.pending.list.length; + for (var i = pendingCount - 1; i >= 0; i--) { + if (newHeight - _this.pending.list[i].h >= 10) { + _this.pending.list.splice(i, 1); + } + } + if (pendingCount !== _this.pending.list.length) { + _this.pending.total = 0; + for (var i = 0; i < _this.pending.list.length; i++) { + _this.pending.total += _this.pending.list[i].a; + } + } + } + }); + this.refreshStackingEvent = this.variablesService.getRefreshStackingEvent.subscribe(function (wallet_id) { + if (_this.variablesService.currentWallet.wallet_id === wallet_id) { + _this.getMiningHistory(); + } + }); + }; + StakingComponent.prototype.drawChart = function (data) { + var _this = this; + this.chart = new angular_highcharts__WEBPACK_IMPORTED_MODULE_2__["Chart"]({ + title: { text: '' }, + credits: { enabled: false }, + exporting: { enabled: false }, + legend: { enabled: false }, + chart: { + type: 'line', + backgroundColor: 'transparent', + height: null, + zoomType: null + }, + yAxis: { + min: 0, + tickAmount: 5, + title: { + text: '' + }, + gridLineColor: '#2b3644', + gridLineWidth: 2, + lineColor: '#2b3644', + lineWidth: 2, + tickWidth: 2, + tickLength: 120, + tickColor: '#2b3644', + labels: { + y: -8, + align: 'left', + x: -120, + style: { + 'color': '#e0e0e0', + 'fontSize': '13px' + }, + format: '{value} ' + this.variablesService.defaultCurrency + }, + showLastLabel: false, + }, + xAxis: { + type: 'datetime', + gridLineColor: '#2b3644', + lineColor: '#2b3644', + lineWidth: 2, + tickWidth: 2, + tickLength: 10, + tickColor: '#2b3644', + labels: { + style: { + 'color': '#e0e0e0', + 'fontSize': '13px' + } + }, + minPadding: 0, + maxPadding: 0, + minRange: 86400000, + // tickInterval: 86400000, + minTickInterval: 3600000, + }, + tooltip: { + enabled: false + }, + plotOptions: { + area: { + fillColor: { + linearGradient: { + x1: 0, + y1: 0, + x2: 0, + y2: 1 + }, + stops: [ + [0, 'rgba(124,181,236,0.2)'], + [1, 'rgba(124,181,236,0)'] + ] + }, + marker: { + enabled: false, + radius: 2 + }, + lineWidth: 2, + threshold: null + }, + series: { + point: { + events: { + mouseOver: function (obj) { + _this.selectedDate.date = obj.target['x']; + _this.selectedDate.amount = obj.target['y']; + } + } + }, + events: { + mouseOut: function () { + _this.selectedDate.date = null; + _this.selectedDate.amount = null; + } + } + } + }, + series: [ + { + type: 'area', + data: data + } + ] + }); + }; + StakingComponent.prototype.getMiningHistory = function () { + var _this = this; + if (this.variablesService.currentWallet.loaded) { + this.backend.getMiningHistory(this.variablesService.currentWallet.wallet_id, function (status, data) { + _this.total = 0; + _this.pending.list = []; + _this.pending.total = 0; + _this.originalData = []; + if (data.mined_entries) { + data.mined_entries.forEach(function (item, key) { + if (item.t.toString().length === 10) { + data.mined_entries[key].t = (new Date(item.t * 1000)).setUTCMilliseconds(0); + } + }); + data.mined_entries.forEach(function (item) { + _this.total += item.a; + if (_this.variablesService.height_app - item.h < 10) { + _this.pending.list.push(item); + _this.pending.total += item.a; + } + _this.originalData.push([parseInt(item.t, 10), parseFloat(_this.intToMoneyPipe.transform(item.a))]); + }); + _this.originalData = _this.originalData.sort(function (a, b) { + return a[0] - b[0]; + }); + } + _this.ngZone.run(function () { + _this.drawChart(JSON.parse(JSON.stringify(_this.originalData))); + }); + }); + } + }; + StakingComponent.prototype.changePeriod = function (period) { + this.periods.forEach(function (p) { + p.active = false; + }); + period.active = true; + var d = new Date(); + var min = null; + var newData = []; + if (period.title === '1 day') { + this.originalData.forEach(function (item) { + var time = (new Date(item[0])).setUTCMinutes(0, 0, 0); + var find = newData.find(function (itemNew) { return itemNew[0] === time; }); + if (find) { + find[1] += item[1]; + } + else { + newData.push([time, item[1]]); + } + }); + this.chart.ref.series[0].setData(newData, true); + min = Date.UTC(d.getFullYear(), d.getMonth(), d.getDate() - 1, 0, 0, 0, 0); + } + else if (period.title === '1 week') { + this.originalData.forEach(function (item) { + var time = (new Date(item[0])).setUTCHours(0, 0, 0, 0); + var find = newData.find(function (itemNew) { return itemNew[0] === time; }); + if (find) { + find[1] += item[1]; + } + else { + newData.push([time, item[1]]); + } + }); + this.chart.ref.series[0].setData(newData, true); + min = Date.UTC(d.getFullYear(), d.getMonth(), d.getDate() - 7, 0, 0, 0, 0); + } + else if (period.title === '1 month') { + this.originalData.forEach(function (item) { + var time = (new Date(item[0])).setUTCHours(0, 0, 0, 0); + var find = newData.find(function (itemNew) { return itemNew[0] === time; }); + if (find) { + find[1] += item[1]; + } + else { + newData.push([time, item[1]]); + } + }); + this.chart.ref.series[0].setData(newData, true); + min = Date.UTC(d.getFullYear(), d.getMonth() - 1, d.getDate(), 0, 0, 0, 0); + } + else if (period.title === '1 year') { + this.originalData.forEach(function (item) { + var time = (new Date(item[0])).setUTCHours(0, 0, 0, 0); + var find = newData.find(function (itemNew) { return itemNew[0] === time; }); + if (find) { + find[1] += item[1]; + } + else { + newData.push([time, item[1]]); + } + }); + this.chart.ref.series[0].setData(newData, true); + min = Date.UTC(d.getFullYear() - 1, d.getMonth(), d.getDate(), 0, 0, 0, 0); + } + else { + this.chart.ref.series[0].setData(this.originalData, true); + } + this.chart.ref.xAxis[0].setExtremes(min, null); + }; + StakingComponent.prototype.ngOnDestroy = function () { + this.parentRouting.unsubscribe(); + this.heightAppEvent.unsubscribe(); + this.refreshStackingEvent.unsubscribe(); + }; + StakingComponent = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Component"])({ + selector: 'app-staking', + template: __webpack_require__(/*! ./staking.component.html */ "./src/app/staking/staking.component.html"), + styles: [__webpack_require__(/*! ./staking.component.scss */ "./src/app/staking/staking.component.scss")] + }), + __metadata("design:paramtypes", [_angular_router__WEBPACK_IMPORTED_MODULE_4__["ActivatedRoute"], + _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_1__["VariablesService"], + _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_3__["BackendService"], + _angular_core__WEBPACK_IMPORTED_MODULE_0__["NgZone"], + _helpers_pipes_int_to_money_pipe__WEBPACK_IMPORTED_MODULE_5__["IntToMoneyPipe"]]) + ], StakingComponent); + return StakingComponent; +}()); + + + +/***/ }), + +/***/ "./src/app/typing-message/typing-message.component.html": +/*!**************************************************************!*\ + !*** ./src/app/typing-message/typing-message.component.html ***! + \**************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = "
\r\n
\r\n @bitmain\r\n
\r\n \r\n \r\n {{ 'COMMON.BACK' | translate }}\r\n \r\n
\r\n\r\n
\r\n
\r\n
10:39
\r\n
\r\n Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\r\n
\r\n
\r\n Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\r\n
\r\n
\r\n Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\r\n
\r\n
\r\n Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\r\n
\r\n
11:44
\r\n
\r\n Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\r\n
\r\n
\r\n Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\r\n
\r\n
\r\n Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\r\n
\r\n
12:15
\r\n
\r\n Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\r\n
\r\n
\r\n Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\r\n
\r\n
\r\n Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\r\n
\r\n
13:13
\r\n
\r\n Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\r\n
\r\n
\r\n Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\r\n
\r\n
\r\n Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\r\n
\r\n
\r\n
\r\n
\r\n \r\n
\r\n \r\n
\r\n
\r\n" + +/***/ }), + +/***/ "./src/app/typing-message/typing-message.component.scss": +/*!**************************************************************!*\ + !*** ./src/app/typing-message/typing-message.component.scss ***! + \**************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = ":host {\n display: flex;\n flex-direction: column;\n width: 100%; }\n\n.head {\n flex: 0 0 auto;\n box-sizing: content-box;\n margin: -3rem -3rem 0; }\n\n.messages-content {\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n flex-grow: 1; }\n\n.messages-content .messages-list {\n display: flex;\n flex-direction: column;\n font-size: 1.3rem;\n margin: 1rem -3rem;\n padding: 0 3rem;\n overflow-y: overlay; }\n\n.messages-content .messages-list div {\n margin: 0.7rem 0; }\n\n.messages-content .messages-list div.date {\n text-align: center; }\n\n.messages-content .messages-list div.my, .messages-content .messages-list div.buddy {\n position: relative;\n padding: 1.8rem;\n max-width: 60%; }\n\n.messages-content .messages-list div.buddy {\n align-self: flex-end; }\n\n.messages-content .type-message {\n display: flex;\n flex: 0 0 auto;\n width: 100%;\n height: 4.2rem; }\n\n.messages-content .type-message .input-block {\n width: 100%; }\n\n.messages-content .type-message .input-block > textarea {\n min-height: 4.2rem; }\n\n.messages-content .type-message button {\n flex: 0 0 15rem; }\n\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvdHlwaW5nLW1lc3NhZ2UvRDpcXHphbm8vc3JjXFxhcHBcXHR5cGluZy1tZXNzYWdlXFx0eXBpbmctbWVzc2FnZS5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLGNBQWE7RUFDYix1QkFBc0I7RUFDdEIsWUFBVyxFQUNaOztBQUVEO0VBQ0UsZUFBYztFQUNkLHdCQUF1QjtFQUN2QixzQkFBcUIsRUFDdEI7O0FBRUQ7RUFDRSxjQUFhO0VBQ2IsdUJBQXNCO0VBQ3RCLCtCQUE4QjtFQUM5QixhQUFZLEVBK0NiOztBQW5ERDtJQU9JLGNBQWE7SUFDYix1QkFBc0I7SUFDdEIsa0JBQWlCO0lBQ2pCLG1CQUFrQjtJQUNsQixnQkFBZTtJQUNmLG9CQUFtQixFQW1CcEI7O0FBL0JIO01BZU0saUJBQWdCLEVBZWpCOztBQTlCTDtRQWtCUSxtQkFBa0IsRUFDbkI7O0FBbkJQO1FBc0JRLG1CQUFrQjtRQUNsQixnQkFBZTtRQUNmLGVBQWMsRUFDZjs7QUF6QlA7UUE0QlEscUJBQW9CLEVBQ3JCOztBQTdCUDtJQWtDSSxjQUFhO0lBQ2IsZUFBYztJQUNkLFlBQVc7SUFDWCxlQUFjLEVBYWY7O0FBbERIO01Bd0NNLFlBQVcsRUFLWjs7QUE3Q0w7UUEyQ1EsbUJBQWtCLEVBQ25COztBQTVDUDtNQWdETSxnQkFBZSxFQUNoQiIsImZpbGUiOiJzcmMvYXBwL3R5cGluZy1tZXNzYWdlL3R5cGluZy1tZXNzYWdlLmNvbXBvbmVudC5zY3NzIiwic291cmNlc0NvbnRlbnQiOlsiOmhvc3Qge1xyXG4gIGRpc3BsYXk6IGZsZXg7XHJcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICB3aWR0aDogMTAwJTtcclxufVxyXG5cclxuLmhlYWQge1xyXG4gIGZsZXg6IDAgMCBhdXRvO1xyXG4gIGJveC1zaXppbmc6IGNvbnRlbnQtYm94O1xyXG4gIG1hcmdpbjogLTNyZW0gLTNyZW0gMDtcclxufVxyXG5cclxuLm1lc3NhZ2VzLWNvbnRlbnQge1xyXG4gIGRpc3BsYXk6IGZsZXg7XHJcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XHJcbiAgZmxleC1ncm93OiAxO1xyXG5cclxuICAubWVzc2FnZXMtbGlzdCB7XHJcbiAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICAgIGZvbnQtc2l6ZTogMS4zcmVtO1xyXG4gICAgbWFyZ2luOiAxcmVtIC0zcmVtO1xyXG4gICAgcGFkZGluZzogMCAzcmVtO1xyXG4gICAgb3ZlcmZsb3cteTogb3ZlcmxheTtcclxuXHJcbiAgICBkaXYge1xyXG4gICAgICBtYXJnaW46IDAuN3JlbSAwO1xyXG5cclxuICAgICAgJi5kYXRlIHtcclxuICAgICAgICB0ZXh0LWFsaWduOiBjZW50ZXI7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICYubXksICYuYnVkZHkge1xyXG4gICAgICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcclxuICAgICAgICBwYWRkaW5nOiAxLjhyZW07XHJcbiAgICAgICAgbWF4LXdpZHRoOiA2MCU7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICYuYnVkZHkge1xyXG4gICAgICAgIGFsaWduLXNlbGY6IGZsZXgtZW5kO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAudHlwZS1tZXNzYWdlIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBmbGV4OiAwIDAgYXV0bztcclxuICAgIHdpZHRoOiAxMDAlO1xyXG4gICAgaGVpZ2h0OiA0LjJyZW07XHJcblxyXG4gICAgLmlucHV0LWJsb2NrIHtcclxuICAgICAgd2lkdGg6IDEwMCU7XHJcblxyXG4gICAgICA+IHRleHRhcmVhIHtcclxuICAgICAgICBtaW4taGVpZ2h0OiA0LjJyZW07XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBidXR0b24ge1xyXG4gICAgICBmbGV4OiAwIDAgMTVyZW07XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcblxyXG4iXX0= */" + +/***/ }), + +/***/ "./src/app/typing-message/typing-message.component.ts": +/*!************************************************************!*\ + !*** ./src/app/typing-message/typing-message.component.ts ***! + \************************************************************/ +/*! exports provided: TypingMessageComponent */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TypingMessageComponent", function() { return TypingMessageComponent; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/router */ "./node_modules/@angular/router/fesm5/router.js"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + + +var TypingMessageComponent = /** @class */ (function () { + function TypingMessageComponent(route) { + this.route = route; + this.route.params.subscribe(function (params) { return console.log(params); }); + } + TypingMessageComponent.prototype.ngOnInit = function () { + }; + TypingMessageComponent = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Component"])({ + selector: 'app-typing-message', + template: __webpack_require__(/*! ./typing-message.component.html */ "./src/app/typing-message/typing-message.component.html"), + styles: [__webpack_require__(/*! ./typing-message.component.scss */ "./src/app/typing-message/typing-message.component.scss")] + }), + __metadata("design:paramtypes", [_angular_router__WEBPACK_IMPORTED_MODULE_1__["ActivatedRoute"]]) + ], TypingMessageComponent); + return TypingMessageComponent; +}()); + + + +/***/ }), + +/***/ "./src/app/wallet-details/wallet-details.component.html": +/*!**************************************************************!*\ + !*** ./src/app/wallet-details/wallet-details.component.html ***! + \**************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = "
\r\n
\r\n
\r\n {{variablesService.currentWallet.name}}\r\n {{ 'BREADCRUMBS.WALLET_DETAILS' | translate }}\r\n
\r\n \r\n
\r\n\r\n
\r\n
\r\n \r\n \r\n
\r\n\r\n
\r\n
\r\n Name is required.\r\n
\r\n
\r\n Name is duplicate.\r\n
\r\n
\r\n\r\n
\r\n \r\n \r\n
\r\n
\r\n \r\n
\r\n
{{ 'WALLET_DETAILS.SEED_PHRASE_HINT' | translate }}
\r\n
\r\n \r\n
{{(index + 1) + '. ' + word}}
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n\r\n
\r\n" + +/***/ }), + +/***/ "./src/app/wallet-details/wallet-details.component.scss": +/*!**************************************************************!*\ + !*** ./src/app/wallet-details/wallet-details.component.scss ***! + \**************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = ".form-details {\n margin-top: 1.8rem; }\n .form-details .input-block:first-child {\n width: 50%; }\n .form-details .seed-phrase {\n display: flex;\n font-size: 1.4rem;\n line-height: 1.5rem;\n padding: 1.4rem;\n width: 100%;\n height: 8.8rem; }\n .form-details .seed-phrase .seed-phrase-hint {\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n width: 100%;\n height: 100%; }\n .form-details .seed-phrase .seed-phrase-content {\n display: flex;\n flex-direction: column;\n flex-wrap: wrap;\n width: 100%;\n height: 100%; }\n .form-details .wallet-buttons {\n display: flex;\n align-items: center;\n justify-content: space-between; }\n .form-details .wallet-buttons button {\n margin: 2.9rem 0;\n width: 100%;\n max-width: 15rem; }\n\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvd2FsbGV0LWRldGFpbHMvRDpcXHphbm8vc3JjXFxhcHBcXHdhbGxldC1kZXRhaWxzXFx3YWxsZXQtZGV0YWlscy5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLG1CQUFrQixFQStDbkI7RUFoREQ7SUFNTSxXQUFVLEVBQ1g7RUFQTDtJQVdJLGNBQWE7SUFDYixrQkFBaUI7SUFDakIsb0JBQW1CO0lBQ25CLGdCQUFlO0lBQ2YsWUFBVztJQUNYLGVBQWMsRUFrQmY7RUFsQ0g7TUFtQk0sY0FBYTtNQUNiLG9CQUFtQjtNQUNuQix3QkFBdUI7TUFDdkIsZ0JBQWU7TUFDZixZQUFXO01BQ1gsYUFBWSxFQUNiO0VBekJMO01BNEJNLGNBQWE7TUFDYix1QkFBc0I7TUFDdEIsZ0JBQWU7TUFDZixZQUFXO01BQ1gsYUFBWSxFQUNiO0VBakNMO0lBcUNJLGNBQWE7SUFDYixvQkFBbUI7SUFDbkIsK0JBQThCLEVBTy9CO0VBOUNIO01BMENNLGlCQUFnQjtNQUNoQixZQUFXO01BQ1gsaUJBQWdCLEVBQ2pCIiwiZmlsZSI6InNyYy9hcHAvd2FsbGV0LWRldGFpbHMvd2FsbGV0LWRldGFpbHMuY29tcG9uZW50LnNjc3MiLCJzb3VyY2VzQ29udGVudCI6WyIuZm9ybS1kZXRhaWxzIHtcclxuICBtYXJnaW4tdG9wOiAxLjhyZW07XHJcblxyXG4gIC5pbnB1dC1ibG9jayB7XHJcblxyXG4gICAgJjpmaXJzdC1jaGlsZCB7XHJcbiAgICAgIHdpZHRoOiA1MCU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAuc2VlZC1waHJhc2Uge1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuICAgIGZvbnQtc2l6ZTogMS40cmVtO1xyXG4gICAgbGluZS1oZWlnaHQ6IDEuNXJlbTtcclxuICAgIHBhZGRpbmc6IDEuNHJlbTtcclxuICAgIHdpZHRoOiAxMDAlO1xyXG4gICAgaGVpZ2h0OiA4LjhyZW07XHJcblxyXG4gICAgLnNlZWQtcGhyYXNlLWhpbnQge1xyXG4gICAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAgICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcclxuICAgICAgY3Vyc29yOiBwb2ludGVyO1xyXG4gICAgICB3aWR0aDogMTAwJTtcclxuICAgICAgaGVpZ2h0OiAxMDAlO1xyXG4gICAgfVxyXG5cclxuICAgIC5zZWVkLXBocmFzZS1jb250ZW50IHtcclxuICAgICAgZGlzcGxheTogZmxleDtcclxuICAgICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICAgICAgZmxleC13cmFwOiB3cmFwO1xyXG4gICAgICB3aWR0aDogMTAwJTtcclxuICAgICAgaGVpZ2h0OiAxMDAlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLndhbGxldC1idXR0b25zIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xyXG5cclxuICAgIGJ1dHRvbiB7XHJcbiAgICAgIG1hcmdpbjogMi45cmVtIDA7XHJcbiAgICAgIHdpZHRoOiAxMDAlO1xyXG4gICAgICBtYXgtd2lkdGg6IDE1cmVtO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbn1cclxuIl19 */" + +/***/ }), + +/***/ "./src/app/wallet-details/wallet-details.component.ts": +/*!************************************************************!*\ + !*** ./src/app/wallet-details/wallet-details.component.ts ***! + \************************************************************/ +/*! exports provided: WalletDetailsComponent */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WalletDetailsComponent", function() { return WalletDetailsComponent; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/forms */ "./node_modules/@angular/forms/fesm5/forms.js"); +/* harmony import */ var _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../_helpers/services/backend.service */ "./src/app/_helpers/services/backend.service.ts"); +/* harmony import */ var _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../_helpers/services/variables.service */ "./src/app/_helpers/services/variables.service.ts"); +/* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/router */ "./node_modules/@angular/router/fesm5/router.js"); +/* harmony import */ var _angular_common__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @angular/common */ "./node_modules/@angular/common/fesm5/common.js"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + + + + + + +var WalletDetailsComponent = /** @class */ (function () { + function WalletDetailsComponent(router, backend, variablesService, ngZone, location) { + var _this = this; + this.router = router; + this.backend = backend; + this.variablesService = variablesService; + this.ngZone = ngZone; + this.location = location; + this.seedPhrase = ''; + this.showSeed = false; + this.detailsForm = new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormGroup"]({ + name: new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormControl"]('', [_angular_forms__WEBPACK_IMPORTED_MODULE_1__["Validators"].required, function (g) { + for (var i = 0; i < _this.variablesService.wallets.length; i++) { + if (g.value === _this.variablesService.wallets[i].name && _this.variablesService.wallets[i].wallet_id !== _this.variablesService.currentWallet.wallet_id) { + return { 'duplicate': true }; + } + } + return null; + }]), + path: new _angular_forms__WEBPACK_IMPORTED_MODULE_1__["FormControl"]('') + }); + } + WalletDetailsComponent.prototype.ngOnInit = function () { + var _this = this; + this.showSeed = false; + this.detailsForm.get('name').setValue(this.variablesService.currentWallet.name); + this.detailsForm.get('path').setValue(this.variablesService.currentWallet.path); + this.backend.getSmartSafeInfo(this.variablesService.currentWallet.wallet_id, function (status, data) { + if (data.hasOwnProperty('restore_key')) { + _this.ngZone.run(function () { + _this.seedPhrase = data['restore_key'].trim(); + }); + } + }); + }; + WalletDetailsComponent.prototype.showSeedPhrase = function () { + this.showSeed = true; + }; + WalletDetailsComponent.prototype.onSubmitEdit = function () { + if (this.detailsForm.value) { + this.variablesService.currentWallet.name = this.detailsForm.get('name').value; + this.router.navigate(['/wallet/' + this.variablesService.currentWallet.wallet_id]); + } + }; + WalletDetailsComponent.prototype.closeWallet = function () { + var _this = this; + this.backend.closeWallet(this.variablesService.currentWallet.wallet_id, function () { + for (var i = _this.variablesService.wallets.length - 1; i >= 0; i--) { + if (_this.variablesService.wallets[i].wallet_id === _this.variablesService.currentWallet.wallet_id) { + _this.variablesService.wallets.splice(i, 1); + } + } + _this.backend.storeSecureAppData(function () { + _this.ngZone.run(function () { + if (_this.variablesService.wallets.length) { + _this.variablesService.currentWallet = _this.variablesService.wallets[0]; + _this.router.navigate(['/wallet/' + _this.variablesService.currentWallet.wallet_id]); + } + else { + _this.router.navigate(['/']); + } + }); + }); + }); + }; + WalletDetailsComponent.prototype.back = function () { + this.location.back(); + }; + WalletDetailsComponent.prototype.ngOnDestroy = function () { }; + WalletDetailsComponent = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Component"])({ + selector: 'app-wallet-details', + template: __webpack_require__(/*! ./wallet-details.component.html */ "./src/app/wallet-details/wallet-details.component.html"), + styles: [__webpack_require__(/*! ./wallet-details.component.scss */ "./src/app/wallet-details/wallet-details.component.scss")] + }), + __metadata("design:paramtypes", [_angular_router__WEBPACK_IMPORTED_MODULE_4__["Router"], + _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_2__["BackendService"], + _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_3__["VariablesService"], + _angular_core__WEBPACK_IMPORTED_MODULE_0__["NgZone"], + _angular_common__WEBPACK_IMPORTED_MODULE_5__["Location"]]) + ], WalletDetailsComponent); + return WalletDetailsComponent; +}()); + + + +/***/ }), + +/***/ "./src/app/wallet/wallet.component.html": +/*!**********************************************!*\ + !*** ./src/app/wallet/wallet.component.html ***! + \**********************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = "
\r\n
\r\n

{{variablesService.currentWallet.name}}

\r\n \r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n
\r\n {{variablesService.currentWallet.address}}\r\n \r\n
\r\n
\r\n {{variablesService.currentWallet.unlocked_balance | intToMoney}} {{variablesService.defaultCurrency}}\r\n $ {{variablesService.currentWallet.getMoneyEquivalent(variablesService.moneyEquivalent) | intToMoney | number : '1.2-2'}}\r\n
\r\n
\r\n
\r\n \r\n
\r\n \r\n {{ tab.title | translate }}\r\n {{variablesService.currentWallet.new_contracts}}\r\n
\r\n
\r\n
\r\n
\r\n \r\n
\r\n
\r\n\r\n" + +/***/ }), + +/***/ "./src/app/wallet/wallet.component.scss": +/*!**********************************************!*\ + !*** ./src/app/wallet/wallet.component.scss ***! + \**********************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = ":host {\n position: relative;\n display: flex;\n flex-direction: column;\n padding: 0 3rem 3rem;\n min-width: 95rem;\n width: 100%;\n height: 100%; }\n\n.header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex: 0 0 auto;\n height: 8rem; }\n\n.header > div {\n display: flex;\n align-items: center; }\n\n.header > div :not(:last-child) {\n margin-right: 3.2rem; }\n\n.header h3 {\n font-size: 1.7rem;\n font-weight: 600; }\n\n.header button {\n display: flex;\n align-items: center;\n background: transparent;\n border: none;\n cursor: pointer;\n font-weight: 400;\n outline: none;\n padding: 0; }\n\n.header button .icon {\n margin-right: 1.2rem;\n width: 1.7rem;\n height: 1.7rem; }\n\n.header button .icon.account {\n -webkit-mask: url('account.svg') no-repeat center;\n mask: url('account.svg') no-repeat center; }\n\n.header button .icon.details {\n -webkit-mask: url('details.svg') no-repeat center;\n mask: url('details.svg') no-repeat center; }\n\n.header button .icon.lock {\n -webkit-mask: url('lock.svg') no-repeat center;\n mask: url('lock.svg') no-repeat center; }\n\n.address {\n display: flex;\n align-items: center;\n flex: 0 0 auto;\n font-size: 1.4rem;\n line-height: 1.7rem; }\n\n.address .icon {\n cursor: pointer;\n margin-left: 1.2rem;\n width: 1.7rem;\n height: 1.7rem; }\n\n.address .icon.copy {\n -webkit-mask: url('copy.svg') no-repeat center;\n mask: url('copy.svg') no-repeat center; }\n\n.balance {\n display: flex;\n align-items: flex-end;\n justify-content: flex-start;\n flex: 0 0 auto;\n margin: 2.6rem 0; }\n\n.balance :first-child {\n font-size: 3.3rem;\n font-weight: 600;\n line-height: 2.4rem;\n margin-right: 3.5rem; }\n\n.balance :last-child {\n font-size: 1.8rem;\n font-weight: 600;\n line-height: 1.3rem; }\n\n.tabs {\n display: flex;\n flex-direction: column;\n flex: 1 1 auto; }\n\n.tabs .tabs-header {\n display: flex;\n justify-content: space-between;\n flex: 0 0 auto; }\n\n.tabs .tabs-header .tab {\n display: flex;\n align-items: center;\n justify-content: center;\n flex: 1 0 auto;\n cursor: pointer;\n padding: 0 1rem;\n height: 5rem; }\n\n.tabs .tabs-header .tab .icon {\n margin-right: 1.3rem;\n width: 1.7rem;\n height: 1.7rem; }\n\n.tabs .tabs-header .tab .icon.send {\n -webkit-mask: url('send.svg') no-repeat center;\n mask: url('send.svg') no-repeat center; }\n\n.tabs .tabs-header .tab .icon.receive {\n -webkit-mask: url('receive.svg') no-repeat center;\n mask: url('receive.svg') no-repeat center; }\n\n.tabs .tabs-header .tab .icon.history {\n -webkit-mask: url('history.svg') no-repeat center;\n mask: url('history.svg') no-repeat center; }\n\n.tabs .tabs-header .tab .icon.contracts {\n -webkit-mask: url('contracts.svg') no-repeat center;\n mask: url('contracts.svg') no-repeat center; }\n\n.tabs .tabs-header .tab .icon.messages {\n -webkit-mask: url('message.svg') no-repeat center;\n mask: url('message.svg') no-repeat center; }\n\n.tabs .tabs-header .tab .icon.staking {\n -webkit-mask: url('staking.svg') no-repeat center;\n mask: url('staking.svg') no-repeat center; }\n\n.tabs .tabs-header .tab .indicator {\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 1rem;\n font-size: 1rem;\n font-weight: 600;\n margin-left: 1.3rem;\n padding: 0 0.5rem;\n min-width: 1.6rem;\n height: 1.6rem; }\n\n.tabs .tabs-header .tab.disabled {\n cursor: not-allowed; }\n\n.tabs .tabs-header .tab:not(:last-child) {\n margin-right: 0.3rem; }\n\n.tabs .tabs-content {\n display: flex;\n padding: 3rem;\n flex: 1 1 auto;\n overflow-x: hidden;\n overflow-y: overlay; }\n\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvd2FsbGV0L0Q6XFx6YW5vL3NyY1xcYXBwXFx3YWxsZXRcXHdhbGxldC5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLG1CQUFrQjtFQUNsQixjQUFhO0VBQ2IsdUJBQXNCO0VBQ3RCLHFCQUFvQjtFQUNwQixpQkFBZ0I7RUFDaEIsWUFBVztFQUNYLGFBQVksRUFDYjs7QUFFRDtFQUNFLGNBQWE7RUFDYixvQkFBbUI7RUFDbkIsK0JBQThCO0VBQzlCLGVBQWM7RUFDZCxhQUFZLEVBNENiOztBQWpERDtJQVFJLGNBQWE7SUFDYixvQkFBbUIsRUFLcEI7O0FBZEg7TUFZTSxxQkFBb0IsRUFDckI7O0FBYkw7SUFpQkksa0JBQWlCO0lBQ2pCLGlCQUFnQixFQUNqQjs7QUFuQkg7SUFzQkksY0FBYTtJQUNiLG9CQUFtQjtJQUNuQix3QkFBdUI7SUFDdkIsYUFBWTtJQUNaLGdCQUFlO0lBQ2YsaUJBQWdCO0lBQ2hCLGNBQWE7SUFDYixXQUFVLEVBbUJYOztBQWhESDtNQWdDTSxxQkFBb0I7TUFDcEIsY0FBYTtNQUNiLGVBQWMsRUFhZjs7QUEvQ0w7UUFxQ1Esa0RBQTBEO2dCQUExRCwwQ0FBMEQsRUFDM0Q7O0FBdENQO1FBeUNRLGtEQUEwRDtnQkFBMUQsMENBQTBELEVBQzNEOztBQTFDUDtRQTZDUSwrQ0FBdUQ7Z0JBQXZELHVDQUF1RCxFQUN4RDs7QUFLUDtFQUNFLGNBQWE7RUFDYixvQkFBbUI7RUFDbkIsZUFBYztFQUNkLGtCQUFpQjtFQUNqQixvQkFBbUIsRUFZcEI7O0FBakJEO0lBUUksZ0JBQWU7SUFDZixvQkFBbUI7SUFDbkIsY0FBYTtJQUNiLGVBQWMsRUFLZjs7QUFoQkg7TUFjTSwrQ0FBdUQ7Y0FBdkQsdUNBQXVELEVBQ3hEOztBQUlMO0VBQ0UsY0FBYTtFQUNiLHNCQUFxQjtFQUNyQiw0QkFBMkI7RUFDM0IsZUFBYztFQUNkLGlCQUFnQixFQWNqQjs7QUFuQkQ7SUFRSSxrQkFBaUI7SUFDakIsaUJBQWdCO0lBQ2hCLG9CQUFtQjtJQUNuQixxQkFBb0IsRUFDckI7O0FBWkg7SUFlSSxrQkFBaUI7SUFDakIsaUJBQWdCO0lBQ2hCLG9CQUFtQixFQUNwQjs7QUFHSDtFQUNFLGNBQWE7RUFDYix1QkFBc0I7RUFDdEIsZUFBYyxFQTRFZjs7QUEvRUQ7SUFNSSxjQUFhO0lBQ2IsK0JBQThCO0lBQzlCLGVBQWMsRUE4RGY7O0FBdEVIO01BV00sY0FBYTtNQUNiLG9CQUFtQjtNQUNuQix3QkFBdUI7TUFDdkIsZUFBYztNQUNkLGdCQUFlO01BQ2YsZ0JBQWU7TUFDZixhQUFZLEVBb0RiOztBQXJFTDtRQW9CUSxxQkFBb0I7UUFDcEIsY0FBYTtRQUNiLGVBQWMsRUF5QmY7O0FBL0NQO1VBeUJVLCtDQUF1RDtrQkFBdkQsdUNBQXVELEVBQ3hEOztBQTFCVDtVQTZCVSxrREFBMEQ7a0JBQTFELDBDQUEwRCxFQUMzRDs7QUE5QlQ7VUFpQ1Usa0RBQTBEO2tCQUExRCwwQ0FBMEQsRUFDM0Q7O0FBbENUO1VBcUNVLG9EQUE0RDtrQkFBNUQsNENBQTRELEVBQzdEOztBQXRDVDtVQXlDVSxrREFBMEQ7a0JBQTFELDBDQUEwRCxFQUMzRDs7QUExQ1Q7VUE2Q1Usa0RBQTBEO2tCQUExRCwwQ0FBMEQsRUFDM0Q7O0FBOUNUO1FBa0RRLGNBQWE7UUFDYixvQkFBbUI7UUFDbkIsd0JBQXVCO1FBQ3ZCLG9CQUFtQjtRQUNuQixnQkFBZTtRQUNmLGlCQUFnQjtRQUNoQixvQkFBbUI7UUFDbkIsa0JBQWlCO1FBQ2pCLGtCQUFpQjtRQUNqQixlQUFjLEVBQ2Y7O0FBNURQO1FBK0RRLG9CQUFtQixFQUNwQjs7QUFoRVA7UUFtRVEscUJBQW9CLEVBQ3JCOztBQXBFUDtJQXlFSSxjQUFhO0lBQ2IsY0FBYTtJQUNiLGVBQWM7SUFDZCxtQkFBa0I7SUFDbEIsb0JBQW1CLEVBQ3BCIiwiZmlsZSI6InNyYy9hcHAvd2FsbGV0L3dhbGxldC5jb21wb25lbnQuc2NzcyIsInNvdXJjZXNDb250ZW50IjpbIjpob3N0IHtcclxuICBwb3NpdGlvbjogcmVsYXRpdmU7XHJcbiAgZGlzcGxheTogZmxleDtcclxuICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xyXG4gIHBhZGRpbmc6IDAgM3JlbSAzcmVtO1xyXG4gIG1pbi13aWR0aDogOTVyZW07XHJcbiAgd2lkdGg6IDEwMCU7XHJcbiAgaGVpZ2h0OiAxMDAlO1xyXG59XHJcblxyXG4uaGVhZGVyIHtcclxuICBkaXNwbGF5OiBmbGV4O1xyXG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xyXG4gIGZsZXg6IDAgMCBhdXRvO1xyXG4gIGhlaWdodDogOHJlbTtcclxuXHJcbiAgPiBkaXYge1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcblxyXG4gICAgOm5vdCg6bGFzdC1jaGlsZCkge1xyXG4gICAgICBtYXJnaW4tcmlnaHQ6IDMuMnJlbTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGgzIHtcclxuICAgIGZvbnQtc2l6ZTogMS43cmVtO1xyXG4gICAgZm9udC13ZWlnaHQ6IDYwMDtcclxuICB9XHJcblxyXG4gIGJ1dHRvbiB7XHJcbiAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuICAgIGJhY2tncm91bmQ6IHRyYW5zcGFyZW50O1xyXG4gICAgYm9yZGVyOiBub25lO1xyXG4gICAgY3Vyc29yOiBwb2ludGVyO1xyXG4gICAgZm9udC13ZWlnaHQ6IDQwMDtcclxuICAgIG91dGxpbmU6IG5vbmU7XHJcbiAgICBwYWRkaW5nOiAwO1xyXG5cclxuICAgIC5pY29uIHtcclxuICAgICAgbWFyZ2luLXJpZ2h0OiAxLjJyZW07XHJcbiAgICAgIHdpZHRoOiAxLjdyZW07XHJcbiAgICAgIGhlaWdodDogMS43cmVtO1xyXG5cclxuICAgICAgJi5hY2NvdW50IHtcclxuICAgICAgICBtYXNrOiB1cmwoLi4vLi4vYXNzZXRzL2ljb25zL2FjY291bnQuc3ZnKSBuby1yZXBlYXQgY2VudGVyO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAmLmRldGFpbHMge1xyXG4gICAgICAgIG1hc2s6IHVybCguLi8uLi9hc3NldHMvaWNvbnMvZGV0YWlscy5zdmcpIG5vLXJlcGVhdCBjZW50ZXI7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICYubG9jayB7XHJcbiAgICAgICAgbWFzazogdXJsKC4uLy4uL2Fzc2V0cy9pY29ucy9sb2NrLnN2Zykgbm8tcmVwZWF0IGNlbnRlcjtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuLmFkZHJlc3Mge1xyXG4gIGRpc3BsYXk6IGZsZXg7XHJcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuICBmbGV4OiAwIDAgYXV0bztcclxuICBmb250LXNpemU6IDEuNHJlbTtcclxuICBsaW5lLWhlaWdodDogMS43cmVtO1xyXG5cclxuICAuaWNvbiB7XHJcbiAgICBjdXJzb3I6IHBvaW50ZXI7XHJcbiAgICBtYXJnaW4tbGVmdDogMS4ycmVtO1xyXG4gICAgd2lkdGg6IDEuN3JlbTtcclxuICAgIGhlaWdodDogMS43cmVtO1xyXG5cclxuICAgICYuY29weSB7XHJcbiAgICAgIG1hc2s6IHVybCguLi8uLi9hc3NldHMvaWNvbnMvY29weS5zdmcpIG5vLXJlcGVhdCBjZW50ZXI7XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcblxyXG4uYmFsYW5jZSB7XHJcbiAgZGlzcGxheTogZmxleDtcclxuICBhbGlnbi1pdGVtczogZmxleC1lbmQ7XHJcbiAganVzdGlmeS1jb250ZW50OiBmbGV4LXN0YXJ0O1xyXG4gIGZsZXg6IDAgMCBhdXRvO1xyXG4gIG1hcmdpbjogMi42cmVtIDA7XHJcblxyXG4gIDpmaXJzdC1jaGlsZCB7XHJcbiAgICBmb250LXNpemU6IDMuM3JlbTtcclxuICAgIGZvbnQtd2VpZ2h0OiA2MDA7XHJcbiAgICBsaW5lLWhlaWdodDogMi40cmVtO1xyXG4gICAgbWFyZ2luLXJpZ2h0OiAzLjVyZW07XHJcbiAgfVxyXG5cclxuICA6bGFzdC1jaGlsZCB7XHJcbiAgICBmb250LXNpemU6IDEuOHJlbTtcclxuICAgIGZvbnQtd2VpZ2h0OiA2MDA7XHJcbiAgICBsaW5lLWhlaWdodDogMS4zcmVtO1xyXG4gIH1cclxufVxyXG5cclxuLnRhYnMge1xyXG4gIGRpc3BsYXk6IGZsZXg7XHJcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICBmbGV4OiAxIDEgYXV0bztcclxuXHJcbiAgLnRhYnMtaGVhZGVyIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XHJcbiAgICBmbGV4OiAwIDAgYXV0bztcclxuXHJcbiAgICAudGFiIHtcclxuICAgICAgZGlzcGxheTogZmxleDtcclxuICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuICAgICAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XHJcbiAgICAgIGZsZXg6IDEgMCBhdXRvO1xyXG4gICAgICBjdXJzb3I6IHBvaW50ZXI7XHJcbiAgICAgIHBhZGRpbmc6IDAgMXJlbTtcclxuICAgICAgaGVpZ2h0OiA1cmVtO1xyXG5cclxuICAgICAgLmljb24ge1xyXG4gICAgICAgIG1hcmdpbi1yaWdodDogMS4zcmVtO1xyXG4gICAgICAgIHdpZHRoOiAxLjdyZW07XHJcbiAgICAgICAgaGVpZ2h0OiAxLjdyZW07XHJcblxyXG4gICAgICAgICYuc2VuZCB7XHJcbiAgICAgICAgICBtYXNrOiB1cmwoLi4vLi4vYXNzZXRzL2ljb25zL3NlbmQuc3ZnKSBuby1yZXBlYXQgY2VudGVyO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgJi5yZWNlaXZlIHtcclxuICAgICAgICAgIG1hc2s6IHVybCguLi8uLi9hc3NldHMvaWNvbnMvcmVjZWl2ZS5zdmcpIG5vLXJlcGVhdCBjZW50ZXI7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAmLmhpc3Rvcnkge1xyXG4gICAgICAgICAgbWFzazogdXJsKC4uLy4uL2Fzc2V0cy9pY29ucy9oaXN0b3J5LnN2Zykgbm8tcmVwZWF0IGNlbnRlcjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgICYuY29udHJhY3RzIHtcclxuICAgICAgICAgIG1hc2s6IHVybCguLi8uLi9hc3NldHMvaWNvbnMvY29udHJhY3RzLnN2Zykgbm8tcmVwZWF0IGNlbnRlcjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgICYubWVzc2FnZXMge1xyXG4gICAgICAgICAgbWFzazogdXJsKC4uLy4uL2Fzc2V0cy9pY29ucy9tZXNzYWdlLnN2Zykgbm8tcmVwZWF0IGNlbnRlcjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgICYuc3Rha2luZyB7XHJcbiAgICAgICAgICBtYXNrOiB1cmwoLi4vLi4vYXNzZXRzL2ljb25zL3N0YWtpbmcuc3ZnKSBuby1yZXBlYXQgY2VudGVyO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgLmluZGljYXRvciB7XHJcbiAgICAgICAgZGlzcGxheTogZmxleDtcclxuICAgICAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAgICAgIGp1c3RpZnktY29udGVudDogY2VudGVyO1xyXG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDFyZW07XHJcbiAgICAgICAgZm9udC1zaXplOiAxcmVtO1xyXG4gICAgICAgIGZvbnQtd2VpZ2h0OiA2MDA7XHJcbiAgICAgICAgbWFyZ2luLWxlZnQ6IDEuM3JlbTtcclxuICAgICAgICBwYWRkaW5nOiAwIDAuNXJlbTtcclxuICAgICAgICBtaW4td2lkdGg6IDEuNnJlbTtcclxuICAgICAgICBoZWlnaHQ6IDEuNnJlbTtcclxuICAgICAgfVxyXG5cclxuICAgICAgJi5kaXNhYmxlZCB7XHJcbiAgICAgICAgY3Vyc29yOiBub3QtYWxsb3dlZDtcclxuICAgICAgfVxyXG5cclxuICAgICAgJjpub3QoOmxhc3QtY2hpbGQpIHtcclxuICAgICAgICBtYXJnaW4tcmlnaHQ6IDAuM3JlbTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLnRhYnMtY29udGVudCB7XHJcbiAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgcGFkZGluZzogM3JlbTtcclxuICAgIGZsZXg6IDEgMSBhdXRvO1xyXG4gICAgb3ZlcmZsb3cteDogaGlkZGVuO1xyXG4gICAgb3ZlcmZsb3cteTogb3ZlcmxheTtcclxuICB9XHJcbn1cclxuIl19 */" + +/***/ }), + +/***/ "./src/app/wallet/wallet.component.ts": +/*!********************************************!*\ + !*** ./src/app/wallet/wallet.component.ts ***! + \********************************************/ +/*! exports provided: WalletComponent */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WalletComponent", function() { return WalletComponent; }); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/router */ "./node_modules/@angular/router/fesm5/router.js"); +/* harmony import */ var _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../_helpers/services/variables.service */ "./src/app/_helpers/services/variables.service.ts"); +/* harmony import */ var _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../_helpers/services/backend.service */ "./src/app/_helpers/services/backend.service.ts"); +var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (undefined && undefined.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; + + + + +var WalletComponent = /** @class */ (function () { + function WalletComponent(route, router, backend, variablesService, ngZone) { + this.route = route; + this.router = router; + this.backend = backend; + this.variablesService = variablesService; + this.ngZone = ngZone; + this.tabs = [ + { + title: 'WALLET.TABS.SEND', + icon: 'send', + link: '/send', + indicator: false, + active: true + }, + { + title: 'WALLET.TABS.RECEIVE', + icon: 'receive', + link: '/receive', + indicator: false, + active: false + }, + { + title: 'WALLET.TABS.HISTORY', + icon: 'history', + link: '/history', + indicator: false, + active: false + }, + { + title: 'WALLET.TABS.CONTRACTS', + icon: 'contracts', + link: '/contracts', + indicator: 1, + active: false + }, + { + title: 'WALLET.TABS.MESSAGES', + icon: 'messages', + link: '/messages', + indicator: 32, + active: false + }, + { + title: 'WALLET.TABS.STAKING', + icon: 'staking', + link: '/staking', + indicator: false, + active: false + } + ]; + } + WalletComponent.prototype.ngOnInit = function () { + var _this = this; + this.subRouting = this.route.params.subscribe(function (params) { + _this.walletID = +params['id']; + _this.variablesService.setCurrentWallet(_this.walletID); + for (var i = 0; i < _this.tabs.length; i++) { + _this.tabs[i].active = (_this.tabs[i].link === '/' + _this.route.snapshot.firstChild.url[0].path); + } + }); + }; + WalletComponent.prototype.changeTab = function (index) { + if ((this.tabs[index].link === '/contracts' || this.tabs[index].link === '/staking') && this.variablesService.daemon_state !== 2) { + return; + } + this.tabs.forEach(function (tab) { + tab.active = false; + }); + this.tabs[index].active = true; + this.router.navigate(['wallet/' + this.walletID + this.tabs[index].link]); + }; + WalletComponent.prototype.copyAddress = function () { + this.backend.setClipboard(this.variablesService.currentWallet.address); + }; + /*closeWallet() { + this.backend.closeWallet(this.walletID, () => { + for (let i = this.variablesService.wallets.length - 1; i >= 0; i--) { + if (this.variablesService.wallets[i].wallet_id === this.walletID) { + this.variablesService.wallets.splice(i, 1); + } + } + this.backend.storeSecureAppData(() => { + this.ngZone.run(() => { + this.router.navigate(['/']); + }); + }); + }); + }*/ + WalletComponent.prototype.ngOnDestroy = function () { + this.subRouting.unsubscribe(); + }; + WalletComponent = __decorate([ + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Component"])({ + selector: 'app-wallet', + template: __webpack_require__(/*! ./wallet.component.html */ "./src/app/wallet/wallet.component.html"), + styles: [__webpack_require__(/*! ./wallet.component.scss */ "./src/app/wallet/wallet.component.scss")] + }), + __metadata("design:paramtypes", [_angular_router__WEBPACK_IMPORTED_MODULE_1__["ActivatedRoute"], + _angular_router__WEBPACK_IMPORTED_MODULE_1__["Router"], + _helpers_services_backend_service__WEBPACK_IMPORTED_MODULE_3__["BackendService"], + _helpers_services_variables_service__WEBPACK_IMPORTED_MODULE_2__["VariablesService"], + _angular_core__WEBPACK_IMPORTED_MODULE_0__["NgZone"]]) + ], WalletComponent); + return WalletComponent; +}()); + + + +/***/ }), + +/***/ "./src/environments/environment.ts": +/*!*****************************************!*\ + !*** ./src/environments/environment.ts ***! + \*****************************************/ +/*! exports provided: environment */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "environment", function() { return environment; }); +// This file can be replaced during build by using the `fileReplacements` array. +// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. +// The list of file replacements can be found in `angular.json`. +var environment = { + production: false +}; +/* + * For easier debugging in development mode, you can import the following file + * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. + * + * This import should be commented out in production mode because it will have a negative impact + * on performance if an error is thrown. + */ +// import 'zone.js/dist/zone-error'; // Included with Angular CLI. + + +/***/ }), + +/***/ "./src/main.ts": +/*!*********************!*\ + !*** ./src/main.ts ***! + \*********************/ +/*! no exports provided */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ "./node_modules/@angular/core/fesm5/core.js"); +/* harmony import */ var _angular_platform_browser_dynamic__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/platform-browser-dynamic */ "./node_modules/@angular/platform-browser-dynamic/fesm5/platform-browser-dynamic.js"); +/* harmony import */ var _app_app_module__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./app/app.module */ "./src/app/app.module.ts"); +/* harmony import */ var _environments_environment__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./environments/environment */ "./src/environments/environment.ts"); + + + + +if (_environments_environment__WEBPACK_IMPORTED_MODULE_3__["environment"].production) { + Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["enableProdMode"])(); +} +Object(_angular_platform_browser_dynamic__WEBPACK_IMPORTED_MODULE_1__["platformBrowserDynamic"])().bootstrapModule(_app_app_module__WEBPACK_IMPORTED_MODULE_2__["AppModule"]) + .catch(function (err) { return console.error(err); }); + + +/***/ }), + +/***/ 0: +/*!***************************!*\ + !*** multi ./src/main.ts ***! + \***************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +module.exports = __webpack_require__(/*! D:\zano\src\main.ts */"./src/main.ts"); + + +/***/ }) + +},[[0,"runtime","vendor"]]]); +//# sourceMappingURL=main.js.map \ No newline at end of file diff --git a/src/gui/qt-daemon/html/main.js.map b/src/gui/qt-daemon/html/main.js.map new file mode 100644 index 00000000..44a669a7 --- /dev/null +++ b/src/gui/qt-daemon/html/main.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack:///./src/$_lazy_route_resource lazy namespace object","webpack:///./src/app/_helpers/directives/input-validate/input-validate.directive.ts","webpack:///./src/app/_helpers/directives/modal-container/modal-container.component.html","webpack:///./src/app/_helpers/directives/modal-container/modal-container.component.scss","webpack:///./src/app/_helpers/directives/modal-container/modal-container.component.ts","webpack:///./src/app/_helpers/directives/staking-switch/staking-switch.component.html","webpack:///./src/app/_helpers/directives/staking-switch/staking-switch.component.scss","webpack:///./src/app/_helpers/directives/staking-switch/staking-switch.component.ts","webpack:///./src/app/_helpers/directives/tooltip.directive.ts","webpack:///./src/app/_helpers/models/wallet.model.ts","webpack:///./src/app/_helpers/pipes/contract-status-messages.pipe.ts","webpack:///./src/app/_helpers/pipes/contract-time-left.pipe.ts","webpack:///./src/app/_helpers/pipes/history-type-messages.pipe.ts","webpack:///./src/app/_helpers/pipes/int-to-money.pipe.ts","webpack:///./src/app/_helpers/pipes/money-to-int.pipe.ts","webpack:///./src/app/_helpers/services/backend.service.ts","webpack:///./src/app/_helpers/services/variables.service.ts","webpack:///./src/app/app-routing.module.ts","webpack:///./src/app/app.component.html","webpack:///./src/app/app.component.scss","webpack:///./src/app/app.component.ts","webpack:///./src/app/app.module.ts","webpack:///./src/app/contracts/contracts.component.html","webpack:///./src/app/contracts/contracts.component.scss","webpack:///./src/app/contracts/contracts.component.ts","webpack:///./src/app/create-wallet/create-wallet.component.html","webpack:///./src/app/create-wallet/create-wallet.component.scss","webpack:///./src/app/create-wallet/create-wallet.component.ts","webpack:///./src/app/history/history.component.html","webpack:///./src/app/history/history.component.scss","webpack:///./src/app/history/history.component.ts","webpack:///./src/app/login/login.component.html","webpack:///./src/app/login/login.component.scss","webpack:///./src/app/login/login.component.ts","webpack:///./src/app/main/main.component.html","webpack:///./src/app/main/main.component.scss","webpack:///./src/app/main/main.component.ts","webpack:///./src/app/messages/messages.component.html","webpack:///./src/app/messages/messages.component.scss","webpack:///./src/app/messages/messages.component.ts","webpack:///./src/app/open-wallet/open-wallet.component.html","webpack:///./src/app/open-wallet/open-wallet.component.scss","webpack:///./src/app/open-wallet/open-wallet.component.ts","webpack:///./src/app/purchase/purchase.component.html","webpack:///./src/app/purchase/purchase.component.scss","webpack:///./src/app/purchase/purchase.component.ts","webpack:///./src/app/receive/receive.component.html","webpack:///./src/app/receive/receive.component.scss","webpack:///./src/app/receive/receive.component.ts","webpack:///./src/app/restore-wallet/restore-wallet.component.html","webpack:///./src/app/restore-wallet/restore-wallet.component.scss","webpack:///./src/app/restore-wallet/restore-wallet.component.ts","webpack:///./src/app/seed-phrase/seed-phrase.component.html","webpack:///./src/app/seed-phrase/seed-phrase.component.scss","webpack:///./src/app/seed-phrase/seed-phrase.component.ts","webpack:///./src/app/send/send.component.html","webpack:///./src/app/send/send.component.scss","webpack:///./src/app/send/send.component.ts","webpack:///./src/app/settings/settings.component.html","webpack:///./src/app/settings/settings.component.scss","webpack:///./src/app/settings/settings.component.ts","webpack:///./src/app/sidebar/sidebar.component.html","webpack:///./src/app/sidebar/sidebar.component.scss","webpack:///./src/app/sidebar/sidebar.component.ts","webpack:///./src/app/staking/staking.component.html","webpack:///./src/app/staking/staking.component.scss","webpack:///./src/app/staking/staking.component.ts","webpack:///./src/app/typing-message/typing-message.component.html","webpack:///./src/app/typing-message/typing-message.component.scss","webpack:///./src/app/typing-message/typing-message.component.ts","webpack:///./src/app/wallet-details/wallet-details.component.html","webpack:///./src/app/wallet-details/wallet-details.component.scss","webpack:///./src/app/wallet-details/wallet-details.component.ts","webpack:///./src/app/wallet/wallet.component.html","webpack:///./src/app/wallet/wallet.component.scss","webpack:///./src/app/wallet/wallet.component.ts","webpack:///./src/environments/environment.ts","webpack:///./src/main.ts"],"names":[],"mappings":";;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;AACF;AACA,4CAA4C,WAAW;AACvD;AACA;AACA,4E;;;;;;;;;;;;;;;;;;;;;;;;;;ACZ2D;AACpB;AAKvC;IAoBE,gCAAoB,EAAc;QAAd,OAAE,GAAF,EAAE,CAAY;QAlB1B,aAAQ,GAAG;YACjB,OAAO,EAAE;gBACP,KAAK,EAAE,UAAU;gBACjB,WAAW,EAAE,EAAE;aAChB;YACD,sCAAsC;YACtC,yBAAyB;YACzB,gDAAgD;YAChD,KAAK,EAAE;gBACL,KAAK,EAAE,SAAS;gBAChB,MAAM,EAAE,CAAC;gBACT,GAAG,EAAE,YAAY;gBACjB,UAAU,EAAE,KAAK;gBACjB,UAAU,EAAE,KAAK;gBACjB,YAAY,EAAE,UAAC,KAAK,IAAK,YAAK,EAAL,CAAK;aAC/B;SACF,CAAC;IAGF,CAAC;IAGD,sBAAW,mDAAe;aAA1B,UAA2B,IAAY;YACrC,sCAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC;QAC7D,CAAC;;;OAAA;IAFD;QADC,2DAAK,CAAC,kBAAkB,CAAC;;;iEAGzB;IA1BU,sBAAsB;QAHlC,+DAAS,CAAC;YACT,QAAQ,EAAE,oBAAoB;SAC/B,CAAC;yCAqBwB,wDAAU;OApBvB,sBAAsB,CA4BlC;IAAD,6BAAC;CAAA;AA5BkC;;;;;;;;;;;;ACNnC,0a;;;;;;;;;;;ACAA,yBAAyB,oBAAoB,WAAW,cAAc,YAAY,aAAa,kBAAkB,wBAAwB,4BAA4B,0CAA0C,EAAE,YAAY,uBAAuB,kBAAkB,2BAA2B,kBAAkB,iBAAiB,wBAAwB,EAAE,qBAAqB,oBAAoB,uBAAuB,EAAE,2BAA2B,sBAAsB,uBAAuB,EAAE,8BAA8B,sBAAsB,+BAA+B,0BAA0B,EAAE,2BAA2B,0BAA0B,iCAAiC,mBAAmB,qBAAqB,EAAE,0BAA0B,yBAAyB,kBAAkB,oBAAoB,oBAAoB,0BAA0B,8BAA8B,8BAA8B,gBAAgB,iBAAiB,oBAAoB,qBAAqB,EAAE,+CAA+C,m8E;;;;;;;;;;;;;;;;;;;;;;;;ACAr+B;AAOlD;IAEE;IAAgB,CAAC;IAEjB,0CAAQ,GAAR;IACA,CAAC;IALU,uBAAuB;QALnC,+DAAS,CAAC;YACT,QAAQ,EAAE,qBAAqB;;;SAGhC,CAAC;;OACW,uBAAuB,CAOnC;IAAD,8BAAC;CAAA;AAPmC;;;;;;;;;;;;ACPpC,yR;;;;;;;;;;;ACAA,2BAA2B,kBAAkB,wBAAwB,mCAAmC,wBAAwB,oBAAoB,oBAAoB,oBAAoB,gBAAgB,iBAAiB,EAAE,qBAAqB,0BAA0B,oBAAoB,qBAAqB,EAAE,qBAAqB,uBAAuB,0BAA0B,EAAE,+CAA+C,2qC;;;;;;;;;;;;;;;;;;;;;;;;;;ACAnW;AACf;AACI;AAOlE;IAME,gCAAoB,OAAuB,EAAU,gBAAkC;QAAnE,YAAO,GAAP,OAAO,CAAgB;QAAU,qBAAgB,GAAhB,gBAAgB,CAAkB;QAF7E,kBAAa,GAAG,IAAI,0DAAY,EAAW,CAAC;IAGtD,CAAC;IAED,yCAAQ,GAAR;IACA,CAAC;IAED,8CAAa,GAAb;QACE,IAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/D,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE;YAC3B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACvC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;gBACjB,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;aAC7C;iBAAM;gBACL,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;aAC5C;SACF;IACH,CAAC;IApBQ;QAAR,2DAAK,EAAE;;6DAAoB;IACnB;QAAR,2DAAK,EAAE;;2DAAkB;IAChB;QAAT,4DAAM,EAAE;;iEAA6C;IAJ3C,sBAAsB;QALlC,+DAAS,CAAC;YACT,QAAQ,EAAE,oBAAoB;;;SAG/B,CAAC;yCAO6B,wEAAc,EAA4B,4EAAgB;OAN5E,sBAAsB,CAuBlC;IAAD,6BAAC;CAAA;AAvBkC;;;;;;;;;;;;;;;;;;;;;;;;;ACTiD;AASpF;IAQE,0BAAoB,EAAc,EAAU,QAAmB;QAA3C,OAAE,GAAF,EAAE,CAAY;QAAU,aAAQ,GAAR,QAAQ,CAAW;QAF/D,WAAM,GAAG,EAAE,CAAC;IAEsD,CAAC;IAEvC,uCAAY,GAAZ;QAC1B,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;YAAE,IAAI,CAAC,IAAI,EAAE,CAAC;SAAE;IACrC,CAAC;IAE2B,uCAAY,GAAZ;QAC1B,IAAI,IAAI,CAAC,OAAO,EAAE;YAAE,IAAI,CAAC,IAAI,EAAE,CAAC;SAAE;IACpC,CAAC;IAED,+BAAI,GAAJ;QACE,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAED,+BAAI,GAAJ;QAAA,iBAMC;QALC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;QACrD,MAAM,CAAC,UAAU,CAAC;YAChB,KAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAI,CAAC,OAAO,CAAC,CAAC;YACvD,KAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACtB,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IACjB,CAAC;IAED,iCAAM,GAAN;QAAA,iBAyBC;QAxBC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;QACnD,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;QACrF,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACvD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;QAC9D,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;QAC7D,IAAI,IAAI,CAAC,YAAY,KAAK,IAAI,EAAE;YAC9B,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;SACzD;QACD,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI,EAAE;YAC3B,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;SACtE;aAAM;YACL,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;YACvB,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;SACxD;QACD,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE;YACvB,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;YACrD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,oBAAoB,EAAE,aAAW,IAAI,CAAC,KAAK,OAAI,CAAC,CAAC;YACtF,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,iBAAiB,EAAE,aAAW,IAAI,CAAC,KAAK,OAAI,CAAC,CAAC;YACnF,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,eAAe,EAAE,aAAW,IAAI,CAAC,KAAK,OAAI,CAAC,CAAC;YACjF,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,aAAW,IAAI,CAAC,KAAK,OAAI,CAAC,CAAC;YAC9E,MAAM,CAAC,UAAU,CAAC;gBAChB,KAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAI,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;YACvD,CAAC,EAAE,CAAC,CAAC,CAAC;SACP;IACH,CAAC;IAED,sCAAW,GAAX;QACE,IAAM,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,qBAAqB,EAAE,CAAC;QAC9D,IAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,qBAAqB,EAAE,CAAC;QACxD,8GAA8G;QAE9G,IAAI,IAAI,CAAC,SAAS,KAAK,KAAK,EAAE;YAC5B,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,GAAG,UAAU,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;YACpF,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;SACnE;QAED,IAAI,IAAI,CAAC,SAAS,KAAK,QAAQ,EAAE;YAC/B,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;YACnE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;SACnE;QAED,IAAI,IAAI,CAAC,SAAS,KAAK,MAAM,EAAE;YAC7B,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;YAChE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,IAAI,GAAG,UAAU,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;SACtF;QAED,IAAI,IAAI,CAAC,SAAS,KAAK,OAAO,EAAE;YAC9B,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;YAChE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;SACpE;IACH,CAAC;IAjFiB;QAAjB,2DAAK,CAAC,SAAS,CAAC;;0DAAsB;IAC9B;QAAR,2DAAK,EAAE;;uDAAmB;IAClB;QAAR,2DAAK,EAAE;;0DAAsB;IACrB;QAAR,2DAAK,EAAE;;mDAAe;IAMK;QAA3B,kEAAY,CAAC,YAAY,CAAC;;;;wDAE1B;IAE2B;QAA3B,kEAAY,CAAC,YAAY,CAAC;;;;wDAE1B;IAhBU,gBAAgB;QAP5B,+DAAS,CAAC;YACT,QAAQ,EAAE,WAAW;YACrB,IAAI,EAAE;gBACJ,gBAAgB,EAAE,WAAW;aAC9B;SACF,CAAC;yCAUwB,wDAAU,EAAoB,uDAAS;OARpD,gBAAgB,CAmF5B;IAAD,uBAAC;CAAA;AAnF4B;;;;;;;;;;;;;ACP7B;AAAA;AAAA;IAwBE,gBAAY,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAW,EAAE,gBAAoB,EAAE,KAAS,EAAE,QAAa;QAA3D,qCAAW;QAAE,uDAAoB;QAAE,iCAAS;QAAE,wCAAa;QALtG,cAAS,GAAoB,EAAE,CAAC;QAM9B,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;QACpB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;QACzC,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,YAAY,GAAG,QAAQ,CAAC;QAE7B,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC;QAEvB,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;QAClB,IAAI,CAAC,gBAAgB,GAAG,EAAE,CAAC;QAE3B,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;QAClB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,CAAC;IAED,mCAAkB,GAAlB,UAAmB,UAAU;QAC3B,OAAO,IAAI,CAAC,OAAO,GAAG,UAAU,CAAC;IACnC,CAAC;IAED,yBAAQ,GAAR;QACE,OAAO,CAAC,IAAI,CAAC,IAAI,KAAK,EAAE,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAClD,CAAC;IAED,yBAAQ,GAAR,UAAS,EAAE;QACT,OAAO,IAAI,CAAC,SAAS,KAAK,EAAE,CAAC;IAC/B,CAAC;IAED,mCAAkB,GAAlB,UAAmB,IAAS;QAC1B,IAAI,IAAI,CAAC,OAAO,KAAK,CAAC,EAAE;YACtB,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;YACzC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;SACrB;aAAM,IAAI,IAAI,CAAC,OAAO,KAAK,CAAC,EAAE;YAC7B,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;SAClB;aAAM,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;YAC1K,IAAI,CAAC,OAAO,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;YACzB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC;SAC/B;aAAM;YACL,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;gBACnB,IAAI,CAAC,OAAO,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;gBACzB,IAAI,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;aAChC;iBAAM;gBACL,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC;aAC/B;SACF;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,+BAAc,GAAd,UAAe,KAAY;QACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YACrC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,EAAE,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,EAAE;gBACtJ,IAAI,MAAM,GAAG,KAAK,CAAC;gBACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;oBACrD,IAAI,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE;wBACzD,MAAM,GAAG,IAAI,CAAC;wBACd,IAAI,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE;4BACvD,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;yBACrC;wBACD,MAAM;qBACP;iBACF;gBACD,IAAI,CAAC,MAAM,EAAE;oBACX,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;iBACtC;aACF;iBAAM;gBACL,IAAI,MAAM,GAAG,KAAK,CAAC;gBACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;oBAC5C,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE;wBAChD,MAAM,GAAG,IAAI,CAAC;wBACd,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE;4BAC9C,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;yBACrD;wBACD,MAAM;qBACP;iBACF;gBACD,IAAI,CAAC,MAAM,EAAE;oBACX,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE;wBACzE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;qBACzD;yBAAM;wBACL,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;qBACtD;iBACF;aACF;SACF;IACH,CAAC;IAED,0CAAyB,GAAzB,UAA0B,KAAY,EAAE,UAAU,EAAE,UAAU,EAAE,eAAe,EAAE,kBAAkB;QACjG,IAAM,IAAI,GAAG,IAAI,CAAC;gCACT,CAAC;YACR,IAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YAC1B,IAAI,wBAAwB,GAAG,KAAK,CAAC;YACrC,IAAI,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE;gBACxB,wBAAwB,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,cAAI,IAAI,WAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,KAAK,QAAQ,CAAC,WAAW,EAA9F,CAA8F,CAAC,CAAC;aACtJ;YACD,IAAI,CAAC,wBAAwB,IAAI,IAAI,IAAI,IAAI,CAAC,gBAAgB,EAAE;gBAC9D,wBAAwB,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,cAAI,IAAI,WAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,KAAK,QAAQ,CAAC,WAAW,EAA9F,CAA8F,CAAC,CAAC;aAC/J;YAED,IAAI,CAAC,wBAAwB,EAAE;gBAC7B,QAAQ,CAAC,KAAK,GAAG,GAAG,CAAC;aACtB;iBAAM,IAAI,QAAQ,CAAC,KAAK,KAAK,CAAC,IAAI,QAAQ,CAAC,eAAe,GAAG,UAAU,EAAE;gBACxE,QAAQ,CAAC,KAAK,GAAG,GAAG,CAAC;aACtB;iBAAM,IAAI,QAAQ,CAAC,KAAK,KAAK,CAAC,IAAI,QAAQ,CAAC,sBAAsB,KAAK,CAAC,IAAI,QAAQ,CAAC,sBAAsB,GAAG,UAAU,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE;gBACjJ,IAAM,aAAa,GAAG,eAAe,CAAC,IAAI,CAAC,cAAI,IAAI,WAAI,CAAC,KAAK,KAAK,CAAC,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,IAAI,IAAI,CAAC,WAAW,KAAK,QAAQ,CAAC,WAAW,EAA5F,CAA4F,CAAC,CAAC;gBACjJ,IAAI,CAAC,aAAa,EAAE;oBAClB,QAAQ,CAAC,KAAK,GAAG,GAAG,CAAC;oBACrB,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC;iBACxB;aACF;iBAAM,IAAI,QAAQ,CAAC,KAAK,KAAK,CAAC,EAAE;gBAC/B,IAAM,aAAa,GAAG,kBAAkB,CAAC,IAAI,CAAC,cAAI,IAAI,WAAI,CAAC,KAAK,KAAK,GAAG,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,IAAI,IAAI,CAAC,WAAW,KAAK,QAAQ,CAAC,WAAW,EAA9F,CAA8F,CAAC,CAAC;gBACtJ,IAAI,aAAa,EAAE;oBACjB,IAAI,aAAa,CAAC,IAAI,KAAK,QAAQ,CAAC,eAAe,EAAE;wBACnD,QAAQ,CAAC,KAAK,GAAG,GAAG,CAAC;qBACtB;yBAAM;wBACL,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,kBAAkB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;4BAClD,IAAI,kBAAkB,CAAC,CAAC,CAAC,CAAC,WAAW,KAAK,QAAQ,CAAC,WAAW,IAAI,kBAAkB,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,EAAE;gCAC9G,kBAAkB,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gCAChC,MAAM;6BACP;yBACF;wBACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,eAAe,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;4BAC/C,IAAI,eAAe,CAAC,CAAC,CAAC,CAAC,WAAW,KAAK,QAAQ,CAAC,WAAW,IAAI,eAAe,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,EAAE;gCACxG,eAAe,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gCAC7B,MAAM;6BACP;yBACF;qBACF;iBACF;aACF;iBAAM,IAAI,QAAQ,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE;gBACjG,QAAQ,CAAC,KAAK,GAAG,GAAG,CAAC;aACtB;iBAAM,IAAI,QAAQ,CAAC,KAAK,KAAK,CAAC,EAAE;gBAC/B,IAAM,aAAa,GAAG,eAAe,CAAC,IAAI,CAAC,cAAI,IAAI,WAAI,CAAC,KAAK,KAAK,GAAG,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,IAAI,IAAI,CAAC,WAAW,KAAK,QAAQ,CAAC,WAAW,EAA9F,CAA8F,CAAC,CAAC;gBACnJ,IAAI,aAAa,EAAE;oBACjB,QAAQ,CAAC,KAAK,GAAG,GAAG,CAAC;iBACtB;aACF;iBAAM,IAAI,QAAQ,CAAC,KAAK,KAAK,CAAC,EAAE;gBAC/B,IAAM,aAAa,GAAG,kBAAkB,CAAC,IAAI,CAAC,cAAI,IAAI,WAAI,CAAC,KAAK,KAAK,GAAG,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,IAAI,IAAI,CAAC,WAAW,KAAK,QAAQ,CAAC,WAAW,EAA9F,CAA8F,CAAC,CAAC;gBACtJ,IAAI,aAAa,EAAE;oBACjB,IAAI,aAAa,CAAC,IAAI,KAAK,QAAQ,CAAC,sBAAsB,EAAE;wBAC1D,QAAQ,CAAC,KAAK,GAAG,GAAG,CAAC;qBACtB;yBAAM;wBACL,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,kBAAkB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;4BAClD,IAAI,kBAAkB,CAAC,CAAC,CAAC,CAAC,WAAW,KAAK,QAAQ,CAAC,WAAW,IAAI,kBAAkB,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,EAAE;gCAC9G,kBAAkB,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gCAChC,MAAM;6BACP;yBACF;wBACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,eAAe,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;4BAC/C,IAAI,eAAe,CAAC,CAAC,CAAC,CAAC,WAAW,KAAK,QAAQ,CAAC,WAAW,IAAI,eAAe,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,EAAE;gCACxG,eAAe,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gCAC7B,MAAM;6BACP;yBACF;qBACF;iBACF;aACF;iBAAM,IAAI,QAAQ,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE;gBACjG,QAAQ,CAAC,KAAK,GAAG,GAAG,CAAC;aACtB;YACD,IAAM,YAAY,GAAG,eAAe,CAAC,IAAI,CAAC,cAAI,IAAI,WAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,IAAI,IAAI,CAAC,WAAW,KAAK,QAAQ,CAAC,WAAW,EAAzG,CAAyG,CAAC,CAAC;YAC7J,QAAQ,CAAC,MAAM,GAAG,CAAC,YAAY,CAAC;YAChC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,QAAQ,IAAI,QAAQ,CAAC,kBAAkB,CAAC,CAAC,MAAM,CAAC;YAE7E,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAChC,CAAC;QA3ED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE;oBAA5B,CAAC;SA2ET;QACD,IAAI,CAAC,mBAAmB,EAAE,CAAC;IAC7B,CAAC;IAED,oCAAmB,GAAnB;QACE,IAAI,CAAC,aAAa,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,cAAI,IAAI,WAAI,CAAC,MAAM,KAAK,IAAI,EAApB,CAAoB,CAAE,CAAC,CAAC,MAAM,CAAC;IACrF,CAAC;IAED,4BAAW,GAAX,UAAY,EAAE;QACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YAC9C,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,WAAW,KAAK,EAAE,EAAE;gBACxC,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;aAC1B;SACF;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAEH,aAAC;AAAD,CAAC;;;;;;;;;;;;;;;;;;;;;;;ACrNiD;AAKlD;IAAA;IA2GA,CAAC;IAzGC,mDAAc,GAAd,UAAe,QAAgB;QAC7B,IAAM,KAAK,GAAG,EAAC,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAC,CAAC;QACrC,QAAQ,QAAQ,EAAE;YAChB,KAAK,CAAC;gBACJ,KAAK,CAAC,KAAK,GAAG,uBAAuB,CAAC;gBACtC,MAAM;YACR,KAAK,GAAG;gBACN,KAAK,CAAC,KAAK,GAAG,mCAAmC,CAAC;gBAClD,MAAM;YACR,KAAK,GAAG;gBACN,KAAK,CAAC,KAAK,GAAG,yCAAyC,CAAC;gBACxD,KAAK,CAAC,KAAK,GAAG,wCAAwC,CAAC;gBACvD,MAAM;YACR,KAAK,CAAC;gBACJ,KAAK,CAAC,KAAK,GAAG,mDAAmD,CAAC;gBAClE,KAAK,CAAC,KAAK,GAAG,cAAc,CAAC;gBAC7B,MAAM;YACR,KAAK,CAAC;gBACJ,KAAK,CAAC,KAAK,GAAG,iCAAiC,CAAC;gBAChD,KAAK,CAAC,KAAK,GAAG,sDAAsD,CAAC;gBACrE,MAAM;YACR,KAAK,CAAC;gBACJ,KAAK,CAAC,KAAK,GAAG,mBAAmB,CAAC;gBAClC,KAAK,CAAC,KAAK,GAAG,uBAAuB,CAAC;gBACtC,MAAM;YACR,KAAK,CAAC;gBACJ,KAAK,CAAC,KAAK,GAAG,oDAAoD,CAAC;gBACnE,MAAM;YACR,KAAK,GAAG;gBACN,KAAK,CAAC,KAAK,GAAG,4EAA4E,CAAC;gBAC3F,MAAM;YACR,KAAK,CAAC;gBACJ,KAAK,CAAC,KAAK,GAAG,mBAAmB,CAAC;gBAClC,KAAK,CAAC,KAAK,GAAG,kBAAkB,CAAC;gBACjC,MAAM;YACR,KAAK,GAAG;gBACN,KAAK,CAAC,KAAK,GAAG,iDAAiD,CAAC;gBAChE,MAAM;YACR,KAAK,GAAG;gBACN,KAAK,CAAC,KAAK,GAAG,mCAAmC,CAAC;gBAClD,MAAM;SACT;QACD,OAAO,KAAK,CAAC,KAAK,GAAG,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC;IACzC,CAAC;IAED,qDAAgB,GAAhB,UAAiB,QAAgB;QAC/B,IAAM,KAAK,GAAG,EAAC,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAC,CAAC;QACrC,QAAQ,QAAQ,EAAE;YAChB,KAAK,CAAC;gBACJ,KAAK,CAAC,KAAK,GAAG,iDAAiD,CAAC;gBAChE,KAAK,CAAC,KAAK,GAAG,wBAAwB,CAAC;gBACvC,MAAM;YACR,KAAK,GAAG;gBACN,KAAK,CAAC,KAAK,GAAG,2CAA2C,CAAC;gBAC1D,KAAK,CAAC,KAAK,GAAG,yBAAyB,CAAC;gBACxC,MAAM;YACR,KAAK,GAAG;gBACN,KAAK,CAAC,KAAK,GAAG,4CAA4C,CAAC;gBAC3D,KAAK,CAAC,KAAK,GAAG,wCAAwC,CAAC;gBACvD,MAAM;YACR,KAAK,CAAC;gBACJ,KAAK,CAAC,KAAK,GAAG,4CAA4C,CAAC;gBAC3D,KAAK,CAAC,KAAK,GAAG,cAAc,CAAC;gBAC7B,MAAM;YACR,KAAK,GAAG;gBACN,KAAK,CAAC,KAAK,GAAG,iCAAiC,CAAC;gBAChD,KAAK,CAAC,KAAK,GAAG,cAAc,CAAC;gBAC7B,MAAM;YACR,KAAK,CAAC;gBACJ,KAAK,CAAC,KAAK,GAAG,iCAAiC,CAAC;gBAChD,KAAK,CAAC,KAAK,GAAG,sDAAsD,CAAC;gBACrE,MAAM;YACR,KAAK,CAAC;gBACJ,KAAK,CAAC,KAAK,GAAG,mBAAmB,CAAC;gBAClC,KAAK,CAAC,KAAK,GAAG,uBAAuB,CAAC;gBACtC,MAAM;YACR,KAAK,CAAC;gBACJ,KAAK,CAAC,KAAK,GAAG,iFAAiF,CAAC;gBAChG,MAAM;YACR,KAAK,GAAG;gBACN,KAAK,CAAC,KAAK,GAAG,4EAA4E,CAAC;gBAC3F,MAAM;YACR,KAAK,CAAC;gBACJ,KAAK,CAAC,KAAK,GAAG,mBAAmB,CAAC;gBAClC,KAAK,CAAC,KAAK,GAAG,kBAAkB,CAAC;gBACjC,MAAM;YACR,KAAK,GAAG;gBACN,KAAK,CAAC,KAAK,GAAG,yDAAyD,CAAC;gBACxE,MAAM;YACR,KAAK,GAAG;gBACN,KAAK,CAAC,KAAK,GAAG,mCAAmC,CAAC;gBAClD,MAAM;SACT;QACD,OAAO,KAAK,CAAC,KAAK,GAAG,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC;IACzC,CAAC;IAED,8CAAS,GAAT,UAAU,IAAS,EAAE,IAAU;QAE7B,IAAI,IAAI,CAAC,IAAI,EAAE;YACb,OAAO,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;SAC1C;aAAM;YACL,OAAO,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;SACxC;IACH,CAAC;IAzGU,0BAA0B;QAHtC,0DAAI,CAAC;YACJ,IAAI,EAAE,wBAAwB;SAC/B,CAAC;OACW,0BAA0B,CA2GtC;IAAD,iCAAC;CAAA;AA3GsC;;;;;;;;;;;;;;;;;;;;;;;;;;;ACLW;AACa;AACV;AAKrD;IAEE,8BAAoB,OAAyB,EAAU,SAA2B;QAA9D,YAAO,GAAP,OAAO,CAAkB;QAAU,cAAS,GAAT,SAAS,CAAkB;IAAG,CAAC;IAEtF,wCAAS,GAAT,UAAU,KAAU,EAAE,GAAS;QAC7B,IAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC/F,IAAM,IAAI,GAAG,GAAG,IAAI,CAAC,CAAC;QACtB,IAAI,IAAI,KAAK,CAAC,EAAE;YACd,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC;SACzE;QACD,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,KAAK,IAAI,EAAE;YAC3C,IAAI,IAAI,KAAK,CAAC,EAAE;gBACd,IAAI,IAAI,KAAK,CAAC,EAAE;oBACd,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,mCAAmC,EAAE,EAAC,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC;iBAClF;qBAAM;oBACL,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,oCAAoC,EAAE,EAAC,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC;iBACnF;aACF;iBAAM,IAAI,IAAI,KAAK,CAAC,EAAE;gBACrB,IAAI,IAAI,KAAK,CAAC,EAAE;oBACd,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,4CAA4C,EAAE,EAAC,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC;iBAC3F;qBAAM;oBACL,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,6CAA6C,EAAE,EAAC,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC;iBAC5F;aACF;iBAAM,IAAI,IAAI,KAAK,CAAC,EAAE;gBACrB,IAAI,IAAI,KAAK,CAAC,EAAE;oBACd,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,2CAA2C,EAAE,EAAC,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC;iBAC1F;qBAAM;oBACL,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,4CAA4C,EAAE,EAAC,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC;iBAC3F;aACF;SACF;aAAM;YACL,IAAM,IAAI,GAAG,IAAI,GAAG,EAAE,CAAC;YACvB,IAAI,IAAI,KAAK,CAAC,EAAE;gBACd,IAAI,CAAC,CAAC,IAAI,GAAG,EAAE,CAAE,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC,EAAE;oBAChD,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,mCAAmC,EAAE,EAAC,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC;iBAClF;qBAAM,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,EAAE,CAAE,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE;oBACjG,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,oCAAoC,EAAE,EAAC,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC;iBACnF;qBAAM;oBACL,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,wCAAwC,EAAE,EAAC,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC;iBACvF;aACF;iBAAM,IAAI,IAAI,KAAK,CAAC,EAAE;gBACrB,IAAI,CAAC,CAAC,IAAI,GAAG,EAAE,CAAE,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC,EAAE;oBAChD,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,4CAA4C,EAAE,EAAC,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC;iBAC3F;qBAAM,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,EAAE,CAAE,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE;oBACjG,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,6CAA6C,EAAE,EAAC,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC;iBAC5F;qBAAM;oBACL,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,iDAAiD,EAAE,EAAC,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC;iBAChG;aACF;iBAAM,IAAI,IAAI,KAAK,CAAC,EAAE;gBACrB,IAAI,CAAC,CAAC,IAAI,GAAG,EAAE,CAAE,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC,EAAE;oBAChD,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,2CAA2C,EAAE,EAAC,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC;iBAC1F;qBAAM,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,EAAE,CAAE,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE;oBACjG,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,4CAA4C,EAAE,EAAC,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC;iBAC3F;qBAAM;oBACL,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,gDAAgD,EAAE,EAAC,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC;iBAC/F;aACF;SACF;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IA3DU,oBAAoB;QAHhC,0DAAI,CAAC;YACJ,IAAI,EAAE,kBAAkB;SACzB,CAAC;yCAG6B,4EAAgB,EAAqB,oEAAgB;OAFvE,oBAAoB,CA6DhC;IAAD,2BAAC;CAAA;AA7DgC;;;;;;;;;;;;;;;;;;;;;;ACPiB;AAKlD;IAAA;IA0DA,CAAC;IAxDC,2CAAS,GAAT,UAAU,IAAS,EAAE,IAAU;QAE7B,IAAI,IAAI,CAAC,OAAO,KAAK,CAAC,EAAE;YACtB,IAAI,IAAI,CAAC,gBAAgB,IAAI,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE;gBACrD,OAAO,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;aACjC;iBAAM;gBACL,IAAI,IAAI,CAAC,SAAS,EAAE;oBAClB,OAAO,QAAQ,CAAC;iBACjB;qBAAM;oBACL,OAAO,WAAW,CAAC;iBACpB;aACF;SACF;aAAM,IAAI,IAAI,CAAC,OAAO,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE;YAClD,OAAO,SAAS,CAAC;SAClB;aAAM,IAAI,IAAI,CAAC,OAAO,KAAK,CAAC,EAAE;YAC7B,IAAI,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;gBAC5D,OAAO,yDAAyD,CAAC;aAClE;iBAAM;gBACL,OAAO,gFAAgF,CAAC;aACzF;SACF;aAAM;YACL,QAAQ,IAAI,CAAC,OAAO,EAAE;gBACpB,UAAU;gBACV,uDAAuD;gBACvD,WAAW;gBACX,UAAU;gBACV,2DAA2D;gBAC3D,UAAU;gBACV,6DAA6D;gBAC7D,UAAU;gBACV,6DAA6D;gBAC7D,UAAU;gBACV,0DAA0D;gBAC1D,UAAU;gBACV,6DAA6D;gBAC7D,KAAK,CAAC;oBACJ,OAAO,aAAa,CAAC;gBACvB,KAAK,CAAC;oBACJ,OAAO,qBAAqB,CAAC;gBAC/B,KAAK,CAAC;oBACJ,OAAO,sBAAsB,CAAC;gBAChC,UAAU;gBACV,uEAAuE;gBACvE,YAAY;gBACZ,KAAK,EAAE;oBACL,OAAO,8BAA8B,CAAC;gBACxC,KAAK,EAAE;oBACL,OAAO,kCAAkC,CAAC;gBAC5C,KAAK,EAAE;oBACL,OAAO,iCAAiC,CAAC;aAC5C;SACF;QAED,OAAO,WAAW,CAAC;IACrB,CAAC;IAxDU,uBAAuB;QAHnC,0DAAI,CAAC;YACJ,IAAI,EAAE,qBAAqB;SAC5B,CAAC;OACW,uBAAuB,CA0DnC;IAAD,8BAAC;CAAA;AA1DmC;;;;;;;;;;;;;;;;;;;;;;ACLc;AAKlD;IAAA;IAoBA,CAAC;IAlBC,kCAAS,GAAT,UAAU,KAAU,EAAE,IAAU;QAC9B,IAAI,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,SAAS,EAAE;YACtC,OAAO,GAAG,CAAC;SACZ;QACD,IAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QAC9B,IAAI,GAAG,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACrC,KAAK,IAAI,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;YACxC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE;gBAClB,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC3B,MAAM;aACP;SACF;QACD,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE;YAC/B,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;SACrC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAlBU,cAAc;QAH1B,0DAAI,CAAC;YACJ,IAAI,EAAE,YAAY;SACnB,CAAC;OACW,cAAc,CAoB1B;IAAD,qBAAC;CAAA;AApB0B;;;;;;;;;;;;;;;;;;;;;;ACLuB;AAKlD;IAAA;IAmCA,CAAC;IAjCC,kCAAS,GAAT,UAAU,KAAU,EAAE,IAAU;QAC9B,IAAM,8BAA8B,GAAG,CAAC,CAAC;QACzC,IAAI,MAAM,CAAC;QACX,IAAI,KAAK,EAAE;YACT,IAAI,MAAM,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;YACrC,IAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACxC,IAAI,aAAa,GAAG,CAAC,CAAC;YACtB,IAAI,CAAC,CAAC,KAAK,WAAW,EAAE;gBACtB,aAAa,GAAG,MAAM,CAAC,MAAM,GAAG,WAAW,GAAG,CAAC,CAAC;gBAChD,OAAO,8BAA8B,GAAG,aAAa,IAAI,GAAG,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE;oBAC1F,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;oBAC5C,EAAE,aAAa,CAAC;iBACjB;gBACD,IAAI,8BAA8B,GAAG,aAAa,EAAE;oBAClD,OAAO,SAAS,CAAC;iBAClB;gBACD,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;aACtF;iBAAM;gBACL,aAAa,GAAG,CAAC,CAAC;aACnB;YACD,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE;gBAClB,OAAO,SAAS,CAAC;aAClB;YACD,IAAI,aAAa,GAAG,8BAA8B,EAAE;gBAClD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,8BAA8B,GAAG,aAAa,EAAE,CAAC,EAAE,EAAE;oBACzE,MAAM,GAAG,MAAM,GAAG,GAAG,CAAC;iBACvB;aACF;YACD,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;SAC/B;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAjCU,cAAc;QAH1B,0DAAI,CAAC;YACJ,IAAI,EAAE,YAAY;SACnB,CAAC;OACW,cAAc,CAmC1B;IAAD,qBAAC;CAAA;AAnC0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACLc;AACT;AACqB;AACK;AAG1D;IAKE,wBAAoB,gBAAkC,EAAU,cAA8B;QAA1E,qBAAgB,GAAhB,gBAAgB,CAAkB;QAAU,mBAAc,GAAd,cAAc,CAAgB;QAF9F,kBAAa,GAAG,KAAK,CAAC;IAGtB,CAAC;IAGO,8BAAK,GAAb,UAAc,IAAI,EAAE,OAAO;QACzB,QAAQ,IAAI,EAAE;YACZ,KAAK,CAAC;gBACJ,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBACvB,MAAM;YACR,KAAK,CAAC;gBACJ,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACtB,MAAM;YACR,KAAK,CAAC;gBACJ,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBACrB,MAAM;YACR;gBACE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBACrB,MAAM;SACT;IACH,CAAC;IAEO,oCAAW,GAAnB,UAAoB,KAAK,EAAE,MAAM,EAAE,OAAO;QACxC,IAAI,eAAe,GAAG,EAAE,CAAC;QAEzB,QAAQ,KAAK,EAAE;YACb,KAAK,kBAAkB;gBACrB,eAAe,GAAG,wBAAwB,CAAC;gBAC3C,MAAM;YACR,KAAK,WAAW;gBACd,IAAI,OAAO,KAAK,iBAAiB,EAAE;oBACjC,eAAe,GAAG,oBAAoB,CAAC;iBACxC;gBACD,MAAM;YACR,KAAK,UAAU;gBACb,IAAI,OAAO,KAAK,iBAAiB,EAAE;oBACjC,eAAe,GAAG,EAAE,CAAC;iBACtB;gBACD,MAAM;YACR,KAAK,+BAA+B;gBAClC,eAAe,GAAG,sBAAsB,CAAC;gBACzC,MAAM;YACR,KAAK,iCAAiC,CAAC;YACvC,KAAK,iCAAiC;gBACpC,IAAI,OAAO,KAAK,cAAc,EAAE;oBAC9B,6EAA6E;oBAC7E,gCAAgC;oBAChC,uCAAuC;oBACvC,MAAM;iBACP;qBAAM;oBACL,eAAe,GAAG,mBAAmB,CAAC;iBACvC;gBACD,MAAM;YACR,KAAK,0CAA0C;gBAC7C,eAAe,GAAG,mCAAmC,CAAC;gBACtD,MAAM;YACR,KAAK,uCAAuC;gBAC1C,eAAe,GAAG,+BAA+B,CAAC;gBAClD,MAAM;YACR,KAAK,sDAAsD;gBACzD,eAAe,GAAG,0BAA0B,CAAC;gBAC7C,MAAM;YACR,KAAK,eAAe;gBAClB,eAAe,GAAG,wBAAwB,CAAC;gBAC3C,MAAM;YACR,KAAK,mDAAmD;gBACtD,IAAI,OAAO,KAAK,4BAA4B,EAAE;oBAC5C,eAAe,GAAG,4BAA4B,CAAC;iBAChD;qBAAM;oBACL,eAAe,GAAG,4BAA4B,CAAC;iBAChD;gBACD,MAAM;YACR,KAAK,gBAAgB;gBACnB,eAAe,GAAG,4BAA4B,CAAC;gBAC/C,MAAM;YACR,KAAK,SAAS;gBACZ,eAAe,GAAG,kBAAkB,CAAC;gBACrC,MAAM;YACR,KAAK,iBAAiB;gBACpB,eAAe,GAAG,0BAA0B,CAAC;gBAC7C,MAAM;YACR,KAAK,gBAAgB,CAAC;YACtB,KAAK,iCAAiC;gBACpC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBAC5B,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE;oBACrB,eAAe,GAAG,yBAAyB,CAAC;iBAC7C;gBACD,MAAM;YACR,KAAK,eAAe;gBAClB,IAAI,OAAO,KAAK,aAAa,EAAE;oBAC7B,oEAAoE;iBACrE;gBACD,MAAM;YACR,KAAK,gBAAgB;gBACnB,IAAI,OAAO,KAAK,aAAa,IAAI,OAAO,KAAK,wBAAwB,IAAI,OAAO,KAAK,2BAA2B,EAAE;oBAChH,qEAAqE;oBACrE,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;oBAC5B,IAAI,MAAM,CAAC,IAAI,EAAE;wBACf,eAAe,IAAI,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;qBACvC;iBACF;gBACD,MAAM;YACR,KAAK,UAAU,CAAC;YAChB,KAAK,EAAE;gBACL,MAAM;YACR,KAAK,MAAM;gBACT,IAAI,OAAO,KAAK,iBAAiB,IAAI,OAAO,KAAK,iBAAiB,IAAI,OAAO,KAAK,kBAAkB,IAAI,OAAO,KAAK,yBAAyB,IAAI,OAAO,KAAK,wBAAwB,EAAE;oBACrL,eAAe,GAAG,GAAG,CAAC;iBACvB;gBACD,MAAM;YACR,KAAK,gBAAgB;gBACnB,eAAe,GAAG,qBAAqB,CAAC;gBACxC,MAAM;YACR;gBACE,eAAe,GAAG,KAAK,CAAC;SAC3B;QACD,IAAI,KAAK,CAAC,OAAO,CAAC,0BAA0B,CAAC,GAAG,CAAC,CAAC,EAAE;YAClD,eAAe,GAAG,yBAAyB,CAAC;SAC7C;QACD,IAAI,eAAe,KAAK,EAAE,EAAE;YAC1B,KAAK,CAAC,eAAe,CAAC,CAAC;SACxB;IACH,CAAC;IAGO,qCAAY,GAApB,UAAqB,OAAO,EAAE,MAAM,EAAE,MAAM;QAC1C,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,oBAAoB,GAAG,OAAO,GAAG,oBAAoB,CAAC,CAAC;QACrE,IAAM,KAAK,GAAG;YACZ,YAAY,EAAE,MAAM;YACpB,OAAO,EAAE,MAAM;SAChB,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QACrB,IAAI;YACF,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;SACnC;QAAC,OAAO,CAAC,EAAE;YACV,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAC,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAC,CAAC,CAAC;SAC1D;IACH,CAAC;IAEO,8BAAK,GAAb,UAAc,IAAI;QAChB,OAAO,EAAC,CAAC,EAAE,IAAI,EAAC,CAAC;IACnB,CAAC;IAEO,wCAAe,GAAvB,UAAwB,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO;QAC1D,IAAI,MAAM,GAAG,SAAS,CAAC;QACvB,IAAI,OAAO,KAAK,eAAe,EAAE;YAC/B,IAAI,CAAC,SAAS,IAAI,SAAS,KAAK,EAAE,EAAE;gBAClC,MAAM,GAAG,EAAE,CAAC;aACb;iBAAM;gBACL,IAAI;oBACF,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;iBAChC;gBAAC,OAAO,CAAC,EAAE;oBACV,MAAM,GAAG,EAAC,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,EAAC,CAAC;iBACvD;aACF;SACF;aAAM;YACL,MAAM,GAAG;gBACP,UAAU,EAAE,IAAI;gBAChB,aAAa,EAAE,MAAM;aACtB,CAAC;SACH;QAED,IAAM,MAAM,GAAG,CAAC,MAAM,CAAC,UAAU,KAAK,IAAI,IAAI,MAAM,CAAC,UAAU,KAAK,MAAM,CAAC,CAAC;QAE5E,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,EAAE;YACtE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,0BAA0B,GAAG,OAAO,GAAG,iBAAiB,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;SAC7F;QACD,IAAM,IAAI,GAAG,CAAC,CAAC,OAAO,MAAM,KAAK,QAAQ,CAAC,IAAI,eAAe,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC;QAEzG,IAAI,cAAc,GAAG,KAAK,CAAC;QAC3B,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,YAAY,IAAI,MAAM,IAAI,MAAM,CAAC,UAAU,KAAK,IAAI,IAAI,MAAM,CAAC,UAAU,KAAK,MAAM,IAAI,MAAM,CAAC,UAAU,KAAK,OAAO,EAAE;YACvJ,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;YACrD,cAAc,GAAG,MAAM,CAAC,UAAU,CAAC;SACpC;QAED,sCAAsC;QACtC,4FAA4F;QAC5F,IAAI;QAEJ,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE;YAClC,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;SACxC;aAAM;YACL,OAAO,IAAI,CAAC;SACb;IACH,CAAC;IAGO,mCAAU,GAAlB,UAAmB,OAAO,EAAE,MAAO,EAAE,QAAS;QAC5C,IAAI,IAAI,CAAC,aAAa,EAAE;YACtB,IAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YAC3C,IAAI,CAAC,MAAM,EAAE;gBACX,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,8BAA8B,GAAG,OAAO,GAAG,iCAAiC,CAAC,CAAC;aAC7F;iBAAM;gBACL,IAAM,MAAI,GAAG,IAAI,CAAC;gBAClB,MAAM,GAAG,CAAC,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;gBACxE,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,IAAI,EAAE;oBAC3C,MAAM,CAAC,UAAU,SAAS;wBACxB,MAAI,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;wBAC9C,OAAO,MAAI,CAAC,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;oBACpE,CAAC,CAAC,CAAC;iBACJ;qBAAM;oBACL,MAAM,CAAC,MAAM,EAAE,UAAU,SAAS;wBAChC,MAAI,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;wBAC9C,OAAO,MAAI,CAAC,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;oBACpE,CAAC,CAAC,CAAC;iBACJ;aACF;SACF;IACH,CAAC;IAGD,uCAAc,GAAd,UAAe,OAAO,EAAE,QAAQ;QAC9B,IAAI,OAAO,KAAK,eAAe,EAAE;YAC/B,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;SAC/C;aAAM;YACL,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,UAAC,GAAG;gBACtC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;YAC5B,CAAC,CAAC,CAAC;SACJ;IACH,CAAC;IAGD,oCAAW,GAAX;QAAA,iBAkBC;QAjBC,OAAO,IAAI,+CAAU,CACnB,kBAAQ;YACN,IAAI,CAAC,KAAI,CAAC,aAAa,EAAE;gBACvB,KAAI,CAAC,aAAa,GAAG,IAAI,CAAC;gBAC1B,IAAM,MAAI,GAAG,KAAI,CAAC;gBACZ,MAAO,CAAC,WAAW,CAAO,MAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,UAAU,OAAO;oBAC/E,MAAI,CAAC,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC;oBACrD,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACtB,CAAC,CAAC,CAAC;aACJ;iBAAM;gBACL,IAAI,CAAC,KAAI,CAAC,aAAa,EAAE;oBACvB,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;oBACxB,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;iBACzB;aACF;QACH,CAAC,CACF,CAAC;IACJ,CAAC;IAGD,6CAAoB,GAApB;QACE,OAAO,IAAI,CAAC,UAAU,CAAC,wBAAwB,CAAC,CAAC;IACnD,CAAC;IAED,oCAAW,GAAX;QACE,OAAO,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;IAC5C,CAAC;IAED,mCAAU,GAAV,UAAW,QAAQ;QACjB,IAAI,CAAC,UAAU,CAAC,cAAc,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC;IAChD,CAAC;IAED,qCAAY,GAAZ,UAAa,QAAS;QACpB,IAAI,CAAC,UAAU,CAAC,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC9E,CAAC;IAED,yCAAgB,GAAhB,UAAiB,IAAI,EAAE,QAAQ;QAC7B,IAAI,CAAC,UAAU,CAAC,qBAAqB,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IACzD,CAAC;IAED,2CAAkB,GAAlB,UAAmB,QAAQ;QAA3B,iBAWC;QAVC,IAAK,IAAI,CAAC,gBAAgB,CAAC,OAAO,KAAK,EAAE,EAAG;YAC1C,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC;SACxB;QACD,IAAM,OAAO,GAAG,EAAE,CAAC;QACnB,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,UAAC,MAAM;YAC3C,OAAO,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAC,CAAC,CAAC;QAC1E,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,aAAa,CAAC,uBAAuB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,UAAC,SAAS;YAC5G,KAAI,CAAC,eAAe,CAAC,SAAS,EAAE,EAAE,EAAE,QAAQ,EAAE,uBAAuB,CAAC,CAAC;QACzE,CAAC,CAAC,CAAC;IACL,CAAC;IAED,0CAAiB,GAAjB,UAAkB,QAAQ;QACxB,IAAI,CAAC,UAAU,CAAC,sBAAsB,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC;IACxD,CAAC;IAED,uCAAc,GAAd,UAAe,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ;QACtD,IAAM,GAAG,GAAG,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC;QAC9C,IAAM,MAAM,GAAG;YACb,OAAO,EAAE,OAAO;YAChB,QAAQ,EAAE,QAAQ;YAClB,WAAW,EAAE,GAAG;SACjB,CAAC;QACF,IAAI,CAAC,UAAU,CAAC,sBAAsB,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC5D,CAAC;IAED,uCAAc,GAAd,UAAe,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ;QACtD,IAAM,GAAG,GAAG,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC;QAC9C,IAAM,MAAM,GAAG;YACb,OAAO,EAAE,OAAO;YAChB,QAAQ,EAAE,QAAQ;YAClB,WAAW,EAAE,GAAG;SACjB,CAAC;QACF,IAAI,CAAC,UAAU,CAAC,sBAAsB,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC5D,CAAC;IAED,uCAAc,GAAd,UAAe,IAAI,EAAE,IAAI,EAAE,QAAQ;QACjC,IAAM,MAAM,GAAG;YACb,IAAI,EAAE,IAAI;YACV,IAAI,EAAE,IAAI;SACX,CAAC;QACF,IAAI,CAAC,UAAU,CAAC,iBAAiB,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IACvD,CAAC;IAED,mCAAU,GAAV,UAAW,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ;QACxC,IAAM,MAAM,GAAG;YACb,IAAI,EAAE,IAAI;YACV,IAAI,EAAE,IAAI;SACX,CAAC;QACF,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACpC,IAAI,CAAC,UAAU,CAAC,aAAa,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IACnD,CAAC;IAED,oCAAW,GAAX,UAAY,SAAS,EAAE,QAAQ;QAC7B,IAAI,CAAC,UAAU,CAAC,cAAc,EAAE,EAAC,SAAS,EAAE,SAAS,EAAC,EAAE,QAAQ,CAAC,CAAC;IACpE,CAAC;IAED,yCAAgB,GAAhB,UAAiB,SAAS,EAAE,QAAQ;QAClC,IAAI,CAAC,UAAU,CAAC,qBAAqB,EAAE,EAAC,SAAS,EAAE,CAAC,SAAS,EAAC,EAAE,QAAQ,CAAC,CAAC;IAC5E,CAAC;IAED,kCAAS,GAAT,UAAU,SAAS,EAAE,QAAQ;QAC3B,IAAI,CAAC,UAAU,CAAC,YAAY,EAAE,EAAC,SAAS,EAAE,CAAC,SAAS,EAAC,EAAE,QAAQ,CAAC,CAAC;IACnE,CAAC;IAED,iDAAwB,GAAxB,UAAyB,IAAI,EAAE,QAAQ;QACrC,IAAI,CAAC,UAAU,CAAC,8BAA8B,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IAClE,CAAC;IAED,sCAAa,GAAb,UAAc,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ;QAC7C,IAAM,MAAM,GAAG;YACb,WAAW,EAAE,WAAW;YACxB,IAAI,EAAE,IAAI;YACV,IAAI,EAAE,IAAI;SACX,CAAC;QACF,IAAI,CAAC,UAAU,CAAC,gBAAgB,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IACtD,CAAC;IAGD,kCAAS,GAAT,UAAU,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ;QACzE,IAAM,MAAM,GAAG;YACb,SAAS,EAAE,QAAQ,CAAC,cAAc,EAAE,EAAE,CAAC;YACvC,YAAY,EAAE;gBACZ;oBACE,OAAO,EAAE,UAAU;oBACnB,MAAM,EAAE,MAAM;iBACf;aACF;YACD,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAC9C,SAAS,EAAE,CAAC;YACZ,GAAG,EAAE,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,GAAG,CAAC;YACvC,OAAO,EAAE,OAAO;YAChB,UAAU,EAAE,IAAI;SACjB,CAAC;QACF,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAChD,CAAC;IAED,wCAAe,GAAf,UAAgB,OAAO,EAAE,QAAQ;QAC/B,IAAI,CAAC,UAAU,CAAC,kBAAkB,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IACzD,CAAC;IAED,qCAAY,GAAZ,UAAa,GAAG,EAAE,QAAS;QACzB,OAAO,IAAI,CAAC,UAAU,CAAC,eAAe,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;IACzD,CAAC;IAED,qCAAY,GAAZ,UAAa,QAAQ;QACnB,OAAO,IAAI,CAAC,UAAU,CAAC,eAAe,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC;IACxD,CAAC;IAED,uCAAc,GAAd,UAAe,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ;QAC9G,IAAM,MAAM,GAAG;YACb,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC;YAClC,OAAO,EAAE;gBACP,CAAC,EAAE,KAAK;gBACR,CAAC,EAAE,OAAO;gBACV,MAAM,EAAE,MAAM;gBACd,MAAM,EAAE,MAAM;gBACd,MAAM,EAAE,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,MAAM,CAAC;gBAC7C,QAAQ,EAAE,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,MAAM,CAAC;gBACzF,QAAQ,EAAE,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,QAAQ,CAAC;aAClD;YACD,UAAU,EAAE,UAAU;YACtB,iBAAiB,EAAE,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE;YAC/C,GAAG,EAAE,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,MAAM,CAAC;YAC1C,KAAK,EAAE,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,MAAM,CAAC;SAC7C,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QACtB,IAAI,CAAC,UAAU,CAAC,iBAAiB,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IACvD,CAAC;IAED,qCAAY,GAAZ,UAAa,SAAS,EAAE,QAAQ;QAC9B,IAAM,MAAM,GAAG;YACb,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC;SACnC,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QACtB,IAAI,CAAC,UAAU,CAAC,eAAe,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IACrD,CAAC;IAED,uCAAc,GAAd,UAAe,SAAS,EAAE,WAAW,EAAE,QAAQ;QAC7C,IAAM,MAAM,GAAG;YACb,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC;YAClC,WAAW,EAAE,WAAW;SACzB,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QACtB,IAAI,CAAC,UAAU,CAAC,iBAAiB,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IACvD,CAAC;IAED,wCAAe,GAAf,UAAgB,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ;QAC5D,IAAM,MAAM,GAAG;YACb,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC;YAClC,WAAW,EAAE,WAAW;YACxB,YAAY,EAAE,YAAY,CAAC,qBAAqB;SACjD,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QACtB,IAAI,CAAC,UAAU,CAAC,kBAAkB,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IACxD,CAAC;IAED,8CAAqB,GAArB,UAAsB,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ;QAC1D,IAAM,MAAM,GAAG;YACb,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC;YAClC,WAAW,EAAE,WAAW;YACxB,GAAG,EAAE,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,MAAM,CAAC;YAC1C,iBAAiB,EAAE,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE;SAChD,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QACtB,IAAI,CAAC,UAAU,CAAC,yBAAyB,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC/D,CAAC;IAED,6CAAoB,GAApB,UAAqB,SAAS,EAAE,WAAW,EAAE,QAAQ;QACnD,IAAM,MAAM,GAAG;YACb,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC;YAClC,WAAW,EAAE,WAAW;SACzB,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QACtB,IAAI,CAAC,UAAU,CAAC,wBAAwB,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC9D,CAAC;IAED,yCAAgB,GAAhB,UAAiB,SAAS,EAAE,QAAQ;QAClC,IAAI,CAAC,UAAU,CAAC,oBAAoB,EAAE,EAAC,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,EAAC,EAAE,QAAQ,CAAC,CAAC;IACxF,CAAC;IAED,uCAAc,GAAd,UAAe,SAAS,EAAE,QAAS;QACjC,IAAI,CAAC,UAAU,CAAC,kBAAkB,EAAE,EAAC,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,EAAC,EAAE,QAAQ,CAAC,CAAC;IACtF,CAAC;IAED,sCAAa,GAAb,UAAc,SAAS,EAAE,QAAS;QAChC,IAAI,CAAC,UAAU,CAAC,iBAAiB,EAAE,EAAC,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,EAAC,EAAE,QAAQ,CAAC,CAAC;IACrF,CAAC;IAvcU,cAAc;QAD1B,gEAAU,EAAE;yCAM2B,mEAAgB,EAA0B,uEAAc;OALnF,cAAc,CAyc1B;IAAD,qBAAC;CAAA;AAzc0B;AA4c3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2ME;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7pBsD;AAEnB;AACJ;AACM;AACkC;AAKzE;IA0CE,0BAAoB,MAAc,EAAU,MAAc,EAAU,kBAAsC;QAA1G,iBACC;QADmB,WAAM,GAAN,MAAM,CAAQ;QAAU,WAAM,GAAN,MAAM,CAAQ;QAAU,uBAAkB,GAAlB,kBAAkB,CAAoB;QAxCnG,YAAO,GAAG,EAAE,CAAC;QACb,oBAAe,GAAG,CAAC,CAAC;QACpB,iBAAY,GAAG,MAAM,CAAC;QACtB,oBAAe,GAAG,KAAK,CAAC;QAExB,eAAU,GAAG,CAAC,CAAC;QACf,eAAU,GAAG,CAAC,CAAC;QACf,iBAAY,GAAG,CAAC,CAAC;QACjB,SAAI,GAAG;YACZ,cAAc,EAAE,CAAC;YACjB,mBAAmB,EAAE,GAAG;SACzB,CAAC;QAEK,aAAQ,GAAG;YAChB,KAAK,EAAE,EAAE;YACT,QAAQ,EAAE,IAAI;YACd,YAAY,EAAE,GAAG;YACjB,eAAe,EAAE,EAAE;YACnB,kBAAkB,EAAE,EAAE;SACvB,CAAC;QAEK,YAAO,GAAkB,EAAE,CAAC;QAGnC,sBAAiB,GAAG,IAAI,oDAAe,CAAC,IAAI,CAAC,CAAC;QAC9C,4BAAuB,GAAG,IAAI,oDAAe,CAAC,IAAI,CAAC,CAAC;QAE7C,SAAI,GAAG,IAAI,gDAAI,EAAE;aACrB,kBAAkB,EAAE;aACpB,MAAM,CAAC,EAAE,CAAC;aACV,EAAE,CAAC;YACF,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;gBACd,KAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;gBACjB,KAAI,CAAC,OAAO,GAAG,EAAE,CAAC;gBAClB,KAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAC,WAAW,EAAE,EAAC,IAAI,EAAE,MAAM,EAAC,EAAC,CAAC,CAAC;YAClE,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IAKL,CAAC;IAED,uCAAY,GAAZ,UAAa,MAAc;QACzB,IAAI,MAAM,KAAK,IAAI,CAAC,UAAU,EAAE;YAC9B,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC;YACzB,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;SACrC;IACH,CAAC;IAED,6CAAkB,GAAlB,UAAmB,SAAiB;QAClC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACzC,CAAC;IAED,2CAAgB,GAAhB,UAAiB,EAAE;QAAnB,iBAMC;QALC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,UAAC,MAAM;YAC1B,IAAI,MAAM,CAAC,SAAS,KAAK,EAAE,EAAE;gBAC3B,KAAI,CAAC,aAAa,GAAG,MAAM,CAAC;aAC7B;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,oCAAS,GAAT,UAAU,EAAE;QACV,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YAC5C,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,EAAE,EAAE;gBACpC,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;aACxB;SACF;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,yCAAc,GAAd;QACE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;IACtB,CAAC;IAED,wCAAa,GAAb;QACE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACnB,CAAC;IAEM,wCAAa,GAApB,UAAqB,MAAkB;QACrC,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;QACzE,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QACrE,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,KAAK,UAAU,IAAI,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE;YAClK,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC;gBAChC,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,KAAK,EAAE,MAAM;gBACb,IAAI,EAAE,MAAM,CAAC,MAAM;aACpB,CAAC,CAAC;YACH,MAAM,CAAC,cAAc,EAAE,CAAC;YACxB,MAAM,CAAC,eAAe,EAAE,CAAC;SAC1B;IACH,CAAC;IArDQ;QAAR,2DAAK,EAAE;kCAAc,oEAAoB;yDAAC;IAxChC,gBAAgB;QAH5B,gEAAU,CAAC;YACV,UAAU,EAAE,MAAM;SACnB,CAAC;yCA2C4B,sDAAM,EAAkB,oDAAM,EAA8B,kEAAkB;OA1C/F,gBAAgB,CA+F5B;IAAD,uBAAC;CAAA;AA/F4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVY;AACc;AAEvD,aAAa;AACyC;AACG;AACG;AACN;AACS;AACA;AACM;AACH;AACA;AACiB;AACpB;AACG;AACc;AACN;AACS;AACT;AACS;AAEnF,IAAM,MAAM,GAAW;IACrB;QACE,IAAI,EAAE,EAAE;QACR,SAAS,EAAE,kEAAa;KACzB;IACD;QACE,IAAI,EAAE,MAAM;QACZ,SAAS,EAAE,kEAAa;KACzB;IACD;QACE,IAAI,EAAE,OAAO;QACb,SAAS,EAAE,qEAAc;KAC1B;IACD;QACE,IAAI,EAAE,YAAY;QAClB,SAAS,EAAE,wEAAe;QAC1B,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAM;gBACZ,SAAS,EAAE,kEAAa;aACzB;YACD;gBACE,IAAI,EAAE,SAAS;gBACf,SAAS,EAAE,2EAAgB;aAC5B;YACD;gBACE,IAAI,EAAE,SAAS;gBACf,SAAS,EAAE,2EAAgB;aAC5B;YACD;gBACE,IAAI,EAAE,WAAW;gBACjB,SAAS,EAAE,iFAAkB;aAC9B;YACD;gBACE,IAAI,EAAE,UAAU;gBAChB,SAAS,EAAE,8EAAiB;aAC7B;YACD;gBACE,IAAI,EAAE,cAAc;gBACpB,SAAS,EAAE,8EAAiB;aAC7B;YACD;gBACE,IAAI,EAAE,UAAU;gBAChB,SAAS,EAAE,+EAAiB;aAC7B;YACD;gBACE,IAAI,EAAE,cAAc;gBACpB,SAAS,EAAE,gGAAsB;aAClC;YACD;gBACE,IAAI,EAAE,SAAS;gBACf,SAAS,EAAE,4EAAgB;aAC5B;YACD;gBACE,IAAI,EAAE,EAAE;gBACR,UAAU,EAAE,MAAM;gBAClB,SAAS,EAAE,MAAM;aAClB;SACF;KACF;IACD;QACE,IAAI,EAAE,QAAQ;QACd,SAAS,EAAE,6FAAqB;KACjC;IACD;QACE,IAAI,EAAE,MAAM;QACZ,SAAS,EAAE,uFAAmB;KAC/B;IACD;QACE,IAAI,EAAE,SAAS;QACf,SAAS,EAAE,gGAAsB;KAClC;IACD;QACE,IAAI,EAAE,aAAa;QACnB,SAAS,EAAE,uFAAmB;KAC/B;IACD;QACE,IAAI,EAAE,SAAS;QACf,SAAS,EAAE,gGAAsB;KAClC;IACD;QACE,IAAI,EAAE,UAAU;QAChB,SAAS,EAAE,+EAAiB;KAC7B;IACD;QACE,IAAI,EAAE,EAAE;QACR,UAAU,EAAE,GAAG;QACf,SAAS,EAAE,MAAM;KAClB;CACF,CAAC;AAQF;IAAA;IAAgC,CAAC;IAApB,gBAAgB;QAN5B,8DAAQ,CAAC;YACR,OAAO,EAAE,CAAC,4DAAY,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YACvC,OAAO,EAAE,CAAC,4DAAY,CAAC;SACxB,CAAC;OAGW,gBAAgB,CAAI;IAAD,uBAAC;CAAA;AAAJ;;;;;;;;;;;;ACvH7B,2gB;;;;;;;;;;;ACAA,wEAAwE,kBAAkB,wBAAwB,uBAAuB,gBAAgB,EAAE,iDAAiD,+uH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACA9H;AAC9B;AACK;AACc;AAC5B;AACgC;AAOvE;IAKE,sBACU,IAAgB,EAChB,QAAmB,EACpB,SAA2B,EAC1B,OAAuB,EACvB,MAAc,EACd,gBAAkC,EAClC,MAAc;QANd,SAAI,GAAJ,IAAI,CAAY;QAChB,aAAQ,GAAR,QAAQ,CAAW;QACpB,cAAS,GAAT,SAAS,CAAkB;QAC1B,YAAO,GAAP,OAAO,CAAgB;QACvB,WAAM,GAAN,MAAM,CAAQ;QACd,qBAAgB,GAAhB,gBAAgB,CAAkB;QAClC,WAAM,GAAN,MAAM,CAAQ;QATxB,kBAAa,GAAG,KAAK,CAAC;QAWpB,SAAS,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QACjC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QAC/B,kDAAkD;QAClD,kEAAkE;IACpE,CAAC;IAED,+BAAQ,GAAR;QAAA,iBAgWC;QA/VC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,SAAS,CAAC,qBAAW;YAC9C,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,WAAW,CAAC,CAAC;YAE3C,KAAI,CAAC,OAAO,CAAC,oBAAoB,EAAE,CAAC;YAEpC,KAAI,CAAC,OAAO,CAAC,cAAc,CAAC,gBAAgB,EAAE;gBAC5C,IAAI,CAAC,KAAI,CAAC,aAAa,EAAE;oBACvB,KAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC;wBAC9B,KAAI,CAAC,OAAO,CAAC,YAAY,CAAC;4BACxB,IAAM,qBAAqB,GAAG;gCAC5B,IAAI,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,MAAM,EAAE;oCACxC,IAAM,WAAS,GAAG,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;oCAC3D,KAAI,CAAC,OAAO,CAAC,WAAW,CAAC,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,WAAS,CAAC,CAAC,SAAS,EAAE;wCAC3E,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,MAAM,CAAC,WAAS,EAAE,CAAC,CAAC,CAAC;wCACnD,qBAAqB,EAAE,CAAC;oCAC1B,CAAC,CAAC,CAAC;iCACJ;qCAAM;oCACL,KAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;iCAC5B;4BACH,CAAC,CAAC;4BACF,qBAAqB,EAAE,CAAC;wBAC1B,CAAC,CAAC,CAAC;oBACL,CAAC,CAAC,CAAC;iBACJ;gBACD,KAAI,CAAC,aAAa,GAAG,IAAI,CAAC;YAC5B,CAAC,CAAC,CAAC;YAGH,KAAI,CAAC,OAAO,CAAC,cAAc,CAAC,sBAAsB,EAAE,UAAC,IAAI;gBACvD,OAAO,CAAC,GAAG,CAAC,0DAA0D,CAAC,CAAC;gBACxE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAElB,IAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;gBACvC,IAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;gBACjC,IAAM,MAAM,GAAG,KAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAE/D,8BAA8B;gBAC9B,IAAI,MAAM,EAAE;oBACV,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;wBACd,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC;wBACtB,MAAM,CAAC,OAAO,GAAG,SAAS,CAAC;wBAC3B,IAAI,YAAY,KAAK,CAAC,EAAE,EAAE,QAAQ;4BAChC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC;yBACtB;wBACD,IAAI,YAAY,KAAK,CAAC,EAAE,EAAE,QAAQ;4BAChC,qBAAqB;yBACtB;wBACD,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;wBAC9B,MAAM,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,CAAC;wBAChD,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC;oBACzC,CAAC,CAAC,CAAC;iBACJ;YACH,CAAC,CAAC,CAAC;YAGH,KAAI,CAAC,OAAO,CAAC,cAAc,CAAC,sBAAsB,EAAE,UAAC,IAAI;gBACvD,OAAO,CAAC,GAAG,CAAC,0DAA0D,CAAC,CAAC;gBACxE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAElB,IAAM,MAAM,GAAG,KAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAC/D,IAAI,MAAM,EAAE;oBACV,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;wBACd,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;wBAChC,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,EAAE;4BACzB,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC;yBACvB;6BAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,GAAG,EAAE;4BAClC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC;yBACtB;oBACH,CAAC,CAAC,CAAC;iBACJ;YACH,CAAC,CAAC,CAAC;YAGH,KAAI,CAAC,OAAO,CAAC,cAAc,CAAC,qBAAqB,EAAE,UAAC,IAAI;gBACtD,OAAO,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;gBACvE,OAAO,CAAC,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,oBAAoB,CAAC,CAAC;gBACnD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAClB,KAAI,CAAC,gBAAgB,CAAC,UAAU,GAAG,IAAI,CAAC,6BAA6B,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC;gBACjF,kDAAkD;gBAClD,KAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAEhD,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;oBACd,KAAI,CAAC,gBAAgB,CAAC,YAAY,GAAG,IAAI,CAAC,oBAAoB,CAAC;oBAC/D,IAAI,IAAI,CAAC,oBAAoB,KAAK,CAAC,EAAE;wBACnC,IAAM,GAAG,GAAG,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,4BAA4B,CAAC;wBACzE,IAAM,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,4BAA4B,CAAC;wBAChE,IAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;wBACjE,IAAI,GAAG,KAAK,CAAC,IAAI,UAAU,GAAG,CAAC,EAAE;4BAC/B,KAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC;4BAC9C,KAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,mBAAmB,GAAG,MAAM,CAAC;yBACzD;6BAAM,IAAI,UAAU,IAAI,GAAG,EAAE;4BAC5B,KAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,cAAc,GAAG,GAAG,CAAC;4BAChD,KAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,mBAAmB,GAAG,OAAO,CAAC;yBAC1D;6BAAM;4BACL,KAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,cAAc,GAAG,UAAU,CAAC;4BACvD,KAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,mBAAmB,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;yBACxE;qBACF;gBACH,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,KAAI,CAAC,OAAO,CAAC,cAAc,CAAC,gBAAgB,EAAE,UAAC,IAAI;gBACjD,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;gBAClE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAElB,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE;oBACZ,OAAO;iBACR;gBAED,IAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;gBACjC,IAAM,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC;gBAExB,IAAM,IAAI,GAAG,KAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;gBAExD,IAAI,IAAI,EAAE;oBACR,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;wBAEd,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;4BAChB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;4BAC5B,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,CAAC;yBAC/C;6BAAM;4BACL,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;4BAC5B,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,CAAC;yBAC/C;wBAED,IAAI,OAAO,CAAC,OAAO,KAAK,CAAC,EAAE;4BACzB,KAAI,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;yBACrD;wBAED,IAAI,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,cAAI,IAAI,WAAI,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,EAAhC,CAAgC,CAAC,CAAC;wBACrF,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,cAAI,IAAI,WAAI,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,EAAhC,CAAgC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;wBAEnG,IAAI,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;wBAE/B,IAAI,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE;4BACtC,IAAM,UAAU,GAAG,KAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC;4BACpD,IAAM,UAAU,GAAG,KAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC;4BAEpD,IAAM,UAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;4BAErC,IAAI,SAAS,EAAE;gCACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;oCAC9C,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,WAAW,KAAK,UAAQ,CAAC,WAAW,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,UAAQ,CAAC,IAAI,EAAE;wCACtG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,sBAAsB,GAAG,UAAQ,CAAC,sBAAsB,CAAC;wCAC3E,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,eAAe,GAAG,UAAQ,CAAC,eAAe,CAAC;wCAC7D,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,UAAQ,CAAC,MAAM,CAAC;wCAC3C,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,UAAQ,CAAC,SAAS,CAAC;wCACjD,MAAM;qCACP;iCACF;gCACD,oCAAoC;gCACpC,OAAO;6BACR;4BAED,IAAI,UAAQ,CAAC,KAAK,KAAK,CAAC,IAAI,UAAQ,CAAC,eAAe,GAAG,UAAU,EAAE;gCACjE,UAAQ,CAAC,KAAK,GAAG,GAAG,CAAC;6BACtB;iCAAM,IAAI,UAAQ,CAAC,KAAK,KAAK,CAAC,IAAI,UAAQ,CAAC,sBAAsB,GAAG,UAAU,EAAE;gCAC/E,UAAQ,CAAC,KAAK,GAAG,GAAG,CAAC;6BACtB;iCAAM,IAAI,UAAQ,CAAC,KAAK,KAAK,CAAC,EAAE;gCAC/B,IAAM,aAAa,GAAG,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,CAAC,cAAI,IAAI,WAAI,CAAC,KAAK,KAAK,GAAG,IAAI,IAAI,CAAC,IAAI,KAAK,UAAQ,CAAC,IAAI,IAAI,IAAI,CAAC,WAAW,KAAK,UAAQ,CAAC,WAAW,EAA9F,CAA8F,CAAC,CAAC;gCACrL,IAAI,aAAa,EAAE;oCACjB,IAAI,aAAa,CAAC,IAAI,KAAK,UAAQ,CAAC,eAAe,EAAE;wCACnD,UAAQ,CAAC,KAAK,GAAG,GAAG,CAAC;qCACtB;yCAAM;wCACL,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;4CACjF,IAAI,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,WAAW,KAAK,UAAQ,CAAC,WAAW,IAAI,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,UAAQ,CAAC,IAAI,EAAE;gDAC5K,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gDAC/D,MAAM;6CACP;yCACF;wCACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,eAAe,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;4CAC9E,IAAI,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,WAAW,KAAK,UAAQ,CAAC,WAAW,IAAI,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,UAAQ,CAAC,IAAI,EAAE;gDACtK,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gDAC5D,MAAM;6CACP;yCACF;qCACF;iCACF;6BACF;iCAAM,IAAI,UAAQ,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,UAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,UAAU,GAAG,UAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE;gCACjG,UAAQ,CAAC,KAAK,GAAG,GAAG,CAAC;6BACtB;iCAAM,IAAI,UAAQ,CAAC,KAAK,KAAK,CAAC,EAAE;gCAC/B,IAAM,aAAa,GAAG,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,CAAC,cAAI,IAAI,WAAI,CAAC,KAAK,KAAK,GAAG,IAAI,IAAI,CAAC,IAAI,KAAK,UAAQ,CAAC,IAAI,IAAI,IAAI,CAAC,WAAW,KAAK,UAAQ,CAAC,WAAW,EAA9F,CAA8F,CAAC,CAAC;gCAClL,IAAI,aAAa,EAAE;oCACjB,UAAQ,CAAC,KAAK,GAAG,GAAG,CAAC;iCACtB;6BACF;iCAAM,IAAI,UAAQ,CAAC,KAAK,KAAK,CAAC,EAAE;gCAC/B,IAAM,aAAa,GAAG,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,CAAC,cAAI,IAAI,WAAI,CAAC,KAAK,KAAK,GAAG,IAAI,IAAI,CAAC,IAAI,KAAK,UAAQ,CAAC,IAAI,IAAI,IAAI,CAAC,WAAW,KAAK,UAAQ,CAAC,WAAW,EAA9F,CAA8F,CAAC,CAAC;gCACrL,IAAI,aAAa,EAAE;oCACjB,IAAI,aAAa,CAAC,IAAI,KAAK,UAAQ,CAAC,sBAAsB,EAAE;wCAC1D,UAAQ,CAAC,KAAK,GAAG,GAAG,CAAC;qCACtB;yCAAM;wCACL,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;4CACjF,IAAI,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,WAAW,KAAK,UAAQ,CAAC,WAAW,IAAI,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,UAAQ,CAAC,IAAI,EAAE;gDAC5K,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gDAC/D,MAAM;6CACP;yCACF;wCACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,eAAe,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;4CAC9E,IAAI,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,WAAW,KAAK,UAAQ,CAAC,WAAW,IAAI,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,UAAQ,CAAC,IAAI,EAAE;gDACtK,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gDAC5D,MAAM;6CACP;yCACF;qCACF;iCACF;6BACF;iCAAM,IAAI,UAAQ,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,UAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,UAAU,GAAG,UAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE;gCACjG,UAAQ,CAAC,KAAK,GAAG,GAAG,CAAC;6BACtB;4BAED,IAAM,YAAY,GAAG,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,CAAC,cAAI,IAAI,WAAI,CAAC,KAAK,KAAK,UAAQ,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,KAAK,UAAQ,CAAC,IAAI,IAAI,IAAI,CAAC,WAAW,KAAK,UAAQ,CAAC,WAAW,EAAzG,CAAyG,CAAC,CAAC;4BAC5L,UAAQ,CAAC,MAAM,GAAG,CAAC,YAAY,CAAC;4BAEhC,UAAQ,CAAC,kBAAkB,CAAC,CAAC,QAAQ,IAAI,UAAQ,CAAC,kBAAkB,CAAC,CAAC,MAAM,CAAC;4BAE7E,IAAI,YAAY,GAAG,KAAK,CAAC;4BACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;gCAC9C,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,WAAW,KAAK,UAAQ,CAAC,WAAW,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,UAAQ,CAAC,IAAI,EAAE;oCACtG,KAAK,IAAM,IAAI,IAAI,UAAQ,EAAE;wCAC3B,IAAI,UAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE;4CACjC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,UAAQ,CAAC,IAAI,CAAC,CAAC;yCAC1C;qCACF;oCACD,YAAY,GAAG,IAAI,CAAC;oCACpB,MAAM;iCACP;6BACF;4BACD,IAAI,YAAY,KAAK,KAAK,EAAE;gCAC1B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,UAAQ,CAAC,CAAC;6BAC/B;4BACD,IAAI,CAAC,mBAAmB,EAAE,CAAC;yBAC5B;oBAEH,CAAC,CAAC,CAAC;iBACJ;YACH,CAAC,CAAC,CAAC;YAGH,KAAI,CAAC,OAAO,CAAC,cAAc,CAAC,uBAAuB,EAAE,UAAC,IAAI;gBACxD,OAAO,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;gBACzE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAElB,kBAAkB;gBAClB,YAAY;gBACZ,IAAI;gBACJ,EAAE;gBACF,kCAAkC;gBAClC,yBAAyB;gBACzB,gDAAgD;gBAChD,cAAc;gBACd,+CAA+C;gBAC/C,8DAA8D;gBAC9D,oJAAoJ;gBACpJ,8FAA8F;gBAC9F,kDAAkD;gBAClD,iDAAiD;gBACjD,4DAA4D;gBAC5D,YAAY;gBACZ,iBAAiB;gBACjB,UAAU;gBACV,QAAQ;gBACR,MAAM;gBACN,4DAA4D;gBAC5D,iDAAiD;gBACjD,qCAAqC;gBACrC,QAAQ;gBACR,QAAQ;gBACR,EAAE;gBACF,uBAAuB;gBACvB,+BAA+B;gBAC/B,cAAc;gBACd,+EAA+E;gBAC/E,kFAAkF;gBAClF,oHAAoH;gBACpH,gEAAgE;gBAChE,kCAAkC;gBAClC,eAAe;gBACf,cAAc;gBACd,wDAAwD;gBACxD,eAAe;gBACf,cAAc;gBACd,0DAA0D;gBAC1D,eAAe;gBACf,cAAc;gBACd,0DAA0D;gBAC1D,eAAe;gBACf,cAAc;gBACd,kFAAkF;gBAClF,kFAAkF;gBAClF,mEAAmE;gBACnE,kCAAkC;gBAClC,eAAe;gBACf,cAAc;gBACd,qFAAqF;gBACrF,kFAAkF;gBAClF,mEAAmE;gBACnE,kCAAkC;gBAClC,eAAe;gBACf,cAAc;gBACd,uDAAuD;gBACvD,eAAe;gBACf,MAAM;gBACN,IAAI;YACN,CAAC,CAAC,CAAC;YAEH,KAAI,CAAC,4BAA4B,GAAG,WAAW,CAAC;gBAC9C,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,UAAC,MAAM;oBAC3C,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,UAAC,QAAQ;wBAChC,IAAI,QAAQ,CAAC,KAAK,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAI,CAAC,gBAAgB,CAAC,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE;4BACjH,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC;4BACnB,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC;4BACvB,OAAO,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;yBAC/C;6BAAM,IAAI,QAAQ,CAAC,KAAK,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAI,CAAC,gBAAgB,CAAC,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE;4BACxH,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC;4BACnB,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC;yBACxB;oBACH,CAAC,CAAC,CAAC;gBACL,CAAC,CAAC,CAAC;YACL,CAAC,EAAE,KAAK,CAAC,CAAC;YAGV,KAAI,CAAC,OAAO,CAAC,UAAU,CAAC,UAAC,MAAM,EAAE,IAAI;gBACnC,IAAI,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE;oBACxC,KAAI,CAAC,gBAAgB,CAAC,QAAQ,GAAG,IAAI,CAAC;oBACtC,IAAI,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE;wBAC5I,KAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;qBACxF;yBAAM;wBACL,KAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,KAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC;qBACtF;iBACF;qBAAM;oBACL,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,KAAK,GAAG,KAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC;oBAC1E,KAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;iBACxF;gBAED,IAAI,KAAI,CAAC,MAAM,CAAC,GAAG,KAAK,QAAQ,EAAE;oBAChC,KAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,UAAC,UAAU;wBACxC,IAAI,UAAU,EAAE;4BACd,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;gCACd,KAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAC,WAAW,EAAE,EAAC,IAAI,EAAE,MAAM,EAAC,EAAC,CAAC,CAAC;4BAClE,CAAC,CAAC,CAAC;yBACJ;6BAAM;4BACL,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;gCACd,KAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAC,WAAW,EAAE,EAAC,IAAI,EAAE,KAAK,EAAC,EAAC,CAAC,CAAC;4BACjE,CAAC,CAAC,CAAC;yBACJ;oBACH,CAAC,CAAC,CAAC;iBACJ;YACH,CAAC,CAAC,CAAC;QACL,CAAC,EAAE,eAAK;YACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,kBAAkB,EAAE,CAAC;IAC5B,CAAC;IAED,yCAAkB,GAAlB;QAAA,iBAYC;QAXC,gEAAgE;QAChE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC,SAAS,CAClE,gBAAM;YACJ,IAAI,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE;gBACjC,KAAI,CAAC,gBAAgB,CAAC,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC;aAClF;QACH,CAAC,EACD,eAAK;YACH,OAAO,CAAC,IAAI,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC;QAC7C,CAAC,CACF,CAAC;IACJ,CAAC;IAGD,sCAAe,GAAf,UAAgB,MAAM;QACpB,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,KAAK,UAAU,IAAI,MAAM,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC,EAAE;YAC/G,IAAM,KAAK,GAAG,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,gBAAgB,CAAC;YAC7F,IAAM,GAAG,GAAG,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,cAAc,CAAC;YACrF,IAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;YACrE,IAAM,YAAY,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACjH,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;SACjD;IACH,CAAC;IAED,uCAAgB,GAAhB,UAAiB,MAAM;QACrB,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,KAAK,UAAU,IAAI,MAAM,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC,EAAE;YAC/G,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,UAAC,MAAM,EAAE,SAAS;gBAC1C,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;gBAC9B,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,CAAC,MAAM,EAAE;oBACrD,IAAM,KAAK,GAAG,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,gBAAgB,CAAC;oBAC7F,IAAM,GAAG,GAAG,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,cAAc,CAAC;oBACrF,IAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;oBACrE,IAAI,IAAI,GAAG,EAAE,CAAC;oBACd,IAAI,IAAI,GAAG,EAAE,CAAC;oBACd,IAAI,eAAe,EAAE;wBACnB,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;wBACnD,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;qBACvE;oBACD,IAAI,IAAI,GAAG,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,GAAG,SAAS,GAAG,IAAI,CAAC;oBACpE,IAAI,MAAM,CAAC,WAAW,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE;wBAChE,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;qBAC1D;oBACD,MAAM,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;oBACvB,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;iBACnB;YACH,CAAC,CAAC,CAAC;SACJ;IACH,CAAC;IAED,wCAAiB,GAAjB,UAAkB,MAAM;QACtB,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,KAAK,UAAU,IAAI,MAAM,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC,EAAE;YAC/G,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YAClB,UAAU,CAAC;gBACT,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YACrB,CAAC,CAAC,CAAC;SACJ;IACH,CAAC;IAED,kCAAW,GAAX;QACE,IAAI,IAAI,CAAC,4BAA4B,EAAE;YACrC,aAAa,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;SAClD;IACH,CAAC;IArbU,YAAY;QALxB,+DAAS,CAAC;YACT,QAAQ,EAAE,UAAU;;;SAGrB,CAAC;yCAOgB,+DAAU;YACN,uDAAS;YACT,oEAAgB;YACjB,gFAAc;YACf,sDAAM;YACI,oFAAgB;YAC1B,oDAAM;OAZb,YAAY,CAubxB;IAAD,mBAAC;CAAA;AAvbwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACZiC;AACjB;AAEe;AAET;AACU;AACS;AACH;AACT;AAC0B;AACN;AACS;AACT;AACS;AACvB;AACN;AACS;AACA;AACM;AACH;AACA;AACH;AAEK;AACG;AACN;AACC;AACiB;AAEd;AACD;AACA;AACmC;AAC5B;AACW;AACM;AACZ;AAC5B;AAE7C,SAAS,iBAAiB,CAAC,UAAsB;IACtD,OAAO,IAAI,+EAAmB,CAAC,UAAU,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;AACxE,CAAC;AAG+E;AACuB;AACG;AAC1G,0DAA0D;AAC1D,iEAAiE;AACjE,6DAA6D;AAE7D,8DAAU,CAAC,UAAU,CAAC;AACpB,YAAY;AACZ,kBAAkB;AAClB,IAAI;CACL,CAAC,CAAC;AAyDH;IAAA;IAAyB,CAAC;IAAb,SAAS;QAvDrB,8DAAQ,CAAC;YACR,YAAY,EAAE;gBACZ,2DAAY;gBACZ,qEAAc;gBACd,8EAAiB;gBACjB,2EAAgB;gBAChB,kEAAa;gBACb,4FAAqB;gBACrB,sFAAmB;gBACnB,gGAAsB;gBACtB,uFAAmB;gBACnB,gGAAsB;gBACtB,yEAAe;gBACf,mEAAa;gBACb,4EAAgB;gBAChB,4EAAgB;gBAChB,kFAAkB;gBAClB,+EAAiB;gBACjB,+EAAiB;gBACjB,4EAAgB;gBAChB,gGAAsB;gBACtB,gFAAc;gBACd,gFAAc;gBACd,mHAAsB;gBACtB,kGAAuB;gBACvB,wGAA0B;gBAC1B,4FAAoB;gBACpB,uFAAgB;gBAChB,mHAAsB;gBACtB,sHAAuB;aACxB;YACD,OAAO,EAAE;gBACP,uEAAa;gBACb,oEAAgB;gBAChB,sEAAgB;gBAChB,oEAAe,CAAC,OAAO,CAAC;oBACtB,MAAM,EAAE;wBACN,OAAO,EAAE,oEAAe;wBACxB,UAAU,EAAE,iBAAiB;wBAC7B,IAAI,EAAE,CAAC,gEAAU,CAAC;qBACnB;iBACF,CAAC;gBACF,2DAAW;gBACX,mEAAmB;gBACnB,+DAAW;gBACX,kEAAiB,CAAC,OAAO,EAAE;aAC5B;YACD,SAAS,EAAE;gBACT,iFAAc;gBACd,gFAAc;gBACd,gFAAc;aAEf;YACD,SAAS,EAAE,CAAC,2DAAY,CAAC;SAC1B,CAAC;OACW,SAAS,CAAI;IAAD,gBAAC;CAAA;AAAJ;;;;;;;;;;;;ACjHtB,0HAA0H,iCAAiC,gNAAgN,qCAAqC,qBAAqB,gCAAgC,qBAAqB,kCAAkC,qBAAqB,kCAAkC,qBAAqB,oCAAoC,4eAA4e,yBAAyB,wDAAwD,mDAAmD,qBAAqB,2CAA2C,GAAG,kCAAkC,qEAAqE,+BAA+B,kGAAkG,yBAAyB,0OAA0O,2CAA2C,wEAAwE,0CAA0C,wB;;;;;;;;;;;ACAv6D,yBAAyB,gBAAgB,EAAE,sBAAsB,sBAAsB,EAAE,iBAAiB,gCAAgC,qBAAqB,EAAE,2BAA2B,yBAAyB,oBAAoB,0BAA0B,EAAE,iCAAiC,uBAAuB,EAAE,wEAAwE,6BAA6B,iBAAiB,EAAE,qCAAqC,wBAAwB,wDAAwD,wDAAwD,wBAAwB,yBAAyB,EAAE,uCAAuC,sBAAsB,wBAAwB,0DAA0D,0DAA0D,wBAAwB,yBAAyB,EAAE,4EAA4E,6BAA6B,wBAAwB,yBAAyB,EAAE,0CAA0C,6DAA6D,6DAA6D,EAAE,sCAAsC,yDAAyD,yDAAyD,EAAE,gCAAgC,gCAAgC,yBAAyB,wBAAwB,EAAE,+CAA+C,8BAA8B,uBAAuB,sBAAsB,EAAE,wBAAwB,kBAAkB,mBAAmB,eAAe,EAAE,+BAA+B,oBAAoB,2BAA2B,EAAE,+CAA+C,mnG;;;;;;;;;;;;;;;;;;;;;;;;;;ACAhvD;AACJ;AACiB;AAOxE;IAKE,4BACU,KAAqB,EACrB,MAAc,EACd,gBAAkC;QAFlC,UAAK,GAAL,KAAK,CAAgB;QACrB,WAAM,GAAN,MAAM,CAAQ;QACd,qBAAgB,GAAhB,gBAAgB,CAAkB;IACzC,CAAC;IAEJ,qCAAQ,GAAR;QAAA,iBAMC;QALC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,gBAAM;YAC5D,IAAI,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE;gBAC/B,KAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;aAC9B;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,wCAAW,GAAX;QACE,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC;IACnC,CAAC;IArBU,kBAAkB;QAL9B,+DAAS,CAAC;YACT,QAAQ,EAAE,eAAe;;;SAG1B,CAAC;yCAOiB,8DAAc;YACb,sDAAM;YACI,oFAAgB;OARjC,kBAAkB,CAuB9B;IAAD,yBAAC;CAAA;AAvB8B;;;;;;;;;;;;ACT/B,4HAA4H,wCAAwC,yBAAyB,2CAA2C,qIAAqI,6BAA6B,0KAA0K,oCAAoC,onBAAonB,oCAAoC,+OAA+O,uCAAuC,8kBAA8kB,mCAAmC,kKAAkK,6CAA6C,wIAAwI,6CAA6C,uD;;;;;;;;;;;ACA3/E,gCAAgC,qBAAqB,eAAe,EAAE,gCAAgC,oBAAoB,6BAA6B,EAAE,uCAAuC,yBAAyB,EAAE,0DAA0D,0BAA0B,EAAE,qDAAqD,0BAA0B,EAAE,qDAAqD,wBAAwB,EAAE,+CAA+C,mjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAxc;AACU;AACE;AACI;AACjC;AACgB;AAOvD;IAuBE,+BACU,MAAc,EACd,OAAuB,EACvB,gBAAkC,EAClC,MAAc;QAJxB,iBAMC;QALS,WAAM,GAAN,MAAM,CAAQ;QACd,YAAO,GAAP,OAAO,CAAgB;QACvB,qBAAgB,GAAhB,gBAAgB,CAAkB;QAClC,WAAM,GAAN,MAAM,CAAQ;QAzBxB,eAAU,GAAG,IAAI,wDAAS,CAAC;YACzB,IAAI,EAAE,IAAI,0DAAW,CAAC,EAAE,EAAE,CAAC,yDAAU,CAAC,QAAQ,EAAE,UAAC,CAAc;oBAC7D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;wBAC7D,IAAI,CAAC,CAAC,KAAK,KAAK,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;4BACrD,OAAO,EAAC,WAAW,EAAE,IAAI,EAAC,CAAC;yBAC5B;qBACF;oBACD,OAAO,IAAI,CAAC;gBACd,CAAC,CAAC,CAAC;YACH,QAAQ,EAAE,IAAI,0DAAW,CAAC,EAAE,CAAC;YAC7B,OAAO,EAAE,IAAI,0DAAW,CAAC,EAAE,CAAC;SAC7B,EAAE,UAAU,CAAY;YACvB,OAAO,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAC,kBAAkB,EAAE,IAAI,EAAC,CAAC;QAChG,CAAC,CAAC,CAAC;QAEH,WAAM,GAAG;YACP,EAAE,EAAE,EAAE;SACP,CAAC;QAEF,gBAAW,GAAG,KAAK,CAAC;IAQpB,CAAC;IAED,wCAAQ,GAAR;IACA,CAAC;IAED,4CAAY,GAAZ;QACE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,cAAc,CAAC,EAAE,EAAC,WAAW,EAAE,EAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,EAAC,EAAC,CAAC,CAAC;IACrF,CAAC;IAED,0CAAU,GAAV;QAAA,iBAiCC;QAhCC,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE;YACzB,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,uBAAuB,EAAE,GAAG,EAAE,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,YAAY,EAAE,UAAC,WAAW,EAAE,SAAS;gBAC5H,IAAI,WAAW,EAAE;oBACf,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,YAAY,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;oBACxG,KAAI,CAAC,OAAO,CAAC,cAAc,CAAC,SAAS,CAAC,IAAI,EAAE,KAAI,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,UAAC,eAAe,EAAE,aAAa,EAAE,SAAS;wBAC3H,IAAI,eAAe,EAAE;4BACnB,KAAI,CAAC,MAAM,CAAC,EAAE,GAAG,aAAa,CAAC,SAAS,CAAC;4BACzC,KAAI,CAAC,gBAAgB,CAAC,cAAc,GAAG,IAAI,mEAAM,CAC/C,aAAa,CAAC,SAAS,EACvB,KAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,KAAK,EACjC,KAAI,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,KAAK,EACrC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,EACxB,aAAa,CAAC,IAAI,CAAC,CAAC,OAAO,EAC3B,aAAa,CAAC,IAAI,CAAC,CAAC,OAAO,EAC3B,aAAa,CAAC,IAAI,CAAC,CAAC,gBAAgB,EACpC,aAAa,CAAC,IAAI,CAAC,CAAC,WAAW,EAC/B,aAAa,CAAC,IAAI,CAAC,CAAC,YAAY,CACjC,CAAC;4BACF,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;gCACd,KAAI,CAAC,WAAW,GAAG,IAAI,CAAC;4BAC1B,CAAC,CAAC,CAAC;yBACJ;6BAAM;4BACL,IAAI,SAAS,IAAI,SAAS,KAAK,gBAAgB,EAAE;gCAC/C,KAAK,CAAC,iDAAiD,CAAC,CAAC;6BAC1D;iCAAM;gCACL,KAAK,CAAC,qDAAqD,CAAC,CAAC;6BAC9D;yBACF;oBACH,CAAC,CAAC,CAAC;iBACJ;YACH,CAAC,CAAC,CAAC;SACJ;IACH,CAAC;IAvEU,qBAAqB;QALjC,+DAAS,CAAC;YACT,QAAQ,EAAE,mBAAmB;;;SAG9B,CAAC;yCAyBkB,sDAAM;YACL,gFAAc;YACL,oFAAgB;YAC1B,oDAAM;OA3Bb,qBAAqB,CAyEjC;IAAD,4BAAC;CAAA;AAzEiC;;;;;;;;;;;;ACZlC,4HAA4H,gCAAgC,qBAAqB,8BAA8B,qBAAqB,gCAAgC,qBAAqB,6BAA6B,qBAAqB,iCAAiC,sSAAsS,yCAAyC,2CAA2C,GAAG,wOAAwO,sEAAsE,wDAAwD,mDAAmD,qBAAqB,8BAA8B,GAAG,kCAAkC,8DAA8D,2BAA2B,GAAG,kCAAkC,iFAAiF,4BAA4B,gF;;;;;;;;;;;ACAr8C,yBAAyB,gBAAgB,EAAE,iBAAiB,kBAAkB,EAAE,wCAAwC,yBAAyB,oBAAoB,0BAA0B,EAAE,sDAAsD,2BAA2B,iBAAiB,oBAAoB,4CAA4C,4CAA4C,sBAAsB,8BAA8B,sBAAsB,uBAAuB,EAAE,4DAA4D,sBAAsB,EAAE,8CAA8C,2BAA2B,sBAAsB,uBAAuB,EAAE,mDAAmD,uDAAuD,uDAAuD,EAAE,uDAAuD,0DAA0D,0DAA0D,EAAE,gDAAgD,uBAAuB,8BAA8B,sBAAsB,EAAE,+CAA+C,+8E;;;;;;;;;;;;;;;;;;;;;;;;;;;ACA/nC;AACZ;AACqB;AACI;AAOxE;IAGE,0BACU,KAAqB,EACrB,OAAuB,EACvB,gBAAkC;QAFlC,UAAK,GAAL,KAAK,CAAgB;QACrB,YAAO,GAAP,OAAO,CAAgB;QACvB,qBAAgB,GAAhB,gBAAgB,CAAkB;IAE5C,CAAC;IAED,mCAAQ,GAAR;QAAA,iBAIC;QAHC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC;YACtD,OAAO,CAAC,GAAG,CAAC,KAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC;IACL,CAAC;IAED,oCAAS,GAAT,UAAU,IAAI;QACZ,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,UAAU,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,KAAK,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE;YACjI,OAAO,GAAG,CAAC;SACZ;aAAM;YACL,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,gBAAgB,CAAC,UAAU,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;gBAC3E,OAAO,CAAC,CAAC;aACV;iBAAM;gBACL,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;aAC9D;SACF;IACH,CAAC;IAED,sCAAW,GAAX;QACE,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC;IACnC,CAAC;IA9BU,gBAAgB;QAL5B,+DAAS,CAAC;YACT,QAAQ,EAAE,aAAa;;;SAGxB,CAAC;yCAKiB,8DAAc;YACZ,gFAAc;YACL,oFAAgB;OANjC,gBAAgB,CAgC5B;IAAD,uBAAC;CAAA;AAhC4B;;;;;;;;;;;;ACV7B,yTAAyT,yCAAyC,gfAAgf,0CAA0C,ivBAAivB,mCAAmC,uOAAuO,mCAAmC,+eAA+e,mCAAmC,uD;;;;;;;;;;;ACA56E,yBAAyB,oBAAoB,WAAW,YAAY,gBAAgB,iBAAiB,EAAE,oBAAoB,oBAAoB,EAAE,gCAAgC,qBAAqB,oBAAoB,yBAAyB,EAAE,sCAAsC,2DAA2D,sBAAsB,wBAAwB,EAAE,4CAA4C,wBAAwB,iCAAiC,EAAE,mDAAmD,gCAAgC,wBAAwB,6BAA6B,EAAE,+CAA+C,m7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACA9mB;AACU;AACX;AACa;AACI;AACjB;AAOvD;IAeE,wBACU,KAAqB,EACrB,MAAc,EACd,OAAuB,EACvB,gBAAkC,EAClC,MAAc;QAJd,UAAK,GAAL,KAAK,CAAgB;QACrB,WAAM,GAAN,MAAM,CAAQ;QACd,YAAO,GAAP,OAAO,CAAgB;QACvB,qBAAgB,GAAhB,gBAAgB,CAAkB;QAClC,WAAM,GAAN,MAAM,CAAQ;QAlBxB,YAAO,GAAG,IAAI,wDAAS,CAAC;YACtB,QAAQ,EAAE,IAAI,0DAAW,CAAC,EAAE,EAAE,yDAAU,CAAC,QAAQ,CAAC;YAClD,YAAY,EAAE,IAAI,0DAAW,CAAC,EAAE,EAAE,yDAAU,CAAC,QAAQ,CAAC;SACvD,EAAE,UAAU,CAAY;YACvB,OAAO,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAC,UAAU,EAAE,IAAI,EAAC,CAAC;QAC7F,CAAC,CAAC,CAAC;QAEH,aAAQ,GAAG,IAAI,wDAAS,CAAC;YACvB,QAAQ,EAAE,IAAI,0DAAW,CAAC,EAAE,EAAE,yDAAU,CAAC,QAAQ,CAAC;SACnD,CAAC,CAAC;QAEH,SAAI,GAAG,KAAK,CAAC;IASb,CAAC;IAED,iCAAQ,GAAR;QAAA,iBAMC;QALC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,SAAS,CAAC,gBAAM;YACrC,IAAI,MAAM,CAAC,IAAI,EAAE;gBACf,KAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;aACzB;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,2CAAkB,GAAlB;QAAA,iBAcC;QAbC,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE;YACtB,IAAI,CAAC,gBAAgB,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC;YACnE,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,UAAC,MAAM,EAAE,IAAI;gBAC3C,IAAI,MAAM,EAAE;oBACV,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;wBACd,KAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;oBAC9B,CAAC,CAAC,CAAC;iBACJ;qBAAM;oBACL,qBAAqB;oBACrB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;iBACjC;YACH,CAAC,CAAC,CAAC;SACJ;IACH,CAAC;IAED,yCAAgB,GAAhB;QAAA,iBAgFC;QA/EC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE;YACvB,IAAM,SAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC;YACpD,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAC,IAAI,EAAE,SAAO,EAAC,EAAE,UAAC,MAAM,EAAE,IAAI;gBAC1D,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,UAAU,KAAK,gBAAgB,EAAE;oBAC3D,kEAAkE;oBAClE,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;iBAC/B;qBAAM;oBACL,KAAI,CAAC,gBAAgB,CAAC,cAAc,EAAE,CAAC;oBACvC,KAAI,CAAC,gBAAgB,CAAC,OAAO,GAAG,SAAO,CAAC;oBACxC,IAAI,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,MAAM,EAAE;wBACxC,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;4BACd,KAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,UAAU,GAAG,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;wBAClF,CAAC,CAAC,CAAC;wBACH,OAAO;qBACR;oBACD,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE;wBAClC,IAAI,aAAW,GAAG,CAAC,CAAC;wBACpB,IAAI,YAAU,GAAG,CAAC,CAAC;wBACnB,IAAI,CAAC,OAAO,CAAC,UAAC,MAAM,EAAE,YAAY;4BAChC,KAAI,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,UAAC,WAAW,EAAE,SAAS;gCAC7E,IAAI,WAAW,EAAE;oCACf,aAAW,EAAE,CAAC;oCACd,KAAI,CAAC,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC,SAAS,EAAE,UAAC,UAAU;wCACrD,IAAI,UAAU,EAAE;4CACd,YAAU,EAAE,CAAC;4CACb,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;gDACd,IAAM,UAAU,GAAG,IAAI,mEAAM,CAC3B,SAAS,CAAC,SAAS,EACnB,MAAM,CAAC,IAAI,EACX,MAAM,CAAC,IAAI,EACX,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,EACpB,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,EACvB,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,EACvB,SAAS,CAAC,IAAI,CAAC,CAAC,gBAAgB,EAChC,SAAS,CAAC,IAAI,CAAC,CAAC,WAAW,EAC3B,SAAS,CAAC,IAAI,CAAC,CAAC,YAAY,CAC7B,CAAC;gDACF,IAAI,SAAS,CAAC,cAAc,IAAI,SAAS,CAAC,cAAc,CAAC,OAAO,EAAE;oDAChE,UAAU,CAAC,cAAc,CAAC,SAAS,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;iDAC7D;gDACD,KAAI,CAAC,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,SAAS,EAAE,UAAC,gBAAgB,EAAE,cAAc;oDAC9E,IAAI,gBAAgB,IAAI,cAAc,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE;wDAClE,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;4DACd,UAAU,CAAC,yBAAyB,CAAC,cAAc,CAAC,SAAS,EAAE,KAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,KAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,eAAe,EAAE,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC;wDACxO,CAAC,CAAC,CAAC;qDACJ;gDACH,CAAC,CAAC,CAAC;gDAEH,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gDAC/C,IAAI,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE;oDAC9C,KAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,UAAU,GAAG,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;iDACjF;4CACH,CAAC,CAAC,CAAC;yCACJ;6CAAM;4CACL,IAAI,YAAY,KAAK,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,YAAU,KAAK,CAAC,EAAE;gDACxD,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;oDACd,KAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;gDAC9B,CAAC,CAAC,CAAC;6CACJ;4CACD,uCAAuC;yCACxC;oCACH,CAAC,CAAC,CAAC;iCACJ;qCAAM;oCACL,IAAI,YAAY,KAAK,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,aAAW,KAAK,CAAC,EAAE;wCACzD,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;4CACd,KAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;wCAC9B,CAAC,CAAC,CAAC;qCACJ;iCACF;4BACH,CAAC,CAAC,CAAC;wBACL,CAAC,CAAC,CAAC;qBACJ;yBAAM;wBACL,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;4BACd,KAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;wBAC9B,CAAC,CAAC,CAAC;qBACJ;iBACF;YACH,CAAC,CAAC,CAAC;SACJ;IACH,CAAC;IAhIU,cAAc;QAL1B,+DAAS,CAAC;YACT,QAAQ,EAAE,WAAW;;;SAGtB,CAAC;yCAiBiB,8DAAc;YACb,sDAAM;YACL,gFAAc;YACL,oFAAgB;YAC1B,oDAAM;OApBb,cAAc,CAiI1B;IAAD,qBAAC;CAAA;AAjI0B;;;;;;;;;;;;ACZ3B,kHAAkH,4BAA4B,sIAAsI,wCAAwC,4FAA4F,yCAAyC,iGAAiG,4CAA4C,sGAAsG,2BAA2B,gD;;;;;;;;;;;ACA/sB,yBAAyB,mBAAmB,kBAAkB,EAAE,cAAc,kBAAkB,qBAAqB,EAAE,mCAAmC,wBAAwB,EAAE,qCAAqC,kBAAkB,wBAAwB,mCAAmC,sBAAsB,sBAAsB,EAAE,4CAA4C,qBAAqB,uBAAuB,EAAE,kCAAkC,kBAAkB,sBAAsB,wBAAwB,EAAE,wCAAwC,sDAAsD,sDAAsD,2BAA2B,oBAAoB,qBAAqB,EAAE,+CAA+C,+oD;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAnuB;AACY;AACI;AACjC;AAOvC;IAEE,uBACU,MAAc,EACd,OAAuB,EACvB,gBAAkC,EAClC,MAAc;QAHd,WAAM,GAAN,MAAM,CAAQ;QACd,YAAO,GAAP,OAAO,CAAgB;QACvB,qBAAgB,GAAhB,gBAAgB,CAAkB;QAClC,WAAM,GAAN,MAAM,CAAQ;IACrB,CAAC;IAEJ,gCAAQ,GAAR,cAAY,CAAC;IAEb,kCAAU,GAAV;QAAA,iBAWC;QAVC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,uBAAuB,EAAE,GAAG,EAAE,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,YAAY,EAAE,UAAC,WAAW,EAAE,SAAS;YAC5H,IAAI,WAAW,EAAE;gBACf,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,YAAY,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;gBACxG,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;oBACd,KAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,EAAC,WAAW,EAAE,EAAC,IAAI,EAAE,SAAS,CAAC,IAAI,EAAC,EAAC,CAAC,CAAC;gBACzE,CAAC,CAAC,CAAC;aACJ;iBAAM;gBACL,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC;aACtC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAtBU,aAAa;QALzB,+DAAS,CAAC;YACT,QAAQ,EAAE,UAAU;;;SAGrB,CAAC;yCAIkB,sDAAM;YACL,gFAAc;YACL,oFAAgB;YAC1B,oDAAM;OANb,aAAa,CAwBzB;IAAD,oBAAC;CAAA;AAxByB;;;;;;;;;;;;ACV1B,6HAA6H,kCAAkC,qBAAqB,kCAAkC,qKAAqK,iBAAiB,mHAAmH,iBAAiB,gF;;;;;;;;;;;ACAhhB,yBAAyB,gBAAgB,EAAE,iBAAiB,kBAAkB,EAAE,+CAA+C,yBAAyB,0BAA0B,mBAAmB,EAAE,oDAAoD,uBAAuB,4BAA4B,yBAAyB,EAAE,qDAAqD,2BAA2B,iBAAiB,oBAAoB,4CAA4C,4CAA4C,uBAAuB,mDAAmD,mDAAmD,sBAAsB,uBAAuB,EAAE,+CAA+C,utD;;;;;;;;;;;;;;;;;;;;;;;;ACA/rB;AAOlD;IAoBE;QAlBA,aAAQ,GAAG;YACT;gBACE,MAAM,EAAE,IAAI;gBACZ,OAAO,EAAE,SAAS;gBAClB,OAAO,EAAE,yBAAyB;aACnC;YACD;gBACE,MAAM,EAAE,KAAK;gBACb,OAAO,EAAE,kDAAkD;gBAC3D,OAAO,EAAE,gCAAgC;aAC1C;YACD;gBACE,MAAM,EAAE,KAAK;gBACb,OAAO,EAAE,OAAO;gBAChB,OAAO,EAAE,aAAa;aACvB;SACF,CAAC;IAEa,CAAC;IAEhB,oCAAQ,GAAR,cAAY,CAAC;IAtBF,iBAAiB;QAL7B,+DAAS,CAAC;YACT,QAAQ,EAAE,cAAc;;;SAGzB,CAAC;;OACW,iBAAiB,CAyB7B;IAAD,wBAAC;CAAA;AAzB6B;;;;;;;;;;;;ACP9B,4HAA4H,wCAAwC,yBAAyB,yCAAyC,qIAAqI,6BAA6B,sKAAsK,kCAAkC,8jBAA8jB,kCAAkC,iRAAiR,oCAAoC,2D;;;;;;;;;;;ACAr+C,8BAA8B,qBAAqB,eAAe,EAAE,8BAA8B,oBAAoB,6BAA6B,EAAE,qCAAqC,yBAAyB,EAAE,mDAAmD,wBAAwB,EAAE,+CAA+C,2xB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAzR;AACU;AACE;AACI;AACjB;AACA;AAOvD;IAgBE,6BACU,KAAqB,EACrB,MAAc,EACd,OAAuB,EACvB,gBAAkC,EAClC,MAAc;QALxB,iBAOC;QANS,UAAK,GAAL,KAAK,CAAgB;QACrB,WAAM,GAAN,MAAM,CAAQ;QACd,YAAO,GAAP,OAAO,CAAgB;QACvB,qBAAgB,GAAhB,gBAAgB,CAAkB;QAClC,WAAM,GAAN,MAAM,CAAQ;QAjBxB,aAAQ,GAAG,IAAI,wDAAS,CAAC;YACvB,IAAI,EAAE,IAAI,0DAAW,CAAC,EAAE,EAAE,CAAC,yDAAU,CAAC,QAAQ,EAAE,UAAC,CAAc;oBAC7D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;wBAC7D,IAAI,CAAC,CAAC,KAAK,KAAK,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;4BACrD,OAAO,EAAC,WAAW,EAAE,IAAI,EAAC,CAAC;yBAC5B;qBACF;oBACD,OAAO,IAAI,CAAC;gBACd,CAAC,CAAC,CAAC;YACH,QAAQ,EAAE,IAAI,0DAAW,CAAC,EAAE,CAAC;SAC9B,CAAC,CAAC;IASH,CAAC;IAED,sCAAQ,GAAR;QAAA,iBAgBC;QAfC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,SAAS,CAAC,gBAAM;YACrC,IAAI,MAAM,CAAC,IAAI,EAAE;gBACf,KAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC;gBAC5B,IAAI,QAAQ,GAAG,EAAE,CAAC;gBAClB,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE;oBACvC,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;iBACjE;qBAAM;oBACL,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;iBAClI;gBACD,IAAI,QAAQ,CAAC,MAAM,GAAG,EAAE,EAAE;oBACxB,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;iBAClC;gBACD,KAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;aAC9C;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,wCAAU,GAAV;QAAA,iBAmEC;QAlEC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE;YACvB,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,UAAC,WAAW,EAAE,SAAS,EAAE,UAAU;gBACpH,IAAI,UAAU,IAAI,UAAU,KAAK,gBAAgB,EAAE;oBACjD,+EAA+E;oBAC/E,iDAAiD;oBACjD,4EAA4E;oBAC5E,0CAA0C;oBAC1C,KAAK,CAAC,gBAAgB,CAAC,CAAC;iBACzB;qBAAM;oBACL,IAAI,WAAW,IAAI,UAAU,KAAK,eAAe,EAAE;wBAEjD,IAAI,QAAM,GAAG,KAAK,CAAC;wBACnB,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,UAAC,MAAM;4BAC3C,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE;gCAC9C,QAAM,GAAG,IAAI,CAAC;6BACf;wBACH,CAAC,CAAC,CAAC;wBAEH,IAAI,QAAM,EAAE;4BACV,KAAK,CAAC,iCAAiC,CAAC,CAAC;4BACzC,KAAI,CAAC,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,SAAS,EAAE,UAAC,YAAY,EAAE,UAAU;gCACrE,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;gCACtC,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;oCACd,KAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;gCAC9B,CAAC,CAAC,CAAC;4BACL,CAAC,CAAC,CAAC;yBACJ;6BAAM;4BACL,KAAI,CAAC,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC,SAAS,EAAE,UAAC,UAAU,EAAE,QAAQ;gCAC/D,IAAI,UAAU,EAAE;oCACd,IAAM,YAAU,GAAG,IAAI,mEAAM,CAC3B,SAAS,CAAC,SAAS,EACnB,KAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,KAAK,EAC/B,KAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,KAAK,EACnC,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,EACpB,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,EACvB,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,EACvB,SAAS,CAAC,IAAI,CAAC,CAAC,gBAAgB,EAChC,SAAS,CAAC,IAAI,CAAC,CAAC,WAAW,EAC3B,SAAS,CAAC,IAAI,CAAC,CAAC,YAAY,CAC7B,CAAC;oCACF,IAAI,SAAS,CAAC,cAAc,IAAI,SAAS,CAAC,cAAc,CAAC,OAAO,EAAE;wCAChE,YAAU,CAAC,cAAc,CAAC,SAAS,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;qCAC7D;oCACD,KAAI,CAAC,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,SAAS,EAAE,UAAC,gBAAgB,EAAE,cAAc;wCAC9E,IAAI,gBAAgB,IAAI,cAAc,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE;4CAClE,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;gDACd,YAAU,CAAC,yBAAyB,CAAC,cAAc,CAAC,SAAS,EAAE,KAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,KAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,eAAe,EAAE,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC;4CACxO,CAAC,CAAC,CAAC;yCACJ;oCACH,CAAC,CAAC,CAAC;oCACH,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC,YAAU,CAAC,CAAC;oCAC/C,KAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,UAAC,MAAM,EAAE,IAAI;wCAC3C,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;oCAC9C,CAAC,CAAC,CAAC;oCACH,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;wCACd,KAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,UAAU,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC;oCAC3D,CAAC,CAAC,CAAC;iCACJ;qCAAM;oCACL,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;iCACrC;4BACH,CAAC,CAAC,CAAC;yBACJ;qBACF;iBACF;YACH,CAAC,CAAC,CAAC;SACJ;IACH,CAAC;IA9GU,mBAAmB;QAL/B,+DAAS,CAAC;YACT,QAAQ,EAAE,iBAAiB;;;SAG5B,CAAC;yCAkBiB,8DAAc;YACb,sDAAM;YACL,gFAAc;YACL,oFAAgB;YAC1B,oDAAM;OArBb,mBAAmB,CAgH/B;IAAD,0BAAC;CAAA;AAhH+B;;;;;;;;;;;;ACZhC,uFAAuF,uCAAuC,6CAA6C,0CAA0C,8CAA8C,0CAA0C,0IAA0I,6BAA6B,uMAAuM,sCAAsC,6nBAA6nB,iCAAiC,wuBAAwuB,iCAAiC,qpBAAqpB,uCAAuC,grBAAgrB,yCAAyC,woCAAwoC,kCAAkC,sQAAsQ,kCAAkC,0QAA0Q,8BAA8B,yLAAyL,kCAAkC,sWAAsW,sCAAsC,oUAAoU,6FAA6F,8IAA8I,+CAA+C,kNAAkN,2DAA2D,gEAAgE,yCAAyC,oEAAoE,iDAAiD,oEAAoE,yEAAyE,oEAAoE,mDAAmD,oEAAoE,wDAAwD,kEAAkE,iDAAiD,kEAAkE,iDAAiD,8DAA8D,sEAAsE,kEAAkE,mCAAmC,8DAA8D,uCAAuC,kEAAkE,iEAAiE,kNAAkN,4FAA4F,kEAAkE,mCAAmC,8DAA8D,kCAAkC,+IAA+I,mDAAmD,2MAA2M,mDAAmD,oEAAoE,iEAAiE,oEAAoE,mDAAmD,oEAAoE,wDAAwD,kEAAkE,mEAAmE,8DAA8D,8BAA8B,kEAAkE,iDAAiD,8DAA8D,sEAAsE,kEAAkE,mCAAmC,8DAA8D,uCAAuC,kEAAkE,oFAAoF,kNAAkN,4FAA4F,kEAAkE,mCAAmC,8DAA8D,kCAAkC,uNAAuN,sDAAsD,8EAA8E,8EAA8E,2KAA2K,wCAAwC,6EAA6E,2CAA2C,yEAAyE,0CAA0C,oLAAoL,8KAA8K,oCAAoC,4GAA4G,KAAK,sBAAsB,2SAA2S,4KAA4K,mDAAmD,+GAA+G,4KAA4K,4EAA4E,2GAA2G,4KAA4K,+CAA+C,gOAAgO,KAAK,4CAA4C,2GAA2G,KAAK,+CAA+C,uSAAuS,uCAAuC,uBAAuB,wCAAwC,uBAAuB,4CAA4C,0JAA0J,uDAAuD,oFAAoF,8DAA8D,qFAAqF,uDAAuD,qFAAqF,8DAA8D,kC;;;;;;;;;;;ACAjmd,yBAAyB,kBAAkB,2BAA2B,gBAAgB,EAAE,WAAW,mBAAmB,4BAA4B,0BAA0B,EAAE,oBAAoB,mBAAmB,2BAA2B,oBAAoB,wBAAwB,EAAE,sCAAsC,oBAAoB,EAAE,mDAAmD,wBAAwB,EAAE,+DAA+D,+BAA+B,EAAE,8DAA8D,8BAA8B,EAAE,mEAAmE,wBAAwB,EAAE,qCAAqC,oBAAoB,0BAA0B,8BAA8B,mBAAmB,wBAAwB,0BAA0B,yBAAyB,iBAAiB,kBAAkB,uBAAuB,qBAAqB,EAAE,4CAA4C,0BAA0B,sBAAsB,uBAAuB,EAAE,iDAAiD,+DAA+D,+DAA+D,EAAE,+CAA+C,6DAA6D,6DAA6D,EAAE,wCAAwC,oBAAoB,yBAAyB,6BAA6B,EAAE,8CAA8C,wBAAwB,EAAE,0DAA0D,+BAA+B,8BAA8B,EAAE,yDAAyD,6BAA6B,gCAAgC,EAAE,qCAAqC,oBAAoB,6BAA6B,0BAA0B,8BAA8B,wBAAwB,0BAA0B,EAAE,iCAAiC,uBAAuB,kBAAkB,uBAAuB,EAAE,sCAAsC,oBAAoB,qCAAqC,6BAA6B,+BAA+B,EAAE,6CAA6C,sBAAsB,yBAAyB,EAAE,6BAA6B,uBAAuB,cAAc,YAAY,oBAAoB,gBAAgB,iBAAiB,EAAE,2CAA2C,yBAAyB,mBAAmB,cAAc,qBAAqB,+BAA+B,qBAAqB,EAAE,8DAA8D,uBAAuB,EAAE,8CAA8C,oBAAoB,0BAA0B,qCAAqC,wBAAwB,mBAAmB,EAAE,mDAAmD,oBAAoB,2BAA2B,EAAE,+DAA+D,2BAA2B,EAAE,8DAA8D,4BAA4B,EAAE,4CAA4C,yBAAyB,iBAAiB,gBAAgB,0CAA0C,0CAA0C,wBAAwB,EAAE,+CAA+C,mlM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAt5G;AACpB;AACmB;AACE;AACI;AAC/B;AAC0B;AAOnE;IAqBE,2BACU,KAAqB,EACrB,OAAuB,EACvB,gBAAkC,EAClC,MAAc,EACd,QAAkB,EAClB,cAA8B;QAL9B,UAAK,GAAL,KAAK,CAAgB;QACrB,YAAO,GAAP,OAAO,CAAgB;QACvB,qBAAgB,GAAhB,gBAAgB,CAAkB;QAClC,WAAM,GAAN,MAAM,CAAQ;QACd,aAAQ,GAAR,QAAQ,CAAU;QAClB,mBAAc,GAAd,cAAc,CAAgB;QAzBxC,gBAAW,GAAG,KAAK,CAAC;QAIpB,iBAAY,GAAG,IAAI,wDAAS,CAAC;YAC3B,WAAW,EAAE,IAAI,0DAAW,CAAC,EAAE,EAAE,yDAAU,CAAC,QAAQ,CAAC;YACrD,MAAM,EAAE,IAAI,0DAAW,CAAC,EAAE,EAAE,yDAAU,CAAC,QAAQ,CAAC;YAChD,MAAM,EAAE,IAAI,0DAAW,CAAC,IAAI,EAAE,yDAAU,CAAC,QAAQ,CAAC;YAClD,WAAW,EAAE,IAAI,0DAAW,CAAC,IAAI,EAAE,yDAAU,CAAC,QAAQ,CAAC;YACvD,aAAa,EAAE,IAAI,0DAAW,CAAC,IAAI,EAAE,yDAAU,CAAC,QAAQ,CAAC;YACzD,UAAU,EAAE,IAAI,0DAAW,CAAC,KAAK,CAAC;YAClC,OAAO,EAAE,IAAI,0DAAW,CAAC,EAAE,CAAC;YAC5B,GAAG,EAAE,IAAI,0DAAW,CAAC,MAAM,CAAC;YAC5B,OAAO,EAAE,IAAI,0DAAW,CAAC,EAAE,CAAC;SAC7B,CAAC,CAAC;QAEH,sBAAiB,GAAG,KAAK,CAAC;QAC1B,oBAAe,GAAG,IAAI,CAAC;IAUvB,CAAC;IAED,iDAAqB,GAArB;QAAA,iBAMC;QALC,IAAI,IAAI,CAAC,eAAe,CAAC,KAAK,KAAK,GAAG,EAAE;YACtC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,cAAI,IAAI,WAAI,CAAC,OAAO,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,KAAK,KAAI,CAAC,eAAe,CAAC,WAAW,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,KAAI,CAAC,eAAe,CAAC,IAAI,EAA9I,CAA8I,CAAC,CAAC;SAC9N;aAAM,IAAI,IAAI,CAAC,eAAe,CAAC,KAAK,KAAK,GAAG,EAAE;YAC7C,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,cAAI,IAAI,WAAI,CAAC,OAAO,KAAK,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,KAAK,KAAI,CAAC,eAAe,CAAC,WAAW,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,KAAI,CAAC,eAAe,CAAC,IAAI,EAA/I,CAA+I,CAAC,CAAC;SAC/N;IACH,CAAC;IAED,oCAAQ,GAAR;QAAA,iBAwEC;QAvEC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,gBAAM;YAC5D,KAAI,CAAC,eAAe,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,gBAAM;YAChC,IAAI,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE;gBAC/B,KAAI,CAAC,eAAe,GAAG,KAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;gBACrF,KAAI,CAAC,YAAY,CAAC,QAAQ,CAAC;oBACzB,WAAW,EAAE,KAAI,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC;oBACpD,MAAM,EAAE,KAAI,CAAC,eAAe,CAAC,gBAAgB,CAAC,MAAM;oBACpD,MAAM,EAAE,KAAI,CAAC,cAAc,CAAC,SAAS,CAAC,KAAI,CAAC,eAAe,CAAC,gBAAgB,CAAC,MAAM,CAAC;oBACnF,WAAW,EAAE,KAAI,CAAC,cAAc,CAAC,SAAS,CAAC,KAAI,CAAC,eAAe,CAAC,gBAAgB,CAAC,QAAQ,CAAC;oBAC1F,aAAa,EAAE,KAAI,CAAC,cAAc,CAAC,SAAS,CAAC,KAAI,CAAC,eAAe,CAAC,gBAAgB,CAAC,QAAQ,CAAC;oBAC5F,UAAU,EAAE,KAAK;oBACjB,OAAO,EAAE,KAAI,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC;oBAChD,GAAG,EAAE,MAAM;oBACX,OAAO,EAAE,KAAI,CAAC,eAAe,CAAC,UAAU;iBACzC,CAAC,CAAC;gBACH,KAAI,CAAC,WAAW,GAAG,KAAK,CAAC;gBAGzB,oCAAoC;gBACpC,IAAI,KAAI,CAAC,eAAe,CAAC,KAAK,KAAK,GAAG,IAAI,KAAI,CAAC,eAAe,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAI,CAAC,gBAAgB,CAAC,UAAU,GAAG,KAAI,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE;oBACrJ,KAAI,CAAC,eAAe,CAAC,KAAK,GAAG,CAAC,CAAC;oBAC/B,KAAI,CAAC,eAAe,CAAC,MAAM,GAAG,IAAI,CAAC;oBACnC,KAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,mBAAmB,EAAE,CAAC;iBAC3D;qBAAM,IAAI,KAAI,CAAC,eAAe,CAAC,KAAK,KAAK,GAAG,IAAI,KAAI,CAAC,eAAe,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAI,CAAC,gBAAgB,CAAC,UAAU,GAAG,KAAI,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE;oBAC5J,KAAI,CAAC,eAAe,CAAC,KAAK,GAAG,CAAC,CAAC;oBAC/B,KAAI,CAAC,eAAe,CAAC,MAAM,GAAG,IAAI,CAAC;oBACnC,KAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,mBAAmB,EAAE,CAAC;iBAC3D;gBAGD,IAAI,KAAI,CAAC,eAAe,CAAC,MAAM,EAAE;oBAC/B,IAAI,KAAI,CAAC,eAAe,CAAC,IAAI,IAAI,KAAI,CAAC,eAAe,CAAC,KAAK,KAAK,CAAC,EAAE;wBACjE,KAAI,CAAC,eAAe,CAAC,KAAK,GAAG,GAAG,CAAC;qBAClC;oBACD,IAAI,KAAI,CAAC,eAAe,CAAC,KAAK,KAAK,GAAG,IAAI,KAAI,CAAC,eAAe,CAAC,sBAAsB,KAAK,CAAC,IAAI,KAAI,CAAC,eAAe,CAAC,sBAAsB,GAAG,KAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE;wBAC7K,KAAI,CAAC,eAAe,CAAC,KAAK,GAAG,CAAC,CAAC;qBAChC;oBAED,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,eAAe,GAAG,CAAC,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC;oBACxJ,IAAI,cAAc,GAAG,KAAK,CAAC;oBAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,eAAe,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;wBAC9E,IAAI,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,WAAW,KAAK,KAAI,CAAC,eAAe,CAAC,WAAW,IAAI,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,KAAI,CAAC,eAAe,CAAC,IAAI,EAAE;4BAC9L,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,KAAI,CAAC,eAAe,CAAC,KAAK,CAAC;4BACrF,cAAc,GAAG,IAAI,CAAC;4BACtB,MAAM;yBACP;qBACF;oBACD,IAAI,CAAC,cAAc,EAAE;wBACnB,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,CAAC;4BAClD,WAAW,EAAE,KAAI,CAAC,eAAe,CAAC,WAAW;4BAC7C,IAAI,EAAE,KAAI,CAAC,eAAe,CAAC,IAAI;4BAC/B,KAAK,EAAE,KAAI,CAAC,eAAe,CAAC,KAAK;yBAClC,CAAC,CAAC;qBACJ;oBACD,KAAI,CAAC,eAAe,CAAC,MAAM,GAAG,KAAK,CAAC;oBAEpC,2BAA2B;oBAC3B,UAAU,CAAC;wBACT,KAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,mBAAmB,EAAE,CAAC;oBAC5D,CAAC,EAAE,CAAC,CAAC,CAAC;oBAEN,KAAI,CAAC,qBAAqB,EAAE,CAAC;iBAE9B;aAEF;iBAAM;gBACL,KAAI,CAAC,WAAW,GAAG,IAAI,CAAC;aACzB;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,yCAAa,GAAb;QACE,IAAI,CAAC,iBAAiB,GAAG,CAAC,IAAI,CAAC,iBAAiB,CAAC;IACnD,CAAC;IAED,+CAAmB,GAAnB;QACE,IAAI,IAAI,CAAC,WAAW,EAAE;YACpB,OAAO,MAAM,CAAC;SACf;aAAM;YACL,OAAO,KAAK,CAAC;SACd;IACH,CAAC;IAED,4CAAgB,GAAhB;QACE,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,KAAK,EAAE;YAC7C,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,eAAe,EAAE,CAAC;YACzD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,sBAAsB,EAAE,CAAC;SACjE;aAAM;YACL,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,aAAa,CAAC,CAAC,yDAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC5E,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,sBAAsB,EAAE,CAAC;SACjE;IACH,CAAC;IAED,kDAAsB,GAAtB;QAAA,iBAUC;QATC,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE;YACzC,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,UAAC,YAAY;gBAC/E,IAAI,YAAY,KAAK,KAAK,EAAE;oBAC1B,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;wBACd,KAAI,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,EAAC,iBAAiB,EAAE,IAAI,EAAC,CAAC,CAAC;oBACvE,CAAC,CAAC,CAAC;iBACJ;YACH,CAAC,CAAC,CAAC;SACJ;IACH,CAAC;IAED,0CAAc,GAAd;QAAA,iBAoBC;QAnBC,IAAI,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE;YAC3B,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,KAAK,EAAE;gBAC7C,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC;aACxF;YACD,IAAI,CAAC,OAAO,CAAC,cAAc,CACzB,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,SAAS,EAC7C,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,KAAK,EAC1C,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,KAAK,EACtC,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,OAAO,EAC3C,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,KAAK,EACrC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,KAAK,EACrC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,KAAK,EAC1C,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,KAAK,EAC5C,EAAE,EACF,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,KAAK,EACtC;gBACE,KAAI,CAAC,IAAI,EAAE,CAAC;YACd,CAAC,CAAC,CAAC;SACN;IACH,CAAC;IAED,gCAAI,GAAJ;QACE,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;IACvB,CAAC;IAED,uCAAW,GAAX;QAAA,iBAOC;QANC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,eAAe,CAAC,WAAW,EAAE,UAAC,aAAa;YAChG,IAAI,aAAa,EAAE;gBACjB,KAAK,CAAC,iFAAiF,CAAC,CAAC;gBACzF,KAAI,CAAC,IAAI,EAAE,CAAC;aACb;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,2CAAe,GAAf;QACE,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC;QACjK,IAAI,cAAc,GAAG,KAAK,CAAC;QAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YACjF,IAAI,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,WAAW,KAAK,IAAI,CAAC,eAAe,CAAC,WAAW,IAAI,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE;gBACpM,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC;gBACjE,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC;gBACjG,cAAc,GAAG,IAAI,CAAC;gBACtB,MAAM;aACP;SACF;QACD,IAAI,CAAC,cAAc,EAAE;YACnB,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,CAAC;gBACrD,WAAW,EAAE,IAAI,CAAC,eAAe,CAAC,WAAW;gBAC7C,IAAI,EAAE,IAAI,CAAC,eAAe,CAAC,IAAI;gBAC/B,KAAK,EAAE,GAAG;gBACV,IAAI,EAAE,IAAI,CAAC,eAAe,CAAC,eAAe;aAC3C,CAAC,CAAC;SACJ;QACD,IAAI,CAAC,eAAe,CAAC,MAAM,GAAG,IAAI,CAAC;QACnC,IAAI,CAAC,eAAe,CAAC,KAAK,GAAG,GAAG,CAAC;QACjC,IAAI,CAAC,eAAe,CAAC,IAAI,GAAG,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC;QAEjE,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,mBAAmB,EAAE,CAAC;QAC1D,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAChD,IAAI,CAAC,IAAI,EAAE,CAAC;IACd,CAAC;IAGD,yCAAa,GAAb;QAAA,iBAOC;QANC,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,eAAe,CAAC,WAAW,EAAE,OAAO,EAAE,UAAC,cAAc;YAC3G,IAAI,cAAc,EAAE;gBAClB,KAAK,CAAC,kCAAkC,CAAC,CAAC;gBAC1C,KAAI,CAAC,IAAI,EAAE,CAAC;aACb;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,8CAAkB,GAAlB;QAAA,iBAOC;QANC,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,eAAe,CAAC,WAAW,EAAE,OAAO,EAAE,UAAC,cAAc;YAC3G,IAAI,cAAc,EAAE;gBAClB,KAAK,CAAC,sDAAsD,CAAC,CAAC;gBAC9D,KAAI,CAAC,IAAI,EAAE,CAAC;aACb;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,8CAAkB,GAAlB;QAAA,iBAOC;QANC,IAAI,CAAC,OAAO,CAAC,qBAAqB,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,eAAe,CAAC,WAAW,EAAE,EAAE,EAAE,UAAC,aAAa;YAC3G,IAAI,aAAa,EAAE;gBACjB,KAAK,CAAC,4CAA4C,CAAC,CAAC;gBACpD,KAAI,CAAC,IAAI,EAAE,CAAC;aACb;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,qDAAyB,GAAzB;QACE,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,GAAG,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/J,IAAI,cAAc,GAAG,KAAK,CAAC;QAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YACjF,IAAI,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,WAAW,KAAK,IAAI,CAAC,eAAe,CAAC,WAAW,IAAI,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE;gBACpM,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC;gBACjE,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,eAAe,CAAC,sBAAsB,CAAC;gBACxG,cAAc,GAAG,IAAI,CAAC;gBACtB,MAAM;aACP;SACF;QACD,IAAI,CAAC,cAAc,EAAE;YACnB,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,CAAC;gBACrD,WAAW,EAAE,IAAI,CAAC,eAAe,CAAC,WAAW;gBAC7C,IAAI,EAAE,IAAI,CAAC,eAAe,CAAC,IAAI;gBAC/B,KAAK,EAAE,GAAG;gBACV,IAAI,EAAE,IAAI,CAAC,eAAe,CAAC,sBAAsB;aAClD,CAAC,CAAC;SACJ;QACD,IAAI,CAAC,eAAe,CAAC,MAAM,GAAG,IAAI,CAAC;QACnC,IAAI,CAAC,eAAe,CAAC,KAAK,GAAG,GAAG,CAAC;QACjC,IAAI,CAAC,eAAe,CAAC,IAAI,GAAG,IAAI,CAAC,eAAe,CAAC,sBAAsB,CAAC;QAExE,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,mBAAmB,EAAE,CAAC;QAC1D,KAAK,CAAC,sDAAsD,CAAC,CAAC;QAC9D,IAAI,CAAC,IAAI,EAAE,CAAC;IACd,CAAC;IAED,oDAAwB,GAAxB;QAAA,iBAOC;QANC,IAAI,CAAC,OAAO,CAAC,oBAAoB,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,eAAe,CAAC,WAAW,EAAE,UAAC,aAAa;YACtG,IAAI,aAAa,EAAE;gBACjB,KAAK,CAAC,4EAA4E,CAAC,CAAC;gBACpF,KAAI,CAAC,IAAI,EAAE,CAAC;aACb;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,uCAAW,GAAX;QACE,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC;IACnC,CAAC;IArRU,iBAAiB;QAL7B,+DAAS,CAAC;YACT,QAAQ,EAAE,cAAc;;;SAGzB,CAAC;yCAuBiB,8DAAc;YACZ,gFAAc;YACL,oFAAgB;YAC1B,oDAAM;YACJ,wDAAQ;YACF,+EAAc;OA3B7B,iBAAiB,CAuR7B;IAAD,wBAAC;CAAA;AAvR6B;;;;;;;;;;;;ACb9B,4DAA4D,YAAY,sFAAsF,wCAAwC,+H;;;;;;;;;;;ACAtM,yBAAyB,gBAAgB,EAAE,cAAc,kBAAkB,2BAA2B,wBAAwB,EAAE,kBAAkB,qBAAqB,EAAE,4BAA4B,oBAAoB,0BAA0B,wBAAwB,0BAA0B,EAAE,8CAA8C,uDAAuD,uDAAuD,4BAA4B,sBAAsB,uBAAuB,EAAE,+CAA+C,usC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAlgB;AAC/B;AACwC;AACI;AACzB;AAO/C;IAIE,0BACU,KAAqB,EACrB,OAAuB,EACvB,gBAAkC;QAFlC,UAAK,GAAL,KAAK,CAAgB;QACrB,YAAO,GAAP,OAAO,CAAgB;QACvB,qBAAgB,GAAhB,gBAAgB,CAAkB;IAE5C,CAAC;IAED,mCAAQ,GAAR;QAAA,iBAWC;QAVC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC;YACtD,6CAAM,CAAC,SAAS,CAAC,KAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,OAAO,EAAE;gBAC5D,KAAK,EAAE,GAAG;gBACV,MAAM,EAAE,GAAG;aACZ,CAAC,CAAC,IAAI,CAAC,aAAG;gBACT,KAAI,CAAC,UAAU,GAAG,GAAG,CAAC;YACxB,CAAC,CAAC,CAAC,KAAK,CAAC,aAAG;gBACV,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACrB,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAEM,sCAAW,GAAlB;QACE,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IACzE,CAAC;IAED,sCAAW,GAAX;QACE,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC;IACnC,CAAC;IA9BU,gBAAgB;QAL5B,+DAAS,CAAC;YACT,QAAQ,EAAE,aAAa;;;SAGxB,CAAC;yCAMiB,8DAAc;YACZ,gFAAc;YACL,oFAAgB;OAPjC,gBAAgB,CAgC5B;IAAD,uBAAC;CAAA;AAhC4B;;;;;;;;;;;;ACX7B,wHAAwH,wCAAwC,yBAAyB,4CAA4C,qIAAqI,6BAA6B,uLAAuL,2CAA2C,mpBAAmpB,qCAAqC,0PAA0P,wCAAwC,ghBAAghB,iDAAiD,kqBAAkqB,oCAAoC,mKAAmK,8CAA8C,wIAAwI,8CAA8C,uD;;;;;;;;;;;ACAjtG,iCAAiC,qBAAqB,gBAAgB,EAAE,kFAAkF,iBAAiB,EAAE,iCAAiC,oBAAoB,6BAA6B,iBAAiB,EAAE,wCAAwC,yBAAyB,EAAE,2DAA2D,0BAA0B,EAAE,sDAAsD,0BAA0B,EAAE,sDAAsD,wBAAwB,EAAE,+CAA+C,uwC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACArkB;AACU;AAC3B;AAC6B;AACI;AACjB;AAOvD;IAwBE,gCACU,MAAc,EACd,OAAuB,EACvB,gBAAkC,EAClC,MAAc;QAJxB,iBAMC;QALS,WAAM,GAAN,MAAM,CAAQ;QACd,YAAO,GAAP,OAAO,CAAgB;QACvB,qBAAgB,GAAhB,gBAAgB,CAAkB;QAClC,WAAM,GAAN,MAAM,CAAQ;QA1BxB,gBAAW,GAAG,IAAI,wDAAS,CAAC;YAC1B,IAAI,EAAE,IAAI,0DAAW,CAAC,EAAE,EAAE,CAAC,yDAAU,CAAC,QAAQ,EAAE,UAAC,CAAc;oBAC7D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;wBAC7D,IAAI,CAAC,CAAC,KAAK,KAAK,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;4BACrD,OAAO,EAAC,WAAW,EAAE,IAAI,EAAC,CAAC;yBAC5B;qBACF;oBACD,OAAO,IAAI,CAAC;gBACd,CAAC,CAAC,CAAC;YACH,GAAG,EAAE,IAAI,0DAAW,CAAC,EAAE,EAAE,yDAAU,CAAC,QAAQ,CAAC;YAC7C,QAAQ,EAAE,IAAI,0DAAW,CAAC,EAAE,CAAC;YAC7B,OAAO,EAAE,IAAI,0DAAW,CAAC,EAAE,CAAC;SAC7B,EAAE,UAAU,CAAY;YACvB,OAAO,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAC,kBAAkB,EAAE,IAAI,EAAC,CAAC;QAChG,CAAC,CAAC,CAAC;QAEH,WAAM,GAAG;YACP,EAAE,EAAE,EAAE;SACP,CAAC;QAEF,gBAAW,GAAG,KAAK,CAAC;IAQpB,CAAC;IAED,yCAAQ,GAAR;IACA,CAAC;IAGD,6CAAY,GAAZ;QACE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,cAAc,CAAC,EAAE,EAAC,WAAW,EAAE,EAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,EAAC,EAAC,CAAC,CAAC;IACrF,CAAC;IAED,2CAAU,GAAV;QAAA,iBAgDC;QA/CC,IAAI,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE;YAC1B,IAAI,CAAC,OAAO,CAAC,wBAAwB,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,UAAC,YAAY,EAAE,UAAU;gBAEhG,IAAI,UAAU,KAAK,OAAO,EAAE;oBAC1B,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;wBACd,KAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,EAAC,aAAa,EAAE,IAAI,EAAC,CAAC,CAAC;oBAC/D,CAAC,CAAC,CAAC;iBACJ;qBAAM;oBACL,KAAI,CAAC,OAAO,CAAC,cAAc,CAAC,uBAAuB,EAAE,GAAG,EAAE,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,YAAY,EAAE,UAAC,WAAW,EAAE,SAAS;wBAC5H,IAAI,WAAW,EAAE;4BACf,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,YAAY,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;4BACxG,KAAI,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,IAAI,EAAE,KAAI,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,KAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,UAAC,cAAc,EAAE,YAAY;gCACjJ,IAAI,cAAc,EAAE;oCAClB,KAAI,CAAC,MAAM,CAAC,EAAE,GAAG,YAAY,CAAC,SAAS,CAAC;oCACxC,KAAI,CAAC,gBAAgB,CAAC,cAAc,GAAG,IAAI,mEAAM,CAC/C,YAAY,CAAC,SAAS,EACtB,KAAI,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,KAAK,EAClC,KAAI,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,KAAK,EACtC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,EACvB,YAAY,CAAC,IAAI,CAAC,CAAC,OAAO,EAC1B,YAAY,CAAC,IAAI,CAAC,CAAC,OAAO,EAC1B,YAAY,CAAC,IAAI,CAAC,CAAC,gBAAgB,EACnC,YAAY,CAAC,IAAI,CAAC,CAAC,WAAW,EAC9B,YAAY,CAAC,IAAI,CAAC,CAAC,YAAY,CAChC,CAAC;oCACF,IAAI,YAAY,CAAC,cAAc,IAAI,YAAY,CAAC,cAAc,CAAC,OAAO,EAAE;wCACtE,KAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC,cAAc,CAAC,YAAY,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;qCAC1F;oCACD,KAAI,CAAC,OAAO,CAAC,YAAY,CAAC,KAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC,SAAS,EAAE,UAAC,gBAAgB,EAAE,cAAc;wCACzG,IAAI,gBAAgB,IAAI,cAAc,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE;4CAClE,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;gDACd,KAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC,yBAAyB,CAAC,cAAc,CAAC,SAAS,EAAE,KAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,KAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,eAAe,EAAE,KAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC;4CAClQ,CAAC,CAAC,CAAC;yCACJ;oCACH,CAAC,CAAC,CAAC;oCACH,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;wCACd,KAAI,CAAC,WAAW,GAAG,IAAI,CAAC;oCAC1B,CAAC,CAAC,CAAC;iCACJ;qCAAM;oCACL,KAAK,CAAC,oCAAoC,CAAC,CAAC;iCAC7C;4BACH,CAAC,CAAC,CAAC;yBACJ;oBACH,CAAC,CAAC,CAAC;iBACJ;YACH,CAAC,CAAC,CAAC;SACJ;IACH,CAAC;IAxFU,sBAAsB;QALlC,+DAAS,CAAC;YACT,QAAQ,EAAE,oBAAoB;;;SAG/B,CAAC;yCA0BkB,sDAAM;YACL,gFAAc;YACL,oFAAgB;YAC1B,oDAAM;OA5Bb,sBAAsB,CA2FlC;IAAD,6BAAC;CAAA;AA3FkC;;;;;;;;;;;;ACZnC,wHAAwH,wCAAwC,yBAAyB,yCAAyC,qIAAqI,6BAA6B,2EAA2E,mCAAmC,mHAAmH,qDAAqD,2BAA2B,2HAA2H,mDAAmD,wB;;;;;;;;;;;ACAn2B,sCAAsC,wBAAwB,sBAAsB,EAAE,0BAA0B,kBAAkB,2BAA2B,oBAAoB,oBAAoB,gBAAgB,kBAAkB,EAAE,gCAAgC,0BAA0B,uBAAuB,EAAE,YAAY,qBAAqB,eAAe,sBAAsB,EAAE,+CAA+C,ukC;;;;;;;;;;;;;;;;;;;;;;;;;;;ACA3X;AACY;AACb;AACiB;AAOxE;IAKE,6BACU,KAAqB,EACrB,MAAc,EACd,OAAuB,EACvB,gBAAkC,EAClC,MAAc;QAJd,UAAK,GAAL,KAAK,CAAgB;QACrB,WAAM,GAAN,MAAM,CAAQ;QACd,YAAO,GAAP,OAAO,CAAgB;QACvB,qBAAgB,GAAhB,gBAAgB,CAAkB;QAClC,WAAM,GAAN,MAAM,CAAQ;QARxB,eAAU,GAAG,EAAE,CAAC;IASb,CAAC;IAEJ,sCAAQ,GAAR;QAAA,iBAaC;QAZC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,SAAS,CAAC,gBAAM;YACrC,IAAI,MAAM,CAAC,SAAS,EAAE;gBACpB,KAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;gBAClC,KAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,MAAM,CAAC,SAAS,EAAE,UAAC,MAAM,EAAE,IAAI;oBAC3D,IAAI,IAAI,CAAC,cAAc,CAAC,aAAa,CAAC,EAAE;wBACtC,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;4BACd,KAAI,CAAC,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,IAAI,EAAE,CAAC;wBAC/C,CAAC,CAAC,CAAC;qBACJ;gBACH,CAAC,CAAC,CAAC;aACJ;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,uCAAS,GAAT;QAAA,iBAiCC;QAhCC,IAAI,MAAM,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,UAAC,MAAM;YAC3C,IAAI,MAAM,CAAC,OAAO,KAAK,KAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC,OAAO,EAAE;gBACnE,MAAM,GAAG,IAAI,CAAC;aACf;QACH,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,EAAE;YACX,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,UAAC,UAAU,EAAE,QAAQ;gBAC1D,IAAI,UAAU,EAAE;oBACd,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC,KAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC;oBACzE,KAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,UAAC,MAAM,EAAE,IAAI;wBAC3C,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;oBAC9C,CAAC,CAAC,CAAC;oBACH,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;wBACd,KAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,UAAU,GAAG,KAAI,CAAC,SAAS,CAAC,CAAC,CAAC;oBACtD,CAAC,CAAC,CAAC;iBACJ;qBAAM;oBACL,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;iBACrC;gBACD,+BAA+B;gBAC/B,iDAAiD;gBACjD,+BAA+B;YACjC,CAAC,CAAC,CAAC;SACJ;aAAM;YACL,IAAI,CAAC,gBAAgB,CAAC,cAAc,GAAG,IAAI,CAAC;YAC5C,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,EAAE,UAAC,YAAY,EAAE,UAAU;gBAChE,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;gBACtC,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;oBACd,KAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC9B,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;SACJ;IACH,CAAC;IA7DU,mBAAmB;QAL/B,+DAAS,CAAC;YACT,QAAQ,EAAE,iBAAiB;;;SAG5B,CAAC;yCAOiB,8DAAc;YACb,sDAAM;YACL,gFAAc;YACL,oFAAgB;YAC1B,oDAAM;OAVb,mBAAmB,CA+D/B;IAAD,0BAAC;CAAA;AA/D+B;;;;;;;;;;;;ACVhC,wKAAwK,8BAA8B,+sBAA+sB,6BAA6B,+jBAA+jB,8BAA8B,8QAA8Q,8BAA8B,wQAAwQ,4BAA4B,8hBAA8hB,0BAA0B,olBAAolB,6BAA6B,yB;;;;;;;;;;;ACAxwG,yBAAyB,gBAAgB,EAAE,kCAAkC,kBAAkB,EAAE,wCAAwC,sBAAsB,EAAE,oDAAoD,6BAA6B,EAAE,mDAAmD,4BAA4B,EAAE,6BAA6B,kBAAkB,wBAAwB,4BAA4B,iBAAiB,sBAAsB,wBAAwB,uBAAuB,eAAe,gBAAgB,qBAAqB,mBAAmB,EAAE,oCAAoC,wBAAwB,oBAAoB,qBAAqB,EAAE,yCAAyC,6DAA6D,6DAA6D,EAAE,uCAAuC,2DAA2D,2DAA2D,EAAE,oCAAoC,kBAAkB,uBAAuB,2BAA2B,EAAE,0CAA0C,sBAAsB,EAAE,sDAAsD,6BAA6B,4BAA4B,EAAE,qDAAqD,2BAA2B,8BAA8B,EAAE,uBAAuB,qBAAqB,gBAAgB,qBAAqB,EAAE,+CAA+C,20F;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACA97C;AACD;AACnB;AACqB;AACI;AAOxE;IAaE,uBACU,KAAqB,EACrB,OAAuB,EACvB,gBAAkC,EAClC,MAAc;QAHd,UAAK,GAAL,KAAK,CAAgB;QACrB,YAAO,GAAP,OAAO,CAAgB;QACvB,qBAAgB,GAAhB,gBAAgB,CAAkB;QAClC,WAAM,GAAN,MAAM,CAAQ;QAfxB,oBAAe,GAAG,IAAI,CAAC;QAEvB,aAAQ,GAAG,IAAI,wDAAS,CAAC;YACvB,OAAO,EAAE,IAAI,0DAAW,CAAC,EAAE,EAAE,yDAAU,CAAC,QAAQ,CAAC;YACjD,MAAM,EAAE,IAAI,0DAAW,CAAC,IAAI,EAAE,yDAAU,CAAC,QAAQ,CAAC;YAClD,OAAO,EAAE,IAAI,0DAAW,CAAC,EAAE,CAAC;YAC5B,KAAK,EAAE,IAAI,0DAAW,CAAC,CAAC,EAAE,yDAAU,CAAC,QAAQ,CAAC;YAC9C,GAAG,EAAE,IAAI,0DAAW,CAAC,MAAM,EAAE,yDAAU,CAAC,QAAQ,CAAC;SAClD,CAAC,CAAC;QACH,sBAAiB,GAAG,KAAK,CAAC;IAOvB,CAAC;IAEJ,gCAAQ,GAAR;QAAA,iBAKC;QAJC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,gBAAM;YAC5D,KAAI,CAAC,eAAe,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;YACpC,KAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAC,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,EAAC,CAAC,CAAC;QACvF,CAAC,CAAC,CAAC;IACL,CAAC;IAED,8CAAsB,GAAtB;QAAA,iBAUC;QATC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE;YACtC,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,UAAC,YAAY;gBAC5E,IAAI,YAAY,KAAK,KAAK,EAAE;oBAC1B,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;wBACd,KAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,EAAC,iBAAiB,EAAE,IAAI,EAAC,CAAC,CAAC;oBACpE,CAAC,CAAC,CAAC;iBACJ;YACH,CAAC,CAAC,CAAC;SACJ;IACH,CAAC;IAED,8BAAM,GAAN;QAAA,iBAwBC;QAvBC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE;YACvB,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,UAAC,YAAY;gBAC5E,IAAI,YAAY,KAAK,KAAK,EAAE;oBAC1B,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;wBACd,KAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,EAAC,iBAAiB,EAAE,IAAI,EAAC,CAAC,CAAC;oBACpE,CAAC,CAAC,CAAC;iBACJ;qBAAM;oBACL,KAAI,CAAC,OAAO,CAAC,SAAS,CACpB,KAAI,CAAC,eAAe,EACpB,KAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,KAAK,EAClC,KAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,KAAK,EACjC,KAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,EAC9B,KAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,KAAK,EAChC,KAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,KAAK,EAClC,UAAC,WAAW,EAAE,SAAS;wBACrB,IAAI,WAAW,EAAE;4BACf,KAAK,CAAC,yBAAyB,CAAC,CAAC;4BACjC,KAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAC,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,EAAC,CAAC,CAAC;yBACtF;oBACH,CAAC,CAAC,CAAC;iBACN;YACH,CAAC,CAAC,CAAC;SACJ;IACH,CAAC;IAED,qCAAa,GAAb;QACE,IAAI,CAAC,iBAAiB,GAAG,CAAC,IAAI,CAAC,iBAAiB,CAAC;IACnD,CAAC;IAED,mCAAW,GAAX;QACE,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC;IACnC,CAAC;IAvEU,aAAa;QALzB,+DAAS,CAAC;YACT,QAAQ,EAAE,UAAU;;;SAGrB,CAAC;yCAeiB,8DAAc;YACZ,gFAAc;YACL,oFAAgB;YAC1B,oDAAM;OAjBb,aAAa,CAyEzB;IAAD,oBAAC;CAAA;AAzEyB;;;;;;;;;;;;ACX1B,gMAAgM,6BAA6B,6EAA6E,gCAAgC,yQAAyQ,qCAAqC,0PAA0P,sCAAsC,qPAAqP,qCAAqC,2LAA2L,gDAAgD,kFAAkF,8CAA8C,mvBAAmvB,8CAA8C,qfAAqf,kDAAkD,0vBAA0vB,iDAAiD,yC;;;;;;;;;;;ACAhpH,yBAAyB,8BAA8B,EAAE,qBAAqB,sBAAsB,EAAE,sBAAsB,kBAAkB,2BAA2B,4BAA4B,qBAAqB,eAAe,EAAE,mCAAmC,oBAAoB,0BAA0B,kCAAkC,wBAAwB,0BAA0B,EAAE,sBAAsB,eAAe,EAAE,6CAA6C,oBAAoB,wBAAwB,0BAA0B,0BAA0B,EAAE,6BAA6B,0BAA0B,kBAAkB,uBAAuB,EAAE,+CAA+C,mnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACA9pB;AACa;AACJ;AACF;AACzB;AAOzC;IAIE,2BAAoB,QAAmB,EAAU,gBAAkC,EAAU,OAAuB,EAAU,QAAkB;QAAhJ,iBAWC;QAXmB,aAAQ,GAAR,QAAQ,CAAW;QAAU,qBAAgB,GAAhB,gBAAgB,CAAkB;QAAU,YAAO,GAAP,OAAO,CAAgB;QAAU,aAAQ,GAAR,QAAQ,CAAU;QAC9I,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,KAAK,CAAC;QAClD,IAAI,CAAC,UAAU,GAAG,IAAI,wDAAS,CAAC;YAC9B,QAAQ,EAAE,IAAI,0DAAW,CAAC,EAAE,EAAE,yDAAU,CAAC,QAAQ,CAAC;YAClD,YAAY,EAAE,IAAI,0DAAW,CAAC,EAAE,EAAE,yDAAU,CAAC,QAAQ,CAAC;YACtD,gBAAgB,EAAE,IAAI,0DAAW,CAAC,EAAE,EAAE,yDAAU,CAAC,QAAQ,CAAC;SAC3D,EAAE,CAAC,UAAC,CAAY;gBACf,OAAO,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAC,kBAAkB,EAAE,IAAI,EAAC,CAAC;YAC7G,CAAC,EAAE,UAAC,CAAY;gBACd,OAAO,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,KAAK,KAAK,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAC,eAAe,EAAE,IAAI,EAAC,CAAC;YACpG,CAAC,CAAC,CAAC,CAAC;IACN,CAAC;IAED,oCAAQ,GAAR,cAAY,CAAC;IAEb,oCAAQ,GAAR,UAAS,KAAK;QACZ,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QAChE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QAClD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7D,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;IAC9B,CAAC;IAED,8CAAkB,GAAlB;QAAA,iBAWC;QAVC,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE;YACzB,IAAI,CAAC,gBAAgB,CAAC,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC;YAC1E,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,UAAC,MAAM,EAAE,IAAI;gBAC3C,IAAI,MAAM,EAAE;oBACV,KAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;iBACzB;qBAAM;oBACL,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;iBACnB;YACH,CAAC,CAAC,CAAC;SACJ;IACH,CAAC;IAED,gCAAI,GAAJ;QACE,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;IACvB,CAAC;IA1CU,iBAAiB;QAL7B,+DAAS,CAAC;YACT,QAAQ,EAAE,cAAc;;;SAGzB,CAAC;yCAK8B,uDAAS,EAA4B,oFAAgB,EAAmB,gFAAc,EAAoB,wDAAQ;OAJrI,iBAAiB,CA4C7B;IAAD,wBAAC;CAAA;AA5C6B;;;;;;;;;;;;ACX9B,6GAA6G,+BAA+B,yCAAyC,iCAAiC,yZAAyZ,aAAa,6CAA6C,sCAAsC,GAAG,kCAAkC,sGAAsG,cAAc,6BAA6B,6FAA6F,0LAA0L,yCAAyC,kTAAkT,0CAA0C,+CAA+C,sBAAsB,iMAAiM,iDAAiD,yPAAyP,mBAAmB,iPAAiP,kCAAkC,8GAA8G,iCAAiC,wMAAwM,iDAAiD,uFAAuF,iDAAiD,sFAAsF,gDAAgD,uFAAuF,iDAAiD,uFAAuF,+CAA+C,sFAAsF,kDAAkD,iVAAiV,6CAA6C,mI;;;;;;;;;;;ACAjyH,yBAAyB,kBAAkB,2BAA2B,mCAAmC,oBAAoB,yBAAyB,EAAE,uBAAuB,kBAAkB,2BAA2B,mBAAmB,EAAE,gDAAgD,oBAAoB,0BAA0B,qCAAqC,qBAAqB,mBAAmB,uBAAuB,EAAE,mDAAmD,0BAA0B,EAAE,uDAAuD,gCAAgC,qBAAqB,sBAAsB,EAAE,8CAA8C,oBAAoB,6BAA6B,qBAAqB,sBAAsB,0BAA0B,EAAE,+DAA+D,sBAAsB,+BAA+B,uBAAuB,wBAAwB,2BAA2B,EAAE,oFAAoF,wBAAwB,8BAA8B,yCAAyC,EAAE,0GAA0G,gCAAgC,EAAE,iHAAiH,gCAAgC,EAAE,mHAAmH,gCAAgC,+BAA+B,EAAE,kGAAkG,8BAA8B,gCAAgC,kCAAkC,EAAE,oGAAoG,gCAAgC,EAAE,0GAA0G,gCAAgC,EAAE,qGAAqG,gCAAgC,EAAE,2GAA2G,gCAAgC,EAAE,gHAAgH,4BAA4B,kCAAkC,sCAAsC,kCAAkC,8BAA8B,8BAA8B,2BAA2B,6BAA6B,EAAE,4GAA4G,mCAAmC,2BAA2B,EAAE,oHAAoH,qCAAqC,gCAAgC,kCAAkC,EAAE,oIAAoI,4BAA4B,+BAA+B,6BAA6B,0BAA0B,EAAE,kJAAkJ,+BAA+B,EAAE,wJAAwJ,+BAA+B,EAAE,sJAAsJ,+BAA+B,kCAAkC,oCAAoC,qCAAqC,EAAE,qEAAqE,wBAAwB,EAAE,uBAAuB,mBAAmB,yBAAyB,EAAE,8BAA8B,oBAAoB,0BAA0B,8BAA8B,mBAAmB,wBAAwB,oBAAoB,iBAAiB,uBAAuB,EAAE,oCAAoC,6BAA6B,sBAAsB,uBAAuB,EAAE,6CAA6C,6DAA6D,6DAA6D,EAAE,2CAA2C,2DAA2D,2DAA2D,EAAE,qCAAqC,uBAAuB,kBAAkB,0BAA0B,gCAAgC,mBAAmB,sBAAsB,EAAE,2HAA2H,yBAAyB,qBAAqB,0BAA0B,2BAA2B,EAAE,yIAAyI,oBAAoB,2BAA2B,eAAe,gBAAgB,2BAA2B,sBAAsB,uBAAuB,EAAE,4HAA4H,wBAAwB,EAAE,6DAA6D,yBAAyB,sBAAsB,cAAc,qBAAqB,kBAAkB,EAAE,sEAAsE,sBAAsB,EAAE,oFAAoF,yBAAyB,EAAE,0FAA0F,yBAAyB,EAAE,wFAAwF,yBAAyB,4BAA4B,8BAA8B,+BAA+B,EAAE,sEAAsE,6CAA6C,qBAAqB,EAAE,+CAA+C,unS;;;;;;;;;;;;;;;;;;;;;;;;;;ACAv4M;AACa;AACA;AAOxE;IAME,0BACU,KAAqB,EACrB,MAAc,EACd,gBAAkC;QAFlC,UAAK,GAAL,KAAK,CAAgB;QACrB,WAAM,GAAN,MAAM,CAAQ;QACd,qBAAgB,GAAhB,gBAAgB,CAAkB;QAR5C,6BAAwB,GAAG,EAAE,CAAC;IAU9B,CAAC;IAED,mCAAQ,GAAR;QAAA,iBAmCC;QAlCC,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE;YAC9C,IAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAChD,IAAI,YAAY,CAAC,MAAM,IAAI,CAAC,EAAE;gBAC5B,IAAI,CAAC,YAAY,GAAG,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;aACnD;YACD,IAAI,YAAY,CAAC,MAAM,IAAI,CAAC,EAAE;gBAC5B,IAAI,CAAC,wBAAwB,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;aACjD;SACF;aAAM,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE;YACrD,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,SAAS,CAAC;SACnE;aAAM;YACL,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;SAC1B;QAED,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,UAAC,KAAK;YACzD,IAAI,KAAK,YAAY,+DAAe,EAAE;gBACpC,IAAI,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE;oBACxC,IAAM,YAAY,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;oBAC1C,IAAI,YAAY,CAAC,MAAM,IAAI,CAAC,EAAE;wBAC5B,KAAI,CAAC,YAAY,GAAG,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;qBACnD;oBACD,IAAI,YAAY,CAAC,MAAM,IAAI,CAAC,EAAE;wBAC5B,KAAI,CAAC,wBAAwB,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;wBAChD,IAAI,KAAI,CAAC,wBAAwB,KAAK,UAAU,EAAE;4BAChD,KAAI,CAAC,wBAAwB,GAAG,WAAW,CAAC;yBAC7C;qBACF;iBACF;qBAAM,IAAI,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE;oBAC/C,KAAI,CAAC,YAAY,GAAG,KAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,SAAS,CAAC;iBACnE;qBAAM;oBACL,KAAI,CAAC,YAAY,GAAG,IAAI,CAAC;iBAC1B;aACF;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,sCAAW,GAAX;QACE,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE,CAAC;IACtC,CAAC;IAED,iCAAM,GAAN;QACE,IAAI,CAAC,gBAAgB,CAAC,aAAa,EAAE,CAAC;QACtC,IAAI,CAAC,gBAAgB,CAAC,OAAO,GAAG,EAAE,CAAC;QACnC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAC,WAAW,EAAE,EAAC,IAAI,EAAE,MAAM,EAAC,EAAC,CAAC,CAAC;IAClE,CAAC;IA1DU,gBAAgB;QAL5B,+DAAS,CAAC;YACT,QAAQ,EAAE,aAAa;;;SAGxB,CAAC;yCAQiB,8DAAc;YACb,sDAAM;YACI,oFAAgB;OATjC,gBAAgB,CA4D5B;IAAD,uBAAC;CAAA;AA5D4B;;;;;;;;;;;;ACT7B,ycAAyc,4BAA4B,GAAG,kCAAkC,gHAAgH,oBAAoB,GAAG,kCAAkC,2HAA2H,kDAAkD,uBAAuB,qBAAqB,GAAG,kCAAkC,yYAAyY,cAAc,2D;;;;;;;;;;;ACAx0C,yBAAyB,kBAAkB,2BAA2B,gBAAgB,EAAE,mBAAmB,kBAAkB,mBAAmB,EAAE,4BAA4B,oBAAoB,6BAA6B,8BAA8B,8BAA8B,mBAAmB,wBAAwB,wBAAwB,EAAE,kCAAkC,sBAAsB,4BAA4B,yBAAyB,qBAAqB,EAAE,yCAAyC,gCAAgC,sBAAsB,EAAE,6BAA6B,oBAAoB,6BAA6B,4BAA4B,8BAA8B,mBAAmB,wBAAwB,EAAE,kCAAkC,4BAA4B,EAAE,YAAY,kBAAkB,wBAAwB,mBAAmB,sBAAsB,EAAE,kBAAkB,kBAAkB,mBAAmB,EAAE,oBAAoB,kBAAkB,wBAAwB,mBAAmB,mBAAmB,EAAE,2BAA2B,wBAAwB,kBAAkB,EAAE,6BAA6B,oBAAoB,qCAAqC,mBAAmB,mBAAmB,EAAE,oCAAoC,sBAAsB,4BAA4B,gCAAgC,uBAAuB,wBAAwB,0BAA0B,yBAAyB,mBAAmB,qBAAqB,EAAE,+CAA+C,myG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACA7+C;AACK;AAC/B;AAC2B;AACrB;AACoB;AAOnE;IA4CE,0BACU,KAAqB,EACrB,gBAAkC,EAClC,OAAuB,EACvB,MAAc,EACd,cAA8B;QAJ9B,UAAK,GAAL,KAAK,CAAgB;QACrB,qBAAgB,GAAhB,gBAAgB,CAAkB;QAClC,YAAO,GAAP,OAAO,CAAgB;QACvB,WAAM,GAAN,MAAM,CAAQ;QACd,mBAAc,GAAd,cAAc,CAAgB;QA3CxC,YAAO,GAAG;YACR;gBACE,KAAK,EAAE,OAAO;gBACd,MAAM,EAAE,KAAK;aACd;YACD;gBACE,KAAK,EAAE,QAAQ;gBACf,MAAM,EAAE,KAAK;aACd;YACD;gBACE,KAAK,EAAE,SAAS;gBAChB,MAAM,EAAE,KAAK;aACd;YACD;gBACE,KAAK,EAAE,QAAQ;gBACf,MAAM,EAAE,KAAK;aACd;YACD;gBACE,KAAK,EAAE,KAAK;gBACZ,MAAM,EAAE,IAAI;aACb;SACF,CAAC;QAEF,iBAAY,GAAG;YACb,IAAI,EAAE,IAAI;YACV,MAAM,EAAE,IAAI;SACb,CAAC;QAEF,iBAAY,GAAG,EAAE,CAAC;QAIlB,UAAK,GAAG,CAAC,CAAC;QACV,YAAO,GAAG;YACR,IAAI,EAAE,EAAE;YACR,KAAK,EAAE,CAAC;SACT,CAAC;IASF,CAAC;IAGD,mCAAQ,GAAR;QAAA,iBAyBC;QAxBC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC;YACtD,KAAI,CAAC,gBAAgB,EAAE,CAAC;QAC1B,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,SAAS,CAAC,UAAC,SAAiB;YACxF,IAAI,KAAI,CAAC,OAAO,CAAC,KAAK,EAAE;gBACtB,IAAM,YAAY,GAAG,KAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;gBAC9C,KAAK,IAAI,CAAC,GAAG,YAAY,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;oBAC1C,IAAI,SAAS,GAAG,KAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE;wBAC5C,KAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;qBAChC;iBACF;gBACD,IAAI,YAAY,KAAK,KAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE;oBAC7C,KAAI,CAAC,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC;oBACvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;wBACjD,KAAI,CAAC,OAAO,CAAC,KAAK,IAAI,KAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;qBAC9C;iBACF;aACF;QACH,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC,gBAAgB,CAAC,uBAAuB,CAAC,SAAS,CAAC,UAAC,SAAiB;YACpG,IAAI,KAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,SAAS,KAAK,SAAS,EAAE;gBAC/D,KAAI,CAAC,gBAAgB,EAAE,CAAC;aACzB;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAGD,oCAAS,GAAT,UAAU,IAAI;QAAd,iBA8GC;QA7GC,IAAI,CAAC,KAAK,GAAG,IAAI,wDAAK,CAAC;YACrB,KAAK,EAAE,EAAC,IAAI,EAAE,EAAE,EAAC;YACjB,OAAO,EAAE,EAAC,OAAO,EAAE,KAAK,EAAC;YACzB,SAAS,EAAE,EAAC,OAAO,EAAE,KAAK,EAAC;YAC3B,MAAM,EAAE,EAAC,OAAO,EAAE,KAAK,EAAC;YACxB,KAAK,EAAE;gBACL,IAAI,EAAE,MAAM;gBACZ,eAAe,EAAE,aAAa;gBAC9B,MAAM,EAAE,IAAI;gBACZ,QAAQ,EAAE,IAAI;aACf;YAED,KAAK,EAAE;gBACL,GAAG,EAAE,CAAC;gBACN,UAAU,EAAE,CAAC;gBACb,KAAK,EAAE;oBACL,IAAI,EAAE,EAAE;iBACT;gBACD,aAAa,EAAE,SAAS;gBACxB,aAAa,EAAE,CAAC;gBAChB,SAAS,EAAE,SAAS;gBACpB,SAAS,EAAE,CAAC;gBACZ,SAAS,EAAE,CAAC;gBACZ,UAAU,EAAE,GAAG;gBACf,SAAS,EAAE,SAAS;gBACpB,MAAM,EAAE;oBACN,CAAC,EAAE,CAAC,CAAC;oBACL,KAAK,EAAE,MAAM;oBACb,CAAC,EAAE,CAAC,GAAG;oBACP,KAAK,EAAE;wBACL,OAAO,EAAE,SAAS;wBAClB,UAAU,EAAE,MAAM;qBACnB;oBACD,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,eAAe;iBAC3D;gBACD,aAAa,EAAE,KAAK;aACrB;YAED,KAAK,EAAE;gBACL,IAAI,EAAE,UAAU;gBAChB,aAAa,EAAE,SAAS;gBACxB,SAAS,EAAE,SAAS;gBACpB,SAAS,EAAE,CAAC;gBACZ,SAAS,EAAE,CAAC;gBACZ,UAAU,EAAE,EAAE;gBACd,SAAS,EAAE,SAAS;gBACpB,MAAM,EAAE;oBACN,KAAK,EAAE;wBACL,OAAO,EAAE,SAAS;wBAClB,UAAU,EAAE,MAAM;qBACnB;iBACF;gBACD,UAAU,EAAE,CAAC;gBACb,UAAU,EAAE,CAAC;gBACb,QAAQ,EAAE,QAAQ;gBAClB,0BAA0B;gBAC1B,eAAe,EAAE,OAAO;aACzB;YAED,OAAO,EAAE;gBACP,OAAO,EAAE,KAAK;aACf;YAED,WAAW,EAAE;gBACX,IAAI,EAAE;oBACJ,SAAS,EAAE;wBACT,cAAc,EAAE;4BACd,EAAE,EAAE,CAAC;4BACL,EAAE,EAAE,CAAC;4BACL,EAAE,EAAE,CAAC;4BACL,EAAE,EAAE,CAAC;yBACN;wBACD,KAAK,EAAE;4BACL,CAAC,CAAC,EAAE,uBAAuB,CAAC;4BAC5B,CAAC,CAAC,EAAE,qBAAqB,CAAC;yBAC3B;qBACF;oBACD,MAAM,EAAE;wBACN,OAAO,EAAE,KAAK;wBACd,MAAM,EAAE,CAAC;qBACV;oBACD,SAAS,EAAE,CAAC;oBACZ,SAAS,EAAE,IAAI;iBAChB;gBAED,MAAM,EAAE;oBACN,KAAK,EAAE;wBACL,MAAM,EAAE;4BACN,SAAS,EAAE,UAAC,GAAG;gCACb,KAAI,CAAC,YAAY,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gCACzC,KAAI,CAAC,YAAY,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;4BAC7C,CAAC;yBACF;qBACF;oBACD,MAAM,EAAE;wBACN,QAAQ,EAAE;4BACR,KAAI,CAAC,YAAY,CAAC,IAAI,GAAG,IAAI,CAAC;4BAC9B,KAAI,CAAC,YAAY,CAAC,MAAM,GAAG,IAAI,CAAC;wBAClC,CAAC;qBACF;iBACF;aACF;YACD,MAAM,EAAE;gBACN;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,IAAI;iBACX;aACF;SACF,CAAC,CAAC;IACL,CAAC;IAGD,2CAAgB,GAAhB;QAAA,iBA+BC;QA9BC,IAAI,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,MAAM,EAAE;YAC9C,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,SAAS,EAAE,UAAC,MAAM,EAAE,IAAI;gBACxF,KAAI,CAAC,KAAK,GAAG,CAAC,CAAC;gBACf,KAAI,CAAC,OAAO,CAAC,IAAI,GAAG,EAAE,CAAC;gBACvB,KAAI,CAAC,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC;gBACvB,KAAI,CAAC,YAAY,GAAG,EAAE,CAAC;gBACvB,IAAI,IAAI,CAAC,aAAa,EAAE;oBACtB,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,UAAC,IAAI,EAAE,GAAG;wBACnC,IAAI,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,MAAM,KAAK,EAAE,EAAE;4BACnC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC;yBAC7E;oBACH,CAAC,CAAC,CAAC;oBACH,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,UAAC,IAAI;wBAC9B,KAAI,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC;wBACrB,IAAI,KAAI,CAAC,gBAAgB,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;4BAClD,KAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;4BAC7B,KAAI,CAAC,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC;yBAC9B;wBACD,KAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,UAAU,CAAC,KAAI,CAAC,cAAc,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBACpG,CAAC,CAAC,CAAC;oBACH,KAAI,CAAC,YAAY,GAAG,KAAI,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;wBACvD,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;oBACrB,CAAC,CAAC,CAAC;iBACJ;gBACD,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;oBACd,KAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;gBAChE,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;SACJ;IAEH,CAAC;IAED,uCAAY,GAAZ,UAAa,MAAM;QACjB,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,UAAC,CAAC;YACrB,CAAC,CAAC,MAAM,GAAG,KAAK,CAAC;QACnB,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC;QAErB,IAAM,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC;QACrB,IAAI,GAAG,GAAG,IAAI,CAAC;QACf,IAAM,OAAO,GAAG,EAAE,CAAC;QAEnB,IAAI,MAAM,CAAC,KAAK,KAAK,OAAO,EAAE;YAC5B,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,UAAC,IAAI;gBAC7B,IAAM,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;gBACxD,IAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,iBAAO,IAAI,cAAO,CAAC,CAAC,CAAC,KAAK,IAAI,EAAnB,CAAmB,CAAC,CAAC;gBAC1D,IAAI,IAAI,EAAE;oBACR,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;iBACpB;qBAAM;oBACL,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;iBAC/B;YACH,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YAChD,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;SAC5E;aAAM,IAAI,MAAM,CAAC,KAAK,KAAK,QAAQ,EAAE;YACpC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,UAAC,IAAI;gBAC7B,IAAM,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;gBACzD,IAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,iBAAO,IAAI,cAAO,CAAC,CAAC,CAAC,KAAK,IAAI,EAAnB,CAAmB,CAAC,CAAC;gBAC1D,IAAI,IAAI,EAAE;oBACR,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;iBACpB;qBAAM;oBACL,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;iBAC/B;YACH,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YAChD,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;SAC5E;aAAM,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,EAAE;YACrC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,UAAC,IAAI;gBAC7B,IAAM,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;gBACzD,IAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,iBAAO,IAAI,cAAO,CAAC,CAAC,CAAC,KAAK,IAAI,EAAnB,CAAmB,CAAC,CAAC;gBAC1D,IAAI,IAAI,EAAE;oBACR,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;iBACpB;qBAAM;oBACL,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;iBAC/B;YACH,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YAChD,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;SAC5E;aAAM,IAAI,MAAM,CAAC,KAAK,KAAK,QAAQ,EAAE;YACpC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,UAAC,IAAI;gBAC7B,IAAM,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;gBACzD,IAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,iBAAO,IAAI,cAAO,CAAC,CAAC,CAAC,KAAK,IAAI,EAAnB,CAAmB,CAAC,CAAC;gBAC1D,IAAI,IAAI,EAAE;oBACR,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;iBACpB;qBAAM;oBACL,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;iBAC/B;YACH,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YAChD,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;SAC5E;aAAM;YACL,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;SAC3D;QAED,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACjD,CAAC;IAGD,sCAAW,GAAX;QACE,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC;QACjC,IAAI,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC;QAClC,IAAI,CAAC,oBAAoB,CAAC,WAAW,EAAE,CAAC;IAC1C,CAAC;IA1SU,gBAAgB;QAL5B,+DAAS,CAAC;YACT,QAAQ,EAAE,aAAa;;;SAGxB,CAAC;yCA8CiB,8DAAc;YACH,oFAAgB;YACzB,gFAAc;YACf,oDAAM;YACE,+EAAc;OAjD7B,gBAAgB,CA4S5B;IAAD,uBAAC;CAAA;AA5S4B;;;;;;;;;;;;ACZ7B,8MAA8M,6BAA6B,yhFAAyhF,2CAA2C,oFAAoF,sCAAsC,oC;;;;;;;;;;;ACAz6F,yBAAyB,kBAAkB,2BAA2B,gBAAgB,EAAE,WAAW,mBAAmB,4BAA4B,0BAA0B,EAAE,uBAAuB,kBAAkB,2BAA2B,mCAAmC,iBAAiB,EAAE,sCAAsC,oBAAoB,6BAA6B,wBAAwB,yBAAyB,sBAAsB,0BAA0B,EAAE,0CAA0C,yBAAyB,EAAE,+CAA+C,6BAA6B,EAAE,yFAAyF,6BAA6B,0BAA0B,yBAAyB,EAAE,gDAAgD,+BAA+B,EAAE,qCAAqC,oBAAoB,qBAAqB,kBAAkB,qBAAqB,EAAE,kDAAkD,oBAAoB,EAAE,6DAA6D,6BAA6B,EAAE,4CAA4C,wBAAwB,EAAE,+CAA+C,u5E;;;;;;;;;;;;;;;;;;;;;;;;;ACA/sC;AACD;AAOjD;IAKE,gCAAoB,KAAqB;QAArB,UAAK,GAAL,KAAK,CAAgB;QACvC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAE,gBAAM,IAAI,cAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAnB,CAAmB,CAAE,CAAC;IAC/D,CAAC;IAED,yCAAQ,GAAR;IAEA,CAAC;IAXU,sBAAsB;QALlC,+DAAS,CAAC;YACT,QAAQ,EAAE,oBAAoB;;;SAG/B,CAAC;yCAM2B,8DAAc;OAL9B,sBAAsB,CAalC;IAAD,6BAAC;CAAA;AAbkC;;;;;;;;;;;;ACRnC,wHAAwH,qCAAqC,yBAAyB,4CAA4C,kJAAkJ,6BAA6B,+MAA+M,2CAA2C,qlBAAqlB,oDAAoD,iMAAiM,kDAAkD,+JAA+J,iDAAiD,+IAA+I,2DAA2D,2BAA2B,mLAAmL,4CAA4C,6FAA6F,8CAA8C,uD;;;;;;;;;;;ACAtyE,iCAAiC,uBAAuB,EAAE,4CAA4C,iBAAiB,EAAE,gCAAgC,oBAAoB,wBAAwB,0BAA0B,sBAAsB,kBAAkB,qBAAqB,EAAE,kDAAkD,sBAAsB,4BAA4B,gCAAgC,wBAAwB,oBAAoB,qBAAqB,EAAE,qDAAqD,sBAAsB,+BAA+B,wBAAwB,oBAAoB,qBAAqB,EAAE,mCAAmC,oBAAoB,0BAA0B,qCAAqC,EAAE,0CAA0C,yBAAyB,oBAAoB,yBAAyB,EAAE,+CAA+C,29D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAx2B;AACD;AACE;AACI;AACjC;AACE;AAOzC;IAgBE,gCACU,MAAc,EACd,OAAuB,EACvB,gBAAkC,EAClC,MAAc,EACd,QAAkB;QAL5B,iBAOC;QANS,WAAM,GAAN,MAAM,CAAQ;QACd,YAAO,GAAP,OAAO,CAAgB;QACvB,qBAAgB,GAAhB,gBAAgB,CAAkB;QAClC,WAAM,GAAN,MAAM,CAAQ;QACd,aAAQ,GAAR,QAAQ,CAAU;QApB5B,eAAU,GAAG,EAAE,CAAC;QAChB,aAAQ,GAAG,KAAK,CAAC;QAEjB,gBAAW,GAAG,IAAI,wDAAS,CAAC;YAC1B,IAAI,EAAE,IAAI,0DAAW,CAAC,EAAE,EAAE,CAAC,yDAAU,CAAC,QAAQ,EAAE,UAAC,CAAc;oBAC7D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;wBAC7D,IAAI,CAAC,CAAC,KAAK,KAAK,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,KAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,SAAS,EAAE;4BACrJ,OAAO,EAAC,WAAW,EAAE,IAAI,EAAC,CAAC;yBAC5B;qBACF;oBACD,OAAO,IAAI,CAAC;gBACd,CAAC,CAAC,CAAC;YACH,IAAI,EAAE,IAAI,0DAAW,CAAC,EAAE,CAAC;SAC1B,CAAC,CAAC;IASH,CAAC;IAED,yCAAQ,GAAR;QAAA,iBAWC;QAVC,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAChF,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAChF,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,SAAS,EAAE,UAAC,MAAM,EAAE,IAAI;YACxF,IAAI,IAAI,CAAC,cAAc,CAAC,aAAa,CAAC,EAAE;gBACtC,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;oBACd,KAAI,CAAC,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,IAAI,EAAE,CAAC;gBAC/C,CAAC,CAAC,CAAC;aACJ;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,+CAAc,GAAd;QACE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;IACvB,CAAC;IAED,6CAAY,GAAZ;QACE,IAAI,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE;YAC1B,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC;YAC9E,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC;SACpF;IACH,CAAC;IAED,4CAAW,GAAX;QAAA,iBAkBC;QAjBC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,SAAS,EAAE;YACtE,KAAK,IAAI,CAAC,GAAG,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;gBAClE,IAAI,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,KAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,SAAS,EAAE;oBAChG,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;iBAC5C;aACF;YACD,KAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC;gBAC9B,KAAI,CAAC,MAAM,CAAC,GAAG,CAAC;oBACd,IAAI,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,MAAM,EAAE;wBACxC,KAAI,CAAC,gBAAgB,CAAC,aAAa,GAAG,KAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;wBACvE,KAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,UAAU,GAAG,KAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC;qBACpF;yBAAM;wBACL,KAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;qBAC7B;gBACH,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,qCAAI,GAAJ;QACE,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;IACvB,CAAC;IAED,4CAAW,GAAX,cAAe,CAAC;IAzEL,sBAAsB;QALlC,+DAAS,CAAC;YACT,QAAQ,EAAE,oBAAoB;;;SAG/B,CAAC;yCAkBkB,sDAAM;YACL,gFAAc;YACL,oFAAgB;YAC1B,oDAAM;YACJ,wDAAQ;OArBjB,sBAAsB,CA2ElC;IAAD,6BAAC;CAAA;AA3EkC;;;;;;;;;;;;ACZnC,iEAAiE,qCAAqC,+EAA+E,uCAAuC,mLAAmL,gCAAgC,6HAA6H,6BAA6B,0FAA0F,wCAAwC,qHAAqH,8DAA8D,GAAG,kCAAkC,uBAAuB,qHAAqH,yHAAyH,6SAA6S,yBAAyB,uEAAuE,8CAA8C,mL;;;;;;;;;;;ACAnmD,yBAAyB,uBAAuB,kBAAkB,2BAA2B,yBAAyB,qBAAqB,gBAAgB,iBAAiB,EAAE,aAAa,kBAAkB,wBAAwB,mCAAmC,mBAAmB,iBAAiB,EAAE,mBAAmB,oBAAoB,0BAA0B,EAAE,qCAAqC,6BAA6B,EAAE,gBAAgB,wBAAwB,uBAAuB,EAAE,oBAAoB,oBAAoB,0BAA0B,8BAA8B,mBAAmB,sBAAsB,uBAAuB,oBAAoB,iBAAiB,EAAE,0BAA0B,6BAA6B,sBAAsB,uBAAuB,EAAE,kCAAkC,4DAA4D,4DAA4D,EAAE,kCAAkC,4DAA4D,4DAA4D,EAAE,+BAA+B,yDAAyD,yDAAyD,EAAE,cAAc,kBAAkB,wBAAwB,mBAAmB,sBAAsB,wBAAwB,EAAE,oBAAoB,sBAAsB,0BAA0B,oBAAoB,qBAAqB,EAAE,yBAAyB,uDAAuD,uDAAuD,EAAE,cAAc,kBAAkB,0BAA0B,gCAAgC,mBAAmB,qBAAqB,EAAE,2BAA2B,wBAAwB,uBAAuB,0BAA0B,2BAA2B,EAAE,0BAA0B,wBAAwB,uBAAuB,0BAA0B,EAAE,WAAW,kBAAkB,2BAA2B,mBAAmB,EAAE,wBAAwB,oBAAoB,qCAAqC,qBAAqB,EAAE,6BAA6B,sBAAsB,4BAA4B,gCAAgC,uBAAuB,wBAAwB,wBAAwB,qBAAqB,EAAE,mCAAmC,+BAA+B,wBAAwB,yBAAyB,EAAE,wCAAwC,2DAA2D,2DAA2D,EAAE,2CAA2C,8DAA8D,8DAA8D,EAAE,2CAA2C,8DAA8D,8DAA8D,EAAE,6CAA6C,gEAAgE,gEAAgE,EAAE,4CAA4C,8DAA8D,8DAA8D,EAAE,2CAA2C,8DAA8D,8DAA8D,EAAE,wCAAwC,wBAAwB,8BAA8B,kCAAkC,8BAA8B,0BAA0B,2BAA2B,8BAA8B,4BAA4B,4BAA4B,yBAAyB,EAAE,sCAAsC,8BAA8B,EAAE,8CAA8C,+BAA+B,EAAE,yBAAyB,oBAAoB,oBAAoB,qBAAqB,yBAAyB,0BAA0B,EAAE,+CAA+C,+wO;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAtgI;AACZ;AACiB;AACJ;AAOpE;IAgDE,yBACU,KAAqB,EACrB,MAAc,EACd,OAAuB,EACvB,gBAAkC,EAClC,MAAc;QAJd,UAAK,GAAL,KAAK,CAAgB;QACrB,WAAM,GAAN,MAAM,CAAQ;QACd,YAAO,GAAP,OAAO,CAAgB;QACvB,qBAAgB,GAAhB,gBAAgB,CAAkB;QAClC,WAAM,GAAN,MAAM,CAAQ;QAlDxB,SAAI,GAAG;YACL;gBACE,KAAK,EAAE,kBAAkB;gBACzB,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,OAAO;gBACb,SAAS,EAAE,KAAK;gBAChB,MAAM,EAAE,IAAI;aACb;YACD;gBACE,KAAK,EAAE,qBAAqB;gBAC5B,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,UAAU;gBAChB,SAAS,EAAE,KAAK;gBAChB,MAAM,EAAE,KAAK;aACd;YACD;gBACE,KAAK,EAAE,qBAAqB;gBAC5B,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,UAAU;gBAChB,SAAS,EAAE,KAAK;gBAChB,MAAM,EAAE,KAAK;aACd;YACD;gBACE,KAAK,EAAE,uBAAuB;gBAC9B,IAAI,EAAE,WAAW;gBACjB,IAAI,EAAE,YAAY;gBAClB,SAAS,EAAE,CAAC;gBACZ,MAAM,EAAE,KAAK;aACd;YACD;gBACE,KAAK,EAAE,sBAAsB;gBAC7B,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,WAAW;gBACjB,SAAS,EAAE,EAAE;gBACb,MAAM,EAAE,KAAK;aACd;YACD;gBACE,KAAK,EAAE,qBAAqB;gBAC5B,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,UAAU;gBAChB,SAAS,EAAE,KAAK;gBAChB,MAAM,EAAE,KAAK;aACd;SACF,CAAC;IASF,CAAC;IAED,kCAAQ,GAAR;QAAA,iBAQC;QAPC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,gBAAM;YAClD,KAAI,CAAC,QAAQ,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC9B,KAAI,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,KAAI,CAAC,QAAQ,CAAC,CAAC;YACtD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;gBACzC,KAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,KAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,GAAG,KAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;aAChG;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,mCAAS,GAAT,UAAU,KAAK;QACb,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,IAAI,IAAI,CAAC,gBAAgB,CAAC,YAAY,KAAK,CAAC,EAAE;YAChI,OAAO;SACR;QACD,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAC,GAAG;YACpB,GAAG,CAAC,MAAM,GAAG,KAAK,CAAC;QACrB,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5E,CAAC;IAED,qCAAW,GAAX;QACE,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IACzE,CAAC;IAED;;;;;;;;;;;;;OAaG;IAEH,qCAAW,GAAX;QACE,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC;IAChC,CAAC;IAnGU,eAAe;QAL3B,+DAAS,CAAC;YACT,QAAQ,EAAE,YAAY;;;SAGvB,CAAC;yCAkDiB,8DAAc;YACb,sDAAM;YACL,gFAAc;YACL,oFAAgB;YAC1B,oDAAM;OArDb,eAAe,CAqG3B;IAAD,sBAAC;CAAA;AArG2B;;;;;;;;;;;;;ACV5B;AAAA;AAAA,gFAAgF;AAChF,0EAA0E;AAC1E,gEAAgE;AAEzD,IAAM,WAAW,GAAG;IACzB,UAAU,EAAE,KAAK;CAClB,CAAC;AAEF;;;;;;GAMG;AACH,mEAAmE;;;;;;;;;;;;;ACfnE;AAAA;AAAA;AAAA;AAAA;AAA+C;AAC4B;AAE9B;AACY;AAEzD,IAAI,qEAAW,CAAC,UAAU,EAAE;IAC1B,oEAAc,EAAE,CAAC;CAClB;AAED,gGAAsB,EAAE,CAAC,eAAe,CAAC,yDAAS,CAAC;KAChD,KAAK,CAAC,aAAG,IAAI,cAAO,CAAC,KAAK,CAAC,GAAG,CAAC,EAAlB,CAAkB,CAAC,CAAC","file":"main.js","sourcesContent":["function webpackEmptyAsyncContext(req) {\n\t// Here Promise.resolve().then() is used instead of new Promise() to prevent\n\t// uncaught exception popping up in devtools\n\treturn Promise.resolve().then(function() {\n\t\tvar e = new Error(\"Cannot find module '\" + req + \"'\");\n\t\te.code = 'MODULE_NOT_FOUND';\n\t\tthrow e;\n\t});\n}\nwebpackEmptyAsyncContext.keys = function() { return []; };\nwebpackEmptyAsyncContext.resolve = webpackEmptyAsyncContext;\nmodule.exports = webpackEmptyAsyncContext;\nwebpackEmptyAsyncContext.id = \"./src/$$_lazy_route_resource lazy recursive\";","import {Directive, ElementRef, Input} from '@angular/core';\nimport * as Inputmask from 'inputmask';\n\n@Directive({\n selector: '[appInputValidate]'\n})\nexport class InputValidateDirective {\n\n private regexMap = {\n integer: {\n regex: '^[0-9]*$',\n placeholder: ''\n },\n // float: '^[+-]?([0-9]*[.])?[0-9]+$',\n // words: '([A-z]*\\\\s)*',\n // point25: '^\\-?[0-9]*(?:\\\\.25|\\\\.50|\\\\.75|)$',\n money: {\n alias: 'decimal',\n digits: 8,\n max: 999999999999,\n rightAlign: false,\n allowMinus: false,\n onBeforeMask: (value) => value\n }\n };\n\n constructor(private el: ElementRef) {\n }\n\n @Input('appInputValidate')\n public set defineInputType(type: string) {\n Inputmask(this.regexMap[type]).mask(this.el.nativeElement);\n }\n\n}\n\n\n\n\n","module.exports = \"
\\r\\n
\\r\\n \\r\\n
\\r\\n Success\\r\\n Successfully\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n\"","module.exports = \":host {\\n position: fixed;\\n top: 0;\\n bottom: 0;\\n left: 0;\\n right: 0;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n background: rgba(255, 255, 255, 0.25); }\\n\\n.modal {\\n position: relative;\\n display: flex;\\n flex-direction: column;\\n padding: 2rem;\\n width: 34rem;\\n background: #1a1a1a; }\\n\\n.modal .content {\\n display: flex;\\n margin: 1.2rem 0; }\\n\\n.modal .content .icon {\\n width: 4.4rem;\\n height: 4.4rem; }\\n\\n.modal .content .message {\\n display: flex;\\n flex-direction: column;\\n margin-left: 2rem; }\\n\\n.modal .action-button {\\n background: #2c95f1;\\n margin: 1.2rem auto 0.6rem;\\n width: 10rem;\\n height: 2.4rem; }\\n\\n.modal .close-button {\\n position: absolute;\\n top: 0.5rem;\\n right: 0.5rem;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n background: transparent;\\n margin: 0;\\n padding: 0;\\n width: 1.5rem;\\n height: 1.5rem; }\\n\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvX2hlbHBlcnMvZGlyZWN0aXZlcy9tb2RhbC1jb250YWluZXIvRDpcXHphbm8vc3JjXFxhcHBcXF9oZWxwZXJzXFxkaXJlY3RpdmVzXFxtb2RhbC1jb250YWluZXJcXG1vZGFsLWNvbnRhaW5lci5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLGdCQUFlO0VBQ2YsT0FBTTtFQUNOLFVBQVM7RUFDVCxRQUFPO0VBQ1AsU0FBUTtFQUNSLGNBQWE7RUFDYixvQkFBbUI7RUFDbkIsd0JBQXVCO0VBQ3ZCLHNDQUFxQyxFQUN0Qzs7QUFDRDtFQUNFLG1CQUFrQjtFQUNsQixjQUFhO0VBQ2IsdUJBQXNCO0VBQ3RCLGNBQWE7RUFDYixhQUFZO0VBQ1osb0JBQW1CLEVBc0NwQjs7QUE1Q0Q7SUFTSSxjQUFhO0lBQ2IsaUJBQWdCLEVBWWpCOztBQXRCSDtNQWFNLGNBQWE7TUFDYixlQUFjLEVBQ2Y7O0FBZkw7TUFrQk0sY0FBYTtNQUNiLHVCQUFzQjtNQUN0QixrQkFBaUIsRUFDbEI7O0FBckJMO0lBeUJJLG9CQUFtQjtJQUNuQiwyQkFBMEI7SUFDMUIsYUFBWTtJQUNaLGVBQWMsRUFDZjs7QUE3Qkg7SUFnQ0ksbUJBQWtCO0lBQ2xCLFlBQVc7SUFDWCxjQUFhO0lBQ2IsY0FBYTtJQUNiLG9CQUFtQjtJQUNuQix3QkFBdUI7SUFDdkIsd0JBQXVCO0lBQ3ZCLFVBQVM7SUFDVCxXQUFVO0lBQ1YsY0FBYTtJQUNiLGVBQWMsRUFDZiIsImZpbGUiOiJzcmMvYXBwL19oZWxwZXJzL2RpcmVjdGl2ZXMvbW9kYWwtY29udGFpbmVyL21vZGFsLWNvbnRhaW5lci5jb21wb25lbnQuc2NzcyIsInNvdXJjZXNDb250ZW50IjpbIjpob3N0IHtcclxuICBwb3NpdGlvbjogZml4ZWQ7XHJcbiAgdG9wOiAwO1xyXG4gIGJvdHRvbTogMDtcclxuICBsZWZ0OiAwO1xyXG4gIHJpZ2h0OiAwO1xyXG4gIGRpc3BsYXk6IGZsZXg7XHJcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcclxuICBiYWNrZ3JvdW5kOiByZ2JhKDI1NSwgMjU1LCAyNTUsIDAuMjUpO1xyXG59XHJcbi5tb2RhbCB7XHJcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xyXG4gIGRpc3BsYXk6IGZsZXg7XHJcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICBwYWRkaW5nOiAycmVtO1xyXG4gIHdpZHRoOiAzNHJlbTtcclxuICBiYWNrZ3JvdW5kOiAjMWExYTFhO1xyXG5cclxuICAuY29udGVudCB7XHJcbiAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgbWFyZ2luOiAxLjJyZW0gMDtcclxuXHJcbiAgICAuaWNvbiB7XHJcbiAgICAgIHdpZHRoOiA0LjRyZW07XHJcbiAgICAgIGhlaWdodDogNC40cmVtO1xyXG4gICAgfVxyXG5cclxuICAgIC5tZXNzYWdlIHtcclxuICAgICAgZGlzcGxheTogZmxleDtcclxuICAgICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICAgICAgbWFyZ2luLWxlZnQ6IDJyZW07XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAuYWN0aW9uLWJ1dHRvbiB7XHJcbiAgICBiYWNrZ3JvdW5kOiAjMmM5NWYxO1xyXG4gICAgbWFyZ2luOiAxLjJyZW0gYXV0byAwLjZyZW07XHJcbiAgICB3aWR0aDogMTByZW07XHJcbiAgICBoZWlnaHQ6IDIuNHJlbTtcclxuICB9XHJcblxyXG4gIC5jbG9zZS1idXR0b24ge1xyXG4gICAgcG9zaXRpb246IGFic29sdXRlO1xyXG4gICAgdG9wOiAwLjVyZW07XHJcbiAgICByaWdodDogMC41cmVtO1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAgICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcclxuICAgIGJhY2tncm91bmQ6IHRyYW5zcGFyZW50O1xyXG4gICAgbWFyZ2luOiAwO1xyXG4gICAgcGFkZGluZzogMDtcclxuICAgIHdpZHRoOiAxLjVyZW07XHJcbiAgICBoZWlnaHQ6IDEuNXJlbTtcclxuICB9XHJcbn1cclxuIl19 */\"","import { Component, OnInit } from '@angular/core';\r\n\r\n@Component({\r\n selector: 'app-modal-container',\r\n templateUrl: './modal-container.component.html',\r\n styleUrls: ['./modal-container.component.scss']\r\n})\r\nexport class ModalContainerComponent implements OnInit {\r\n\r\n constructor() { }\r\n\r\n ngOnInit() {\r\n }\r\n\r\n}\r\n","module.exports = \"
\\r\\n ON\\r\\n \\r\\n OFF\\r\\n
\\r\\n\"","module.exports = \".switch {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n border-radius: 1rem;\\n cursor: pointer;\\n font-size: 1rem;\\n padding: 0.5rem;\\n width: 5rem;\\n height: 2rem; }\\n .switch .circle {\\n border-radius: 1rem;\\n width: 1.2rem;\\n height: 1.2rem; }\\n .switch .option {\\n margin: 0 0.2rem;\\n line-height: 1.2rem; }\\n\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvX2hlbHBlcnMvZGlyZWN0aXZlcy9zdGFraW5nLXN3aXRjaC9EOlxcemFuby9zcmNcXGFwcFxcX2hlbHBlcnNcXGRpcmVjdGl2ZXNcXHN0YWtpbmctc3dpdGNoXFxzdGFraW5nLXN3aXRjaC5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLGNBQWE7RUFDYixvQkFBbUI7RUFDbkIsK0JBQThCO0VBQzlCLG9CQUFtQjtFQUNuQixnQkFBZTtFQUNmLGdCQUFlO0VBQ2YsZ0JBQWU7RUFDZixZQUFXO0VBQ1gsYUFBWSxFQVliO0VBckJEO0lBWUksb0JBQW1CO0lBQ25CLGNBQWE7SUFDYixlQUFjLEVBQ2Y7RUFmSDtJQWtCSSxpQkFBZ0I7SUFDaEIsb0JBQW1CLEVBQ3BCIiwiZmlsZSI6InNyYy9hcHAvX2hlbHBlcnMvZGlyZWN0aXZlcy9zdGFraW5nLXN3aXRjaC9zdGFraW5nLXN3aXRjaC5jb21wb25lbnQuc2NzcyIsInNvdXJjZXNDb250ZW50IjpbIi5zd2l0Y2gge1xyXG4gIGRpc3BsYXk6IGZsZXg7XHJcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XHJcbiAgYm9yZGVyLXJhZGl1czogMXJlbTtcclxuICBjdXJzb3I6IHBvaW50ZXI7XHJcbiAgZm9udC1zaXplOiAxcmVtO1xyXG4gIHBhZGRpbmc6IDAuNXJlbTtcclxuICB3aWR0aDogNXJlbTtcclxuICBoZWlnaHQ6IDJyZW07XHJcblxyXG4gIC5jaXJjbGUge1xyXG4gICAgYm9yZGVyLXJhZGl1czogMXJlbTtcclxuICAgIHdpZHRoOiAxLjJyZW07XHJcbiAgICBoZWlnaHQ6IDEuMnJlbTtcclxuICB9XHJcblxyXG4gIC5vcHRpb24ge1xyXG4gICAgbWFyZ2luOiAwIDAuMnJlbTtcclxuICAgIGxpbmUtaGVpZ2h0OiAxLjJyZW07XHJcbiAgfVxyXG59XHJcbiJdfQ== */\"","import {Component, OnInit, Input, Output, EventEmitter} from '@angular/core';\r\nimport {BackendService} from '../../services/backend.service';\r\nimport {VariablesService} from '../../services/variables.service';\r\n\r\n@Component({\r\n selector: 'app-staking-switch',\r\n templateUrl: './staking-switch.component.html',\r\n styleUrls: ['./staking-switch.component.scss']\r\n})\r\nexport class StakingSwitchComponent implements OnInit {\r\n\r\n @Input() wallet_id: boolean;\r\n @Input() staking: boolean;\r\n @Output() stakingChange = new EventEmitter();\r\n\r\n constructor(private backend: BackendService, private variablesService: VariablesService) {\r\n }\r\n\r\n ngOnInit() {\r\n }\r\n\r\n toggleStaking() {\r\n const wallet = this.variablesService.getWallet(this.wallet_id);\r\n if (wallet && wallet.loaded) {\r\n this.stakingChange.emit(!this.staking);\r\n if (!this.staking) {\r\n this.backend.startPosMining(this.wallet_id);\r\n } else {\r\n this.backend.stopPosMining(this.wallet_id);\r\n }\r\n }\r\n }\r\n}\r\n","import {Directive, Input, ElementRef, HostListener, Renderer2} from '@angular/core';\r\n\r\n@Directive({\r\n selector: '[tooltip]',\r\n host: {\r\n '[style.cursor]': '\"pointer\"'\r\n }\r\n})\r\n\r\nexport class TooltipDirective {\r\n @Input('tooltip') tooltipTitle: string;\r\n @Input() placement: string;\r\n @Input() tooltipClass: string;\r\n @Input() delay: number;\r\n tooltip: HTMLElement;\r\n offset = 10;\r\n\r\n constructor(private el: ElementRef, private renderer: Renderer2) {}\r\n\r\n @HostListener('mouseenter') onMouseEnter() {\r\n if (!this.tooltip) { this.show(); }\r\n }\r\n\r\n @HostListener('mouseleave') onMouseLeave() {\r\n if (this.tooltip) { this.hide(); }\r\n }\r\n\r\n show() {\r\n this.create();\r\n this.setPosition();\r\n }\r\n\r\n hide() {\r\n this.renderer.setStyle(this.tooltip, 'opacity', '0');\r\n window.setTimeout(() => {\r\n this.renderer.removeChild(document.body, this.tooltip);\r\n this.tooltip = null;\r\n }, this.delay);\r\n }\r\n\r\n create() {\r\n this.tooltip = this.renderer.createElement('span');\r\n this.renderer.appendChild(this.tooltip, this.renderer.createText(this.tooltipTitle));\r\n this.renderer.appendChild(document.body, this.tooltip);\r\n this.renderer.setStyle(document.body, 'position', 'relative');\r\n this.renderer.setStyle(this.tooltip, 'position', 'absolute');\r\n if (this.tooltipClass !== null) {\r\n this.renderer.addClass(this.tooltip, this.tooltipClass);\r\n }\r\n if (this.placement !== null) {\r\n this.renderer.addClass(this.tooltip, 'ng-tooltip-' + this.placement);\r\n } else {\r\n this.placement = 'top';\r\n this.renderer.addClass(this.tooltip, 'ng-tooltip-top');\r\n }\r\n if (this.delay !== null) {\r\n this.renderer.setStyle(this.tooltip, 'opacity', '0');\r\n this.renderer.setStyle(this.tooltip, '-webkit-transition', `opacity ${this.delay}ms`);\r\n this.renderer.setStyle(this.tooltip, '-moz-transition', `opacity ${this.delay}ms`);\r\n this.renderer.setStyle(this.tooltip, '-o-transition', `opacity ${this.delay}ms`);\r\n this.renderer.setStyle(this.tooltip, 'transition', `opacity ${this.delay}ms`);\r\n window.setTimeout(() => {\r\n this.renderer.setStyle(this.tooltip, 'opacity', '1');\r\n }, 0);\r\n }\r\n }\r\n\r\n setPosition() {\r\n const hostPos = this.el.nativeElement.getBoundingClientRect();\r\n const tooltipPos = this.tooltip.getBoundingClientRect();\r\n // const scrollPos = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;\r\n\r\n if (this.placement === 'top') {\r\n this.renderer.setStyle(this.tooltip, 'top', hostPos.top - tooltipPos.height + 'px');\r\n this.renderer.setStyle(this.tooltip, 'left', hostPos.left + 'px');\r\n }\r\n\r\n if (this.placement === 'bottom') {\r\n this.renderer.setStyle(this.tooltip, 'top', hostPos.bottom + 'px');\r\n this.renderer.setStyle(this.tooltip, 'left', hostPos.left + 'px');\r\n }\r\n\r\n if (this.placement === 'left') {\r\n this.renderer.setStyle(this.tooltip, 'top', hostPos.top + 'px');\r\n this.renderer.setStyle(this.tooltip, 'left', hostPos.left - tooltipPos.width + 'px');\r\n }\r\n\r\n if (this.placement === 'right') {\r\n this.renderer.setStyle(this.tooltip, 'top', hostPos.top + 'px');\r\n this.renderer.setStyle(this.tooltip, 'left', hostPos.right + 'px');\r\n }\r\n }\r\n}\r\n","import {Contract} from './contract.model';\r\n\r\nexport class Wallet {\r\n wallet_id: number;\r\n name: string;\r\n pass: string;\r\n path: string;\r\n address: string;\r\n balance: number;\r\n unlocked_balance: number;\r\n mined_total: number;\r\n tracking_hey: string;\r\n\r\n alias?: string;\r\n staking?: boolean;\r\n new_messages?: number;\r\n new_contracts?: number;\r\n\r\n history: any[];\r\n excluded_history: any[];\r\n\r\n contracts: Array = [];\r\n\r\n progress?: number;\r\n loaded?: boolean;\r\n\r\n constructor(id, name, pass, path, address, balance = 0, unlocked_balance = 0, mined = 0, tracking = '') {\r\n this.wallet_id = id;\r\n this.name = name;\r\n this.pass = pass;\r\n this.path = path;\r\n this.address = address;\r\n this.balance = balance;\r\n this.unlocked_balance = unlocked_balance;\r\n this.mined_total = mined;\r\n this.tracking_hey = tracking;\r\n\r\n this.alias = '';\r\n this.staking = false;\r\n this.new_messages = 0;\r\n this.new_contracts = 0;\r\n\r\n this.history = [];\r\n this.excluded_history = [];\r\n\r\n this.progress = 0;\r\n this.loaded = false;\r\n }\r\n\r\n getMoneyEquivalent(equivalent) {\r\n return this.balance * equivalent;\r\n }\r\n\r\n havePass(): boolean {\r\n return (this.pass !== '' && this.pass !== null);\r\n }\r\n\r\n isActive(id): boolean {\r\n return this.wallet_id === id;\r\n }\r\n\r\n prepareHistoryItem(item: any): any {\r\n if (item.tx_type === 4) {\r\n item.sortFee = -(item.amount + item.fee);\r\n item.sortAmount = 0;\r\n } else if (item.tx_type === 3) {\r\n item.sortFee = 0;\r\n } else if ((item.hasOwnProperty('contract') && (item.contract[0].state === 3 || item.contract[0].state === 6 || item.contract[0].state === 601) && !item.contract[0].is_a)) {\r\n item.sortFee = -item.fee;\r\n item.sortAmount = item.amount;\r\n } else {\r\n if (!item.is_income) {\r\n item.sortFee = -item.fee;\r\n item.sortAmount = -item.amount;\r\n } else {\r\n item.sortAmount = item.amount;\r\n }\r\n }\r\n return item;\r\n }\r\n\r\n prepareHistory(items: any[]): void {\r\n for (let i = 0; i < items.length; i++) {\r\n if ((items[i].tx_type === 7 && items[i].is_income) || (items[i].tx_type === 11 && items[i].is_income) || (items[i].amount === 0 && items[i].fee === 0)) {\r\n let exists = false;\r\n for (let j = 0; j < this.excluded_history.length; j++) {\r\n if (this.excluded_history[j].tx_hash === items[i].tx_hash) {\r\n exists = true;\r\n if (this.excluded_history[j].height !== items[i].height) {\r\n this.excluded_history[j] = items[i];\r\n }\r\n break;\r\n }\r\n }\r\n if (!exists) {\r\n this.excluded_history.push(items[i]);\r\n }\r\n } else {\r\n let exists = false;\r\n for (let j = 0; j < this.history.length; j++) {\r\n if (this.history[j].tx_hash === items[i].tx_hash) {\r\n exists = true;\r\n if (this.history[j].height !== items[i].height) {\r\n this.history[j] = this.prepareHistoryItem(items[i]);\r\n }\r\n break;\r\n }\r\n }\r\n if (!exists) {\r\n if (this.history.length && items[i].timestamp > this.history[0].timestamp) {\r\n this.history.unshift(this.prepareHistoryItem(items[i]));\r\n } else {\r\n this.history.push(this.prepareHistoryItem(items[i]));\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n prepareContractsAfterOpen(items: any[], exp_med_ts, height_app, viewedContracts, notViewedContracts): void {\r\n const safe = this;\r\n for (let i = 0; i < items.length; i++) {\r\n const contract = items[i];\r\n let contractTransactionExist = false;\r\n if (safe && safe.history) {\r\n contractTransactionExist = safe.history.some(elem => elem.contract && elem.contract.length && elem.contract[0].contract_id === contract.contract_id);\r\n }\r\n if (!contractTransactionExist && safe && safe.excluded_history) {\r\n contractTransactionExist = safe.excluded_history.some(elem => elem.contract && elem.contract.length && elem.contract[0].contract_id === contract.contract_id);\r\n }\r\n\r\n if (!contractTransactionExist) {\r\n contract.state = 140;\r\n } else if (contract.state === 1 && contract.expiration_time < exp_med_ts) {\r\n contract.state = 110;\r\n } else if (contract.state === 2 && contract.cancel_expiration_time !== 0 && contract.cancel_expiration_time < exp_med_ts && contract.height === 0) {\r\n const searchResult1 = viewedContracts.some(elem => elem.state === 2 && elem.is_a === contract.is_a && elem.contract_id === contract.contract_id);\r\n if (!searchResult1) {\r\n contract.state = 130;\r\n contract.is_new = true;\r\n }\r\n } else if (contract.state === 1) {\r\n const searchResult2 = notViewedContracts.find(elem => elem.state === 110 && elem.is_a === contract.is_a && elem.contract_id === contract.contract_id);\r\n if (searchResult2) {\r\n if (searchResult2.time === contract.expiration_time) {\r\n contract.state = 110;\r\n } else {\r\n for (let j = 0; j < notViewedContracts.length; j++) {\r\n if (notViewedContracts[j].contract_id === contract.contract_id && notViewedContracts[j].is_a === contract.is_a) {\r\n notViewedContracts.splice(j, 1);\r\n break;\r\n }\r\n }\r\n for (let j = 0; j < viewedContracts.length; j++) {\r\n if (viewedContracts[j].contract_id === contract.contract_id && viewedContracts[j].is_a === contract.is_a) {\r\n viewedContracts.splice(j, 1);\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n } else if (contract.state === 2 && (contract.height === 0 || (height_app - contract.height) < 10)) {\r\n contract.state = 201;\r\n } else if (contract.state === 2) {\r\n const searchResult3 = viewedContracts.some(elem => elem.state === 120 && elem.is_a === contract.is_a && elem.contract_id === contract.contract_id);\r\n if (searchResult3) {\r\n contract.state = 120;\r\n }\r\n } else if (contract.state === 5) {\r\n const searchResult4 = notViewedContracts.find(elem => elem.state === 130 && elem.is_a === contract.is_a && elem.contract_id === contract.contract_id);\r\n if (searchResult4) {\r\n if (searchResult4.time === contract.cancel_expiration_time) {\r\n contract.state = 130;\r\n } else {\r\n for (let j = 0; j < notViewedContracts.length; j++) {\r\n if (notViewedContracts[j].contract_id === contract.contract_id && notViewedContracts[j].is_a === contract.is_a) {\r\n notViewedContracts.splice(j, 1);\r\n break;\r\n }\r\n }\r\n for (let j = 0; j < viewedContracts.length; j++) {\r\n if (viewedContracts[j].contract_id === contract.contract_id && viewedContracts[j].is_a === contract.is_a) {\r\n viewedContracts.splice(j, 1);\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n } else if (contract.state === 6 && (contract.height === 0 || (height_app - contract.height) < 10)) {\r\n contract.state = 601;\r\n }\r\n const searchResult = viewedContracts.some(elem => elem.state === contract.state && elem.is_a === contract.is_a && elem.contract_id === contract.contract_id);\r\n contract.is_new = !searchResult;\r\n contract['private_detailes'].a_pledge += contract['private_detailes'].to_pay;\r\n\r\n safe.contracts.push(contract);\r\n }\r\n this.recountNewContracts();\r\n }\r\n\r\n recountNewContracts() {\r\n this.new_contracts = (this.contracts.filter(item => item.is_new === true )).length;\r\n }\r\n\r\n getContract(id): Contract {\r\n for (let i = 0; i < this.contracts.length; i++) {\r\n if (this.contracts[i].contract_id === id) {\r\n return this.contracts[i];\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n}\r\n","import {Pipe, PipeTransform} from '@angular/core';\n\n@Pipe({\n name: 'contractStatusMessages'\n})\nexport class ContractStatusMessagesPipe implements PipeTransform {\n\n getStateSeller(stateNum: number): string {\n const state = {part1: '', part2: ''};\n switch (stateNum) {\n case 1:\n state.part1 = 'New contract proposal';\n break;\n case 110:\n state.part1 = 'You ignored the contract proposal';\n break;\n case 201:\n state.part1 = 'You have accepted the contract proposal';\n state.part2 = 'Please wait for the pledges to be made';\n break;\n case 2:\n state.part1 = 'The buyer is waiting for the item to be delivered';\n state.part2 = 'Pledges made';\n break;\n case 3:\n state.part1 = 'Contract completed successfully';\n state.part2 = 'Item received, payment transferred, pledges returned';\n break;\n case 4:\n state.part1 = 'Item not received';\n state.part2 = 'All pledges nullified';\n break;\n case 5:\n state.part1 = 'New proposal to cancel contract and return pledges';\n break;\n case 601:\n state.part1 = 'The contract is being cancelled. Please wait for the pledge to be returned';\n break;\n case 6:\n state.part1 = 'Contract canceled';\n state.part2 = 'Pledges returned';\n break;\n case 130:\n state.part1 = 'You ignored the proposal to cancel the contract';\n break;\n case 140:\n state.part1 = 'The contract proposal has expired';\n break;\n }\n return state.part1 + ' ' + state.part2;\n }\n\n getStateCustomer(stateNum: number): string {\n const state = {part1: '', part2: ''};\n switch (stateNum) {\n case 1:\n state.part1 = 'Waiting for seller respond to contract proposal';\n state.part2 = 'Pledge amount reserved';\n break;\n case 110:\n state.part1 = 'The seller ignored your contract proposal';\n state.part2 = 'Pledge amount unblocked';\n break;\n case 201:\n state.part1 = 'The seller accepted your contract proposal';\n state.part2 = 'Please wait for the pledges to be made';\n break;\n case 2:\n state.part1 = 'The seller accepted your contract proposal';\n state.part2 = 'Pledges made';\n break;\n case 120:\n state.part1 = 'Waiting for seller to ship item';\n state.part2 = 'Pledges made';\n break;\n case 3:\n state.part1 = 'Contract completed successfully';\n state.part2 = 'Item received, payment transferred, pledges returned';\n break;\n case 4:\n state.part1 = 'Item not received';\n state.part2 = 'All pledges nullified';\n break;\n case 5:\n state.part1 = 'Waiting for seller to respond to proposal to cancel contract and return pledges';\n break;\n case 601:\n state.part1 = 'The contract is being cancelled. Please wait for the pledge to be returned';\n break;\n case 6:\n state.part1 = 'Contract canceled';\n state.part2 = 'Pledges returned';\n break;\n case 130:\n state.part1 = 'The seller ignored your proposal to cancel the contract';\n break;\n case 140:\n state.part1 = 'The contract proposal has expired';\n break;\n }\n return state.part1 + ' ' + state.part2;\n }\n\n transform(item: any, args?: any): any {\n\n if (item.is_a) {\n return this.getStateCustomer(item.state);\n } else {\n return this.getStateSeller(item.state);\n }\n }\n\n}\n","import {Pipe, PipeTransform} from '@angular/core';\r\nimport {VariablesService} from '../services/variables.service';\r\nimport {TranslateService} from '@ngx-translate/core';\r\n\r\n@Pipe({\r\n name: 'contractTimeLeft'\r\n})\r\nexport class ContractTimeLeftPipe implements PipeTransform {\r\n\r\n constructor(private service: VariablesService, private translate: TranslateService) {}\r\n\r\n transform(value: any, arg?: any): any {\r\n const time = parseInt(((parseInt(value, 10) - this.service.exp_med_ts) / 3600).toFixed(0), 10);\r\n const type = arg || 0;\r\n if (time === 0) {\r\n return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_LESS_ONE');\r\n }\r\n if (this.service.settings.language === 'en') {\r\n if (type === 0) {\r\n if (time === 1) {\r\n return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_ONE', {time: time});\r\n } else {\r\n return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_MANY', {time: time});\r\n }\r\n } else if (type === 1) {\r\n if (time === 1) {\r\n return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_ONE_RESPONSE', {time: time});\r\n } else {\r\n return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_MANY_RESPONSE', {time: time});\r\n }\r\n } else if (type === 2) {\r\n if (time === 1) {\r\n return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_ONE_WAITING', {time: time});\r\n } else {\r\n return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_MANY_WAITING', {time: time});\r\n }\r\n }\r\n } else {\r\n const rest = time % 10;\r\n if (type === 0) {\r\n if (((time > 20 ) && (rest === 1)) || time === 1) {\r\n return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_ONE', {time: time});\r\n } else if ((time > 1) && (time < 5) || ((time > 20 ) && (rest === 2 || rest === 3 || rest === 4))) {\r\n return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_MANY', {time: time});\r\n } else {\r\n return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_MANY_ALT', {time: time});\r\n }\r\n } else if (type === 1) {\r\n if (((time > 20 ) && (rest === 1)) || time === 1) {\r\n return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_ONE_RESPONSE', {time: time});\r\n } else if ((time > 1) && (time < 5) || ((time > 20 ) && (rest === 2 || rest === 3 || rest === 4))) {\r\n return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_MANY_RESPONSE', {time: time});\r\n } else {\r\n return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_MANY_ALT_RESPONSE', {time: time});\r\n }\r\n } else if (type === 2) {\r\n if (((time > 20 ) && (rest === 1)) || time === 1) {\r\n return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_ONE_WAITING', {time: time});\r\n } else if ((time > 1) && (time < 5) || ((time > 20 ) && (rest === 2 || rest === 3 || rest === 4))) {\r\n return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_MANY_WAITING', {time: time});\r\n } else {\r\n return this.translate.instant('CONTRACTS.TIME_LEFT.REMAINING_MANY_ALT_WAITING', {time: time});\r\n }\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n}\r\n","import {Pipe, PipeTransform} from '@angular/core';\n\n@Pipe({\n name: 'historyTypeMessages'\n})\nexport class HistoryTypeMessagesPipe implements PipeTransform {\n\n transform(item: any, args?: any): any {\n\n if (item.tx_type === 0) {\n if (item.remote_addresses && item.remote_addresses[0]) {\n return item.remote_addresses[0];\n } else {\n if (item.is_income) {\n return 'hidden';\n } else {\n return 'Undefined';\n }\n }\n } else if (item.tx_type === 6 && item.height === 0) {\n return 'unknown';\n } else if (item.tx_type === 9) {\n if (item.hasOwnProperty('contract') && item.contract[0].is_a) {\n return 'Successfully complete contract, return remaining pledge';\n } else {\n return 'Successfully complete contract, receive payment on contract, and return pledge';\n }\n } else {\n switch (item.tx_type) {\n // case 0:\n // return $filter('translate')('GUI_TX_TYPE_NORMAL');\n // break;\n // case 1:\n // return $filter('translate')('GUI_TX_TYPE_PUSH_OFFER');\n // case 2:\n // return $filter('translate')('GUI_TX_TYPE_UPDATE_OFFER');\n // case 3:\n // return $filter('translate')('GUI_TX_TYPE_CANCEL_OFFER');\n // case 4:\n // return $filter('translate')('GUI_TX_TYPE_NEW_ALIAS');\n // case 5:\n // return $filter('translate')('GUI_TX_TYPE_UPDATE_ALIAS');\n case 6:\n return 'Mined funds';\n case 7:\n return 'Send contract offer';\n case 8:\n return 'Make pledge on offer';\n // case 9:\n // return $filter('translate')('GUI_TX_TYPE_ESCROW_RELEASE_NORMAL');\n // break;\n case 10:\n return 'Nullify pledges for contract';\n case 11:\n return 'Send proposal to cancel contract';\n case 12:\n return 'Cancel contract, return pledges';\n }\n }\n\n return 'Undefined';\n }\n\n}\n","import {Pipe, PipeTransform} from '@angular/core';\n\n@Pipe({\n name: 'intToMoney'\n})\nexport class IntToMoneyPipe implements PipeTransform {\n\n transform(value: any, args?: any): any {\n if (value === 0 || value === undefined) {\n return '0';\n }\n const power = Math.pow(10, 8);\n let str = (value / power).toFixed(8);\n for (let i = str.length - 1; i >= 0; i--) {\n if (str[i] !== '0') {\n str = str.substr(0, i + 1);\n break;\n }\n }\n if (str[str.length - 1] === '.') {\n str = str.substr(0, str.length - 1);\n }\n return str;\n }\n\n}\n","import {Pipe, PipeTransform} from '@angular/core';\r\n\r\n@Pipe({\r\n name: 'moneyToInt'\r\n})\r\nexport class MoneyToIntPipe implements PipeTransform {\r\n\r\n transform(value: any, args?: any): any {\r\n const CURRENCY_DISPLAY_DECIMAL_POINT = 8;\r\n let result;\r\n if (value) {\r\n let am_str = value.toString().trim();\r\n const point_index = am_str.indexOf('.');\r\n let fraction_size = 0;\r\n if (-1 !== point_index) {\r\n fraction_size = am_str.length - point_index - 1;\r\n while (CURRENCY_DISPLAY_DECIMAL_POINT < fraction_size && '0' === am_str[am_str.length - 1]) {\r\n am_str = am_str.slice(0, am_str.length - 1);\r\n --fraction_size;\r\n }\r\n if (CURRENCY_DISPLAY_DECIMAL_POINT < fraction_size) {\r\n return undefined;\r\n }\r\n am_str = am_str.slice(0, point_index) + am_str.slice(point_index + 1, am_str.length);\r\n } else {\r\n fraction_size = 0;\r\n }\r\n if (!am_str.length) {\r\n return undefined;\r\n }\r\n if (fraction_size < CURRENCY_DISPLAY_DECIMAL_POINT) {\r\n for (let i = 0; i !== CURRENCY_DISPLAY_DECIMAL_POINT - fraction_size; i++) {\r\n am_str = am_str + '0';\r\n }\r\n }\r\n result = parseInt(am_str, 10);\r\n }\r\n return result;\r\n }\r\n\r\n}\r\n","import {Injectable} from '@angular/core';\r\nimport {Observable} from 'rxjs';\r\nimport {VariablesService} from './variables.service';\r\nimport {MoneyToIntPipe} from '../pipes/money-to-int.pipe';\r\n\r\n@Injectable()\r\nexport class BackendService {\r\n\r\n backendObject: any;\r\n backendLoaded = false;\r\n\r\n constructor(private variablesService: VariablesService, private moneyToIntPipe: MoneyToIntPipe) {\r\n }\r\n\r\n\r\n private Debug(type, message) {\r\n switch (type) {\r\n case 0:\r\n console.error(message);\r\n break;\r\n case 1:\r\n console.warn(message);\r\n break;\r\n case 2:\r\n console.log(message);\r\n break;\r\n default:\r\n console.log(message);\r\n break;\r\n }\r\n }\r\n\r\n private informerRun(error, params, command) {\r\n let error_translate = '';\r\n\r\n switch (error) {\r\n case 'NOT_ENOUGH_MONEY':\r\n error_translate = 'ERROR.NOT_ENOUGH_MONEY';\r\n break;\r\n case 'CORE_BUSY':\r\n if (command !== 'get_all_aliases') {\r\n error_translate = 'INFORMER.CORE_BUSY';\r\n }\r\n break;\r\n case 'OVERFLOW':\r\n if (command !== 'get_all_aliases') {\r\n error_translate = '';\r\n }\r\n break;\r\n case 'INTERNAL_ERROR:daemon is busy':\r\n error_translate = 'INFORMER.DAEMON_BUSY';\r\n break;\r\n case 'INTERNAL_ERROR:not enough money':\r\n case 'INTERNAL_ERROR:NOT_ENOUGH_MONEY':\r\n if (command === 'cancel_offer') {\r\n // error_translate = $filter('translate')('INFORMER.NO_MONEY_REMOVE_OFFER', {\r\n // 'fee': CONFIG.standart_fee,\r\n // 'currency': CONFIG.currency_symbol\r\n // });\r\n } else {\r\n error_translate = 'INFORMER.NO_MONEY';\r\n }\r\n break;\r\n case 'INTERNAL_ERROR:not enough outputs to mix':\r\n error_translate = 'MESSAGE.NOT_ENOUGH_OUTPUTS_TO_MIX';\r\n break;\r\n case 'INTERNAL_ERROR:transaction is too big':\r\n error_translate = 'MESSAGE.TRANSACTION_IS_TO_BIG';\r\n break;\r\n case 'INTERNAL_ERROR:Transfer attempt while daemon offline':\r\n error_translate = 'MESSAGE.TRANSFER_ATTEMPT';\r\n break;\r\n case 'ACCESS_DENIED':\r\n error_translate = 'INFORMER.ACCESS_DENIED';\r\n break;\r\n case 'INTERNAL_ERROR:transaction was rejected by daemon':\r\n if (command === 'request_alias_registration') {\r\n error_translate = 'INFORMER.ALIAS_IN_REGISTER';\r\n } else {\r\n error_translate = 'INFORMER.TRANSACTION_ERROR';\r\n }\r\n break;\r\n case 'INTERNAL_ERROR':\r\n error_translate = 'INFORMER.TRANSACTION_ERROR';\r\n break;\r\n case 'BAD_ARG':\r\n error_translate = 'INFORMER.BAD_ARG';\r\n break;\r\n case 'WALLET_WRONG_ID':\r\n error_translate = 'INFORMER.WALLET_WRONG_ID';\r\n break;\r\n case 'WRONG_PASSWORD':\r\n case 'WRONG_PASSWORD:invalid password':\r\n params = JSON.parse(params);\r\n if (!params.testEmpty) {\r\n error_translate = 'INFORMER.WRONG_PASSWORD';\r\n }\r\n break;\r\n case 'FILE_RESTORED':\r\n if (command === 'open_wallet') {\r\n // error_translate = $filter('translate')('INFORMER.FILE_RESTORED');\r\n }\r\n break;\r\n case 'FILE_NOT_FOUND':\r\n if (command !== 'open_wallet' && command !== 'get_alias_info_by_name' && command !== 'get_alias_info_by_address') {\r\n // error_translate = $filter('translate')('INFORMER.FILE_NOT_FOUND');\r\n params = JSON.parse(params);\r\n if (params.path) {\r\n error_translate += ': ' + params.path;\r\n }\r\n }\r\n break;\r\n case 'CANCELED':\r\n case '':\r\n break;\r\n case 'FAIL':\r\n if (command === 'create_proposal' || command === 'accept_proposal' || command === 'release_contract' || command === 'request_cancel_contract' || command === 'accept_cancel_contract') {\r\n error_translate = ' ';\r\n }\r\n break;\r\n case 'ALREADY_EXISTS':\r\n error_translate = 'INFORMER.FILE_EXIST';\r\n break;\r\n default:\r\n error_translate = error;\r\n }\r\n if (error.indexOf('FAIL:failed to save file') > -1) {\r\n error_translate = 'INFORMER.FILE_NOT_SAVED';\r\n }\r\n if (error_translate !== '') {\r\n alert(error_translate);\r\n }\r\n }\r\n\r\n\r\n private commandDebug(command, params, result) {\r\n this.Debug(2, '----------------- ' + command + ' -----------------');\r\n const debug = {\r\n _send_params: params,\r\n _result: result\r\n };\r\n this.Debug(2, debug);\r\n try {\r\n this.Debug(2, JSON.parse(result));\r\n } catch (e) {\r\n this.Debug(2, {response_data: result, error_code: 'OK'});\r\n }\r\n }\r\n\r\n private asVal(data) {\r\n return {v: data};\r\n }\r\n\r\n private backendCallback(resultStr, params, callback, command) {\r\n let Result = resultStr;\r\n if (command !== 'get_clipboard') {\r\n if (!resultStr || resultStr === '') {\r\n Result = {};\r\n } else {\r\n try {\r\n Result = JSON.parse(resultStr);\r\n } catch (e) {\r\n Result = {response_data: resultStr, error_code: 'OK'};\r\n }\r\n }\r\n } else {\r\n Result = {\r\n error_code: 'OK',\r\n response_data: Result\r\n };\r\n }\r\n\r\n const Status = (Result.error_code === 'OK' || Result.error_code === 'TRUE');\r\n\r\n if (!Status && Status !== undefined && Result.error_code !== undefined) {\r\n this.Debug(1, 'API error for command: \"' + command + '\". Error code: ' + Result.error_code);\r\n }\r\n const data = ((typeof Result === 'object') && 'response_data' in Result) ? Result.response_data : Result;\r\n\r\n let res_error_code = false;\r\n if (typeof Result === 'object' && 'error_code' in Result && Result.error_code !== 'OK' && Result.error_code !== 'TRUE' && Result.error_code !== 'FALSE') {\r\n this.informerRun(Result.error_code, params, command);\r\n res_error_code = Result.error_code;\r\n }\r\n\r\n // if ( command === 'get_offers_ex' ){\r\n // Service.printLog( \"get_offers_ex offers count \"+((data.offers)?data.offers.length:0) );\r\n // }\r\n\r\n if (typeof callback === 'function') {\r\n callback(Status, data, res_error_code);\r\n } else {\r\n return data;\r\n }\r\n }\r\n\r\n\r\n private runCommand(command, params?, callback?) {\r\n if (this.backendObject) {\r\n const Action = this.backendObject[command];\r\n if (!Action) {\r\n this.Debug(0, 'Run Command Error! Command \"' + command + '\" don\\'t found in backendObject');\r\n } else {\r\n const that = this;\r\n params = (typeof params === 'string') ? params : JSON.stringify(params);\r\n if (params === undefined || params === '{}') {\r\n Action(function (resultStr) {\r\n that.commandDebug(command, params, resultStr);\r\n return that.backendCallback(resultStr, params, callback, command);\r\n });\r\n } else {\r\n Action(params, function (resultStr) {\r\n that.commandDebug(command, params, resultStr);\r\n return that.backendCallback(resultStr, params, callback, command);\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n\r\n eventSubscribe(command, callback) {\r\n if (command === 'on_core_event') {\r\n this.backendObject[command].connect(callback);\r\n } else {\r\n this.backendObject[command].connect((str) => {\r\n callback(JSON.parse(str));\r\n });\r\n }\r\n }\r\n\r\n\r\n initService() {\r\n return new Observable(\r\n observer => {\r\n if (!this.backendLoaded) {\r\n this.backendLoaded = true;\r\n const that = this;\r\n (window).QWebChannel((window).qt.webChannelTransport, function (channel) {\r\n that.backendObject = channel.objects.mediator_object;\r\n observer.next('ok');\r\n });\r\n } else {\r\n if (!this.backendObject) {\r\n observer.error('error');\r\n observer.error('error');\r\n }\r\n }\r\n }\r\n );\r\n }\r\n\r\n\r\n webkitLaunchedScript() {\r\n return this.runCommand('webkit_launched_script');\r\n }\r\n\r\n quitRequest() {\r\n return this.runCommand('on_request_quit');\r\n }\r\n\r\n getAppData(callback) {\r\n this.runCommand('get_app_data', {}, callback);\r\n }\r\n\r\n storeAppData(callback?) {\r\n this.runCommand('store_app_data', this.variablesService.settings, callback);\r\n }\r\n\r\n getSecureAppData(pass, callback) {\r\n this.runCommand('get_secure_app_data', pass, callback);\r\n }\r\n\r\n storeSecureAppData(callback) {\r\n if ( this.variablesService.appPass === '' ) {\r\n return callback(false);\r\n }\r\n const wallets = [];\r\n this.variablesService.wallets.forEach((wallet) => {\r\n wallets.push({name: wallet.name, pass: wallet.pass, path: wallet.path});\r\n });\r\n this.backendObject['store_secure_app_data'](JSON.stringify(wallets), this.variablesService.appPass, (dataStore) => {\r\n this.backendCallback(dataStore, {}, callback, 'store_secure_app_data');\r\n });\r\n }\r\n\r\n haveSecureAppData(callback) {\r\n this.runCommand('have_secure_app_data', {}, callback);\r\n }\r\n\r\n saveFileDialog(caption, fileMask, default_path, callback) {\r\n const dir = default_path ? default_path : '/';\r\n const params = {\r\n caption: caption,\r\n filemask: fileMask,\r\n default_dir: dir\r\n };\r\n this.runCommand('show_savefile_dialog', params, callback);\r\n }\r\n\r\n openFileDialog(caption, fileMask, default_path, callback) {\r\n const dir = default_path ? default_path : '/';\r\n const params = {\r\n caption: caption,\r\n filemask: fileMask,\r\n default_dir: dir\r\n };\r\n this.runCommand('show_openfile_dialog', params, callback);\r\n }\r\n\r\n generateWallet(path, pass, callback) {\r\n const params = {\r\n path: path,\r\n pass: pass\r\n };\r\n this.runCommand('generate_wallet', params, callback);\r\n }\r\n\r\n openWallet(path, pass, testEmpty, callback) {\r\n const params = {\r\n path: path,\r\n pass: pass\r\n };\r\n params['testEmpty'] = !!(testEmpty);\r\n this.runCommand('open_wallet', params, callback);\r\n }\r\n\r\n closeWallet(wallet_id, callback) {\r\n this.runCommand('close_wallet', {wallet_id: wallet_id}, callback);\r\n }\r\n\r\n getSmartSafeInfo(wallet_id, callback) {\r\n this.runCommand('get_smart_safe_info', {wallet_id: +wallet_id}, callback);\r\n }\r\n\r\n runWallet(wallet_id, callback) {\r\n this.runCommand('run_wallet', {wallet_id: +wallet_id}, callback);\r\n }\r\n\r\n isValidRestoreWalletText(text, callback) {\r\n this.runCommand('is_valid_restore_wallet_text', text, callback);\r\n }\r\n\r\n restoreWallet(path, pass, restore_key, callback) {\r\n const params = {\r\n restore_key: restore_key,\r\n path: path,\r\n pass: pass\r\n };\r\n this.runCommand('restore_wallet', params, callback);\r\n }\r\n\r\n\r\n sendMoney(from_wallet_id, to_address, amount, fee, mixin, comment, callback) {\r\n const params = {\r\n wallet_id: parseInt(from_wallet_id, 10),\r\n destinations: [\r\n {\r\n address: to_address,\r\n amount: amount\r\n }\r\n ],\r\n mixin_count: (mixin) ? parseInt(mixin, 10) : 0,\r\n lock_time: 0,\r\n fee: this.moneyToIntPipe.transform(fee),\r\n comment: comment,\r\n push_payer: true\r\n };\r\n this.runCommand('transfer', params, callback);\r\n }\r\n\r\n validateAddress(address, callback) {\r\n this.runCommand('validate_address', address, callback);\r\n }\r\n\r\n setClipboard(str, callback?) {\r\n return this.runCommand('set_clipboard', str, callback);\r\n }\r\n\r\n getClipboard(callback) {\r\n return this.runCommand('get_clipboard', {}, callback);\r\n }\r\n\r\n createProposal(wallet_id, title, comment, a_addr, b_addr, to_pay, a_pledge, b_pledge, time, payment_id, callback) {\r\n const params = {\r\n wallet_id: parseInt(wallet_id, 10),\r\n details: {\r\n t: title,\r\n c: comment,\r\n a_addr: a_addr,\r\n b_addr: b_addr,\r\n to_pay: this.moneyToIntPipe.transform(to_pay),\r\n a_pledge: this.moneyToIntPipe.transform(a_pledge) - this.moneyToIntPipe.transform(to_pay),\r\n b_pledge: this.moneyToIntPipe.transform(b_pledge)\r\n },\r\n payment_id: payment_id,\r\n expiration_period: parseInt(time, 10) * 60 * 60,\r\n fee: this.moneyToIntPipe.transform('0.01'),\r\n b_fee: this.moneyToIntPipe.transform('0.01')\r\n };\r\n this.Debug(1, params);\r\n this.runCommand('create_proposal', params, callback);\r\n }\r\n\r\n getContracts(wallet_id, callback) {\r\n const params = {\r\n wallet_id: parseInt(wallet_id, 10)\r\n };\r\n this.Debug(1, params);\r\n this.runCommand('get_contracts', params, callback);\r\n }\r\n\r\n acceptProposal(wallet_id, contract_id, callback) {\r\n const params = {\r\n wallet_id: parseInt(wallet_id, 10),\r\n contract_id: contract_id\r\n };\r\n this.Debug(1, params);\r\n this.runCommand('accept_proposal', params, callback);\r\n }\r\n\r\n releaseProposal(wallet_id, contract_id, release_type, callback) {\r\n const params = {\r\n wallet_id: parseInt(wallet_id, 10),\r\n contract_id: contract_id,\r\n release_type: release_type // \"normal\" or \"burn\"\r\n };\r\n this.Debug(1, params);\r\n this.runCommand('release_contract', params, callback);\r\n }\r\n\r\n requestCancelContract(wallet_id, contract_id, time, callback) {\r\n const params = {\r\n wallet_id: parseInt(wallet_id, 10),\r\n contract_id: contract_id,\r\n fee: this.moneyToIntPipe.transform('0.01'),\r\n expiration_period: parseInt(time, 10) * 60 * 60\r\n };\r\n this.Debug(1, params);\r\n this.runCommand('request_cancel_contract', params, callback);\r\n }\r\n\r\n acceptCancelContract(wallet_id, contract_id, callback) {\r\n const params = {\r\n wallet_id: parseInt(wallet_id, 10),\r\n contract_id: contract_id\r\n };\r\n this.Debug(1, params);\r\n this.runCommand('accept_cancel_contract', params, callback);\r\n }\r\n\r\n getMiningHistory(wallet_id, callback) {\r\n this.runCommand('get_mining_history', {wallet_id: parseInt(wallet_id, 10)}, callback);\r\n }\r\n\r\n startPosMining(wallet_id, callback?) {\r\n this.runCommand('start_pos_mining', {wallet_id: parseInt(wallet_id, 10)}, callback);\r\n }\r\n\r\n stopPosMining(wallet_id, callback?) {\r\n this.runCommand('stop_pos_mining', {wallet_id: parseInt(wallet_id, 10)}, callback);\r\n }\r\n\r\n}\r\n\r\n\r\n/*\r\n\r\n var deferred = null;\r\n\r\n var Service = {\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n /!* API *!/\r\n\r\n toggleAutoStart: function (value) {\r\n return this.runCommand('toggle_autostart', asVal(value));\r\n },\r\n\r\n\r\n\r\n getDefaultFee: function (callback) {\r\n return this.runCommand('get_default_fee', {}, callback);\r\n },\r\n\r\n getOptions: function (callback) {\r\n return this.runCommand('get_options', {}, callback);\r\n },\r\n\r\n isFileExist: function (path, callback) {\r\n return this.runCommand('is_file_exist', path, callback);\r\n },\r\n\r\n\r\n\r\n isAutoStartEnabled: function (callback) {\r\n this.runCommand('is_autostart_enabled', {}, function (status, data) {\r\n if (angular.isFunction(callback)) {\r\n callback('error_code' in data && data.error_code !== 'FALSE')\r\n }\r\n });\r\n },\r\n\r\n\r\n\r\n setLogLevel: function (level) {\r\n return this.runCommand('set_log_level', asVal(level))\r\n },\r\n\r\n resetWalletPass: function (wallet_id, pass, callback) {\r\n this.runCommand('reset_wallet_password', {wallet_id: wallet_id, pass: pass}, callback);\r\n },\r\n\r\n getVersion: function (callback) {\r\n this.runCommand('get_version', {}, function (status, version) {\r\n callback(version)\r\n })\r\n },\r\n\r\n getOsVersion: function (callback) {\r\n this.runCommand('get_os_version', {}, function (status, version) {\r\n callback(version)\r\n })\r\n },\r\n\r\n getLogFile: function (callback) {\r\n this.runCommand('get_log_file', {}, function (status, version) {\r\n callback(version)\r\n })\r\n },\r\n\r\n\r\n resync_wallet: function (wallet_id, callback) {\r\n this.runCommand('resync_wallet', {wallet_id: wallet_id}, callback);\r\n },\r\n\r\n\r\n\r\n\r\n\r\n registerAlias: function (wallet_id, alias, address, fee, comment, reward, callback) {\r\n var params = {\r\n \"wallet_id\": wallet_id,\r\n \"alias\": {\r\n \"alias\": alias,\r\n \"address\": address,\r\n \"tracking_key\": \"\",\r\n \"comment\": comment\r\n },\r\n \"fee\": $filter('money_to_int')(fee),\r\n \"reward\": $filter('money_to_int')(reward)\r\n };\r\n this.runCommand('request_alias_registration', params, callback);\r\n },\r\n\r\n updateAlias: function (wallet_id, alias, fee, callback) {\r\n var params = {\r\n wallet_id: wallet_id,\r\n alias: {\r\n \"alias\": alias.name.replace(\"@\", \"\"),\r\n \"address\": alias.address,\r\n \"tracking_key\": \"\",\r\n \"comment\": alias.comment\r\n },\r\n fee: $filter('money_to_int')(fee)\r\n };\r\n this.runCommand('request_alias_update', params, callback);\r\n },\r\n\r\n getAllAliases: function (callback) {\r\n this.runCommand('get_all_aliases', {}, callback);\r\n },\r\n\r\n getAliasByName: function (value, callback) {\r\n return this.runCommand('get_alias_info_by_name', value, callback);\r\n },\r\n\r\n getAliasByAddress: function (value, callback) {\r\n return this.runCommand('get_alias_info_by_address', value, callback);\r\n },\r\n\r\n getPoolInfo: function (callback) {\r\n this.runCommand('get_tx_pool_info', {}, callback);\r\n },\r\n\r\n localization: function (stringsArray, title, callback) {\r\n var data = {\r\n strings: stringsArray,\r\n language_title: title\r\n };\r\n this.runCommand('set_localization_strings', data, callback);\r\n },\r\n\r\n storeFile: function (path, buff, callback) {\r\n this.backendObject['store_to_file'](path, (typeof buff === 'string' ? buff : JSON.stringify(buff)), function (data) {\r\n backendCallback(data, {}, callback, 'store_to_file');\r\n });\r\n },\r\n\r\n\r\n\r\n\r\n\r\n getMiningEstimate: function (amount_coins, time, callback) {\r\n var params = {\r\n \"amount_coins\": $filter('money_to_int')(amount_coins),\r\n \"time\": parseInt(time)\r\n };\r\n this.runCommand('get_mining_estimate', params, callback);\r\n },\r\n\r\n backupWalletKeys: function (wallet_id, path, callback) {\r\n var params = {\r\n \"wallet_id\": wallet_id,\r\n \"path\": path\r\n };\r\n this.runCommand('backup_wallet_keys', params, callback);\r\n },\r\n\r\n\r\n getAliasCoast: function (alias, callback) {\r\n this.runCommand('get_alias_coast', asVal(alias), callback);\r\n },\r\n\r\n\r\n\r\n\r\n setBlockedIcon: function (enabled, callback) {\r\n var mode = (enabled) ? \"blocked\" : \"normal\";\r\n Service.runCommand('bool_toggle_icon', mode, callback);\r\n },\r\n\r\n\r\n\r\n\r\n\r\n getWalletInfo: function (wallet_id, callback) {\r\n this.runCommand('get_wallet_info', {wallet_id: wallet_id}, callback);\r\n },\r\n\r\n\r\n\r\n printText: function (content) {\r\n return this.runCommand('print_text', {html_text: content});\r\n },\r\n\r\n printLog: function (msg, log_level) {\r\n return this.runCommand('print_log', {msg: msg, log_level: log_level});\r\n },\r\n\r\n openUrlInBrowser: function (url, callback) {\r\n return this.runCommand('open_url_in_browser', url, callback);\r\n },\r\n\r\n\r\n\r\n /!* API END *!/\r\n\r\n };\r\n return Service;\r\n }]);\r\n\r\n})();\r\n\r\n*/\r\n\r\n","import {Injectable, Input, NgZone} from '@angular/core';\r\nimport {Wallet} from '../models/wallet.model';\r\nimport {BehaviorSubject} from 'rxjs';\r\nimport {Idle} from 'idlejs/dist';\r\nimport {Router} from '@angular/router';\r\nimport {ContextMenuComponent, ContextMenuService} from 'ngx-contextmenu';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class VariablesService {\r\n\r\n public appPass = '';\r\n public moneyEquivalent = 0;\r\n public defaultTheme = 'dark';\r\n public defaultCurrency = 'ZAN';\r\n public opening_wallet: Wallet;\r\n public exp_med_ts = 0;\r\n public height_app = 0;\r\n public daemon_state = 0;\r\n public sync = {\r\n progress_value: 0,\r\n progress_value_text: '0'\r\n };\r\n\r\n public settings = {\r\n theme: '',\r\n language: 'en',\r\n default_path: '/',\r\n viewedContracts: [],\r\n notViewedContracts: []\r\n };\r\n\r\n public wallets: Array = [];\r\n public currentWallet: Wallet;\r\n\r\n getHeightAppEvent = new BehaviorSubject(null);\r\n getRefreshStackingEvent = new BehaviorSubject(null);\r\n\r\n public idle = new Idle()\r\n .whenNotInteractive()\r\n .within(15)\r\n .do(() => {\r\n this.ngZone.run(() => {\r\n this.idle.stop();\r\n this.appPass = '';\r\n this.router.navigate(['/login'], {queryParams: {type: 'auth'}});\r\n });\r\n });\r\n\r\n @Input() contextMenu: ContextMenuComponent;\r\n\r\n constructor(private router: Router, private ngZone: NgZone, private contextMenuService: ContextMenuService) {\r\n }\r\n\r\n setHeightApp(height: number) {\r\n if (height !== this.height_app) {\r\n this.height_app = height;\r\n this.getHeightAppEvent.next(height);\r\n }\r\n }\r\n\r\n setRefreshStacking(wallet_id: number) {\r\n this.getHeightAppEvent.next(wallet_id);\r\n }\r\n\r\n setCurrentWallet(id): void {\r\n this.wallets.forEach((wallet) => {\r\n if (wallet.wallet_id === id) {\r\n this.currentWallet = wallet;\r\n }\r\n });\r\n }\r\n\r\n getWallet(id): Wallet {\r\n for (let i = 0; i < this.wallets.length; i++) {\r\n if (this.wallets[i].wallet_id === id) {\r\n return this.wallets[i];\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n startCountdown() {\r\n this.idle.restart();\r\n }\r\n\r\n stopCountdown() {\r\n this.idle.stop();\r\n }\r\n\r\n public onContextMenu($event: MouseEvent): void {\r\n $event.target['contextSelectionStart'] = $event.target['selectionStart'];\r\n $event.target['contextSelectionEnd'] = $event.target['selectionEnd'];\r\n if ($event.target && ($event.target['nodeName'].toUpperCase() === 'TEXTAREA' || $event.target['nodeName'].toUpperCase() === 'INPUT') && !$event.target['readOnly']) {\r\n this.contextMenuService.show.next({\r\n contextMenu: this.contextMenu,\r\n event: $event,\r\n item: $event.target,\r\n });\r\n $event.preventDefault();\r\n $event.stopPropagation();\r\n }\r\n }\r\n\r\n}\r\n","import { NgModule } from '@angular/core';\r\nimport { Routes, RouterModule } from '@angular/router';\r\n\r\n// Components\r\nimport { MainComponent } from './main/main.component';\r\nimport { LoginComponent } from './login/login.component';\r\nimport { WalletComponent } from './wallet/wallet.component';\r\nimport { SendComponent } from './send/send.component';\r\nimport { ReceiveComponent } from './receive/receive.component';\r\nimport { HistoryComponent } from './history/history.component';\r\nimport { ContractsComponent } from './contracts/contracts.component';\r\nimport { PurchaseComponent } from './purchase/purchase.component';\r\nimport { MessagesComponent } from './messages/messages.component';\r\nimport { TypingMessageComponent } from './typing-message/typing-message.component';\r\nimport { StakingComponent } from './staking/staking.component';\r\nimport { SettingsComponent } from './settings/settings.component';\r\nimport { CreateWalletComponent } from './create-wallet/create-wallet.component';\r\nimport { OpenWalletComponent } from './open-wallet/open-wallet.component';\r\nimport { RestoreWalletComponent } from './restore-wallet/restore-wallet.component';\r\nimport { SeedPhraseComponent } from './seed-phrase/seed-phrase.component';\r\nimport { WalletDetailsComponent } from './wallet-details/wallet-details.component';\r\n\r\nconst routes: Routes = [\r\n {\r\n path: '',\r\n component: MainComponent\r\n },\r\n {\r\n path: 'main',\r\n component: MainComponent\r\n },\r\n {\r\n path: 'login',\r\n component: LoginComponent\r\n },\r\n {\r\n path: 'wallet/:id',\r\n component: WalletComponent,\r\n children: [\r\n {\r\n path: 'send',\r\n component: SendComponent\r\n },\r\n {\r\n path: 'receive',\r\n component: ReceiveComponent\r\n },\r\n {\r\n path: 'history',\r\n component: HistoryComponent\r\n },\r\n {\r\n path: 'contracts',\r\n component: ContractsComponent,\r\n },\r\n {\r\n path: 'purchase',\r\n component: PurchaseComponent\r\n },\r\n {\r\n path: 'purchase/:id',\r\n component: PurchaseComponent\r\n },\r\n {\r\n path: 'messages',\r\n component: MessagesComponent,\r\n },\r\n {\r\n path: 'messages/:id',\r\n component: TypingMessageComponent,\r\n },\r\n {\r\n path: 'staking',\r\n component: StakingComponent\r\n },\r\n {\r\n path: '',\r\n redirectTo: 'send',\r\n pathMatch: 'full'\r\n }\r\n ]\r\n },\r\n {\r\n path: 'create',\r\n component: CreateWalletComponent\r\n },\r\n {\r\n path: 'open',\r\n component: OpenWalletComponent\r\n },\r\n {\r\n path: 'restore',\r\n component: RestoreWalletComponent\r\n },\r\n {\r\n path: 'seed-phrase',\r\n component: SeedPhraseComponent\r\n },\r\n {\r\n path: 'details',\r\n component: WalletDetailsComponent\r\n },\r\n {\r\n path: 'settings',\r\n component: SettingsComponent\r\n },\r\n {\r\n path: '',\r\n redirectTo: '/',\r\n pathMatch: 'full'\r\n }\r\n];\r\n\r\n@NgModule({\r\n imports: [RouterModule.forRoot(routes)],\r\n exports: [RouterModule]\r\n})\r\n\r\n\r\nexport class AppRoutingModule { }\r\n","module.exports = \"\\r\\n\\r\\n
\\r\\n \\r\\n
\\r\\n\\r\\n\\r\\n copy\\r\\n paste\\r\\n select all\\r\\n\\r\\n\"","module.exports = \"/*\\r\\n* Implementation of themes\\r\\n*/\\n.app-content {\\n display: flex;\\n overflow-x: overlay;\\n overflow-y: hidden;\\n width: 100%; }\\n\\r\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvRDpcXHphbm8vc3JjXFxhc3NldHNcXHNjc3NcXGJhc2VcXF9taXhpbnMuc2NzcyIsInNyYy9hcHAvRDpcXHphbm8vc3JjXFxhcHBcXGFwcC5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUE4RUE7O0VBRUU7QUM5RUY7RUFDRSxjQUFhO0VBQ2Isb0JBQW1CO0VBQ25CLG1CQUFrQjtFQUNsQixZQUFXLEVBQ1oiLCJmaWxlIjoic3JjL2FwcC9hcHAuY29tcG9uZW50LnNjc3MiLCJzb3VyY2VzQ29udGVudCI6WyJAbWl4aW4gdGV4dC10cnVuY2F0ZSB7XHJcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcclxuICB0ZXh0LW92ZXJmbG93OiBlbGxpcHNpcztcclxuICB3aGl0ZS1zcGFjZTogbm93cmFwO1xyXG59XHJcbkBtaXhpbiB0ZXh0V3JhcCB7XHJcbiAgd2hpdGUtc3BhY2U6IG5vcm1hbDtcclxuICBvdmVyZmxvdy13cmFwOiBicmVhay13b3JkO1xyXG4gIHdvcmQtd3JhcDogYnJlYWstd29yZDtcclxuICB3b3JkLWJyZWFrOiBicmVhay1hbGw7XHJcbiAgbGluZS1icmVhazogc3RyaWN0O1xyXG4gIC13ZWJraXQtaHlwaGVuczogYXV0bztcclxuICAtbXMtaHlwaGVuczogYXV0bztcclxuICBoeXBoZW5zOiBhdXRvO1xyXG59XHJcbkBtaXhpbiBjb3ZlckJveCB7XHJcblx0cG9zaXRpb246IGFic29sdXRlO1xyXG5cdHRvcDogMDtcclxuXHRsZWZ0OiAwO1xyXG5cdHdpZHRoOiAxMDAlO1xyXG5cdGhlaWdodDogMTAwJTtcclxufVxyXG5AbWl4aW4gYWJzICgkdG9wOiBhdXRvLCAkcmlnaHQ6IGF1dG8sICRib3R0b206IGF1dG8sICRsZWZ0OiBhdXRvKSB7XHJcbiAgdG9wOiAkdG9wO1xyXG4gIHJpZ2h0OiAkcmlnaHQ7XHJcbiAgYm90dG9tOiAkYm90dG9tO1xyXG4gIGxlZnQ6ICRsZWZ0O1xyXG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcclxufVxyXG5AbWl4aW4gY292ZXJJbWcge1xyXG5cdGJhY2tncm91bmQtcmVwZWF0OiBuby1yZXBlYXQ7XHJcblx0LXdlYmtpdC1iYWNrZ3JvdW5kLXNpemU6IGNvdmVyO1xyXG5cdC1vLWJhY2tncm91bmQtc2l6ZTogY292ZXI7XHJcblx0YmFja2dyb3VuZC1zaXplOiBjb3ZlcjtcclxuXHRiYWNrZ3JvdW5kLXBvc2l0aW9uOiA1MCUgNTAlO1xyXG59XHJcbkBtaXhpbiB2YWxpbmdCb3gge1xyXG5cdHBvc2l0aW9uOiBhYnNvbHV0ZTtcclxuXHR0b3A6ICA1MCU7XHJcblx0bGVmdDogNTAlO1xyXG5cdHRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUsIC01MCUpO1xyXG59XHJcbkBtaXhpbiB1blNlbGVjdCB7XHJcblx0LXdlYmtpdC10b3VjaC1jb2xsb3V0OiBub25lO1xyXG4gIC13ZWJraXQtdXNlci1zZWxlY3Q6IG5vbmU7XHJcbiAgLWtodG1sLXVzZXItc2VsZWN0OiBub25lO1xyXG4gIC1tb3otdXNlci1zZWxlY3Q6IG5vbmU7XHJcbiAgLW1zLXVzZXItc2VsZWN0OiBub25lO1xyXG4gIHVzZXItc2VsZWN0OiBub25lO1xyXG59XHJcbkBtaXhpbiBtYXgxMTk5IHsgLy8gbWFrZXQgMTE3MVxyXG4gIEBtZWRpYSAobWF4LXdpZHRoOiAxMTk5cHgpIHsgQGNvbnRlbnQ7IH1cclxufVxyXG5AbWl4aW4gbWF4MTE3MCB7IC8vIG1ha2V0cyA5OTJcclxuICBAbWVkaWEgKG1heC13aWR0aDogMTE3MHB4KSB7IEBjb250ZW50OyB9XHJcbn1cclxuQG1peGluIG1heDk5MSB7IC8vIG1ha2V0cyA3NjJcclxuICBAbWVkaWEgKG1heC13aWR0aDogOTkxcHgpIHsgQGNvbnRlbnQ7IH1cclxufVxyXG5AbWl4aW4gbWF4NzYxIHsgLy8gbWFrZXRzIDU3NlxyXG4gIEBtZWRpYSAobWF4LXdpZHRoOiA3NjFweCkgeyBAY29udGVudDsgfVxyXG59XHJcbkBtaXhpbiBtYXg1NzUgeyAvLyBtYWtldHMgNDAwXHJcbiAgQG1lZGlhIChtYXgtd2lkdGg6IDU3NXB4KSB7IEBjb250ZW50OyB9XHJcbn1cclxuQG1peGluIG1vYmlsZSB7XHJcbiAgQG1lZGlhIChtYXgtd2lkdGg6IDM5OXB4KSB7IEBjb250ZW50OyB9XHJcbn1cclxuQG1peGluIGljb0NlbnRlciB7XHJcbiAgICBiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0O1xyXG4gICAgYmFja2dyb3VuZC1wb3NpdGlvbjogY2VudGVyIGNlbnRlcjtcclxufVxyXG5AbWl4aW4gcHNldWRvICgkZGlzcGxheTogYmxvY2ssICRwb3M6IGFic29sdXRlLCAkY29udGVudDogJycpe1xyXG4gIGNvbnRlbnQ6ICRjb250ZW50O1xyXG4gIGRpc3BsYXk6ICRkaXNwbGF5O1xyXG4gIHBvc2l0aW9uOiAkcG9zO1xyXG59XHJcblxyXG4vKlxyXG4qIEltcGxlbWVudGF0aW9uIG9mIHRoZW1lc1xyXG4qL1xyXG5AbWl4aW4gdGhlbWlmeSgkdGhlbWVzOiAkdGhlbWVzKSB7XHJcbiAgQGVhY2ggJHRoZW1lLCAkbWFwIGluICR0aGVtZXMge1xyXG4gICAgLnRoZW1lLSN7JHRoZW1lfSAmIHtcclxuICAgICAgJHRoZW1lLW1hcDogKCkgIWdsb2JhbDtcclxuICAgICAgQGVhY2ggJGtleSwgJHN1Ym1hcCBpbiAkbWFwIHtcclxuICAgICAgICAkdmFsdWU6IG1hcC1nZXQobWFwLWdldCgkdGhlbWVzLCAkdGhlbWUpLCAnI3ska2V5fScpO1xyXG4gICAgICAgICR0aGVtZS1tYXA6IG1hcC1tZXJnZSgkdGhlbWUtbWFwLCAoJGtleTogJHZhbHVlKSkgIWdsb2JhbDtcclxuICAgICAgfVxyXG4gICAgICBAY29udGVudDtcclxuICAgICAgJHRoZW1lLW1hcDogbnVsbCAhZ2xvYmFsO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuQGZ1bmN0aW9uIHRoZW1lZCgka2V5KSB7XHJcbiAgQHJldHVybiBtYXAtZ2V0KCR0aGVtZS1tYXAsICRrZXkpO1xyXG59XHJcbiIsIkBpbXBvcnQgJ35zcmMvYXNzZXRzL3Njc3MvYmFzZS9taXhpbnMnO1xyXG5cclxuLmFwcC1jb250ZW50IHtcclxuICBkaXNwbGF5OiBmbGV4O1xyXG4gIG92ZXJmbG93LXg6IG92ZXJsYXk7XHJcbiAgb3ZlcmZsb3cteTogaGlkZGVuO1xyXG4gIHdpZHRoOiAxMDAlO1xyXG59XHJcbiJdfQ== */\"","import {Component, OnInit, NgZone, Renderer2, OnDestroy} from '@angular/core';\r\nimport {HttpClient} from '@angular/common/http';\r\nimport {TranslateService} from '@ngx-translate/core';\r\nimport {BackendService} from './_helpers/services/backend.service';\r\nimport {Router} from '@angular/router';\r\nimport {VariablesService} from './_helpers/services/variables.service';\r\n\r\n@Component({\r\n selector: 'app-root',\r\n templateUrl: './app.component.html',\r\n styleUrls: ['./app.component.scss']\r\n})\r\nexport class AppComponent implements OnInit, OnDestroy {\r\n\r\n intervalUpdateContractsState;\r\n onQuitRequest = false;\r\n\r\n constructor(\r\n private http: HttpClient,\r\n private renderer: Renderer2,\r\n public translate: TranslateService,\r\n private backend: BackendService,\r\n private router: Router,\r\n private variablesService: VariablesService,\r\n private ngZone: NgZone\r\n ) {\r\n translate.addLangs(['en', 'fr']);\r\n translate.setDefaultLang('en');\r\n // const browserLang = translate.getBrowserLang();\r\n // translate.use(browserLang.match(/en|fr/) ? browserLang : 'en');\r\n }\r\n\r\n ngOnInit() {\r\n this.backend.initService().subscribe(initMessage => {\r\n console.log('Init message: ', initMessage);\r\n\r\n this.backend.webkitLaunchedScript();\r\n\r\n this.backend.eventSubscribe('quit_requested', () => {\r\n if (!this.onQuitRequest) {\r\n this.backend.storeSecureAppData(() => {\r\n this.backend.storeAppData(() => {\r\n const recursionCloseWallets = () => {\r\n if (this.variablesService.wallets.length) {\r\n const lastIndex = this.variablesService.wallets.length - 1;\r\n this.backend.closeWallet(this.variablesService.wallets[lastIndex].wallet_id, () => {\r\n this.variablesService.wallets.splice(lastIndex, 1);\r\n recursionCloseWallets();\r\n });\r\n } else {\r\n this.backend.quitRequest();\r\n }\r\n };\r\n recursionCloseWallets();\r\n });\r\n });\r\n }\r\n this.onQuitRequest = true;\r\n });\r\n\r\n\r\n this.backend.eventSubscribe('update_wallet_status', (data) => {\r\n console.log('----------------- update_wallet_status -----------------');\r\n console.log(data);\r\n\r\n const wallet_state = data.wallet_state;\r\n const is_mining = data.is_mining;\r\n const wallet = this.variablesService.getWallet(data.wallet_id);\r\n\r\n // 1-synch, 2-ready, 3 - error\r\n if (wallet) {\r\n this.ngZone.run(() => {\r\n wallet.loaded = false;\r\n wallet.staking = is_mining;\r\n if (wallet_state === 2) { // ready\r\n wallet.loaded = true;\r\n }\r\n if (wallet_state === 3) { // error\r\n // safe.error = true;\r\n }\r\n wallet.balance = data.balance;\r\n wallet.unlocked_balance = data.unlocked_balance;\r\n wallet.mined_total = data.minied_total;\r\n });\r\n }\r\n });\r\n\r\n\r\n this.backend.eventSubscribe('wallet_sync_progress', (data) => {\r\n console.log('----------------- wallet_sync_progress -----------------');\r\n console.log(data);\r\n\r\n const wallet = this.variablesService.getWallet(data.wallet_id);\r\n if (wallet) {\r\n this.ngZone.run(() => {\r\n wallet.progress = data.progress;\r\n if (wallet.progress === 0) {\r\n wallet.loaded = false;\r\n } else if (wallet.progress === 100) {\r\n wallet.loaded = true;\r\n }\r\n });\r\n }\r\n });\r\n\r\n\r\n this.backend.eventSubscribe('update_daemon_state', (data) => {\r\n console.log('----------------- update_daemon_state -----------------');\r\n console.log('DAEMON:' + data.daemon_network_state);\r\n console.log(data);\r\n this.variablesService.exp_med_ts = data['expiration_median_timestamp'] + 600 + 1;\r\n // this.variablesService.height_app = data.height;\r\n this.variablesService.setHeightApp(data.height);\r\n\r\n this.ngZone.run(() => {\r\n this.variablesService.daemon_state = data.daemon_network_state;\r\n if (data.daemon_network_state === 1) {\r\n const max = data.max_net_seen_height - data.synchronization_start_height;\r\n const current = data.height - data.synchronization_start_height;\r\n const return_val = Math.floor((current * 100 / max) * 100) / 100;\r\n if (max === 0 || return_val < 0) {\r\n this.variablesService.sync.progress_value = 0;\r\n this.variablesService.sync.progress_value_text = '0.00';\r\n } else if (return_val >= 100) {\r\n this.variablesService.sync.progress_value = 100;\r\n this.variablesService.sync.progress_value_text = '99.99';\r\n } else {\r\n this.variablesService.sync.progress_value = return_val;\r\n this.variablesService.sync.progress_value_text = return_val.toFixed(2);\r\n }\r\n }\r\n });\r\n });\r\n\r\n this.backend.eventSubscribe('money_transfer', (data) => {\r\n console.log('----------------- money_transfer -----------------');\r\n console.log(data);\r\n\r\n if (!data.ti) {\r\n return;\r\n }\r\n\r\n const wallet_id = data.wallet_id;\r\n const tr_info = data.ti;\r\n\r\n const safe = this.variablesService.getWallet(wallet_id);\r\n\r\n if (safe) {\r\n this.ngZone.run(() => {\r\n\r\n if (!safe.loaded) {\r\n safe.balance = data.balance;\r\n safe.unlocked_balance = data.unlocked_balance;\r\n } else {\r\n safe.balance = data.balance;\r\n safe.unlocked_balance = data.unlocked_balance;\r\n }\r\n\r\n if (tr_info.tx_type === 6) {\r\n this.variablesService.setRefreshStacking(wallet_id);\r\n }\r\n\r\n let tr_exists = safe.excluded_history.some(elem => elem.tx_hash === tr_info.tx_hash);\r\n tr_exists = (!tr_exists) ? safe.history.some(elem => elem.tx_hash === tr_info.tx_hash) : tr_exists;\r\n\r\n safe.prepareHistory([tr_info]);\r\n\r\n if (tr_info.hasOwnProperty('contract')) {\r\n const exp_med_ts = this.variablesService.exp_med_ts;\r\n const height_app = this.variablesService.height_app;\r\n\r\n const contract = tr_info.contract[0];\r\n\r\n if (tr_exists) {\r\n for (let i = 0; i < safe.contracts.length; i++) {\r\n if (safe.contracts[i].contract_id === contract.contract_id && safe.contracts[i].is_a === contract.is_a) {\r\n safe.contracts[i].cancel_expiration_time = contract.cancel_expiration_time;\r\n safe.contracts[i].expiration_time = contract.expiration_time;\r\n safe.contracts[i].height = contract.height;\r\n safe.contracts[i].timestamp = contract.timestamp;\r\n break;\r\n }\r\n }\r\n // $rootScope.getContractsRecount();\r\n return;\r\n }\r\n\r\n if (contract.state === 1 && contract.expiration_time < exp_med_ts) {\r\n contract.state = 110;\r\n } else if (contract.state === 5 && contract.cancel_expiration_time < exp_med_ts) {\r\n contract.state = 130;\r\n } else if (contract.state === 1) {\r\n const searchResult2 = this.variablesService.settings.notViewedContracts.find(elem => elem.state === 110 && elem.is_a === contract.is_a && elem.contract_id === contract.contract_id);\r\n if (searchResult2) {\r\n if (searchResult2.time === contract.expiration_time) {\r\n contract.state = 110;\r\n } else {\r\n for (let j = 0; j < this.variablesService.settings.notViewedContracts.length; j++) {\r\n if (this.variablesService.settings.notViewedContracts[j].contract_id === contract.contract_id && this.variablesService.settings.notViewedContracts[j].is_a === contract.is_a) {\r\n this.variablesService.settings.notViewedContracts.splice(j, 1);\r\n break;\r\n }\r\n }\r\n for (let j = 0; j < this.variablesService.settings.viewedContracts.length; j++) {\r\n if (this.variablesService.settings.viewedContracts[j].contract_id === contract.contract_id && this.variablesService.settings.viewedContracts[j].is_a === contract.is_a) {\r\n this.variablesService.settings.viewedContracts.splice(j, 1);\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n } else if (contract.state === 2 && (contract.height === 0 || (height_app - contract.height) < 10)) {\r\n contract.state = 201;\r\n } else if (contract.state === 2) {\r\n const searchResult3 = this.variablesService.settings.viewedContracts.some(elem => elem.state === 120 && elem.is_a === contract.is_a && elem.contract_id === contract.contract_id);\r\n if (searchResult3) {\r\n contract.state = 120;\r\n }\r\n } else if (contract.state === 5) {\r\n const searchResult4 = this.variablesService.settings.notViewedContracts.find(elem => elem.state === 130 && elem.is_a === contract.is_a && elem.contract_id === contract.contract_id);\r\n if (searchResult4) {\r\n if (searchResult4.time === contract.cancel_expiration_time) {\r\n contract.state = 130;\r\n } else {\r\n for (let j = 0; j < this.variablesService.settings.notViewedContracts.length; j++) {\r\n if (this.variablesService.settings.notViewedContracts[j].contract_id === contract.contract_id && this.variablesService.settings.notViewedContracts[j].is_a === contract.is_a) {\r\n this.variablesService.settings.notViewedContracts.splice(j, 1);\r\n break;\r\n }\r\n }\r\n for (let j = 0; j < this.variablesService.settings.viewedContracts.length; j++) {\r\n if (this.variablesService.settings.viewedContracts[j].contract_id === contract.contract_id && this.variablesService.settings.viewedContracts[j].is_a === contract.is_a) {\r\n this.variablesService.settings.viewedContracts.splice(j, 1);\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n } else if (contract.state === 6 && (contract.height === 0 || (height_app - contract.height) < 10)) {\r\n contract.state = 601;\r\n }\r\n\r\n const searchResult = this.variablesService.settings.viewedContracts.some(elem => elem.state === contract.state && elem.is_a === contract.is_a && elem.contract_id === contract.contract_id);\r\n contract.is_new = !searchResult;\r\n\r\n contract['private_detailes'].a_pledge += contract['private_detailes'].to_pay;\r\n\r\n let findContract = false;\r\n for (let i = 0; i < safe.contracts.length; i++) {\r\n if (safe.contracts[i].contract_id === contract.contract_id && safe.contracts[i].is_a === contract.is_a) {\r\n for (const prop in contract) {\r\n if (contract.hasOwnProperty(prop)) {\r\n safe.contracts[i][prop] = contract[prop];\r\n }\r\n }\r\n findContract = true;\r\n break;\r\n }\r\n }\r\n if (findContract === false) {\r\n safe.contracts.push(contract);\r\n }\r\n safe.recountNewContracts();\r\n }\r\n\r\n });\r\n }\r\n });\r\n\r\n\r\n this.backend.eventSubscribe('money_transfer_cancel', (data) => {\r\n console.log('----------------- money_transfer_cancel -----------------');\r\n console.log(data);\r\n\r\n // if (!data.ti) {\r\n // return;\r\n // }\r\n //\r\n // var wallet_id = data.wallet_id;\r\n // var tr_info = data.ti;\r\n // var safe = $rootScope.getSafeById(wallet_id);\r\n // if (safe) {\r\n // if ( tr_info.hasOwnProperty(\"contract\") ){\r\n // for (var i = 0; i < $rootScope.contracts.length; i++) {\r\n // if ($rootScope.contracts[i].contract_id === tr_info.contract[0].contract_id && $rootScope.contracts[i].is_a === tr_info.contract[0].is_a) {\r\n // if ($rootScope.contracts[i].state === 1 || $rootScope.contracts[i].state === 110) {\r\n // $rootScope.contracts[i].isNew = true;\r\n // $rootScope.contracts[i].state = 140;\r\n // $rootScope.getContractsRecount(); //escrow_code\r\n // }\r\n // break;\r\n // }\r\n // }\r\n // }\r\n // angular.forEach(safe.history, function (tr_item, key) {\r\n // if (tr_item.tx_hash === tr_info.tx_hash) {\r\n // safe.history.splice(key, 1);\r\n // }\r\n // });\r\n //\r\n // var error_tr = '';\r\n // switch (tr_info.tx_type) {\r\n // case 0:\r\n // error_tr = $filter('translate')('ERROR_GUI_TX_TYPE_NORMAL') + '
' +\r\n // tr_info.tx_hash + '
' + safe.name + '
' + safe.address + '
' +\r\n // $filter('translate')('ERROR_GUI_TX_TYPE_NORMAL_TO') + ' ' + $rootScope.moneyParse(tr_info.amount) + ' ' +\r\n // $filter('translate')('ERROR_GUI_TX_TYPE_NORMAL_END');\r\n // informer.error(error_tr);\r\n // break;\r\n // case 1:\r\n // informer.error('ERROR_GUI_TX_TYPE_PUSH_OFFER');\r\n // break;\r\n // case 2:\r\n // informer.error('ERROR_GUI_TX_TYPE_UPDATE_OFFER');\r\n // break;\r\n // case 3:\r\n // informer.error('ERROR_GUI_TX_TYPE_CANCEL_OFFER');\r\n // break;\r\n // case 4:\r\n // error_tr = $filter('translate')('ERROR_GUI_TX_TYPE_NEW_ALIAS') + '
' +\r\n // tr_info.tx_hash + '
' + safe.name + '
' + safe.address + '
' +\r\n // $filter('translate')('ERROR_GUI_TX_TYPE_NEW_ALIAS_END');\r\n // informer.error(error_tr);\r\n // break;\r\n // case 5:\r\n // error_tr = $filter('translate')('ERROR_GUI_TX_TYPE_UPDATE_ALIAS') + '
' +\r\n // tr_info.tx_hash + '
' + safe.name + '
' + safe.address + '
' +\r\n // $filter('translate')('ERROR_GUI_TX_TYPE_NEW_ALIAS_END');\r\n // informer.error(error_tr);\r\n // break;\r\n // case 6:\r\n // informer.error('ERROR_GUI_TX_TYPE_COIN_BASE');\r\n // break;\r\n // }\r\n // }\r\n });\r\n\r\n this.intervalUpdateContractsState = setInterval(() => {\r\n this.variablesService.wallets.forEach((wallet) => {\r\n wallet.contracts.forEach((contract) => {\r\n if (contract.state === 201 && contract.height !== 0 && (this.variablesService.height_app - contract.height) >= 10) {\r\n contract.state = 2;\r\n contract.is_new = true;\r\n console.warn('need check state in contracts');\r\n } else if (contract.state === 601 && contract.height !== 0 && (this.variablesService.height_app - contract.height) >= 10) {\r\n contract.state = 6;\r\n contract.is_new = true;\r\n }\r\n });\r\n });\r\n }, 30000);\r\n\r\n\r\n this.backend.getAppData((status, data) => {\r\n if (data && Object.keys(data).length > 0) {\r\n this.variablesService.settings = data;\r\n if (this.variablesService.settings.hasOwnProperty('theme') && ['dark', 'white', 'gray'].indexOf(this.variablesService.settings.theme) !== -1) {\r\n this.renderer.addClass(document.body, 'theme-' + this.variablesService.settings.theme);\r\n } else {\r\n this.renderer.addClass(document.body, 'theme-' + this.variablesService.defaultTheme);\r\n }\r\n } else {\r\n this.variablesService.settings.theme = this.variablesService.defaultTheme;\r\n this.renderer.addClass(document.body, 'theme-' + this.variablesService.settings.theme);\r\n }\r\n\r\n if (this.router.url !== '/login') {\r\n this.backend.haveSecureAppData((statusPass) => {\r\n if (statusPass) {\r\n this.ngZone.run(() => {\r\n this.router.navigate(['/login'], {queryParams: {type: 'auth'}});\r\n });\r\n } else {\r\n this.ngZone.run(() => {\r\n this.router.navigate(['/login'], {queryParams: {type: 'reg'}});\r\n });\r\n }\r\n });\r\n }\r\n });\r\n }, error => {\r\n console.log(error);\r\n });\r\n this.getMoneyEquivalent();\r\n }\r\n\r\n getMoneyEquivalent() {\r\n // todo now start only once, need check daemon state and re-init\r\n this.http.get('https://api.coinmarketcap.com/v2/ticker/2').subscribe(\r\n result => {\r\n if (result.hasOwnProperty('data')) {\r\n this.variablesService.moneyEquivalent = result['data']['quotes']['USD']['price'];\r\n }\r\n },\r\n error => {\r\n console.warn('Error coinmarketcap', error);\r\n }\r\n );\r\n }\r\n\r\n\r\n contextMenuCopy(target) {\r\n if (target && (target['nodeName'].toUpperCase() === 'TEXTAREA' || target['nodeName'].toUpperCase() === 'INPUT')) {\r\n const start = (target['contextSelectionStart']) ? 'contextSelectionStart' : 'selectionStart';\r\n const end = (target['contextSelectionEnd']) ? 'contextSelectionEnd' : 'selectionEnd';\r\n const canUseSelection = ((target[start]) || (target[start] === '0'));\r\n const SelectedText = (canUseSelection) ? target['value'].substring(target[start], target[end]) : target['value'];\r\n this.backend.setClipboard(String(SelectedText));\r\n }\r\n }\r\n\r\n contextMenuPaste(target) {\r\n if (target && (target['nodeName'].toUpperCase() === 'TEXTAREA' || target['nodeName'].toUpperCase() === 'INPUT')) {\r\n this.backend.getClipboard((status, clipboard) => {\r\n clipboard = String(clipboard);\r\n if (typeof clipboard !== 'string' || clipboard.length) {\r\n const start = (target['contextSelectionStart']) ? 'contextSelectionStart' : 'selectionStart';\r\n const end = (target['contextSelectionEnd']) ? 'contextSelectionEnd' : 'selectionEnd';\r\n const canUseSelection = ((target[start]) || (target[start] === '0'));\r\n let _pre = '';\r\n let _aft = '';\r\n if (canUseSelection) {\r\n _pre = target['value'].substring(0, target[start]);\r\n _aft = target['value'].substring(target[end], target['value'].length);\r\n }\r\n let text = (!canUseSelection) ? clipboard : _pre + clipboard + _aft;\r\n if (target['maxLength'] && parseInt(target['maxLength'], 10) > 0) {\r\n text = text.substr(0, parseInt(target['maxLength'], 10));\r\n }\r\n target['value'] = text;\r\n target['focus']();\r\n }\r\n });\r\n }\r\n }\r\n\r\n contextMenuSelect(target) {\r\n if (target && (target['nodeName'].toUpperCase() === 'TEXTAREA' || target['nodeName'].toUpperCase() === 'INPUT')) {\r\n target['focus']();\r\n setTimeout(() => {\r\n target['select']();\r\n });\r\n }\r\n }\r\n\r\n ngOnDestroy() {\r\n if (this.intervalUpdateContractsState) {\r\n clearInterval(this.intervalUpdateContractsState);\r\n }\r\n }\r\n\r\n}\r\n","import { BrowserModule } from '@angular/platform-browser';\r\nimport { NgModule } from '@angular/core';\r\n\r\nimport { AppRoutingModule } from './app-routing.module';\r\n\r\nimport { AppComponent } from './app.component';\r\nimport { LoginComponent } from './login/login.component';\r\nimport { SettingsComponent } from './settings/settings.component';\r\nimport { SidebarComponent } from './sidebar/sidebar.component';\r\nimport { MainComponent } from './main/main.component';\r\nimport { CreateWalletComponent } from './create-wallet/create-wallet.component';\r\nimport { OpenWalletComponent } from './open-wallet/open-wallet.component';\r\nimport { RestoreWalletComponent } from './restore-wallet/restore-wallet.component';\r\nimport { SeedPhraseComponent } from './seed-phrase/seed-phrase.component';\r\nimport { WalletDetailsComponent } from './wallet-details/wallet-details.component';\r\nimport { WalletComponent } from './wallet/wallet.component';\r\nimport { SendComponent } from './send/send.component';\r\nimport { ReceiveComponent } from './receive/receive.component';\r\nimport { HistoryComponent } from './history/history.component';\r\nimport { ContractsComponent } from './contracts/contracts.component';\r\nimport { PurchaseComponent } from './purchase/purchase.component';\r\nimport { MessagesComponent } from './messages/messages.component';\r\nimport { StakingComponent } from './staking/staking.component';\r\n\r\nimport { HttpClient, HttpClientModule } from '@angular/common/http';\r\nimport { TranslateModule, TranslateLoader } from '@ngx-translate/core';\r\nimport { TranslateHttpLoader } from '@ngx-translate/http-loader';\r\nimport { FormsModule, ReactiveFormsModule } from '@angular/forms';\r\nimport { TypingMessageComponent } from './typing-message/typing-message.component';\r\n\r\nimport { BackendService } from './_helpers/services/backend.service';\r\nimport { MoneyToIntPipe } from './_helpers/pipes/money-to-int.pipe';\r\nimport { IntToMoneyPipe } from './_helpers/pipes/int-to-money.pipe';\r\nimport { StakingSwitchComponent } from './_helpers/directives/staking-switch/staking-switch.component';\r\nimport { TooltipDirective } from './_helpers/directives/tooltip.directive';\r\nimport { HistoryTypeMessagesPipe } from './_helpers/pipes/history-type-messages.pipe';\r\nimport { ContractStatusMessagesPipe } from './_helpers/pipes/contract-status-messages.pipe';\r\nimport { ContractTimeLeftPipe } from './_helpers/pipes/contract-time-left.pipe';\r\nimport { ContextMenuModule } from 'ngx-contextmenu';\r\n\r\nexport function HttpLoaderFactory(httpClient: HttpClient) {\r\n return new TranslateHttpLoader(httpClient, './assets/i18n/', '.json');\r\n}\r\n\r\n\r\nimport { ChartModule, HIGHCHARTS_MODULES, Highcharts} from 'angular-highcharts';\r\nimport { InputValidateDirective } from './_helpers/directives/input-validate/input-validate.directive';\r\nimport { ModalContainerComponent } from './_helpers/directives/modal-container/modal-container.component';\r\n// import * as more from 'highcharts/highcharts-more.src';\r\n// import * as exporting from 'highcharts/modules/exporting.src';\r\n// import * as highstock from 'highcharts/modules/stock.src';\r\n\r\nHighcharts.setOptions({\r\n // global: {\r\n // useUTC: false\r\n // }\r\n});\r\n\r\n@NgModule({\r\n declarations: [\r\n AppComponent,\r\n LoginComponent,\r\n SettingsComponent,\r\n SidebarComponent,\r\n MainComponent,\r\n CreateWalletComponent,\r\n OpenWalletComponent,\r\n RestoreWalletComponent,\r\n SeedPhraseComponent,\r\n WalletDetailsComponent,\r\n WalletComponent,\r\n SendComponent,\r\n ReceiveComponent,\r\n HistoryComponent,\r\n ContractsComponent,\r\n PurchaseComponent,\r\n MessagesComponent,\r\n StakingComponent,\r\n TypingMessageComponent,\r\n MoneyToIntPipe,\r\n IntToMoneyPipe,\r\n StakingSwitchComponent,\r\n HistoryTypeMessagesPipe,\r\n ContractStatusMessagesPipe,\r\n ContractTimeLeftPipe,\r\n TooltipDirective,\r\n InputValidateDirective,\r\n ModalContainerComponent\r\n ],\r\n imports: [\r\n BrowserModule,\r\n AppRoutingModule,\r\n HttpClientModule,\r\n TranslateModule.forRoot({\r\n loader: {\r\n provide: TranslateLoader,\r\n useFactory: HttpLoaderFactory,\r\n deps: [HttpClient]\r\n }\r\n }),\r\n FormsModule,\r\n ReactiveFormsModule,\r\n ChartModule,\r\n ContextMenuModule.forRoot()\r\n ],\r\n providers: [\r\n BackendService,\r\n MoneyToIntPipe,\r\n IntToMoneyPipe,\r\n // {provide: HIGHCHARTS_MODULES, useFactory: () => [ highstock, more, exporting ] }\r\n ],\r\n bootstrap: [AppComponent]\r\n})\r\nexport class AppModule { }\r\n","module.exports = \"
\\r\\n {{ 'CONTRACTS.EMPTY' | translate }}\\r\\n
\\r\\n\\r\\n
\\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n
{{ 'CONTRACTS.CONTRACTS' | translate }}{{ 'CONTRACTS.DATE' | translate }}{{ 'CONTRACTS.AMOUNT' | translate }}{{ 'CONTRACTS.STATUS' | translate }}{{ 'CONTRACTS.COMMENTS' | translate }}
\\r\\n
\\r\\n \\r\\n \\r\\n \\r\\n {{item.private_detailes.t}}\\r\\n
\\r\\n
{{item.timestamp * 1000 | date : 'dd-MM-yyyy HH:mm'}}{{item.private_detailes.to_pay | intToMoney}} {{variablesService.defaultCurrency}}\\r\\n
\\r\\n {{item | contractStatusMessages}}\\r\\n
\\r\\n
\\r\\n
\\r\\n {{item.private_detailes.c}}\\r\\n
\\r\\n
\\r\\n
\\r\\n\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n\"","module.exports = \":host {\\n width: 100%; }\\n\\n.empty-contracts {\\n font-size: 1.5rem; }\\n\\n.wrap-table {\\n margin: -3rem -3rem 0 -3rem;\\n overflow-x: auto; }\\n\\n.wrap-table .contract {\\n position: relative;\\n display: flex;\\n align-items: center; }\\n\\n.wrap-table .contract .icon {\\n flex-shrink: 0; }\\n\\n.wrap-table .contract .icon.new, .wrap-table .contract .icon.alert {\\n position: absolute;\\n top: 0; }\\n\\n.wrap-table .contract .icon.new {\\n left: -2.3rem;\\n -webkit-mask: url('new.svg') no-repeat center;\\n mask: url('new.svg') no-repeat center;\\n width: 1.7rem;\\n height: 1.7rem; }\\n\\n.wrap-table .contract .icon.alert {\\n top: 0.2rem;\\n left: -2.1rem;\\n -webkit-mask: url('alert.svg') no-repeat center;\\n mask: url('alert.svg') no-repeat center;\\n width: 1.2rem;\\n height: 1.2rem; }\\n\\n.wrap-table .contract .icon.purchase, .wrap-table .contract .icon.sell {\\n margin-right: 1rem;\\n width: 1.5rem;\\n height: 1.5rem; }\\n\\n.wrap-table .contract .icon.purchase {\\n -webkit-mask: url('purchase.svg') no-repeat center;\\n mask: url('purchase.svg') no-repeat center; }\\n\\n.wrap-table .contract .icon.sell {\\n -webkit-mask: url('sell.svg') no-repeat center;\\n mask: url('sell.svg') no-repeat center; }\\n\\n.wrap-table .contract span {\\n text-overflow: ellipsis;\\n overflow: hidden;\\n max-width: 20vw; }\\n\\n.wrap-table .status, .wrap-table .comment {\\n text-overflow: ellipsis;\\n overflow: hidden;\\n max-width: 20vw; }\\n\\n.contracts-buttons {\\n display: flex;\\n margin: 3rem 0;\\n width: 50%; }\\n\\n.contracts-buttons button {\\n flex: 0 1 50%;\\n margin-right: 1.5rem; }\\n\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvY29udHJhY3RzL0Q6XFx6YW5vL3NyY1xcYXBwXFxjb250cmFjdHNcXGNvbnRyYWN0cy5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLFlBQVcsRUFDWjs7QUFFRDtFQUNFLGtCQUFpQixFQUNsQjs7QUFFRDtFQUNFLDRCQUEyQjtFQUMzQixpQkFBZ0IsRUF5RGpCOztBQTNERDtJQUtJLG1CQUFrQjtJQUNsQixjQUFhO0lBQ2Isb0JBQW1CLEVBNkNwQjs7QUFwREg7TUFVTSxlQUFjLEVBbUNmOztBQTdDTDtRQWFRLG1CQUFrQjtRQUNsQixPQUFNLEVBQ1A7O0FBZlA7UUFrQlEsY0FBYTtRQUNiLDhDQUFzRDtnQkFBdEQsc0NBQXNEO1FBQ3RELGNBQWE7UUFDYixlQUFjLEVBQ2Y7O0FBdEJQO1FBeUJRLFlBQVc7UUFDWCxjQUFhO1FBQ2IsZ0RBQXdEO2dCQUF4RCx3Q0FBd0Q7UUFDeEQsY0FBYTtRQUNiLGVBQWMsRUFDZjs7QUE5QlA7UUFpQ1EsbUJBQWtCO1FBQ2xCLGNBQWE7UUFDYixlQUFjLEVBQ2Y7O0FBcENQO1FBdUNRLG1EQUEyRDtnQkFBM0QsMkNBQTJELEVBQzVEOztBQXhDUDtRQTJDUSwrQ0FBdUQ7Z0JBQXZELHVDQUF1RCxFQUN4RDs7QUE1Q1A7TUFnRE0sd0JBQXVCO01BQ3ZCLGlCQUFnQjtNQUNoQixnQkFBZSxFQUNoQjs7QUFuREw7SUF1REksd0JBQXVCO0lBQ3ZCLGlCQUFnQjtJQUNoQixnQkFBZSxFQUNoQjs7QUFHSDtFQUNFLGNBQWE7RUFDYixlQUFjO0VBQ2QsV0FBVSxFQU1YOztBQVREO0lBTUksY0FBYTtJQUNiLHFCQUFvQixFQUNyQiIsImZpbGUiOiJzcmMvYXBwL2NvbnRyYWN0cy9jb250cmFjdHMuY29tcG9uZW50LnNjc3MiLCJzb3VyY2VzQ29udGVudCI6WyI6aG9zdCB7XHJcbiAgd2lkdGg6IDEwMCU7XHJcbn1cclxuXHJcbi5lbXB0eS1jb250cmFjdHMge1xyXG4gIGZvbnQtc2l6ZTogMS41cmVtO1xyXG59XHJcblxyXG4ud3JhcC10YWJsZSB7XHJcbiAgbWFyZ2luOiAtM3JlbSAtM3JlbSAwIC0zcmVtO1xyXG4gIG92ZXJmbG93LXg6IGF1dG87XHJcblxyXG4gIC5jb250cmFjdCB7XHJcbiAgICBwb3NpdGlvbjogcmVsYXRpdmU7XHJcbiAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuXHJcbiAgICAuaWNvbiB7XHJcbiAgICAgIGZsZXgtc2hyaW5rOiAwO1xyXG5cclxuICAgICAgJi5uZXcsICYuYWxlcnQge1xyXG4gICAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcclxuICAgICAgICB0b3A6IDA7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICYubmV3IHtcclxuICAgICAgICBsZWZ0OiAtMi4zcmVtO1xyXG4gICAgICAgIG1hc2s6IHVybCguLi8uLi9hc3NldHMvaWNvbnMvbmV3LnN2Zykgbm8tcmVwZWF0IGNlbnRlcjtcclxuICAgICAgICB3aWR0aDogMS43cmVtO1xyXG4gICAgICAgIGhlaWdodDogMS43cmVtO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAmLmFsZXJ0IHtcclxuICAgICAgICB0b3A6IDAuMnJlbTtcclxuICAgICAgICBsZWZ0OiAtMi4xcmVtO1xyXG4gICAgICAgIG1hc2s6IHVybCguLi8uLi9hc3NldHMvaWNvbnMvYWxlcnQuc3ZnKSBuby1yZXBlYXQgY2VudGVyO1xyXG4gICAgICAgIHdpZHRoOiAxLjJyZW07XHJcbiAgICAgICAgaGVpZ2h0OiAxLjJyZW07XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICYucHVyY2hhc2UsICYuc2VsbCB7XHJcbiAgICAgICAgbWFyZ2luLXJpZ2h0OiAxcmVtO1xyXG4gICAgICAgIHdpZHRoOiAxLjVyZW07XHJcbiAgICAgICAgaGVpZ2h0OiAxLjVyZW07XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICYucHVyY2hhc2Uge1xyXG4gICAgICAgIG1hc2s6IHVybCguLi8uLi9hc3NldHMvaWNvbnMvcHVyY2hhc2Uuc3ZnKSBuby1yZXBlYXQgY2VudGVyO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAmLnNlbGwge1xyXG4gICAgICAgIG1hc2s6IHVybCguLi8uLi9hc3NldHMvaWNvbnMvc2VsbC5zdmcpIG5vLXJlcGVhdCBjZW50ZXI7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBzcGFuIHtcclxuICAgICAgdGV4dC1vdmVyZmxvdzogZWxsaXBzaXM7XHJcbiAgICAgIG92ZXJmbG93OiBoaWRkZW47XHJcbiAgICAgIG1heC13aWR0aDogMjB2dztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC5zdGF0dXMsIC5jb21tZW50IHtcclxuICAgIHRleHQtb3ZlcmZsb3c6IGVsbGlwc2lzO1xyXG4gICAgb3ZlcmZsb3c6IGhpZGRlbjtcclxuICAgIG1heC13aWR0aDogMjB2dztcclxuICB9XHJcbn1cclxuXHJcbi5jb250cmFjdHMtYnV0dG9ucyB7XHJcbiAgZGlzcGxheTogZmxleDtcclxuICBtYXJnaW46IDNyZW0gMDtcclxuICB3aWR0aDogNTAlO1xyXG5cclxuICBidXR0b24ge1xyXG4gICAgZmxleDogMCAxIDUwJTtcclxuICAgIG1hcmdpbi1yaWdodDogMS41cmVtO1xyXG4gIH1cclxufVxyXG4iXX0= */\"","import {Component, OnInit, OnDestroy} from '@angular/core';\r\nimport {ActivatedRoute, Router} from '@angular/router';\r\nimport {VariablesService} from '../_helpers/services/variables.service';\r\n\r\n@Component({\r\n selector: 'app-contracts',\r\n templateUrl: './contracts.component.html',\r\n styleUrls: ['./contracts.component.scss']\r\n})\r\nexport class ContractsComponent implements OnInit, OnDestroy {\r\n\r\n parentRouting;\r\n walletId;\r\n\r\n constructor(\r\n private route: ActivatedRoute,\r\n private router: Router,\r\n private variablesService: VariablesService\r\n ) {}\r\n\r\n ngOnInit() {\r\n this.parentRouting = this.route.parent.params.subscribe(params => {\r\n if (params.hasOwnProperty('id')) {\r\n this.walletId = params['id'];\r\n }\r\n });\r\n }\r\n\r\n ngOnDestroy() {\r\n this.parentRouting.unsubscribe();\r\n }\r\n\r\n}\r\n","module.exports = \"
\\r\\n\\r\\n
\\r\\n
\\r\\n {{ 'BREADCRUMBS.ADD_WALLET' | translate }}\\r\\n {{ 'BREADCRUMBS.CREATE_WALLET' | translate }}\\r\\n
\\r\\n \\r\\n \\r\\n {{ 'COMMON.BACK' | translate }}\\r\\n \\r\\n
\\r\\n\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n
\\r\\n Name is required.\\r\\n
\\r\\n
\\r\\n Name is duplicate.\\r\\n
\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n
\\r\\n Confirm password not match.\\r\\n
\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n\\r\\n
\\r\\n\"","module.exports = \".form-create {\\n margin: 2.4rem 0;\\n width: 50%; }\\n .form-create .wrap-buttons {\\n display: flex;\\n margin: 2.5rem -0.7rem; }\\n .form-create .wrap-buttons button {\\n margin: 0 0.7rem; }\\n .form-create .wrap-buttons button.transparent-button {\\n flex-basis: 50%; }\\n .form-create .wrap-buttons button.select-button {\\n flex-basis: 60%; }\\n .form-create .wrap-buttons button.create-button {\\n flex: 1 1 50%; }\\n\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvY3JlYXRlLXdhbGxldC9EOlxcemFuby9zcmNcXGFwcFxcY3JlYXRlLXdhbGxldFxcY3JlYXRlLXdhbGxldC5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLGlCQUFnQjtFQUNoQixXQUFVLEVBc0JYO0VBeEJEO0lBS0ksY0FBYTtJQUNiLHVCQUFzQixFQWlCdkI7RUF2Qkg7TUFTTSxpQkFBZ0IsRUFhakI7RUF0Qkw7UUFZUSxnQkFBZSxFQUNoQjtFQWJQO1FBZ0JRLGdCQUFlLEVBQ2hCO0VBakJQO1FBb0JRLGNBQWEsRUFDZCIsImZpbGUiOiJzcmMvYXBwL2NyZWF0ZS13YWxsZXQvY3JlYXRlLXdhbGxldC5jb21wb25lbnQuc2NzcyIsInNvdXJjZXNDb250ZW50IjpbIi5mb3JtLWNyZWF0ZSB7XHJcbiAgbWFyZ2luOiAyLjRyZW0gMDtcclxuICB3aWR0aDogNTAlO1xyXG5cclxuICAud3JhcC1idXR0b25zIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBtYXJnaW46IDIuNXJlbSAtMC43cmVtO1xyXG5cclxuICAgIGJ1dHRvbiB7XHJcbiAgICAgIG1hcmdpbjogMCAwLjdyZW07XHJcblxyXG4gICAgICAmLnRyYW5zcGFyZW50LWJ1dHRvbiB7XHJcbiAgICAgICAgZmxleC1iYXNpczogNTAlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAmLnNlbGVjdC1idXR0b24ge1xyXG4gICAgICAgIGZsZXgtYmFzaXM6IDYwJTtcclxuICAgICAgfVxyXG5cclxuICAgICAgJi5jcmVhdGUtYnV0dG9uIHtcclxuICAgICAgICBmbGV4OiAxIDEgNTAlO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcbiJdfQ== */\"","import {Component, NgZone, OnInit} from '@angular/core';\r\nimport {FormGroup, FormControl, Validators} from '@angular/forms';\r\nimport {BackendService} from '../_helpers/services/backend.service';\r\nimport {VariablesService} from '../_helpers/services/variables.service';\r\nimport {Router} from '@angular/router';\r\nimport {Wallet} from '../_helpers/models/wallet.model';\r\n\r\n@Component({\r\n selector: 'app-create-wallet',\r\n templateUrl: './create-wallet.component.html',\r\n styleUrls: ['./create-wallet.component.scss']\r\n})\r\nexport class CreateWalletComponent implements OnInit {\r\n\r\n createForm = new FormGroup({\r\n name: new FormControl('', [Validators.required, (g: FormControl) => {\r\n for (let i = 0; i < this.variablesService.wallets.length; i++) {\r\n if (g.value === this.variablesService.wallets[i].name) {\r\n return {'duplicate': true};\r\n }\r\n }\r\n return null;\r\n }]),\r\n password: new FormControl(''),\r\n confirm: new FormControl('')\r\n }, function (g: FormGroup) {\r\n return g.get('password').value === g.get('confirm').value ? null : {'confirm_mismatch': true};\r\n });\r\n\r\n wallet = {\r\n id: ''\r\n };\r\n\r\n walletSaved = false;\r\n\r\n constructor(\r\n private router: Router,\r\n private backend: BackendService,\r\n private variablesService: VariablesService,\r\n private ngZone: NgZone\r\n ) {\r\n }\r\n\r\n ngOnInit() {\r\n }\r\n\r\n createWallet() {\r\n this.router.navigate(['/seed-phrase'], {queryParams: {wallet_id: this.wallet.id}});\r\n }\r\n\r\n saveWallet() {\r\n if (this.createForm.valid) {\r\n this.backend.saveFileDialog('Save the wallet file.', '*', this.variablesService.settings.default_path, (file_status, file_data) => {\r\n if (file_status) {\r\n this.variablesService.settings.default_path = file_data.path.substr(0, file_data.path.lastIndexOf('/'));\r\n this.backend.generateWallet(file_data.path, this.createForm.get('password').value, (generate_status, generate_data, errorCode) => {\r\n if (generate_status) {\r\n this.wallet.id = generate_data.wallet_id;\r\n this.variablesService.opening_wallet = new Wallet(\r\n generate_data.wallet_id,\r\n this.createForm.get('name').value,\r\n this.createForm.get('password').value,\r\n generate_data['wi'].path,\r\n generate_data['wi'].address,\r\n generate_data['wi'].balance,\r\n generate_data['wi'].unlocked_balance,\r\n generate_data['wi'].mined_total,\r\n generate_data['wi'].tracking_hey\r\n );\r\n this.ngZone.run(() => {\r\n this.walletSaved = true;\r\n });\r\n } else {\r\n if (errorCode && errorCode === 'ALREADY_EXISTS') {\r\n alert('You cannot record a file on top of another file');\r\n } else {\r\n alert('You cannot save a safe file to the system partition');\r\n }\r\n }\r\n });\r\n }\r\n });\r\n }\r\n }\r\n\r\n}\r\n","module.exports = \"
\\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n
{{ 'HISTORY.STATUS' | translate }}{{ 'HISTORY.DATE' | translate }}{{ 'HISTORY.AMOUNT' | translate }}{{ 'HISTORY.FEE' | translate }}{{ 'HISTORY.ADDRESS' | translate }}
\\r\\n
\\r\\n
\\r\\n
\\r\\n
\\r\\n \\r\\n {{ (item.is_income ? 'HISTORY.RECEIVED' : 'HISTORY.SEND') | translate }}\\r\\n
\\r\\n
{{item.timestamp * 1000 | date : 'dd-MM-yyyy HH:mm'}}{{item.sortAmount | intToMoney}} {{variablesService.defaultCurrency}}\\r\\n {{item.sortFee | intToMoney}} {{variablesService.defaultCurrency}}\\r\\n \\r\\n {{item | historyTypeMessages}}\\r\\n
\\r\\n
\\r\\n\"","module.exports = \":host {\\n width: 100%; }\\n\\n.wrap-table {\\n margin: -3rem; }\\n\\n.wrap-table table tbody tr .status {\\n position: relative;\\n display: flex;\\n align-items: center; }\\n\\n.wrap-table table tbody tr .status .confirmation {\\n position: absolute;\\n top: 50%;\\n left: -2rem;\\n -webkit-transform: translateY(-50%);\\n transform: translateY(-50%);\\n display: flex;\\n align-items: flex-end;\\n width: 0.7rem;\\n height: 1.5rem; }\\n\\n.wrap-table table tbody tr .status .confirmation .fill {\\n width: 100%; }\\n\\n.wrap-table table tbody tr .status .icon {\\n margin-right: 1rem;\\n width: 1.7rem;\\n height: 1.7rem; }\\n\\n.wrap-table table tbody tr .status.send .icon {\\n -webkit-mask: url('send.svg') no-repeat center;\\n mask: url('send.svg') no-repeat center; }\\n\\n.wrap-table table tbody tr .status.received .icon {\\n -webkit-mask: url('receive.svg') no-repeat center;\\n mask: url('receive.svg') no-repeat center; }\\n\\n.wrap-table table tbody tr .remote-address {\\n overflow: hidden;\\n text-overflow: ellipsis;\\n max-width: 25vw; }\\n\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvaGlzdG9yeS9EOlxcemFuby9zcmNcXGFwcFxcaGlzdG9yeVxcaGlzdG9yeS5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLFlBQVcsRUFDWjs7QUFFRDtFQUNFLGNBQWEsRUF5RGQ7O0FBMUREO0lBVVUsbUJBQWtCO0lBQ2xCLGNBQWE7SUFDYixvQkFBbUIsRUFvQ3BCOztBQWhEVDtNQWVZLG1CQUFrQjtNQUNsQixTQUFRO01BQ1IsWUFBVztNQUNYLG9DQUEyQjtjQUEzQiw0QkFBMkI7TUFDM0IsY0FBYTtNQUNiLHNCQUFxQjtNQUNyQixjQUFhO01BQ2IsZUFBYyxFQUtmOztBQTNCWDtRQXlCYyxZQUFXLEVBQ1o7O0FBMUJiO01BOEJZLG1CQUFrQjtNQUNsQixjQUFhO01BQ2IsZUFBYyxFQUNmOztBQWpDWDtNQXNDYywrQ0FBdUQ7Y0FBdkQsdUNBQXVELEVBQ3hEOztBQXZDYjtNQTZDYyxrREFBMEQ7Y0FBMUQsMENBQTBELEVBQzNEOztBQTlDYjtJQW1EVSxpQkFBZ0I7SUFDaEIsd0JBQXVCO0lBQ3ZCLGdCQUFlLEVBQ2hCIiwiZmlsZSI6InNyYy9hcHAvaGlzdG9yeS9oaXN0b3J5LmNvbXBvbmVudC5zY3NzIiwic291cmNlc0NvbnRlbnQiOlsiOmhvc3Qge1xyXG4gIHdpZHRoOiAxMDAlO1xyXG59XHJcblxyXG4ud3JhcC10YWJsZSB7XHJcbiAgbWFyZ2luOiAtM3JlbTtcclxuXHJcbiAgdGFibGUge1xyXG5cclxuICAgIHRib2R5IHtcclxuXHJcbiAgICAgIHRyIHtcclxuXHJcbiAgICAgICAgLnN0YXR1cyB7XHJcbiAgICAgICAgICBwb3NpdGlvbjogcmVsYXRpdmU7XHJcbiAgICAgICAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuXHJcbiAgICAgICAgICAuY29uZmlybWF0aW9uIHtcclxuICAgICAgICAgICAgcG9zaXRpb246IGFic29sdXRlO1xyXG4gICAgICAgICAgICB0b3A6IDUwJTtcclxuICAgICAgICAgICAgbGVmdDogLTJyZW07XHJcbiAgICAgICAgICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlWSgtNTAlKTtcclxuICAgICAgICAgICAgZGlzcGxheTogZmxleDtcclxuICAgICAgICAgICAgYWxpZ24taXRlbXM6IGZsZXgtZW5kO1xyXG4gICAgICAgICAgICB3aWR0aDogMC43cmVtO1xyXG4gICAgICAgICAgICBoZWlnaHQ6IDEuNXJlbTtcclxuXHJcbiAgICAgICAgICAgIC5maWxsIHtcclxuICAgICAgICAgICAgICB3aWR0aDogMTAwJTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIC5pY29uIHtcclxuICAgICAgICAgICAgbWFyZ2luLXJpZ2h0OiAxcmVtO1xyXG4gICAgICAgICAgICB3aWR0aDogMS43cmVtO1xyXG4gICAgICAgICAgICBoZWlnaHQ6IDEuN3JlbTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAmLnNlbmQgIHtcclxuXHJcbiAgICAgICAgICAgIC5pY29uIHtcclxuICAgICAgICAgICAgICBtYXNrOiB1cmwoLi4vLi4vYXNzZXRzL2ljb25zL3NlbmQuc3ZnKSBuby1yZXBlYXQgY2VudGVyO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgJi5yZWNlaXZlZCB7XHJcblxyXG4gICAgICAgICAgICAuaWNvbiB7XHJcbiAgICAgICAgICAgICAgbWFzazogdXJsKC4uLy4uL2Fzc2V0cy9pY29ucy9yZWNlaXZlLnN2Zykgbm8tcmVwZWF0IGNlbnRlcjtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLnJlbW90ZS1hZGRyZXNzIHtcclxuICAgICAgICAgIG92ZXJmbG93OiBoaWRkZW47XHJcbiAgICAgICAgICB0ZXh0LW92ZXJmbG93OiBlbGxpcHNpcztcclxuICAgICAgICAgIG1heC13aWR0aDogMjV2dztcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbn1cclxuIl19 */\"","import {Component, OnInit, OnDestroy} from '@angular/core';\r\nimport {ActivatedRoute} from '@angular/router';\r\nimport {BackendService} from '../_helpers/services/backend.service';\r\nimport {VariablesService} from '../_helpers/services/variables.service';\r\n\r\n@Component({\r\n selector: 'app-history',\r\n templateUrl: './history.component.html',\r\n styleUrls: ['./history.component.scss']\r\n})\r\nexport class HistoryComponent implements OnInit, OnDestroy {\r\n parentRouting;\r\n\r\n constructor(\r\n private route: ActivatedRoute,\r\n private backend: BackendService,\r\n private variablesService: VariablesService\r\n ) {\r\n }\r\n\r\n ngOnInit() {\r\n this.parentRouting = this.route.parent.params.subscribe(() => {\r\n console.log(this.variablesService.currentWallet.history);\r\n });\r\n }\r\n\r\n getHeight(item) {\r\n if ((this.variablesService.height_app - item.height >= 10 && item.height !== 0) || (item.is_mining === true && item.height === 0)) {\r\n return 100;\r\n } else {\r\n if (item.height === 0 || this.variablesService.height_app - item.height < 0) {\r\n return 0;\r\n } else {\r\n return (this.variablesService.height_app - item.height) * 10;\r\n }\r\n }\r\n }\r\n\r\n ngOnDestroy() {\r\n this.parentRouting.unsubscribe();\r\n }\r\n\r\n}\r\n","module.exports = \"
\\r\\n
\\r\\n\\r\\n
\\r\\n\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n
\\r\\n Password is required.\\r\\n
\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n
\\r\\n Confirmation is required.\\r\\n
\\r\\n
\\r\\n
\\r\\n
\\r\\n Mismatch.\\r\\n
\\r\\n
\\r\\n \\r\\n
\\r\\n\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n
\\r\\n Password is required.\\r\\n
\\r\\n
\\r\\n \\r\\n
\\r\\n\\r\\n
\\r\\n
\\r\\n\"","module.exports = \":host {\\n position: fixed;\\n top: 0;\\n left: 0;\\n width: 100%;\\n height: 100%; }\\n :host .content {\\n display: flex; }\\n :host .content .wrap-login {\\n margin: auto;\\n width: 100%;\\n max-width: 40rem; }\\n :host .content .wrap-login .logo {\\n background: url('logo.png') no-repeat center top;\\n width: 100%;\\n height: 14rem; }\\n :host .content .wrap-login .form-login {\\n display: flex;\\n flex-direction: column; }\\n :host .content .wrap-login .form-login button {\\n margin: 2.5rem auto;\\n width: 100%;\\n max-width: 15rem; }\\n\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvbG9naW4vRDpcXHphbm8vc3JjXFxhcHBcXGxvZ2luXFxsb2dpbi5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLGdCQUFlO0VBQ2YsT0FBTTtFQUNOLFFBQU87RUFDUCxZQUFXO0VBQ1gsYUFBWSxFQTRCYjtFQWpDRDtJQVFJLGNBQWEsRUF3QmQ7RUFoQ0g7TUFXTSxhQUFZO01BQ1osWUFBVztNQUNYLGlCQUFnQixFQWtCakI7RUEvQkw7UUFnQlEsaURBQW9FO1FBQ3BFLFlBQVc7UUFDWCxjQUFhLEVBQ2Q7RUFuQlA7UUFzQlEsY0FBYTtRQUNiLHVCQUFzQixFQU92QjtFQTlCUDtVQTBCVSxvQkFBbUI7VUFDbkIsWUFBVztVQUNYLGlCQUFnQixFQUNqQiIsImZpbGUiOiJzcmMvYXBwL2xvZ2luL2xvZ2luLmNvbXBvbmVudC5zY3NzIiwic291cmNlc0NvbnRlbnQiOlsiOmhvc3Qge1xyXG4gIHBvc2l0aW9uOiBmaXhlZDtcclxuICB0b3A6IDA7XHJcbiAgbGVmdDogMDtcclxuICB3aWR0aDogMTAwJTtcclxuICBoZWlnaHQ6IDEwMCU7XHJcblxyXG4gIC5jb250ZW50IHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcblxyXG4gICAgLndyYXAtbG9naW4ge1xyXG4gICAgICBtYXJnaW46IGF1dG87XHJcbiAgICAgIHdpZHRoOiAxMDAlO1xyXG4gICAgICBtYXgtd2lkdGg6IDQwcmVtO1xyXG5cclxuICAgICAgLmxvZ28ge1xyXG4gICAgICAgIGJhY2tncm91bmQ6IHVybChcIi4uLy4uL2Fzc2V0cy9pbWFnZXMvbG9nby5wbmdcIikgbm8tcmVwZWF0IGNlbnRlciB0b3A7XHJcbiAgICAgICAgd2lkdGg6IDEwMCU7XHJcbiAgICAgICAgaGVpZ2h0OiAxNHJlbTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLmZvcm0tbG9naW4ge1xyXG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICAgICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuXHJcbiAgICAgICAgYnV0dG9uIHtcclxuICAgICAgICAgIG1hcmdpbjogMi41cmVtIGF1dG87XHJcbiAgICAgICAgICB3aWR0aDogMTAwJTtcclxuICAgICAgICAgIG1heC13aWR0aDogMTVyZW07XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcbiJdfQ== */\"","import {Component, NgZone, OnInit} from '@angular/core';\r\nimport {FormGroup, FormControl, Validators} from '@angular/forms';\r\nimport {ActivatedRoute, Router} from '@angular/router';\r\nimport {BackendService} from '../_helpers/services/backend.service';\r\nimport {VariablesService} from '../_helpers/services/variables.service';\r\nimport {Wallet} from '../_helpers/models/wallet.model';\r\n\r\n@Component({\r\n selector: 'app-login',\r\n templateUrl: './login.component.html',\r\n styleUrls: ['./login.component.scss']\r\n})\r\nexport class LoginComponent implements OnInit {\r\n\r\n regForm = new FormGroup({\r\n password: new FormControl('', Validators.required),\r\n confirmation: new FormControl('', Validators.required)\r\n }, function (g: FormGroup) {\r\n return g.get('password').value === g.get('confirmation').value ? null : {'mismatch': true};\r\n });\r\n\r\n authForm = new FormGroup({\r\n password: new FormControl('', Validators.required)\r\n });\r\n\r\n type = 'reg';\r\n\r\n constructor(\r\n private route: ActivatedRoute,\r\n private router: Router,\r\n private backend: BackendService,\r\n private variablesService: VariablesService,\r\n private ngZone: NgZone\r\n ) {\r\n }\r\n\r\n ngOnInit() {\r\n this.route.queryParams.subscribe(params => {\r\n if (params.type) {\r\n this.type = params.type;\r\n }\r\n });\r\n }\r\n\r\n onSubmitCreatePass(): void {\r\n if (this.regForm.valid) {\r\n this.variablesService.appPass = this.regForm.get('password').value;\r\n this.backend.storeSecureAppData((status, data) => {\r\n if (status) {\r\n this.ngZone.run(() => {\r\n this.router.navigate(['/']);\r\n });\r\n } else {\r\n // TODO error sign in\r\n console.log(data['error_code']);\r\n }\r\n });\r\n }\r\n }\r\n\r\n onSubmitAuthPass(): void {\r\n if (this.authForm.valid) {\r\n const appPass = this.authForm.get('password').value;\r\n this.backend.getSecureAppData({pass: appPass}, (status, data) => {\r\n if (data.error_code && data.error_code === 'WRONG_PASSWORD') {\r\n // TODO error log in informer.error('MESSAGE.INCORRECT_PASSWORD');\r\n console.log('WRONG_PASSWORD');\r\n } else {\r\n this.variablesService.startCountdown();\r\n this.variablesService.appPass = appPass;\r\n if (this.variablesService.wallets.length) {\r\n this.ngZone.run(() => {\r\n this.router.navigate(['/wallet/' + this.variablesService.wallets[0].wallet_id]);\r\n });\r\n return;\r\n }\r\n if (Object.keys(data).length !== 0) {\r\n let openWallets = 0;\r\n let runWallets = 0;\r\n data.forEach((wallet, wallet_index) => {\r\n this.backend.openWallet(wallet.path, wallet.pass, true, (open_status, open_data) => {\r\n if (open_status) {\r\n openWallets++;\r\n this.backend.runWallet(open_data.wallet_id, (run_status) => {\r\n if (run_status) {\r\n runWallets++;\r\n this.ngZone.run(() => {\r\n const new_wallet = new Wallet(\r\n open_data.wallet_id,\r\n wallet.name,\r\n wallet.pass,\r\n open_data['wi'].path,\r\n open_data['wi'].address,\r\n open_data['wi'].balance,\r\n open_data['wi'].unlocked_balance,\r\n open_data['wi'].mined_total,\r\n open_data['wi'].tracking_hey\r\n );\r\n if (open_data.recent_history && open_data.recent_history.history) {\r\n new_wallet.prepareHistory(open_data.recent_history.history);\r\n }\r\n this.backend.getContracts(open_data.wallet_id, (contracts_status, contracts_data) => {\r\n if (contracts_status && contracts_data.hasOwnProperty('contracts')) {\r\n this.ngZone.run(() => {\r\n new_wallet.prepareContractsAfterOpen(contracts_data.contracts, this.variablesService.exp_med_ts, this.variablesService.height_app, this.variablesService.settings.viewedContracts, this.variablesService.settings.notViewedContracts);\r\n });\r\n }\r\n });\r\n\r\n this.variablesService.wallets.push(new_wallet);\r\n if (this.variablesService.wallets.length === 1) {\r\n this.router.navigate(['/wallet/' + this.variablesService.wallets[0].wallet_id]);\r\n }\r\n });\r\n } else {\r\n if (wallet_index === data.length - 1 && runWallets === 0) {\r\n this.ngZone.run(() => {\r\n this.router.navigate(['/']);\r\n });\r\n }\r\n // console.log(run_data['error_code']);\r\n }\r\n });\r\n } else {\r\n if (wallet_index === data.length - 1 && openWallets === 0) {\r\n this.ngZone.run(() => {\r\n this.router.navigate(['/']);\r\n });\r\n }\r\n }\r\n });\r\n });\r\n } else {\r\n this.ngZone.run(() => {\r\n this.router.navigate(['/']);\r\n });\r\n }\r\n }\r\n });\r\n }\r\n }\r\n}\r\n","module.exports = \"
\\r\\n
\\r\\n

{{ 'MAIN.TITLE' | translate }}

\\r\\n
\\r\\n \\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n {{ 'MAIN.HELP' | translate }}\\r\\n
\\r\\n
\\r\\n
\\r\\n\"","module.exports = \":host {\\n flex: 1 0 auto;\\n padding: 3rem; }\\n\\n.content {\\n padding: 3rem;\\n min-height: 100%; }\\n\\n.add-wallet .add-wallet-title {\\n margin-bottom: 1rem; }\\n\\n.add-wallet .add-wallet-buttons {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n margin: 0 -0.5rem;\\n padding: 1.5rem 0; }\\n\\n.add-wallet .add-wallet-buttons button {\\n flex: 1 0 auto;\\n margin: 0 0.5rem; }\\n\\n.add-wallet .add-wallet-help {\\n display: flex;\\n font-size: 1.3rem;\\n line-height: 1.4rem; }\\n\\n.add-wallet .add-wallet-help .icon {\\n -webkit-mask: url('howto.svg') no-repeat center;\\n mask: url('howto.svg') no-repeat center;\\n margin-right: 0.8rem;\\n width: 1.4rem;\\n height: 1.4rem; }\\n\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvbWFpbi9EOlxcemFuby9zcmNcXGFwcFxcbWFpblxcbWFpbi5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLGVBQWM7RUFDZCxjQUFhLEVBQ2Q7O0FBRUQ7RUFDRSxjQUFhO0VBQ2IsaUJBQWdCLEVBQ2pCOztBQUVEO0VBR0ksb0JBQW1CLEVBQ3BCOztBQUpIO0VBT0ksY0FBYTtFQUNiLG9CQUFtQjtFQUNuQiwrQkFBOEI7RUFDOUIsa0JBQWlCO0VBQ2pCLGtCQUFpQixFQU1sQjs7QUFqQkg7SUFjTSxlQUFjO0lBQ2QsaUJBQWdCLEVBQ2pCOztBQWhCTDtFQW9CSSxjQUFhO0VBQ2Isa0JBQWlCO0VBQ2pCLG9CQUFtQixFQVFwQjs7QUE5Qkg7SUF5Qk0sZ0RBQXdEO1lBQXhELHdDQUF3RDtJQUN4RCxxQkFBb0I7SUFDcEIsY0FBYTtJQUNiLGVBQWMsRUFDZiIsImZpbGUiOiJzcmMvYXBwL21haW4vbWFpbi5jb21wb25lbnQuc2NzcyIsInNvdXJjZXNDb250ZW50IjpbIjpob3N0IHtcclxuICBmbGV4OiAxIDAgYXV0bztcclxuICBwYWRkaW5nOiAzcmVtO1xyXG59XHJcblxyXG4uY29udGVudCB7XHJcbiAgcGFkZGluZzogM3JlbTtcclxuICBtaW4taGVpZ2h0OiAxMDAlO1xyXG59XHJcblxyXG4uYWRkLXdhbGxldCB7XHJcblxyXG4gIC5hZGQtd2FsbGV0LXRpdGxlIHtcclxuICAgIG1hcmdpbi1ib3R0b206IDFyZW07XHJcbiAgfVxyXG5cclxuICAuYWRkLXdhbGxldC1idXR0b25zIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xyXG4gICAgbWFyZ2luOiAwIC0wLjVyZW07XHJcbiAgICBwYWRkaW5nOiAxLjVyZW0gMDtcclxuXHJcbiAgICBidXR0b24ge1xyXG4gICAgICBmbGV4OiAxIDAgYXV0bztcclxuICAgICAgbWFyZ2luOiAwIDAuNXJlbTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC5hZGQtd2FsbGV0LWhlbHAge1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuICAgIGZvbnQtc2l6ZTogMS4zcmVtO1xyXG4gICAgbGluZS1oZWlnaHQ6IDEuNHJlbTtcclxuXHJcbiAgICAuaWNvbiB7XHJcbiAgICAgIG1hc2s6IHVybCguLi8uLi9hc3NldHMvaWNvbnMvaG93dG8uc3ZnKSBuby1yZXBlYXQgY2VudGVyO1xyXG4gICAgICBtYXJnaW4tcmlnaHQ6IDAuOHJlbTtcclxuICAgICAgd2lkdGg6IDEuNHJlbTtcclxuICAgICAgaGVpZ2h0OiAxLjRyZW07XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcbiJdfQ== */\"","import {Component, NgZone, OnInit} from '@angular/core';\r\nimport {BackendService} from '../_helpers/services/backend.service';\r\nimport {VariablesService} from '../_helpers/services/variables.service';\r\nimport {Router} from '@angular/router';\r\n\r\n@Component({\r\n selector: 'app-main',\r\n templateUrl: './main.component.html',\r\n styleUrls: ['./main.component.scss']\r\n})\r\nexport class MainComponent implements OnInit {\r\n\r\n constructor(\r\n private router: Router,\r\n private backend: BackendService,\r\n private variablesService: VariablesService,\r\n private ngZone: NgZone\r\n ) {}\r\n\r\n ngOnInit() {}\r\n\r\n openWallet() {\r\n this.backend.openFileDialog('Open the wallet file.', '*', this.variablesService.settings.default_path, (file_status, file_data) => {\r\n if (file_status) {\r\n this.variablesService.settings.default_path = file_data.path.substr(0, file_data.path.lastIndexOf('/'));\r\n this.ngZone.run(() => {\r\n this.router.navigate(['/open'], {queryParams: {path: file_data.path}});\r\n });\r\n } else {\r\n console.log(file_data['error_code']);\r\n }\r\n });\r\n }\r\n\r\n}\r\n","module.exports = \"
\\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n
{{ 'MESSAGES.ADDRESS' | translate }}{{ 'MESSAGES.MESSAGE' | translate }}
\\r\\n {{message.address}}\\r\\n \\r\\n \\r\\n {{message.message}}\\r\\n
\\r\\n
\\r\\n\"","module.exports = \":host {\\n width: 100%; }\\n\\n.wrap-table {\\n margin: -3rem; }\\n\\n.wrap-table table tbody tr td:first-child {\\n position: relative;\\n padding-right: 5rem;\\n width: 18rem; }\\n\\n.wrap-table table tbody tr td:first-child span {\\n display: block;\\n line-height: 3.5rem;\\n max-width: 10rem; }\\n\\n.wrap-table table tbody tr td:first-child .icon {\\n position: absolute;\\n top: 50%;\\n right: 1rem;\\n -webkit-transform: translateY(-50%);\\n transform: translateY(-50%);\\n display: block;\\n -webkit-mask: url('alert.svg') no-repeat 0;\\n mask: url('alert.svg') no-repeat 0;\\n width: 1.2rem;\\n height: 1.2rem; }\\n\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvbWVzc2FnZXMvRDpcXHphbm8vc3JjXFxhcHBcXG1lc3NhZ2VzXFxtZXNzYWdlcy5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLFlBQVcsRUFDWjs7QUFFRDtFQUNFLGNBQWEsRUFvQ2Q7O0FBckNEO0lBWVksbUJBQWtCO0lBQ2xCLG9CQUFtQjtJQUNuQixhQUFZLEVBa0JiOztBQWhDWDtNQWlCYyxlQUFjO01BQ2Qsb0JBQW1CO01BQ25CLGlCQUFnQixFQUNqQjs7QUFwQmI7TUF1QmMsbUJBQWtCO01BQ2xCLFNBQVE7TUFDUixZQUFXO01BQ1gsb0NBQTJCO2NBQTNCLDRCQUEyQjtNQUMzQixlQUFjO01BQ2QsMkNBQW1EO2NBQW5ELG1DQUFtRDtNQUNuRCxjQUFhO01BQ2IsZUFBYyxFQUNmIiwiZmlsZSI6InNyYy9hcHAvbWVzc2FnZXMvbWVzc2FnZXMuY29tcG9uZW50LnNjc3MiLCJzb3VyY2VzQ29udGVudCI6WyI6aG9zdCB7XHJcbiAgd2lkdGg6IDEwMCU7XHJcbn1cclxuXHJcbi53cmFwLXRhYmxlIHtcclxuICBtYXJnaW46IC0zcmVtO1xyXG5cclxuICB0YWJsZSB7XHJcblxyXG4gICAgdGJvZHkge1xyXG5cclxuICAgICAgdHIge1xyXG5cclxuICAgICAgICB0ZCB7XHJcblxyXG4gICAgICAgICAgJjpmaXJzdC1jaGlsZCB7XHJcbiAgICAgICAgICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcclxuICAgICAgICAgICAgcGFkZGluZy1yaWdodDogNXJlbTtcclxuICAgICAgICAgICAgd2lkdGg6IDE4cmVtO1xyXG5cclxuICAgICAgICAgICAgc3BhbiB7XHJcbiAgICAgICAgICAgICAgZGlzcGxheTogYmxvY2s7XHJcbiAgICAgICAgICAgICAgbGluZS1oZWlnaHQ6IDMuNXJlbTtcclxuICAgICAgICAgICAgICBtYXgtd2lkdGg6IDEwcmVtO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAuaWNvbiB7XHJcbiAgICAgICAgICAgICAgcG9zaXRpb246IGFic29sdXRlO1xyXG4gICAgICAgICAgICAgIHRvcDogNTAlO1xyXG4gICAgICAgICAgICAgIHJpZ2h0OiAxcmVtO1xyXG4gICAgICAgICAgICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlWSgtNTAlKTtcclxuICAgICAgICAgICAgICBkaXNwbGF5OiBibG9jaztcclxuICAgICAgICAgICAgICBtYXNrOiB1cmwoLi4vLi4vYXNzZXRzL2ljb25zL2FsZXJ0LnN2Zykgbm8tcmVwZWF0IDA7XHJcbiAgICAgICAgICAgICAgd2lkdGg6IDEuMnJlbTtcclxuICAgICAgICAgICAgICBoZWlnaHQ6IDEuMnJlbTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxufVxyXG4iXX0= */\"","import { Component, OnInit } from '@angular/core';\r\n\r\n@Component({\r\n selector: 'app-messages',\r\n templateUrl: './messages.component.html',\r\n styleUrls: ['./messages.component.scss']\r\n})\r\nexport class MessagesComponent implements OnInit {\r\n\r\n messages = [\r\n {\r\n is_new: true,\r\n address: '@bitmap',\r\n message: 'No more miners for you!'\r\n },\r\n {\r\n is_new: false,\r\n address: 'Hjkwey36gHasdhkajshd4bxnb5mcvowyefb2633FdsFGGWbb',\r\n message: 'Hey! What’s with our BBR deal?'\r\n },\r\n {\r\n is_new: false,\r\n address: '@john',\r\n message: 'I’m coming!'\r\n }\r\n ];\r\n\r\n constructor() {}\r\n\r\n ngOnInit() {}\r\n\r\n\r\n}\r\n","module.exports = \"
\\r\\n\\r\\n
\\r\\n
\\r\\n {{ 'BREADCRUMBS.ADD_WALLET' | translate }}\\r\\n {{ 'BREADCRUMBS.OPEN_WALLET' | translate }}\\r\\n
\\r\\n \\r\\n \\r\\n {{ 'COMMON.BACK' | translate }}\\r\\n \\r\\n
\\r\\n\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n
\\r\\n Name is required.\\r\\n
\\r\\n
\\r\\n Name is duplicate.\\r\\n
\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n \\r\\n
\\r\\n
\\r\\n\\r\\n
\\r\\n\\r\\n\"","module.exports = \".form-open {\\n margin: 2.4rem 0;\\n width: 50%; }\\n .form-open .wrap-buttons {\\n display: flex;\\n margin: 2.5rem -0.7rem; }\\n .form-open .wrap-buttons button {\\n margin: 0 0.7rem; }\\n .form-open .wrap-buttons button.create-button {\\n flex: 1 1 50%; }\\n\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvb3Blbi13YWxsZXQvRDpcXHphbm8vc3JjXFxhcHBcXG9wZW4td2FsbGV0XFxvcGVuLXdhbGxldC5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLGlCQUFnQjtFQUNoQixXQUFVLEVBY1g7RUFoQkQ7SUFLSSxjQUFhO0lBQ2IsdUJBQXNCLEVBU3ZCO0VBZkg7TUFTTSxpQkFBZ0IsRUFLakI7RUFkTDtRQVlRLGNBQWEsRUFDZCIsImZpbGUiOiJzcmMvYXBwL29wZW4td2FsbGV0L29wZW4td2FsbGV0LmNvbXBvbmVudC5zY3NzIiwic291cmNlc0NvbnRlbnQiOlsiLmZvcm0tb3BlbiB7XHJcbiAgbWFyZ2luOiAyLjRyZW0gMDtcclxuICB3aWR0aDogNTAlO1xyXG5cclxuICAud3JhcC1idXR0b25zIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBtYXJnaW46IDIuNXJlbSAtMC43cmVtO1xyXG5cclxuICAgIGJ1dHRvbiB7XHJcbiAgICAgIG1hcmdpbjogMCAwLjdyZW07XHJcblxyXG4gICAgICAmLmNyZWF0ZS1idXR0b24ge1xyXG4gICAgICAgIGZsZXg6IDEgMSA1MCU7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbn1cclxuIl19 */\"","import {Component, NgZone, OnInit} from '@angular/core';\r\nimport {FormGroup, FormControl, Validators} from '@angular/forms';\r\nimport {BackendService} from '../_helpers/services/backend.service';\r\nimport {VariablesService} from '../_helpers/services/variables.service';\r\nimport {ActivatedRoute, Router} from '@angular/router';\r\nimport {Wallet} from '../_helpers/models/wallet.model';\r\n\r\n@Component({\r\n selector: 'app-open-wallet',\r\n templateUrl: './open-wallet.component.html',\r\n styleUrls: ['./open-wallet.component.scss']\r\n})\r\nexport class OpenWalletComponent implements OnInit {\r\n\r\n filePath: string;\r\n\r\n openForm = new FormGroup({\r\n name: new FormControl('', [Validators.required, (g: FormControl) => {\r\n for (let i = 0; i < this.variablesService.wallets.length; i++) {\r\n if (g.value === this.variablesService.wallets[i].name) {\r\n return {'duplicate': true};\r\n }\r\n }\r\n return null;\r\n }]),\r\n password: new FormControl('')\r\n });\r\n\r\n constructor(\r\n private route: ActivatedRoute,\r\n private router: Router,\r\n private backend: BackendService,\r\n private variablesService: VariablesService,\r\n private ngZone: NgZone\r\n ) {\r\n }\r\n\r\n ngOnInit() {\r\n this.route.queryParams.subscribe(params => {\r\n if (params.path) {\r\n this.filePath = params.path;\r\n let filename = '';\r\n if (params.path.lastIndexOf('.') === -1) {\r\n filename = params.path.substr(params.path.lastIndexOf('/') + 1);\r\n } else {\r\n filename = params.path.substr(params.path.lastIndexOf('/') + 1, params.path.lastIndexOf('.') - 1 - params.path.lastIndexOf('/'));\r\n }\r\n if (filename.length > 25) {\r\n filename = filename.slice(0, 25);\r\n }\r\n this.openForm.get('name').setValue(filename);\r\n }\r\n });\r\n }\r\n\r\n openWallet() {\r\n if (this.openForm.valid) {\r\n this.backend.openWallet(this.filePath, this.openForm.get('password').value, false, (open_status, open_data, open_error) => {\r\n if (open_error && open_error === 'FILE_NOT_FOUND') {\r\n // var error_translate = $filter('translate')('INFORMER.SAFE_FILE_NOT_FOUND1');\r\n // error_translate += ':
' + $scope.safe.path;\r\n // error_translate += $filter('translate')('INFORMER.SAFE_FILE_NOT_FOUND2');\r\n // informer.fileNotFound(error_translate);\r\n alert('FILE_NOT_FOUND');\r\n } else {\r\n if (open_status || open_error === 'FILE_RESTORED') {\r\n\r\n let exists = false;\r\n this.variablesService.wallets.forEach((wallet) => {\r\n if (wallet.address === open_data['wi'].address) {\r\n exists = true;\r\n }\r\n });\r\n\r\n if (exists) {\r\n alert('SAFES.WITH_ADDRESS_ALREADY_OPEN');\r\n this.backend.closeWallet(open_data.wallet_id, (close_status, close_data) => {\r\n console.log(close_status, close_data);\r\n this.ngZone.run(() => {\r\n this.router.navigate(['/']);\r\n });\r\n });\r\n } else {\r\n this.backend.runWallet(open_data.wallet_id, (run_status, run_data) => {\r\n if (run_status) {\r\n const new_wallet = new Wallet(\r\n open_data.wallet_id,\r\n this.openForm.get('name').value,\r\n this.openForm.get('password').value,\r\n open_data['wi'].path,\r\n open_data['wi'].address,\r\n open_data['wi'].balance,\r\n open_data['wi'].unlocked_balance,\r\n open_data['wi'].mined_total,\r\n open_data['wi'].tracking_hey\r\n );\r\n if (open_data.recent_history && open_data.recent_history.history) {\r\n new_wallet.prepareHistory(open_data.recent_history.history);\r\n }\r\n this.backend.getContracts(open_data.wallet_id, (contracts_status, contracts_data) => {\r\n if (contracts_status && contracts_data.hasOwnProperty('contracts')) {\r\n this.ngZone.run(() => {\r\n new_wallet.prepareContractsAfterOpen(contracts_data.contracts, this.variablesService.exp_med_ts, this.variablesService.height_app, this.variablesService.settings.viewedContracts, this.variablesService.settings.notViewedContracts);\r\n });\r\n }\r\n });\r\n this.variablesService.wallets.push(new_wallet);\r\n this.backend.storeSecureAppData((status, data) => {\r\n console.log('Store App Data', status, data);\r\n });\r\n this.ngZone.run(() => {\r\n this.router.navigate(['/wallet/' + open_data.wallet_id]);\r\n });\r\n } else {\r\n console.log(run_data['error_code']);\r\n }\r\n });\r\n }\r\n }\r\n }\r\n });\r\n }\r\n }\r\n\r\n}\r\n","module.exports = \"
\\r\\n
\\r\\n {{ 'BREADCRUMBS.CONTRACTS' | translate }}\\r\\n {{ 'BREADCRUMBS.NEW_PURCHASE' | translate }}\\r\\n {{ 'BREADCRUMBS.OLD_PURCHASE' | translate }}\\r\\n
\\r\\n \\r\\n
\\r\\n\\r\\n
\\r\\n\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n
\\r\\n Description is required.\\r\\n
\\r\\n
\\r\\n\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n
\\r\\n Seller is required.\\r\\n
\\r\\n
\\r\\n Seller not valid.\\r\\n
\\r\\n
\\r\\n\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n
\\r\\n Amount is required.\\r\\n
\\r\\n
\\r\\n
\\r\\n\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n
\\r\\n Your deposit is required.\\r\\n
\\r\\n
\\r\\n\\r\\n
\\r\\n
\\r\\n \\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n
\\r\\n Seller deposit is required.\\r\\n
\\r\\n
\\r\\n
\\r\\n\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n\\r\\n \\r\\n\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n\\r\\n \\r\\n\\r\\n
\\r\\n\\r\\n variablesService.currentWallet.unlocked_balance\\\">\\r\\n {{ 'There are insufficient funds in the safe. Add funds to the safe to continue' | translate }}\\r\\n \\r\\n\\r\\n \\r\\n {{ 'DEALS.CUSTOMER_WAITING_ANSWER' | translate }}\\r\\n \\r\\n\\r\\n {{ 'The seller ignored your contract proposal' | translate }}\\r\\n {{ 'Pledge amount unblocked' | translate }}\\r\\n\\r\\n {{ 'Waiting for seller to ship item' | translate }}\\r\\n\\r\\n {{ 'The seller ignored your proposal to cancel the contract' | translate }}\\r\\n\\r\\n {{ 'The contract proposal has expired' | translate }}\\r\\n\\r\\n {{ 'Please wait for the pledges to be made' | translate }}\\r\\n\\r\\n {{ 'Waiting for seller to ship item' | translate }}\\r\\n\\r\\n {{ 'Contract completed successfully' | translate }}\\r\\n {{ 'Item received, payment transferred, pledges returned' | translate }}\\r\\n\\r\\n {{ 'Item not received' | translate }}\\r\\n {{ 'All pledges nullified' | translate }}\\r\\n\\r\\n {{ 'You have made a proposal to cancel the contract' | translate }}\\r\\n \\r\\n\\r\\n {{ 'The contract is being cancelled. Please wait for the pledge to be returned' | translate }}\\r\\n\\r\\n {{ 'Contract canceled' | translate }}\\r\\n {{ 'Pledges returned' | translate }}\\r\\n \\r\\n\\r\\n \\r\\n {{ 'The buyer is proposing a contract' | translate }}\\r\\n \\r\\n\\r\\n {{ 'You ignored the contract proposal' | translate }}\\r\\n\\r\\n {{ 'You ignored the proposal to cancel the contract' | translate }}\\r\\n\\r\\n {{ 'The contract proposal has expired' | translate }}\\r\\n\\r\\n {{ 'Please wait for the pledges to be made' | translate }}\\r\\n\\r\\n {{ 'The buyer is waiting for the item to be delivered' | translate }}\\r\\n {{ 'Pledges made' | translate }}\\r\\n\\r\\n {{ 'Contract completed successfully' | translate }}\\r\\n {{ 'Item received, payment transferred, pledges returned' | translate }}\\r\\n\\r\\n {{ 'Item not received' | translate }}\\r\\n {{ 'All pledges nullified' | translate }}\\r\\n\\r\\n {{ 'The buyer is offering to cancel the contract and return the pledge' | translate }}\\r\\n \\r\\n\\r\\n {{ 'The contract is being cancelled. Please wait for the pledge to be returned' | translate }}\\r\\n\\r\\n {{ 'Contract canceled' | translate }}\\r\\n {{ 'Pledges returned' | translate }}\\r\\n \\r\\n\\r\\n \\r\\n {{variablesService.height_app - currentContract.height}}/10\\r\\n {{(historyBlock.is_income ? '+' : '') + (historyBlock.sortAmount | intToMoney)}}\\r\\n \\r\\n\\r\\n
\\r\\n\\r\\n
\\r\\n \\r\\n \\r\\n \\r\\n\\r\\n \\r\\n \\r\\n \\r\\n \\r\\n\\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n\\r\\n \\r\\n \\r\\n \\r\\n \\r\\n\\r\\n
\\r\\n\\r\\n
\\r\\n\\r\\n
\\r\\n
\\r\\n
\\r\\n
\\r\\n
\\r\\n {{ 'PURCHASE.PROGRESS_NEW' | translate }}\\r\\n {{ 'PURCHASE.PROGRESS_WAIT' | translate }}\\r\\n {{ 'PURCHASE.PROGRESS_COMPLETE' | translate }}\\r\\n
\\r\\n
\\r\\n {{currentContract.expiration_time | contractTimeLeft: 0}}\\r\\n {{currentContract.cancel_expiration_time | contractTimeLeft: 2}}\\r\\n {{currentContract.expiration_time | contractTimeLeft: 1}}\\r\\n {{currentContract.cancel_expiration_time | contractTimeLeft: 1}}\\r\\n
\\r\\n
\\r\\n\"","module.exports = \":host {\\n display: flex;\\n flex-direction: column;\\n width: 100%; }\\n\\n.head {\\n flex: 0 0 auto;\\n box-sizing: content-box;\\n margin: -3rem -3rem 0; }\\n\\n.form-purchase {\\n flex: 1 1 auto;\\n margin: 1.5rem -3rem 0;\\n padding: 0 3rem;\\n overflow-y: overlay; }\\n\\n.form-purchase .input-blocks-row {\\n display: flex; }\\n\\n.form-purchase .input-blocks-row .input-block {\\n flex-basis: 50%; }\\n\\n.form-purchase .input-blocks-row .input-block:first-child {\\n margin-right: 1.5rem; }\\n\\n.form-purchase .input-blocks-row .input-block:last-child {\\n margin-left: 1.5rem; }\\n\\n.form-purchase .input-blocks-row .input-block .checkbox-block {\\n display: flex; }\\n\\n.form-purchase .purchase-select {\\n display: flex;\\n align-items: center;\\n background: transparent;\\n border: none;\\n font-size: 1.3rem;\\n line-height: 1.3rem;\\n margin: 1.5rem 0 0;\\n padding: 0;\\n width: 100%;\\n max-width: 15rem;\\n height: 1.3rem; }\\n\\n.form-purchase .purchase-select .arrow {\\n margin-left: 1rem;\\n width: 0.8rem;\\n height: 0.8rem; }\\n\\n.form-purchase .purchase-select .arrow.down {\\n -webkit-mask: url('arrow-down.svg') no-repeat center;\\n mask: url('arrow-down.svg') no-repeat center; }\\n\\n.form-purchase .purchase-select .arrow.up {\\n -webkit-mask: url('arrow-up.svg') no-repeat center;\\n mask: url('arrow-up.svg') no-repeat center; }\\n\\n.form-purchase .additional-details {\\n display: flex;\\n margin-top: 1.5rem;\\n padding: 0.5rem 0 2rem; }\\n\\n.form-purchase .additional-details > div {\\n flex-basis: 25%; }\\n\\n.form-purchase .additional-details > div:first-child {\\n padding-left: 1.5rem;\\n padding-right: 1rem; }\\n\\n.form-purchase .additional-details > div:last-child {\\n padding-left: 1rem;\\n padding-right: 1.5rem; }\\n\\n.form-purchase .purchase-states {\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n justify-content: center;\\n font-size: 1.2rem;\\n line-height: 2.9rem; }\\n\\n.form-purchase .send-button {\\n margin: 2.4rem 0;\\n width: 100%;\\n max-width: 15rem; }\\n\\n.form-purchase .purchase-buttons {\\n display: flex;\\n justify-content: space-between;\\n margin: 2.4rem -0.5rem;\\n width: calc(100% + 1rem); }\\n\\n.form-purchase .purchase-buttons button {\\n flex: 0 1 33%;\\n margin: 0 0.5rem; }\\n\\n.progress-bar-container {\\n position: absolute;\\n bottom: 0;\\n left: 0;\\n padding: 0 3rem;\\n width: 100%;\\n height: 3rem; }\\n\\n.progress-bar-container .progress-bar {\\n position: absolute;\\n top: -0.7rem;\\n left: 0;\\n margin: 0 3rem;\\n width: calc(100% - 6rem);\\n height: 0.7rem; }\\n\\n.progress-bar-container .progress-bar .progress-bar-full {\\n height: 0.7rem; }\\n\\n.progress-bar-container .progress-labels {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n font-size: 1.2rem;\\n height: 100%; }\\n\\n.progress-bar-container .progress-labels span {\\n flex: 1 0 0;\\n text-align: center; }\\n\\n.progress-bar-container .progress-labels span:first-child {\\n text-align: left; }\\n\\n.progress-bar-container .progress-labels span:last-child {\\n text-align: right; }\\n\\n.progress-bar-container .progress-time {\\n position: absolute;\\n top: -3rem;\\n left: 50%;\\n -webkit-transform: translateX(-50%);\\n transform: translateX(-50%);\\n font-size: 1.2rem; }\\n\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvcHVyY2hhc2UvRDpcXHphbm8vc3JjXFxhcHBcXHB1cmNoYXNlXFxwdXJjaGFzZS5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLGNBQWE7RUFDYix1QkFBc0I7RUFDdEIsWUFBVyxFQUNaOztBQUVEO0VBQ0UsZUFBYztFQUNkLHdCQUF1QjtFQUN2QixzQkFBcUIsRUFDdEI7O0FBRUQ7RUFDRSxlQUFjO0VBQ2QsdUJBQXNCO0VBQ3RCLGdCQUFlO0VBQ2Ysb0JBQW1CLEVBZ0dwQjs7QUFwR0Q7SUFPSSxjQUFhLEVBaUJkOztBQXhCSDtNQVVNLGdCQUFlLEVBYWhCOztBQXZCTDtRQWFRLHFCQUFvQixFQUNyQjs7QUFkUDtRQWlCUSxvQkFBbUIsRUFDcEI7O0FBbEJQO1FBcUJRLGNBQWEsRUFDZDs7QUF0QlA7SUEyQkksY0FBYTtJQUNiLG9CQUFtQjtJQUNuQix3QkFBdUI7SUFDdkIsYUFBWTtJQUNaLGtCQUFpQjtJQUNqQixvQkFBbUI7SUFDbkIsbUJBQWtCO0lBQ2xCLFdBQVU7SUFDVixZQUFXO0lBQ1gsaUJBQWdCO0lBQ2hCLGVBQWMsRUFlZjs7QUFwREg7TUF3Q00sa0JBQWlCO01BQ2pCLGNBQWE7TUFDYixlQUFjLEVBU2Y7O0FBbkRMO1FBNkNRLHFEQUE0RDtnQkFBNUQsNkNBQTRELEVBQzdEOztBQTlDUDtRQWlEUSxtREFBMEQ7Z0JBQTFELDJDQUEwRCxFQUMzRDs7QUFsRFA7SUF1REksY0FBYTtJQUNiLG1CQUFrQjtJQUNsQix1QkFBc0IsRUFldkI7O0FBeEVIO01BNERNLGdCQUFlLEVBV2hCOztBQXZFTDtRQStEUSxxQkFBb0I7UUFDcEIsb0JBQW1CLEVBQ3BCOztBQWpFUDtRQW9FUSxtQkFBa0I7UUFDbEIsc0JBQXFCLEVBQ3RCOztBQXRFUDtJQTJFSSxjQUFhO0lBQ2IsdUJBQXNCO0lBQ3RCLG9CQUFtQjtJQUNuQix3QkFBdUI7SUFDdkIsa0JBQWlCO0lBQ2pCLG9CQUFtQixFQUNwQjs7QUFqRkg7SUFvRkksaUJBQWdCO0lBQ2hCLFlBQVc7SUFDWCxpQkFBZ0IsRUFDakI7O0FBdkZIO0lBMEZJLGNBQWE7SUFDYiwrQkFBOEI7SUFDOUIsdUJBQXNCO0lBQ3RCLHlCQUF3QixFQU16Qjs7QUFuR0g7TUFnR00sY0FBYTtNQUNiLGlCQUFnQixFQUNqQjs7QUFJTDtFQUNFLG1CQUFrQjtFQUNsQixVQUFTO0VBQ1QsUUFBTztFQUNQLGdCQUFlO0VBQ2YsWUFBVztFQUNYLGFBQVksRUEyQ2I7O0FBakREO0lBU0ksbUJBQWtCO0lBQ2xCLGFBQVk7SUFDWixRQUFPO0lBQ1AsZUFBYztJQUNkLHlCQUF3QjtJQUN4QixlQUFjLEVBS2Y7O0FBbkJIO01BaUJNLGVBQWMsRUFDZjs7QUFsQkw7SUFzQkksY0FBYTtJQUNiLG9CQUFtQjtJQUNuQiwrQkFBOEI7SUFDOUIsa0JBQWlCO0lBQ2pCLGFBQVksRUFjYjs7QUF4Q0g7TUE2Qk0sWUFBVztNQUNYLG1CQUFrQixFQVNuQjs7QUF2Q0w7UUFpQ1EsaUJBQWdCLEVBQ2pCOztBQWxDUDtRQXFDUSxrQkFBaUIsRUFDbEI7O0FBdENQO0lBMkNJLG1CQUFrQjtJQUNsQixXQUFVO0lBQ1YsVUFBUztJQUNULG9DQUEyQjtZQUEzQiw0QkFBMkI7SUFDM0Isa0JBQWlCLEVBQ2xCIiwiZmlsZSI6InNyYy9hcHAvcHVyY2hhc2UvcHVyY2hhc2UuY29tcG9uZW50LnNjc3MiLCJzb3VyY2VzQ29udGVudCI6WyI6aG9zdCB7XHJcbiAgZGlzcGxheTogZmxleDtcclxuICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xyXG4gIHdpZHRoOiAxMDAlO1xyXG59XHJcblxyXG4uaGVhZCB7XHJcbiAgZmxleDogMCAwIGF1dG87XHJcbiAgYm94LXNpemluZzogY29udGVudC1ib3g7XHJcbiAgbWFyZ2luOiAtM3JlbSAtM3JlbSAwO1xyXG59XHJcblxyXG4uZm9ybS1wdXJjaGFzZSB7XHJcbiAgZmxleDogMSAxIGF1dG87XHJcbiAgbWFyZ2luOiAxLjVyZW0gLTNyZW0gMDtcclxuICBwYWRkaW5nOiAwIDNyZW07XHJcbiAgb3ZlcmZsb3cteTogb3ZlcmxheTtcclxuXHJcbiAgLmlucHV0LWJsb2Nrcy1yb3cge1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuXHJcbiAgICAuaW5wdXQtYmxvY2sge1xyXG4gICAgICBmbGV4LWJhc2lzOiA1MCU7XHJcblxyXG4gICAgICAmOmZpcnN0LWNoaWxkIHtcclxuICAgICAgICBtYXJnaW4tcmlnaHQ6IDEuNXJlbTtcclxuICAgICAgfVxyXG5cclxuICAgICAgJjpsYXN0LWNoaWxkIHtcclxuICAgICAgICBtYXJnaW4tbGVmdDogMS41cmVtO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAuY2hlY2tib3gtYmxvY2sge1xyXG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIC5wdXJjaGFzZS1zZWxlY3Qge1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAgICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudDtcclxuICAgIGJvcmRlcjogbm9uZTtcclxuICAgIGZvbnQtc2l6ZTogMS4zcmVtO1xyXG4gICAgbGluZS1oZWlnaHQ6IDEuM3JlbTtcclxuICAgIG1hcmdpbjogMS41cmVtIDAgMDtcclxuICAgIHBhZGRpbmc6IDA7XHJcbiAgICB3aWR0aDogMTAwJTtcclxuICAgIG1heC13aWR0aDogMTVyZW07XHJcbiAgICBoZWlnaHQ6IDEuM3JlbTtcclxuXHJcbiAgICAuYXJyb3cge1xyXG4gICAgICBtYXJnaW4tbGVmdDogMXJlbTtcclxuICAgICAgd2lkdGg6IDAuOHJlbTtcclxuICAgICAgaGVpZ2h0OiAwLjhyZW07XHJcblxyXG4gICAgICAmLmRvd24ge1xyXG4gICAgICAgIG1hc2s6IHVybCh+c3JjL2Fzc2V0cy9pY29ucy9hcnJvdy1kb3duLnN2Zykgbm8tcmVwZWF0IGNlbnRlcjtcclxuICAgICAgfVxyXG5cclxuICAgICAgJi51cCB7XHJcbiAgICAgICAgbWFzazogdXJsKH5zcmMvYXNzZXRzL2ljb25zL2Fycm93LXVwLnN2Zykgbm8tcmVwZWF0IGNlbnRlcjtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLmFkZGl0aW9uYWwtZGV0YWlscyB7XHJcbiAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgbWFyZ2luLXRvcDogMS41cmVtO1xyXG4gICAgcGFkZGluZzogMC41cmVtIDAgMnJlbTtcclxuXHJcbiAgICA+IGRpdiB7XHJcbiAgICAgIGZsZXgtYmFzaXM6IDI1JTtcclxuXHJcbiAgICAgICY6Zmlyc3QtY2hpbGQge1xyXG4gICAgICAgIHBhZGRpbmctbGVmdDogMS41cmVtO1xyXG4gICAgICAgIHBhZGRpbmctcmlnaHQ6IDFyZW07XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICY6bGFzdC1jaGlsZCB7XHJcbiAgICAgICAgcGFkZGluZy1sZWZ0OiAxcmVtO1xyXG4gICAgICAgIHBhZGRpbmctcmlnaHQ6IDEuNXJlbTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLnB1cmNoYXNlLXN0YXRlcyB7XHJcbiAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAgICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcclxuICAgIGZvbnQtc2l6ZTogMS4ycmVtO1xyXG4gICAgbGluZS1oZWlnaHQ6IDIuOXJlbTtcclxuICB9XHJcblxyXG4gIC5zZW5kLWJ1dHRvbiB7XHJcbiAgICBtYXJnaW46IDIuNHJlbSAwO1xyXG4gICAgd2lkdGg6IDEwMCU7XHJcbiAgICBtYXgtd2lkdGg6IDE1cmVtO1xyXG4gIH1cclxuXHJcbiAgLnB1cmNoYXNlLWJ1dHRvbnMge1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuICAgIGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjtcclxuICAgIG1hcmdpbjogMi40cmVtIC0wLjVyZW07XHJcbiAgICB3aWR0aDogY2FsYygxMDAlICsgMXJlbSk7XHJcblxyXG4gICAgYnV0dG9uIHtcclxuICAgICAgZmxleDogMCAxIDMzJTtcclxuICAgICAgbWFyZ2luOiAwIDAuNXJlbTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbi5wcm9ncmVzcy1iYXItY29udGFpbmVyIHtcclxuICBwb3NpdGlvbjogYWJzb2x1dGU7XHJcbiAgYm90dG9tOiAwO1xyXG4gIGxlZnQ6IDA7XHJcbiAgcGFkZGluZzogMCAzcmVtO1xyXG4gIHdpZHRoOiAxMDAlO1xyXG4gIGhlaWdodDogM3JlbTtcclxuXHJcbiAgLnByb2dyZXNzLWJhciB7XHJcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XHJcbiAgICB0b3A6IC0wLjdyZW07XHJcbiAgICBsZWZ0OiAwO1xyXG4gICAgbWFyZ2luOiAwIDNyZW07XHJcbiAgICB3aWR0aDogY2FsYygxMDAlIC0gNnJlbSk7XHJcbiAgICBoZWlnaHQ6IDAuN3JlbTtcclxuXHJcbiAgICAucHJvZ3Jlc3MtYmFyLWZ1bGwge1xyXG4gICAgICBoZWlnaHQ6IDAuN3JlbTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC5wcm9ncmVzcy1sYWJlbHMge1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAgICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XHJcbiAgICBmb250LXNpemU6IDEuMnJlbTtcclxuICAgIGhlaWdodDogMTAwJTtcclxuXHJcbiAgICBzcGFuIHtcclxuICAgICAgZmxleDogMSAwIDA7XHJcbiAgICAgIHRleHQtYWxpZ246IGNlbnRlcjtcclxuXHJcbiAgICAgICY6Zmlyc3QtY2hpbGQge1xyXG4gICAgICAgIHRleHQtYWxpZ246IGxlZnQ7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICY6bGFzdC1jaGlsZCB7XHJcbiAgICAgICAgdGV4dC1hbGlnbjogcmlnaHQ7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIC5wcm9ncmVzcy10aW1lIHtcclxuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcclxuICAgIHRvcDogLTNyZW07XHJcbiAgICBsZWZ0OiA1MCU7XHJcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZVgoLTUwJSk7XHJcbiAgICBmb250LXNpemU6IDEuMnJlbTtcclxuICB9XHJcbn1cclxuIl19 */\"","import {Component, OnInit, OnDestroy, NgZone} from '@angular/core';\r\nimport {ActivatedRoute} from '@angular/router';\r\nimport {FormControl, FormGroup, Validators} from '@angular/forms';\r\nimport {BackendService} from '../_helpers/services/backend.service';\r\nimport {VariablesService} from '../_helpers/services/variables.service';\r\nimport {Location} from '@angular/common';\r\nimport {IntToMoneyPipe} from '../_helpers/pipes/int-to-money.pipe';\r\n\r\n@Component({\r\n selector: 'app-purchase',\r\n templateUrl: './purchase.component.html',\r\n styleUrls: ['./purchase.component.scss']\r\n})\r\nexport class PurchaseComponent implements OnInit, OnDestroy {\r\n currentWalletId;\r\n newPurchase = false;\r\n parentRouting;\r\n historyBlock;\r\n\r\n purchaseForm = new FormGroup({\r\n description: new FormControl('', Validators.required),\r\n seller: new FormControl('', Validators.required),\r\n amount: new FormControl(null, Validators.required),\r\n yourDeposit: new FormControl(null, Validators.required),\r\n sellerDeposit: new FormControl(null, Validators.required),\r\n sameAmount: new FormControl(false),\r\n comment: new FormControl(''),\r\n fee: new FormControl('0.01'),\r\n payment: new FormControl('')\r\n });\r\n\r\n additionalOptions = false;\r\n currentContract = null;\r\n\r\n constructor(\r\n private route: ActivatedRoute,\r\n private backend: BackendService,\r\n private variablesService: VariablesService,\r\n private ngZone: NgZone,\r\n private location: Location,\r\n private intToMoneyPipe: IntToMoneyPipe\r\n ) {\r\n }\r\n\r\n checkAndChangeHistory() {\r\n if (this.currentContract.state === 201) {\r\n this.historyBlock = this.variablesService.currentWallet.history.find(item => item.tx_type === 8 && item.contract[0].contract_id === this.currentContract.contract_id && item.contract[0].is_a === this.currentContract.is_a);\r\n } else if (this.currentContract.state === 601) {\r\n this.historyBlock = this.variablesService.currentWallet.history.find(item => item.tx_type === 12 && item.contract[0].contract_id === this.currentContract.contract_id && item.contract[0].is_a === this.currentContract.is_a);\r\n }\r\n }\r\n\r\n ngOnInit() {\r\n this.parentRouting = this.route.parent.params.subscribe(params => {\r\n this.currentWalletId = params['id'];\r\n });\r\n this.route.params.subscribe(params => {\r\n if (params.hasOwnProperty('id')) {\r\n this.currentContract = this.variablesService.currentWallet.getContract(params['id']);\r\n this.purchaseForm.setValue({\r\n description: this.currentContract.private_detailes.t,\r\n seller: this.currentContract.private_detailes.b_addr,\r\n amount: this.intToMoneyPipe.transform(this.currentContract.private_detailes.to_pay),\r\n yourDeposit: this.intToMoneyPipe.transform(this.currentContract.private_detailes.a_pledge),\r\n sellerDeposit: this.intToMoneyPipe.transform(this.currentContract.private_detailes.b_pledge),\r\n sameAmount: false,\r\n comment: this.currentContract.private_detailes.c,\r\n fee: '0.01',\r\n payment: this.currentContract.payment_id\r\n });\r\n this.newPurchase = false;\r\n\r\n\r\n // todo original code watch height_v\r\n if (this.currentContract.state === 201 && this.currentContract.height !== 0 && (this.variablesService.height_app - this.currentContract.height) >= 10) {\r\n this.currentContract.state = 2;\r\n this.currentContract.is_new = true;\r\n this.variablesService.currentWallet.recountNewContracts();\r\n } else if (this.currentContract.state === 601 && this.currentContract.height !== 0 && (this.variablesService.height_app - this.currentContract.height) >= 10) {\r\n this.currentContract.state = 6;\r\n this.currentContract.is_new = true;\r\n this.variablesService.currentWallet.recountNewContracts();\r\n }\r\n\r\n\r\n if (this.currentContract.is_new) {\r\n if (this.currentContract.is_a && this.currentContract.state === 2) {\r\n this.currentContract.state = 120;\r\n }\r\n if (this.currentContract.state === 130 && this.currentContract.cancel_expiration_time !== 0 && this.currentContract.cancel_expiration_time < this.variablesService.exp_med_ts) {\r\n this.currentContract.state = 2;\r\n }\r\n\r\n this.variablesService.settings.viewedContracts = (this.variablesService.settings.viewedContracts) ? this.variablesService.settings.viewedContracts : [];\r\n let findViewedCont = false;\r\n for (let j = 0; j < this.variablesService.settings.viewedContracts.length; j++) {\r\n if (this.variablesService.settings.viewedContracts[j].contract_id === this.currentContract.contract_id && this.variablesService.settings.viewedContracts[j].is_a === this.currentContract.is_a) {\r\n this.variablesService.settings.viewedContracts[j].state = this.currentContract.state;\r\n findViewedCont = true;\r\n break;\r\n }\r\n }\r\n if (!findViewedCont) {\r\n this.variablesService.settings.viewedContracts.push({\r\n contract_id: this.currentContract.contract_id,\r\n is_a: this.currentContract.is_a,\r\n state: this.currentContract.state\r\n });\r\n }\r\n this.currentContract.is_new = false;\r\n\r\n // todo need remove timeout\r\n setTimeout(() => {\r\n this.variablesService.currentWallet.recountNewContracts();\r\n }, 0);\r\n\r\n this.checkAndChangeHistory();\r\n\r\n }\r\n\r\n } else {\r\n this.newPurchase = true;\r\n }\r\n });\r\n }\r\n\r\n toggleOptions() {\r\n this.additionalOptions = !this.additionalOptions;\r\n }\r\n\r\n getProgressBarWidth() {\r\n if (this.newPurchase) {\r\n return '9rem';\r\n } else {\r\n return '50%';\r\n }\r\n }\r\n\r\n sameAmountChange() {\r\n if (this.purchaseForm.get('sameAmount').value) {\r\n this.purchaseForm.get('sellerDeposit').clearValidators();\r\n this.purchaseForm.get('sellerDeposit').updateValueAndValidity();\r\n } else {\r\n this.purchaseForm.get('sellerDeposit').setValidators([Validators.required]);\r\n this.purchaseForm.get('sellerDeposit').updateValueAndValidity();\r\n }\r\n }\r\n\r\n checkAddressValidation() {\r\n if (this.purchaseForm.get('seller').value) {\r\n this.backend.validateAddress(this.purchaseForm.get('seller').value, (valid_status) => {\r\n if (valid_status === false) {\r\n this.ngZone.run(() => {\r\n this.purchaseForm.get('seller').setErrors({address_not_valid: true});\r\n });\r\n }\r\n });\r\n }\r\n }\r\n\r\n createPurchase() {\r\n if (this.purchaseForm.valid) {\r\n if (this.purchaseForm.get('sameAmount').value) {\r\n this.purchaseForm.get('sellerDeposit').setValue(this.purchaseForm.get('amount').value);\r\n }\r\n this.backend.createProposal(\r\n this.variablesService.currentWallet.wallet_id,\r\n this.purchaseForm.get('description').value,\r\n this.purchaseForm.get('comment').value,\r\n this.variablesService.currentWallet.address,\r\n this.purchaseForm.get('seller').value,\r\n this.purchaseForm.get('amount').value,\r\n this.purchaseForm.get('yourDeposit').value,\r\n this.purchaseForm.get('sellerDeposit').value,\r\n 12,\r\n this.purchaseForm.get('payment').value,\r\n () => {\r\n this.back();\r\n });\r\n }\r\n }\r\n\r\n back() {\r\n this.location.back();\r\n }\r\n\r\n acceptState() {\r\n this.backend.acceptProposal(this.currentWalletId, this.currentContract.contract_id, (accept_status) => {\r\n if (accept_status) {\r\n alert('You have accepted the contract proposal. Please wait for the pledges to be made');\r\n this.back();\r\n }\r\n });\r\n }\r\n\r\n ignoredContract() {\r\n this.variablesService.settings.notViewedContracts = (this.variablesService.settings.notViewedContracts) ? this.variablesService.settings.notViewedContracts : [];\r\n let findViewedCont = false;\r\n for (let j = 0; j < this.variablesService.settings.notViewedContracts.length; j++) {\r\n if (this.variablesService.settings.notViewedContracts[j].contract_id === this.currentContract.contract_id && this.variablesService.settings.notViewedContracts[j].is_a === this.currentContract.is_a) {\r\n this.variablesService.settings.notViewedContracts[j].state = 110;\r\n this.variablesService.settings.notViewedContracts[j].time = this.currentContract.expiration_time;\r\n findViewedCont = true;\r\n break;\r\n }\r\n }\r\n if (!findViewedCont) {\r\n this.variablesService.settings.notViewedContracts.push({\r\n contract_id: this.currentContract.contract_id,\r\n is_a: this.currentContract.is_a,\r\n state: 110,\r\n time: this.currentContract.expiration_time\r\n });\r\n }\r\n this.currentContract.is_new = true;\r\n this.currentContract.state = 110;\r\n this.currentContract.time = this.currentContract.expiration_time;\r\n\r\n this.variablesService.currentWallet.recountNewContracts();\r\n alert('You have ignored the contract proposal');\r\n this.back();\r\n }\r\n\r\n\r\n productNotGot() {\r\n this.backend.releaseProposal(this.currentWalletId, this.currentContract.contract_id, 'REL_B', (release_status) => {\r\n if (release_status) {\r\n alert('The pledges have been nullified.');\r\n this.back();\r\n }\r\n });\r\n }\r\n\r\n dealsDetailsFinish() {\r\n this.backend.releaseProposal(this.currentWalletId, this.currentContract.contract_id, 'REL_N', (release_status) => {\r\n if (release_status) {\r\n alert('The contract is complete. The payment has been sent.');\r\n this.back();\r\n }\r\n });\r\n }\r\n\r\n dealsDetailsCancel() {\r\n this.backend.requestCancelContract(this.currentWalletId, this.currentContract.contract_id, 12, (cancel_status) => {\r\n if (cancel_status) {\r\n alert('Proposal to cancel contract sent to seller');\r\n this.back();\r\n }\r\n });\r\n }\r\n\r\n dealsDetailsDontCanceling() {\r\n this.variablesService.settings.notViewedContracts = this.variablesService.settings.notViewedContracts ? this.variablesService.settings.notViewedContracts : [];\r\n let findViewedCont = false;\r\n for (let j = 0; j < this.variablesService.settings.notViewedContracts.length; j++) {\r\n if (this.variablesService.settings.notViewedContracts[j].contract_id === this.currentContract.contract_id && this.variablesService.settings.notViewedContracts[j].is_a === this.currentContract.is_a) {\r\n this.variablesService.settings.notViewedContracts[j].state = 130;\r\n this.variablesService.settings.notViewedContracts[j].time = this.currentContract.cancel_expiration_time;\r\n findViewedCont = true;\r\n break;\r\n }\r\n }\r\n if (!findViewedCont) {\r\n this.variablesService.settings.notViewedContracts.push({\r\n contract_id: this.currentContract.contract_id,\r\n is_a: this.currentContract.is_a,\r\n state: 130,\r\n time: this.currentContract.cancel_expiration_time\r\n });\r\n }\r\n this.currentContract.is_new = true;\r\n this.currentContract.state = 130;\r\n this.currentContract.time = this.currentContract.cancel_expiration_time;\r\n\r\n this.variablesService.currentWallet.recountNewContracts();\r\n alert('You have ignored the proposal to cancel the contract');\r\n this.back();\r\n }\r\n\r\n dealsDetailsSellerCancel() {\r\n this.backend.acceptCancelContract(this.currentWalletId, this.currentContract.contract_id, (accept_status) => {\r\n if (accept_status) {\r\n alert('The contract is being cancelled. Please wait for the pledge to be returned');\r\n this.back();\r\n }\r\n });\r\n }\r\n\r\n ngOnDestroy() {\r\n this.parentRouting.unsubscribe();\r\n }\r\n\r\n}\r\n","module.exports = \"
\\r\\n \\\"qr-code\\\"\\r\\n
\\r\\n
{{variablesService.currentWallet.address}}
\\r\\n \\r\\n
\\r\\n
\\r\\n\"","module.exports = \":host {\\n width: 100%; }\\n\\n.wrap-qr {\\n display: flex;\\n flex-direction: column;\\n align-items: center; }\\n\\n.wrap-qr img {\\n margin: 4rem 0; }\\n\\n.wrap-qr .wrap-address {\\n display: flex;\\n align-items: center;\\n font-size: 1.4rem;\\n line-height: 2.7rem; }\\n\\n.wrap-qr .wrap-address .btn-copy-address {\\n -webkit-mask: url('copy.svg') no-repeat center;\\n mask: url('copy.svg') no-repeat center;\\n margin-left: 1.2rem;\\n width: 1.7rem;\\n height: 1.7rem; }\\n\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvcmVjZWl2ZS9EOlxcemFuby9zcmNcXGFwcFxccmVjZWl2ZVxccmVjZWl2ZS5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLFlBQVcsRUFDWjs7QUFFRDtFQUNFLGNBQWE7RUFDYix1QkFBc0I7RUFDdEIsb0JBQW1CLEVBbUJwQjs7QUF0QkQ7SUFNSSxlQUFjLEVBQ2Y7O0FBUEg7SUFVSSxjQUFhO0lBQ2Isb0JBQW1CO0lBQ25CLGtCQUFpQjtJQUNqQixvQkFBbUIsRUFRcEI7O0FBckJIO01BZ0JNLCtDQUF1RDtjQUF2RCx1Q0FBdUQ7TUFDdkQsb0JBQW1CO01BQ25CLGNBQWE7TUFDYixlQUFjLEVBQ2YiLCJmaWxlIjoic3JjL2FwcC9yZWNlaXZlL3JlY2VpdmUuY29tcG9uZW50LnNjc3MiLCJzb3VyY2VzQ29udGVudCI6WyI6aG9zdCB7XHJcbiAgd2lkdGg6IDEwMCU7XHJcbn1cclxuXHJcbi53cmFwLXFyIHtcclxuICBkaXNwbGF5OiBmbGV4O1xyXG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XHJcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuXHJcbiAgaW1nIHtcclxuICAgIG1hcmdpbjogNHJlbSAwO1xyXG4gIH1cclxuXHJcbiAgLndyYXAtYWRkcmVzcyB7XHJcbiAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuICAgIGZvbnQtc2l6ZTogMS40cmVtO1xyXG4gICAgbGluZS1oZWlnaHQ6IDIuN3JlbTtcclxuXHJcbiAgICAuYnRuLWNvcHktYWRkcmVzcyB7XHJcbiAgICAgIG1hc2s6IHVybCguLi8uLi9hc3NldHMvaWNvbnMvY29weS5zdmcpIG5vLXJlcGVhdCBjZW50ZXI7XHJcbiAgICAgIG1hcmdpbi1sZWZ0OiAxLjJyZW07XHJcbiAgICAgIHdpZHRoOiAxLjdyZW07XHJcbiAgICAgIGhlaWdodDogMS43cmVtO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG4iXX0= */\"","import {Component, OnInit, OnDestroy} from '@angular/core';\r\nimport QRCode from 'qrcode';\r\nimport {BackendService} from '../_helpers/services/backend.service';\r\nimport {VariablesService} from '../_helpers/services/variables.service';\r\nimport {ActivatedRoute} from '@angular/router';\r\n\r\n@Component({\r\n selector: 'app-receive',\r\n templateUrl: './receive.component.html',\r\n styleUrls: ['./receive.component.scss']\r\n})\r\nexport class ReceiveComponent implements OnInit, OnDestroy {\r\n qrImageSrc: string;\r\n parentRouting;\r\n\r\n constructor(\r\n private route: ActivatedRoute,\r\n private backend: BackendService,\r\n private variablesService: VariablesService\r\n ) {\r\n }\r\n\r\n ngOnInit() {\r\n this.parentRouting = this.route.parent.params.subscribe(() => {\r\n QRCode.toDataURL(this.variablesService.currentWallet.address, {\r\n width: 106,\r\n height: 106\r\n }).then(url => {\r\n this.qrImageSrc = url;\r\n }).catch(err => {\r\n console.error(err);\r\n });\r\n });\r\n }\r\n\r\n public copyAddress() {\r\n this.backend.setClipboard(this.variablesService.currentWallet.address);\r\n }\r\n\r\n ngOnDestroy() {\r\n this.parentRouting.unsubscribe();\r\n }\r\n\r\n}\r\n","module.exports = \"
\\r\\n
\\r\\n
\\r\\n {{ 'BREADCRUMBS.ADD_WALLET' | translate }}\\r\\n {{ 'BREADCRUMBS.RESTORE_WALLET' | translate }}\\r\\n
\\r\\n \\r\\n \\r\\n {{ 'COMMON.BACK' | translate }}\\r\\n \\r\\n
\\r\\n\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n
\\r\\n Name is required.\\r\\n
\\r\\n
\\r\\n Name is duplicate.\\r\\n
\\r\\n
\\r\\n\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n
\\r\\n Confirm password not match.\\r\\n
\\r\\n
\\r\\n\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n
\\r\\n Key is required.\\r\\n
\\r\\n
\\r\\n Key not valid.\\r\\n
\\r\\n
\\r\\n\\r\\n
\\r\\n \\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n\\r\\n
\\r\\n\"","module.exports = \".form-restore {\\n margin: 2.4rem 0;\\n width: 100%; }\\n .form-restore .input-block.half-block, .form-restore .error-block.half-block {\\n width: 50%; }\\n .form-restore .wrap-buttons {\\n display: flex;\\n margin: 2.5rem -0.7rem;\\n width: 50%; }\\n .form-restore .wrap-buttons button {\\n margin: 0 0.7rem; }\\n .form-restore .wrap-buttons button.transparent-button {\\n flex-basis: 50%; }\\n .form-restore .wrap-buttons button.select-button {\\n flex-basis: 60%; }\\n .form-restore .wrap-buttons button.create-button {\\n flex: 1 1 50%; }\\n\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvcmVzdG9yZS13YWxsZXQvRDpcXHphbm8vc3JjXFxhcHBcXHJlc3RvcmUtd2FsbGV0XFxyZXN0b3JlLXdhbGxldC5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLGlCQUFnQjtFQUNoQixZQUFXLEVBOEJaO0VBaENEO0lBT00sV0FBVSxFQUNYO0VBUkw7SUFZSSxjQUFhO0lBQ2IsdUJBQXNCO0lBQ3RCLFdBQVUsRUFpQlg7RUEvQkg7TUFpQk0saUJBQWdCLEVBYWpCO0VBOUJMO1FBb0JRLGdCQUFlLEVBQ2hCO0VBckJQO1FBd0JRLGdCQUFlLEVBQ2hCO0VBekJQO1FBNEJRLGNBQWEsRUFDZCIsImZpbGUiOiJzcmMvYXBwL3Jlc3RvcmUtd2FsbGV0L3Jlc3RvcmUtd2FsbGV0LmNvbXBvbmVudC5zY3NzIiwic291cmNlc0NvbnRlbnQiOlsiLmZvcm0tcmVzdG9yZSB7XHJcbiAgbWFyZ2luOiAyLjRyZW0gMDtcclxuICB3aWR0aDogMTAwJTtcclxuXHJcbiAgLmlucHV0LWJsb2NrLCAuZXJyb3ItYmxvY2sge1xyXG5cclxuICAgICYuaGFsZi1ibG9jayB7XHJcbiAgICAgIHdpZHRoOiA1MCU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAud3JhcC1idXR0b25zIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBtYXJnaW46IDIuNXJlbSAtMC43cmVtO1xyXG4gICAgd2lkdGg6IDUwJTtcclxuXHJcbiAgICBidXR0b24ge1xyXG4gICAgICBtYXJnaW46IDAgMC43cmVtO1xyXG5cclxuICAgICAgJi50cmFuc3BhcmVudC1idXR0b24ge1xyXG4gICAgICAgIGZsZXgtYmFzaXM6IDUwJTtcclxuICAgICAgfVxyXG5cclxuICAgICAgJi5zZWxlY3QtYnV0dG9uIHtcclxuICAgICAgICBmbGV4LWJhc2lzOiA2MCU7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICYuY3JlYXRlLWJ1dHRvbiB7XHJcbiAgICAgICAgZmxleDogMSAxIDUwJTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxufVxyXG4iXX0= */\"","import {Component, NgZone, OnInit} from '@angular/core';\r\nimport {FormGroup, FormControl, Validators} from '@angular/forms';\r\nimport {Router} from '@angular/router';\r\nimport {BackendService} from '../_helpers/services/backend.service';\r\nimport {VariablesService} from '../_helpers/services/variables.service';\r\nimport {Wallet} from '../_helpers/models/wallet.model';\r\n\r\n@Component({\r\n selector: 'app-restore-wallet',\r\n templateUrl: './restore-wallet.component.html',\r\n styleUrls: ['./restore-wallet.component.scss']\r\n})\r\nexport class RestoreWalletComponent implements OnInit {\r\n\r\n restoreForm = new FormGroup({\r\n name: new FormControl('', [Validators.required, (g: FormControl) => {\r\n for (let i = 0; i < this.variablesService.wallets.length; i++) {\r\n if (g.value === this.variablesService.wallets[i].name) {\r\n return {'duplicate': true};\r\n }\r\n }\r\n return null;\r\n }]),\r\n key: new FormControl('', Validators.required),\r\n password: new FormControl(''),\r\n confirm: new FormControl('')\r\n }, function (g: FormGroup) {\r\n return g.get('password').value === g.get('confirm').value ? null : {'confirm_mismatch': true};\r\n });\r\n\r\n wallet = {\r\n id: ''\r\n };\r\n\r\n walletSaved = false;\r\n\r\n constructor(\r\n private router: Router,\r\n private backend: BackendService,\r\n private variablesService: VariablesService,\r\n private ngZone: NgZone\r\n ) {\r\n }\r\n\r\n ngOnInit() {\r\n }\r\n\r\n\r\n createWallet() {\r\n this.router.navigate(['/seed-phrase'], {queryParams: {wallet_id: this.wallet.id}});\r\n }\r\n\r\n saveWallet() {\r\n if (this.restoreForm.valid) {\r\n this.backend.isValidRestoreWalletText(this.restoreForm.get('key').value, (valid_status, valid_data) => {\r\n\r\n if (valid_data === 'FALSE') {\r\n this.ngZone.run(() => {\r\n this.restoreForm.get('key').setErrors({key_not_valid: true});\r\n });\r\n } else {\r\n this.backend.saveFileDialog('Save the wallet file.', '*', this.variablesService.settings.default_path, (save_status, save_data) => {\r\n if (save_status) {\r\n this.variablesService.settings.default_path = save_data.path.substr(0, save_data.path.lastIndexOf('/'));\r\n this.backend.restoreWallet(save_data.path, this.restoreForm.get('password').value, this.restoreForm.get('key').value, (restore_status, restore_data) => {\r\n if (restore_status) {\r\n this.wallet.id = restore_data.wallet_id;\r\n this.variablesService.opening_wallet = new Wallet(\r\n restore_data.wallet_id,\r\n this.restoreForm.get('name').value,\r\n this.restoreForm.get('password').value,\r\n restore_data['wi'].path,\r\n restore_data['wi'].address,\r\n restore_data['wi'].balance,\r\n restore_data['wi'].unlocked_balance,\r\n restore_data['wi'].mined_total,\r\n restore_data['wi'].tracking_hey\r\n );\r\n if (restore_data.recent_history && restore_data.recent_history.history) {\r\n this.variablesService.opening_wallet.prepareHistory(restore_data.recent_history.history);\r\n }\r\n this.backend.getContracts(this.variablesService.opening_wallet.wallet_id, (contracts_status, contracts_data) => {\r\n if (contracts_status && contracts_data.hasOwnProperty('contracts')) {\r\n this.ngZone.run(() => {\r\n this.variablesService.opening_wallet.prepareContractsAfterOpen(contracts_data.contracts, this.variablesService.exp_med_ts, this.variablesService.height_app, this.variablesService.settings.viewedContracts, this.variablesService.settings.notViewedContracts);\r\n });\r\n }\r\n });\r\n this.ngZone.run(() => {\r\n this.walletSaved = true;\r\n });\r\n } else {\r\n alert('SAFES.NOT_CORRECT_FILE_OR_PASSWORD');\r\n }\r\n });\r\n }\r\n });\r\n }\r\n });\r\n }\r\n }\r\n\r\n\r\n}\r\n","module.exports = \"
\\r\\n
\\r\\n
\\r\\n {{ 'BREADCRUMBS.ADD_WALLET' | translate }}\\r\\n {{ 'BREADCRUMBS.SAVE_PHRASE' | translate }}\\r\\n
\\r\\n \\r\\n \\r\\n {{ 'COMMON.BACK' | translate }}\\r\\n \\r\\n
\\r\\n\\r\\n

{{ 'SEED_PHRASE.TITLE' | translate }}

\\r\\n\\r\\n
\\r\\n \\r\\n
{{(index + 1) + '. ' + word}}
\\r\\n
\\r\\n
\\r\\n\\r\\n \\r\\n
\\r\\n\"","module.exports = \".seed-phrase-title {\\n line-height: 2.2rem;\\n padding: 2.2rem 0; }\\n\\n.seed-phrase-content {\\n display: flex;\\n flex-direction: column;\\n flex-wrap: wrap;\\n padding: 1.4rem;\\n width: 100%;\\n height: 12rem; }\\n\\n.seed-phrase-content .word {\\n line-height: 2.2rem;\\n max-width: 13rem; }\\n\\nbutton {\\n margin: 2.8rem 0;\\n width: 25%;\\n min-width: 1.5rem; }\\n\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvc2VlZC1waHJhc2UvRDpcXHphbm8vc3JjXFxhcHBcXHNlZWQtcGhyYXNlXFxzZWVkLXBocmFzZS5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLG9CQUFtQjtFQUNuQixrQkFBaUIsRUFDbEI7O0FBRUQ7RUFDRSxjQUFhO0VBQ2IsdUJBQXNCO0VBQ3RCLGdCQUFlO0VBQ2YsZ0JBQWU7RUFDZixZQUFXO0VBQ1gsY0FBYSxFQU1kOztBQVpEO0lBU0ksb0JBQW1CO0lBQ25CLGlCQUFnQixFQUNqQjs7QUFHSDtFQUNFLGlCQUFnQjtFQUNoQixXQUFVO0VBQ1Ysa0JBQWlCLEVBQ2xCIiwiZmlsZSI6InNyYy9hcHAvc2VlZC1waHJhc2Uvc2VlZC1waHJhc2UuY29tcG9uZW50LnNjc3MiLCJzb3VyY2VzQ29udGVudCI6WyIuc2VlZC1waHJhc2UtdGl0bGUge1xyXG4gIGxpbmUtaGVpZ2h0OiAyLjJyZW07XHJcbiAgcGFkZGluZzogMi4ycmVtIDA7XHJcbn1cclxuXHJcbi5zZWVkLXBocmFzZS1jb250ZW50IHtcclxuICBkaXNwbGF5OiBmbGV4O1xyXG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XHJcbiAgZmxleC13cmFwOiB3cmFwO1xyXG4gIHBhZGRpbmc6IDEuNHJlbTtcclxuICB3aWR0aDogMTAwJTtcclxuICBoZWlnaHQ6IDEycmVtO1xyXG5cclxuICAud29yZCB7XHJcbiAgICBsaW5lLWhlaWdodDogMi4ycmVtO1xyXG4gICAgbWF4LXdpZHRoOiAxM3JlbTtcclxuICB9XHJcbn1cclxuXHJcbmJ1dHRvbiB7XHJcbiAgbWFyZ2luOiAyLjhyZW0gMDtcclxuICB3aWR0aDogMjUlO1xyXG4gIG1pbi13aWR0aDogMS41cmVtO1xyXG59XHJcbiJdfQ== */\"","import {Component, NgZone, OnInit} from '@angular/core';\r\nimport {BackendService} from '../_helpers/services/backend.service';\r\nimport {ActivatedRoute, Router} from '@angular/router';\r\nimport {VariablesService} from '../_helpers/services/variables.service';\r\n\r\n@Component({\r\n selector: 'app-seed-phrase',\r\n templateUrl: './seed-phrase.component.html',\r\n styleUrls: ['./seed-phrase.component.scss']\r\n})\r\nexport class SeedPhraseComponent implements OnInit {\r\n\r\n seedPhrase = '';\r\n wallet_id: number;\r\n\r\n constructor(\r\n private route: ActivatedRoute,\r\n private router: Router,\r\n private backend: BackendService,\r\n private variablesService: VariablesService,\r\n private ngZone: NgZone\r\n ) {}\r\n\r\n ngOnInit() {\r\n this.route.queryParams.subscribe(params => {\r\n if (params.wallet_id) {\r\n this.wallet_id = params.wallet_id;\r\n this.backend.getSmartSafeInfo(params.wallet_id, (status, data) => {\r\n if (data.hasOwnProperty('restore_key')) {\r\n this.ngZone.run(() => {\r\n this.seedPhrase = data['restore_key'].trim();\r\n });\r\n }\r\n });\r\n }\r\n });\r\n }\r\n\r\n runWallet() {\r\n let exists = false;\r\n this.variablesService.wallets.forEach((wallet) => {\r\n if (wallet.address === this.variablesService.opening_wallet.address) {\r\n exists = true;\r\n }\r\n });\r\n if (!exists) {\r\n this.backend.runWallet(this.wallet_id, (run_status, run_data) => {\r\n if (run_status) {\r\n this.variablesService.wallets.push(this.variablesService.opening_wallet);\r\n this.backend.storeSecureAppData((status, data) => {\r\n console.log('Store App Data', status, data);\r\n });\r\n this.ngZone.run(() => {\r\n this.router.navigate(['/wallet/' + this.wallet_id]);\r\n });\r\n } else {\r\n console.log(run_data['error_code']);\r\n }\r\n // $rootScope.reloadCounters();\r\n // $rootScope.$broadcast('NEED_REFRESH_HISTORY');\r\n // $rootScope.saveSecureData();\r\n });\r\n } else {\r\n this.variablesService.opening_wallet = null;\r\n this.backend.closeWallet(this.wallet_id, (close_status, close_data) => {\r\n console.log(close_status, close_data);\r\n this.ngZone.run(() => {\r\n this.router.navigate(['/']);\r\n });\r\n });\r\n }\r\n }\r\n\r\n}\r\n","module.exports = \"
\\r\\n\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n\\r\\n
\\r\\n
\\r\\n Address is required.\\r\\n
\\r\\n
\\r\\n Address not valid.\\r\\n
\\r\\n
\\r\\n\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n\\r\\n
\\r\\n
\\r\\n Amount is required.\\r\\n
\\r\\n
\\r\\n\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n\\r\\n \\r\\n\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n
\\r\\n Amount is required.\\r\\n
\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n
\\r\\n Amount is required.\\r\\n
\\r\\n
\\r\\n
\\r\\n \\r\\n
\\r\\n\"","module.exports = \":host {\\n width: 100%; }\\n\\n.form-send .input-blocks-row {\\n display: flex; }\\n\\n.form-send .input-blocks-row > div {\\n flex-basis: 50%; }\\n\\n.form-send .input-blocks-row > div:first-child {\\n margin-right: 1.5rem; }\\n\\n.form-send .input-blocks-row > div:last-child {\\n margin-left: 1.5rem; }\\n\\n.form-send .send-select {\\n display: flex;\\n align-items: center;\\n background: transparent;\\n border: none;\\n font-size: 1.3rem;\\n line-height: 1.3rem;\\n margin: 1.5rem 0 0;\\n padding: 0;\\n width: 100%;\\n max-width: 15rem;\\n height: 1.3rem; }\\n\\n.form-send .send-select .arrow {\\n margin-left: 1rem;\\n width: 0.8rem;\\n height: 0.8rem; }\\n\\n.form-send .send-select .arrow.down {\\n -webkit-mask: url('arrow-down.svg') no-repeat center;\\n mask: url('arrow-down.svg') no-repeat center; }\\n\\n.form-send .send-select .arrow.up {\\n -webkit-mask: url('arrow-up.svg') no-repeat center;\\n mask: url('arrow-up.svg') no-repeat center; }\\n\\n.form-send .additional-details {\\n display: flex;\\n margin-top: 1.5rem;\\n padding: 0.5rem 0 2rem; }\\n\\n.form-send .additional-details > div {\\n flex-basis: 25%; }\\n\\n.form-send .additional-details > div:first-child {\\n padding-left: 1.5rem;\\n padding-right: 1rem; }\\n\\n.form-send .additional-details > div:last-child {\\n padding-left: 1rem;\\n padding-right: 1.5rem; }\\n\\n.form-send button {\\n margin: 2.4rem 0;\\n width: 100%;\\n max-width: 15rem; }\\n\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvc2VuZC9EOlxcemFuby9zcmNcXGFwcFxcc2VuZFxcc2VuZC5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLFlBQVcsRUFDWjs7QUFFRDtFQUdJLGNBQWEsRUFhZDs7QUFoQkg7SUFNTSxnQkFBZSxFQVNoQjs7QUFmTDtNQVNRLHFCQUFvQixFQUNyQjs7QUFWUDtNQWFRLG9CQUFtQixFQUNwQjs7QUFkUDtFQW1CSSxjQUFhO0VBQ2Isb0JBQW1CO0VBQ25CLHdCQUF1QjtFQUN2QixhQUFZO0VBQ1osa0JBQWlCO0VBQ2pCLG9CQUFtQjtFQUNuQixtQkFBa0I7RUFDbEIsV0FBVTtFQUNWLFlBQVc7RUFDWCxpQkFBZ0I7RUFDaEIsZUFBYyxFQWVmOztBQTVDSDtJQWdDTSxrQkFBaUI7SUFDakIsY0FBYTtJQUNiLGVBQWMsRUFTZjs7QUEzQ0w7TUFxQ1EscURBQTREO2NBQTVELDZDQUE0RCxFQUM3RDs7QUF0Q1A7TUF5Q1EsbURBQTBEO2NBQTFELDJDQUEwRCxFQUMzRDs7QUExQ1A7RUErQ0ksY0FBYTtFQUNiLG1CQUFrQjtFQUNsQix1QkFBc0IsRUFldkI7O0FBaEVIO0lBb0RNLGdCQUFlLEVBV2hCOztBQS9ETDtNQXVEUSxxQkFBb0I7TUFDcEIsb0JBQW1CLEVBQ3BCOztBQXpEUDtNQTREUSxtQkFBa0I7TUFDbEIsc0JBQXFCLEVBQ3RCOztBQTlEUDtFQW1FSSxpQkFBZ0I7RUFDaEIsWUFBVztFQUNYLGlCQUFnQixFQUNqQiIsImZpbGUiOiJzcmMvYXBwL3NlbmQvc2VuZC5jb21wb25lbnQuc2NzcyIsInNvdXJjZXNDb250ZW50IjpbIjpob3N0IHtcclxuICB3aWR0aDogMTAwJTtcclxufVxyXG5cclxuLmZvcm0tc2VuZCB7XHJcblxyXG4gIC5pbnB1dC1ibG9ja3Mtcm93IHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcblxyXG4gICAgPiBkaXYge1xyXG4gICAgICBmbGV4LWJhc2lzOiA1MCU7XHJcblxyXG4gICAgICAmOmZpcnN0LWNoaWxkIHtcclxuICAgICAgICBtYXJnaW4tcmlnaHQ6IDEuNXJlbTtcclxuICAgICAgfVxyXG5cclxuICAgICAgJjpsYXN0LWNoaWxkIHtcclxuICAgICAgICBtYXJnaW4tbGVmdDogMS41cmVtO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAuc2VuZC1zZWxlY3Qge1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAgICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudDtcclxuICAgIGJvcmRlcjogbm9uZTtcclxuICAgIGZvbnQtc2l6ZTogMS4zcmVtO1xyXG4gICAgbGluZS1oZWlnaHQ6IDEuM3JlbTtcclxuICAgIG1hcmdpbjogMS41cmVtIDAgMDtcclxuICAgIHBhZGRpbmc6IDA7XHJcbiAgICB3aWR0aDogMTAwJTtcclxuICAgIG1heC13aWR0aDogMTVyZW07XHJcbiAgICBoZWlnaHQ6IDEuM3JlbTtcclxuXHJcbiAgICAuYXJyb3cge1xyXG4gICAgICBtYXJnaW4tbGVmdDogMXJlbTtcclxuICAgICAgd2lkdGg6IDAuOHJlbTtcclxuICAgICAgaGVpZ2h0OiAwLjhyZW07XHJcblxyXG4gICAgICAmLmRvd24ge1xyXG4gICAgICAgIG1hc2s6IHVybCh+c3JjL2Fzc2V0cy9pY29ucy9hcnJvdy1kb3duLnN2Zykgbm8tcmVwZWF0IGNlbnRlcjtcclxuICAgICAgfVxyXG5cclxuICAgICAgJi51cCB7XHJcbiAgICAgICAgbWFzazogdXJsKH5zcmMvYXNzZXRzL2ljb25zL2Fycm93LXVwLnN2Zykgbm8tcmVwZWF0IGNlbnRlcjtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLmFkZGl0aW9uYWwtZGV0YWlscyB7XHJcbiAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgbWFyZ2luLXRvcDogMS41cmVtO1xyXG4gICAgcGFkZGluZzogMC41cmVtIDAgMnJlbTtcclxuXHJcbiAgICA+IGRpdiB7XHJcbiAgICAgIGZsZXgtYmFzaXM6IDI1JTtcclxuXHJcbiAgICAgICY6Zmlyc3QtY2hpbGQge1xyXG4gICAgICAgIHBhZGRpbmctbGVmdDogMS41cmVtO1xyXG4gICAgICAgIHBhZGRpbmctcmlnaHQ6IDFyZW07XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICY6bGFzdC1jaGlsZCB7XHJcbiAgICAgICAgcGFkZGluZy1sZWZ0OiAxcmVtO1xyXG4gICAgICAgIHBhZGRpbmctcmlnaHQ6IDEuNXJlbTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgYnV0dG9uIHtcclxuICAgIG1hcmdpbjogMi40cmVtIDA7XHJcbiAgICB3aWR0aDogMTAwJTtcclxuICAgIG1heC13aWR0aDogMTVyZW07XHJcbiAgfVxyXG59XHJcbiJdfQ== */\"","import {Component, OnInit, OnDestroy, NgZone} from '@angular/core';\r\nimport {FormGroup, FormControl, Validators} from '@angular/forms';\r\nimport {ActivatedRoute} from '@angular/router';\r\nimport {BackendService} from '../_helpers/services/backend.service';\r\nimport {VariablesService} from '../_helpers/services/variables.service';\r\n\r\n@Component({\r\n selector: 'app-send',\r\n templateUrl: './send.component.html',\r\n styleUrls: ['./send.component.scss']\r\n})\r\nexport class SendComponent implements OnInit, OnDestroy {\r\n\r\n currentWalletId = null;\r\n parentRouting;\r\n sendForm = new FormGroup({\r\n address: new FormControl('', Validators.required),\r\n amount: new FormControl(null, Validators.required),\r\n comment: new FormControl(''),\r\n mixin: new FormControl(0, Validators.required),\r\n fee: new FormControl('0.01', Validators.required)\r\n });\r\n additionalOptions = false;\r\n\r\n constructor(\r\n private route: ActivatedRoute,\r\n private backend: BackendService,\r\n private variablesService: VariablesService,\r\n private ngZone: NgZone\r\n ) {}\r\n\r\n ngOnInit() {\r\n this.parentRouting = this.route.parent.params.subscribe(params => {\r\n this.currentWalletId = params['id'];\r\n this.sendForm.reset({address: '', amount: null, comment: '', mixin: 0, fee: '0.01'});\r\n });\r\n }\r\n\r\n checkAddressValidation() {\r\n if (this.sendForm.get('address').value) {\r\n this.backend.validateAddress(this.sendForm.get('address').value, (valid_status) => {\r\n if (valid_status === false) {\r\n this.ngZone.run(() => {\r\n this.sendForm.get('address').setErrors({address_not_valid: true});\r\n });\r\n }\r\n });\r\n }\r\n }\r\n\r\n onSend() {\r\n if (this.sendForm.valid) {\r\n this.backend.validateAddress(this.sendForm.get('address').value, (valid_status) => {\r\n if (valid_status === false) {\r\n this.ngZone.run(() => {\r\n this.sendForm.get('address').setErrors({address_not_valid: true});\r\n });\r\n } else {\r\n this.backend.sendMoney(\r\n this.currentWalletId,\r\n this.sendForm.get('address').value,\r\n this.sendForm.get('amount').value,\r\n this.sendForm.get('fee').value,\r\n this.sendForm.get('mixin').value,\r\n this.sendForm.get('comment').value,\r\n (send_status, send_data) => {\r\n if (send_status) {\r\n alert('SEND_MONEY.SUCCESS_SENT');\r\n this.sendForm.reset({address: '', amount: null, comment: '', mixin: 0, fee: '0.01'});\r\n }\r\n });\r\n }\r\n });\r\n }\r\n }\r\n\r\n toggleOptions() {\r\n this.additionalOptions = !this.additionalOptions;\r\n }\r\n\r\n ngOnDestroy() {\r\n this.parentRouting.unsubscribe();\r\n }\r\n\r\n}\r\n","module.exports = \"
\\r\\n
\\r\\n \\r\\n
\\r\\n\\r\\n

{{ 'SETTINGS.TITLE' | translate }}

\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n\\r\\n
\\r\\n {{ 'SETTINGS.MASTER_PASSWORD.TITLE' | translate }}\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n Password is required.\\r\\n
\\r\\n
\\r\\n
\\r\\n Old password not match.\\r\\n
\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n Password is required.\\r\\n
\\r\\n
\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n Password is required.\\r\\n
\\r\\n
\\r\\n
\\r\\n Confirm password not match.\\r\\n
\\r\\n
\\r\\n \\r\\n
\\r\\n\\r\\n
\\r\\n\"","module.exports = \".head {\\n justify-content: flex-end; }\\n\\n.settings-title {\\n font-size: 1.7rem; }\\n\\n.theme-selection {\\n display: flex;\\n flex-direction: column;\\n align-items: flex-start;\\n margin: 2.4rem 0;\\n width: 50%; }\\n\\n.theme-selection .radio-block {\\n display: flex;\\n align-items: center;\\n justify-content: flex-start;\\n font-size: 1.3rem;\\n line-height: 2.7rem; }\\n\\n.master-password {\\n width: 50%; }\\n\\n.master-password .master-password-title {\\n display: flex;\\n font-size: 1.5rem;\\n line-height: 2.7rem;\\n margin-bottom: 1rem; }\\n\\n.master-password button {\\n margin: 2.5rem auto;\\n width: 100%;\\n max-width: 15rem; }\\n\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvc2V0dGluZ3MvRDpcXHphbm8vc3JjXFxhcHBcXHNldHRpbmdzXFxzZXR0aW5ncy5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLDBCQUF5QixFQUMxQjs7QUFFRDtFQUNFLGtCQUFpQixFQUNsQjs7QUFFRDtFQUNFLGNBQWE7RUFDYix1QkFBc0I7RUFDdEIsd0JBQXVCO0VBQ3ZCLGlCQUFnQjtFQUNoQixXQUFVLEVBU1g7O0FBZEQ7SUFRSSxjQUFhO0lBQ2Isb0JBQW1CO0lBQ25CLDRCQUEyQjtJQUMzQixrQkFBaUI7SUFDakIsb0JBQW1CLEVBQ3BCOztBQUdIO0VBQ0UsV0FBVSxFQWNYOztBQWZEO0lBSUksY0FBYTtJQUNiLGtCQUFpQjtJQUNqQixvQkFBbUI7SUFDbkIsb0JBQW1CLEVBQ3BCOztBQVJIO0lBV0ksb0JBQW1CO0lBQ25CLFlBQVc7SUFDWCxpQkFBZ0IsRUFDakIiLCJmaWxlIjoic3JjL2FwcC9zZXR0aW5ncy9zZXR0aW5ncy5jb21wb25lbnQuc2NzcyIsInNvdXJjZXNDb250ZW50IjpbIi5oZWFkIHtcclxuICBqdXN0aWZ5LWNvbnRlbnQ6IGZsZXgtZW5kO1xyXG59XHJcblxyXG4uc2V0dGluZ3MtdGl0bGUge1xyXG4gIGZvbnQtc2l6ZTogMS43cmVtO1xyXG59XHJcblxyXG4udGhlbWUtc2VsZWN0aW9uIHtcclxuICBkaXNwbGF5OiBmbGV4O1xyXG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XHJcbiAgYWxpZ24taXRlbXM6IGZsZXgtc3RhcnQ7XHJcbiAgbWFyZ2luOiAyLjRyZW0gMDtcclxuICB3aWR0aDogNTAlO1xyXG5cclxuICAucmFkaW8tYmxvY2sge1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAgICBqdXN0aWZ5LWNvbnRlbnQ6IGZsZXgtc3RhcnQ7XHJcbiAgICBmb250LXNpemU6IDEuM3JlbTtcclxuICAgIGxpbmUtaGVpZ2h0OiAyLjdyZW07XHJcbiAgfVxyXG59XHJcblxyXG4ubWFzdGVyLXBhc3N3b3JkIHtcclxuICB3aWR0aDogNTAlO1xyXG5cclxuICAubWFzdGVyLXBhc3N3b3JkLXRpdGxlIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBmb250LXNpemU6IDEuNXJlbTtcclxuICAgIGxpbmUtaGVpZ2h0OiAyLjdyZW07XHJcbiAgICBtYXJnaW4tYm90dG9tOiAxcmVtO1xyXG4gIH1cclxuXHJcbiAgYnV0dG9uIHtcclxuICAgIG1hcmdpbjogMi41cmVtIGF1dG87XHJcbiAgICB3aWR0aDogMTAwJTtcclxuICAgIG1heC13aWR0aDogMTVyZW07XHJcbiAgfVxyXG59XHJcblxyXG4iXX0= */\"","import {Component, OnInit, Renderer2} from '@angular/core';\r\nimport {VariablesService} from '../_helpers/services/variables.service';\r\nimport {BackendService} from '../_helpers/services/backend.service';\r\nimport {FormControl, FormGroup, Validators} from '@angular/forms';\r\nimport {Location} from '@angular/common';\r\n\r\n@Component({\r\n selector: 'app-settings',\r\n templateUrl: './settings.component.html',\r\n styleUrls: ['./settings.component.scss']\r\n})\r\nexport class SettingsComponent implements OnInit {\r\n theme: string;\r\n changeForm: any;\r\n\r\n constructor(private renderer: Renderer2, private variablesService: VariablesService, private backend: BackendService, private location: Location) {\r\n this.theme = this.variablesService.settings.theme;\r\n this.changeForm = new FormGroup({\r\n password: new FormControl('', Validators.required),\r\n new_password: new FormControl('', Validators.required),\r\n new_confirmation: new FormControl('', Validators.required)\r\n }, [(g: FormGroup) => {\r\n return g.get('new_password').value === g.get('new_confirmation').value ? null : {'confirm_mismatch': true};\r\n }, (g: FormGroup) => {\r\n return g.get('password').value === this.variablesService.appPass ? null : {'pass_mismatch': true};\r\n }]);\r\n }\r\n\r\n ngOnInit() {}\r\n\r\n setTheme(theme) {\r\n this.renderer.removeClass(document.body, 'theme-' + this.theme);\r\n this.theme = theme;\r\n this.variablesService.settings.theme = this.theme;\r\n this.renderer.addClass(document.body, 'theme-' + this.theme);\r\n this.backend.storeAppData();\r\n }\r\n\r\n onSubmitChangePass() {\r\n if (this.changeForm.valid) {\r\n this.variablesService.appPass = this.changeForm.get('new_password').value;\r\n this.backend.storeSecureAppData((status, data) => {\r\n if (status) {\r\n this.changeForm.reset();\r\n } else {\r\n console.log(data);\r\n }\r\n });\r\n }\r\n }\r\n\r\n back() {\r\n this.location.back();\r\n }\r\n\r\n}\r\n","module.exports = \"
\\r\\n
\\r\\n

{{ 'SIDEBAR.TITLE' | translate }}

\\r\\n
\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n
\\r\\n {{ 'SIDEBAR.SYNCHRONIZATION.OFFLINE' | translate }}\\r\\n {{ 'SIDEBAR.SYNCHRONIZATION.SYNCING' | translate }}\\r\\n {{ 'SIDEBAR.SYNCHRONIZATION.ONLINE' | translate }}\\r\\n {{ 'SIDEBAR.SYNCHRONIZATION.LOADING' | translate }}\\r\\n {{ 'SIDEBAR.SYNCHRONIZATION.ERROR' | translate }}\\r\\n {{ 'SIDEBAR.SYNCHRONIZATION.COMPLETE' | translate }}\\r\\n
\\r\\n
\\r\\n
\\r\\n
\\r\\n
\\r\\n
\\r\\n
{{ variablesService.sync.progress_value_text }}%
\\r\\n
\\r\\n
\\r\\n
\\r\\n
\\r\\n\"","module.exports = \":host {\\n display: flex;\\n flex-direction: column;\\n justify-content: space-between;\\n flex: 0 0 25rem;\\n padding: 0 3rem 3rem; }\\n\\n.sidebar-accounts {\\n display: flex;\\n flex-direction: column;\\n flex: 1 1 auto; }\\n\\n.sidebar-accounts .sidebar-accounts-header {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n flex: 0 0 auto;\\n height: 8rem;\\n font-weight: 400; }\\n\\n.sidebar-accounts .sidebar-accounts-header h3 {\\n font-size: 1.7rem; }\\n\\n.sidebar-accounts .sidebar-accounts-header button {\\n background: transparent;\\n border: none;\\n outline: none; }\\n\\n.sidebar-accounts .sidebar-accounts-list {\\n display: flex;\\n flex-direction: column;\\n flex: 1 1 auto;\\n margin: 0 -3rem;\\n overflow-y: overlay; }\\n\\n.sidebar-accounts .sidebar-accounts-list .sidebar-account {\\n display: flex;\\n flex-direction: column;\\n flex-shrink: 0;\\n cursor: pointer;\\n padding: 2rem 3rem; }\\n\\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row {\\n display: flex;\\n align-items: center;\\n justify-content: space-between; }\\n\\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-title-balance {\\n line-height: 2.7rem; }\\n\\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-title-balance .title {\\n font-size: 1.5rem; }\\n\\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-title-balance .balance {\\n font-size: 1.8rem;\\n font-weight: 600; }\\n\\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-alias {\\n font-size: 1.3rem;\\n line-height: 3.4rem;\\n margin-bottom: 0.7rem; }\\n\\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-staking {\\n line-height: 2.9rem; }\\n\\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-staking .text {\\n font-size: 1.3rem; }\\n\\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-messages {\\n line-height: 2.7rem; }\\n\\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-messages .text {\\n font-size: 1.3rem; }\\n\\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-messages .indicator {\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 1rem;\\n font-size: 1rem;\\n min-width: 24px;\\n height: 16px;\\n padding: 0 5px; }\\n\\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-synchronization {\\n flex-direction: column;\\n height: 5.6rem; }\\n\\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-synchronization .status {\\n align-self: flex-start;\\n font-size: 1.3rem;\\n line-height: 2.6rem; }\\n\\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-synchronization .progress-bar-container {\\n display: flex;\\n margin: 0.4rem 0;\\n height: 0.7rem;\\n width: 100%; }\\n\\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-synchronization .progress-bar-container .progress-bar {\\n flex: 1 0 auto; }\\n\\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-synchronization .progress-bar-container .progress-bar .fill {\\n height: 100%; }\\n\\n.sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-synchronization .progress-bar-container .progress-percent {\\n flex: 0 0 auto;\\n font-size: 1.3rem;\\n line-height: 0.7rem;\\n padding-left: 0.7rem; }\\n\\n.sidebar-accounts .sidebar-accounts-list .sidebar-account:focus {\\n outline: none; }\\n\\n.sidebar-settings {\\n flex: 0 0 auto;\\n padding-bottom: 1rem; }\\n\\n.sidebar-settings button {\\n display: flex;\\n align-items: center;\\n background: transparent;\\n border: none;\\n line-height: 3rem;\\n outline: none;\\n padding: 0;\\n font-weight: 400; }\\n\\n.sidebar-settings button .icon {\\n margin-right: 1.2rem;\\n width: 1.7rem;\\n height: 1.7rem; }\\n\\n.sidebar-settings button .icon.settings {\\n -webkit-mask: url('settings.svg') no-repeat center;\\n mask: url('settings.svg') no-repeat center; }\\n\\n.sidebar-settings button .icon.logout {\\n -webkit-mask: url('logout.svg') no-repeat center;\\n mask: url('logout.svg') no-repeat center; }\\n\\n.sidebar-synchronization-status {\\n position: relative;\\n display: flex;\\n align-items: flex-end;\\n justify-content: flex-start;\\n flex: 0 0 4rem;\\n font-size: 1.3rem; }\\n\\n.sidebar-synchronization-status .status-container .offline, .sidebar-synchronization-status .status-container .online {\\n position: relative;\\n display: block;\\n line-height: 1.2rem;\\n padding-left: 2.2rem; }\\n\\n.sidebar-synchronization-status .status-container .offline:before, .sidebar-synchronization-status .status-container .online:before {\\n content: '';\\n position: absolute;\\n top: 0;\\n left: 0;\\n border-radius: 50%;\\n width: 1.2rem;\\n height: 1.2rem; }\\n\\n.sidebar-synchronization-status .status-container .syncing, .sidebar-synchronization-status .status-container .loading {\\n line-height: 4rem; }\\n\\n.sidebar-synchronization-status .progress-bar-container {\\n position: absolute;\\n bottom: -0.7rem;\\n left: 0;\\n height: 0.7rem;\\n width: 100%; }\\n\\n.sidebar-synchronization-status .progress-bar-container .syncing {\\n display: flex; }\\n\\n.sidebar-synchronization-status .progress-bar-container .syncing .progress-bar {\\n flex: 1 0 auto; }\\n\\n.sidebar-synchronization-status .progress-bar-container .syncing .progress-bar .fill {\\n height: 100%; }\\n\\n.sidebar-synchronization-status .progress-bar-container .syncing .progress-percent {\\n flex: 0 0 auto;\\n font-size: 1.3rem;\\n line-height: 0.7rem;\\n padding-left: 0.7rem; }\\n\\n.sidebar-synchronization-status .progress-bar-container .loading {\\n background-image: url('loading.png');\\n height: 100%; }\\n\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvc2lkZWJhci9EOlxcemFuby9zcmNcXGFwcFxcc2lkZWJhclxcc2lkZWJhci5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLGNBQWE7RUFDYix1QkFBc0I7RUFDdEIsK0JBQThCO0VBQzlCLGdCQUFlO0VBQ2YscUJBQW9CLEVBQ3JCOztBQUVEO0VBQ0UsY0FBYTtFQUNiLHVCQUFzQjtFQUN0QixlQUFjLEVBNkhmOztBQWhJRDtJQU1JLGNBQWE7SUFDYixvQkFBbUI7SUFDbkIsK0JBQThCO0lBQzlCLGVBQWM7SUFDZCxhQUFZO0lBQ1osaUJBQWdCLEVBV2pCOztBQXRCSDtNQWNNLGtCQUFpQixFQUNsQjs7QUFmTDtNQWtCTSx3QkFBdUI7TUFDdkIsYUFBWTtNQUNaLGNBQWEsRUFDZDs7QUFyQkw7SUF5QkksY0FBYTtJQUNiLHVCQUFzQjtJQUN0QixlQUFjO0lBQ2QsZ0JBQWU7SUFDZixvQkFBbUIsRUFrR3BCOztBQS9ISDtNQWdDTSxjQUFhO01BQ2IsdUJBQXNCO01BQ3RCLGVBQWM7TUFDZCxnQkFBZTtNQUNmLG1CQUFrQixFQTBGbkI7O0FBOUhMO1FBdUNRLGNBQWE7UUFDYixvQkFBbUI7UUFDbkIsK0JBQThCLEVBZ0YvQjs7QUF6SFA7VUE0Q1Usb0JBQW1CLEVBVXBCOztBQXREVDtZQStDWSxrQkFBaUIsRUFDbEI7O0FBaERYO1lBbURZLGtCQUFpQjtZQUNqQixpQkFBZ0IsRUFDakI7O0FBckRYO1VBeURVLGtCQUFpQjtVQUNqQixvQkFBbUI7VUFDbkIsc0JBQXFCLEVBQ3RCOztBQTVEVDtVQStEVSxvQkFBbUIsRUFLcEI7O0FBcEVUO1lBa0VZLGtCQUFpQixFQUNsQjs7QUFuRVg7VUF1RVUsb0JBQW1CLEVBZ0JwQjs7QUF2RlQ7WUEwRVksa0JBQWlCLEVBQ2xCOztBQTNFWDtZQThFWSxjQUFhO1lBQ2Isb0JBQW1CO1lBQ25CLHdCQUF1QjtZQUN2QixvQkFBbUI7WUFDbkIsZ0JBQWU7WUFDZixnQkFBZTtZQUNmLGFBQVk7WUFDWixlQUFjLEVBQ2Y7O0FBdEZYO1VBMEZVLHVCQUFzQjtVQUN0QixlQUFjLEVBNkJmOztBQXhIVDtZQThGWSx1QkFBc0I7WUFDdEIsa0JBQWlCO1lBQ2pCLG9CQUFtQixFQUNwQjs7QUFqR1g7WUFvR1ksY0FBYTtZQUNiLGlCQUFnQjtZQUNoQixlQUFjO1lBQ2QsWUFBVyxFQWdCWjs7QUF2SFg7Y0EwR2MsZUFBYyxFQUtmOztBQS9HYjtnQkE2R2dCLGFBQVksRUFDYjs7QUE5R2Y7Y0FrSGMsZUFBYztjQUNkLGtCQUFpQjtjQUNqQixvQkFBbUI7Y0FDbkIscUJBQW9CLEVBQ3JCOztBQXRIYjtRQTRIUSxjQUFhLEVBQ2Q7O0FBS1A7RUFDRSxlQUFjO0VBQ2QscUJBQW9CLEVBMEJyQjs7QUE1QkQ7SUFLSSxjQUFhO0lBQ2Isb0JBQW1CO0lBQ25CLHdCQUF1QjtJQUN2QixhQUFZO0lBQ1osa0JBQWlCO0lBQ2pCLGNBQWE7SUFDYixXQUFVO0lBQ1YsaUJBQWdCLEVBZWpCOztBQTNCSDtNQWVNLHFCQUFvQjtNQUNwQixjQUFhO01BQ2IsZUFBYyxFQVNmOztBQTFCTDtRQW9CUSxtREFBMkQ7Z0JBQTNELDJDQUEyRCxFQUM1RDs7QUFyQlA7UUF3QlEsaURBQXlEO2dCQUF6RCx5Q0FBeUQsRUFDMUQ7O0FBS1A7RUFDRSxtQkFBa0I7RUFDbEIsY0FBYTtFQUNiLHNCQUFxQjtFQUNyQiw0QkFBMkI7RUFDM0IsZUFBYztFQUNkLGtCQUFpQixFQXlEbEI7O0FBL0REO0lBV00sbUJBQWtCO0lBQ2xCLGVBQWM7SUFDZCxvQkFBbUI7SUFDbkIscUJBQW9CLEVBV3JCOztBQXpCTDtNQWlCUSxZQUFXO01BQ1gsbUJBQWtCO01BQ2xCLE9BQU07TUFDTixRQUFPO01BQ1AsbUJBQWtCO01BQ2xCLGNBQWE7TUFDYixlQUFjLEVBQ2Y7O0FBeEJQO0lBNEJNLGtCQUFpQixFQUNsQjs7QUE3Qkw7SUFpQ0ksbUJBQWtCO0lBQ2xCLGdCQUFlO0lBQ2YsUUFBTztJQUNQLGVBQWM7SUFDZCxZQUFXLEVBeUJaOztBQTlESDtNQXdDTSxjQUFhLEVBZ0JkOztBQXhETDtRQTJDUSxlQUFjLEVBS2Y7O0FBaERQO1VBOENVLGFBQVksRUFDYjs7QUEvQ1Q7UUFtRFEsZUFBYztRQUNkLGtCQUFpQjtRQUNqQixvQkFBbUI7UUFDbkIscUJBQW9CLEVBQ3JCOztBQXZEUDtNQTJETSxxQ0FBd0Q7TUFDeEQsYUFBWSxFQUNiIiwiZmlsZSI6InNyYy9hcHAvc2lkZWJhci9zaWRlYmFyLmNvbXBvbmVudC5zY3NzIiwic291cmNlc0NvbnRlbnQiOlsiOmhvc3Qge1xyXG4gIGRpc3BsYXk6IGZsZXg7XHJcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XHJcbiAgZmxleDogMCAwIDI1cmVtO1xyXG4gIHBhZGRpbmc6IDAgM3JlbSAzcmVtO1xyXG59XHJcblxyXG4uc2lkZWJhci1hY2NvdW50cyB7XHJcbiAgZGlzcGxheTogZmxleDtcclxuICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xyXG4gIGZsZXg6IDEgMSBhdXRvO1xyXG5cclxuICAuc2lkZWJhci1hY2NvdW50cy1oZWFkZXIge1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAgICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XHJcbiAgICBmbGV4OiAwIDAgYXV0bztcclxuICAgIGhlaWdodDogOHJlbTtcclxuICAgIGZvbnQtd2VpZ2h0OiA0MDA7XHJcblxyXG4gICAgaDMge1xyXG4gICAgICBmb250LXNpemU6IDEuN3JlbTtcclxuICAgIH1cclxuXHJcbiAgICBidXR0b24ge1xyXG4gICAgICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudDtcclxuICAgICAgYm9yZGVyOiBub25lO1xyXG4gICAgICBvdXRsaW5lOiBub25lO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLnNpZGViYXItYWNjb3VudHMtbGlzdCB7XHJcbiAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICAgIGZsZXg6IDEgMSBhdXRvO1xyXG4gICAgbWFyZ2luOiAwIC0zcmVtO1xyXG4gICAgb3ZlcmZsb3cteTogb3ZlcmxheTtcclxuXHJcbiAgICAuc2lkZWJhci1hY2NvdW50IHtcclxuICAgICAgZGlzcGxheTogZmxleDtcclxuICAgICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICAgICAgZmxleC1zaHJpbms6IDA7XHJcbiAgICAgIGN1cnNvcjogcG9pbnRlcjtcclxuICAgICAgcGFkZGluZzogMnJlbSAzcmVtO1xyXG5cclxuICAgICAgLnNpZGViYXItYWNjb3VudC1yb3cge1xyXG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuICAgICAgICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XHJcblxyXG4gICAgICAgICYuYWNjb3VudC10aXRsZS1iYWxhbmNlIHtcclxuICAgICAgICAgIGxpbmUtaGVpZ2h0OiAyLjdyZW07XHJcblxyXG4gICAgICAgICAgLnRpdGxlIHtcclxuICAgICAgICAgICAgZm9udC1zaXplOiAxLjVyZW07XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgLmJhbGFuY2Uge1xyXG4gICAgICAgICAgICBmb250LXNpemU6IDEuOHJlbTtcclxuICAgICAgICAgICAgZm9udC13ZWlnaHQ6IDYwMDtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgICYuYWNjb3VudC1hbGlhcyB7XHJcbiAgICAgICAgICBmb250LXNpemU6IDEuM3JlbTtcclxuICAgICAgICAgIGxpbmUtaGVpZ2h0OiAzLjRyZW07XHJcbiAgICAgICAgICBtYXJnaW4tYm90dG9tOiAwLjdyZW07XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAmLmFjY291bnQtc3Rha2luZyB7XHJcbiAgICAgICAgICBsaW5lLWhlaWdodDogMi45cmVtO1xyXG5cclxuICAgICAgICAgIC50ZXh0IHtcclxuICAgICAgICAgICAgZm9udC1zaXplOiAxLjNyZW07XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAmLmFjY291bnQtbWVzc2FnZXMge1xyXG4gICAgICAgICAgbGluZS1oZWlnaHQ6IDIuN3JlbTtcclxuXHJcbiAgICAgICAgICAudGV4dCB7XHJcbiAgICAgICAgICAgIGZvbnQtc2l6ZTogMS4zcmVtO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIC5pbmRpY2F0b3Ige1xyXG4gICAgICAgICAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgICAgICAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAgICAgICAgICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcclxuICAgICAgICAgICAgYm9yZGVyLXJhZGl1czogMXJlbTtcclxuICAgICAgICAgICAgZm9udC1zaXplOiAxcmVtO1xyXG4gICAgICAgICAgICBtaW4td2lkdGg6IDI0cHg7XHJcbiAgICAgICAgICAgIGhlaWdodDogMTZweDtcclxuICAgICAgICAgICAgcGFkZGluZzogMCA1cHg7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAmLmFjY291bnQtc3luY2hyb25pemF0aW9uIHtcclxuICAgICAgICAgIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XHJcbiAgICAgICAgICBoZWlnaHQ6IDUuNnJlbTtcclxuXHJcbiAgICAgICAgICAuc3RhdHVzIHtcclxuICAgICAgICAgICAgYWxpZ24tc2VsZjogZmxleC1zdGFydDtcclxuICAgICAgICAgICAgZm9udC1zaXplOiAxLjNyZW07XHJcbiAgICAgICAgICAgIGxpbmUtaGVpZ2h0OiAyLjZyZW07XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgLnByb2dyZXNzLWJhci1jb250YWluZXIge1xyXG4gICAgICAgICAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgICAgICAgICBtYXJnaW46IDAuNHJlbSAwO1xyXG4gICAgICAgICAgICBoZWlnaHQ6IDAuN3JlbTtcclxuICAgICAgICAgICAgd2lkdGg6IDEwMCU7XHJcblxyXG4gICAgICAgICAgICAucHJvZ3Jlc3MtYmFyIHtcclxuICAgICAgICAgICAgICBmbGV4OiAxIDAgYXV0bztcclxuXHJcbiAgICAgICAgICAgICAgLmZpbGwge1xyXG4gICAgICAgICAgICAgICAgaGVpZ2h0OiAxMDAlO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLnByb2dyZXNzLXBlcmNlbnQge1xyXG4gICAgICAgICAgICAgIGZsZXg6IDAgMCBhdXRvO1xyXG4gICAgICAgICAgICAgIGZvbnQtc2l6ZTogMS4zcmVtO1xyXG4gICAgICAgICAgICAgIGxpbmUtaGVpZ2h0OiAwLjdyZW07XHJcbiAgICAgICAgICAgICAgcGFkZGluZy1sZWZ0OiAwLjdyZW07XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICY6Zm9jdXMge1xyXG4gICAgICAgIG91dGxpbmU6IG5vbmU7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbi5zaWRlYmFyLXNldHRpbmdzIHtcclxuICBmbGV4OiAwIDAgYXV0bztcclxuICBwYWRkaW5nLWJvdHRvbTogMXJlbTtcclxuXHJcbiAgYnV0dG9uIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAgYmFja2dyb3VuZDogdHJhbnNwYXJlbnQ7XHJcbiAgICBib3JkZXI6IG5vbmU7XHJcbiAgICBsaW5lLWhlaWdodDogM3JlbTtcclxuICAgIG91dGxpbmU6IG5vbmU7XHJcbiAgICBwYWRkaW5nOiAwO1xyXG4gICAgZm9udC13ZWlnaHQ6IDQwMDtcclxuXHJcbiAgICAuaWNvbiB7XHJcbiAgICAgIG1hcmdpbi1yaWdodDogMS4ycmVtO1xyXG4gICAgICB3aWR0aDogMS43cmVtO1xyXG4gICAgICBoZWlnaHQ6IDEuN3JlbTtcclxuXHJcbiAgICAgICYuc2V0dGluZ3Mge1xyXG4gICAgICAgIG1hc2s6IHVybCguLi8uLi9hc3NldHMvaWNvbnMvc2V0dGluZ3Muc3ZnKSBuby1yZXBlYXQgY2VudGVyO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAmLmxvZ291dCB7XHJcbiAgICAgICAgbWFzazogdXJsKC4uLy4uL2Fzc2V0cy9pY29ucy9sb2dvdXQuc3ZnKSBuby1yZXBlYXQgY2VudGVyO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcblxyXG4uc2lkZWJhci1zeW5jaHJvbml6YXRpb24tc3RhdHVzIHtcclxuICBwb3NpdGlvbjogcmVsYXRpdmU7XHJcbiAgZGlzcGxheTogZmxleDtcclxuICBhbGlnbi1pdGVtczogZmxleC1lbmQ7XHJcbiAganVzdGlmeS1jb250ZW50OiBmbGV4LXN0YXJ0O1xyXG4gIGZsZXg6IDAgMCA0cmVtO1xyXG4gIGZvbnQtc2l6ZTogMS4zcmVtO1xyXG5cclxuICAuc3RhdHVzLWNvbnRhaW5lciB7XHJcblxyXG4gICAgLm9mZmxpbmUsIC5vbmxpbmUge1xyXG4gICAgICBwb3NpdGlvbjogcmVsYXRpdmU7XHJcbiAgICAgIGRpc3BsYXk6IGJsb2NrO1xyXG4gICAgICBsaW5lLWhlaWdodDogMS4ycmVtO1xyXG4gICAgICBwYWRkaW5nLWxlZnQ6IDIuMnJlbTtcclxuXHJcbiAgICAgICY6YmVmb3JlIHtcclxuICAgICAgICBjb250ZW50OiAnJztcclxuICAgICAgICBwb3NpdGlvbjogYWJzb2x1dGU7XHJcbiAgICAgICAgdG9wOiAwO1xyXG4gICAgICAgIGxlZnQ6IDA7XHJcbiAgICAgICAgYm9yZGVyLXJhZGl1czogNTAlO1xyXG4gICAgICAgIHdpZHRoOiAxLjJyZW07XHJcbiAgICAgICAgaGVpZ2h0OiAxLjJyZW07XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAuc3luY2luZywgLmxvYWRpbmcge1xyXG4gICAgICBsaW5lLWhlaWdodDogNHJlbTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC5wcm9ncmVzcy1iYXItY29udGFpbmVyIHtcclxuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcclxuICAgIGJvdHRvbTogLTAuN3JlbTtcclxuICAgIGxlZnQ6IDA7XHJcbiAgICBoZWlnaHQ6IDAuN3JlbTtcclxuICAgIHdpZHRoOiAxMDAlO1xyXG5cclxuICAgIC5zeW5jaW5nIHtcclxuICAgICAgZGlzcGxheTogZmxleDtcclxuXHJcbiAgICAgIC5wcm9ncmVzcy1iYXIge1xyXG4gICAgICAgIGZsZXg6IDEgMCBhdXRvO1xyXG5cclxuICAgICAgICAuZmlsbCB7XHJcbiAgICAgICAgICBoZWlnaHQ6IDEwMCU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICAucHJvZ3Jlc3MtcGVyY2VudCB7XHJcbiAgICAgICAgZmxleDogMCAwIGF1dG87XHJcbiAgICAgICAgZm9udC1zaXplOiAxLjNyZW07XHJcbiAgICAgICAgbGluZS1oZWlnaHQ6IDAuN3JlbTtcclxuICAgICAgICBwYWRkaW5nLWxlZnQ6IDAuN3JlbTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC5sb2FkaW5nIHtcclxuICAgICAgYmFja2dyb3VuZC1pbWFnZTogdXJsKFwiLi4vLi4vYXNzZXRzL2ltYWdlcy9sb2FkaW5nLnBuZ1wiKTtcclxuICAgICAgaGVpZ2h0OiAxMDAlO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG4iXX0= */\"","import {Component, OnInit, OnDestroy} from '@angular/core';\r\nimport {ActivatedRoute, NavigationStart, Router} from '@angular/router';\r\nimport {VariablesService} from '../_helpers/services/variables.service';\r\n\r\n@Component({\r\n selector: 'app-sidebar',\r\n templateUrl: './sidebar.component.html',\r\n styleUrls: ['./sidebar.component.scss']\r\n})\r\nexport class SidebarComponent implements OnInit, OnDestroy {\r\n walletActiveSubDirectory = '';\r\n walletSubRouting;\r\n\r\n walletActive: number;\r\n\r\n constructor(\r\n private route: ActivatedRoute,\r\n private router: Router,\r\n private variablesService: VariablesService\r\n ) {\r\n }\r\n\r\n ngOnInit() {\r\n if (this.router.url.indexOf('/wallet/') !== -1) {\r\n const localPathArr = this.router.url.split('/');\r\n if (localPathArr.length >= 3) {\r\n this.walletActive = parseInt(localPathArr[2], 10);\r\n }\r\n if (localPathArr.length >= 4) {\r\n this.walletActiveSubDirectory = localPathArr[3];\r\n }\r\n } else if (this.router.url.indexOf('/details') !== -1) {\r\n this.walletActive = this.variablesService.currentWallet.wallet_id;\r\n } else {\r\n this.walletActive = null;\r\n }\r\n\r\n this.walletSubRouting = this.router.events.subscribe((event) => {\r\n if (event instanceof NavigationStart) {\r\n if (event.url.indexOf('/wallet/') !== -1) {\r\n const localPathArr = event.url.split('/');\r\n if (localPathArr.length >= 3) {\r\n this.walletActive = parseInt(localPathArr[2], 10);\r\n }\r\n if (localPathArr.length >= 4) {\r\n this.walletActiveSubDirectory = localPathArr[3];\r\n if (this.walletActiveSubDirectory === 'purchase') {\r\n this.walletActiveSubDirectory = 'contracts';\r\n }\r\n }\r\n } else if (event.url.indexOf('/details') !== -1) {\r\n this.walletActive = this.variablesService.currentWallet.wallet_id;\r\n } else {\r\n this.walletActive = null;\r\n }\r\n }\r\n });\r\n }\r\n\r\n ngOnDestroy() {\r\n this.walletSubRouting.unsubscribe();\r\n }\r\n\r\n logOut() {\r\n this.variablesService.stopCountdown();\r\n this.variablesService.appPass = '';\r\n this.router.navigate(['/login'], {queryParams: {type: 'auth'}});\r\n }\r\n\r\n}\r\n","module.exports = \"
\\r\\n
\\r\\n
\\r\\n Staking\\r\\n \\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n Pending\\r\\n {{pending.total | intToMoney}} {{variablesService.defaultCurrency}}\\r\\n
\\r\\n
\\r\\n Total\\r\\n {{total | intToMoney}} {{variablesService.defaultCurrency}}\\r\\n
\\r\\n
\\r\\n
\\r\\n {{selectedDate.date | date : 'MMM. EEEE, dd, yyyy'}}\\r\\n {{selectedDate.amount}} {{variablesService.defaultCurrency}}\\r\\n
\\r\\n
\\r\\n\\r\\n
\\r\\n\\r\\n
\\r\\n\\r\\n
\\r\\n\\r\\n
\\r\\n
\\r\\n Time period:\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n\"","module.exports = \":host {\\n display: flex;\\n flex-direction: column;\\n width: 100%; }\\n\\n.chart-header {\\n display: flex;\\n flex: 0 0 auto; }\\n\\n.chart-header .general {\\n display: flex;\\n flex-direction: column;\\n align-items: flex-start;\\n justify-content: center;\\n flex-grow: 1;\\n font-size: 1.3rem;\\n margin: -0.5rem 0; }\\n\\n.chart-header .general > div {\\n display: flex;\\n align-items: center;\\n margin: 0.5rem 0;\\n height: 2rem; }\\n\\n.chart-header .general > div .label {\\n display: inline-block;\\n width: 9rem; }\\n\\n.chart-header .selected {\\n display: flex;\\n flex-direction: column;\\n align-items: flex-end;\\n justify-content: center;\\n flex-grow: 1;\\n font-size: 1.8rem; }\\n\\n.chart-header .selected span {\\n line-height: 2.9rem; }\\n\\n.chart {\\n display: flex;\\n align-items: center;\\n flex: 1 1 auto;\\n min-height: 40rem; }\\n\\n.chart > div {\\n width: 100%;\\n height: 100%; }\\n\\n.chart-options {\\n display: flex;\\n align-items: center;\\n height: 2.4rem;\\n flex: 0 0 auto; }\\n\\n.chart-options .title {\\n font-size: 1.3rem;\\n width: 9rem; }\\n\\n.chart-options .options {\\n display: flex;\\n justify-content: space-between;\\n flex-grow: 1;\\n height: 100%; }\\n\\n.chart-options .options button {\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n flex: 1 1 auto;\\n cursor: pointer;\\n font-size: 1.3rem;\\n margin: 0 0.1rem;\\n padding: 0;\\n height: 100%; }\\n\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvc3Rha2luZy9EOlxcemFuby9zcmNcXGFwcFxcc3Rha2luZ1xcc3Rha2luZy5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLGNBQWE7RUFDYix1QkFBc0I7RUFDdEIsWUFBVyxFQUNaOztBQUVEO0VBQ0UsY0FBYTtFQUNiLGVBQWMsRUFvQ2Y7O0FBdENEO0lBS0ksY0FBYTtJQUNiLHVCQUFzQjtJQUN0Qix3QkFBdUI7SUFDdkIsd0JBQXVCO0lBQ3ZCLGFBQVk7SUFDWixrQkFBaUI7SUFDakIsa0JBQWlCLEVBYWxCOztBQXhCSDtNQWNNLGNBQWE7TUFDYixvQkFBbUI7TUFDbkIsaUJBQWdCO01BQ2hCLGFBQVksRUFNYjs7QUF2Qkw7UUFvQlEsc0JBQXFCO1FBQ3JCLFlBQVcsRUFDWjs7QUF0QlA7SUEyQkksY0FBYTtJQUNiLHVCQUFzQjtJQUN0QixzQkFBcUI7SUFDckIsd0JBQXVCO0lBQ3ZCLGFBQVk7SUFDWixrQkFBaUIsRUFLbEI7O0FBckNIO01BbUNNLG9CQUFtQixFQUNwQjs7QUFJTDtFQUNFLGNBQWE7RUFDYixvQkFBbUI7RUFDbkIsZUFBYztFQUNkLGtCQUFpQixFQU1sQjs7QUFWRDtJQU9JLFlBQVc7SUFDWCxhQUFZLEVBQ2I7O0FBR0g7RUFDRSxjQUFhO0VBQ2Isb0JBQW1CO0VBQ25CLGVBQWM7RUFDZCxlQUFjLEVBeUJmOztBQTdCRDtJQU9JLGtCQUFpQjtJQUNqQixZQUFXLEVBQ1o7O0FBVEg7SUFZSSxjQUFhO0lBQ2IsK0JBQThCO0lBQzlCLGFBQVk7SUFDWixhQUFZLEVBYWI7O0FBNUJIO01Ba0JNLGNBQWE7TUFDYixvQkFBbUI7TUFDbkIsd0JBQXVCO01BQ3ZCLGVBQWM7TUFDZCxnQkFBZTtNQUNmLGtCQUFpQjtNQUNqQixpQkFBZ0I7TUFDaEIsV0FBVTtNQUNWLGFBQVksRUFDYiIsImZpbGUiOiJzcmMvYXBwL3N0YWtpbmcvc3Rha2luZy5jb21wb25lbnQuc2NzcyIsInNvdXJjZXNDb250ZW50IjpbIjpob3N0IHtcclxuICBkaXNwbGF5OiBmbGV4O1xyXG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XHJcbiAgd2lkdGg6IDEwMCU7XHJcbn1cclxuXHJcbi5jaGFydC1oZWFkZXIge1xyXG4gIGRpc3BsYXk6IGZsZXg7XHJcbiAgZmxleDogMCAwIGF1dG87XHJcblxyXG4gIC5nZW5lcmFsIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xyXG4gICAgYWxpZ24taXRlbXM6IGZsZXgtc3RhcnQ7XHJcbiAgICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcclxuICAgIGZsZXgtZ3JvdzogMTtcclxuICAgIGZvbnQtc2l6ZTogMS4zcmVtO1xyXG4gICAgbWFyZ2luOiAtMC41cmVtIDA7XHJcblxyXG4gICAgPiBkaXYge1xyXG4gICAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAgICBtYXJnaW46IDAuNXJlbSAwO1xyXG4gICAgICBoZWlnaHQ6IDJyZW07XHJcblxyXG4gICAgICAubGFiZWwge1xyXG4gICAgICAgIGRpc3BsYXk6IGlubGluZS1ibG9jaztcclxuICAgICAgICB3aWR0aDogOXJlbTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLnNlbGVjdGVkIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xyXG4gICAgYWxpZ24taXRlbXM6IGZsZXgtZW5kO1xyXG4gICAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XHJcbiAgICBmbGV4LWdyb3c6IDE7XHJcbiAgICBmb250LXNpemU6IDEuOHJlbTtcclxuXHJcbiAgICBzcGFuIHtcclxuICAgICAgbGluZS1oZWlnaHQ6IDIuOXJlbTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbi5jaGFydCB7XHJcbiAgZGlzcGxheTogZmxleDtcclxuICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gIGZsZXg6IDEgMSBhdXRvO1xyXG4gIG1pbi1oZWlnaHQ6IDQwcmVtO1xyXG5cclxuICA+IGRpdiB7XHJcbiAgICB3aWR0aDogMTAwJTtcclxuICAgIGhlaWdodDogMTAwJTtcclxuICB9XHJcbn1cclxuXHJcbi5jaGFydC1vcHRpb25zIHtcclxuICBkaXNwbGF5OiBmbGV4O1xyXG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAgaGVpZ2h0OiAyLjRyZW07XHJcbiAgZmxleDogMCAwIGF1dG87XHJcblxyXG4gIC50aXRsZSB7XHJcbiAgICBmb250LXNpemU6IDEuM3JlbTtcclxuICAgIHdpZHRoOiA5cmVtO1xyXG4gIH1cclxuXHJcbiAgLm9wdGlvbnMge1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuICAgIGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjtcclxuICAgIGZsZXgtZ3JvdzogMTtcclxuICAgIGhlaWdodDogMTAwJTtcclxuXHJcbiAgICBidXR0b24ge1xyXG4gICAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAgICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcclxuICAgICAgZmxleDogMSAxIGF1dG87XHJcbiAgICAgIGN1cnNvcjogcG9pbnRlcjtcclxuICAgICAgZm9udC1zaXplOiAxLjNyZW07XHJcbiAgICAgIG1hcmdpbjogMCAwLjFyZW07XHJcbiAgICAgIHBhZGRpbmc6IDA7XHJcbiAgICAgIGhlaWdodDogMTAwJTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuIl19 */\"","import {Component, NgZone, OnInit, OnDestroy} from '@angular/core';\r\nimport {VariablesService} from '../_helpers/services/variables.service';\r\nimport {Chart} from 'angular-highcharts';\r\nimport {BackendService} from '../_helpers/services/backend.service';\r\nimport {ActivatedRoute} from '@angular/router';\r\nimport {IntToMoneyPipe} from '../_helpers/pipes/int-to-money.pipe';\r\n\r\n@Component({\r\n selector: 'app-staking',\r\n templateUrl: './staking.component.html',\r\n styleUrls: ['./staking.component.scss']\r\n})\r\nexport class StakingComponent implements OnInit, OnDestroy {\r\n\r\n parentRouting;\r\n heightAppEvent;\r\n refreshStackingEvent;\r\n\r\n periods = [\r\n {\r\n title: '1 day',\r\n active: false\r\n },\r\n {\r\n title: '1 week',\r\n active: false\r\n },\r\n {\r\n title: '1 month',\r\n active: false\r\n },\r\n {\r\n title: '1 year',\r\n active: false\r\n },\r\n {\r\n title: 'All',\r\n active: true\r\n }\r\n ];\r\n\r\n selectedDate = {\r\n date: null,\r\n amount: null\r\n };\r\n\r\n originalData = [];\r\n\r\n chart: Chart;\r\n\r\n total = 0;\r\n pending = {\r\n list: [],\r\n total: 0\r\n };\r\n\r\n constructor(\r\n private route: ActivatedRoute,\r\n private variablesService: VariablesService,\r\n private backend: BackendService,\r\n private ngZone: NgZone,\r\n private intToMoneyPipe: IntToMoneyPipe\r\n ) {\r\n }\r\n\r\n\r\n ngOnInit() {\r\n this.parentRouting = this.route.parent.params.subscribe(() => {\r\n this.getMiningHistory();\r\n });\r\n this.heightAppEvent = this.variablesService.getHeightAppEvent.subscribe((newHeight: number) => {\r\n if (this.pending.total) {\r\n const pendingCount = this.pending.list.length;\r\n for (let i = pendingCount - 1; i >= 0; i--) {\r\n if (newHeight - this.pending.list[i].h >= 10) {\r\n this.pending.list.splice(i, 1);\r\n }\r\n }\r\n if (pendingCount !== this.pending.list.length) {\r\n this.pending.total = 0;\r\n for (let i = 0; i < this.pending.list.length; i++) {\r\n this.pending.total += this.pending.list[i].a;\r\n }\r\n }\r\n }\r\n });\r\n this.refreshStackingEvent = this.variablesService.getRefreshStackingEvent.subscribe((wallet_id: number) => {\r\n if (this.variablesService.currentWallet.wallet_id === wallet_id) {\r\n this.getMiningHistory();\r\n }\r\n });\r\n }\r\n\r\n\r\n drawChart(data) {\r\n this.chart = new Chart({\r\n title: {text: ''},\r\n credits: {enabled: false},\r\n exporting: {enabled: false},\r\n legend: {enabled: false},\r\n chart: {\r\n type: 'line',\r\n backgroundColor: 'transparent',\r\n height: null,\r\n zoomType: null\r\n },\r\n\r\n yAxis: {\r\n min: 0,\r\n tickAmount: 5,\r\n title: {\r\n text: ''\r\n },\r\n gridLineColor: '#2b3644',\r\n gridLineWidth: 2,\r\n lineColor: '#2b3644',\r\n lineWidth: 2,\r\n tickWidth: 2,\r\n tickLength: 120,\r\n tickColor: '#2b3644',\r\n labels: {\r\n y: -8,\r\n align: 'left',\r\n x: -120,\r\n style: {\r\n 'color': '#e0e0e0',\r\n 'fontSize': '13px'\r\n },\r\n format: '{value} ' + this.variablesService.defaultCurrency\r\n },\r\n showLastLabel: false,\r\n },\r\n\r\n xAxis: {\r\n type: 'datetime',\r\n gridLineColor: '#2b3644',\r\n lineColor: '#2b3644',\r\n lineWidth: 2,\r\n tickWidth: 2,\r\n tickLength: 10,\r\n tickColor: '#2b3644',\r\n labels: {\r\n style: {\r\n 'color': '#e0e0e0',\r\n 'fontSize': '13px'\r\n }\r\n },\r\n minPadding: 0,\r\n maxPadding: 0,\r\n minRange: 86400000,\r\n // tickInterval: 86400000,\r\n minTickInterval: 3600000,\r\n },\r\n\r\n tooltip: {\r\n enabled: false\r\n },\r\n\r\n plotOptions: {\r\n area: {\r\n fillColor: {\r\n linearGradient: {\r\n x1: 0,\r\n y1: 0,\r\n x2: 0,\r\n y2: 1\r\n },\r\n stops: [\r\n [0, 'rgba(124,181,236,0.2)'],\r\n [1, 'rgba(124,181,236,0)']\r\n ]\r\n },\r\n marker: {\r\n enabled: false,\r\n radius: 2\r\n },\r\n lineWidth: 2,\r\n threshold: null\r\n },\r\n\r\n series: {\r\n point: {\r\n events: {\r\n mouseOver: (obj) => {\r\n this.selectedDate.date = obj.target['x'];\r\n this.selectedDate.amount = obj.target['y'];\r\n }\r\n }\r\n },\r\n events: {\r\n mouseOut: () => {\r\n this.selectedDate.date = null;\r\n this.selectedDate.amount = null;\r\n }\r\n }\r\n }\r\n },\r\n series: [\r\n {\r\n type: 'area',\r\n data: data\r\n }\r\n ]\r\n });\r\n }\r\n\r\n\r\n getMiningHistory() {\r\n if (this.variablesService.currentWallet.loaded) {\r\n this.backend.getMiningHistory(this.variablesService.currentWallet.wallet_id, (status, data) => {\r\n this.total = 0;\r\n this.pending.list = [];\r\n this.pending.total = 0;\r\n this.originalData = [];\r\n if (data.mined_entries) {\r\n data.mined_entries.forEach((item, key) => {\r\n if (item.t.toString().length === 10) {\r\n data.mined_entries[key].t = (new Date(item.t * 1000)).setUTCMilliseconds(0);\r\n }\r\n });\r\n data.mined_entries.forEach((item) => {\r\n this.total += item.a;\r\n if (this.variablesService.height_app - item.h < 10) {\r\n this.pending.list.push(item);\r\n this.pending.total += item.a;\r\n }\r\n this.originalData.push([parseInt(item.t, 10), parseFloat(this.intToMoneyPipe.transform(item.a))]);\r\n });\r\n this.originalData = this.originalData.sort(function (a, b) {\r\n return a[0] - b[0];\r\n });\r\n }\r\n this.ngZone.run(() => {\r\n this.drawChart(JSON.parse(JSON.stringify(this.originalData)));\r\n });\r\n });\r\n }\r\n\r\n }\r\n\r\n changePeriod(period) {\r\n this.periods.forEach((p) => {\r\n p.active = false;\r\n });\r\n period.active = true;\r\n\r\n const d = new Date();\r\n let min = null;\r\n const newData = [];\r\n\r\n if (period.title === '1 day') {\r\n this.originalData.forEach((item) => {\r\n const time = (new Date(item[0])).setUTCMinutes(0, 0, 0);\r\n const find = newData.find(itemNew => itemNew[0] === time);\r\n if (find) {\r\n find[1] += item[1];\r\n } else {\r\n newData.push([time, item[1]]);\r\n }\r\n });\r\n this.chart.ref.series[0].setData(newData, true);\r\n min = Date.UTC(d.getFullYear(), d.getMonth(), d.getDate() - 1, 0, 0, 0, 0);\r\n } else if (period.title === '1 week') {\r\n this.originalData.forEach((item) => {\r\n const time = (new Date(item[0])).setUTCHours(0, 0, 0, 0);\r\n const find = newData.find(itemNew => itemNew[0] === time);\r\n if (find) {\r\n find[1] += item[1];\r\n } else {\r\n newData.push([time, item[1]]);\r\n }\r\n });\r\n this.chart.ref.series[0].setData(newData, true);\r\n min = Date.UTC(d.getFullYear(), d.getMonth(), d.getDate() - 7, 0, 0, 0, 0);\r\n } else if (period.title === '1 month') {\r\n this.originalData.forEach((item) => {\r\n const time = (new Date(item[0])).setUTCHours(0, 0, 0, 0);\r\n const find = newData.find(itemNew => itemNew[0] === time);\r\n if (find) {\r\n find[1] += item[1];\r\n } else {\r\n newData.push([time, item[1]]);\r\n }\r\n });\r\n this.chart.ref.series[0].setData(newData, true);\r\n min = Date.UTC(d.getFullYear(), d.getMonth() - 1, d.getDate(), 0, 0, 0, 0);\r\n } else if (period.title === '1 year') {\r\n this.originalData.forEach((item) => {\r\n const time = (new Date(item[0])).setUTCHours(0, 0, 0, 0);\r\n const find = newData.find(itemNew => itemNew[0] === time);\r\n if (find) {\r\n find[1] += item[1];\r\n } else {\r\n newData.push([time, item[1]]);\r\n }\r\n });\r\n this.chart.ref.series[0].setData(newData, true);\r\n min = Date.UTC(d.getFullYear() - 1, d.getMonth(), d.getDate(), 0, 0, 0, 0);\r\n } else {\r\n this.chart.ref.series[0].setData(this.originalData, true);\r\n }\r\n\r\n this.chart.ref.xAxis[0].setExtremes(min, null);\r\n }\r\n\r\n\r\n ngOnDestroy() {\r\n this.parentRouting.unsubscribe();\r\n this.heightAppEvent.unsubscribe();\r\n this.refreshStackingEvent.unsubscribe();\r\n }\r\n\r\n}\r\n","module.exports = \"
\\r\\n
\\r\\n @bitmain\\r\\n
\\r\\n \\r\\n \\r\\n {{ 'COMMON.BACK' | translate }}\\r\\n \\r\\n
\\r\\n\\r\\n
\\r\\n
\\r\\n
10:39
\\r\\n
\\r\\n Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\\r\\n
\\r\\n
\\r\\n Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\\r\\n
\\r\\n
\\r\\n Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\\r\\n
\\r\\n
\\r\\n Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\\r\\n
\\r\\n
11:44
\\r\\n
\\r\\n Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\\r\\n
\\r\\n
\\r\\n Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\\r\\n
\\r\\n
\\r\\n Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\\r\\n
\\r\\n
12:15
\\r\\n
\\r\\n Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\\r\\n
\\r\\n
\\r\\n Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\\r\\n
\\r\\n
\\r\\n Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\\r\\n
\\r\\n
13:13
\\r\\n
\\r\\n Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\\r\\n
\\r\\n
\\r\\n Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\\r\\n
\\r\\n
\\r\\n Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\\r\\n
\\r\\n
\\r\\n
\\r\\n
\\r\\n \\r\\n
\\r\\n \\r\\n
\\r\\n
\\r\\n\"","module.exports = \":host {\\n display: flex;\\n flex-direction: column;\\n width: 100%; }\\n\\n.head {\\n flex: 0 0 auto;\\n box-sizing: content-box;\\n margin: -3rem -3rem 0; }\\n\\n.messages-content {\\n display: flex;\\n flex-direction: column;\\n justify-content: space-between;\\n flex-grow: 1; }\\n\\n.messages-content .messages-list {\\n display: flex;\\n flex-direction: column;\\n font-size: 1.3rem;\\n margin: 1rem -3rem;\\n padding: 0 3rem;\\n overflow-y: overlay; }\\n\\n.messages-content .messages-list div {\\n margin: 0.7rem 0; }\\n\\n.messages-content .messages-list div.date {\\n text-align: center; }\\n\\n.messages-content .messages-list div.my, .messages-content .messages-list div.buddy {\\n position: relative;\\n padding: 1.8rem;\\n max-width: 60%; }\\n\\n.messages-content .messages-list div.buddy {\\n align-self: flex-end; }\\n\\n.messages-content .type-message {\\n display: flex;\\n flex: 0 0 auto;\\n width: 100%;\\n height: 4.2rem; }\\n\\n.messages-content .type-message .input-block {\\n width: 100%; }\\n\\n.messages-content .type-message .input-block > textarea {\\n min-height: 4.2rem; }\\n\\n.messages-content .type-message button {\\n flex: 0 0 15rem; }\\n\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvdHlwaW5nLW1lc3NhZ2UvRDpcXHphbm8vc3JjXFxhcHBcXHR5cGluZy1tZXNzYWdlXFx0eXBpbmctbWVzc2FnZS5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLGNBQWE7RUFDYix1QkFBc0I7RUFDdEIsWUFBVyxFQUNaOztBQUVEO0VBQ0UsZUFBYztFQUNkLHdCQUF1QjtFQUN2QixzQkFBcUIsRUFDdEI7O0FBRUQ7RUFDRSxjQUFhO0VBQ2IsdUJBQXNCO0VBQ3RCLCtCQUE4QjtFQUM5QixhQUFZLEVBK0NiOztBQW5ERDtJQU9JLGNBQWE7SUFDYix1QkFBc0I7SUFDdEIsa0JBQWlCO0lBQ2pCLG1CQUFrQjtJQUNsQixnQkFBZTtJQUNmLG9CQUFtQixFQW1CcEI7O0FBL0JIO01BZU0saUJBQWdCLEVBZWpCOztBQTlCTDtRQWtCUSxtQkFBa0IsRUFDbkI7O0FBbkJQO1FBc0JRLG1CQUFrQjtRQUNsQixnQkFBZTtRQUNmLGVBQWMsRUFDZjs7QUF6QlA7UUE0QlEscUJBQW9CLEVBQ3JCOztBQTdCUDtJQWtDSSxjQUFhO0lBQ2IsZUFBYztJQUNkLFlBQVc7SUFDWCxlQUFjLEVBYWY7O0FBbERIO01Bd0NNLFlBQVcsRUFLWjs7QUE3Q0w7UUEyQ1EsbUJBQWtCLEVBQ25COztBQTVDUDtNQWdETSxnQkFBZSxFQUNoQiIsImZpbGUiOiJzcmMvYXBwL3R5cGluZy1tZXNzYWdlL3R5cGluZy1tZXNzYWdlLmNvbXBvbmVudC5zY3NzIiwic291cmNlc0NvbnRlbnQiOlsiOmhvc3Qge1xyXG4gIGRpc3BsYXk6IGZsZXg7XHJcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICB3aWR0aDogMTAwJTtcclxufVxyXG5cclxuLmhlYWQge1xyXG4gIGZsZXg6IDAgMCBhdXRvO1xyXG4gIGJveC1zaXppbmc6IGNvbnRlbnQtYm94O1xyXG4gIG1hcmdpbjogLTNyZW0gLTNyZW0gMDtcclxufVxyXG5cclxuLm1lc3NhZ2VzLWNvbnRlbnQge1xyXG4gIGRpc3BsYXk6IGZsZXg7XHJcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XHJcbiAgZmxleC1ncm93OiAxO1xyXG5cclxuICAubWVzc2FnZXMtbGlzdCB7XHJcbiAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICAgIGZvbnQtc2l6ZTogMS4zcmVtO1xyXG4gICAgbWFyZ2luOiAxcmVtIC0zcmVtO1xyXG4gICAgcGFkZGluZzogMCAzcmVtO1xyXG4gICAgb3ZlcmZsb3cteTogb3ZlcmxheTtcclxuXHJcbiAgICBkaXYge1xyXG4gICAgICBtYXJnaW46IDAuN3JlbSAwO1xyXG5cclxuICAgICAgJi5kYXRlIHtcclxuICAgICAgICB0ZXh0LWFsaWduOiBjZW50ZXI7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICYubXksICYuYnVkZHkge1xyXG4gICAgICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcclxuICAgICAgICBwYWRkaW5nOiAxLjhyZW07XHJcbiAgICAgICAgbWF4LXdpZHRoOiA2MCU7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICYuYnVkZHkge1xyXG4gICAgICAgIGFsaWduLXNlbGY6IGZsZXgtZW5kO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAudHlwZS1tZXNzYWdlIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBmbGV4OiAwIDAgYXV0bztcclxuICAgIHdpZHRoOiAxMDAlO1xyXG4gICAgaGVpZ2h0OiA0LjJyZW07XHJcblxyXG4gICAgLmlucHV0LWJsb2NrIHtcclxuICAgICAgd2lkdGg6IDEwMCU7XHJcblxyXG4gICAgICA+IHRleHRhcmVhIHtcclxuICAgICAgICBtaW4taGVpZ2h0OiA0LjJyZW07XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBidXR0b24ge1xyXG4gICAgICBmbGV4OiAwIDAgMTVyZW07XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcblxyXG4iXX0= */\"","import { Component, OnInit } from '@angular/core';\r\nimport { ActivatedRoute } from '@angular/router';\r\n\r\n@Component({\r\n selector: 'app-typing-message',\r\n templateUrl: './typing-message.component.html',\r\n styleUrls: ['./typing-message.component.scss']\r\n})\r\nexport class TypingMessageComponent implements OnInit {\r\n\r\n messagesId: number;\r\n private subMessages: any;\r\n\r\n constructor(private route: ActivatedRoute) {\r\n this.route.params.subscribe( params => console.log(params) );\r\n }\r\n\r\n ngOnInit() {\r\n\r\n }\r\n\r\n}\r\n","module.exports = \"
\\r\\n
\\r\\n
\\r\\n {{variablesService.currentWallet.name}}\\r\\n {{ 'BREADCRUMBS.WALLET_DETAILS' | translate }}\\r\\n
\\r\\n \\r\\n
\\r\\n\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n\\r\\n
\\r\\n
\\r\\n Name is required.\\r\\n
\\r\\n
\\r\\n Name is duplicate.\\r\\n
\\r\\n
\\r\\n\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n \\r\\n
\\r\\n
{{ 'WALLET_DETAILS.SEED_PHRASE_HINT' | translate }}
\\r\\n
\\r\\n \\r\\n
{{(index + 1) + '. ' + word}}
\\r\\n
\\r\\n
\\r\\n
\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n\\r\\n
\\r\\n\"","module.exports = \".form-details {\\n margin-top: 1.8rem; }\\n .form-details .input-block:first-child {\\n width: 50%; }\\n .form-details .seed-phrase {\\n display: flex;\\n font-size: 1.4rem;\\n line-height: 1.5rem;\\n padding: 1.4rem;\\n width: 100%;\\n height: 8.8rem; }\\n .form-details .seed-phrase .seed-phrase-hint {\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n cursor: pointer;\\n width: 100%;\\n height: 100%; }\\n .form-details .seed-phrase .seed-phrase-content {\\n display: flex;\\n flex-direction: column;\\n flex-wrap: wrap;\\n width: 100%;\\n height: 100%; }\\n .form-details .wallet-buttons {\\n display: flex;\\n align-items: center;\\n justify-content: space-between; }\\n .form-details .wallet-buttons button {\\n margin: 2.9rem 0;\\n width: 100%;\\n max-width: 15rem; }\\n\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvd2FsbGV0LWRldGFpbHMvRDpcXHphbm8vc3JjXFxhcHBcXHdhbGxldC1kZXRhaWxzXFx3YWxsZXQtZGV0YWlscy5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLG1CQUFrQixFQStDbkI7RUFoREQ7SUFNTSxXQUFVLEVBQ1g7RUFQTDtJQVdJLGNBQWE7SUFDYixrQkFBaUI7SUFDakIsb0JBQW1CO0lBQ25CLGdCQUFlO0lBQ2YsWUFBVztJQUNYLGVBQWMsRUFrQmY7RUFsQ0g7TUFtQk0sY0FBYTtNQUNiLG9CQUFtQjtNQUNuQix3QkFBdUI7TUFDdkIsZ0JBQWU7TUFDZixZQUFXO01BQ1gsYUFBWSxFQUNiO0VBekJMO01BNEJNLGNBQWE7TUFDYix1QkFBc0I7TUFDdEIsZ0JBQWU7TUFDZixZQUFXO01BQ1gsYUFBWSxFQUNiO0VBakNMO0lBcUNJLGNBQWE7SUFDYixvQkFBbUI7SUFDbkIsK0JBQThCLEVBTy9CO0VBOUNIO01BMENNLGlCQUFnQjtNQUNoQixZQUFXO01BQ1gsaUJBQWdCLEVBQ2pCIiwiZmlsZSI6InNyYy9hcHAvd2FsbGV0LWRldGFpbHMvd2FsbGV0LWRldGFpbHMuY29tcG9uZW50LnNjc3MiLCJzb3VyY2VzQ29udGVudCI6WyIuZm9ybS1kZXRhaWxzIHtcclxuICBtYXJnaW4tdG9wOiAxLjhyZW07XHJcblxyXG4gIC5pbnB1dC1ibG9jayB7XHJcblxyXG4gICAgJjpmaXJzdC1jaGlsZCB7XHJcbiAgICAgIHdpZHRoOiA1MCU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAuc2VlZC1waHJhc2Uge1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuICAgIGZvbnQtc2l6ZTogMS40cmVtO1xyXG4gICAgbGluZS1oZWlnaHQ6IDEuNXJlbTtcclxuICAgIHBhZGRpbmc6IDEuNHJlbTtcclxuICAgIHdpZHRoOiAxMDAlO1xyXG4gICAgaGVpZ2h0OiA4LjhyZW07XHJcblxyXG4gICAgLnNlZWQtcGhyYXNlLWhpbnQge1xyXG4gICAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAgICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcclxuICAgICAgY3Vyc29yOiBwb2ludGVyO1xyXG4gICAgICB3aWR0aDogMTAwJTtcclxuICAgICAgaGVpZ2h0OiAxMDAlO1xyXG4gICAgfVxyXG5cclxuICAgIC5zZWVkLXBocmFzZS1jb250ZW50IHtcclxuICAgICAgZGlzcGxheTogZmxleDtcclxuICAgICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICAgICAgZmxleC13cmFwOiB3cmFwO1xyXG4gICAgICB3aWR0aDogMTAwJTtcclxuICAgICAgaGVpZ2h0OiAxMDAlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLndhbGxldC1idXR0b25zIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xyXG5cclxuICAgIGJ1dHRvbiB7XHJcbiAgICAgIG1hcmdpbjogMi45cmVtIDA7XHJcbiAgICAgIHdpZHRoOiAxMDAlO1xyXG4gICAgICBtYXgtd2lkdGg6IDE1cmVtO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbn1cclxuIl19 */\"","import {Component, NgZone, OnDestroy, OnInit} from '@angular/core';\r\nimport {FormGroup, FormControl, Validators} from '@angular/forms';\r\nimport {BackendService} from '../_helpers/services/backend.service';\r\nimport {VariablesService} from '../_helpers/services/variables.service';\r\nimport {Router} from '@angular/router';\r\nimport {Location} from '@angular/common';\r\n\r\n@Component({\r\n selector: 'app-wallet-details',\r\n templateUrl: './wallet-details.component.html',\r\n styleUrls: ['./wallet-details.component.scss']\r\n})\r\nexport class WalletDetailsComponent implements OnInit, OnDestroy {\r\n seedPhrase = '';\r\n showSeed = false;\r\n\r\n detailsForm = new FormGroup({\r\n name: new FormControl('', [Validators.required, (g: FormControl) => {\r\n for (let i = 0; i < this.variablesService.wallets.length; i++) {\r\n if (g.value === this.variablesService.wallets[i].name && this.variablesService.wallets[i].wallet_id !== this.variablesService.currentWallet.wallet_id) {\r\n return {'duplicate': true};\r\n }\r\n }\r\n return null;\r\n }]),\r\n path: new FormControl('')\r\n });\r\n\r\n constructor(\r\n private router: Router,\r\n private backend: BackendService,\r\n private variablesService: VariablesService,\r\n private ngZone: NgZone,\r\n private location: Location\r\n ) {\r\n }\r\n\r\n ngOnInit() {\r\n this.showSeed = false;\r\n this.detailsForm.get('name').setValue(this.variablesService.currentWallet.name);\r\n this.detailsForm.get('path').setValue(this.variablesService.currentWallet.path);\r\n this.backend.getSmartSafeInfo(this.variablesService.currentWallet.wallet_id, (status, data) => {\r\n if (data.hasOwnProperty('restore_key')) {\r\n this.ngZone.run(() => {\r\n this.seedPhrase = data['restore_key'].trim();\r\n });\r\n }\r\n });\r\n }\r\n\r\n showSeedPhrase() {\r\n this.showSeed = true;\r\n }\r\n\r\n onSubmitEdit() {\r\n if (this.detailsForm.value) {\r\n this.variablesService.currentWallet.name = this.detailsForm.get('name').value;\r\n this.router.navigate(['/wallet/' + this.variablesService.currentWallet.wallet_id]);\r\n }\r\n }\r\n\r\n closeWallet() {\r\n this.backend.closeWallet(this.variablesService.currentWallet.wallet_id, () => {\r\n for (let i = this.variablesService.wallets.length - 1; i >= 0; i--) {\r\n if (this.variablesService.wallets[i].wallet_id === this.variablesService.currentWallet.wallet_id) {\r\n this.variablesService.wallets.splice(i, 1);\r\n }\r\n }\r\n this.backend.storeSecureAppData(() => {\r\n this.ngZone.run(() => {\r\n if (this.variablesService.wallets.length) {\r\n this.variablesService.currentWallet = this.variablesService.wallets[0];\r\n this.router.navigate(['/wallet/' + this.variablesService.currentWallet.wallet_id]);\r\n } else {\r\n this.router.navigate(['/']);\r\n }\r\n });\r\n });\r\n });\r\n }\r\n\r\n back() {\r\n this.location.back();\r\n }\r\n\r\n ngOnDestroy() {}\r\n\r\n}\r\n","module.exports = \"
\\r\\n
\\r\\n

{{variablesService.currentWallet.name}}

\\r\\n \\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n
\\r\\n {{variablesService.currentWallet.address}}\\r\\n \\r\\n
\\r\\n
\\r\\n {{variablesService.currentWallet.unlocked_balance | intToMoney}} {{variablesService.defaultCurrency}}\\r\\n $ {{variablesService.currentWallet.getMoneyEquivalent(variablesService.moneyEquivalent) | intToMoney | number : '1.2-2'}}\\r\\n
\\r\\n
\\r\\n
\\r\\n \\r\\n
\\r\\n \\r\\n {{ tab.title | translate }}\\r\\n {{variablesService.currentWallet.new_contracts}}\\r\\n
\\r\\n
\\r\\n
\\r\\n
\\r\\n \\r\\n
\\r\\n
\\r\\n\\r\\n\"","module.exports = \":host {\\n position: relative;\\n display: flex;\\n flex-direction: column;\\n padding: 0 3rem 3rem;\\n min-width: 95rem;\\n width: 100%;\\n height: 100%; }\\n\\n.header {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n flex: 0 0 auto;\\n height: 8rem; }\\n\\n.header > div {\\n display: flex;\\n align-items: center; }\\n\\n.header > div :not(:last-child) {\\n margin-right: 3.2rem; }\\n\\n.header h3 {\\n font-size: 1.7rem;\\n font-weight: 600; }\\n\\n.header button {\\n display: flex;\\n align-items: center;\\n background: transparent;\\n border: none;\\n cursor: pointer;\\n font-weight: 400;\\n outline: none;\\n padding: 0; }\\n\\n.header button .icon {\\n margin-right: 1.2rem;\\n width: 1.7rem;\\n height: 1.7rem; }\\n\\n.header button .icon.account {\\n -webkit-mask: url('account.svg') no-repeat center;\\n mask: url('account.svg') no-repeat center; }\\n\\n.header button .icon.details {\\n -webkit-mask: url('details.svg') no-repeat center;\\n mask: url('details.svg') no-repeat center; }\\n\\n.header button .icon.lock {\\n -webkit-mask: url('lock.svg') no-repeat center;\\n mask: url('lock.svg') no-repeat center; }\\n\\n.address {\\n display: flex;\\n align-items: center;\\n flex: 0 0 auto;\\n font-size: 1.4rem;\\n line-height: 1.7rem; }\\n\\n.address .icon {\\n cursor: pointer;\\n margin-left: 1.2rem;\\n width: 1.7rem;\\n height: 1.7rem; }\\n\\n.address .icon.copy {\\n -webkit-mask: url('copy.svg') no-repeat center;\\n mask: url('copy.svg') no-repeat center; }\\n\\n.balance {\\n display: flex;\\n align-items: flex-end;\\n justify-content: flex-start;\\n flex: 0 0 auto;\\n margin: 2.6rem 0; }\\n\\n.balance :first-child {\\n font-size: 3.3rem;\\n font-weight: 600;\\n line-height: 2.4rem;\\n margin-right: 3.5rem; }\\n\\n.balance :last-child {\\n font-size: 1.8rem;\\n font-weight: 600;\\n line-height: 1.3rem; }\\n\\n.tabs {\\n display: flex;\\n flex-direction: column;\\n flex: 1 1 auto; }\\n\\n.tabs .tabs-header {\\n display: flex;\\n justify-content: space-between;\\n flex: 0 0 auto; }\\n\\n.tabs .tabs-header .tab {\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n flex: 1 0 auto;\\n cursor: pointer;\\n padding: 0 1rem;\\n height: 5rem; }\\n\\n.tabs .tabs-header .tab .icon {\\n margin-right: 1.3rem;\\n width: 1.7rem;\\n height: 1.7rem; }\\n\\n.tabs .tabs-header .tab .icon.send {\\n -webkit-mask: url('send.svg') no-repeat center;\\n mask: url('send.svg') no-repeat center; }\\n\\n.tabs .tabs-header .tab .icon.receive {\\n -webkit-mask: url('receive.svg') no-repeat center;\\n mask: url('receive.svg') no-repeat center; }\\n\\n.tabs .tabs-header .tab .icon.history {\\n -webkit-mask: url('history.svg') no-repeat center;\\n mask: url('history.svg') no-repeat center; }\\n\\n.tabs .tabs-header .tab .icon.contracts {\\n -webkit-mask: url('contracts.svg') no-repeat center;\\n mask: url('contracts.svg') no-repeat center; }\\n\\n.tabs .tabs-header .tab .icon.messages {\\n -webkit-mask: url('message.svg') no-repeat center;\\n mask: url('message.svg') no-repeat center; }\\n\\n.tabs .tabs-header .tab .icon.staking {\\n -webkit-mask: url('staking.svg') no-repeat center;\\n mask: url('staking.svg') no-repeat center; }\\n\\n.tabs .tabs-header .tab .indicator {\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 1rem;\\n font-size: 1rem;\\n font-weight: 600;\\n margin-left: 1.3rem;\\n padding: 0 0.5rem;\\n min-width: 1.6rem;\\n height: 1.6rem; }\\n\\n.tabs .tabs-header .tab.disabled {\\n cursor: not-allowed; }\\n\\n.tabs .tabs-header .tab:not(:last-child) {\\n margin-right: 0.3rem; }\\n\\n.tabs .tabs-content {\\n display: flex;\\n padding: 3rem;\\n flex: 1 1 auto;\\n overflow-x: hidden;\\n overflow-y: overlay; }\\n\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcHAvd2FsbGV0L0Q6XFx6YW5vL3NyY1xcYXBwXFx3YWxsZXRcXHdhbGxldC5jb21wb25lbnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLG1CQUFrQjtFQUNsQixjQUFhO0VBQ2IsdUJBQXNCO0VBQ3RCLHFCQUFvQjtFQUNwQixpQkFBZ0I7RUFDaEIsWUFBVztFQUNYLGFBQVksRUFDYjs7QUFFRDtFQUNFLGNBQWE7RUFDYixvQkFBbUI7RUFDbkIsK0JBQThCO0VBQzlCLGVBQWM7RUFDZCxhQUFZLEVBNENiOztBQWpERDtJQVFJLGNBQWE7SUFDYixvQkFBbUIsRUFLcEI7O0FBZEg7TUFZTSxxQkFBb0IsRUFDckI7O0FBYkw7SUFpQkksa0JBQWlCO0lBQ2pCLGlCQUFnQixFQUNqQjs7QUFuQkg7SUFzQkksY0FBYTtJQUNiLG9CQUFtQjtJQUNuQix3QkFBdUI7SUFDdkIsYUFBWTtJQUNaLGdCQUFlO0lBQ2YsaUJBQWdCO0lBQ2hCLGNBQWE7SUFDYixXQUFVLEVBbUJYOztBQWhESDtNQWdDTSxxQkFBb0I7TUFDcEIsY0FBYTtNQUNiLGVBQWMsRUFhZjs7QUEvQ0w7UUFxQ1Esa0RBQTBEO2dCQUExRCwwQ0FBMEQsRUFDM0Q7O0FBdENQO1FBeUNRLGtEQUEwRDtnQkFBMUQsMENBQTBELEVBQzNEOztBQTFDUDtRQTZDUSwrQ0FBdUQ7Z0JBQXZELHVDQUF1RCxFQUN4RDs7QUFLUDtFQUNFLGNBQWE7RUFDYixvQkFBbUI7RUFDbkIsZUFBYztFQUNkLGtCQUFpQjtFQUNqQixvQkFBbUIsRUFZcEI7O0FBakJEO0lBUUksZ0JBQWU7SUFDZixvQkFBbUI7SUFDbkIsY0FBYTtJQUNiLGVBQWMsRUFLZjs7QUFoQkg7TUFjTSwrQ0FBdUQ7Y0FBdkQsdUNBQXVELEVBQ3hEOztBQUlMO0VBQ0UsY0FBYTtFQUNiLHNCQUFxQjtFQUNyQiw0QkFBMkI7RUFDM0IsZUFBYztFQUNkLGlCQUFnQixFQWNqQjs7QUFuQkQ7SUFRSSxrQkFBaUI7SUFDakIsaUJBQWdCO0lBQ2hCLG9CQUFtQjtJQUNuQixxQkFBb0IsRUFDckI7O0FBWkg7SUFlSSxrQkFBaUI7SUFDakIsaUJBQWdCO0lBQ2hCLG9CQUFtQixFQUNwQjs7QUFHSDtFQUNFLGNBQWE7RUFDYix1QkFBc0I7RUFDdEIsZUFBYyxFQTRFZjs7QUEvRUQ7SUFNSSxjQUFhO0lBQ2IsK0JBQThCO0lBQzlCLGVBQWMsRUE4RGY7O0FBdEVIO01BV00sY0FBYTtNQUNiLG9CQUFtQjtNQUNuQix3QkFBdUI7TUFDdkIsZUFBYztNQUNkLGdCQUFlO01BQ2YsZ0JBQWU7TUFDZixhQUFZLEVBb0RiOztBQXJFTDtRQW9CUSxxQkFBb0I7UUFDcEIsY0FBYTtRQUNiLGVBQWMsRUF5QmY7O0FBL0NQO1VBeUJVLCtDQUF1RDtrQkFBdkQsdUNBQXVELEVBQ3hEOztBQTFCVDtVQTZCVSxrREFBMEQ7a0JBQTFELDBDQUEwRCxFQUMzRDs7QUE5QlQ7VUFpQ1Usa0RBQTBEO2tCQUExRCwwQ0FBMEQsRUFDM0Q7O0FBbENUO1VBcUNVLG9EQUE0RDtrQkFBNUQsNENBQTRELEVBQzdEOztBQXRDVDtVQXlDVSxrREFBMEQ7a0JBQTFELDBDQUEwRCxFQUMzRDs7QUExQ1Q7VUE2Q1Usa0RBQTBEO2tCQUExRCwwQ0FBMEQsRUFDM0Q7O0FBOUNUO1FBa0RRLGNBQWE7UUFDYixvQkFBbUI7UUFDbkIsd0JBQXVCO1FBQ3ZCLG9CQUFtQjtRQUNuQixnQkFBZTtRQUNmLGlCQUFnQjtRQUNoQixvQkFBbUI7UUFDbkIsa0JBQWlCO1FBQ2pCLGtCQUFpQjtRQUNqQixlQUFjLEVBQ2Y7O0FBNURQO1FBK0RRLG9CQUFtQixFQUNwQjs7QUFoRVA7UUFtRVEscUJBQW9CLEVBQ3JCOztBQXBFUDtJQXlFSSxjQUFhO0lBQ2IsY0FBYTtJQUNiLGVBQWM7SUFDZCxtQkFBa0I7SUFDbEIsb0JBQW1CLEVBQ3BCIiwiZmlsZSI6InNyYy9hcHAvd2FsbGV0L3dhbGxldC5jb21wb25lbnQuc2NzcyIsInNvdXJjZXNDb250ZW50IjpbIjpob3N0IHtcclxuICBwb3NpdGlvbjogcmVsYXRpdmU7XHJcbiAgZGlzcGxheTogZmxleDtcclxuICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xyXG4gIHBhZGRpbmc6IDAgM3JlbSAzcmVtO1xyXG4gIG1pbi13aWR0aDogOTVyZW07XHJcbiAgd2lkdGg6IDEwMCU7XHJcbiAgaGVpZ2h0OiAxMDAlO1xyXG59XHJcblxyXG4uaGVhZGVyIHtcclxuICBkaXNwbGF5OiBmbGV4O1xyXG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xyXG4gIGZsZXg6IDAgMCBhdXRvO1xyXG4gIGhlaWdodDogOHJlbTtcclxuXHJcbiAgPiBkaXYge1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcblxyXG4gICAgOm5vdCg6bGFzdC1jaGlsZCkge1xyXG4gICAgICBtYXJnaW4tcmlnaHQ6IDMuMnJlbTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGgzIHtcclxuICAgIGZvbnQtc2l6ZTogMS43cmVtO1xyXG4gICAgZm9udC13ZWlnaHQ6IDYwMDtcclxuICB9XHJcblxyXG4gIGJ1dHRvbiB7XHJcbiAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuICAgIGJhY2tncm91bmQ6IHRyYW5zcGFyZW50O1xyXG4gICAgYm9yZGVyOiBub25lO1xyXG4gICAgY3Vyc29yOiBwb2ludGVyO1xyXG4gICAgZm9udC13ZWlnaHQ6IDQwMDtcclxuICAgIG91dGxpbmU6IG5vbmU7XHJcbiAgICBwYWRkaW5nOiAwO1xyXG5cclxuICAgIC5pY29uIHtcclxuICAgICAgbWFyZ2luLXJpZ2h0OiAxLjJyZW07XHJcbiAgICAgIHdpZHRoOiAxLjdyZW07XHJcbiAgICAgIGhlaWdodDogMS43cmVtO1xyXG5cclxuICAgICAgJi5hY2NvdW50IHtcclxuICAgICAgICBtYXNrOiB1cmwoLi4vLi4vYXNzZXRzL2ljb25zL2FjY291bnQuc3ZnKSBuby1yZXBlYXQgY2VudGVyO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAmLmRldGFpbHMge1xyXG4gICAgICAgIG1hc2s6IHVybCguLi8uLi9hc3NldHMvaWNvbnMvZGV0YWlscy5zdmcpIG5vLXJlcGVhdCBjZW50ZXI7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICYubG9jayB7XHJcbiAgICAgICAgbWFzazogdXJsKC4uLy4uL2Fzc2V0cy9pY29ucy9sb2NrLnN2Zykgbm8tcmVwZWF0IGNlbnRlcjtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuLmFkZHJlc3Mge1xyXG4gIGRpc3BsYXk6IGZsZXg7XHJcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuICBmbGV4OiAwIDAgYXV0bztcclxuICBmb250LXNpemU6IDEuNHJlbTtcclxuICBsaW5lLWhlaWdodDogMS43cmVtO1xyXG5cclxuICAuaWNvbiB7XHJcbiAgICBjdXJzb3I6IHBvaW50ZXI7XHJcbiAgICBtYXJnaW4tbGVmdDogMS4ycmVtO1xyXG4gICAgd2lkdGg6IDEuN3JlbTtcclxuICAgIGhlaWdodDogMS43cmVtO1xyXG5cclxuICAgICYuY29weSB7XHJcbiAgICAgIG1hc2s6IHVybCguLi8uLi9hc3NldHMvaWNvbnMvY29weS5zdmcpIG5vLXJlcGVhdCBjZW50ZXI7XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcblxyXG4uYmFsYW5jZSB7XHJcbiAgZGlzcGxheTogZmxleDtcclxuICBhbGlnbi1pdGVtczogZmxleC1lbmQ7XHJcbiAganVzdGlmeS1jb250ZW50OiBmbGV4LXN0YXJ0O1xyXG4gIGZsZXg6IDAgMCBhdXRvO1xyXG4gIG1hcmdpbjogMi42cmVtIDA7XHJcblxyXG4gIDpmaXJzdC1jaGlsZCB7XHJcbiAgICBmb250LXNpemU6IDMuM3JlbTtcclxuICAgIGZvbnQtd2VpZ2h0OiA2MDA7XHJcbiAgICBsaW5lLWhlaWdodDogMi40cmVtO1xyXG4gICAgbWFyZ2luLXJpZ2h0OiAzLjVyZW07XHJcbiAgfVxyXG5cclxuICA6bGFzdC1jaGlsZCB7XHJcbiAgICBmb250LXNpemU6IDEuOHJlbTtcclxuICAgIGZvbnQtd2VpZ2h0OiA2MDA7XHJcbiAgICBsaW5lLWhlaWdodDogMS4zcmVtO1xyXG4gIH1cclxufVxyXG5cclxuLnRhYnMge1xyXG4gIGRpc3BsYXk6IGZsZXg7XHJcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICBmbGV4OiAxIDEgYXV0bztcclxuXHJcbiAgLnRhYnMtaGVhZGVyIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XHJcbiAgICBmbGV4OiAwIDAgYXV0bztcclxuXHJcbiAgICAudGFiIHtcclxuICAgICAgZGlzcGxheTogZmxleDtcclxuICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuICAgICAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XHJcbiAgICAgIGZsZXg6IDEgMCBhdXRvO1xyXG4gICAgICBjdXJzb3I6IHBvaW50ZXI7XHJcbiAgICAgIHBhZGRpbmc6IDAgMXJlbTtcclxuICAgICAgaGVpZ2h0OiA1cmVtO1xyXG5cclxuICAgICAgLmljb24ge1xyXG4gICAgICAgIG1hcmdpbi1yaWdodDogMS4zcmVtO1xyXG4gICAgICAgIHdpZHRoOiAxLjdyZW07XHJcbiAgICAgICAgaGVpZ2h0OiAxLjdyZW07XHJcblxyXG4gICAgICAgICYuc2VuZCB7XHJcbiAgICAgICAgICBtYXNrOiB1cmwoLi4vLi4vYXNzZXRzL2ljb25zL3NlbmQuc3ZnKSBuby1yZXBlYXQgY2VudGVyO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgJi5yZWNlaXZlIHtcclxuICAgICAgICAgIG1hc2s6IHVybCguLi8uLi9hc3NldHMvaWNvbnMvcmVjZWl2ZS5zdmcpIG5vLXJlcGVhdCBjZW50ZXI7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAmLmhpc3Rvcnkge1xyXG4gICAgICAgICAgbWFzazogdXJsKC4uLy4uL2Fzc2V0cy9pY29ucy9oaXN0b3J5LnN2Zykgbm8tcmVwZWF0IGNlbnRlcjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgICYuY29udHJhY3RzIHtcclxuICAgICAgICAgIG1hc2s6IHVybCguLi8uLi9hc3NldHMvaWNvbnMvY29udHJhY3RzLnN2Zykgbm8tcmVwZWF0IGNlbnRlcjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgICYubWVzc2FnZXMge1xyXG4gICAgICAgICAgbWFzazogdXJsKC4uLy4uL2Fzc2V0cy9pY29ucy9tZXNzYWdlLnN2Zykgbm8tcmVwZWF0IGNlbnRlcjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgICYuc3Rha2luZyB7XHJcbiAgICAgICAgICBtYXNrOiB1cmwoLi4vLi4vYXNzZXRzL2ljb25zL3N0YWtpbmcuc3ZnKSBuby1yZXBlYXQgY2VudGVyO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgLmluZGljYXRvciB7XHJcbiAgICAgICAgZGlzcGxheTogZmxleDtcclxuICAgICAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAgICAgIGp1c3RpZnktY29udGVudDogY2VudGVyO1xyXG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDFyZW07XHJcbiAgICAgICAgZm9udC1zaXplOiAxcmVtO1xyXG4gICAgICAgIGZvbnQtd2VpZ2h0OiA2MDA7XHJcbiAgICAgICAgbWFyZ2luLWxlZnQ6IDEuM3JlbTtcclxuICAgICAgICBwYWRkaW5nOiAwIDAuNXJlbTtcclxuICAgICAgICBtaW4td2lkdGg6IDEuNnJlbTtcclxuICAgICAgICBoZWlnaHQ6IDEuNnJlbTtcclxuICAgICAgfVxyXG5cclxuICAgICAgJi5kaXNhYmxlZCB7XHJcbiAgICAgICAgY3Vyc29yOiBub3QtYWxsb3dlZDtcclxuICAgICAgfVxyXG5cclxuICAgICAgJjpub3QoOmxhc3QtY2hpbGQpIHtcclxuICAgICAgICBtYXJnaW4tcmlnaHQ6IDAuM3JlbTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLnRhYnMtY29udGVudCB7XHJcbiAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgcGFkZGluZzogM3JlbTtcclxuICAgIGZsZXg6IDEgMSBhdXRvO1xyXG4gICAgb3ZlcmZsb3cteDogaGlkZGVuO1xyXG4gICAgb3ZlcmZsb3cteTogb3ZlcmxheTtcclxuICB9XHJcbn1cclxuIl19 */\"","import {Component, OnInit, OnDestroy, NgZone} from '@angular/core';\r\nimport {ActivatedRoute, Router} from '@angular/router';\r\nimport {VariablesService} from '../_helpers/services/variables.service';\r\nimport {BackendService} from '../_helpers/services/backend.service';\r\n\r\n@Component({\r\n selector: 'app-wallet',\r\n templateUrl: './wallet.component.html',\r\n styleUrls: ['./wallet.component.scss']\r\n})\r\nexport class WalletComponent implements OnInit, OnDestroy {\r\n subRouting;\r\n walletID;\r\n tabs = [\r\n {\r\n title: 'WALLET.TABS.SEND',\r\n icon: 'send',\r\n link: '/send',\r\n indicator: false,\r\n active: true\r\n },\r\n {\r\n title: 'WALLET.TABS.RECEIVE',\r\n icon: 'receive',\r\n link: '/receive',\r\n indicator: false,\r\n active: false\r\n },\r\n {\r\n title: 'WALLET.TABS.HISTORY',\r\n icon: 'history',\r\n link: '/history',\r\n indicator: false,\r\n active: false\r\n },\r\n {\r\n title: 'WALLET.TABS.CONTRACTS',\r\n icon: 'contracts',\r\n link: '/contracts',\r\n indicator: 1,\r\n active: false\r\n },\r\n {\r\n title: 'WALLET.TABS.MESSAGES',\r\n icon: 'messages',\r\n link: '/messages',\r\n indicator: 32,\r\n active: false\r\n },\r\n {\r\n title: 'WALLET.TABS.STAKING',\r\n icon: 'staking',\r\n link: '/staking',\r\n indicator: false,\r\n active: false\r\n }\r\n ];\r\n\r\n constructor(\r\n private route: ActivatedRoute,\r\n private router: Router,\r\n private backend: BackendService,\r\n private variablesService: VariablesService,\r\n private ngZone: NgZone\r\n ) {\r\n }\r\n\r\n ngOnInit() {\r\n this.subRouting = this.route.params.subscribe(params => {\r\n this.walletID = +params['id'];\r\n this.variablesService.setCurrentWallet(this.walletID);\r\n for (let i = 0; i < this.tabs.length; i++) {\r\n this.tabs[i].active = (this.tabs[i].link === '/' + this.route.snapshot.firstChild.url[0].path);\r\n }\r\n });\r\n }\r\n\r\n changeTab(index) {\r\n if ((this.tabs[index].link === '/contracts' || this.tabs[index].link === '/staking') && this.variablesService.daemon_state !== 2) {\r\n return;\r\n }\r\n this.tabs.forEach((tab) => {\r\n tab.active = false;\r\n });\r\n this.tabs[index].active = true;\r\n this.router.navigate(['wallet/' + this.walletID + this.tabs[index].link]);\r\n }\r\n\r\n copyAddress() {\r\n this.backend.setClipboard(this.variablesService.currentWallet.address);\r\n }\r\n\r\n /*closeWallet() {\r\n this.backend.closeWallet(this.walletID, () => {\r\n for (let i = this.variablesService.wallets.length - 1; i >= 0; i--) {\r\n if (this.variablesService.wallets[i].wallet_id === this.walletID) {\r\n this.variablesService.wallets.splice(i, 1);\r\n }\r\n }\r\n this.backend.storeSecureAppData(() => {\r\n this.ngZone.run(() => {\r\n this.router.navigate(['/']);\r\n });\r\n });\r\n });\r\n }*/\r\n\r\n ngOnDestroy() {\r\n this.subRouting.unsubscribe();\r\n }\r\n\r\n}\r\n","// This file can be replaced during build by using the `fileReplacements` array.\r\n// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.\r\n// The list of file replacements can be found in `angular.json`.\r\n\r\nexport const environment = {\r\n production: false\r\n};\r\n\r\n/*\r\n * For easier debugging in development mode, you can import the following file\r\n * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.\r\n *\r\n * This import should be commented out in production mode because it will have a negative impact\r\n * on performance if an error is thrown.\r\n */\r\n// import 'zone.js/dist/zone-error'; // Included with Angular CLI.\r\n","import { enableProdMode } from '@angular/core';\r\nimport { platformBrowserDynamic } from '@angular/platform-browser-dynamic';\r\n\r\nimport { AppModule } from './app/app.module';\r\nimport { environment } from './environments/environment';\r\n\r\nif (environment.production) {\r\n enableProdMode();\r\n}\r\n\r\nplatformBrowserDynamic().bootstrapModule(AppModule)\r\n .catch(err => console.error(err));\r\n"],"sourceRoot":""} \ No newline at end of file diff --git a/src/gui/qt-daemon/html/message.svg b/src/gui/qt-daemon/html/message.svg new file mode 100644 index 00000000..544888cc --- /dev/null +++ b/src/gui/qt-daemon/html/message.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/gui/qt-daemon/html/new.svg b/src/gui/qt-daemon/html/new.svg new file mode 100644 index 00000000..89622385 --- /dev/null +++ b/src/gui/qt-daemon/html/new.svg @@ -0,0 +1,17 @@ + + + + + + + + + + diff --git a/src/gui/qt-daemon/html/polyfills.js b/src/gui/qt-daemon/html/polyfills.js new file mode 100644 index 00000000..eed9a6b4 --- /dev/null +++ b/src/gui/qt-daemon/html/polyfills.js @@ -0,0 +1,5507 @@ +(window["webpackJsonp"] = window["webpackJsonp"] || []).push([["polyfills"],{ + +/***/ "./node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/jit-polyfills.js": +/*!**************************************************************************************************!*\ + !*** ./node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/jit-polyfills.js ***! + \**************************************************************************************************/ +/*! no exports provided */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var core_js_es7_reflect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! core-js/es7/reflect */ "./node_modules/core-js/es7/reflect.js"); +/* harmony import */ var core_js_es7_reflect__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(core_js_es7_reflect__WEBPACK_IMPORTED_MODULE_0__); +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + + + +/***/ }), + +/***/ "./node_modules/core-js/es7/reflect.js": +/*!*********************************************!*\ + !*** ./node_modules/core-js/es7/reflect.js ***! + \*********************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +__webpack_require__(/*! ../modules/es7.reflect.define-metadata */ "./node_modules/core-js/modules/es7.reflect.define-metadata.js"); +__webpack_require__(/*! ../modules/es7.reflect.delete-metadata */ "./node_modules/core-js/modules/es7.reflect.delete-metadata.js"); +__webpack_require__(/*! ../modules/es7.reflect.get-metadata */ "./node_modules/core-js/modules/es7.reflect.get-metadata.js"); +__webpack_require__(/*! ../modules/es7.reflect.get-metadata-keys */ "./node_modules/core-js/modules/es7.reflect.get-metadata-keys.js"); +__webpack_require__(/*! ../modules/es7.reflect.get-own-metadata */ "./node_modules/core-js/modules/es7.reflect.get-own-metadata.js"); +__webpack_require__(/*! ../modules/es7.reflect.get-own-metadata-keys */ "./node_modules/core-js/modules/es7.reflect.get-own-metadata-keys.js"); +__webpack_require__(/*! ../modules/es7.reflect.has-metadata */ "./node_modules/core-js/modules/es7.reflect.has-metadata.js"); +__webpack_require__(/*! ../modules/es7.reflect.has-own-metadata */ "./node_modules/core-js/modules/es7.reflect.has-own-metadata.js"); +__webpack_require__(/*! ../modules/es7.reflect.metadata */ "./node_modules/core-js/modules/es7.reflect.metadata.js"); +module.exports = __webpack_require__(/*! ../modules/_core */ "./node_modules/core-js/modules/_core.js").Reflect; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_a-function.js": +/*!*****************************************************!*\ + !*** ./node_modules/core-js/modules/_a-function.js ***! + \*****************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = function (it) { + if (typeof it != 'function') throw TypeError(it + ' is not a function!'); + return it; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_an-instance.js": +/*!******************************************************!*\ + !*** ./node_modules/core-js/modules/_an-instance.js ***! + \******************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = function (it, Constructor, name, forbiddenField) { + if (!(it instanceof Constructor) || (forbiddenField !== undefined && forbiddenField in it)) { + throw TypeError(name + ': incorrect invocation!'); + } return it; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_an-object.js": +/*!****************************************************!*\ + !*** ./node_modules/core-js/modules/_an-object.js ***! + \****************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var isObject = __webpack_require__(/*! ./_is-object */ "./node_modules/core-js/modules/_is-object.js"); +module.exports = function (it) { + if (!isObject(it)) throw TypeError(it + ' is not an object!'); + return it; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_array-from-iterable.js": +/*!**************************************************************!*\ + !*** ./node_modules/core-js/modules/_array-from-iterable.js ***! + \**************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var forOf = __webpack_require__(/*! ./_for-of */ "./node_modules/core-js/modules/_for-of.js"); + +module.exports = function (iter, ITERATOR) { + var result = []; + forOf(iter, false, result.push, result, ITERATOR); + return result; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_array-includes.js": +/*!*********************************************************!*\ + !*** ./node_modules/core-js/modules/_array-includes.js ***! + \*********************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +// false -> Array#indexOf +// true -> Array#includes +var toIObject = __webpack_require__(/*! ./_to-iobject */ "./node_modules/core-js/modules/_to-iobject.js"); +var toLength = __webpack_require__(/*! ./_to-length */ "./node_modules/core-js/modules/_to-length.js"); +var toAbsoluteIndex = __webpack_require__(/*! ./_to-absolute-index */ "./node_modules/core-js/modules/_to-absolute-index.js"); +module.exports = function (IS_INCLUDES) { + return function ($this, el, fromIndex) { + var O = toIObject($this); + var length = toLength(O.length); + var index = toAbsoluteIndex(fromIndex, length); + var value; + // Array#includes uses SameValueZero equality algorithm + // eslint-disable-next-line no-self-compare + if (IS_INCLUDES && el != el) while (length > index) { + value = O[index++]; + // eslint-disable-next-line no-self-compare + if (value != value) return true; + // Array#indexOf ignores holes, Array#includes - not + } else for (;length > index; index++) if (IS_INCLUDES || index in O) { + if (O[index] === el) return IS_INCLUDES || index || 0; + } return !IS_INCLUDES && -1; + }; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_array-methods.js": +/*!********************************************************!*\ + !*** ./node_modules/core-js/modules/_array-methods.js ***! + \********************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +// 0 -> Array#forEach +// 1 -> Array#map +// 2 -> Array#filter +// 3 -> Array#some +// 4 -> Array#every +// 5 -> Array#find +// 6 -> Array#findIndex +var ctx = __webpack_require__(/*! ./_ctx */ "./node_modules/core-js/modules/_ctx.js"); +var IObject = __webpack_require__(/*! ./_iobject */ "./node_modules/core-js/modules/_iobject.js"); +var toObject = __webpack_require__(/*! ./_to-object */ "./node_modules/core-js/modules/_to-object.js"); +var toLength = __webpack_require__(/*! ./_to-length */ "./node_modules/core-js/modules/_to-length.js"); +var asc = __webpack_require__(/*! ./_array-species-create */ "./node_modules/core-js/modules/_array-species-create.js"); +module.exports = function (TYPE, $create) { + var IS_MAP = TYPE == 1; + var IS_FILTER = TYPE == 2; + var IS_SOME = TYPE == 3; + var IS_EVERY = TYPE == 4; + var IS_FIND_INDEX = TYPE == 6; + var NO_HOLES = TYPE == 5 || IS_FIND_INDEX; + var create = $create || asc; + return function ($this, callbackfn, that) { + var O = toObject($this); + var self = IObject(O); + var f = ctx(callbackfn, that, 3); + var length = toLength(self.length); + var index = 0; + var result = IS_MAP ? create($this, length) : IS_FILTER ? create($this, 0) : undefined; + var val, res; + for (;length > index; index++) if (NO_HOLES || index in self) { + val = self[index]; + res = f(val, index, O); + if (TYPE) { + if (IS_MAP) result[index] = res; // map + else if (res) switch (TYPE) { + case 3: return true; // some + case 5: return val; // find + case 6: return index; // findIndex + case 2: result.push(val); // filter + } else if (IS_EVERY) return false; // every + } + } + return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : result; + }; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_array-species-constructor.js": +/*!********************************************************************!*\ + !*** ./node_modules/core-js/modules/_array-species-constructor.js ***! + \********************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var isObject = __webpack_require__(/*! ./_is-object */ "./node_modules/core-js/modules/_is-object.js"); +var isArray = __webpack_require__(/*! ./_is-array */ "./node_modules/core-js/modules/_is-array.js"); +var SPECIES = __webpack_require__(/*! ./_wks */ "./node_modules/core-js/modules/_wks.js")('species'); + +module.exports = function (original) { + var C; + if (isArray(original)) { + C = original.constructor; + // cross-realm fallback + if (typeof C == 'function' && (C === Array || isArray(C.prototype))) C = undefined; + if (isObject(C)) { + C = C[SPECIES]; + if (C === null) C = undefined; + } + } return C === undefined ? Array : C; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_array-species-create.js": +/*!***************************************************************!*\ + !*** ./node_modules/core-js/modules/_array-species-create.js ***! + \***************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +// 9.4.2.3 ArraySpeciesCreate(originalArray, length) +var speciesConstructor = __webpack_require__(/*! ./_array-species-constructor */ "./node_modules/core-js/modules/_array-species-constructor.js"); + +module.exports = function (original, length) { + return new (speciesConstructor(original))(length); +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_classof.js": +/*!**************************************************!*\ + !*** ./node_modules/core-js/modules/_classof.js ***! + \**************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +// getting tag from 19.1.3.6 Object.prototype.toString() +var cof = __webpack_require__(/*! ./_cof */ "./node_modules/core-js/modules/_cof.js"); +var TAG = __webpack_require__(/*! ./_wks */ "./node_modules/core-js/modules/_wks.js")('toStringTag'); +// ES3 wrong here +var ARG = cof(function () { return arguments; }()) == 'Arguments'; + +// fallback for IE11 Script Access Denied error +var tryGet = function (it, key) { + try { + return it[key]; + } catch (e) { /* empty */ } +}; + +module.exports = function (it) { + var O, T, B; + return it === undefined ? 'Undefined' : it === null ? 'Null' + // @@toStringTag case + : typeof (T = tryGet(O = Object(it), TAG)) == 'string' ? T + // builtinTag case + : ARG ? cof(O) + // ES3 arguments fallback + : (B = cof(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : B; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_cof.js": +/*!**********************************************!*\ + !*** ./node_modules/core-js/modules/_cof.js ***! + \**********************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +var toString = {}.toString; + +module.exports = function (it) { + return toString.call(it).slice(8, -1); +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_collection-strong.js": +/*!************************************************************!*\ + !*** ./node_modules/core-js/modules/_collection-strong.js ***! + \************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var dP = __webpack_require__(/*! ./_object-dp */ "./node_modules/core-js/modules/_object-dp.js").f; +var create = __webpack_require__(/*! ./_object-create */ "./node_modules/core-js/modules/_object-create.js"); +var redefineAll = __webpack_require__(/*! ./_redefine-all */ "./node_modules/core-js/modules/_redefine-all.js"); +var ctx = __webpack_require__(/*! ./_ctx */ "./node_modules/core-js/modules/_ctx.js"); +var anInstance = __webpack_require__(/*! ./_an-instance */ "./node_modules/core-js/modules/_an-instance.js"); +var forOf = __webpack_require__(/*! ./_for-of */ "./node_modules/core-js/modules/_for-of.js"); +var $iterDefine = __webpack_require__(/*! ./_iter-define */ "./node_modules/core-js/modules/_iter-define.js"); +var step = __webpack_require__(/*! ./_iter-step */ "./node_modules/core-js/modules/_iter-step.js"); +var setSpecies = __webpack_require__(/*! ./_set-species */ "./node_modules/core-js/modules/_set-species.js"); +var DESCRIPTORS = __webpack_require__(/*! ./_descriptors */ "./node_modules/core-js/modules/_descriptors.js"); +var fastKey = __webpack_require__(/*! ./_meta */ "./node_modules/core-js/modules/_meta.js").fastKey; +var validate = __webpack_require__(/*! ./_validate-collection */ "./node_modules/core-js/modules/_validate-collection.js"); +var SIZE = DESCRIPTORS ? '_s' : 'size'; + +var getEntry = function (that, key) { + // fast case + var index = fastKey(key); + var entry; + if (index !== 'F') return that._i[index]; + // frozen object case + for (entry = that._f; entry; entry = entry.n) { + if (entry.k == key) return entry; + } +}; + +module.exports = { + getConstructor: function (wrapper, NAME, IS_MAP, ADDER) { + var C = wrapper(function (that, iterable) { + anInstance(that, C, NAME, '_i'); + that._t = NAME; // collection type + that._i = create(null); // index + that._f = undefined; // first entry + that._l = undefined; // last entry + that[SIZE] = 0; // size + if (iterable != undefined) forOf(iterable, IS_MAP, that[ADDER], that); + }); + redefineAll(C.prototype, { + // 23.1.3.1 Map.prototype.clear() + // 23.2.3.2 Set.prototype.clear() + clear: function clear() { + for (var that = validate(this, NAME), data = that._i, entry = that._f; entry; entry = entry.n) { + entry.r = true; + if (entry.p) entry.p = entry.p.n = undefined; + delete data[entry.i]; + } + that._f = that._l = undefined; + that[SIZE] = 0; + }, + // 23.1.3.3 Map.prototype.delete(key) + // 23.2.3.4 Set.prototype.delete(value) + 'delete': function (key) { + var that = validate(this, NAME); + var entry = getEntry(that, key); + if (entry) { + var next = entry.n; + var prev = entry.p; + delete that._i[entry.i]; + entry.r = true; + if (prev) prev.n = next; + if (next) next.p = prev; + if (that._f == entry) that._f = next; + if (that._l == entry) that._l = prev; + that[SIZE]--; + } return !!entry; + }, + // 23.2.3.6 Set.prototype.forEach(callbackfn, thisArg = undefined) + // 23.1.3.5 Map.prototype.forEach(callbackfn, thisArg = undefined) + forEach: function forEach(callbackfn /* , that = undefined */) { + validate(this, NAME); + var f = ctx(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3); + var entry; + while (entry = entry ? entry.n : this._f) { + f(entry.v, entry.k, this); + // revert to the last existing entry + while (entry && entry.r) entry = entry.p; + } + }, + // 23.1.3.7 Map.prototype.has(key) + // 23.2.3.7 Set.prototype.has(value) + has: function has(key) { + return !!getEntry(validate(this, NAME), key); + } + }); + if (DESCRIPTORS) dP(C.prototype, 'size', { + get: function () { + return validate(this, NAME)[SIZE]; + } + }); + return C; + }, + def: function (that, key, value) { + var entry = getEntry(that, key); + var prev, index; + // change existing entry + if (entry) { + entry.v = value; + // create new entry + } else { + that._l = entry = { + i: index = fastKey(key, true), // <- index + k: key, // <- key + v: value, // <- value + p: prev = that._l, // <- previous entry + n: undefined, // <- next entry + r: false // <- removed + }; + if (!that._f) that._f = entry; + if (prev) prev.n = entry; + that[SIZE]++; + // add to index + if (index !== 'F') that._i[index] = entry; + } return that; + }, + getEntry: getEntry, + setStrong: function (C, NAME, IS_MAP) { + // add .keys, .values, .entries, [@@iterator] + // 23.1.3.4, 23.1.3.8, 23.1.3.11, 23.1.3.12, 23.2.3.5, 23.2.3.8, 23.2.3.10, 23.2.3.11 + $iterDefine(C, NAME, function (iterated, kind) { + this._t = validate(iterated, NAME); // target + this._k = kind; // kind + this._l = undefined; // previous + }, function () { + var that = this; + var kind = that._k; + var entry = that._l; + // revert to the last existing entry + while (entry && entry.r) entry = entry.p; + // get next entry + if (!that._t || !(that._l = entry = entry ? entry.n : that._t._f)) { + // or finish the iteration + that._t = undefined; + return step(1); + } + // return step by kind + if (kind == 'keys') return step(0, entry.k); + if (kind == 'values') return step(0, entry.v); + return step(0, [entry.k, entry.v]); + }, IS_MAP ? 'entries' : 'values', !IS_MAP, true); + + // add [@@species], 23.1.2.2, 23.2.2.2 + setSpecies(NAME); + } +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_collection-weak.js": +/*!**********************************************************!*\ + !*** ./node_modules/core-js/modules/_collection-weak.js ***! + \**********************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var redefineAll = __webpack_require__(/*! ./_redefine-all */ "./node_modules/core-js/modules/_redefine-all.js"); +var getWeak = __webpack_require__(/*! ./_meta */ "./node_modules/core-js/modules/_meta.js").getWeak; +var anObject = __webpack_require__(/*! ./_an-object */ "./node_modules/core-js/modules/_an-object.js"); +var isObject = __webpack_require__(/*! ./_is-object */ "./node_modules/core-js/modules/_is-object.js"); +var anInstance = __webpack_require__(/*! ./_an-instance */ "./node_modules/core-js/modules/_an-instance.js"); +var forOf = __webpack_require__(/*! ./_for-of */ "./node_modules/core-js/modules/_for-of.js"); +var createArrayMethod = __webpack_require__(/*! ./_array-methods */ "./node_modules/core-js/modules/_array-methods.js"); +var $has = __webpack_require__(/*! ./_has */ "./node_modules/core-js/modules/_has.js"); +var validate = __webpack_require__(/*! ./_validate-collection */ "./node_modules/core-js/modules/_validate-collection.js"); +var arrayFind = createArrayMethod(5); +var arrayFindIndex = createArrayMethod(6); +var id = 0; + +// fallback for uncaught frozen keys +var uncaughtFrozenStore = function (that) { + return that._l || (that._l = new UncaughtFrozenStore()); +}; +var UncaughtFrozenStore = function () { + this.a = []; +}; +var findUncaughtFrozen = function (store, key) { + return arrayFind(store.a, function (it) { + return it[0] === key; + }); +}; +UncaughtFrozenStore.prototype = { + get: function (key) { + var entry = findUncaughtFrozen(this, key); + if (entry) return entry[1]; + }, + has: function (key) { + return !!findUncaughtFrozen(this, key); + }, + set: function (key, value) { + var entry = findUncaughtFrozen(this, key); + if (entry) entry[1] = value; + else this.a.push([key, value]); + }, + 'delete': function (key) { + var index = arrayFindIndex(this.a, function (it) { + return it[0] === key; + }); + if (~index) this.a.splice(index, 1); + return !!~index; + } +}; + +module.exports = { + getConstructor: function (wrapper, NAME, IS_MAP, ADDER) { + var C = wrapper(function (that, iterable) { + anInstance(that, C, NAME, '_i'); + that._t = NAME; // collection type + that._i = id++; // collection id + that._l = undefined; // leak store for uncaught frozen objects + if (iterable != undefined) forOf(iterable, IS_MAP, that[ADDER], that); + }); + redefineAll(C.prototype, { + // 23.3.3.2 WeakMap.prototype.delete(key) + // 23.4.3.3 WeakSet.prototype.delete(value) + 'delete': function (key) { + if (!isObject(key)) return false; + var data = getWeak(key); + if (data === true) return uncaughtFrozenStore(validate(this, NAME))['delete'](key); + return data && $has(data, this._i) && delete data[this._i]; + }, + // 23.3.3.4 WeakMap.prototype.has(key) + // 23.4.3.4 WeakSet.prototype.has(value) + has: function has(key) { + if (!isObject(key)) return false; + var data = getWeak(key); + if (data === true) return uncaughtFrozenStore(validate(this, NAME)).has(key); + return data && $has(data, this._i); + } + }); + return C; + }, + def: function (that, key, value) { + var data = getWeak(anObject(key), true); + if (data === true) uncaughtFrozenStore(that).set(key, value); + else data[that._i] = value; + return that; + }, + ufstore: uncaughtFrozenStore +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_collection.js": +/*!*****************************************************!*\ + !*** ./node_modules/core-js/modules/_collection.js ***! + \*****************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var global = __webpack_require__(/*! ./_global */ "./node_modules/core-js/modules/_global.js"); +var $export = __webpack_require__(/*! ./_export */ "./node_modules/core-js/modules/_export.js"); +var redefine = __webpack_require__(/*! ./_redefine */ "./node_modules/core-js/modules/_redefine.js"); +var redefineAll = __webpack_require__(/*! ./_redefine-all */ "./node_modules/core-js/modules/_redefine-all.js"); +var meta = __webpack_require__(/*! ./_meta */ "./node_modules/core-js/modules/_meta.js"); +var forOf = __webpack_require__(/*! ./_for-of */ "./node_modules/core-js/modules/_for-of.js"); +var anInstance = __webpack_require__(/*! ./_an-instance */ "./node_modules/core-js/modules/_an-instance.js"); +var isObject = __webpack_require__(/*! ./_is-object */ "./node_modules/core-js/modules/_is-object.js"); +var fails = __webpack_require__(/*! ./_fails */ "./node_modules/core-js/modules/_fails.js"); +var $iterDetect = __webpack_require__(/*! ./_iter-detect */ "./node_modules/core-js/modules/_iter-detect.js"); +var setToStringTag = __webpack_require__(/*! ./_set-to-string-tag */ "./node_modules/core-js/modules/_set-to-string-tag.js"); +var inheritIfRequired = __webpack_require__(/*! ./_inherit-if-required */ "./node_modules/core-js/modules/_inherit-if-required.js"); + +module.exports = function (NAME, wrapper, methods, common, IS_MAP, IS_WEAK) { + var Base = global[NAME]; + var C = Base; + var ADDER = IS_MAP ? 'set' : 'add'; + var proto = C && C.prototype; + var O = {}; + var fixMethod = function (KEY) { + var fn = proto[KEY]; + redefine(proto, KEY, + KEY == 'delete' ? function (a) { + return IS_WEAK && !isObject(a) ? false : fn.call(this, a === 0 ? 0 : a); + } : KEY == 'has' ? function has(a) { + return IS_WEAK && !isObject(a) ? false : fn.call(this, a === 0 ? 0 : a); + } : KEY == 'get' ? function get(a) { + return IS_WEAK && !isObject(a) ? undefined : fn.call(this, a === 0 ? 0 : a); + } : KEY == 'add' ? function add(a) { fn.call(this, a === 0 ? 0 : a); return this; } + : function set(a, b) { fn.call(this, a === 0 ? 0 : a, b); return this; } + ); + }; + if (typeof C != 'function' || !(IS_WEAK || proto.forEach && !fails(function () { + new C().entries().next(); + }))) { + // create collection constructor + C = common.getConstructor(wrapper, NAME, IS_MAP, ADDER); + redefineAll(C.prototype, methods); + meta.NEED = true; + } else { + var instance = new C(); + // early implementations not supports chaining + var HASNT_CHAINING = instance[ADDER](IS_WEAK ? {} : -0, 1) != instance; + // V8 ~ Chromium 40- weak-collections throws on primitives, but should return false + var THROWS_ON_PRIMITIVES = fails(function () { instance.has(1); }); + // most early implementations doesn't supports iterables, most modern - not close it correctly + var ACCEPT_ITERABLES = $iterDetect(function (iter) { new C(iter); }); // eslint-disable-line no-new + // for early implementations -0 and +0 not the same + var BUGGY_ZERO = !IS_WEAK && fails(function () { + // V8 ~ Chromium 42- fails only with 5+ elements + var $instance = new C(); + var index = 5; + while (index--) $instance[ADDER](index, index); + return !$instance.has(-0); + }); + if (!ACCEPT_ITERABLES) { + C = wrapper(function (target, iterable) { + anInstance(target, C, NAME); + var that = inheritIfRequired(new Base(), target, C); + if (iterable != undefined) forOf(iterable, IS_MAP, that[ADDER], that); + return that; + }); + C.prototype = proto; + proto.constructor = C; + } + if (THROWS_ON_PRIMITIVES || BUGGY_ZERO) { + fixMethod('delete'); + fixMethod('has'); + IS_MAP && fixMethod('get'); + } + if (BUGGY_ZERO || HASNT_CHAINING) fixMethod(ADDER); + // weak collections should not contains .clear method + if (IS_WEAK && proto.clear) delete proto.clear; + } + + setToStringTag(C, NAME); + + O[NAME] = C; + $export($export.G + $export.W + $export.F * (C != Base), O); + + if (!IS_WEAK) common.setStrong(C, NAME, IS_MAP); + + return C; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_core.js": +/*!***********************************************!*\ + !*** ./node_modules/core-js/modules/_core.js ***! + \***********************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +var core = module.exports = { version: '2.5.7' }; +if (typeof __e == 'number') __e = core; // eslint-disable-line no-undef + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_ctx.js": +/*!**********************************************!*\ + !*** ./node_modules/core-js/modules/_ctx.js ***! + \**********************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +// optional / simple context binding +var aFunction = __webpack_require__(/*! ./_a-function */ "./node_modules/core-js/modules/_a-function.js"); +module.exports = function (fn, that, length) { + aFunction(fn); + if (that === undefined) return fn; + switch (length) { + case 1: return function (a) { + return fn.call(that, a); + }; + case 2: return function (a, b) { + return fn.call(that, a, b); + }; + case 3: return function (a, b, c) { + return fn.call(that, a, b, c); + }; + } + return function (/* ...args */) { + return fn.apply(that, arguments); + }; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_defined.js": +/*!**************************************************!*\ + !*** ./node_modules/core-js/modules/_defined.js ***! + \**************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +// 7.2.1 RequireObjectCoercible(argument) +module.exports = function (it) { + if (it == undefined) throw TypeError("Can't call method on " + it); + return it; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_descriptors.js": +/*!******************************************************!*\ + !*** ./node_modules/core-js/modules/_descriptors.js ***! + \******************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +// Thank's IE8 for his funny defineProperty +module.exports = !__webpack_require__(/*! ./_fails */ "./node_modules/core-js/modules/_fails.js")(function () { + return Object.defineProperty({}, 'a', { get: function () { return 7; } }).a != 7; +}); + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_dom-create.js": +/*!*****************************************************!*\ + !*** ./node_modules/core-js/modules/_dom-create.js ***! + \*****************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var isObject = __webpack_require__(/*! ./_is-object */ "./node_modules/core-js/modules/_is-object.js"); +var document = __webpack_require__(/*! ./_global */ "./node_modules/core-js/modules/_global.js").document; +// typeof document.createElement is 'object' in old IE +var is = isObject(document) && isObject(document.createElement); +module.exports = function (it) { + return is ? document.createElement(it) : {}; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_enum-bug-keys.js": +/*!********************************************************!*\ + !*** ./node_modules/core-js/modules/_enum-bug-keys.js ***! + \********************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +// IE 8- don't enum bug keys +module.exports = ( + 'constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf' +).split(','); + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_export.js": +/*!*************************************************!*\ + !*** ./node_modules/core-js/modules/_export.js ***! + \*************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var global = __webpack_require__(/*! ./_global */ "./node_modules/core-js/modules/_global.js"); +var core = __webpack_require__(/*! ./_core */ "./node_modules/core-js/modules/_core.js"); +var hide = __webpack_require__(/*! ./_hide */ "./node_modules/core-js/modules/_hide.js"); +var redefine = __webpack_require__(/*! ./_redefine */ "./node_modules/core-js/modules/_redefine.js"); +var ctx = __webpack_require__(/*! ./_ctx */ "./node_modules/core-js/modules/_ctx.js"); +var PROTOTYPE = 'prototype'; + +var $export = function (type, name, source) { + var IS_FORCED = type & $export.F; + var IS_GLOBAL = type & $export.G; + var IS_STATIC = type & $export.S; + var IS_PROTO = type & $export.P; + var IS_BIND = type & $export.B; + var target = IS_GLOBAL ? global : IS_STATIC ? global[name] || (global[name] = {}) : (global[name] || {})[PROTOTYPE]; + var exports = IS_GLOBAL ? core : core[name] || (core[name] = {}); + var expProto = exports[PROTOTYPE] || (exports[PROTOTYPE] = {}); + var key, own, out, exp; + if (IS_GLOBAL) source = name; + for (key in source) { + // contains in native + own = !IS_FORCED && target && target[key] !== undefined; + // export native or passed + out = (own ? target : source)[key]; + // bind timers to global for call from export context + exp = IS_BIND && own ? ctx(out, global) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out; + // extend global + if (target) redefine(target, key, out, type & $export.U); + // export + if (exports[key] != out) hide(exports, key, exp); + if (IS_PROTO && expProto[key] != out) expProto[key] = out; + } +}; +global.core = core; +// type bitmap +$export.F = 1; // forced +$export.G = 2; // global +$export.S = 4; // static +$export.P = 8; // proto +$export.B = 16; // bind +$export.W = 32; // wrap +$export.U = 64; // safe +$export.R = 128; // real proto method for `library` +module.exports = $export; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_fails.js": +/*!************************************************!*\ + !*** ./node_modules/core-js/modules/_fails.js ***! + \************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = function (exec) { + try { + return !!exec(); + } catch (e) { + return true; + } +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_for-of.js": +/*!*************************************************!*\ + !*** ./node_modules/core-js/modules/_for-of.js ***! + \*************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var ctx = __webpack_require__(/*! ./_ctx */ "./node_modules/core-js/modules/_ctx.js"); +var call = __webpack_require__(/*! ./_iter-call */ "./node_modules/core-js/modules/_iter-call.js"); +var isArrayIter = __webpack_require__(/*! ./_is-array-iter */ "./node_modules/core-js/modules/_is-array-iter.js"); +var anObject = __webpack_require__(/*! ./_an-object */ "./node_modules/core-js/modules/_an-object.js"); +var toLength = __webpack_require__(/*! ./_to-length */ "./node_modules/core-js/modules/_to-length.js"); +var getIterFn = __webpack_require__(/*! ./core.get-iterator-method */ "./node_modules/core-js/modules/core.get-iterator-method.js"); +var BREAK = {}; +var RETURN = {}; +var exports = module.exports = function (iterable, entries, fn, that, ITERATOR) { + var iterFn = ITERATOR ? function () { return iterable; } : getIterFn(iterable); + var f = ctx(fn, that, entries ? 2 : 1); + var index = 0; + var length, step, iterator, result; + if (typeof iterFn != 'function') throw TypeError(iterable + ' is not iterable!'); + // fast case for arrays with default iterator + if (isArrayIter(iterFn)) for (length = toLength(iterable.length); length > index; index++) { + result = entries ? f(anObject(step = iterable[index])[0], step[1]) : f(iterable[index]); + if (result === BREAK || result === RETURN) return result; + } else for (iterator = iterFn.call(iterable); !(step = iterator.next()).done;) { + result = call(iterator, f, step.value, entries); + if (result === BREAK || result === RETURN) return result; + } +}; +exports.BREAK = BREAK; +exports.RETURN = RETURN; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_global.js": +/*!*************************************************!*\ + !*** ./node_modules/core-js/modules/_global.js ***! + \*************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 +var global = module.exports = typeof window != 'undefined' && window.Math == Math + ? window : typeof self != 'undefined' && self.Math == Math ? self + // eslint-disable-next-line no-new-func + : Function('return this')(); +if (typeof __g == 'number') __g = global; // eslint-disable-line no-undef + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_has.js": +/*!**********************************************!*\ + !*** ./node_modules/core-js/modules/_has.js ***! + \**********************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +var hasOwnProperty = {}.hasOwnProperty; +module.exports = function (it, key) { + return hasOwnProperty.call(it, key); +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_hide.js": +/*!***********************************************!*\ + !*** ./node_modules/core-js/modules/_hide.js ***! + \***********************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var dP = __webpack_require__(/*! ./_object-dp */ "./node_modules/core-js/modules/_object-dp.js"); +var createDesc = __webpack_require__(/*! ./_property-desc */ "./node_modules/core-js/modules/_property-desc.js"); +module.exports = __webpack_require__(/*! ./_descriptors */ "./node_modules/core-js/modules/_descriptors.js") ? function (object, key, value) { + return dP.f(object, key, createDesc(1, value)); +} : function (object, key, value) { + object[key] = value; + return object; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_html.js": +/*!***********************************************!*\ + !*** ./node_modules/core-js/modules/_html.js ***! + \***********************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var document = __webpack_require__(/*! ./_global */ "./node_modules/core-js/modules/_global.js").document; +module.exports = document && document.documentElement; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_ie8-dom-define.js": +/*!*********************************************************!*\ + !*** ./node_modules/core-js/modules/_ie8-dom-define.js ***! + \*********************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +module.exports = !__webpack_require__(/*! ./_descriptors */ "./node_modules/core-js/modules/_descriptors.js") && !__webpack_require__(/*! ./_fails */ "./node_modules/core-js/modules/_fails.js")(function () { + return Object.defineProperty(__webpack_require__(/*! ./_dom-create */ "./node_modules/core-js/modules/_dom-create.js")('div'), 'a', { get: function () { return 7; } }).a != 7; +}); + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_inherit-if-required.js": +/*!**************************************************************!*\ + !*** ./node_modules/core-js/modules/_inherit-if-required.js ***! + \**************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var isObject = __webpack_require__(/*! ./_is-object */ "./node_modules/core-js/modules/_is-object.js"); +var setPrototypeOf = __webpack_require__(/*! ./_set-proto */ "./node_modules/core-js/modules/_set-proto.js").set; +module.exports = function (that, target, C) { + var S = target.constructor; + var P; + if (S !== C && typeof S == 'function' && (P = S.prototype) !== C.prototype && isObject(P) && setPrototypeOf) { + setPrototypeOf(that, P); + } return that; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_iobject.js": +/*!**************************************************!*\ + !*** ./node_modules/core-js/modules/_iobject.js ***! + \**************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +// fallback for non-array-like ES3 and non-enumerable old V8 strings +var cof = __webpack_require__(/*! ./_cof */ "./node_modules/core-js/modules/_cof.js"); +// eslint-disable-next-line no-prototype-builtins +module.exports = Object('z').propertyIsEnumerable(0) ? Object : function (it) { + return cof(it) == 'String' ? it.split('') : Object(it); +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_is-array-iter.js": +/*!********************************************************!*\ + !*** ./node_modules/core-js/modules/_is-array-iter.js ***! + \********************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +// check on default Array iterator +var Iterators = __webpack_require__(/*! ./_iterators */ "./node_modules/core-js/modules/_iterators.js"); +var ITERATOR = __webpack_require__(/*! ./_wks */ "./node_modules/core-js/modules/_wks.js")('iterator'); +var ArrayProto = Array.prototype; + +module.exports = function (it) { + return it !== undefined && (Iterators.Array === it || ArrayProto[ITERATOR] === it); +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_is-array.js": +/*!***************************************************!*\ + !*** ./node_modules/core-js/modules/_is-array.js ***! + \***************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +// 7.2.2 IsArray(argument) +var cof = __webpack_require__(/*! ./_cof */ "./node_modules/core-js/modules/_cof.js"); +module.exports = Array.isArray || function isArray(arg) { + return cof(arg) == 'Array'; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_is-object.js": +/*!****************************************************!*\ + !*** ./node_modules/core-js/modules/_is-object.js ***! + \****************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = function (it) { + return typeof it === 'object' ? it !== null : typeof it === 'function'; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_iter-call.js": +/*!****************************************************!*\ + !*** ./node_modules/core-js/modules/_iter-call.js ***! + \****************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +// call something on iterator step with safe closing on error +var anObject = __webpack_require__(/*! ./_an-object */ "./node_modules/core-js/modules/_an-object.js"); +module.exports = function (iterator, fn, value, entries) { + try { + return entries ? fn(anObject(value)[0], value[1]) : fn(value); + // 7.4.6 IteratorClose(iterator, completion) + } catch (e) { + var ret = iterator['return']; + if (ret !== undefined) anObject(ret.call(iterator)); + throw e; + } +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_iter-create.js": +/*!******************************************************!*\ + !*** ./node_modules/core-js/modules/_iter-create.js ***! + \******************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var create = __webpack_require__(/*! ./_object-create */ "./node_modules/core-js/modules/_object-create.js"); +var descriptor = __webpack_require__(/*! ./_property-desc */ "./node_modules/core-js/modules/_property-desc.js"); +var setToStringTag = __webpack_require__(/*! ./_set-to-string-tag */ "./node_modules/core-js/modules/_set-to-string-tag.js"); +var IteratorPrototype = {}; + +// 25.1.2.1.1 %IteratorPrototype%[@@iterator]() +__webpack_require__(/*! ./_hide */ "./node_modules/core-js/modules/_hide.js")(IteratorPrototype, __webpack_require__(/*! ./_wks */ "./node_modules/core-js/modules/_wks.js")('iterator'), function () { return this; }); + +module.exports = function (Constructor, NAME, next) { + Constructor.prototype = create(IteratorPrototype, { next: descriptor(1, next) }); + setToStringTag(Constructor, NAME + ' Iterator'); +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_iter-define.js": +/*!******************************************************!*\ + !*** ./node_modules/core-js/modules/_iter-define.js ***! + \******************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var LIBRARY = __webpack_require__(/*! ./_library */ "./node_modules/core-js/modules/_library.js"); +var $export = __webpack_require__(/*! ./_export */ "./node_modules/core-js/modules/_export.js"); +var redefine = __webpack_require__(/*! ./_redefine */ "./node_modules/core-js/modules/_redefine.js"); +var hide = __webpack_require__(/*! ./_hide */ "./node_modules/core-js/modules/_hide.js"); +var Iterators = __webpack_require__(/*! ./_iterators */ "./node_modules/core-js/modules/_iterators.js"); +var $iterCreate = __webpack_require__(/*! ./_iter-create */ "./node_modules/core-js/modules/_iter-create.js"); +var setToStringTag = __webpack_require__(/*! ./_set-to-string-tag */ "./node_modules/core-js/modules/_set-to-string-tag.js"); +var getPrototypeOf = __webpack_require__(/*! ./_object-gpo */ "./node_modules/core-js/modules/_object-gpo.js"); +var ITERATOR = __webpack_require__(/*! ./_wks */ "./node_modules/core-js/modules/_wks.js")('iterator'); +var BUGGY = !([].keys && 'next' in [].keys()); // Safari has buggy iterators w/o `next` +var FF_ITERATOR = '@@iterator'; +var KEYS = 'keys'; +var VALUES = 'values'; + +var returnThis = function () { return this; }; + +module.exports = function (Base, NAME, Constructor, next, DEFAULT, IS_SET, FORCED) { + $iterCreate(Constructor, NAME, next); + var getMethod = function (kind) { + if (!BUGGY && kind in proto) return proto[kind]; + switch (kind) { + case KEYS: return function keys() { return new Constructor(this, kind); }; + case VALUES: return function values() { return new Constructor(this, kind); }; + } return function entries() { return new Constructor(this, kind); }; + }; + var TAG = NAME + ' Iterator'; + var DEF_VALUES = DEFAULT == VALUES; + var VALUES_BUG = false; + var proto = Base.prototype; + var $native = proto[ITERATOR] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT]; + var $default = $native || getMethod(DEFAULT); + var $entries = DEFAULT ? !DEF_VALUES ? $default : getMethod('entries') : undefined; + var $anyNative = NAME == 'Array' ? proto.entries || $native : $native; + var methods, key, IteratorPrototype; + // Fix native + if ($anyNative) { + IteratorPrototype = getPrototypeOf($anyNative.call(new Base())); + if (IteratorPrototype !== Object.prototype && IteratorPrototype.next) { + // Set @@toStringTag to native iterators + setToStringTag(IteratorPrototype, TAG, true); + // fix for some old engines + if (!LIBRARY && typeof IteratorPrototype[ITERATOR] != 'function') hide(IteratorPrototype, ITERATOR, returnThis); + } + } + // fix Array#{values, @@iterator}.name in V8 / FF + if (DEF_VALUES && $native && $native.name !== VALUES) { + VALUES_BUG = true; + $default = function values() { return $native.call(this); }; + } + // Define iterator + if ((!LIBRARY || FORCED) && (BUGGY || VALUES_BUG || !proto[ITERATOR])) { + hide(proto, ITERATOR, $default); + } + // Plug for library + Iterators[NAME] = $default; + Iterators[TAG] = returnThis; + if (DEFAULT) { + methods = { + values: DEF_VALUES ? $default : getMethod(VALUES), + keys: IS_SET ? $default : getMethod(KEYS), + entries: $entries + }; + if (FORCED) for (key in methods) { + if (!(key in proto)) redefine(proto, key, methods[key]); + } else $export($export.P + $export.F * (BUGGY || VALUES_BUG), NAME, methods); + } + return methods; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_iter-detect.js": +/*!******************************************************!*\ + !*** ./node_modules/core-js/modules/_iter-detect.js ***! + \******************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var ITERATOR = __webpack_require__(/*! ./_wks */ "./node_modules/core-js/modules/_wks.js")('iterator'); +var SAFE_CLOSING = false; + +try { + var riter = [7][ITERATOR](); + riter['return'] = function () { SAFE_CLOSING = true; }; + // eslint-disable-next-line no-throw-literal + Array.from(riter, function () { throw 2; }); +} catch (e) { /* empty */ } + +module.exports = function (exec, skipClosing) { + if (!skipClosing && !SAFE_CLOSING) return false; + var safe = false; + try { + var arr = [7]; + var iter = arr[ITERATOR](); + iter.next = function () { return { done: safe = true }; }; + arr[ITERATOR] = function () { return iter; }; + exec(arr); + } catch (e) { /* empty */ } + return safe; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_iter-step.js": +/*!****************************************************!*\ + !*** ./node_modules/core-js/modules/_iter-step.js ***! + \****************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = function (done, value) { + return { value: value, done: !!done }; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_iterators.js": +/*!****************************************************!*\ + !*** ./node_modules/core-js/modules/_iterators.js ***! + \****************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = {}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_library.js": +/*!**************************************************!*\ + !*** ./node_modules/core-js/modules/_library.js ***! + \**************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = false; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_meta.js": +/*!***********************************************!*\ + !*** ./node_modules/core-js/modules/_meta.js ***! + \***********************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var META = __webpack_require__(/*! ./_uid */ "./node_modules/core-js/modules/_uid.js")('meta'); +var isObject = __webpack_require__(/*! ./_is-object */ "./node_modules/core-js/modules/_is-object.js"); +var has = __webpack_require__(/*! ./_has */ "./node_modules/core-js/modules/_has.js"); +var setDesc = __webpack_require__(/*! ./_object-dp */ "./node_modules/core-js/modules/_object-dp.js").f; +var id = 0; +var isExtensible = Object.isExtensible || function () { + return true; +}; +var FREEZE = !__webpack_require__(/*! ./_fails */ "./node_modules/core-js/modules/_fails.js")(function () { + return isExtensible(Object.preventExtensions({})); +}); +var setMeta = function (it) { + setDesc(it, META, { value: { + i: 'O' + ++id, // object ID + w: {} // weak collections IDs + } }); +}; +var fastKey = function (it, create) { + // return primitive with prefix + if (!isObject(it)) return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it; + if (!has(it, META)) { + // can't set metadata to uncaught frozen object + if (!isExtensible(it)) return 'F'; + // not necessary to add metadata + if (!create) return 'E'; + // add missing metadata + setMeta(it); + // return object ID + } return it[META].i; +}; +var getWeak = function (it, create) { + if (!has(it, META)) { + // can't set metadata to uncaught frozen object + if (!isExtensible(it)) return true; + // not necessary to add metadata + if (!create) return false; + // add missing metadata + setMeta(it); + // return hash weak collections IDs + } return it[META].w; +}; +// add metadata on freeze-family methods calling +var onFreeze = function (it) { + if (FREEZE && meta.NEED && isExtensible(it) && !has(it, META)) setMeta(it); + return it; +}; +var meta = module.exports = { + KEY: META, + NEED: false, + fastKey: fastKey, + getWeak: getWeak, + onFreeze: onFreeze +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_metadata.js": +/*!***************************************************!*\ + !*** ./node_modules/core-js/modules/_metadata.js ***! + \***************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var Map = __webpack_require__(/*! ./es6.map */ "./node_modules/core-js/modules/es6.map.js"); +var $export = __webpack_require__(/*! ./_export */ "./node_modules/core-js/modules/_export.js"); +var shared = __webpack_require__(/*! ./_shared */ "./node_modules/core-js/modules/_shared.js")('metadata'); +var store = shared.store || (shared.store = new (__webpack_require__(/*! ./es6.weak-map */ "./node_modules/core-js/modules/es6.weak-map.js"))()); + +var getOrCreateMetadataMap = function (target, targetKey, create) { + var targetMetadata = store.get(target); + if (!targetMetadata) { + if (!create) return undefined; + store.set(target, targetMetadata = new Map()); + } + var keyMetadata = targetMetadata.get(targetKey); + if (!keyMetadata) { + if (!create) return undefined; + targetMetadata.set(targetKey, keyMetadata = new Map()); + } return keyMetadata; +}; +var ordinaryHasOwnMetadata = function (MetadataKey, O, P) { + var metadataMap = getOrCreateMetadataMap(O, P, false); + return metadataMap === undefined ? false : metadataMap.has(MetadataKey); +}; +var ordinaryGetOwnMetadata = function (MetadataKey, O, P) { + var metadataMap = getOrCreateMetadataMap(O, P, false); + return metadataMap === undefined ? undefined : metadataMap.get(MetadataKey); +}; +var ordinaryDefineOwnMetadata = function (MetadataKey, MetadataValue, O, P) { + getOrCreateMetadataMap(O, P, true).set(MetadataKey, MetadataValue); +}; +var ordinaryOwnMetadataKeys = function (target, targetKey) { + var metadataMap = getOrCreateMetadataMap(target, targetKey, false); + var keys = []; + if (metadataMap) metadataMap.forEach(function (_, key) { keys.push(key); }); + return keys; +}; +var toMetaKey = function (it) { + return it === undefined || typeof it == 'symbol' ? it : String(it); +}; +var exp = function (O) { + $export($export.S, 'Reflect', O); +}; + +module.exports = { + store: store, + map: getOrCreateMetadataMap, + has: ordinaryHasOwnMetadata, + get: ordinaryGetOwnMetadata, + set: ordinaryDefineOwnMetadata, + keys: ordinaryOwnMetadataKeys, + key: toMetaKey, + exp: exp +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_object-assign.js": +/*!********************************************************!*\ + !*** ./node_modules/core-js/modules/_object-assign.js ***! + \********************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +// 19.1.2.1 Object.assign(target, source, ...) +var getKeys = __webpack_require__(/*! ./_object-keys */ "./node_modules/core-js/modules/_object-keys.js"); +var gOPS = __webpack_require__(/*! ./_object-gops */ "./node_modules/core-js/modules/_object-gops.js"); +var pIE = __webpack_require__(/*! ./_object-pie */ "./node_modules/core-js/modules/_object-pie.js"); +var toObject = __webpack_require__(/*! ./_to-object */ "./node_modules/core-js/modules/_to-object.js"); +var IObject = __webpack_require__(/*! ./_iobject */ "./node_modules/core-js/modules/_iobject.js"); +var $assign = Object.assign; + +// should work with symbols and should have deterministic property order (V8 bug) +module.exports = !$assign || __webpack_require__(/*! ./_fails */ "./node_modules/core-js/modules/_fails.js")(function () { + var A = {}; + var B = {}; + // eslint-disable-next-line no-undef + var S = Symbol(); + var K = 'abcdefghijklmnopqrst'; + A[S] = 7; + K.split('').forEach(function (k) { B[k] = k; }); + return $assign({}, A)[S] != 7 || Object.keys($assign({}, B)).join('') != K; +}) ? function assign(target, source) { // eslint-disable-line no-unused-vars + var T = toObject(target); + var aLen = arguments.length; + var index = 1; + var getSymbols = gOPS.f; + var isEnum = pIE.f; + while (aLen > index) { + var S = IObject(arguments[index++]); + var keys = getSymbols ? getKeys(S).concat(getSymbols(S)) : getKeys(S); + var length = keys.length; + var j = 0; + var key; + while (length > j) if (isEnum.call(S, key = keys[j++])) T[key] = S[key]; + } return T; +} : $assign; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_object-create.js": +/*!********************************************************!*\ + !*** ./node_modules/core-js/modules/_object-create.js ***! + \********************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +// 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties]) +var anObject = __webpack_require__(/*! ./_an-object */ "./node_modules/core-js/modules/_an-object.js"); +var dPs = __webpack_require__(/*! ./_object-dps */ "./node_modules/core-js/modules/_object-dps.js"); +var enumBugKeys = __webpack_require__(/*! ./_enum-bug-keys */ "./node_modules/core-js/modules/_enum-bug-keys.js"); +var IE_PROTO = __webpack_require__(/*! ./_shared-key */ "./node_modules/core-js/modules/_shared-key.js")('IE_PROTO'); +var Empty = function () { /* empty */ }; +var PROTOTYPE = 'prototype'; + +// Create object with fake `null` prototype: use iframe Object with cleared prototype +var createDict = function () { + // Thrash, waste and sodomy: IE GC bug + var iframe = __webpack_require__(/*! ./_dom-create */ "./node_modules/core-js/modules/_dom-create.js")('iframe'); + var i = enumBugKeys.length; + var lt = '<'; + var gt = '>'; + var iframeDocument; + iframe.style.display = 'none'; + __webpack_require__(/*! ./_html */ "./node_modules/core-js/modules/_html.js").appendChild(iframe); + iframe.src = 'javascript:'; // eslint-disable-line no-script-url + // createDict = iframe.contentWindow.Object; + // html.removeChild(iframe); + iframeDocument = iframe.contentWindow.document; + iframeDocument.open(); + iframeDocument.write(lt + 'script' + gt + 'document.F=Object' + lt + '/script' + gt); + iframeDocument.close(); + createDict = iframeDocument.F; + while (i--) delete createDict[PROTOTYPE][enumBugKeys[i]]; + return createDict(); +}; + +module.exports = Object.create || function create(O, Properties) { + var result; + if (O !== null) { + Empty[PROTOTYPE] = anObject(O); + result = new Empty(); + Empty[PROTOTYPE] = null; + // add "__proto__" for Object.getPrototypeOf polyfill + result[IE_PROTO] = O; + } else result = createDict(); + return Properties === undefined ? result : dPs(result, Properties); +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_object-dp.js": +/*!****************************************************!*\ + !*** ./node_modules/core-js/modules/_object-dp.js ***! + \****************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var anObject = __webpack_require__(/*! ./_an-object */ "./node_modules/core-js/modules/_an-object.js"); +var IE8_DOM_DEFINE = __webpack_require__(/*! ./_ie8-dom-define */ "./node_modules/core-js/modules/_ie8-dom-define.js"); +var toPrimitive = __webpack_require__(/*! ./_to-primitive */ "./node_modules/core-js/modules/_to-primitive.js"); +var dP = Object.defineProperty; + +exports.f = __webpack_require__(/*! ./_descriptors */ "./node_modules/core-js/modules/_descriptors.js") ? Object.defineProperty : function defineProperty(O, P, Attributes) { + anObject(O); + P = toPrimitive(P, true); + anObject(Attributes); + if (IE8_DOM_DEFINE) try { + return dP(O, P, Attributes); + } catch (e) { /* empty */ } + if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported!'); + if ('value' in Attributes) O[P] = Attributes.value; + return O; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_object-dps.js": +/*!*****************************************************!*\ + !*** ./node_modules/core-js/modules/_object-dps.js ***! + \*****************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var dP = __webpack_require__(/*! ./_object-dp */ "./node_modules/core-js/modules/_object-dp.js"); +var anObject = __webpack_require__(/*! ./_an-object */ "./node_modules/core-js/modules/_an-object.js"); +var getKeys = __webpack_require__(/*! ./_object-keys */ "./node_modules/core-js/modules/_object-keys.js"); + +module.exports = __webpack_require__(/*! ./_descriptors */ "./node_modules/core-js/modules/_descriptors.js") ? Object.defineProperties : function defineProperties(O, Properties) { + anObject(O); + var keys = getKeys(Properties); + var length = keys.length; + var i = 0; + var P; + while (length > i) dP.f(O, P = keys[i++], Properties[P]); + return O; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_object-gopd.js": +/*!******************************************************!*\ + !*** ./node_modules/core-js/modules/_object-gopd.js ***! + \******************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var pIE = __webpack_require__(/*! ./_object-pie */ "./node_modules/core-js/modules/_object-pie.js"); +var createDesc = __webpack_require__(/*! ./_property-desc */ "./node_modules/core-js/modules/_property-desc.js"); +var toIObject = __webpack_require__(/*! ./_to-iobject */ "./node_modules/core-js/modules/_to-iobject.js"); +var toPrimitive = __webpack_require__(/*! ./_to-primitive */ "./node_modules/core-js/modules/_to-primitive.js"); +var has = __webpack_require__(/*! ./_has */ "./node_modules/core-js/modules/_has.js"); +var IE8_DOM_DEFINE = __webpack_require__(/*! ./_ie8-dom-define */ "./node_modules/core-js/modules/_ie8-dom-define.js"); +var gOPD = Object.getOwnPropertyDescriptor; + +exports.f = __webpack_require__(/*! ./_descriptors */ "./node_modules/core-js/modules/_descriptors.js") ? gOPD : function getOwnPropertyDescriptor(O, P) { + O = toIObject(O); + P = toPrimitive(P, true); + if (IE8_DOM_DEFINE) try { + return gOPD(O, P); + } catch (e) { /* empty */ } + if (has(O, P)) return createDesc(!pIE.f.call(O, P), O[P]); +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_object-gops.js": +/*!******************************************************!*\ + !*** ./node_modules/core-js/modules/_object-gops.js ***! + \******************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +exports.f = Object.getOwnPropertySymbols; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_object-gpo.js": +/*!*****************************************************!*\ + !*** ./node_modules/core-js/modules/_object-gpo.js ***! + \*****************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +// 19.1.2.9 / 15.2.3.2 Object.getPrototypeOf(O) +var has = __webpack_require__(/*! ./_has */ "./node_modules/core-js/modules/_has.js"); +var toObject = __webpack_require__(/*! ./_to-object */ "./node_modules/core-js/modules/_to-object.js"); +var IE_PROTO = __webpack_require__(/*! ./_shared-key */ "./node_modules/core-js/modules/_shared-key.js")('IE_PROTO'); +var ObjectProto = Object.prototype; + +module.exports = Object.getPrototypeOf || function (O) { + O = toObject(O); + if (has(O, IE_PROTO)) return O[IE_PROTO]; + if (typeof O.constructor == 'function' && O instanceof O.constructor) { + return O.constructor.prototype; + } return O instanceof Object ? ObjectProto : null; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_object-keys-internal.js": +/*!***************************************************************!*\ + !*** ./node_modules/core-js/modules/_object-keys-internal.js ***! + \***************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var has = __webpack_require__(/*! ./_has */ "./node_modules/core-js/modules/_has.js"); +var toIObject = __webpack_require__(/*! ./_to-iobject */ "./node_modules/core-js/modules/_to-iobject.js"); +var arrayIndexOf = __webpack_require__(/*! ./_array-includes */ "./node_modules/core-js/modules/_array-includes.js")(false); +var IE_PROTO = __webpack_require__(/*! ./_shared-key */ "./node_modules/core-js/modules/_shared-key.js")('IE_PROTO'); + +module.exports = function (object, names) { + var O = toIObject(object); + var i = 0; + var result = []; + var key; + for (key in O) if (key != IE_PROTO) has(O, key) && result.push(key); + // Don't enum bug & hidden keys + while (names.length > i) if (has(O, key = names[i++])) { + ~arrayIndexOf(result, key) || result.push(key); + } + return result; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_object-keys.js": +/*!******************************************************!*\ + !*** ./node_modules/core-js/modules/_object-keys.js ***! + \******************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +// 19.1.2.14 / 15.2.3.14 Object.keys(O) +var $keys = __webpack_require__(/*! ./_object-keys-internal */ "./node_modules/core-js/modules/_object-keys-internal.js"); +var enumBugKeys = __webpack_require__(/*! ./_enum-bug-keys */ "./node_modules/core-js/modules/_enum-bug-keys.js"); + +module.exports = Object.keys || function keys(O) { + return $keys(O, enumBugKeys); +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_object-pie.js": +/*!*****************************************************!*\ + !*** ./node_modules/core-js/modules/_object-pie.js ***! + \*****************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +exports.f = {}.propertyIsEnumerable; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_property-desc.js": +/*!********************************************************!*\ + !*** ./node_modules/core-js/modules/_property-desc.js ***! + \********************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = function (bitmap, value) { + return { + enumerable: !(bitmap & 1), + configurable: !(bitmap & 2), + writable: !(bitmap & 4), + value: value + }; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_redefine-all.js": +/*!*******************************************************!*\ + !*** ./node_modules/core-js/modules/_redefine-all.js ***! + \*******************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var redefine = __webpack_require__(/*! ./_redefine */ "./node_modules/core-js/modules/_redefine.js"); +module.exports = function (target, src, safe) { + for (var key in src) redefine(target, key, src[key], safe); + return target; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_redefine.js": +/*!***************************************************!*\ + !*** ./node_modules/core-js/modules/_redefine.js ***! + \***************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var global = __webpack_require__(/*! ./_global */ "./node_modules/core-js/modules/_global.js"); +var hide = __webpack_require__(/*! ./_hide */ "./node_modules/core-js/modules/_hide.js"); +var has = __webpack_require__(/*! ./_has */ "./node_modules/core-js/modules/_has.js"); +var SRC = __webpack_require__(/*! ./_uid */ "./node_modules/core-js/modules/_uid.js")('src'); +var TO_STRING = 'toString'; +var $toString = Function[TO_STRING]; +var TPL = ('' + $toString).split(TO_STRING); + +__webpack_require__(/*! ./_core */ "./node_modules/core-js/modules/_core.js").inspectSource = function (it) { + return $toString.call(it); +}; + +(module.exports = function (O, key, val, safe) { + var isFunction = typeof val == 'function'; + if (isFunction) has(val, 'name') || hide(val, 'name', key); + if (O[key] === val) return; + if (isFunction) has(val, SRC) || hide(val, SRC, O[key] ? '' + O[key] : TPL.join(String(key))); + if (O === global) { + O[key] = val; + } else if (!safe) { + delete O[key]; + hide(O, key, val); + } else if (O[key]) { + O[key] = val; + } else { + hide(O, key, val); + } +// add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative +})(Function.prototype, TO_STRING, function toString() { + return typeof this == 'function' && this[SRC] || $toString.call(this); +}); + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_set-proto.js": +/*!****************************************************!*\ + !*** ./node_modules/core-js/modules/_set-proto.js ***! + \****************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +// Works with __proto__ only. Old v8 can't work with null proto objects. +/* eslint-disable no-proto */ +var isObject = __webpack_require__(/*! ./_is-object */ "./node_modules/core-js/modules/_is-object.js"); +var anObject = __webpack_require__(/*! ./_an-object */ "./node_modules/core-js/modules/_an-object.js"); +var check = function (O, proto) { + anObject(O); + if (!isObject(proto) && proto !== null) throw TypeError(proto + ": can't set as prototype!"); +}; +module.exports = { + set: Object.setPrototypeOf || ('__proto__' in {} ? // eslint-disable-line + function (test, buggy, set) { + try { + set = __webpack_require__(/*! ./_ctx */ "./node_modules/core-js/modules/_ctx.js")(Function.call, __webpack_require__(/*! ./_object-gopd */ "./node_modules/core-js/modules/_object-gopd.js").f(Object.prototype, '__proto__').set, 2); + set(test, []); + buggy = !(test instanceof Array); + } catch (e) { buggy = true; } + return function setPrototypeOf(O, proto) { + check(O, proto); + if (buggy) O.__proto__ = proto; + else set(O, proto); + return O; + }; + }({}, false) : undefined), + check: check +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_set-species.js": +/*!******************************************************!*\ + !*** ./node_modules/core-js/modules/_set-species.js ***! + \******************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var global = __webpack_require__(/*! ./_global */ "./node_modules/core-js/modules/_global.js"); +var dP = __webpack_require__(/*! ./_object-dp */ "./node_modules/core-js/modules/_object-dp.js"); +var DESCRIPTORS = __webpack_require__(/*! ./_descriptors */ "./node_modules/core-js/modules/_descriptors.js"); +var SPECIES = __webpack_require__(/*! ./_wks */ "./node_modules/core-js/modules/_wks.js")('species'); + +module.exports = function (KEY) { + var C = global[KEY]; + if (DESCRIPTORS && C && !C[SPECIES]) dP.f(C, SPECIES, { + configurable: true, + get: function () { return this; } + }); +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_set-to-string-tag.js": +/*!************************************************************!*\ + !*** ./node_modules/core-js/modules/_set-to-string-tag.js ***! + \************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var def = __webpack_require__(/*! ./_object-dp */ "./node_modules/core-js/modules/_object-dp.js").f; +var has = __webpack_require__(/*! ./_has */ "./node_modules/core-js/modules/_has.js"); +var TAG = __webpack_require__(/*! ./_wks */ "./node_modules/core-js/modules/_wks.js")('toStringTag'); + +module.exports = function (it, tag, stat) { + if (it && !has(it = stat ? it : it.prototype, TAG)) def(it, TAG, { configurable: true, value: tag }); +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_shared-key.js": +/*!*****************************************************!*\ + !*** ./node_modules/core-js/modules/_shared-key.js ***! + \*****************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var shared = __webpack_require__(/*! ./_shared */ "./node_modules/core-js/modules/_shared.js")('keys'); +var uid = __webpack_require__(/*! ./_uid */ "./node_modules/core-js/modules/_uid.js"); +module.exports = function (key) { + return shared[key] || (shared[key] = uid(key)); +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_shared.js": +/*!*************************************************!*\ + !*** ./node_modules/core-js/modules/_shared.js ***! + \*************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var core = __webpack_require__(/*! ./_core */ "./node_modules/core-js/modules/_core.js"); +var global = __webpack_require__(/*! ./_global */ "./node_modules/core-js/modules/_global.js"); +var SHARED = '__core-js_shared__'; +var store = global[SHARED] || (global[SHARED] = {}); + +(module.exports = function (key, value) { + return store[key] || (store[key] = value !== undefined ? value : {}); +})('versions', []).push({ + version: core.version, + mode: __webpack_require__(/*! ./_library */ "./node_modules/core-js/modules/_library.js") ? 'pure' : 'global', + copyright: '© 2018 Denis Pushkarev (zloirock.ru)' +}); + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_to-absolute-index.js": +/*!************************************************************!*\ + !*** ./node_modules/core-js/modules/_to-absolute-index.js ***! + \************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var toInteger = __webpack_require__(/*! ./_to-integer */ "./node_modules/core-js/modules/_to-integer.js"); +var max = Math.max; +var min = Math.min; +module.exports = function (index, length) { + index = toInteger(index); + return index < 0 ? max(index + length, 0) : min(index, length); +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_to-integer.js": +/*!*****************************************************!*\ + !*** ./node_modules/core-js/modules/_to-integer.js ***! + \*****************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +// 7.1.4 ToInteger +var ceil = Math.ceil; +var floor = Math.floor; +module.exports = function (it) { + return isNaN(it = +it) ? 0 : (it > 0 ? floor : ceil)(it); +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_to-iobject.js": +/*!*****************************************************!*\ + !*** ./node_modules/core-js/modules/_to-iobject.js ***! + \*****************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +// to indexed object, toObject with fallback for non-array-like ES3 strings +var IObject = __webpack_require__(/*! ./_iobject */ "./node_modules/core-js/modules/_iobject.js"); +var defined = __webpack_require__(/*! ./_defined */ "./node_modules/core-js/modules/_defined.js"); +module.exports = function (it) { + return IObject(defined(it)); +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_to-length.js": +/*!****************************************************!*\ + !*** ./node_modules/core-js/modules/_to-length.js ***! + \****************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +// 7.1.15 ToLength +var toInteger = __webpack_require__(/*! ./_to-integer */ "./node_modules/core-js/modules/_to-integer.js"); +var min = Math.min; +module.exports = function (it) { + return it > 0 ? min(toInteger(it), 0x1fffffffffffff) : 0; // pow(2, 53) - 1 == 9007199254740991 +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_to-object.js": +/*!****************************************************!*\ + !*** ./node_modules/core-js/modules/_to-object.js ***! + \****************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +// 7.1.13 ToObject(argument) +var defined = __webpack_require__(/*! ./_defined */ "./node_modules/core-js/modules/_defined.js"); +module.exports = function (it) { + return Object(defined(it)); +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_to-primitive.js": +/*!*******************************************************!*\ + !*** ./node_modules/core-js/modules/_to-primitive.js ***! + \*******************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +// 7.1.1 ToPrimitive(input [, PreferredType]) +var isObject = __webpack_require__(/*! ./_is-object */ "./node_modules/core-js/modules/_is-object.js"); +// instead of the ES6 spec version, we didn't implement @@toPrimitive case +// and the second argument - flag - preferred type is a string +module.exports = function (it, S) { + if (!isObject(it)) return it; + var fn, val; + if (S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it))) return val; + if (typeof (fn = it.valueOf) == 'function' && !isObject(val = fn.call(it))) return val; + if (!S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it))) return val; + throw TypeError("Can't convert object to primitive value"); +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_uid.js": +/*!**********************************************!*\ + !*** ./node_modules/core-js/modules/_uid.js ***! + \**********************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +var id = 0; +var px = Math.random(); +module.exports = function (key) { + return 'Symbol('.concat(key === undefined ? '' : key, ')_', (++id + px).toString(36)); +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_validate-collection.js": +/*!**************************************************************!*\ + !*** ./node_modules/core-js/modules/_validate-collection.js ***! + \**************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var isObject = __webpack_require__(/*! ./_is-object */ "./node_modules/core-js/modules/_is-object.js"); +module.exports = function (it, TYPE) { + if (!isObject(it) || it._t !== TYPE) throw TypeError('Incompatible receiver, ' + TYPE + ' required!'); + return it; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/_wks.js": +/*!**********************************************!*\ + !*** ./node_modules/core-js/modules/_wks.js ***! + \**********************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var store = __webpack_require__(/*! ./_shared */ "./node_modules/core-js/modules/_shared.js")('wks'); +var uid = __webpack_require__(/*! ./_uid */ "./node_modules/core-js/modules/_uid.js"); +var Symbol = __webpack_require__(/*! ./_global */ "./node_modules/core-js/modules/_global.js").Symbol; +var USE_SYMBOL = typeof Symbol == 'function'; + +var $exports = module.exports = function (name) { + return store[name] || (store[name] = + USE_SYMBOL && Symbol[name] || (USE_SYMBOL ? Symbol : uid)('Symbol.' + name)); +}; + +$exports.store = store; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/core.get-iterator-method.js": +/*!******************************************************************!*\ + !*** ./node_modules/core-js/modules/core.get-iterator-method.js ***! + \******************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var classof = __webpack_require__(/*! ./_classof */ "./node_modules/core-js/modules/_classof.js"); +var ITERATOR = __webpack_require__(/*! ./_wks */ "./node_modules/core-js/modules/_wks.js")('iterator'); +var Iterators = __webpack_require__(/*! ./_iterators */ "./node_modules/core-js/modules/_iterators.js"); +module.exports = __webpack_require__(/*! ./_core */ "./node_modules/core-js/modules/_core.js").getIteratorMethod = function (it) { + if (it != undefined) return it[ITERATOR] + || it['@@iterator'] + || Iterators[classof(it)]; +}; + + +/***/ }), + +/***/ "./node_modules/core-js/modules/es6.map.js": +/*!*************************************************!*\ + !*** ./node_modules/core-js/modules/es6.map.js ***! + \*************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var strong = __webpack_require__(/*! ./_collection-strong */ "./node_modules/core-js/modules/_collection-strong.js"); +var validate = __webpack_require__(/*! ./_validate-collection */ "./node_modules/core-js/modules/_validate-collection.js"); +var MAP = 'Map'; + +// 23.1 Map Objects +module.exports = __webpack_require__(/*! ./_collection */ "./node_modules/core-js/modules/_collection.js")(MAP, function (get) { + return function Map() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; +}, { + // 23.1.3.6 Map.prototype.get(key) + get: function get(key) { + var entry = strong.getEntry(validate(this, MAP), key); + return entry && entry.v; + }, + // 23.1.3.9 Map.prototype.set(key, value) + set: function set(key, value) { + return strong.def(validate(this, MAP), key === 0 ? 0 : key, value); + } +}, strong, true); + + +/***/ }), + +/***/ "./node_modules/core-js/modules/es6.set.js": +/*!*************************************************!*\ + !*** ./node_modules/core-js/modules/es6.set.js ***! + \*************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var strong = __webpack_require__(/*! ./_collection-strong */ "./node_modules/core-js/modules/_collection-strong.js"); +var validate = __webpack_require__(/*! ./_validate-collection */ "./node_modules/core-js/modules/_validate-collection.js"); +var SET = 'Set'; + +// 23.2 Set Objects +module.exports = __webpack_require__(/*! ./_collection */ "./node_modules/core-js/modules/_collection.js")(SET, function (get) { + return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; +}, { + // 23.2.3.1 Set.prototype.add(value) + add: function add(value) { + return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); + } +}, strong); + + +/***/ }), + +/***/ "./node_modules/core-js/modules/es6.weak-map.js": +/*!******************************************************!*\ + !*** ./node_modules/core-js/modules/es6.weak-map.js ***! + \******************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var each = __webpack_require__(/*! ./_array-methods */ "./node_modules/core-js/modules/_array-methods.js")(0); +var redefine = __webpack_require__(/*! ./_redefine */ "./node_modules/core-js/modules/_redefine.js"); +var meta = __webpack_require__(/*! ./_meta */ "./node_modules/core-js/modules/_meta.js"); +var assign = __webpack_require__(/*! ./_object-assign */ "./node_modules/core-js/modules/_object-assign.js"); +var weak = __webpack_require__(/*! ./_collection-weak */ "./node_modules/core-js/modules/_collection-weak.js"); +var isObject = __webpack_require__(/*! ./_is-object */ "./node_modules/core-js/modules/_is-object.js"); +var fails = __webpack_require__(/*! ./_fails */ "./node_modules/core-js/modules/_fails.js"); +var validate = __webpack_require__(/*! ./_validate-collection */ "./node_modules/core-js/modules/_validate-collection.js"); +var WEAK_MAP = 'WeakMap'; +var getWeak = meta.getWeak; +var isExtensible = Object.isExtensible; +var uncaughtFrozenStore = weak.ufstore; +var tmp = {}; +var InternalMap; + +var wrapper = function (get) { + return function WeakMap() { + return get(this, arguments.length > 0 ? arguments[0] : undefined); + }; +}; + +var methods = { + // 23.3.3.3 WeakMap.prototype.get(key) + get: function get(key) { + if (isObject(key)) { + var data = getWeak(key); + if (data === true) return uncaughtFrozenStore(validate(this, WEAK_MAP)).get(key); + return data ? data[this._i] : undefined; + } + }, + // 23.3.3.5 WeakMap.prototype.set(key, value) + set: function set(key, value) { + return weak.def(validate(this, WEAK_MAP), key, value); + } +}; + +// 23.3 WeakMap Objects +var $WeakMap = module.exports = __webpack_require__(/*! ./_collection */ "./node_modules/core-js/modules/_collection.js")(WEAK_MAP, wrapper, methods, weak, true, true); + +// IE11 WeakMap frozen keys fix +if (fails(function () { return new $WeakMap().set((Object.freeze || Object)(tmp), 7).get(tmp) != 7; })) { + InternalMap = weak.getConstructor(wrapper, WEAK_MAP); + assign(InternalMap.prototype, methods); + meta.NEED = true; + each(['delete', 'has', 'get', 'set'], function (key) { + var proto = $WeakMap.prototype; + var method = proto[key]; + redefine(proto, key, function (a, b) { + // store frozen objects on internal weakmap shim + if (isObject(a) && !isExtensible(a)) { + if (!this._f) this._f = new InternalMap(); + var result = this._f[key](a, b); + return key == 'set' ? this : result; + // store all the rest on native weakmap + } return method.call(this, a, b); + }); + }); +} + + +/***/ }), + +/***/ "./node_modules/core-js/modules/es7.reflect.define-metadata.js": +/*!*********************************************************************!*\ + !*** ./node_modules/core-js/modules/es7.reflect.define-metadata.js ***! + \*********************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var metadata = __webpack_require__(/*! ./_metadata */ "./node_modules/core-js/modules/_metadata.js"); +var anObject = __webpack_require__(/*! ./_an-object */ "./node_modules/core-js/modules/_an-object.js"); +var toMetaKey = metadata.key; +var ordinaryDefineOwnMetadata = metadata.set; + +metadata.exp({ defineMetadata: function defineMetadata(metadataKey, metadataValue, target, targetKey) { + ordinaryDefineOwnMetadata(metadataKey, metadataValue, anObject(target), toMetaKey(targetKey)); +} }); + + +/***/ }), + +/***/ "./node_modules/core-js/modules/es7.reflect.delete-metadata.js": +/*!*********************************************************************!*\ + !*** ./node_modules/core-js/modules/es7.reflect.delete-metadata.js ***! + \*********************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var metadata = __webpack_require__(/*! ./_metadata */ "./node_modules/core-js/modules/_metadata.js"); +var anObject = __webpack_require__(/*! ./_an-object */ "./node_modules/core-js/modules/_an-object.js"); +var toMetaKey = metadata.key; +var getOrCreateMetadataMap = metadata.map; +var store = metadata.store; + +metadata.exp({ deleteMetadata: function deleteMetadata(metadataKey, target /* , targetKey */) { + var targetKey = arguments.length < 3 ? undefined : toMetaKey(arguments[2]); + var metadataMap = getOrCreateMetadataMap(anObject(target), targetKey, false); + if (metadataMap === undefined || !metadataMap['delete'](metadataKey)) return false; + if (metadataMap.size) return true; + var targetMetadata = store.get(target); + targetMetadata['delete'](targetKey); + return !!targetMetadata.size || store['delete'](target); +} }); + + +/***/ }), + +/***/ "./node_modules/core-js/modules/es7.reflect.get-metadata-keys.js": +/*!***********************************************************************!*\ + !*** ./node_modules/core-js/modules/es7.reflect.get-metadata-keys.js ***! + \***********************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var Set = __webpack_require__(/*! ./es6.set */ "./node_modules/core-js/modules/es6.set.js"); +var from = __webpack_require__(/*! ./_array-from-iterable */ "./node_modules/core-js/modules/_array-from-iterable.js"); +var metadata = __webpack_require__(/*! ./_metadata */ "./node_modules/core-js/modules/_metadata.js"); +var anObject = __webpack_require__(/*! ./_an-object */ "./node_modules/core-js/modules/_an-object.js"); +var getPrototypeOf = __webpack_require__(/*! ./_object-gpo */ "./node_modules/core-js/modules/_object-gpo.js"); +var ordinaryOwnMetadataKeys = metadata.keys; +var toMetaKey = metadata.key; + +var ordinaryMetadataKeys = function (O, P) { + var oKeys = ordinaryOwnMetadataKeys(O, P); + var parent = getPrototypeOf(O); + if (parent === null) return oKeys; + var pKeys = ordinaryMetadataKeys(parent, P); + return pKeys.length ? oKeys.length ? from(new Set(oKeys.concat(pKeys))) : pKeys : oKeys; +}; + +metadata.exp({ getMetadataKeys: function getMetadataKeys(target /* , targetKey */) { + return ordinaryMetadataKeys(anObject(target), arguments.length < 2 ? undefined : toMetaKey(arguments[1])); +} }); + + +/***/ }), + +/***/ "./node_modules/core-js/modules/es7.reflect.get-metadata.js": +/*!******************************************************************!*\ + !*** ./node_modules/core-js/modules/es7.reflect.get-metadata.js ***! + \******************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var metadata = __webpack_require__(/*! ./_metadata */ "./node_modules/core-js/modules/_metadata.js"); +var anObject = __webpack_require__(/*! ./_an-object */ "./node_modules/core-js/modules/_an-object.js"); +var getPrototypeOf = __webpack_require__(/*! ./_object-gpo */ "./node_modules/core-js/modules/_object-gpo.js"); +var ordinaryHasOwnMetadata = metadata.has; +var ordinaryGetOwnMetadata = metadata.get; +var toMetaKey = metadata.key; + +var ordinaryGetMetadata = function (MetadataKey, O, P) { + var hasOwn = ordinaryHasOwnMetadata(MetadataKey, O, P); + if (hasOwn) return ordinaryGetOwnMetadata(MetadataKey, O, P); + var parent = getPrototypeOf(O); + return parent !== null ? ordinaryGetMetadata(MetadataKey, parent, P) : undefined; +}; + +metadata.exp({ getMetadata: function getMetadata(metadataKey, target /* , targetKey */) { + return ordinaryGetMetadata(metadataKey, anObject(target), arguments.length < 3 ? undefined : toMetaKey(arguments[2])); +} }); + + +/***/ }), + +/***/ "./node_modules/core-js/modules/es7.reflect.get-own-metadata-keys.js": +/*!***************************************************************************!*\ + !*** ./node_modules/core-js/modules/es7.reflect.get-own-metadata-keys.js ***! + \***************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var metadata = __webpack_require__(/*! ./_metadata */ "./node_modules/core-js/modules/_metadata.js"); +var anObject = __webpack_require__(/*! ./_an-object */ "./node_modules/core-js/modules/_an-object.js"); +var ordinaryOwnMetadataKeys = metadata.keys; +var toMetaKey = metadata.key; + +metadata.exp({ getOwnMetadataKeys: function getOwnMetadataKeys(target /* , targetKey */) { + return ordinaryOwnMetadataKeys(anObject(target), arguments.length < 2 ? undefined : toMetaKey(arguments[1])); +} }); + + +/***/ }), + +/***/ "./node_modules/core-js/modules/es7.reflect.get-own-metadata.js": +/*!**********************************************************************!*\ + !*** ./node_modules/core-js/modules/es7.reflect.get-own-metadata.js ***! + \**********************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var metadata = __webpack_require__(/*! ./_metadata */ "./node_modules/core-js/modules/_metadata.js"); +var anObject = __webpack_require__(/*! ./_an-object */ "./node_modules/core-js/modules/_an-object.js"); +var ordinaryGetOwnMetadata = metadata.get; +var toMetaKey = metadata.key; + +metadata.exp({ getOwnMetadata: function getOwnMetadata(metadataKey, target /* , targetKey */) { + return ordinaryGetOwnMetadata(metadataKey, anObject(target) + , arguments.length < 3 ? undefined : toMetaKey(arguments[2])); +} }); + + +/***/ }), + +/***/ "./node_modules/core-js/modules/es7.reflect.has-metadata.js": +/*!******************************************************************!*\ + !*** ./node_modules/core-js/modules/es7.reflect.has-metadata.js ***! + \******************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var metadata = __webpack_require__(/*! ./_metadata */ "./node_modules/core-js/modules/_metadata.js"); +var anObject = __webpack_require__(/*! ./_an-object */ "./node_modules/core-js/modules/_an-object.js"); +var getPrototypeOf = __webpack_require__(/*! ./_object-gpo */ "./node_modules/core-js/modules/_object-gpo.js"); +var ordinaryHasOwnMetadata = metadata.has; +var toMetaKey = metadata.key; + +var ordinaryHasMetadata = function (MetadataKey, O, P) { + var hasOwn = ordinaryHasOwnMetadata(MetadataKey, O, P); + if (hasOwn) return true; + var parent = getPrototypeOf(O); + return parent !== null ? ordinaryHasMetadata(MetadataKey, parent, P) : false; +}; + +metadata.exp({ hasMetadata: function hasMetadata(metadataKey, target /* , targetKey */) { + return ordinaryHasMetadata(metadataKey, anObject(target), arguments.length < 3 ? undefined : toMetaKey(arguments[2])); +} }); + + +/***/ }), + +/***/ "./node_modules/core-js/modules/es7.reflect.has-own-metadata.js": +/*!**********************************************************************!*\ + !*** ./node_modules/core-js/modules/es7.reflect.has-own-metadata.js ***! + \**********************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var metadata = __webpack_require__(/*! ./_metadata */ "./node_modules/core-js/modules/_metadata.js"); +var anObject = __webpack_require__(/*! ./_an-object */ "./node_modules/core-js/modules/_an-object.js"); +var ordinaryHasOwnMetadata = metadata.has; +var toMetaKey = metadata.key; + +metadata.exp({ hasOwnMetadata: function hasOwnMetadata(metadataKey, target /* , targetKey */) { + return ordinaryHasOwnMetadata(metadataKey, anObject(target) + , arguments.length < 3 ? undefined : toMetaKey(arguments[2])); +} }); + + +/***/ }), + +/***/ "./node_modules/core-js/modules/es7.reflect.metadata.js": +/*!**************************************************************!*\ + !*** ./node_modules/core-js/modules/es7.reflect.metadata.js ***! + \**************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var $metadata = __webpack_require__(/*! ./_metadata */ "./node_modules/core-js/modules/_metadata.js"); +var anObject = __webpack_require__(/*! ./_an-object */ "./node_modules/core-js/modules/_an-object.js"); +var aFunction = __webpack_require__(/*! ./_a-function */ "./node_modules/core-js/modules/_a-function.js"); +var toMetaKey = $metadata.key; +var ordinaryDefineOwnMetadata = $metadata.set; + +$metadata.exp({ metadata: function metadata(metadataKey, metadataValue) { + return function decorator(target, targetKey) { + ordinaryDefineOwnMetadata( + metadataKey, metadataValue, + (targetKey !== undefined ? anObject : aFunction)(target), + toMetaKey(targetKey) + ); + }; +} }); + + +/***/ }), + +/***/ "./node_modules/zone.js/dist/zone.js": +/*!*******************************************!*\ + !*** ./node_modules/zone.js/dist/zone.js ***! + \*******************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +/** +* @license +* Copyright Google Inc. All Rights Reserved. +* +* Use of this source code is governed by an MIT-style license that can be +* found in the LICENSE file at https://angular.io/license +*/ +(function (global, factory) { + true ? factory() : + undefined; +}(this, (function () { 'use strict'; + +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +var Zone$1 = (function (global) { + var FUNCTION = 'function'; + var performance = global['performance']; + function mark(name) { + performance && performance['mark'] && performance['mark'](name); + } + function performanceMeasure(name, label) { + performance && performance['measure'] && performance['measure'](name, label); + } + mark('Zone'); + if (global['Zone']) { + throw new Error('Zone already loaded.'); + } + var Zone = /** @class */ (function () { + function Zone(parent, zoneSpec) { + this._properties = null; + this._parent = parent; + this._name = zoneSpec ? zoneSpec.name || 'unnamed' : ''; + this._properties = zoneSpec && zoneSpec.properties || {}; + this._zoneDelegate = + new ZoneDelegate(this, this._parent && this._parent._zoneDelegate, zoneSpec); + } + Zone.assertZonePatched = function () { + if (global['Promise'] !== patches['ZoneAwarePromise']) { + throw new Error('Zone.js has detected that ZoneAwarePromise `(window|global).Promise` ' + + 'has been overwritten.\n' + + 'Most likely cause is that a Promise polyfill has been loaded ' + + 'after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. ' + + 'If you must load one, do so before loading zone.js.)'); + } + }; + Object.defineProperty(Zone, "root", { + get: function () { + var zone = Zone.current; + while (zone.parent) { + zone = zone.parent; + } + return zone; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Zone, "current", { + get: function () { + return _currentZoneFrame.zone; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Zone, "currentTask", { + get: function () { + return _currentTask; + }, + enumerable: true, + configurable: true + }); + Zone.__load_patch = function (name, fn) { + if (patches.hasOwnProperty(name)) { + throw Error('Already loaded patch: ' + name); + } + else if (!global['__Zone_disable_' + name]) { + var perfName = 'Zone:' + name; + mark(perfName); + patches[name] = fn(global, Zone, _api); + performanceMeasure(perfName, perfName); + } + }; + Object.defineProperty(Zone.prototype, "parent", { + get: function () { + return this._parent; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Zone.prototype, "name", { + get: function () { + return this._name; + }, + enumerable: true, + configurable: true + }); + Zone.prototype.get = function (key) { + var zone = this.getZoneWith(key); + if (zone) + return zone._properties[key]; + }; + Zone.prototype.getZoneWith = function (key) { + var current = this; + while (current) { + if (current._properties.hasOwnProperty(key)) { + return current; + } + current = current._parent; + } + return null; + }; + Zone.prototype.fork = function (zoneSpec) { + if (!zoneSpec) + throw new Error('ZoneSpec required!'); + return this._zoneDelegate.fork(this, zoneSpec); + }; + Zone.prototype.wrap = function (callback, source) { + if (typeof callback !== FUNCTION) { + throw new Error('Expecting function got: ' + callback); + } + var _callback = this._zoneDelegate.intercept(this, callback, source); + var zone = this; + return function () { + return zone.runGuarded(_callback, this, arguments, source); + }; + }; + Zone.prototype.run = function (callback, applyThis, applyArgs, source) { + if (applyThis === void 0) { applyThis = undefined; } + if (applyArgs === void 0) { applyArgs = null; } + if (source === void 0) { source = null; } + _currentZoneFrame = { parent: _currentZoneFrame, zone: this }; + try { + return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source); + } + finally { + _currentZoneFrame = _currentZoneFrame.parent; + } + }; + Zone.prototype.runGuarded = function (callback, applyThis, applyArgs, source) { + if (applyThis === void 0) { applyThis = null; } + if (applyArgs === void 0) { applyArgs = null; } + if (source === void 0) { source = null; } + _currentZoneFrame = { parent: _currentZoneFrame, zone: this }; + try { + try { + return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source); + } + catch (error) { + if (this._zoneDelegate.handleError(this, error)) { + throw error; + } + } + } + finally { + _currentZoneFrame = _currentZoneFrame.parent; + } + }; + Zone.prototype.runTask = function (task, applyThis, applyArgs) { + if (task.zone != this) { + throw new Error('A task can only be run in the zone of creation! (Creation: ' + + (task.zone || NO_ZONE).name + '; Execution: ' + this.name + ')'); + } + // https://github.com/angular/zone.js/issues/778, sometimes eventTask + // will run in notScheduled(canceled) state, we should not try to + // run such kind of task but just return + // we have to define an variable here, if not + // typescript compiler will complain below + var isNotScheduled = task.state === notScheduled; + if (isNotScheduled && task.type === eventTask) { + return; + } + var reEntryGuard = task.state != running; + reEntryGuard && task._transitionTo(running, scheduled); + task.runCount++; + var previousTask = _currentTask; + _currentTask = task; + _currentZoneFrame = { parent: _currentZoneFrame, zone: this }; + try { + if (task.type == macroTask && task.data && !task.data.isPeriodic) { + task.cancelFn = null; + } + try { + return this._zoneDelegate.invokeTask(this, task, applyThis, applyArgs); + } + catch (error) { + if (this._zoneDelegate.handleError(this, error)) { + throw error; + } + } + } + finally { + // if the task's state is notScheduled or unknown, then it has already been cancelled + // we should not reset the state to scheduled + if (task.state !== notScheduled && task.state !== unknown) { + if (task.type == eventTask || (task.data && task.data.isPeriodic)) { + reEntryGuard && task._transitionTo(scheduled, running); + } + else { + task.runCount = 0; + this._updateTaskCount(task, -1); + reEntryGuard && + task._transitionTo(notScheduled, running, notScheduled); + } + } + _currentZoneFrame = _currentZoneFrame.parent; + _currentTask = previousTask; + } + }; + Zone.prototype.scheduleTask = function (task) { + if (task.zone && task.zone !== this) { + // check if the task was rescheduled, the newZone + // should not be the children of the original zone + var newZone = this; + while (newZone) { + if (newZone === task.zone) { + throw Error("can not reschedule task to " + this + .name + " which is descendants of the original zone " + task.zone.name); + } + newZone = newZone.parent; + } + } + task._transitionTo(scheduling, notScheduled); + var zoneDelegates = []; + task._zoneDelegates = zoneDelegates; + task._zone = this; + try { + task = this._zoneDelegate.scheduleTask(this, task); + } + catch (err) { + // should set task's state to unknown when scheduleTask throw error + // because the err may from reschedule, so the fromState maybe notScheduled + task._transitionTo(unknown, scheduling, notScheduled); + // TODO: @JiaLiPassion, should we check the result from handleError? + this._zoneDelegate.handleError(this, err); + throw err; + } + if (task._zoneDelegates === zoneDelegates) { + // we have to check because internally the delegate can reschedule the task. + this._updateTaskCount(task, 1); + } + if (task.state == scheduling) { + task._transitionTo(scheduled, scheduling); + } + return task; + }; + Zone.prototype.scheduleMicroTask = function (source, callback, data, customSchedule) { + return this.scheduleTask(new ZoneTask(microTask, source, callback, data, customSchedule, null)); + }; + Zone.prototype.scheduleMacroTask = function (source, callback, data, customSchedule, customCancel) { + return this.scheduleTask(new ZoneTask(macroTask, source, callback, data, customSchedule, customCancel)); + }; + Zone.prototype.scheduleEventTask = function (source, callback, data, customSchedule, customCancel) { + return this.scheduleTask(new ZoneTask(eventTask, source, callback, data, customSchedule, customCancel)); + }; + Zone.prototype.cancelTask = function (task) { + if (task.zone != this) + throw new Error('A task can only be cancelled in the zone of creation! (Creation: ' + + (task.zone || NO_ZONE).name + '; Execution: ' + this.name + ')'); + task._transitionTo(canceling, scheduled, running); + try { + this._zoneDelegate.cancelTask(this, task); + } + catch (err) { + // if error occurs when cancelTask, transit the state to unknown + task._transitionTo(unknown, canceling); + this._zoneDelegate.handleError(this, err); + throw err; + } + this._updateTaskCount(task, -1); + task._transitionTo(notScheduled, canceling); + task.runCount = 0; + return task; + }; + Zone.prototype._updateTaskCount = function (task, count) { + var zoneDelegates = task._zoneDelegates; + if (count == -1) { + task._zoneDelegates = null; + } + for (var i = 0; i < zoneDelegates.length; i++) { + zoneDelegates[i]._updateTaskCount(task.type, count); + } + }; + Zone.__symbol__ = __symbol__; + return Zone; + }()); + var DELEGATE_ZS = { + name: '', + onHasTask: function (delegate, _, target, hasTaskState) { + return delegate.hasTask(target, hasTaskState); + }, + onScheduleTask: function (delegate, _, target, task) { + return delegate.scheduleTask(target, task); + }, + onInvokeTask: function (delegate, _, target, task, applyThis, applyArgs) { return delegate.invokeTask(target, task, applyThis, applyArgs); }, + onCancelTask: function (delegate, _, target, task) { + return delegate.cancelTask(target, task); + } + }; + var ZoneDelegate = /** @class */ (function () { + function ZoneDelegate(zone, parentDelegate, zoneSpec) { + this._taskCounts = { 'microTask': 0, 'macroTask': 0, 'eventTask': 0 }; + this.zone = zone; + this._parentDelegate = parentDelegate; + this._forkZS = zoneSpec && (zoneSpec && zoneSpec.onFork ? zoneSpec : parentDelegate._forkZS); + this._forkDlgt = zoneSpec && (zoneSpec.onFork ? parentDelegate : parentDelegate._forkDlgt); + this._forkCurrZone = zoneSpec && (zoneSpec.onFork ? this.zone : parentDelegate.zone); + this._interceptZS = + zoneSpec && (zoneSpec.onIntercept ? zoneSpec : parentDelegate._interceptZS); + this._interceptDlgt = + zoneSpec && (zoneSpec.onIntercept ? parentDelegate : parentDelegate._interceptDlgt); + this._interceptCurrZone = + zoneSpec && (zoneSpec.onIntercept ? this.zone : parentDelegate.zone); + this._invokeZS = zoneSpec && (zoneSpec.onInvoke ? zoneSpec : parentDelegate._invokeZS); + this._invokeDlgt = + zoneSpec && (zoneSpec.onInvoke ? parentDelegate : parentDelegate._invokeDlgt); + this._invokeCurrZone = zoneSpec && (zoneSpec.onInvoke ? this.zone : parentDelegate.zone); + this._handleErrorZS = + zoneSpec && (zoneSpec.onHandleError ? zoneSpec : parentDelegate._handleErrorZS); + this._handleErrorDlgt = + zoneSpec && (zoneSpec.onHandleError ? parentDelegate : parentDelegate._handleErrorDlgt); + this._handleErrorCurrZone = + zoneSpec && (zoneSpec.onHandleError ? this.zone : parentDelegate.zone); + this._scheduleTaskZS = + zoneSpec && (zoneSpec.onScheduleTask ? zoneSpec : parentDelegate._scheduleTaskZS); + this._scheduleTaskDlgt = + zoneSpec && (zoneSpec.onScheduleTask ? parentDelegate : parentDelegate._scheduleTaskDlgt); + this._scheduleTaskCurrZone = + zoneSpec && (zoneSpec.onScheduleTask ? this.zone : parentDelegate.zone); + this._invokeTaskZS = + zoneSpec && (zoneSpec.onInvokeTask ? zoneSpec : parentDelegate._invokeTaskZS); + this._invokeTaskDlgt = + zoneSpec && (zoneSpec.onInvokeTask ? parentDelegate : parentDelegate._invokeTaskDlgt); + this._invokeTaskCurrZone = + zoneSpec && (zoneSpec.onInvokeTask ? this.zone : parentDelegate.zone); + this._cancelTaskZS = + zoneSpec && (zoneSpec.onCancelTask ? zoneSpec : parentDelegate._cancelTaskZS); + this._cancelTaskDlgt = + zoneSpec && (zoneSpec.onCancelTask ? parentDelegate : parentDelegate._cancelTaskDlgt); + this._cancelTaskCurrZone = + zoneSpec && (zoneSpec.onCancelTask ? this.zone : parentDelegate.zone); + this._hasTaskZS = null; + this._hasTaskDlgt = null; + this._hasTaskDlgtOwner = null; + this._hasTaskCurrZone = null; + var zoneSpecHasTask = zoneSpec && zoneSpec.onHasTask; + var parentHasTask = parentDelegate && parentDelegate._hasTaskZS; + if (zoneSpecHasTask || parentHasTask) { + // If we need to report hasTask, than this ZS needs to do ref counting on tasks. In such + // a case all task related interceptors must go through this ZD. We can't short circuit it. + this._hasTaskZS = zoneSpecHasTask ? zoneSpec : DELEGATE_ZS; + this._hasTaskDlgt = parentDelegate; + this._hasTaskDlgtOwner = this; + this._hasTaskCurrZone = zone; + if (!zoneSpec.onScheduleTask) { + this._scheduleTaskZS = DELEGATE_ZS; + this._scheduleTaskDlgt = parentDelegate; + this._scheduleTaskCurrZone = this.zone; + } + if (!zoneSpec.onInvokeTask) { + this._invokeTaskZS = DELEGATE_ZS; + this._invokeTaskDlgt = parentDelegate; + this._invokeTaskCurrZone = this.zone; + } + if (!zoneSpec.onCancelTask) { + this._cancelTaskZS = DELEGATE_ZS; + this._cancelTaskDlgt = parentDelegate; + this._cancelTaskCurrZone = this.zone; + } + } + } + ZoneDelegate.prototype.fork = function (targetZone, zoneSpec) { + return this._forkZS ? this._forkZS.onFork(this._forkDlgt, this.zone, targetZone, zoneSpec) : + new Zone(targetZone, zoneSpec); + }; + ZoneDelegate.prototype.intercept = function (targetZone, callback, source) { + return this._interceptZS ? + this._interceptZS.onIntercept(this._interceptDlgt, this._interceptCurrZone, targetZone, callback, source) : + callback; + }; + ZoneDelegate.prototype.invoke = function (targetZone, callback, applyThis, applyArgs, source) { + return this._invokeZS ? + this._invokeZS.onInvoke(this._invokeDlgt, this._invokeCurrZone, targetZone, callback, applyThis, applyArgs, source) : + callback.apply(applyThis, applyArgs); + }; + ZoneDelegate.prototype.handleError = function (targetZone, error) { + return this._handleErrorZS ? + this._handleErrorZS.onHandleError(this._handleErrorDlgt, this._handleErrorCurrZone, targetZone, error) : + true; + }; + ZoneDelegate.prototype.scheduleTask = function (targetZone, task) { + var returnTask = task; + if (this._scheduleTaskZS) { + if (this._hasTaskZS) { + returnTask._zoneDelegates.push(this._hasTaskDlgtOwner); + } + returnTask = this._scheduleTaskZS.onScheduleTask(this._scheduleTaskDlgt, this._scheduleTaskCurrZone, targetZone, task); + if (!returnTask) + returnTask = task; + } + else { + if (task.scheduleFn) { + task.scheduleFn(task); + } + else if (task.type == microTask) { + scheduleMicroTask(task); + } + else { + throw new Error('Task is missing scheduleFn.'); + } + } + return returnTask; + }; + ZoneDelegate.prototype.invokeTask = function (targetZone, task, applyThis, applyArgs) { + return this._invokeTaskZS ? + this._invokeTaskZS.onInvokeTask(this._invokeTaskDlgt, this._invokeTaskCurrZone, targetZone, task, applyThis, applyArgs) : + task.callback.apply(applyThis, applyArgs); + }; + ZoneDelegate.prototype.cancelTask = function (targetZone, task) { + var value; + if (this._cancelTaskZS) { + value = this._cancelTaskZS.onCancelTask(this._cancelTaskDlgt, this._cancelTaskCurrZone, targetZone, task); + } + else { + if (!task.cancelFn) { + throw Error('Task is not cancelable'); + } + value = task.cancelFn(task); + } + return value; + }; + ZoneDelegate.prototype.hasTask = function (targetZone, isEmpty) { + // hasTask should not throw error so other ZoneDelegate + // can still trigger hasTask callback + try { + return this._hasTaskZS && + this._hasTaskZS.onHasTask(this._hasTaskDlgt, this._hasTaskCurrZone, targetZone, isEmpty); + } + catch (err) { + this.handleError(targetZone, err); + } + }; + ZoneDelegate.prototype._updateTaskCount = function (type, count) { + var counts = this._taskCounts; + var prev = counts[type]; + var next = counts[type] = prev + count; + if (next < 0) { + throw new Error('More tasks executed then were scheduled.'); + } + if (prev == 0 || next == 0) { + var isEmpty = { + microTask: counts['microTask'] > 0, + macroTask: counts['macroTask'] > 0, + eventTask: counts['eventTask'] > 0, + change: type + }; + this.hasTask(this.zone, isEmpty); + } + }; + return ZoneDelegate; + }()); + var ZoneTask = /** @class */ (function () { + function ZoneTask(type, source, callback, options, scheduleFn, cancelFn) { + this._zone = null; + this.runCount = 0; + this._zoneDelegates = null; + this._state = 'notScheduled'; + this.type = type; + this.source = source; + this.data = options; + this.scheduleFn = scheduleFn; + this.cancelFn = cancelFn; + this.callback = callback; + var self = this; + // TODO: @JiaLiPassion options should have interface + if (type === eventTask && options && options.useG) { + this.invoke = ZoneTask.invokeTask; + } + else { + this.invoke = function () { + return ZoneTask.invokeTask.call(global, self, this, arguments); + }; + } + } + ZoneTask.invokeTask = function (task, target, args) { + if (!task) { + task = this; + } + _numberOfNestedTaskFrames++; + try { + task.runCount++; + return task.zone.runTask(task, target, args); + } + finally { + if (_numberOfNestedTaskFrames == 1) { + drainMicroTaskQueue(); + } + _numberOfNestedTaskFrames--; + } + }; + Object.defineProperty(ZoneTask.prototype, "zone", { + get: function () { + return this._zone; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(ZoneTask.prototype, "state", { + get: function () { + return this._state; + }, + enumerable: true, + configurable: true + }); + ZoneTask.prototype.cancelScheduleRequest = function () { + this._transitionTo(notScheduled, scheduling); + }; + ZoneTask.prototype._transitionTo = function (toState, fromState1, fromState2) { + if (this._state === fromState1 || this._state === fromState2) { + this._state = toState; + if (toState == notScheduled) { + this._zoneDelegates = null; + } + } + else { + throw new Error(this.type + " '" + this.source + "': can not transition to '" + toState + "', expecting state '" + fromState1 + "'" + (fromState2 ? + ' or \'' + fromState2 + '\'' : + '') + ", was '" + this._state + "'."); + } + }; + ZoneTask.prototype.toString = function () { + if (this.data && typeof this.data.handleId !== 'undefined') { + return this.data.handleId; + } + else { + return Object.prototype.toString.call(this); + } + }; + // add toJSON method to prevent cyclic error when + // call JSON.stringify(zoneTask) + ZoneTask.prototype.toJSON = function () { + return { + type: this.type, + state: this.state, + source: this.source, + zone: this.zone.name, + runCount: this.runCount + }; + }; + return ZoneTask; + }()); + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + /// MICROTASK QUEUE + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + var symbolSetTimeout = __symbol__('setTimeout'); + var symbolPromise = __symbol__('Promise'); + var symbolThen = __symbol__('then'); + var _microTaskQueue = []; + var _isDrainingMicrotaskQueue = false; + var nativeMicroTaskQueuePromise; + function scheduleMicroTask(task) { + // if we are not running in any task, and there has not been anything scheduled + // we must bootstrap the initial task creation by manually scheduling the drain + if (_numberOfNestedTaskFrames === 0 && _microTaskQueue.length === 0) { + // We are not running in Task, so we need to kickstart the microtask queue. + if (!nativeMicroTaskQueuePromise) { + if (global[symbolPromise]) { + nativeMicroTaskQueuePromise = global[symbolPromise].resolve(0); + } + } + if (nativeMicroTaskQueuePromise) { + nativeMicroTaskQueuePromise[symbolThen](drainMicroTaskQueue); + } + else { + global[symbolSetTimeout](drainMicroTaskQueue, 0); + } + } + task && _microTaskQueue.push(task); + } + function drainMicroTaskQueue() { + if (!_isDrainingMicrotaskQueue) { + _isDrainingMicrotaskQueue = true; + while (_microTaskQueue.length) { + var queue = _microTaskQueue; + _microTaskQueue = []; + for (var i = 0; i < queue.length; i++) { + var task = queue[i]; + try { + task.zone.runTask(task, null, null); + } + catch (error) { + _api.onUnhandledError(error); + } + } + } + _api.microtaskDrainDone(); + _isDrainingMicrotaskQueue = false; + } + } + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + /// BOOTSTRAP + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + var NO_ZONE = { name: 'NO ZONE' }; + var notScheduled = 'notScheduled', scheduling = 'scheduling', scheduled = 'scheduled', running = 'running', canceling = 'canceling', unknown = 'unknown'; + var microTask = 'microTask', macroTask = 'macroTask', eventTask = 'eventTask'; + var patches = {}; + var _api = { + symbol: __symbol__, + currentZoneFrame: function () { return _currentZoneFrame; }, + onUnhandledError: noop, + microtaskDrainDone: noop, + scheduleMicroTask: scheduleMicroTask, + showUncaughtError: function () { return !Zone[__symbol__('ignoreConsoleErrorUncaughtError')]; }, + patchEventTarget: function () { return []; }, + patchOnProperties: noop, + patchMethod: function () { return noop; }, + bindArguments: function () { return null; }, + setNativePromise: function (NativePromise) { + // sometimes NativePromise.resolve static function + // is not ready yet, (such as core-js/es6.promise) + // so we need to check here. + if (NativePromise && typeof NativePromise.resolve === FUNCTION) { + nativeMicroTaskQueuePromise = NativePromise.resolve(0); + } + }, + }; + var _currentZoneFrame = { parent: null, zone: new Zone(null, null) }; + var _currentTask = null; + var _numberOfNestedTaskFrames = 0; + function noop() { } + function __symbol__(name) { + return '__zone_symbol__' + name; + } + performanceMeasure('Zone', 'Zone'); + return global['Zone'] = Zone; +})(typeof window !== 'undefined' && window || typeof self !== 'undefined' && self || global); + +Zone.__load_patch('ZoneAwarePromise', function (global, Zone, api) { + var ObjectGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; + var ObjectDefineProperty = Object.defineProperty; + function readableObjectToString(obj) { + if (obj && obj.toString === Object.prototype.toString) { + var className = obj.constructor && obj.constructor.name; + return (className ? className : '') + ': ' + JSON.stringify(obj); + } + return obj ? obj.toString() : Object.prototype.toString.call(obj); + } + var __symbol__ = api.symbol; + var _uncaughtPromiseErrors = []; + var symbolPromise = __symbol__('Promise'); + var symbolThen = __symbol__('then'); + var creationTrace = '__creationTrace__'; + api.onUnhandledError = function (e) { + if (api.showUncaughtError()) { + var rejection = e && e.rejection; + if (rejection) { + console.error('Unhandled Promise rejection:', rejection instanceof Error ? rejection.message : rejection, '; Zone:', e.zone.name, '; Task:', e.task && e.task.source, '; Value:', rejection, rejection instanceof Error ? rejection.stack : undefined); + } + else { + console.error(e); + } + } + }; + api.microtaskDrainDone = function () { + while (_uncaughtPromiseErrors.length) { + var _loop_1 = function () { + var uncaughtPromiseError = _uncaughtPromiseErrors.shift(); + try { + uncaughtPromiseError.zone.runGuarded(function () { + throw uncaughtPromiseError; + }); + } + catch (error) { + handleUnhandledRejection(error); + } + }; + while (_uncaughtPromiseErrors.length) { + _loop_1(); + } + } + }; + var UNHANDLED_PROMISE_REJECTION_HANDLER_SYMBOL = __symbol__('unhandledPromiseRejectionHandler'); + function handleUnhandledRejection(e) { + api.onUnhandledError(e); + try { + var handler = Zone[UNHANDLED_PROMISE_REJECTION_HANDLER_SYMBOL]; + if (handler && typeof handler === 'function') { + handler.call(this, e); + } + } + catch (err) { + } + } + function isThenable(value) { + return value && value.then; + } + function forwardResolution(value) { + return value; + } + function forwardRejection(rejection) { + return ZoneAwarePromise.reject(rejection); + } + var symbolState = __symbol__('state'); + var symbolValue = __symbol__('value'); + var symbolFinally = __symbol__('finally'); + var symbolParentPromiseValue = __symbol__('parentPromiseValue'); + var symbolParentPromiseState = __symbol__('parentPromiseState'); + var source = 'Promise.then'; + var UNRESOLVED = null; + var RESOLVED = true; + var REJECTED = false; + var REJECTED_NO_CATCH = 0; + function makeResolver(promise, state) { + return function (v) { + try { + resolvePromise(promise, state, v); + } + catch (err) { + resolvePromise(promise, false, err); + } + // Do not return value or you will break the Promise spec. + }; + } + var once = function () { + var wasCalled = false; + return function wrapper(wrappedFunction) { + return function () { + if (wasCalled) { + return; + } + wasCalled = true; + wrappedFunction.apply(null, arguments); + }; + }; + }; + var TYPE_ERROR = 'Promise resolved with itself'; + var CURRENT_TASK_TRACE_SYMBOL = __symbol__('currentTaskTrace'); + // Promise Resolution + function resolvePromise(promise, state, value) { + var onceWrapper = once(); + if (promise === value) { + throw new TypeError(TYPE_ERROR); + } + if (promise[symbolState] === UNRESOLVED) { + // should only get value.then once based on promise spec. + var then = null; + try { + if (typeof value === 'object' || typeof value === 'function') { + then = value && value.then; + } + } + catch (err) { + onceWrapper(function () { + resolvePromise(promise, false, err); + })(); + return promise; + } + // if (value instanceof ZoneAwarePromise) { + if (state !== REJECTED && value instanceof ZoneAwarePromise && + value.hasOwnProperty(symbolState) && value.hasOwnProperty(symbolValue) && + value[symbolState] !== UNRESOLVED) { + clearRejectedNoCatch(value); + resolvePromise(promise, value[symbolState], value[symbolValue]); + } + else if (state !== REJECTED && typeof then === 'function') { + try { + then.call(value, onceWrapper(makeResolver(promise, state)), onceWrapper(makeResolver(promise, false))); + } + catch (err) { + onceWrapper(function () { + resolvePromise(promise, false, err); + })(); + } + } + else { + promise[symbolState] = state; + var queue = promise[symbolValue]; + promise[symbolValue] = value; + if (promise[symbolFinally] === symbolFinally) { + // the promise is generated by Promise.prototype.finally + if (state === RESOLVED) { + // the state is resolved, should ignore the value + // and use parent promise value + promise[symbolState] = promise[symbolParentPromiseState]; + promise[symbolValue] = promise[symbolParentPromiseValue]; + } + } + // record task information in value when error occurs, so we can + // do some additional work such as render longStackTrace + if (state === REJECTED && value instanceof Error) { + // check if longStackTraceZone is here + var trace = Zone.currentTask && Zone.currentTask.data && + Zone.currentTask.data[creationTrace]; + if (trace) { + // only keep the long stack trace into error when in longStackTraceZone + ObjectDefineProperty(value, CURRENT_TASK_TRACE_SYMBOL, { configurable: true, enumerable: false, writable: true, value: trace }); + } + } + for (var i = 0; i < queue.length;) { + scheduleResolveOrReject(promise, queue[i++], queue[i++], queue[i++], queue[i++]); + } + if (queue.length == 0 && state == REJECTED) { + promise[symbolState] = REJECTED_NO_CATCH; + try { + // try to print more readable error log + throw new Error('Uncaught (in promise): ' + readableObjectToString(value) + + (value && value.stack ? '\n' + value.stack : '')); + } + catch (err) { + var error_1 = err; + error_1.rejection = value; + error_1.promise = promise; + error_1.zone = Zone.current; + error_1.task = Zone.currentTask; + _uncaughtPromiseErrors.push(error_1); + api.scheduleMicroTask(); // to make sure that it is running + } + } + } + } + // Resolving an already resolved promise is a noop. + return promise; + } + var REJECTION_HANDLED_HANDLER = __symbol__('rejectionHandledHandler'); + function clearRejectedNoCatch(promise) { + if (promise[symbolState] === REJECTED_NO_CATCH) { + // if the promise is rejected no catch status + // and queue.length > 0, means there is a error handler + // here to handle the rejected promise, we should trigger + // windows.rejectionhandled eventHandler or nodejs rejectionHandled + // eventHandler + try { + var handler = Zone[REJECTION_HANDLED_HANDLER]; + if (handler && typeof handler === 'function') { + handler.call(this, { rejection: promise[symbolValue], promise: promise }); + } + } + catch (err) { + } + promise[symbolState] = REJECTED; + for (var i = 0; i < _uncaughtPromiseErrors.length; i++) { + if (promise === _uncaughtPromiseErrors[i].promise) { + _uncaughtPromiseErrors.splice(i, 1); + } + } + } + } + function scheduleResolveOrReject(promise, zone, chainPromise, onFulfilled, onRejected) { + clearRejectedNoCatch(promise); + var promiseState = promise[symbolState]; + var delegate = promiseState ? + (typeof onFulfilled === 'function') ? onFulfilled : forwardResolution : + (typeof onRejected === 'function') ? onRejected : forwardRejection; + zone.scheduleMicroTask(source, function () { + try { + var parentPromiseValue = promise[symbolValue]; + var isFinallyPromise = chainPromise && symbolFinally === chainPromise[symbolFinally]; + if (isFinallyPromise) { + // if the promise is generated from finally call, keep parent promise's state and value + chainPromise[symbolParentPromiseValue] = parentPromiseValue; + chainPromise[symbolParentPromiseState] = promiseState; + } + // should not pass value to finally callback + var value = zone.run(delegate, undefined, isFinallyPromise && delegate !== forwardRejection && delegate !== forwardResolution ? [] : [parentPromiseValue]); + resolvePromise(chainPromise, true, value); + } + catch (error) { + // if error occurs, should always return this error + resolvePromise(chainPromise, false, error); + } + }, chainPromise); + } + var ZONE_AWARE_PROMISE_TO_STRING = 'function ZoneAwarePromise() { [native code] }'; + var ZoneAwarePromise = /** @class */ (function () { + function ZoneAwarePromise(executor) { + var promise = this; + if (!(promise instanceof ZoneAwarePromise)) { + throw new Error('Must be an instanceof Promise.'); + } + promise[symbolState] = UNRESOLVED; + promise[symbolValue] = []; // queue; + try { + executor && executor(makeResolver(promise, RESOLVED), makeResolver(promise, REJECTED)); + } + catch (error) { + resolvePromise(promise, false, error); + } + } + ZoneAwarePromise.toString = function () { + return ZONE_AWARE_PROMISE_TO_STRING; + }; + ZoneAwarePromise.resolve = function (value) { + return resolvePromise(new this(null), RESOLVED, value); + }; + ZoneAwarePromise.reject = function (error) { + return resolvePromise(new this(null), REJECTED, error); + }; + ZoneAwarePromise.race = function (values) { + var resolve; + var reject; + var promise = new this(function (res, rej) { + resolve = res; + reject = rej; + }); + function onResolve(value) { + promise && (promise = null || resolve(value)); + } + function onReject(error) { + promise && (promise = null || reject(error)); + } + for (var _i = 0, values_1 = values; _i < values_1.length; _i++) { + var value = values_1[_i]; + if (!isThenable(value)) { + value = this.resolve(value); + } + value.then(onResolve, onReject); + } + return promise; + }; + ZoneAwarePromise.all = function (values) { + var resolve; + var reject; + var promise = new this(function (res, rej) { + resolve = res; + reject = rej; + }); + var count = 0; + var resolvedValues = []; + for (var _i = 0, values_2 = values; _i < values_2.length; _i++) { + var value = values_2[_i]; + if (!isThenable(value)) { + value = this.resolve(value); + } + value.then((function (index) { return function (value) { + resolvedValues[index] = value; + count--; + if (!count) { + resolve(resolvedValues); + } + }; })(count), reject); + count++; + } + if (!count) + resolve(resolvedValues); + return promise; + }; + ZoneAwarePromise.prototype.then = function (onFulfilled, onRejected) { + var chainPromise = new this.constructor(null); + var zone = Zone.current; + if (this[symbolState] == UNRESOLVED) { + this[symbolValue].push(zone, chainPromise, onFulfilled, onRejected); + } + else { + scheduleResolveOrReject(this, zone, chainPromise, onFulfilled, onRejected); + } + return chainPromise; + }; + ZoneAwarePromise.prototype.catch = function (onRejected) { + return this.then(null, onRejected); + }; + ZoneAwarePromise.prototype.finally = function (onFinally) { + var chainPromise = new this.constructor(null); + chainPromise[symbolFinally] = symbolFinally; + var zone = Zone.current; + if (this[symbolState] == UNRESOLVED) { + this[symbolValue].push(zone, chainPromise, onFinally, onFinally); + } + else { + scheduleResolveOrReject(this, zone, chainPromise, onFinally, onFinally); + } + return chainPromise; + }; + return ZoneAwarePromise; + }()); + // Protect against aggressive optimizers dropping seemingly unused properties. + // E.g. Closure Compiler in advanced mode. + ZoneAwarePromise['resolve'] = ZoneAwarePromise.resolve; + ZoneAwarePromise['reject'] = ZoneAwarePromise.reject; + ZoneAwarePromise['race'] = ZoneAwarePromise.race; + ZoneAwarePromise['all'] = ZoneAwarePromise.all; + var NativePromise = global[symbolPromise] = global['Promise']; + var ZONE_AWARE_PROMISE = Zone.__symbol__('ZoneAwarePromise'); + var desc = ObjectGetOwnPropertyDescriptor(global, 'Promise'); + if (!desc || desc.configurable) { + desc && delete desc.writable; + desc && delete desc.value; + if (!desc) { + desc = { configurable: true, enumerable: true }; + } + desc.get = function () { + // if we already set ZoneAwarePromise, use patched one + // otherwise return native one. + return global[ZONE_AWARE_PROMISE] ? global[ZONE_AWARE_PROMISE] : global[symbolPromise]; + }; + desc.set = function (NewNativePromise) { + if (NewNativePromise === ZoneAwarePromise) { + // if the NewNativePromise is ZoneAwarePromise + // save to global + global[ZONE_AWARE_PROMISE] = NewNativePromise; + } + else { + // if the NewNativePromise is not ZoneAwarePromise + // for example: after load zone.js, some library just + // set es6-promise to global, if we set it to global + // directly, assertZonePatched will fail and angular + // will not loaded, so we just set the NewNativePromise + // to global[symbolPromise], so the result is just like + // we load ES6 Promise before zone.js + global[symbolPromise] = NewNativePromise; + if (!NewNativePromise.prototype[symbolThen]) { + patchThen(NewNativePromise); + } + api.setNativePromise(NewNativePromise); + } + }; + ObjectDefineProperty(global, 'Promise', desc); + } + global['Promise'] = ZoneAwarePromise; + var symbolThenPatched = __symbol__('thenPatched'); + function patchThen(Ctor) { + var proto = Ctor.prototype; + var prop = ObjectGetOwnPropertyDescriptor(proto, 'then'); + if (prop && (prop.writable === false || !prop.configurable)) { + // check Ctor.prototype.then propertyDescriptor is writable or not + // in meteor env, writable is false, we should ignore such case + return; + } + var originalThen = proto.then; + // Keep a reference to the original method. + proto[symbolThen] = originalThen; + Ctor.prototype.then = function (onResolve, onReject) { + var _this = this; + var wrapped = new ZoneAwarePromise(function (resolve, reject) { + originalThen.call(_this, resolve, reject); + }); + return wrapped.then(onResolve, onReject); + }; + Ctor[symbolThenPatched] = true; + } + function zoneify(fn) { + return function () { + var resultPromise = fn.apply(this, arguments); + if (resultPromise instanceof ZoneAwarePromise) { + return resultPromise; + } + var ctor = resultPromise.constructor; + if (!ctor[symbolThenPatched]) { + patchThen(ctor); + } + return resultPromise; + }; + } + if (NativePromise) { + patchThen(NativePromise); + var fetch_1 = global['fetch']; + if (typeof fetch_1 == 'function') { + global['fetch'] = zoneify(fetch_1); + } + } + // This is not part of public API, but it is useful for tests, so we expose it. + Promise[Zone.__symbol__('uncaughtPromiseErrors')] = _uncaughtPromiseErrors; + return ZoneAwarePromise; +}); + +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +/** + * Suppress closure compiler errors about unknown 'Zone' variable + * @fileoverview + * @suppress {undefinedVars,globalThis,missingRequire} + */ +// issue #989, to reduce bundle size, use short name +/** Object.getOwnPropertyDescriptor */ +var ObjectGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; +/** Object.defineProperty */ +var ObjectDefineProperty = Object.defineProperty; +/** Object.getPrototypeOf */ +var ObjectGetPrototypeOf = Object.getPrototypeOf; +/** Object.create */ +var ObjectCreate = Object.create; +/** Array.prototype.slice */ +var ArraySlice = Array.prototype.slice; +/** addEventListener string const */ +var ADD_EVENT_LISTENER_STR = 'addEventListener'; +/** removeEventListener string const */ +var REMOVE_EVENT_LISTENER_STR = 'removeEventListener'; +/** zoneSymbol addEventListener */ +var ZONE_SYMBOL_ADD_EVENT_LISTENER = Zone.__symbol__(ADD_EVENT_LISTENER_STR); +/** zoneSymbol removeEventListener */ +var ZONE_SYMBOL_REMOVE_EVENT_LISTENER = Zone.__symbol__(REMOVE_EVENT_LISTENER_STR); +/** true string const */ +var TRUE_STR = 'true'; +/** false string const */ +var FALSE_STR = 'false'; +/** __zone_symbol__ string const */ +var ZONE_SYMBOL_PREFIX = '__zone_symbol__'; +function wrapWithCurrentZone(callback, source) { + return Zone.current.wrap(callback, source); +} +function scheduleMacroTaskWithCurrentZone(source, callback, data, customSchedule, customCancel) { + return Zone.current.scheduleMacroTask(source, callback, data, customSchedule, customCancel); +} +var zoneSymbol = Zone.__symbol__; +var isWindowExists = typeof window !== 'undefined'; +var internalWindow = isWindowExists ? window : undefined; +var _global = isWindowExists && internalWindow || typeof self === 'object' && self || global; +var REMOVE_ATTRIBUTE = 'removeAttribute'; +var NULL_ON_PROP_VALUE = [null]; +function bindArguments(args, source) { + for (var i = args.length - 1; i >= 0; i--) { + if (typeof args[i] === 'function') { + args[i] = wrapWithCurrentZone(args[i], source + '_' + i); + } + } + return args; +} +function patchPrototype(prototype, fnNames) { + var source = prototype.constructor['name']; + var _loop_1 = function (i) { + var name_1 = fnNames[i]; + var delegate = prototype[name_1]; + if (delegate) { + var prototypeDesc = ObjectGetOwnPropertyDescriptor(prototype, name_1); + if (!isPropertyWritable(prototypeDesc)) { + return "continue"; + } + prototype[name_1] = (function (delegate) { + var patched = function () { + return delegate.apply(this, bindArguments(arguments, source + '.' + name_1)); + }; + attachOriginToPatched(patched, delegate); + return patched; + })(delegate); + } + }; + for (var i = 0; i < fnNames.length; i++) { + _loop_1(i); + } +} +function isPropertyWritable(propertyDesc) { + if (!propertyDesc) { + return true; + } + if (propertyDesc.writable === false) { + return false; + } + return !(typeof propertyDesc.get === 'function' && typeof propertyDesc.set === 'undefined'); +} +var isWebWorker = (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope); +// Make sure to access `process` through `_global` so that WebPack does not accidentally browserify +// this code. +var isNode = (!('nw' in _global) && typeof _global.process !== 'undefined' && + {}.toString.call(_global.process) === '[object process]'); +var isBrowser = !isNode && !isWebWorker && !!(isWindowExists && internalWindow['HTMLElement']); +// we are in electron of nw, so we are both browser and nodejs +// Make sure to access `process` through `_global` so that WebPack does not accidentally browserify +// this code. +var isMix = typeof _global.process !== 'undefined' && + {}.toString.call(_global.process) === '[object process]' && !isWebWorker && + !!(isWindowExists && internalWindow['HTMLElement']); +var zoneSymbolEventNames = {}; +var wrapFn = function (event) { + // https://github.com/angular/zone.js/issues/911, in IE, sometimes + // event will be undefined, so we need to use window.event + event = event || _global.event; + if (!event) { + return; + } + var eventNameSymbol = zoneSymbolEventNames[event.type]; + if (!eventNameSymbol) { + eventNameSymbol = zoneSymbolEventNames[event.type] = zoneSymbol('ON_PROPERTY' + event.type); + } + var target = this || event.target || _global; + var listener = target[eventNameSymbol]; + var result = listener && listener.apply(this, arguments); + if (result != undefined && !result) { + event.preventDefault(); + } + return result; +}; +function patchProperty(obj, prop, prototype) { + var desc = ObjectGetOwnPropertyDescriptor(obj, prop); + if (!desc && prototype) { + // when patch window object, use prototype to check prop exist or not + var prototypeDesc = ObjectGetOwnPropertyDescriptor(prototype, prop); + if (prototypeDesc) { + desc = { enumerable: true, configurable: true }; + } + } + // if the descriptor not exists or is not configurable + // just return + if (!desc || !desc.configurable) { + return; + } + // A property descriptor cannot have getter/setter and be writable + // deleting the writable and value properties avoids this error: + // + // TypeError: property descriptors must not specify a value or be writable when a + // getter or setter has been specified + delete desc.writable; + delete desc.value; + var originalDescGet = desc.get; + var originalDescSet = desc.set; + // substr(2) cuz 'onclick' -> 'click', etc + var eventName = prop.substr(2); + var eventNameSymbol = zoneSymbolEventNames[eventName]; + if (!eventNameSymbol) { + eventNameSymbol = zoneSymbolEventNames[eventName] = zoneSymbol('ON_PROPERTY' + eventName); + } + desc.set = function (newValue) { + // in some of windows's onproperty callback, this is undefined + // so we need to check it + var target = this; + if (!target && obj === _global) { + target = _global; + } + if (!target) { + return; + } + var previousValue = target[eventNameSymbol]; + if (previousValue) { + target.removeEventListener(eventName, wrapFn); + } + // issue #978, when onload handler was added before loading zone.js + // we should remove it with originalDescSet + if (originalDescSet) { + originalDescSet.apply(target, NULL_ON_PROP_VALUE); + } + if (typeof newValue === 'function') { + target[eventNameSymbol] = newValue; + target.addEventListener(eventName, wrapFn, false); + } + else { + target[eventNameSymbol] = null; + } + }; + // The getter would return undefined for unassigned properties but the default value of an + // unassigned property is null + desc.get = function () { + // in some of windows's onproperty callback, this is undefined + // so we need to check it + var target = this; + if (!target && obj === _global) { + target = _global; + } + if (!target) { + return null; + } + var listener = target[eventNameSymbol]; + if (listener) { + return listener; + } + else if (originalDescGet) { + // result will be null when use inline event attribute, + // such as + // because the onclick function is internal raw uncompiled handler + // the onclick will be evaluated when first time event was triggered or + // the property is accessed, https://github.com/angular/zone.js/issues/525 + // so we should use original native get to retrieve the handler + var value = originalDescGet && originalDescGet.call(this); + if (value) { + desc.set.call(this, value); + if (typeof target[REMOVE_ATTRIBUTE] === 'function') { + target.removeAttribute(prop); + } + return value; + } + } + return null; + }; + ObjectDefineProperty(obj, prop, desc); +} +function patchOnProperties(obj, properties, prototype) { + if (properties) { + for (var i = 0; i < properties.length; i++) { + patchProperty(obj, 'on' + properties[i], prototype); + } + } + else { + var onProperties = []; + for (var prop in obj) { + if (prop.substr(0, 2) == 'on') { + onProperties.push(prop); + } + } + for (var j = 0; j < onProperties.length; j++) { + patchProperty(obj, onProperties[j], prototype); + } + } +} +var originalInstanceKey = zoneSymbol('originalInstance'); +// wrap some native API on `window` +function patchClass(className) { + var OriginalClass = _global[className]; + if (!OriginalClass) + return; + // keep original class in global + _global[zoneSymbol(className)] = OriginalClass; + _global[className] = function () { + var a = bindArguments(arguments, className); + switch (a.length) { + case 0: + this[originalInstanceKey] = new OriginalClass(); + break; + case 1: + this[originalInstanceKey] = new OriginalClass(a[0]); + break; + case 2: + this[originalInstanceKey] = new OriginalClass(a[0], a[1]); + break; + case 3: + this[originalInstanceKey] = new OriginalClass(a[0], a[1], a[2]); + break; + case 4: + this[originalInstanceKey] = new OriginalClass(a[0], a[1], a[2], a[3]); + break; + default: + throw new Error('Arg list too long.'); + } + }; + // attach original delegate to patched function + attachOriginToPatched(_global[className], OriginalClass); + var instance = new OriginalClass(function () { }); + var prop; + for (prop in instance) { + // https://bugs.webkit.org/show_bug.cgi?id=44721 + if (className === 'XMLHttpRequest' && prop === 'responseBlob') + continue; + (function (prop) { + if (typeof instance[prop] === 'function') { + _global[className].prototype[prop] = function () { + return this[originalInstanceKey][prop].apply(this[originalInstanceKey], arguments); + }; + } + else { + ObjectDefineProperty(_global[className].prototype, prop, { + set: function (fn) { + if (typeof fn === 'function') { + this[originalInstanceKey][prop] = wrapWithCurrentZone(fn, className + '.' + prop); + // keep callback in wrapped function so we can + // use it in Function.prototype.toString to return + // the native one. + attachOriginToPatched(this[originalInstanceKey][prop], fn); + } + else { + this[originalInstanceKey][prop] = fn; + } + }, + get: function () { + return this[originalInstanceKey][prop]; + } + }); + } + }(prop)); + } + for (prop in OriginalClass) { + if (prop !== 'prototype' && OriginalClass.hasOwnProperty(prop)) { + _global[className][prop] = OriginalClass[prop]; + } + } +} +function patchMethod(target, name, patchFn) { + var proto = target; + while (proto && !proto.hasOwnProperty(name)) { + proto = ObjectGetPrototypeOf(proto); + } + if (!proto && target[name]) { + // somehow we did not find it, but we can see it. This happens on IE for Window properties. + proto = target; + } + var delegateName = zoneSymbol(name); + var delegate; + if (proto && !(delegate = proto[delegateName])) { + delegate = proto[delegateName] = proto[name]; + // check whether proto[name] is writable + // some property is readonly in safari, such as HtmlCanvasElement.prototype.toBlob + var desc = proto && ObjectGetOwnPropertyDescriptor(proto, name); + if (isPropertyWritable(desc)) { + var patchDelegate_1 = patchFn(delegate, delegateName, name); + proto[name] = function () { + return patchDelegate_1(this, arguments); + }; + attachOriginToPatched(proto[name], delegate); + } + } + return delegate; +} +// TODO: @JiaLiPassion, support cancel task later if necessary +function patchMacroTask(obj, funcName, metaCreator) { + var setNative = null; + function scheduleTask(task) { + var data = task.data; + data.args[data.cbIdx] = function () { + task.invoke.apply(this, arguments); + }; + setNative.apply(data.target, data.args); + return task; + } + setNative = patchMethod(obj, funcName, function (delegate) { return function (self, args) { + var meta = metaCreator(self, args); + if (meta.cbIdx >= 0 && typeof args[meta.cbIdx] === 'function') { + return scheduleMacroTaskWithCurrentZone(meta.name, args[meta.cbIdx], meta, scheduleTask, null); + } + else { + // cause an error by calling it directly. + return delegate.apply(self, args); + } + }; }); +} + +function attachOriginToPatched(patched, original) { + patched[zoneSymbol('OriginalDelegate')] = original; +} +var isDetectedIEOrEdge = false; +var ieOrEdge = false; +function isIEOrEdge() { + if (isDetectedIEOrEdge) { + return ieOrEdge; + } + isDetectedIEOrEdge = true; + try { + var ua = internalWindow.navigator.userAgent; + if (ua.indexOf('MSIE ') !== -1 || ua.indexOf('Trident/') !== -1 || ua.indexOf('Edge/') !== -1) { + ieOrEdge = true; + } + return ieOrEdge; + } + catch (error) { + } +} + +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +// override Function.prototype.toString to make zone.js patched function +// look like native function +Zone.__load_patch('toString', function (global) { + // patch Func.prototype.toString to let them look like native + var originalFunctionToString = Function.prototype.toString; + var ORIGINAL_DELEGATE_SYMBOL = zoneSymbol('OriginalDelegate'); + var PROMISE_SYMBOL = zoneSymbol('Promise'); + var ERROR_SYMBOL = zoneSymbol('Error'); + var newFunctionToString = function toString() { + if (typeof this === 'function') { + var originalDelegate = this[ORIGINAL_DELEGATE_SYMBOL]; + if (originalDelegate) { + if (typeof originalDelegate === 'function') { + return originalFunctionToString.apply(this[ORIGINAL_DELEGATE_SYMBOL], arguments); + } + else { + return Object.prototype.toString.call(originalDelegate); + } + } + if (this === Promise) { + var nativePromise = global[PROMISE_SYMBOL]; + if (nativePromise) { + return originalFunctionToString.apply(nativePromise, arguments); + } + } + if (this === Error) { + var nativeError = global[ERROR_SYMBOL]; + if (nativeError) { + return originalFunctionToString.apply(nativeError, arguments); + } + } + } + return originalFunctionToString.apply(this, arguments); + }; + newFunctionToString[ORIGINAL_DELEGATE_SYMBOL] = originalFunctionToString; + Function.prototype.toString = newFunctionToString; + // patch Object.prototype.toString to let them look like native + var originalObjectToString = Object.prototype.toString; + var PROMISE_OBJECT_TO_STRING = '[object Promise]'; + Object.prototype.toString = function () { + if (this instanceof Promise) { + return PROMISE_OBJECT_TO_STRING; + } + return originalObjectToString.apply(this, arguments); + }; +}); + +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +/** + * @fileoverview + * @suppress {missingRequire} + */ +// an identifier to tell ZoneTask do not create a new invoke closure +var OPTIMIZED_ZONE_EVENT_TASK_DATA = { + useG: true +}; +var zoneSymbolEventNames$1 = {}; +var globalSources = {}; +var EVENT_NAME_SYMBOL_REGX = /^__zone_symbol__(\w+)(true|false)$/; +var IMMEDIATE_PROPAGATION_SYMBOL = ('__zone_symbol__propagationStopped'); +function patchEventTarget(_global, apis, patchOptions) { + var ADD_EVENT_LISTENER = (patchOptions && patchOptions.add) || ADD_EVENT_LISTENER_STR; + var REMOVE_EVENT_LISTENER = (patchOptions && patchOptions.rm) || REMOVE_EVENT_LISTENER_STR; + var LISTENERS_EVENT_LISTENER = (patchOptions && patchOptions.listeners) || 'eventListeners'; + var REMOVE_ALL_LISTENERS_EVENT_LISTENER = (patchOptions && patchOptions.rmAll) || 'removeAllListeners'; + var zoneSymbolAddEventListener = zoneSymbol(ADD_EVENT_LISTENER); + var ADD_EVENT_LISTENER_SOURCE = '.' + ADD_EVENT_LISTENER + ':'; + var PREPEND_EVENT_LISTENER = 'prependListener'; + var PREPEND_EVENT_LISTENER_SOURCE = '.' + PREPEND_EVENT_LISTENER + ':'; + var invokeTask = function (task, target, event) { + // for better performance, check isRemoved which is set + // by removeEventListener + if (task.isRemoved) { + return; + } + var delegate = task.callback; + if (typeof delegate === 'object' && delegate.handleEvent) { + // create the bind version of handleEvent when invoke + task.callback = function (event) { return delegate.handleEvent(event); }; + task.originalDelegate = delegate; + } + // invoke static task.invoke + task.invoke(task, target, [event]); + var options = task.options; + if (options && typeof options === 'object' && options.once) { + // if options.once is true, after invoke once remove listener here + // only browser need to do this, nodejs eventEmitter will cal removeListener + // inside EventEmitter.once + var delegate_1 = task.originalDelegate ? task.originalDelegate : task.callback; + target[REMOVE_EVENT_LISTENER].call(target, event.type, delegate_1, options); + } + }; + // global shared zoneAwareCallback to handle all event callback with capture = false + var globalZoneAwareCallback = function (event) { + // https://github.com/angular/zone.js/issues/911, in IE, sometimes + // event will be undefined, so we need to use window.event + event = event || _global.event; + if (!event) { + return; + } + // event.target is needed for Samsung TV and SourceBuffer + // || global is needed https://github.com/angular/zone.js/issues/190 + var target = this || event.target || _global; + var tasks = target[zoneSymbolEventNames$1[event.type][FALSE_STR]]; + if (tasks) { + // invoke all tasks which attached to current target with given event.type and capture = false + // for performance concern, if task.length === 1, just invoke + if (tasks.length === 1) { + invokeTask(tasks[0], target, event); + } + else { + // https://github.com/angular/zone.js/issues/836 + // copy the tasks array before invoke, to avoid + // the callback will remove itself or other listener + var copyTasks = tasks.slice(); + for (var i = 0; i < copyTasks.length; i++) { + if (event && event[IMMEDIATE_PROPAGATION_SYMBOL] === true) { + break; + } + invokeTask(copyTasks[i], target, event); + } + } + } + }; + // global shared zoneAwareCallback to handle all event callback with capture = true + var globalZoneAwareCaptureCallback = function (event) { + // https://github.com/angular/zone.js/issues/911, in IE, sometimes + // event will be undefined, so we need to use window.event + event = event || _global.event; + if (!event) { + return; + } + // event.target is needed for Samsung TV and SourceBuffer + // || global is needed https://github.com/angular/zone.js/issues/190 + var target = this || event.target || _global; + var tasks = target[zoneSymbolEventNames$1[event.type][TRUE_STR]]; + if (tasks) { + // invoke all tasks which attached to current target with given event.type and capture = false + // for performance concern, if task.length === 1, just invoke + if (tasks.length === 1) { + invokeTask(tasks[0], target, event); + } + else { + // https://github.com/angular/zone.js/issues/836 + // copy the tasks array before invoke, to avoid + // the callback will remove itself or other listener + var copyTasks = tasks.slice(); + for (var i = 0; i < copyTasks.length; i++) { + if (event && event[IMMEDIATE_PROPAGATION_SYMBOL] === true) { + break; + } + invokeTask(copyTasks[i], target, event); + } + } + } + }; + function patchEventTargetMethods(obj, patchOptions) { + if (!obj) { + return false; + } + var useGlobalCallback = true; + if (patchOptions && patchOptions.useG !== undefined) { + useGlobalCallback = patchOptions.useG; + } + var validateHandler = patchOptions && patchOptions.vh; + var checkDuplicate = true; + if (patchOptions && patchOptions.chkDup !== undefined) { + checkDuplicate = patchOptions.chkDup; + } + var returnTarget = false; + if (patchOptions && patchOptions.rt !== undefined) { + returnTarget = patchOptions.rt; + } + var proto = obj; + while (proto && !proto.hasOwnProperty(ADD_EVENT_LISTENER)) { + proto = ObjectGetPrototypeOf(proto); + } + if (!proto && obj[ADD_EVENT_LISTENER]) { + // somehow we did not find it, but we can see it. This happens on IE for Window properties. + proto = obj; + } + if (!proto) { + return false; + } + if (proto[zoneSymbolAddEventListener]) { + return false; + } + // a shared global taskData to pass data for scheduleEventTask + // so we do not need to create a new object just for pass some data + var taskData = {}; + var nativeAddEventListener = proto[zoneSymbolAddEventListener] = proto[ADD_EVENT_LISTENER]; + var nativeRemoveEventListener = proto[zoneSymbol(REMOVE_EVENT_LISTENER)] = + proto[REMOVE_EVENT_LISTENER]; + var nativeListeners = proto[zoneSymbol(LISTENERS_EVENT_LISTENER)] = + proto[LISTENERS_EVENT_LISTENER]; + var nativeRemoveAllListeners = proto[zoneSymbol(REMOVE_ALL_LISTENERS_EVENT_LISTENER)] = + proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER]; + var nativePrependEventListener; + if (patchOptions && patchOptions.prepend) { + nativePrependEventListener = proto[zoneSymbol(patchOptions.prepend)] = + proto[patchOptions.prepend]; + } + var customScheduleGlobal = function () { + // if there is already a task for the eventName + capture, + // just return, because we use the shared globalZoneAwareCallback here. + if (taskData.isExisting) { + return; + } + return nativeAddEventListener.call(taskData.target, taskData.eventName, taskData.capture ? globalZoneAwareCaptureCallback : globalZoneAwareCallback, taskData.options); + }; + var customCancelGlobal = function (task) { + // if task is not marked as isRemoved, this call is directly + // from Zone.prototype.cancelTask, we should remove the task + // from tasksList of target first + if (!task.isRemoved) { + var symbolEventNames = zoneSymbolEventNames$1[task.eventName]; + var symbolEventName = void 0; + if (symbolEventNames) { + symbolEventName = symbolEventNames[task.capture ? TRUE_STR : FALSE_STR]; + } + var existingTasks = symbolEventName && task.target[symbolEventName]; + if (existingTasks) { + for (var i = 0; i < existingTasks.length; i++) { + var existingTask = existingTasks[i]; + if (existingTask === task) { + existingTasks.splice(i, 1); + // set isRemoved to data for faster invokeTask check + task.isRemoved = true; + if (existingTasks.length === 0) { + // all tasks for the eventName + capture have gone, + // remove globalZoneAwareCallback and remove the task cache from target + task.allRemoved = true; + task.target[symbolEventName] = null; + } + break; + } + } + } + } + // if all tasks for the eventName + capture have gone, + // we will really remove the global event callback, + // if not, return + if (!task.allRemoved) { + return; + } + return nativeRemoveEventListener.call(task.target, task.eventName, task.capture ? globalZoneAwareCaptureCallback : globalZoneAwareCallback, task.options); + }; + var customScheduleNonGlobal = function (task) { + return nativeAddEventListener.call(taskData.target, taskData.eventName, task.invoke, taskData.options); + }; + var customSchedulePrepend = function (task) { + return nativePrependEventListener.call(taskData.target, taskData.eventName, task.invoke, taskData.options); + }; + var customCancelNonGlobal = function (task) { + return nativeRemoveEventListener.call(task.target, task.eventName, task.invoke, task.options); + }; + var customSchedule = useGlobalCallback ? customScheduleGlobal : customScheduleNonGlobal; + var customCancel = useGlobalCallback ? customCancelGlobal : customCancelNonGlobal; + var compareTaskCallbackVsDelegate = function (task, delegate) { + var typeOfDelegate = typeof delegate; + return (typeOfDelegate === 'function' && task.callback === delegate) || + (typeOfDelegate === 'object' && task.originalDelegate === delegate); + }; + var compare = (patchOptions && patchOptions.diff) ? patchOptions.diff : compareTaskCallbackVsDelegate; + var blackListedEvents = Zone[Zone.__symbol__('BLACK_LISTED_EVENTS')]; + var makeAddListener = function (nativeListener, addSource, customScheduleFn, customCancelFn, returnTarget, prepend) { + if (returnTarget === void 0) { returnTarget = false; } + if (prepend === void 0) { prepend = false; } + return function () { + var target = this || _global; + var delegate = arguments[1]; + if (!delegate) { + return nativeListener.apply(this, arguments); + } + // don't create the bind delegate function for handleEvent + // case here to improve addEventListener performance + // we will create the bind delegate when invoke + var isHandleEvent = false; + if (typeof delegate !== 'function') { + if (!delegate.handleEvent) { + return nativeListener.apply(this, arguments); + } + isHandleEvent = true; + } + if (validateHandler && !validateHandler(nativeListener, delegate, target, arguments)) { + return; + } + var eventName = arguments[0]; + var options = arguments[2]; + if (blackListedEvents) { + // check black list + for (var i = 0; i < blackListedEvents.length; i++) { + if (eventName === blackListedEvents[i]) { + return nativeListener.apply(this, arguments); + } + } + } + var capture; + var once = false; + if (options === undefined) { + capture = false; + } + else if (options === true) { + capture = true; + } + else if (options === false) { + capture = false; + } + else { + capture = options ? !!options.capture : false; + once = options ? !!options.once : false; + } + var zone = Zone.current; + var symbolEventNames = zoneSymbolEventNames$1[eventName]; + var symbolEventName; + if (!symbolEventNames) { + // the code is duplicate, but I just want to get some better performance + var falseEventName = eventName + FALSE_STR; + var trueEventName = eventName + TRUE_STR; + var symbol = ZONE_SYMBOL_PREFIX + falseEventName; + var symbolCapture = ZONE_SYMBOL_PREFIX + trueEventName; + zoneSymbolEventNames$1[eventName] = {}; + zoneSymbolEventNames$1[eventName][FALSE_STR] = symbol; + zoneSymbolEventNames$1[eventName][TRUE_STR] = symbolCapture; + symbolEventName = capture ? symbolCapture : symbol; + } + else { + symbolEventName = symbolEventNames[capture ? TRUE_STR : FALSE_STR]; + } + var existingTasks = target[symbolEventName]; + var isExisting = false; + if (existingTasks) { + // already have task registered + isExisting = true; + if (checkDuplicate) { + for (var i = 0; i < existingTasks.length; i++) { + if (compare(existingTasks[i], delegate)) { + // same callback, same capture, same event name, just return + return; + } + } + } + } + else { + existingTasks = target[symbolEventName] = []; + } + var source; + var constructorName = target.constructor['name']; + var targetSource = globalSources[constructorName]; + if (targetSource) { + source = targetSource[eventName]; + } + if (!source) { + source = constructorName + addSource + eventName; + } + // do not create a new object as task.data to pass those things + // just use the global shared one + taskData.options = options; + if (once) { + // if addEventListener with once options, we don't pass it to + // native addEventListener, instead we keep the once setting + // and handle ourselves. + taskData.options.once = false; + } + taskData.target = target; + taskData.capture = capture; + taskData.eventName = eventName; + taskData.isExisting = isExisting; + var data = useGlobalCallback ? OPTIMIZED_ZONE_EVENT_TASK_DATA : null; + // keep taskData into data to allow onScheduleEventTask to access the task information + if (data) { + data.taskData = taskData; + } + var task = zone.scheduleEventTask(source, delegate, data, customScheduleFn, customCancelFn); + // should clear taskData.target to avoid memory leak + // issue, https://github.com/angular/angular/issues/20442 + taskData.target = null; + // need to clear up taskData because it is a global object + if (data) { + data.taskData = null; + } + // have to save those information to task in case + // application may call task.zone.cancelTask() directly + if (once) { + options.once = true; + } + task.options = options; + task.target = target; + task.capture = capture; + task.eventName = eventName; + if (isHandleEvent) { + // save original delegate for compare to check duplicate + task.originalDelegate = delegate; + } + if (!prepend) { + existingTasks.push(task); + } + else { + existingTasks.unshift(task); + } + if (returnTarget) { + return target; + } + }; + }; + proto[ADD_EVENT_LISTENER] = makeAddListener(nativeAddEventListener, ADD_EVENT_LISTENER_SOURCE, customSchedule, customCancel, returnTarget); + if (nativePrependEventListener) { + proto[PREPEND_EVENT_LISTENER] = makeAddListener(nativePrependEventListener, PREPEND_EVENT_LISTENER_SOURCE, customSchedulePrepend, customCancel, returnTarget, true); + } + proto[REMOVE_EVENT_LISTENER] = function () { + var target = this || _global; + var eventName = arguments[0]; + var options = arguments[2]; + var capture; + if (options === undefined) { + capture = false; + } + else if (options === true) { + capture = true; + } + else if (options === false) { + capture = false; + } + else { + capture = options ? !!options.capture : false; + } + var delegate = arguments[1]; + if (!delegate) { + return nativeRemoveEventListener.apply(this, arguments); + } + if (validateHandler && + !validateHandler(nativeRemoveEventListener, delegate, target, arguments)) { + return; + } + var symbolEventNames = zoneSymbolEventNames$1[eventName]; + var symbolEventName; + if (symbolEventNames) { + symbolEventName = symbolEventNames[capture ? TRUE_STR : FALSE_STR]; + } + var existingTasks = symbolEventName && target[symbolEventName]; + if (existingTasks) { + for (var i = 0; i < existingTasks.length; i++) { + var existingTask = existingTasks[i]; + if (compare(existingTask, delegate)) { + existingTasks.splice(i, 1); + // set isRemoved to data for faster invokeTask check + existingTask.isRemoved = true; + if (existingTasks.length === 0) { + // all tasks for the eventName + capture have gone, + // remove globalZoneAwareCallback and remove the task cache from target + existingTask.allRemoved = true; + target[symbolEventName] = null; + } + existingTask.zone.cancelTask(existingTask); + if (returnTarget) { + return target; + } + return; + } + } + } + // issue 930, didn't find the event name or callback + // from zone kept existingTasks, the callback maybe + // added outside of zone, we need to call native removeEventListener + // to try to remove it. + return nativeRemoveEventListener.apply(this, arguments); + }; + proto[LISTENERS_EVENT_LISTENER] = function () { + var target = this || _global; + var eventName = arguments[0]; + var listeners = []; + var tasks = findEventTasks(target, eventName); + for (var i = 0; i < tasks.length; i++) { + var task = tasks[i]; + var delegate = task.originalDelegate ? task.originalDelegate : task.callback; + listeners.push(delegate); + } + return listeners; + }; + proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER] = function () { + var target = this || _global; + var eventName = arguments[0]; + if (!eventName) { + var keys = Object.keys(target); + for (var i = 0; i < keys.length; i++) { + var prop = keys[i]; + var match = EVENT_NAME_SYMBOL_REGX.exec(prop); + var evtName = match && match[1]; + // in nodejs EventEmitter, removeListener event is + // used for monitoring the removeListener call, + // so just keep removeListener eventListener until + // all other eventListeners are removed + if (evtName && evtName !== 'removeListener') { + this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, evtName); + } + } + // remove removeListener listener finally + this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, 'removeListener'); + } + else { + var symbolEventNames = zoneSymbolEventNames$1[eventName]; + if (symbolEventNames) { + var symbolEventName = symbolEventNames[FALSE_STR]; + var symbolCaptureEventName = symbolEventNames[TRUE_STR]; + var tasks = target[symbolEventName]; + var captureTasks = target[symbolCaptureEventName]; + if (tasks) { + var removeTasks = tasks.slice(); + for (var i = 0; i < removeTasks.length; i++) { + var task = removeTasks[i]; + var delegate = task.originalDelegate ? task.originalDelegate : task.callback; + this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options); + } + } + if (captureTasks) { + var removeTasks = captureTasks.slice(); + for (var i = 0; i < removeTasks.length; i++) { + var task = removeTasks[i]; + var delegate = task.originalDelegate ? task.originalDelegate : task.callback; + this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options); + } + } + } + } + if (returnTarget) { + return this; + } + }; + // for native toString patch + attachOriginToPatched(proto[ADD_EVENT_LISTENER], nativeAddEventListener); + attachOriginToPatched(proto[REMOVE_EVENT_LISTENER], nativeRemoveEventListener); + if (nativeRemoveAllListeners) { + attachOriginToPatched(proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER], nativeRemoveAllListeners); + } + if (nativeListeners) { + attachOriginToPatched(proto[LISTENERS_EVENT_LISTENER], nativeListeners); + } + return true; + } + var results = []; + for (var i = 0; i < apis.length; i++) { + results[i] = patchEventTargetMethods(apis[i], patchOptions); + } + return results; +} +function findEventTasks(target, eventName) { + var foundTasks = []; + for (var prop in target) { + var match = EVENT_NAME_SYMBOL_REGX.exec(prop); + var evtName = match && match[1]; + if (evtName && (!eventName || evtName === eventName)) { + var tasks = target[prop]; + if (tasks) { + for (var i = 0; i < tasks.length; i++) { + foundTasks.push(tasks[i]); + } + } + } + } + return foundTasks; +} +function patchEventPrototype(global, api) { + var Event = global['Event']; + if (Event && Event.prototype) { + api.patchMethod(Event.prototype, 'stopImmediatePropagation', function (delegate) { return function (self, args) { + self[IMMEDIATE_PROPAGATION_SYMBOL] = true; + // we need to call the native stopImmediatePropagation + // in case in some hybrid application, some part of + // application will be controlled by zone, some are not + delegate && delegate.apply(self, args); + }; }); + } +} + +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +/** + * @fileoverview + * @suppress {missingRequire} + */ +var taskSymbol = zoneSymbol('zoneTask'); +function patchTimer(window, setName, cancelName, nameSuffix) { + var setNative = null; + var clearNative = null; + setName += nameSuffix; + cancelName += nameSuffix; + var tasksByHandleId = {}; + function scheduleTask(task) { + var data = task.data; + function timer() { + try { + task.invoke.apply(this, arguments); + } + finally { + // issue-934, task will be cancelled + // even it is a periodic task such as + // setInterval + if (!(task.data && task.data.isPeriodic)) { + if (typeof data.handleId === 'number') { + // in non-nodejs env, we remove timerId + // from local cache + delete tasksByHandleId[data.handleId]; + } + else if (data.handleId) { + // Node returns complex objects as handleIds + // we remove task reference from timer object + data.handleId[taskSymbol] = null; + } + } + } + } + data.args[0] = timer; + data.handleId = setNative.apply(window, data.args); + return task; + } + function clearTask(task) { + return clearNative(task.data.handleId); + } + setNative = + patchMethod(window, setName, function (delegate) { return function (self, args) { + if (typeof args[0] === 'function') { + var options = { + handleId: null, + isPeriodic: nameSuffix === 'Interval', + delay: (nameSuffix === 'Timeout' || nameSuffix === 'Interval') ? args[1] || 0 : null, + args: args + }; + var task = scheduleMacroTaskWithCurrentZone(setName, args[0], options, scheduleTask, clearTask); + if (!task) { + return task; + } + // Node.js must additionally support the ref and unref functions. + var handle = task.data.handleId; + if (typeof handle === 'number') { + // for non nodejs env, we save handleId: task + // mapping in local cache for clearTimeout + tasksByHandleId[handle] = task; + } + else if (handle) { + // for nodejs env, we save task + // reference in timerId Object for clearTimeout + handle[taskSymbol] = task; + } + // check whether handle is null, because some polyfill or browser + // may return undefined from setTimeout/setInterval/setImmediate/requestAnimationFrame + if (handle && handle.ref && handle.unref && typeof handle.ref === 'function' && + typeof handle.unref === 'function') { + task.ref = handle.ref.bind(handle); + task.unref = handle.unref.bind(handle); + } + if (typeof handle === 'number' || handle) { + return handle; + } + return task; + } + else { + // cause an error by calling it directly. + return delegate.apply(window, args); + } + }; }); + clearNative = + patchMethod(window, cancelName, function (delegate) { return function (self, args) { + var id = args[0]; + var task; + if (typeof id === 'number') { + // non nodejs env. + task = tasksByHandleId[id]; + } + else { + // nodejs env. + task = id && id[taskSymbol]; + // other environments. + if (!task) { + task = id; + } + } + if (task && typeof task.type === 'string') { + if (task.state !== 'notScheduled' && + (task.cancelFn && task.data.isPeriodic || task.runCount === 0)) { + if (typeof id === 'number') { + delete tasksByHandleId[id]; + } + else if (id) { + id[taskSymbol] = null; + } + // Do not cancel already canceled functions + task.zone.cancelTask(task); + } + } + else { + // cause an error by calling it directly. + delegate.apply(window, args); + } + }; }); +} + +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +/* + * This is necessary for Chrome and Chrome mobile, to enable + * things like redefining `createdCallback` on an element. + */ +var _defineProperty = Object[zoneSymbol('defineProperty')] = Object.defineProperty; +var _getOwnPropertyDescriptor = Object[zoneSymbol('getOwnPropertyDescriptor')] = + Object.getOwnPropertyDescriptor; +var _create = Object.create; +var unconfigurablesKey = zoneSymbol('unconfigurables'); +function propertyPatch() { + Object.defineProperty = function (obj, prop, desc) { + if (isUnconfigurable(obj, prop)) { + throw new TypeError('Cannot assign to read only property \'' + prop + '\' of ' + obj); + } + var originalConfigurableFlag = desc.configurable; + if (prop !== 'prototype') { + desc = rewriteDescriptor(obj, prop, desc); + } + return _tryDefineProperty(obj, prop, desc, originalConfigurableFlag); + }; + Object.defineProperties = function (obj, props) { + Object.keys(props).forEach(function (prop) { + Object.defineProperty(obj, prop, props[prop]); + }); + return obj; + }; + Object.create = function (obj, proto) { + if (typeof proto === 'object' && !Object.isFrozen(proto)) { + Object.keys(proto).forEach(function (prop) { + proto[prop] = rewriteDescriptor(obj, prop, proto[prop]); + }); + } + return _create(obj, proto); + }; + Object.getOwnPropertyDescriptor = function (obj, prop) { + var desc = _getOwnPropertyDescriptor(obj, prop); + if (isUnconfigurable(obj, prop)) { + desc.configurable = false; + } + return desc; + }; +} +function _redefineProperty(obj, prop, desc) { + var originalConfigurableFlag = desc.configurable; + desc = rewriteDescriptor(obj, prop, desc); + return _tryDefineProperty(obj, prop, desc, originalConfigurableFlag); +} +function isUnconfigurable(obj, prop) { + return obj && obj[unconfigurablesKey] && obj[unconfigurablesKey][prop]; +} +function rewriteDescriptor(obj, prop, desc) { + // issue-927, if the desc is frozen, don't try to change the desc + if (!Object.isFrozen(desc)) { + desc.configurable = true; + } + if (!desc.configurable) { + // issue-927, if the obj is frozen, don't try to set the desc to obj + if (!obj[unconfigurablesKey] && !Object.isFrozen(obj)) { + _defineProperty(obj, unconfigurablesKey, { writable: true, value: {} }); + } + if (obj[unconfigurablesKey]) { + obj[unconfigurablesKey][prop] = true; + } + } + return desc; +} +function _tryDefineProperty(obj, prop, desc, originalConfigurableFlag) { + try { + return _defineProperty(obj, prop, desc); + } + catch (error) { + if (desc.configurable) { + // In case of errors, when the configurable flag was likely set by rewriteDescriptor(), let's + // retry with the original flag value + if (typeof originalConfigurableFlag == 'undefined') { + delete desc.configurable; + } + else { + desc.configurable = originalConfigurableFlag; + } + try { + return _defineProperty(obj, prop, desc); + } + catch (error) { + var descJson = null; + try { + descJson = JSON.stringify(desc); + } + catch (error) { + descJson = desc.toString(); + } + console.log("Attempting to configure '" + prop + "' with descriptor '" + descJson + "' on object '" + obj + "' and got error, giving up: " + error); + } + } + else { + throw error; + } + } +} + +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +// we have to patch the instance since the proto is non-configurable +function apply(api, _global) { + var WS = _global.WebSocket; + // On Safari window.EventTarget doesn't exist so need to patch WS add/removeEventListener + // On older Chrome, no need since EventTarget was already patched + if (!_global.EventTarget) { + patchEventTarget(_global, [WS.prototype]); + } + _global.WebSocket = function (x, y) { + var socket = arguments.length > 1 ? new WS(x, y) : new WS(x); + var proxySocket; + var proxySocketProto; + // Safari 7.0 has non-configurable own 'onmessage' and friends properties on the socket instance + var onmessageDesc = ObjectGetOwnPropertyDescriptor(socket, 'onmessage'); + if (onmessageDesc && onmessageDesc.configurable === false) { + proxySocket = ObjectCreate(socket); + // socket have own property descriptor 'onopen', 'onmessage', 'onclose', 'onerror' + // but proxySocket not, so we will keep socket as prototype and pass it to + // patchOnProperties method + proxySocketProto = socket; + [ADD_EVENT_LISTENER_STR, REMOVE_EVENT_LISTENER_STR, 'send', 'close'].forEach(function (propName) { + proxySocket[propName] = function () { + var args = ArraySlice.call(arguments); + if (propName === ADD_EVENT_LISTENER_STR || propName === REMOVE_EVENT_LISTENER_STR) { + var eventName = args.length > 0 ? args[0] : undefined; + if (eventName) { + var propertySymbol = Zone.__symbol__('ON_PROPERTY' + eventName); + socket[propertySymbol] = proxySocket[propertySymbol]; + } + } + return socket[propName].apply(socket, args); + }; + }); + } + else { + // we can patch the real socket + proxySocket = socket; + } + patchOnProperties(proxySocket, ['close', 'error', 'message', 'open'], proxySocketProto); + return proxySocket; + }; + var globalWebSocket = _global['WebSocket']; + for (var prop in WS) { + globalWebSocket[prop] = WS[prop]; + } +} + +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +/** + * @fileoverview + * @suppress {globalThis} + */ +var globalEventHandlersEventNames = [ + 'abort', + 'animationcancel', + 'animationend', + 'animationiteration', + 'auxclick', + 'beforeinput', + 'blur', + 'cancel', + 'canplay', + 'canplaythrough', + 'change', + 'compositionstart', + 'compositionupdate', + 'compositionend', + 'cuechange', + 'click', + 'close', + 'contextmenu', + 'curechange', + 'dblclick', + 'drag', + 'dragend', + 'dragenter', + 'dragexit', + 'dragleave', + 'dragover', + 'drop', + 'durationchange', + 'emptied', + 'ended', + 'error', + 'focus', + 'focusin', + 'focusout', + 'gotpointercapture', + 'input', + 'invalid', + 'keydown', + 'keypress', + 'keyup', + 'load', + 'loadstart', + 'loadeddata', + 'loadedmetadata', + 'lostpointercapture', + 'mousedown', + 'mouseenter', + 'mouseleave', + 'mousemove', + 'mouseout', + 'mouseover', + 'mouseup', + 'mousewheel', + 'orientationchange', + 'pause', + 'play', + 'playing', + 'pointercancel', + 'pointerdown', + 'pointerenter', + 'pointerleave', + 'pointerlockchange', + 'mozpointerlockchange', + 'webkitpointerlockerchange', + 'pointerlockerror', + 'mozpointerlockerror', + 'webkitpointerlockerror', + 'pointermove', + 'pointout', + 'pointerover', + 'pointerup', + 'progress', + 'ratechange', + 'reset', + 'resize', + 'scroll', + 'seeked', + 'seeking', + 'select', + 'selectionchange', + 'selectstart', + 'show', + 'sort', + 'stalled', + 'submit', + 'suspend', + 'timeupdate', + 'volumechange', + 'touchcancel', + 'touchmove', + 'touchstart', + 'touchend', + 'transitioncancel', + 'transitionend', + 'waiting', + 'wheel' +]; +var documentEventNames = [ + 'afterscriptexecute', 'beforescriptexecute', 'DOMContentLoaded', 'fullscreenchange', + 'mozfullscreenchange', 'webkitfullscreenchange', 'msfullscreenchange', 'fullscreenerror', + 'mozfullscreenerror', 'webkitfullscreenerror', 'msfullscreenerror', 'readystatechange', + 'visibilitychange' +]; +var windowEventNames = [ + 'absolutedeviceorientation', + 'afterinput', + 'afterprint', + 'appinstalled', + 'beforeinstallprompt', + 'beforeprint', + 'beforeunload', + 'devicelight', + 'devicemotion', + 'deviceorientation', + 'deviceorientationabsolute', + 'deviceproximity', + 'hashchange', + 'languagechange', + 'message', + 'mozbeforepaint', + 'offline', + 'online', + 'paint', + 'pageshow', + 'pagehide', + 'popstate', + 'rejectionhandled', + 'storage', + 'unhandledrejection', + 'unload', + 'userproximity', + 'vrdisplyconnected', + 'vrdisplaydisconnected', + 'vrdisplaypresentchange' +]; +var htmlElementEventNames = [ + 'beforecopy', 'beforecut', 'beforepaste', 'copy', 'cut', 'paste', 'dragstart', 'loadend', + 'animationstart', 'search', 'transitionrun', 'transitionstart', 'webkitanimationend', + 'webkitanimationiteration', 'webkitanimationstart', 'webkittransitionend' +]; +var mediaElementEventNames = ['encrypted', 'waitingforkey', 'msneedkey', 'mozinterruptbegin', 'mozinterruptend']; +var ieElementEventNames = [ + 'activate', + 'afterupdate', + 'ariarequest', + 'beforeactivate', + 'beforedeactivate', + 'beforeeditfocus', + 'beforeupdate', + 'cellchange', + 'controlselect', + 'dataavailable', + 'datasetchanged', + 'datasetcomplete', + 'errorupdate', + 'filterchange', + 'layoutcomplete', + 'losecapture', + 'move', + 'moveend', + 'movestart', + 'propertychange', + 'resizeend', + 'resizestart', + 'rowenter', + 'rowexit', + 'rowsdelete', + 'rowsinserted', + 'command', + 'compassneedscalibration', + 'deactivate', + 'help', + 'mscontentzoom', + 'msmanipulationstatechanged', + 'msgesturechange', + 'msgesturedoubletap', + 'msgestureend', + 'msgesturehold', + 'msgesturestart', + 'msgesturetap', + 'msgotpointercapture', + 'msinertiastart', + 'mslostpointercapture', + 'mspointercancel', + 'mspointerdown', + 'mspointerenter', + 'mspointerhover', + 'mspointerleave', + 'mspointermove', + 'mspointerout', + 'mspointerover', + 'mspointerup', + 'pointerout', + 'mssitemodejumplistitemremoved', + 'msthumbnailclick', + 'stop', + 'storagecommit' +]; +var webglEventNames = ['webglcontextrestored', 'webglcontextlost', 'webglcontextcreationerror']; +var formEventNames = ['autocomplete', 'autocompleteerror']; +var detailEventNames = ['toggle']; +var frameEventNames = ['load']; +var frameSetEventNames = ['blur', 'error', 'focus', 'load', 'resize', 'scroll', 'messageerror']; +var marqueeEventNames = ['bounce', 'finish', 'start']; +var XMLHttpRequestEventNames = [ + 'loadstart', 'progress', 'abort', 'error', 'load', 'progress', 'timeout', 'loadend', + 'readystatechange' +]; +var IDBIndexEventNames = ['upgradeneeded', 'complete', 'abort', 'success', 'error', 'blocked', 'versionchange', 'close']; +var websocketEventNames = ['close', 'error', 'open', 'message']; +var workerEventNames = ['error', 'message']; +var eventNames = globalEventHandlersEventNames.concat(webglEventNames, formEventNames, detailEventNames, documentEventNames, windowEventNames, htmlElementEventNames, ieElementEventNames); +function filterProperties(target, onProperties, ignoreProperties) { + if (!ignoreProperties) { + return onProperties; + } + var tip = ignoreProperties.filter(function (ip) { return ip.target === target; }); + if (!tip || tip.length === 0) { + return onProperties; + } + var targetIgnoreProperties = tip[0].ignoreProperties; + return onProperties.filter(function (op) { return targetIgnoreProperties.indexOf(op) === -1; }); +} +function patchFilteredProperties(target, onProperties, ignoreProperties, prototype) { + // check whether target is available, sometimes target will be undefined + // because different browser or some 3rd party plugin. + if (!target) { + return; + } + var filteredProperties = filterProperties(target, onProperties, ignoreProperties); + patchOnProperties(target, filteredProperties, prototype); +} +function propertyDescriptorPatch(api, _global) { + if (isNode && !isMix) { + return; + } + var supportsWebSocket = typeof WebSocket !== 'undefined'; + if (canPatchViaPropertyDescriptor()) { + var ignoreProperties = _global.__Zone_ignore_on_properties; + // for browsers that we can patch the descriptor: Chrome & Firefox + if (isBrowser) { + var internalWindow = window; + // in IE/Edge, onProp not exist in window object, but in WindowPrototype + // so we need to pass WindowPrototype to check onProp exist or not + patchFilteredProperties(internalWindow, eventNames.concat(['messageerror']), ignoreProperties, ObjectGetPrototypeOf(internalWindow)); + patchFilteredProperties(Document.prototype, eventNames, ignoreProperties); + if (typeof internalWindow['SVGElement'] !== 'undefined') { + patchFilteredProperties(internalWindow['SVGElement'].prototype, eventNames, ignoreProperties); + } + patchFilteredProperties(Element.prototype, eventNames, ignoreProperties); + patchFilteredProperties(HTMLElement.prototype, eventNames, ignoreProperties); + patchFilteredProperties(HTMLMediaElement.prototype, mediaElementEventNames, ignoreProperties); + patchFilteredProperties(HTMLFrameSetElement.prototype, windowEventNames.concat(frameSetEventNames), ignoreProperties); + patchFilteredProperties(HTMLBodyElement.prototype, windowEventNames.concat(frameSetEventNames), ignoreProperties); + patchFilteredProperties(HTMLFrameElement.prototype, frameEventNames, ignoreProperties); + patchFilteredProperties(HTMLIFrameElement.prototype, frameEventNames, ignoreProperties); + var HTMLMarqueeElement_1 = internalWindow['HTMLMarqueeElement']; + if (HTMLMarqueeElement_1) { + patchFilteredProperties(HTMLMarqueeElement_1.prototype, marqueeEventNames, ignoreProperties); + } + var Worker_1 = internalWindow['Worker']; + if (Worker_1) { + patchFilteredProperties(Worker_1.prototype, workerEventNames, ignoreProperties); + } + } + patchFilteredProperties(XMLHttpRequest.prototype, XMLHttpRequestEventNames, ignoreProperties); + var XMLHttpRequestEventTarget = _global['XMLHttpRequestEventTarget']; + if (XMLHttpRequestEventTarget) { + patchFilteredProperties(XMLHttpRequestEventTarget && XMLHttpRequestEventTarget.prototype, XMLHttpRequestEventNames, ignoreProperties); + } + if (typeof IDBIndex !== 'undefined') { + patchFilteredProperties(IDBIndex.prototype, IDBIndexEventNames, ignoreProperties); + patchFilteredProperties(IDBRequest.prototype, IDBIndexEventNames, ignoreProperties); + patchFilteredProperties(IDBOpenDBRequest.prototype, IDBIndexEventNames, ignoreProperties); + patchFilteredProperties(IDBDatabase.prototype, IDBIndexEventNames, ignoreProperties); + patchFilteredProperties(IDBTransaction.prototype, IDBIndexEventNames, ignoreProperties); + patchFilteredProperties(IDBCursor.prototype, IDBIndexEventNames, ignoreProperties); + } + if (supportsWebSocket) { + patchFilteredProperties(WebSocket.prototype, websocketEventNames, ignoreProperties); + } + } + else { + // Safari, Android browsers (Jelly Bean) + patchViaCapturingAllTheEvents(); + patchClass('XMLHttpRequest'); + if (supportsWebSocket) { + apply(api, _global); + } + } +} +function canPatchViaPropertyDescriptor() { + if ((isBrowser || isMix) && !ObjectGetOwnPropertyDescriptor(HTMLElement.prototype, 'onclick') && + typeof Element !== 'undefined') { + // WebKit https://bugs.webkit.org/show_bug.cgi?id=134364 + // IDL interface attributes are not configurable + var desc = ObjectGetOwnPropertyDescriptor(Element.prototype, 'onclick'); + if (desc && !desc.configurable) + return false; + } + var ON_READY_STATE_CHANGE = 'onreadystatechange'; + var XMLHttpRequestPrototype = XMLHttpRequest.prototype; + var xhrDesc = ObjectGetOwnPropertyDescriptor(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE); + // add enumerable and configurable here because in opera + // by default XMLHttpRequest.prototype.onreadystatechange is undefined + // without adding enumerable and configurable will cause onreadystatechange + // non-configurable + // and if XMLHttpRequest.prototype.onreadystatechange is undefined, + // we should set a real desc instead a fake one + if (xhrDesc) { + ObjectDefineProperty(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE, { + enumerable: true, + configurable: true, + get: function () { + return true; + } + }); + var req = new XMLHttpRequest(); + var result = !!req.onreadystatechange; + // restore original desc + ObjectDefineProperty(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE, xhrDesc || {}); + return result; + } + else { + var SYMBOL_FAKE_ONREADYSTATECHANGE_1 = zoneSymbol('fake'); + ObjectDefineProperty(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE, { + enumerable: true, + configurable: true, + get: function () { + return this[SYMBOL_FAKE_ONREADYSTATECHANGE_1]; + }, + set: function (value) { + this[SYMBOL_FAKE_ONREADYSTATECHANGE_1] = value; + } + }); + var req = new XMLHttpRequest(); + var detectFunc = function () { }; + req.onreadystatechange = detectFunc; + var result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc; + req.onreadystatechange = null; + return result; + } +} +var unboundKey = zoneSymbol('unbound'); +// Whenever any eventListener fires, we check the eventListener target and all parents +// for `onwhatever` properties and replace them with zone-bound functions +// - Chrome (for now) +function patchViaCapturingAllTheEvents() { + var _loop_1 = function (i) { + var property = eventNames[i]; + var onproperty = 'on' + property; + self.addEventListener(property, function (event) { + var elt = event.target, bound, source; + if (elt) { + source = elt.constructor['name'] + '.' + onproperty; + } + else { + source = 'unknown.' + onproperty; + } + while (elt) { + if (elt[onproperty] && !elt[onproperty][unboundKey]) { + bound = wrapWithCurrentZone(elt[onproperty], source); + bound[unboundKey] = elt[onproperty]; + elt[onproperty] = bound; + } + elt = elt.parentElement; + } + }, true); + }; + for (var i = 0; i < eventNames.length; i++) { + _loop_1(i); + } +} + +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +function eventTargetPatch(_global, api) { + var WTF_ISSUE_555 = 'Anchor,Area,Audio,BR,Base,BaseFont,Body,Button,Canvas,Content,DList,Directory,Div,Embed,FieldSet,Font,Form,Frame,FrameSet,HR,Head,Heading,Html,IFrame,Image,Input,Keygen,LI,Label,Legend,Link,Map,Marquee,Media,Menu,Meta,Meter,Mod,OList,Object,OptGroup,Option,Output,Paragraph,Pre,Progress,Quote,Script,Select,Source,Span,Style,TableCaption,TableCell,TableCol,Table,TableRow,TableSection,TextArea,Title,Track,UList,Unknown,Video'; + var NO_EVENT_TARGET = 'ApplicationCache,EventSource,FileReader,InputMethodContext,MediaController,MessagePort,Node,Performance,SVGElementInstance,SharedWorker,TextTrack,TextTrackCue,TextTrackList,WebKitNamedFlow,Window,Worker,WorkerGlobalScope,XMLHttpRequest,XMLHttpRequestEventTarget,XMLHttpRequestUpload,IDBRequest,IDBOpenDBRequest,IDBDatabase,IDBTransaction,IDBCursor,DBIndex,WebSocket' + .split(','); + var EVENT_TARGET = 'EventTarget'; + var apis = []; + var isWtf = _global['wtf']; + var WTF_ISSUE_555_ARRAY = WTF_ISSUE_555.split(','); + if (isWtf) { + // Workaround for: https://github.com/google/tracing-framework/issues/555 + apis = WTF_ISSUE_555_ARRAY.map(function (v) { return 'HTML' + v + 'Element'; }).concat(NO_EVENT_TARGET); + } + else if (_global[EVENT_TARGET]) { + apis.push(EVENT_TARGET); + } + else { + // Note: EventTarget is not available in all browsers, + // if it's not available, we instead patch the APIs in the IDL that inherit from EventTarget + apis = NO_EVENT_TARGET; + } + var isDisableIECheck = _global['__Zone_disable_IE_check'] || false; + var isEnableCrossContextCheck = _global['__Zone_enable_cross_context_check'] || false; + var ieOrEdge = isIEOrEdge(); + var ADD_EVENT_LISTENER_SOURCE = '.addEventListener:'; + var FUNCTION_WRAPPER = '[object FunctionWrapper]'; + var BROWSER_TOOLS = 'function __BROWSERTOOLS_CONSOLE_SAFEFUNC() { [native code] }'; + // predefine all __zone_symbol__ + eventName + true/false string + for (var i = 0; i < eventNames.length; i++) { + var eventName = eventNames[i]; + var falseEventName = eventName + FALSE_STR; + var trueEventName = eventName + TRUE_STR; + var symbol = ZONE_SYMBOL_PREFIX + falseEventName; + var symbolCapture = ZONE_SYMBOL_PREFIX + trueEventName; + zoneSymbolEventNames$1[eventName] = {}; + zoneSymbolEventNames$1[eventName][FALSE_STR] = symbol; + zoneSymbolEventNames$1[eventName][TRUE_STR] = symbolCapture; + } + // predefine all task.source string + for (var i = 0; i < WTF_ISSUE_555.length; i++) { + var target = WTF_ISSUE_555_ARRAY[i]; + var targets = globalSources[target] = {}; + for (var j = 0; j < eventNames.length; j++) { + var eventName = eventNames[j]; + targets[eventName] = target + ADD_EVENT_LISTENER_SOURCE + eventName; + } + } + var checkIEAndCrossContext = function (nativeDelegate, delegate, target, args) { + if (!isDisableIECheck && ieOrEdge) { + if (isEnableCrossContextCheck) { + try { + var testString = delegate.toString(); + if ((testString === FUNCTION_WRAPPER || testString == BROWSER_TOOLS)) { + nativeDelegate.apply(target, args); + return false; + } + } + catch (error) { + nativeDelegate.apply(target, args); + return false; + } + } + else { + var testString = delegate.toString(); + if ((testString === FUNCTION_WRAPPER || testString == BROWSER_TOOLS)) { + nativeDelegate.apply(target, args); + return false; + } + } + } + else if (isEnableCrossContextCheck) { + try { + delegate.toString(); + } + catch (error) { + nativeDelegate.apply(target, args); + return false; + } + } + return true; + }; + var apiTypes = []; + for (var i = 0; i < apis.length; i++) { + var type = _global[apis[i]]; + apiTypes.push(type && type.prototype); + } + // vh is validateHandler to check event handler + // is valid or not(for security check) + patchEventTarget(_global, apiTypes, { vh: checkIEAndCrossContext }); + api.patchEventTarget = patchEventTarget; + return true; +} +function patchEvent(global, api) { + patchEventPrototype(global, api); +} + +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +function registerElementPatch(_global) { + if ((!isBrowser && !isMix) || !('registerElement' in _global.document)) { + return; + } + var _registerElement = document.registerElement; + var callbacks = ['createdCallback', 'attachedCallback', 'detachedCallback', 'attributeChangedCallback']; + document.registerElement = function (name, opts) { + if (opts && opts.prototype) { + callbacks.forEach(function (callback) { + var source = 'Document.registerElement::' + callback; + var prototype = opts.prototype; + if (prototype.hasOwnProperty(callback)) { + var descriptor = ObjectGetOwnPropertyDescriptor(prototype, callback); + if (descriptor && descriptor.value) { + descriptor.value = wrapWithCurrentZone(descriptor.value, source); + _redefineProperty(opts.prototype, callback, descriptor); + } + else { + prototype[callback] = wrapWithCurrentZone(prototype[callback], source); + } + } + else if (prototype[callback]) { + prototype[callback] = wrapWithCurrentZone(prototype[callback], source); + } + }); + } + return _registerElement.call(document, name, opts); + }; + attachOriginToPatched(document.registerElement, _registerElement); +} + +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +/** + * @fileoverview + * @suppress {missingRequire} + */ +Zone.__load_patch('util', function (global, Zone, api) { + api.patchOnProperties = patchOnProperties; + api.patchMethod = patchMethod; + api.bindArguments = bindArguments; +}); +Zone.__load_patch('timers', function (global) { + var set = 'set'; + var clear = 'clear'; + patchTimer(global, set, clear, 'Timeout'); + patchTimer(global, set, clear, 'Interval'); + patchTimer(global, set, clear, 'Immediate'); +}); +Zone.__load_patch('requestAnimationFrame', function (global) { + patchTimer(global, 'request', 'cancel', 'AnimationFrame'); + patchTimer(global, 'mozRequest', 'mozCancel', 'AnimationFrame'); + patchTimer(global, 'webkitRequest', 'webkitCancel', 'AnimationFrame'); +}); +Zone.__load_patch('blocking', function (global, Zone) { + var blockingMethods = ['alert', 'prompt', 'confirm']; + for (var i = 0; i < blockingMethods.length; i++) { + var name_1 = blockingMethods[i]; + patchMethod(global, name_1, function (delegate, symbol, name) { + return function (s, args) { + return Zone.current.run(delegate, global, args, name); + }; + }); + } +}); +Zone.__load_patch('EventTarget', function (global, Zone, api) { + // load blackListEvents from global + var SYMBOL_BLACK_LISTED_EVENTS = Zone.__symbol__('BLACK_LISTED_EVENTS'); + if (global[SYMBOL_BLACK_LISTED_EVENTS]) { + Zone[SYMBOL_BLACK_LISTED_EVENTS] = global[SYMBOL_BLACK_LISTED_EVENTS]; + } + patchEvent(global, api); + eventTargetPatch(global, api); + // patch XMLHttpRequestEventTarget's addEventListener/removeEventListener + var XMLHttpRequestEventTarget = global['XMLHttpRequestEventTarget']; + if (XMLHttpRequestEventTarget && XMLHttpRequestEventTarget.prototype) { + api.patchEventTarget(global, [XMLHttpRequestEventTarget.prototype]); + } + patchClass('MutationObserver'); + patchClass('WebKitMutationObserver'); + patchClass('IntersectionObserver'); + patchClass('FileReader'); +}); +Zone.__load_patch('on_property', function (global, Zone, api) { + propertyDescriptorPatch(api, global); + propertyPatch(); + registerElementPatch(global); +}); +Zone.__load_patch('canvas', function (global) { + var HTMLCanvasElement = global['HTMLCanvasElement']; + if (typeof HTMLCanvasElement !== 'undefined' && HTMLCanvasElement.prototype && + HTMLCanvasElement.prototype.toBlob) { + patchMacroTask(HTMLCanvasElement.prototype, 'toBlob', function (self, args) { + return { name: 'HTMLCanvasElement.toBlob', target: self, cbIdx: 0, args: args }; + }); + } +}); +Zone.__load_patch('XHR', function (global, Zone) { + // Treat XMLHttpRequest as a macrotask. + patchXHR(global); + var XHR_TASK = zoneSymbol('xhrTask'); + var XHR_SYNC = zoneSymbol('xhrSync'); + var XHR_LISTENER = zoneSymbol('xhrListener'); + var XHR_SCHEDULED = zoneSymbol('xhrScheduled'); + var XHR_URL = zoneSymbol('xhrURL'); + function patchXHR(window) { + var XMLHttpRequestPrototype = XMLHttpRequest.prototype; + function findPendingTask(target) { + return target[XHR_TASK]; + } + var oriAddListener = XMLHttpRequestPrototype[ZONE_SYMBOL_ADD_EVENT_LISTENER]; + var oriRemoveListener = XMLHttpRequestPrototype[ZONE_SYMBOL_REMOVE_EVENT_LISTENER]; + if (!oriAddListener) { + var XMLHttpRequestEventTarget = window['XMLHttpRequestEventTarget']; + if (XMLHttpRequestEventTarget) { + var XMLHttpRequestEventTargetPrototype = XMLHttpRequestEventTarget.prototype; + oriAddListener = XMLHttpRequestEventTargetPrototype[ZONE_SYMBOL_ADD_EVENT_LISTENER]; + oriRemoveListener = XMLHttpRequestEventTargetPrototype[ZONE_SYMBOL_REMOVE_EVENT_LISTENER]; + } + } + var READY_STATE_CHANGE = 'readystatechange'; + var SCHEDULED = 'scheduled'; + function scheduleTask(task) { + XMLHttpRequest[XHR_SCHEDULED] = false; + var data = task.data; + var target = data.target; + // remove existing event listener + var listener = target[XHR_LISTENER]; + if (!oriAddListener) { + oriAddListener = target[ZONE_SYMBOL_ADD_EVENT_LISTENER]; + oriRemoveListener = target[ZONE_SYMBOL_REMOVE_EVENT_LISTENER]; + } + if (listener) { + oriRemoveListener.call(target, READY_STATE_CHANGE, listener); + } + var newListener = target[XHR_LISTENER] = function () { + if (target.readyState === target.DONE) { + // sometimes on some browsers XMLHttpRequest will fire onreadystatechange with + // readyState=4 multiple times, so we need to check task state here + if (!data.aborted && XMLHttpRequest[XHR_SCHEDULED] && task.state === SCHEDULED) { + task.invoke(); + } + } + }; + oriAddListener.call(target, READY_STATE_CHANGE, newListener); + var storedTask = target[XHR_TASK]; + if (!storedTask) { + target[XHR_TASK] = task; + } + sendNative.apply(target, data.args); + XMLHttpRequest[XHR_SCHEDULED] = true; + return task; + } + function placeholderCallback() { } + function clearTask(task) { + var data = task.data; + // Note - ideally, we would call data.target.removeEventListener here, but it's too late + // to prevent it from firing. So instead, we store info for the event listener. + data.aborted = true; + return abortNative.apply(data.target, data.args); + } + var openNative = patchMethod(XMLHttpRequestPrototype, 'open', function () { return function (self, args) { + self[XHR_SYNC] = args[2] == false; + self[XHR_URL] = args[1]; + return openNative.apply(self, args); + }; }); + var XMLHTTPREQUEST_SOURCE = 'XMLHttpRequest.send'; + var sendNative = patchMethod(XMLHttpRequestPrototype, 'send', function () { return function (self, args) { + if (self[XHR_SYNC]) { + // if the XHR is sync there is no task to schedule, just execute the code. + return sendNative.apply(self, args); + } + else { + var options = { + target: self, + url: self[XHR_URL], + isPeriodic: false, + delay: null, + args: args, + aborted: false + }; + return scheduleMacroTaskWithCurrentZone(XMLHTTPREQUEST_SOURCE, placeholderCallback, options, scheduleTask, clearTask); + } + }; }); + var abortNative = patchMethod(XMLHttpRequestPrototype, 'abort', function () { return function (self) { + var task = findPendingTask(self); + if (task && typeof task.type == 'string') { + // If the XHR has already completed, do nothing. + // If the XHR has already been aborted, do nothing. + // Fix #569, call abort multiple times before done will cause + // macroTask task count be negative number + if (task.cancelFn == null || (task.data && task.data.aborted)) { + return; + } + task.zone.cancelTask(task); + } + // Otherwise, we are trying to abort an XHR which has not yet been sent, so there is no + // task + // to cancel. Do nothing. + }; }); + } +}); +Zone.__load_patch('geolocation', function (global) { + /// GEO_LOCATION + if (global['navigator'] && global['navigator'].geolocation) { + patchPrototype(global['navigator'].geolocation, ['getCurrentPosition', 'watchPosition']); + } +}); +Zone.__load_patch('PromiseRejectionEvent', function (global, Zone) { + // handle unhandled promise rejection + function findPromiseRejectionHandler(evtName) { + return function (e) { + var eventTasks = findEventTasks(global, evtName); + eventTasks.forEach(function (eventTask) { + // windows has added unhandledrejection event listener + // trigger the event listener + var PromiseRejectionEvent = global['PromiseRejectionEvent']; + if (PromiseRejectionEvent) { + var evt = new PromiseRejectionEvent(evtName, { promise: e.promise, reason: e.rejection }); + eventTask.invoke(evt); + } + }); + }; + } + if (global['PromiseRejectionEvent']) { + Zone[zoneSymbol('unhandledPromiseRejectionHandler')] = + findPromiseRejectionHandler('unhandledrejection'); + Zone[zoneSymbol('rejectionHandledHandler')] = + findPromiseRejectionHandler('rejectionhandled'); + } +}); + +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +}))); + + +/***/ }), + +/***/ "./src/polyfills.ts": +/*!**************************!*\ + !*** ./src/polyfills.ts ***! + \**************************/ +/*! no exports provided */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var zone_js_dist_zone__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! zone.js/dist/zone */ "./node_modules/zone.js/dist/zone.js"); +/* harmony import */ var zone_js_dist_zone__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(zone_js_dist_zone__WEBPACK_IMPORTED_MODULE_0__); +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ +/*************************************************************************************************** + * BROWSER POLYFILLS + */ +/** IE9, IE10 and IE11 requires all of the following polyfills. **/ +// import 'core-js/es6/symbol'; +// import 'core-js/es6/object'; +// import 'core-js/es6/function'; +// import 'core-js/es6/parse-int'; +// import 'core-js/es6/parse-float'; +// import 'core-js/es6/number'; +// import 'core-js/es6/math'; +// import 'core-js/es6/string'; +// import 'core-js/es6/date'; +// import 'core-js/es6/array'; +// import 'core-js/es6/regexp'; +// import 'core-js/es6/map'; +// import 'core-js/es6/weak-map'; +// import 'core-js/es6/set'; +/** + * If the application will be indexed by Google Search, the following is required. + * Googlebot uses a renderer based on Chrome 41. + * https://developers.google.com/search/docs/guides/rendering + **/ +// import 'core-js/es6/array'; +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. +/** IE10 and IE11 requires the following for the Reflect API. */ +// import 'core-js/es6/reflect'; +/** + * Web Animations `@angular/platform-browser/animations` + * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. + * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). + **/ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + */ +// (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame +// (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick +// (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames +/* +* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js +* with the following flag, it will bypass `zone.js` patch for IE/Edge +*/ +// (window as any).__Zone_enable_cross_context_check = true; +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ + // Included with Angular CLI. +/*************************************************************************************************** + * APPLICATION IMPORTS + */ + + +/***/ }), + +/***/ 1: +/*!***************************************************************************************************************************!*\ + !*** multi ./src/polyfills.ts ./node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/jit-polyfills.js ***! + \***************************************************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +__webpack_require__(/*! D:\zano\src\polyfills.ts */"./src/polyfills.ts"); +module.exports = __webpack_require__(/*! D:\zano\node_modules\@angular-devkit\build-angular\src\angular-cli-files\models\jit-polyfills.js */"./node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/jit-polyfills.js"); + + +/***/ }) + +},[[1,"runtime"]]]); +//# sourceMappingURL=polyfills.js.map \ No newline at end of file diff --git a/src/gui/qt-daemon/html/polyfills.js.map b/src/gui/qt-daemon/html/polyfills.js.map new file mode 100644 index 00000000..bb082f5f --- /dev/null +++ b/src/gui/qt-daemon/html/polyfills.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack:///./node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/jit-polyfills.js","webpack:///./node_modules/core-js/es7/reflect.js","webpack:///./node_modules/core-js/modules/_a-function.js","webpack:///./node_modules/core-js/modules/_an-instance.js","webpack:///./node_modules/core-js/modules/_an-object.js","webpack:///./node_modules/core-js/modules/_array-from-iterable.js","webpack:///./node_modules/core-js/modules/_array-includes.js","webpack:///./node_modules/core-js/modules/_array-methods.js","webpack:///./node_modules/core-js/modules/_array-species-constructor.js","webpack:///./node_modules/core-js/modules/_array-species-create.js","webpack:///./node_modules/core-js/modules/_classof.js","webpack:///./node_modules/core-js/modules/_cof.js","webpack:///./node_modules/core-js/modules/_collection-strong.js","webpack:///./node_modules/core-js/modules/_collection-weak.js","webpack:///./node_modules/core-js/modules/_collection.js","webpack:///./node_modules/core-js/modules/_core.js","webpack:///./node_modules/core-js/modules/_ctx.js","webpack:///./node_modules/core-js/modules/_defined.js","webpack:///./node_modules/core-js/modules/_descriptors.js","webpack:///./node_modules/core-js/modules/_dom-create.js","webpack:///./node_modules/core-js/modules/_enum-bug-keys.js","webpack:///./node_modules/core-js/modules/_export.js","webpack:///./node_modules/core-js/modules/_fails.js","webpack:///./node_modules/core-js/modules/_for-of.js","webpack:///./node_modules/core-js/modules/_global.js","webpack:///./node_modules/core-js/modules/_has.js","webpack:///./node_modules/core-js/modules/_hide.js","webpack:///./node_modules/core-js/modules/_html.js","webpack:///./node_modules/core-js/modules/_ie8-dom-define.js","webpack:///./node_modules/core-js/modules/_inherit-if-required.js","webpack:///./node_modules/core-js/modules/_iobject.js","webpack:///./node_modules/core-js/modules/_is-array-iter.js","webpack:///./node_modules/core-js/modules/_is-array.js","webpack:///./node_modules/core-js/modules/_is-object.js","webpack:///./node_modules/core-js/modules/_iter-call.js","webpack:///./node_modules/core-js/modules/_iter-create.js","webpack:///./node_modules/core-js/modules/_iter-define.js","webpack:///./node_modules/core-js/modules/_iter-detect.js","webpack:///./node_modules/core-js/modules/_iter-step.js","webpack:///./node_modules/core-js/modules/_iterators.js","webpack:///./node_modules/core-js/modules/_library.js","webpack:///./node_modules/core-js/modules/_meta.js","webpack:///./node_modules/core-js/modules/_metadata.js","webpack:///./node_modules/core-js/modules/_object-assign.js","webpack:///./node_modules/core-js/modules/_object-create.js","webpack:///./node_modules/core-js/modules/_object-dp.js","webpack:///./node_modules/core-js/modules/_object-dps.js","webpack:///./node_modules/core-js/modules/_object-gopd.js","webpack:///./node_modules/core-js/modules/_object-gops.js","webpack:///./node_modules/core-js/modules/_object-gpo.js","webpack:///./node_modules/core-js/modules/_object-keys-internal.js","webpack:///./node_modules/core-js/modules/_object-keys.js","webpack:///./node_modules/core-js/modules/_object-pie.js","webpack:///./node_modules/core-js/modules/_property-desc.js","webpack:///./node_modules/core-js/modules/_redefine-all.js","webpack:///./node_modules/core-js/modules/_redefine.js","webpack:///./node_modules/core-js/modules/_set-proto.js","webpack:///./node_modules/core-js/modules/_set-species.js","webpack:///./node_modules/core-js/modules/_set-to-string-tag.js","webpack:///./node_modules/core-js/modules/_shared-key.js","webpack:///./node_modules/core-js/modules/_shared.js","webpack:///./node_modules/core-js/modules/_to-absolute-index.js","webpack:///./node_modules/core-js/modules/_to-integer.js","webpack:///./node_modules/core-js/modules/_to-iobject.js","webpack:///./node_modules/core-js/modules/_to-length.js","webpack:///./node_modules/core-js/modules/_to-object.js","webpack:///./node_modules/core-js/modules/_to-primitive.js","webpack:///./node_modules/core-js/modules/_uid.js","webpack:///./node_modules/core-js/modules/_validate-collection.js","webpack:///./node_modules/core-js/modules/_wks.js","webpack:///./node_modules/core-js/modules/core.get-iterator-method.js","webpack:///./node_modules/core-js/modules/es6.map.js","webpack:///./node_modules/core-js/modules/es6.set.js","webpack:///./node_modules/core-js/modules/es6.weak-map.js","webpack:///./node_modules/core-js/modules/es7.reflect.define-metadata.js","webpack:///./node_modules/core-js/modules/es7.reflect.delete-metadata.js","webpack:///./node_modules/core-js/modules/es7.reflect.get-metadata-keys.js","webpack:///./node_modules/core-js/modules/es7.reflect.get-metadata.js","webpack:///./node_modules/core-js/modules/es7.reflect.get-own-metadata-keys.js","webpack:///./node_modules/core-js/modules/es7.reflect.get-own-metadata.js","webpack:///./node_modules/core-js/modules/es7.reflect.has-metadata.js","webpack:///./node_modules/core-js/modules/es7.reflect.has-own-metadata.js","webpack:///./node_modules/core-js/modules/es7.reflect.metadata.js","webpack:///./node_modules/zone.js/dist/zone.js","webpack:///./src/polyfills.ts"],"names":[],"mappings":";;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAC6B;;;;;;;;;;;;ACP7B,mBAAO,CAAC,6GAAwC;AAChD,mBAAO,CAAC,6GAAwC;AAChD,mBAAO,CAAC,uGAAqC;AAC7C,mBAAO,CAAC,iHAA0C;AAClD,mBAAO,CAAC,+GAAyC;AACjD,mBAAO,CAAC,yHAA8C;AACtD,mBAAO,CAAC,uGAAqC;AAC7C,mBAAO,CAAC,+GAAyC;AACjD,mBAAO,CAAC,+FAAiC;AACzC,iBAAiB,mBAAO,CAAC,iEAAkB;;;;;;;;;;;;ACT3C;AACA;AACA;AACA;;;;;;;;;;;;ACHA;AACA;AACA;AACA,GAAG;AACH;;;;;;;;;;;;ACJA,eAAe,mBAAO,CAAC,kEAAc;AACrC;AACA;AACA;AACA;;;;;;;;;;;;ACJA,YAAY,mBAAO,CAAC,4DAAW;;AAE/B;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACNA;AACA;AACA,gBAAgB,mBAAO,CAAC,oEAAe;AACvC,eAAe,mBAAO,CAAC,kEAAc;AACrC,sBAAsB,mBAAO,CAAC,kFAAsB;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK,YAAY,eAAe;AAChC;AACA,KAAK;AACL;AACA;;;;;;;;;;;;ACtBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU,mBAAO,CAAC,sDAAQ;AAC1B,cAAc,mBAAO,CAAC,8DAAY;AAClC,eAAe,mBAAO,CAAC,kEAAc;AACrC,eAAe,mBAAO,CAAC,kEAAc;AACrC,UAAU,mBAAO,CAAC,wFAAyB;AAC3C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU,eAAe;AACzB;AACA;AACA;AACA,wCAAwC;AACxC;AACA,8BAA8B;AAC9B,6BAA6B;AAC7B,+BAA+B;AAC/B,mCAAmC;AACnC,SAAS,iCAAiC;AAC1C;AACA;AACA;AACA;AACA;;;;;;;;;;;;AC3CA,eAAe,mBAAO,CAAC,kEAAc;AACrC,cAAc,mBAAO,CAAC,gEAAa;AACnC,cAAc,mBAAO,CAAC,sDAAQ;;AAE9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;;;;;;;;;;;ACfA;AACA,yBAAyB,mBAAO,CAAC,kGAA8B;;AAE/D;AACA;AACA;;;;;;;;;;;;ACLA;AACA,UAAU,mBAAO,CAAC,sDAAQ;AAC1B,UAAU,mBAAO,CAAC,sDAAQ;AAC1B;AACA,2BAA2B,kBAAkB,EAAE;;AAE/C;AACA;AACA;AACA;AACA,GAAG,YAAY;AACf;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACtBA,iBAAiB;;AAEjB;AACA;AACA;;;;;;;;;;;;;ACJa;AACb,SAAS,mBAAO,CAAC,kEAAc;AAC/B,aAAa,mBAAO,CAAC,0EAAkB;AACvC,kBAAkB,mBAAO,CAAC,wEAAiB;AAC3C,UAAU,mBAAO,CAAC,sDAAQ;AAC1B,iBAAiB,mBAAO,CAAC,sEAAgB;AACzC,YAAY,mBAAO,CAAC,4DAAW;AAC/B,kBAAkB,mBAAO,CAAC,sEAAgB;AAC1C,WAAW,mBAAO,CAAC,kEAAc;AACjC,iBAAiB,mBAAO,CAAC,sEAAgB;AACzC,kBAAkB,mBAAO,CAAC,sEAAgB;AAC1C,cAAc,mBAAO,CAAC,wDAAS;AAC/B,eAAe,mBAAO,CAAC,sFAAwB;AAC/C;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB,OAAO;AAC9B;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,qBAAqB;AACrB,6BAA6B;AAC7B,0BAA0B;AAC1B,0BAA0B;AAC1B,qBAAqB;AACrB;AACA,KAAK;AACL;AACA;AACA;AACA;AACA,8EAA8E,OAAO;AACrF;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA,KAAK;AACL;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL,GAAG;AACH;AACA;AACA;AACA;AACA;AACA,yCAAyC;AACzC,qBAAqB;AACrB,0BAA0B;AAC1B,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;;;;;;;;;;;;;AC/Ia;AACb,kBAAkB,mBAAO,CAAC,wEAAiB;AAC3C,cAAc,mBAAO,CAAC,wDAAS;AAC/B,eAAe,mBAAO,CAAC,kEAAc;AACrC,eAAe,mBAAO,CAAC,kEAAc;AACrC,iBAAiB,mBAAO,CAAC,sEAAgB;AACzC,YAAY,mBAAO,CAAC,4DAAW;AAC/B,wBAAwB,mBAAO,CAAC,0EAAkB;AAClD,WAAW,mBAAO,CAAC,sDAAQ;AAC3B,eAAe,mBAAO,CAAC,sFAAwB;AAC/C;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,qBAAqB;AACrB,qBAAqB;AACrB,0BAA0B;AAC1B;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;;;;;;;;;;;;;ACpFa;AACb,aAAa,mBAAO,CAAC,4DAAW;AAChC,cAAc,mBAAO,CAAC,4DAAW;AACjC,eAAe,mBAAO,CAAC,gEAAa;AACpC,kBAAkB,mBAAO,CAAC,wEAAiB;AAC3C,WAAW,mBAAO,CAAC,wDAAS;AAC5B,YAAY,mBAAO,CAAC,4DAAW;AAC/B,iBAAiB,mBAAO,CAAC,sEAAgB;AACzC,eAAe,mBAAO,CAAC,kEAAc;AACrC,YAAY,mBAAO,CAAC,0DAAU;AAC9B,kBAAkB,mBAAO,CAAC,sEAAgB;AAC1C,qBAAqB,mBAAO,CAAC,kFAAsB;AACnD,wBAAwB,mBAAO,CAAC,sFAAwB;;AAExD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA,OAAO;AACP;AACA,OAAO,mCAAmC,gCAAgC,aAAa;AACvF,8BAA8B,mCAAmC,aAAa;AAC9E;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA,qDAAqD;AACrD;AACA,kDAAkD,iBAAiB,EAAE;AACrE;AACA,wDAAwD,aAAa,EAAE,EAAE;AACzE;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;;;;;;;;;;;ACpFA,6BAA6B;AAC7B,uCAAuC;;;;;;;;;;;;ACDvC;AACA,gBAAgB,mBAAO,CAAC,oEAAe;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACnBA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACJA;AACA,kBAAkB,mBAAO,CAAC,0DAAU;AACpC,iCAAiC,QAAQ,mBAAmB,UAAU,EAAE,EAAE;AAC1E,CAAC;;;;;;;;;;;;ACHD,eAAe,mBAAO,CAAC,kEAAc;AACrC,eAAe,mBAAO,CAAC,4DAAW;AAClC;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACNA;AACA;AACA;AACA;;;;;;;;;;;;ACHA,aAAa,mBAAO,CAAC,4DAAW;AAChC,WAAW,mBAAO,CAAC,wDAAS;AAC5B,WAAW,mBAAO,CAAC,wDAAS;AAC5B,eAAe,mBAAO,CAAC,gEAAa;AACpC,UAAU,mBAAO,CAAC,sDAAQ;AAC1B;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,kFAAkF,uBAAuB;AACzG,iEAAiE;AACjE,+DAA+D;AAC/D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,eAAe;AACf,eAAe;AACf,eAAe;AACf,gBAAgB;AAChB;;;;;;;;;;;;AC1CA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;;;;;;;;;;;;ACNA,UAAU,mBAAO,CAAC,sDAAQ;AAC1B,WAAW,mBAAO,CAAC,kEAAc;AACjC,kBAAkB,mBAAO,CAAC,0EAAkB;AAC5C,eAAe,mBAAO,CAAC,kEAAc;AACrC,eAAe,mBAAO,CAAC,kEAAc;AACrC,gBAAgB,mBAAO,CAAC,8FAA4B;AACpD;AACA;AACA;AACA,uCAAuC,iBAAiB,EAAE;AAC1D;AACA;AACA;AACA;AACA;AACA,mEAAmE,gBAAgB;AACnF;AACA;AACA,GAAG,4CAA4C,gCAAgC;AAC/E;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACxBA;AACA;AACA;AACA;AACA;AACA,yCAAyC;;;;;;;;;;;;ACLzC,uBAAuB;AACvB;AACA;AACA;;;;;;;;;;;;ACHA,SAAS,mBAAO,CAAC,kEAAc;AAC/B,iBAAiB,mBAAO,CAAC,0EAAkB;AAC3C,iBAAiB,mBAAO,CAAC,sEAAgB;AACzC;AACA,CAAC;AACD;AACA;AACA;;;;;;;;;;;;ACPA,eAAe,mBAAO,CAAC,4DAAW;AAClC;;;;;;;;;;;;ACDA,kBAAkB,mBAAO,CAAC,sEAAgB,MAAM,mBAAO,CAAC,0DAAU;AAClE,+BAA+B,mBAAO,CAAC,oEAAe,gBAAgB,mBAAmB,UAAU,EAAE,EAAE;AACvG,CAAC;;;;;;;;;;;;ACFD,eAAe,mBAAO,CAAC,kEAAc;AACrC,qBAAqB,mBAAO,CAAC,kEAAc;AAC3C;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;;;;;;;;;;;ACRA;AACA,UAAU,mBAAO,CAAC,sDAAQ;AAC1B;AACA;AACA;AACA;;;;;;;;;;;;ACLA;AACA,gBAAgB,mBAAO,CAAC,kEAAc;AACtC,eAAe,mBAAO,CAAC,sDAAQ;AAC/B;;AAEA;AACA;AACA;;;;;;;;;;;;ACPA;AACA,UAAU,mBAAO,CAAC,sDAAQ;AAC1B;AACA;AACA;;;;;;;;;;;;ACJA;AACA;AACA;;;;;;;;;;;;ACFA;AACA,eAAe,mBAAO,CAAC,kEAAc;AACrC;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;;;;;;;;;;;;;ACXa;AACb,aAAa,mBAAO,CAAC,0EAAkB;AACvC,iBAAiB,mBAAO,CAAC,0EAAkB;AAC3C,qBAAqB,mBAAO,CAAC,kFAAsB;AACnD;;AAEA;AACA,mBAAO,CAAC,wDAAS,qBAAqB,mBAAO,CAAC,sDAAQ,4BAA4B,aAAa,EAAE;;AAEjG;AACA,qDAAqD,4BAA4B;AACjF;AACA;;;;;;;;;;;;;ACZa;AACb,cAAc,mBAAO,CAAC,8DAAY;AAClC,cAAc,mBAAO,CAAC,4DAAW;AACjC,eAAe,mBAAO,CAAC,gEAAa;AACpC,WAAW,mBAAO,CAAC,wDAAS;AAC5B,gBAAgB,mBAAO,CAAC,kEAAc;AACtC,kBAAkB,mBAAO,CAAC,sEAAgB;AAC1C,qBAAqB,mBAAO,CAAC,kFAAsB;AACnD,qBAAqB,mBAAO,CAAC,oEAAe;AAC5C,eAAe,mBAAO,CAAC,sDAAQ;AAC/B,8CAA8C;AAC9C;AACA;AACA;;AAEA,8BAA8B,aAAa;;AAE3C;AACA;AACA;AACA;AACA;AACA,yCAAyC,oCAAoC;AAC7E,6CAA6C,oCAAoC;AACjF,KAAK,4BAA4B,oCAAoC;AACrE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB,mBAAmB;AACnC;AACA;AACA,kCAAkC,2BAA2B;AAC7D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;;;;;;;;;;;;ACpEA,eAAe,mBAAO,CAAC,sDAAQ;AAC/B;;AAEA;AACA;AACA,iCAAiC,qBAAqB;AACtD;AACA,iCAAiC,SAAS,EAAE;AAC5C,CAAC,YAAY;;AAEb;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B,SAAS,qBAAqB;AAC3D,iCAAiC,aAAa;AAC9C;AACA,GAAG,YAAY;AACf;AACA;;;;;;;;;;;;ACrBA;AACA,UAAU;AACV;;;;;;;;;;;;ACFA;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA,WAAW,mBAAO,CAAC,sDAAQ;AAC3B,eAAe,mBAAO,CAAC,kEAAc;AACrC,UAAU,mBAAO,CAAC,sDAAQ;AAC1B,cAAc,mBAAO,CAAC,kEAAc;AACpC;AACA;AACA;AACA;AACA,cAAc,mBAAO,CAAC,0DAAU;AAChC,iDAAiD;AACjD,CAAC;AACD;AACA,qBAAqB;AACrB;AACA,SAAS;AACT,GAAG,EAAE;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACpDA,UAAU,mBAAO,CAAC,4DAAW;AAC7B,cAAc,mBAAO,CAAC,4DAAW;AACjC,aAAa,mBAAO,CAAC,4DAAW;AAChC,iDAAiD,mBAAO,CAAC,sEAAgB;;AAEzE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0DAA0D,gBAAgB,EAAE;AAC5E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;AClDa;AACb;AACA,cAAc,mBAAO,CAAC,sEAAgB;AACtC,WAAW,mBAAO,CAAC,sEAAgB;AACnC,UAAU,mBAAO,CAAC,oEAAe;AACjC,eAAe,mBAAO,CAAC,kEAAc;AACrC,cAAc,mBAAO,CAAC,8DAAY;AAClC;;AAEA;AACA,6BAA6B,mBAAO,CAAC,0DAAU;AAC/C;AACA;AACA;AACA;AACA;AACA;AACA,oCAAoC,UAAU,EAAE;AAChD,mBAAmB,sCAAsC;AACzD,CAAC,qCAAqC;AACtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH,CAAC;;;;;;;;;;;;ACjCD;AACA,eAAe,mBAAO,CAAC,kEAAc;AACrC,UAAU,mBAAO,CAAC,oEAAe;AACjC,kBAAkB,mBAAO,CAAC,0EAAkB;AAC5C,eAAe,mBAAO,CAAC,oEAAe;AACtC,yBAAyB;AACzB;;AAEA;AACA;AACA;AACA,eAAe,mBAAO,CAAC,oEAAe;AACtC;AACA;AACA;AACA;AACA;AACA,EAAE,mBAAO,CAAC,wDAAS;AACnB,6BAA6B;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;;;;;;;;;;;;ACxCA,eAAe,mBAAO,CAAC,kEAAc;AACrC,qBAAqB,mBAAO,CAAC,4EAAmB;AAChD,kBAAkB,mBAAO,CAAC,wEAAiB;AAC3C;;AAEA,YAAY,mBAAO,CAAC,sEAAgB;AACpC;AACA;AACA;AACA;AACA;AACA,GAAG,YAAY;AACf;AACA;AACA;AACA;;;;;;;;;;;;ACfA,SAAS,mBAAO,CAAC,kEAAc;AAC/B,eAAe,mBAAO,CAAC,kEAAc;AACrC,cAAc,mBAAO,CAAC,sEAAgB;;AAEtC,iBAAiB,mBAAO,CAAC,sEAAgB;AACzC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACZA,UAAU,mBAAO,CAAC,oEAAe;AACjC,iBAAiB,mBAAO,CAAC,0EAAkB;AAC3C,gBAAgB,mBAAO,CAAC,oEAAe;AACvC,kBAAkB,mBAAO,CAAC,wEAAiB;AAC3C,UAAU,mBAAO,CAAC,sDAAQ;AAC1B,qBAAqB,mBAAO,CAAC,4EAAmB;AAChD;;AAEA,YAAY,mBAAO,CAAC,sEAAgB;AACpC;AACA;AACA;AACA;AACA,GAAG,YAAY;AACf;AACA;;;;;;;;;;;;ACfA;;;;;;;;;;;;ACAA;AACA,UAAU,mBAAO,CAAC,sDAAQ;AAC1B,eAAe,mBAAO,CAAC,kEAAc;AACrC,eAAe,mBAAO,CAAC,oEAAe;AACtC;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;;;;;;;;;;;ACZA,UAAU,mBAAO,CAAC,sDAAQ;AAC1B,gBAAgB,mBAAO,CAAC,oEAAe;AACvC,mBAAmB,mBAAO,CAAC,4EAAmB;AAC9C,eAAe,mBAAO,CAAC,oEAAe;;AAEtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;AChBA;AACA,YAAY,mBAAO,CAAC,wFAAyB;AAC7C,kBAAkB,mBAAO,CAAC,0EAAkB;;AAE5C;AACA;AACA;;;;;;;;;;;;ACNA,cAAc;;;;;;;;;;;;ACAd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACPA,eAAe,mBAAO,CAAC,gEAAa;AACpC;AACA;AACA;AACA;;;;;;;;;;;;ACJA,aAAa,mBAAO,CAAC,4DAAW;AAChC,WAAW,mBAAO,CAAC,wDAAS;AAC5B,UAAU,mBAAO,CAAC,sDAAQ;AAC1B,UAAU,mBAAO,CAAC,sDAAQ;AAC1B;AACA;AACA;;AAEA,mBAAO,CAAC,wDAAS;AACjB;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA,GAAG;AACH;AACA,GAAG;AACH;AACA;AACA;AACA,CAAC;AACD;AACA,CAAC;;;;;;;;;;;;AC9BD;AACA;AACA,eAAe,mBAAO,CAAC,kEAAc;AACrC,eAAe,mBAAO,CAAC,kEAAc;AACrC;AACA;AACA;AACA;AACA;AACA,kDAAkD;AAClD;AACA;AACA,cAAc,mBAAO,CAAC,sDAAQ,iBAAiB,mBAAO,CAAC,sEAAgB;AACvE;AACA;AACA,OAAO,YAAY,cAAc;AACjC;AACA;AACA;AACA;AACA;AACA;AACA,KAAK,GAAG;AACR;AACA;;;;;;;;;;;;;ACxBa;AACb,aAAa,mBAAO,CAAC,4DAAW;AAChC,SAAS,mBAAO,CAAC,kEAAc;AAC/B,kBAAkB,mBAAO,CAAC,sEAAgB;AAC1C,cAAc,mBAAO,CAAC,sDAAQ;;AAE9B;AACA;AACA;AACA;AACA,sBAAsB,aAAa;AACnC,GAAG;AACH;;;;;;;;;;;;ACZA,UAAU,mBAAO,CAAC,kEAAc;AAChC,UAAU,mBAAO,CAAC,sDAAQ;AAC1B,UAAU,mBAAO,CAAC,sDAAQ;;AAE1B;AACA,oEAAoE,iCAAiC;AACrG;;;;;;;;;;;;ACNA,aAAa,mBAAO,CAAC,4DAAW;AAChC,UAAU,mBAAO,CAAC,sDAAQ;AAC1B;AACA;AACA;;;;;;;;;;;;ACJA,WAAW,mBAAO,CAAC,wDAAS;AAC5B,aAAa,mBAAO,CAAC,4DAAW;AAChC;AACA,kDAAkD;;AAElD;AACA,qEAAqE;AACrE,CAAC;AACD;AACA,QAAQ,mBAAO,CAAC,8DAAY;AAC5B;AACA,CAAC;;;;;;;;;;;;ACXD,gBAAgB,mBAAO,CAAC,oEAAe;AACvC;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACNA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACLA;AACA,cAAc,mBAAO,CAAC,8DAAY;AAClC,cAAc,mBAAO,CAAC,8DAAY;AAClC;AACA;AACA;;;;;;;;;;;;ACLA;AACA,gBAAgB,mBAAO,CAAC,oEAAe;AACvC;AACA;AACA,2DAA2D;AAC3D;;;;;;;;;;;;ACLA;AACA,cAAc,mBAAO,CAAC,8DAAY;AAClC;AACA;AACA;;;;;;;;;;;;ACJA;AACA,eAAe,mBAAO,CAAC,kEAAc;AACrC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACXA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACJA,eAAe,mBAAO,CAAC,kEAAc;AACrC;AACA;AACA;AACA;;;;;;;;;;;;ACJA,YAAY,mBAAO,CAAC,4DAAW;AAC/B,UAAU,mBAAO,CAAC,sDAAQ;AAC1B,aAAa,mBAAO,CAAC,4DAAW;AAChC;;AAEA;AACA;AACA;AACA;;AAEA;;;;;;;;;;;;ACVA,cAAc,mBAAO,CAAC,8DAAY;AAClC,eAAe,mBAAO,CAAC,sDAAQ;AAC/B,gBAAgB,mBAAO,CAAC,kEAAc;AACtC,iBAAiB,mBAAO,CAAC,wDAAS;AAClC;AACA;AACA;AACA;;;;;;;;;;;;;ACPa;AACb,aAAa,mBAAO,CAAC,kFAAsB;AAC3C,eAAe,mBAAO,CAAC,sFAAwB;AAC/C;;AAEA;AACA,iBAAiB,mBAAO,CAAC,oEAAe;AACxC,yBAAyB,mEAAmE;AAC5F,CAAC;AACD;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA,CAAC;;;;;;;;;;;;;AClBY;AACb,aAAa,mBAAO,CAAC,kFAAsB;AAC3C,eAAe,mBAAO,CAAC,sFAAwB;AAC/C;;AAEA;AACA,iBAAiB,mBAAO,CAAC,oEAAe;AACxC,yBAAyB,mEAAmE;AAC5F,CAAC;AACD;AACA;AACA;AACA;AACA,CAAC;;;;;;;;;;;;;ACbY;AACb,WAAW,mBAAO,CAAC,0EAAkB;AACrC,eAAe,mBAAO,CAAC,gEAAa;AACpC,WAAW,mBAAO,CAAC,wDAAS;AAC5B,aAAa,mBAAO,CAAC,0EAAkB;AACvC,WAAW,mBAAO,CAAC,8EAAoB;AACvC,eAAe,mBAAO,CAAC,kEAAc;AACrC,YAAY,mBAAO,CAAC,0DAAU;AAC9B,eAAe,mBAAO,CAAC,sFAAwB;AAC/C;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;;AAEA;AACA,gCAAgC,mBAAO,CAAC,oEAAe;;AAEvD;AACA,uBAAuB,4EAA4E,EAAE;AACrG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;AACL,GAAG;AACH;;;;;;;;;;;;AC1DA,eAAe,mBAAO,CAAC,gEAAa;AACpC,eAAe,mBAAO,CAAC,kEAAc;AACrC;AACA;;AAEA,cAAc;AACd;AACA,CAAC,EAAE;;;;;;;;;;;;ACPH,eAAe,mBAAO,CAAC,gEAAa;AACpC,eAAe,mBAAO,CAAC,kEAAc;AACrC;AACA;AACA;;AAEA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,EAAE;;;;;;;;;;;;ACdH,UAAU,mBAAO,CAAC,4DAAW;AAC7B,WAAW,mBAAO,CAAC,sFAAwB;AAC3C,eAAe,mBAAO,CAAC,gEAAa;AACpC,eAAe,mBAAO,CAAC,kEAAc;AACrC,qBAAqB,mBAAO,CAAC,oEAAe;AAC5C;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,cAAc;AACd;AACA,CAAC,EAAE;;;;;;;;;;;;AClBH,eAAe,mBAAO,CAAC,gEAAa;AACpC,eAAe,mBAAO,CAAC,kEAAc;AACrC,qBAAqB,mBAAO,CAAC,oEAAe;AAC5C;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,cAAc;AACd;AACA,CAAC,EAAE;;;;;;;;;;;;AChBH,eAAe,mBAAO,CAAC,gEAAa;AACpC,eAAe,mBAAO,CAAC,kEAAc;AACrC;AACA;;AAEA,cAAc;AACd;AACA,CAAC,EAAE;;;;;;;;;;;;ACPH,eAAe,mBAAO,CAAC,gEAAa;AACpC,eAAe,mBAAO,CAAC,kEAAc;AACrC;AACA;;AAEA,cAAc;AACd;AACA;AACA,CAAC,EAAE;;;;;;;;;;;;ACRH,eAAe,mBAAO,CAAC,gEAAa;AACpC,eAAe,mBAAO,CAAC,kEAAc;AACrC,qBAAqB,mBAAO,CAAC,oEAAe;AAC5C;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,cAAc;AACd;AACA,CAAC,EAAE;;;;;;;;;;;;ACfH,eAAe,mBAAO,CAAC,gEAAa;AACpC,eAAe,mBAAO,CAAC,kEAAc;AACrC;AACA;;AAEA,cAAc;AACd;AACA;AACA,CAAC,EAAE;;;;;;;;;;;;ACRH,gBAAgB,mBAAO,CAAC,gEAAa;AACrC,eAAe,mBAAO,CAAC,kEAAc;AACrC,gBAAgB,mBAAO,CAAC,oEAAe;AACvC;AACA;;AAEA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,EAAE;;;;;;;;;;;;ACdH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,KAA4D;AAC7D,CAAC,SACW;AACZ,CAAC,qBAAqB;;AAEtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA,SAAS;AACT;AACA;AACA;AACA,aAAa;AACb;AACA;AACA,SAAS;AACT;AACA;AACA;AACA,aAAa;AACb;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA,SAAS;AACT;AACA;AACA;AACA,aAAa;AACb;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,uBAAuB;AAC9D,uCAAuC,kBAAkB;AACzD,oCAAoC,eAAe;AACnD,iCAAiC;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,kBAAkB;AACzD,uCAAuC,kBAAkB;AACzD,oCAAoC,eAAe;AACnD,iCAAiC;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oDAAoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAiC;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oDAAoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B,0BAA0B;AACrD;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,SAAS;AACT,kFAAkF,gEAAgE,EAAE;AACpJ;AACA;AACA;AACA;AACA;AACA;AACA,gCAAgC;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA,SAAS;AACT;AACA;AACA;AACA,aAAa;AACb;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,kBAAkB;AACjD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAmB;AACnB;AACA;AACA;AACA;AACA;AACA,uCAAuC,0BAA0B,EAAE;AACnE;AACA;AACA;AACA,wCAAwC,6DAA6D,EAAE;AACvG,uCAAuC,WAAW,EAAE;AACpD;AACA,kCAAkC,aAAa,EAAE;AACjD,oCAAoC,aAAa,EAAE;AACnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,6BAA6B;AAC7B;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4HAA4H,wBAAwB,oCAAoC;AACxL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gFAAgF,sEAAsE;AACtJ;AACA;AACA,+BAA+B,kBAAkB;AACjD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gDAAgD;AAChD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC,oDAAoD;AAC5F;AACA;AACA;AACA;AACA;AACA,2BAA2B,mCAAmC;AAC9D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,qEAAqE,gBAAgB;AACrF;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sCAAsC;AACtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA,+CAA+C,sBAAsB;AACrE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA,+CAA+C,sBAAsB;AACrE;AACA;AACA;AACA;AACA,8CAA8C;AAC9C;AACA;AACA;AACA;AACA;AACA,kBAAkB,EAAE;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAiC,QAAQ;AACzC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA,mBAAmB,oBAAoB;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+CAA+C;AAC/C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB,uBAAuB;AAC9C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB,yBAAyB;AAChD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kDAAkD,EAAE;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA,iBAAiB;AACjB;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gEAAgE;AAChE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,EAAE;AACR;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8CAA8C,oCAAoC;AAClF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,sBAAsB;AACrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,sBAAsB;AACrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,0BAA0B;AAC7D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0CAA0C,sBAAsB;AAChE,qCAAqC,iBAAiB;AACtD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,8BAA8B;AACjE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,0BAA0B;AACjE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,0BAA0B;AACzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B,kBAAkB;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,iBAAiB;AAChD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,wBAAwB;AAC/D;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,wBAAwB;AAC/D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAmB,iBAAiB;AACpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,kBAAkB;AACjD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0FAA0F;AAC1F;AACA;AACA;AACA;AACA;AACA,UAAU,EAAE;AACZ;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0DAA0D;AAC1D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU,EAAE;AACZ;AACA,6DAA6D;AAC7D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU,EAAE;AACZ;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sDAAsD,0BAA0B,EAAE;AAClF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qDAAqD,6BAA6B,EAAE;AACpF;AACA;AACA;AACA;AACA,8CAA8C,kDAAkD,EAAE;AAClG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA,0FAA0F;AAC1F;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA,SAAS;AACT;AACA,sCAAsC;AACtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,mBAAmB,uBAAuB;AAC1C;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qDAAqD,+BAA+B,EAAE;AACtF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qEAAqE,gBAAgB;AACrF;AACA,mBAAmB,uBAAuB;AAC1C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAmB,0BAA0B;AAC7C;AACA;AACA,uBAAuB,uBAAuB;AAC9C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAmB,iBAAiB;AACpC;AACA;AACA;AACA;AACA;AACA,yCAAyC,6BAA6B;AACtE;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD;AACA;AACA;AACA;AACA,CAAC;AACD;AACA;AACA,mBAAmB,4BAA4B;AAC/C;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD;AACA;AACA;AACA;AACA,CAAC;AACD;AACA;AACA;AACA;AACA;AACA,oBAAoB;AACpB,SAAS;AACT;AACA,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC;AACxC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mFAAmF;AACnF;AACA;AACA;AACA,UAAU,EAAE;AACZ;AACA,mFAAmF;AACnF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU,EAAE;AACZ,qFAAqF;AACrF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU,EAAE;AACZ;AACA,CAAC;AACD;AACA;AACA;AACA;AACA;AACA,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kEAAkE,0CAA0C;AAC5G;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,CAAC;;;;;;;;;;;;;ACn/FD;AAAA;AAAA;AAAA;;;;;;;;;;;;;;GAcG;AAEH;;GAEG;AAEH,mEAAmE;AACnE,+BAA+B;AAC/B,+BAA+B;AAC/B,iCAAiC;AACjC,kCAAkC;AAClC,oCAAoC;AACpC,+BAA+B;AAC/B,6BAA6B;AAC7B,+BAA+B;AAC/B,6BAA6B;AAC7B,8BAA8B;AAC9B,+BAA+B;AAC/B,4BAA4B;AAC5B,iCAAiC;AACjC,4BAA4B;AAE5B;;;;IAII;AACJ,8BAA8B;AAE9B,+EAA+E;AAC/E,oEAAoE;AAEpE,gEAAgE;AAChE,gCAAgC;AAEhC;;;;IAII;AACJ,8EAA8E;AAE9E;;;GAGG;AAEF,sGAAsG;AACtG,iGAAiG;AACjG,sHAAsH;AAEtH;;;EAGE;AACH,4DAA4D;AAE5D;;GAEG;AACwB,CAAE,6BAA6B;AAG1D;;GAEG","file":"polyfills.js","sourcesContent":["/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\nimport 'core-js/es7/reflect';\n","require('../modules/es7.reflect.define-metadata');\nrequire('../modules/es7.reflect.delete-metadata');\nrequire('../modules/es7.reflect.get-metadata');\nrequire('../modules/es7.reflect.get-metadata-keys');\nrequire('../modules/es7.reflect.get-own-metadata');\nrequire('../modules/es7.reflect.get-own-metadata-keys');\nrequire('../modules/es7.reflect.has-metadata');\nrequire('../modules/es7.reflect.has-own-metadata');\nrequire('../modules/es7.reflect.metadata');\nmodule.exports = require('../modules/_core').Reflect;\n","module.exports = function (it) {\n if (typeof it != 'function') throw TypeError(it + ' is not a function!');\n return it;\n};\n","module.exports = function (it, Constructor, name, forbiddenField) {\n if (!(it instanceof Constructor) || (forbiddenField !== undefined && forbiddenField in it)) {\n throw TypeError(name + ': incorrect invocation!');\n } return it;\n};\n","var isObject = require('./_is-object');\nmodule.exports = function (it) {\n if (!isObject(it)) throw TypeError(it + ' is not an object!');\n return it;\n};\n","var forOf = require('./_for-of');\n\nmodule.exports = function (iter, ITERATOR) {\n var result = [];\n forOf(iter, false, result.push, result, ITERATOR);\n return result;\n};\n","// false -> Array#indexOf\n// true -> Array#includes\nvar toIObject = require('./_to-iobject');\nvar toLength = require('./_to-length');\nvar toAbsoluteIndex = require('./_to-absolute-index');\nmodule.exports = function (IS_INCLUDES) {\n return function ($this, el, fromIndex) {\n var O = toIObject($this);\n var length = toLength(O.length);\n var index = toAbsoluteIndex(fromIndex, length);\n var value;\n // Array#includes uses SameValueZero equality algorithm\n // eslint-disable-next-line no-self-compare\n if (IS_INCLUDES && el != el) while (length > index) {\n value = O[index++];\n // eslint-disable-next-line no-self-compare\n if (value != value) return true;\n // Array#indexOf ignores holes, Array#includes - not\n } else for (;length > index; index++) if (IS_INCLUDES || index in O) {\n if (O[index] === el) return IS_INCLUDES || index || 0;\n } return !IS_INCLUDES && -1;\n };\n};\n","// 0 -> Array#forEach\n// 1 -> Array#map\n// 2 -> Array#filter\n// 3 -> Array#some\n// 4 -> Array#every\n// 5 -> Array#find\n// 6 -> Array#findIndex\nvar ctx = require('./_ctx');\nvar IObject = require('./_iobject');\nvar toObject = require('./_to-object');\nvar toLength = require('./_to-length');\nvar asc = require('./_array-species-create');\nmodule.exports = function (TYPE, $create) {\n var IS_MAP = TYPE == 1;\n var IS_FILTER = TYPE == 2;\n var IS_SOME = TYPE == 3;\n var IS_EVERY = TYPE == 4;\n var IS_FIND_INDEX = TYPE == 6;\n var NO_HOLES = TYPE == 5 || IS_FIND_INDEX;\n var create = $create || asc;\n return function ($this, callbackfn, that) {\n var O = toObject($this);\n var self = IObject(O);\n var f = ctx(callbackfn, that, 3);\n var length = toLength(self.length);\n var index = 0;\n var result = IS_MAP ? create($this, length) : IS_FILTER ? create($this, 0) : undefined;\n var val, res;\n for (;length > index; index++) if (NO_HOLES || index in self) {\n val = self[index];\n res = f(val, index, O);\n if (TYPE) {\n if (IS_MAP) result[index] = res; // map\n else if (res) switch (TYPE) {\n case 3: return true; // some\n case 5: return val; // find\n case 6: return index; // findIndex\n case 2: result.push(val); // filter\n } else if (IS_EVERY) return false; // every\n }\n }\n return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : result;\n };\n};\n","var isObject = require('./_is-object');\nvar isArray = require('./_is-array');\nvar SPECIES = require('./_wks')('species');\n\nmodule.exports = function (original) {\n var C;\n if (isArray(original)) {\n C = original.constructor;\n // cross-realm fallback\n if (typeof C == 'function' && (C === Array || isArray(C.prototype))) C = undefined;\n if (isObject(C)) {\n C = C[SPECIES];\n if (C === null) C = undefined;\n }\n } return C === undefined ? Array : C;\n};\n","// 9.4.2.3 ArraySpeciesCreate(originalArray, length)\nvar speciesConstructor = require('./_array-species-constructor');\n\nmodule.exports = function (original, length) {\n return new (speciesConstructor(original))(length);\n};\n","// getting tag from 19.1.3.6 Object.prototype.toString()\nvar cof = require('./_cof');\nvar TAG = require('./_wks')('toStringTag');\n// ES3 wrong here\nvar ARG = cof(function () { return arguments; }()) == 'Arguments';\n\n// fallback for IE11 Script Access Denied error\nvar tryGet = function (it, key) {\n try {\n return it[key];\n } catch (e) { /* empty */ }\n};\n\nmodule.exports = function (it) {\n var O, T, B;\n return it === undefined ? 'Undefined' : it === null ? 'Null'\n // @@toStringTag case\n : typeof (T = tryGet(O = Object(it), TAG)) == 'string' ? T\n // builtinTag case\n : ARG ? cof(O)\n // ES3 arguments fallback\n : (B = cof(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : B;\n};\n","var toString = {}.toString;\n\nmodule.exports = function (it) {\n return toString.call(it).slice(8, -1);\n};\n","'use strict';\nvar dP = require('./_object-dp').f;\nvar create = require('./_object-create');\nvar redefineAll = require('./_redefine-all');\nvar ctx = require('./_ctx');\nvar anInstance = require('./_an-instance');\nvar forOf = require('./_for-of');\nvar $iterDefine = require('./_iter-define');\nvar step = require('./_iter-step');\nvar setSpecies = require('./_set-species');\nvar DESCRIPTORS = require('./_descriptors');\nvar fastKey = require('./_meta').fastKey;\nvar validate = require('./_validate-collection');\nvar SIZE = DESCRIPTORS ? '_s' : 'size';\n\nvar getEntry = function (that, key) {\n // fast case\n var index = fastKey(key);\n var entry;\n if (index !== 'F') return that._i[index];\n // frozen object case\n for (entry = that._f; entry; entry = entry.n) {\n if (entry.k == key) return entry;\n }\n};\n\nmodule.exports = {\n getConstructor: function (wrapper, NAME, IS_MAP, ADDER) {\n var C = wrapper(function (that, iterable) {\n anInstance(that, C, NAME, '_i');\n that._t = NAME; // collection type\n that._i = create(null); // index\n that._f = undefined; // first entry\n that._l = undefined; // last entry\n that[SIZE] = 0; // size\n if (iterable != undefined) forOf(iterable, IS_MAP, that[ADDER], that);\n });\n redefineAll(C.prototype, {\n // 23.1.3.1 Map.prototype.clear()\n // 23.2.3.2 Set.prototype.clear()\n clear: function clear() {\n for (var that = validate(this, NAME), data = that._i, entry = that._f; entry; entry = entry.n) {\n entry.r = true;\n if (entry.p) entry.p = entry.p.n = undefined;\n delete data[entry.i];\n }\n that._f = that._l = undefined;\n that[SIZE] = 0;\n },\n // 23.1.3.3 Map.prototype.delete(key)\n // 23.2.3.4 Set.prototype.delete(value)\n 'delete': function (key) {\n var that = validate(this, NAME);\n var entry = getEntry(that, key);\n if (entry) {\n var next = entry.n;\n var prev = entry.p;\n delete that._i[entry.i];\n entry.r = true;\n if (prev) prev.n = next;\n if (next) next.p = prev;\n if (that._f == entry) that._f = next;\n if (that._l == entry) that._l = prev;\n that[SIZE]--;\n } return !!entry;\n },\n // 23.2.3.6 Set.prototype.forEach(callbackfn, thisArg = undefined)\n // 23.1.3.5 Map.prototype.forEach(callbackfn, thisArg = undefined)\n forEach: function forEach(callbackfn /* , that = undefined */) {\n validate(this, NAME);\n var f = ctx(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3);\n var entry;\n while (entry = entry ? entry.n : this._f) {\n f(entry.v, entry.k, this);\n // revert to the last existing entry\n while (entry && entry.r) entry = entry.p;\n }\n },\n // 23.1.3.7 Map.prototype.has(key)\n // 23.2.3.7 Set.prototype.has(value)\n has: function has(key) {\n return !!getEntry(validate(this, NAME), key);\n }\n });\n if (DESCRIPTORS) dP(C.prototype, 'size', {\n get: function () {\n return validate(this, NAME)[SIZE];\n }\n });\n return C;\n },\n def: function (that, key, value) {\n var entry = getEntry(that, key);\n var prev, index;\n // change existing entry\n if (entry) {\n entry.v = value;\n // create new entry\n } else {\n that._l = entry = {\n i: index = fastKey(key, true), // <- index\n k: key, // <- key\n v: value, // <- value\n p: prev = that._l, // <- previous entry\n n: undefined, // <- next entry\n r: false // <- removed\n };\n if (!that._f) that._f = entry;\n if (prev) prev.n = entry;\n that[SIZE]++;\n // add to index\n if (index !== 'F') that._i[index] = entry;\n } return that;\n },\n getEntry: getEntry,\n setStrong: function (C, NAME, IS_MAP) {\n // add .keys, .values, .entries, [@@iterator]\n // 23.1.3.4, 23.1.3.8, 23.1.3.11, 23.1.3.12, 23.2.3.5, 23.2.3.8, 23.2.3.10, 23.2.3.11\n $iterDefine(C, NAME, function (iterated, kind) {\n this._t = validate(iterated, NAME); // target\n this._k = kind; // kind\n this._l = undefined; // previous\n }, function () {\n var that = this;\n var kind = that._k;\n var entry = that._l;\n // revert to the last existing entry\n while (entry && entry.r) entry = entry.p;\n // get next entry\n if (!that._t || !(that._l = entry = entry ? entry.n : that._t._f)) {\n // or finish the iteration\n that._t = undefined;\n return step(1);\n }\n // return step by kind\n if (kind == 'keys') return step(0, entry.k);\n if (kind == 'values') return step(0, entry.v);\n return step(0, [entry.k, entry.v]);\n }, IS_MAP ? 'entries' : 'values', !IS_MAP, true);\n\n // add [@@species], 23.1.2.2, 23.2.2.2\n setSpecies(NAME);\n }\n};\n","'use strict';\nvar redefineAll = require('./_redefine-all');\nvar getWeak = require('./_meta').getWeak;\nvar anObject = require('./_an-object');\nvar isObject = require('./_is-object');\nvar anInstance = require('./_an-instance');\nvar forOf = require('./_for-of');\nvar createArrayMethod = require('./_array-methods');\nvar $has = require('./_has');\nvar validate = require('./_validate-collection');\nvar arrayFind = createArrayMethod(5);\nvar arrayFindIndex = createArrayMethod(6);\nvar id = 0;\n\n// fallback for uncaught frozen keys\nvar uncaughtFrozenStore = function (that) {\n return that._l || (that._l = new UncaughtFrozenStore());\n};\nvar UncaughtFrozenStore = function () {\n this.a = [];\n};\nvar findUncaughtFrozen = function (store, key) {\n return arrayFind(store.a, function (it) {\n return it[0] === key;\n });\n};\nUncaughtFrozenStore.prototype = {\n get: function (key) {\n var entry = findUncaughtFrozen(this, key);\n if (entry) return entry[1];\n },\n has: function (key) {\n return !!findUncaughtFrozen(this, key);\n },\n set: function (key, value) {\n var entry = findUncaughtFrozen(this, key);\n if (entry) entry[1] = value;\n else this.a.push([key, value]);\n },\n 'delete': function (key) {\n var index = arrayFindIndex(this.a, function (it) {\n return it[0] === key;\n });\n if (~index) this.a.splice(index, 1);\n return !!~index;\n }\n};\n\nmodule.exports = {\n getConstructor: function (wrapper, NAME, IS_MAP, ADDER) {\n var C = wrapper(function (that, iterable) {\n anInstance(that, C, NAME, '_i');\n that._t = NAME; // collection type\n that._i = id++; // collection id\n that._l = undefined; // leak store for uncaught frozen objects\n if (iterable != undefined) forOf(iterable, IS_MAP, that[ADDER], that);\n });\n redefineAll(C.prototype, {\n // 23.3.3.2 WeakMap.prototype.delete(key)\n // 23.4.3.3 WeakSet.prototype.delete(value)\n 'delete': function (key) {\n if (!isObject(key)) return false;\n var data = getWeak(key);\n if (data === true) return uncaughtFrozenStore(validate(this, NAME))['delete'](key);\n return data && $has(data, this._i) && delete data[this._i];\n },\n // 23.3.3.4 WeakMap.prototype.has(key)\n // 23.4.3.4 WeakSet.prototype.has(value)\n has: function has(key) {\n if (!isObject(key)) return false;\n var data = getWeak(key);\n if (data === true) return uncaughtFrozenStore(validate(this, NAME)).has(key);\n return data && $has(data, this._i);\n }\n });\n return C;\n },\n def: function (that, key, value) {\n var data = getWeak(anObject(key), true);\n if (data === true) uncaughtFrozenStore(that).set(key, value);\n else data[that._i] = value;\n return that;\n },\n ufstore: uncaughtFrozenStore\n};\n","'use strict';\nvar global = require('./_global');\nvar $export = require('./_export');\nvar redefine = require('./_redefine');\nvar redefineAll = require('./_redefine-all');\nvar meta = require('./_meta');\nvar forOf = require('./_for-of');\nvar anInstance = require('./_an-instance');\nvar isObject = require('./_is-object');\nvar fails = require('./_fails');\nvar $iterDetect = require('./_iter-detect');\nvar setToStringTag = require('./_set-to-string-tag');\nvar inheritIfRequired = require('./_inherit-if-required');\n\nmodule.exports = function (NAME, wrapper, methods, common, IS_MAP, IS_WEAK) {\n var Base = global[NAME];\n var C = Base;\n var ADDER = IS_MAP ? 'set' : 'add';\n var proto = C && C.prototype;\n var O = {};\n var fixMethod = function (KEY) {\n var fn = proto[KEY];\n redefine(proto, KEY,\n KEY == 'delete' ? function (a) {\n return IS_WEAK && !isObject(a) ? false : fn.call(this, a === 0 ? 0 : a);\n } : KEY == 'has' ? function has(a) {\n return IS_WEAK && !isObject(a) ? false : fn.call(this, a === 0 ? 0 : a);\n } : KEY == 'get' ? function get(a) {\n return IS_WEAK && !isObject(a) ? undefined : fn.call(this, a === 0 ? 0 : a);\n } : KEY == 'add' ? function add(a) { fn.call(this, a === 0 ? 0 : a); return this; }\n : function set(a, b) { fn.call(this, a === 0 ? 0 : a, b); return this; }\n );\n };\n if (typeof C != 'function' || !(IS_WEAK || proto.forEach && !fails(function () {\n new C().entries().next();\n }))) {\n // create collection constructor\n C = common.getConstructor(wrapper, NAME, IS_MAP, ADDER);\n redefineAll(C.prototype, methods);\n meta.NEED = true;\n } else {\n var instance = new C();\n // early implementations not supports chaining\n var HASNT_CHAINING = instance[ADDER](IS_WEAK ? {} : -0, 1) != instance;\n // V8 ~ Chromium 40- weak-collections throws on primitives, but should return false\n var THROWS_ON_PRIMITIVES = fails(function () { instance.has(1); });\n // most early implementations doesn't supports iterables, most modern - not close it correctly\n var ACCEPT_ITERABLES = $iterDetect(function (iter) { new C(iter); }); // eslint-disable-line no-new\n // for early implementations -0 and +0 not the same\n var BUGGY_ZERO = !IS_WEAK && fails(function () {\n // V8 ~ Chromium 42- fails only with 5+ elements\n var $instance = new C();\n var index = 5;\n while (index--) $instance[ADDER](index, index);\n return !$instance.has(-0);\n });\n if (!ACCEPT_ITERABLES) {\n C = wrapper(function (target, iterable) {\n anInstance(target, C, NAME);\n var that = inheritIfRequired(new Base(), target, C);\n if (iterable != undefined) forOf(iterable, IS_MAP, that[ADDER], that);\n return that;\n });\n C.prototype = proto;\n proto.constructor = C;\n }\n if (THROWS_ON_PRIMITIVES || BUGGY_ZERO) {\n fixMethod('delete');\n fixMethod('has');\n IS_MAP && fixMethod('get');\n }\n if (BUGGY_ZERO || HASNT_CHAINING) fixMethod(ADDER);\n // weak collections should not contains .clear method\n if (IS_WEAK && proto.clear) delete proto.clear;\n }\n\n setToStringTag(C, NAME);\n\n O[NAME] = C;\n $export($export.G + $export.W + $export.F * (C != Base), O);\n\n if (!IS_WEAK) common.setStrong(C, NAME, IS_MAP);\n\n return C;\n};\n","var core = module.exports = { version: '2.5.7' };\nif (typeof __e == 'number') __e = core; // eslint-disable-line no-undef\n","// optional / simple context binding\nvar aFunction = require('./_a-function');\nmodule.exports = function (fn, that, length) {\n aFunction(fn);\n if (that === undefined) return fn;\n switch (length) {\n case 1: return function (a) {\n return fn.call(that, a);\n };\n case 2: return function (a, b) {\n return fn.call(that, a, b);\n };\n case 3: return function (a, b, c) {\n return fn.call(that, a, b, c);\n };\n }\n return function (/* ...args */) {\n return fn.apply(that, arguments);\n };\n};\n","// 7.2.1 RequireObjectCoercible(argument)\nmodule.exports = function (it) {\n if (it == undefined) throw TypeError(\"Can't call method on \" + it);\n return it;\n};\n","// Thank's IE8 for his funny defineProperty\nmodule.exports = !require('./_fails')(function () {\n return Object.defineProperty({}, 'a', { get: function () { return 7; } }).a != 7;\n});\n","var isObject = require('./_is-object');\nvar document = require('./_global').document;\n// typeof document.createElement is 'object' in old IE\nvar is = isObject(document) && isObject(document.createElement);\nmodule.exports = function (it) {\n return is ? document.createElement(it) : {};\n};\n","// IE 8- don't enum bug keys\nmodule.exports = (\n 'constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf'\n).split(',');\n","var global = require('./_global');\nvar core = require('./_core');\nvar hide = require('./_hide');\nvar redefine = require('./_redefine');\nvar ctx = require('./_ctx');\nvar PROTOTYPE = 'prototype';\n\nvar $export = function (type, name, source) {\n var IS_FORCED = type & $export.F;\n var IS_GLOBAL = type & $export.G;\n var IS_STATIC = type & $export.S;\n var IS_PROTO = type & $export.P;\n var IS_BIND = type & $export.B;\n var target = IS_GLOBAL ? global : IS_STATIC ? global[name] || (global[name] = {}) : (global[name] || {})[PROTOTYPE];\n var exports = IS_GLOBAL ? core : core[name] || (core[name] = {});\n var expProto = exports[PROTOTYPE] || (exports[PROTOTYPE] = {});\n var key, own, out, exp;\n if (IS_GLOBAL) source = name;\n for (key in source) {\n // contains in native\n own = !IS_FORCED && target && target[key] !== undefined;\n // export native or passed\n out = (own ? target : source)[key];\n // bind timers to global for call from export context\n exp = IS_BIND && own ? ctx(out, global) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out;\n // extend global\n if (target) redefine(target, key, out, type & $export.U);\n // export\n if (exports[key] != out) hide(exports, key, exp);\n if (IS_PROTO && expProto[key] != out) expProto[key] = out;\n }\n};\nglobal.core = core;\n// type bitmap\n$export.F = 1; // forced\n$export.G = 2; // global\n$export.S = 4; // static\n$export.P = 8; // proto\n$export.B = 16; // bind\n$export.W = 32; // wrap\n$export.U = 64; // safe\n$export.R = 128; // real proto method for `library`\nmodule.exports = $export;\n","module.exports = function (exec) {\n try {\n return !!exec();\n } catch (e) {\n return true;\n }\n};\n","var ctx = require('./_ctx');\nvar call = require('./_iter-call');\nvar isArrayIter = require('./_is-array-iter');\nvar anObject = require('./_an-object');\nvar toLength = require('./_to-length');\nvar getIterFn = require('./core.get-iterator-method');\nvar BREAK = {};\nvar RETURN = {};\nvar exports = module.exports = function (iterable, entries, fn, that, ITERATOR) {\n var iterFn = ITERATOR ? function () { return iterable; } : getIterFn(iterable);\n var f = ctx(fn, that, entries ? 2 : 1);\n var index = 0;\n var length, step, iterator, result;\n if (typeof iterFn != 'function') throw TypeError(iterable + ' is not iterable!');\n // fast case for arrays with default iterator\n if (isArrayIter(iterFn)) for (length = toLength(iterable.length); length > index; index++) {\n result = entries ? f(anObject(step = iterable[index])[0], step[1]) : f(iterable[index]);\n if (result === BREAK || result === RETURN) return result;\n } else for (iterator = iterFn.call(iterable); !(step = iterator.next()).done;) {\n result = call(iterator, f, step.value, entries);\n if (result === BREAK || result === RETURN) return result;\n }\n};\nexports.BREAK = BREAK;\nexports.RETURN = RETURN;\n","// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028\nvar global = module.exports = typeof window != 'undefined' && window.Math == Math\n ? window : typeof self != 'undefined' && self.Math == Math ? self\n // eslint-disable-next-line no-new-func\n : Function('return this')();\nif (typeof __g == 'number') __g = global; // eslint-disable-line no-undef\n","var hasOwnProperty = {}.hasOwnProperty;\nmodule.exports = function (it, key) {\n return hasOwnProperty.call(it, key);\n};\n","var dP = require('./_object-dp');\nvar createDesc = require('./_property-desc');\nmodule.exports = require('./_descriptors') ? function (object, key, value) {\n return dP.f(object, key, createDesc(1, value));\n} : function (object, key, value) {\n object[key] = value;\n return object;\n};\n","var document = require('./_global').document;\nmodule.exports = document && document.documentElement;\n","module.exports = !require('./_descriptors') && !require('./_fails')(function () {\n return Object.defineProperty(require('./_dom-create')('div'), 'a', { get: function () { return 7; } }).a != 7;\n});\n","var isObject = require('./_is-object');\nvar setPrototypeOf = require('./_set-proto').set;\nmodule.exports = function (that, target, C) {\n var S = target.constructor;\n var P;\n if (S !== C && typeof S == 'function' && (P = S.prototype) !== C.prototype && isObject(P) && setPrototypeOf) {\n setPrototypeOf(that, P);\n } return that;\n};\n","// fallback for non-array-like ES3 and non-enumerable old V8 strings\nvar cof = require('./_cof');\n// eslint-disable-next-line no-prototype-builtins\nmodule.exports = Object('z').propertyIsEnumerable(0) ? Object : function (it) {\n return cof(it) == 'String' ? it.split('') : Object(it);\n};\n","// check on default Array iterator\nvar Iterators = require('./_iterators');\nvar ITERATOR = require('./_wks')('iterator');\nvar ArrayProto = Array.prototype;\n\nmodule.exports = function (it) {\n return it !== undefined && (Iterators.Array === it || ArrayProto[ITERATOR] === it);\n};\n","// 7.2.2 IsArray(argument)\nvar cof = require('./_cof');\nmodule.exports = Array.isArray || function isArray(arg) {\n return cof(arg) == 'Array';\n};\n","module.exports = function (it) {\n return typeof it === 'object' ? it !== null : typeof it === 'function';\n};\n","// call something on iterator step with safe closing on error\nvar anObject = require('./_an-object');\nmodule.exports = function (iterator, fn, value, entries) {\n try {\n return entries ? fn(anObject(value)[0], value[1]) : fn(value);\n // 7.4.6 IteratorClose(iterator, completion)\n } catch (e) {\n var ret = iterator['return'];\n if (ret !== undefined) anObject(ret.call(iterator));\n throw e;\n }\n};\n","'use strict';\nvar create = require('./_object-create');\nvar descriptor = require('./_property-desc');\nvar setToStringTag = require('./_set-to-string-tag');\nvar IteratorPrototype = {};\n\n// 25.1.2.1.1 %IteratorPrototype%[@@iterator]()\nrequire('./_hide')(IteratorPrototype, require('./_wks')('iterator'), function () { return this; });\n\nmodule.exports = function (Constructor, NAME, next) {\n Constructor.prototype = create(IteratorPrototype, { next: descriptor(1, next) });\n setToStringTag(Constructor, NAME + ' Iterator');\n};\n","'use strict';\nvar LIBRARY = require('./_library');\nvar $export = require('./_export');\nvar redefine = require('./_redefine');\nvar hide = require('./_hide');\nvar Iterators = require('./_iterators');\nvar $iterCreate = require('./_iter-create');\nvar setToStringTag = require('./_set-to-string-tag');\nvar getPrototypeOf = require('./_object-gpo');\nvar ITERATOR = require('./_wks')('iterator');\nvar BUGGY = !([].keys && 'next' in [].keys()); // Safari has buggy iterators w/o `next`\nvar FF_ITERATOR = '@@iterator';\nvar KEYS = 'keys';\nvar VALUES = 'values';\n\nvar returnThis = function () { return this; };\n\nmodule.exports = function (Base, NAME, Constructor, next, DEFAULT, IS_SET, FORCED) {\n $iterCreate(Constructor, NAME, next);\n var getMethod = function (kind) {\n if (!BUGGY && kind in proto) return proto[kind];\n switch (kind) {\n case KEYS: return function keys() { return new Constructor(this, kind); };\n case VALUES: return function values() { return new Constructor(this, kind); };\n } return function entries() { return new Constructor(this, kind); };\n };\n var TAG = NAME + ' Iterator';\n var DEF_VALUES = DEFAULT == VALUES;\n var VALUES_BUG = false;\n var proto = Base.prototype;\n var $native = proto[ITERATOR] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT];\n var $default = $native || getMethod(DEFAULT);\n var $entries = DEFAULT ? !DEF_VALUES ? $default : getMethod('entries') : undefined;\n var $anyNative = NAME == 'Array' ? proto.entries || $native : $native;\n var methods, key, IteratorPrototype;\n // Fix native\n if ($anyNative) {\n IteratorPrototype = getPrototypeOf($anyNative.call(new Base()));\n if (IteratorPrototype !== Object.prototype && IteratorPrototype.next) {\n // Set @@toStringTag to native iterators\n setToStringTag(IteratorPrototype, TAG, true);\n // fix for some old engines\n if (!LIBRARY && typeof IteratorPrototype[ITERATOR] != 'function') hide(IteratorPrototype, ITERATOR, returnThis);\n }\n }\n // fix Array#{values, @@iterator}.name in V8 / FF\n if (DEF_VALUES && $native && $native.name !== VALUES) {\n VALUES_BUG = true;\n $default = function values() { return $native.call(this); };\n }\n // Define iterator\n if ((!LIBRARY || FORCED) && (BUGGY || VALUES_BUG || !proto[ITERATOR])) {\n hide(proto, ITERATOR, $default);\n }\n // Plug for library\n Iterators[NAME] = $default;\n Iterators[TAG] = returnThis;\n if (DEFAULT) {\n methods = {\n values: DEF_VALUES ? $default : getMethod(VALUES),\n keys: IS_SET ? $default : getMethod(KEYS),\n entries: $entries\n };\n if (FORCED) for (key in methods) {\n if (!(key in proto)) redefine(proto, key, methods[key]);\n } else $export($export.P + $export.F * (BUGGY || VALUES_BUG), NAME, methods);\n }\n return methods;\n};\n","var ITERATOR = require('./_wks')('iterator');\nvar SAFE_CLOSING = false;\n\ntry {\n var riter = [7][ITERATOR]();\n riter['return'] = function () { SAFE_CLOSING = true; };\n // eslint-disable-next-line no-throw-literal\n Array.from(riter, function () { throw 2; });\n} catch (e) { /* empty */ }\n\nmodule.exports = function (exec, skipClosing) {\n if (!skipClosing && !SAFE_CLOSING) return false;\n var safe = false;\n try {\n var arr = [7];\n var iter = arr[ITERATOR]();\n iter.next = function () { return { done: safe = true }; };\n arr[ITERATOR] = function () { return iter; };\n exec(arr);\n } catch (e) { /* empty */ }\n return safe;\n};\n","module.exports = function (done, value) {\n return { value: value, done: !!done };\n};\n","module.exports = {};\n","module.exports = false;\n","var META = require('./_uid')('meta');\nvar isObject = require('./_is-object');\nvar has = require('./_has');\nvar setDesc = require('./_object-dp').f;\nvar id = 0;\nvar isExtensible = Object.isExtensible || function () {\n return true;\n};\nvar FREEZE = !require('./_fails')(function () {\n return isExtensible(Object.preventExtensions({}));\n});\nvar setMeta = function (it) {\n setDesc(it, META, { value: {\n i: 'O' + ++id, // object ID\n w: {} // weak collections IDs\n } });\n};\nvar fastKey = function (it, create) {\n // return primitive with prefix\n if (!isObject(it)) return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it;\n if (!has(it, META)) {\n // can't set metadata to uncaught frozen object\n if (!isExtensible(it)) return 'F';\n // not necessary to add metadata\n if (!create) return 'E';\n // add missing metadata\n setMeta(it);\n // return object ID\n } return it[META].i;\n};\nvar getWeak = function (it, create) {\n if (!has(it, META)) {\n // can't set metadata to uncaught frozen object\n if (!isExtensible(it)) return true;\n // not necessary to add metadata\n if (!create) return false;\n // add missing metadata\n setMeta(it);\n // return hash weak collections IDs\n } return it[META].w;\n};\n// add metadata on freeze-family methods calling\nvar onFreeze = function (it) {\n if (FREEZE && meta.NEED && isExtensible(it) && !has(it, META)) setMeta(it);\n return it;\n};\nvar meta = module.exports = {\n KEY: META,\n NEED: false,\n fastKey: fastKey,\n getWeak: getWeak,\n onFreeze: onFreeze\n};\n","var Map = require('./es6.map');\nvar $export = require('./_export');\nvar shared = require('./_shared')('metadata');\nvar store = shared.store || (shared.store = new (require('./es6.weak-map'))());\n\nvar getOrCreateMetadataMap = function (target, targetKey, create) {\n var targetMetadata = store.get(target);\n if (!targetMetadata) {\n if (!create) return undefined;\n store.set(target, targetMetadata = new Map());\n }\n var keyMetadata = targetMetadata.get(targetKey);\n if (!keyMetadata) {\n if (!create) return undefined;\n targetMetadata.set(targetKey, keyMetadata = new Map());\n } return keyMetadata;\n};\nvar ordinaryHasOwnMetadata = function (MetadataKey, O, P) {\n var metadataMap = getOrCreateMetadataMap(O, P, false);\n return metadataMap === undefined ? false : metadataMap.has(MetadataKey);\n};\nvar ordinaryGetOwnMetadata = function (MetadataKey, O, P) {\n var metadataMap = getOrCreateMetadataMap(O, P, false);\n return metadataMap === undefined ? undefined : metadataMap.get(MetadataKey);\n};\nvar ordinaryDefineOwnMetadata = function (MetadataKey, MetadataValue, O, P) {\n getOrCreateMetadataMap(O, P, true).set(MetadataKey, MetadataValue);\n};\nvar ordinaryOwnMetadataKeys = function (target, targetKey) {\n var metadataMap = getOrCreateMetadataMap(target, targetKey, false);\n var keys = [];\n if (metadataMap) metadataMap.forEach(function (_, key) { keys.push(key); });\n return keys;\n};\nvar toMetaKey = function (it) {\n return it === undefined || typeof it == 'symbol' ? it : String(it);\n};\nvar exp = function (O) {\n $export($export.S, 'Reflect', O);\n};\n\nmodule.exports = {\n store: store,\n map: getOrCreateMetadataMap,\n has: ordinaryHasOwnMetadata,\n get: ordinaryGetOwnMetadata,\n set: ordinaryDefineOwnMetadata,\n keys: ordinaryOwnMetadataKeys,\n key: toMetaKey,\n exp: exp\n};\n","'use strict';\n// 19.1.2.1 Object.assign(target, source, ...)\nvar getKeys = require('./_object-keys');\nvar gOPS = require('./_object-gops');\nvar pIE = require('./_object-pie');\nvar toObject = require('./_to-object');\nvar IObject = require('./_iobject');\nvar $assign = Object.assign;\n\n// should work with symbols and should have deterministic property order (V8 bug)\nmodule.exports = !$assign || require('./_fails')(function () {\n var A = {};\n var B = {};\n // eslint-disable-next-line no-undef\n var S = Symbol();\n var K = 'abcdefghijklmnopqrst';\n A[S] = 7;\n K.split('').forEach(function (k) { B[k] = k; });\n return $assign({}, A)[S] != 7 || Object.keys($assign({}, B)).join('') != K;\n}) ? function assign(target, source) { // eslint-disable-line no-unused-vars\n var T = toObject(target);\n var aLen = arguments.length;\n var index = 1;\n var getSymbols = gOPS.f;\n var isEnum = pIE.f;\n while (aLen > index) {\n var S = IObject(arguments[index++]);\n var keys = getSymbols ? getKeys(S).concat(getSymbols(S)) : getKeys(S);\n var length = keys.length;\n var j = 0;\n var key;\n while (length > j) if (isEnum.call(S, key = keys[j++])) T[key] = S[key];\n } return T;\n} : $assign;\n","// 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties])\nvar anObject = require('./_an-object');\nvar dPs = require('./_object-dps');\nvar enumBugKeys = require('./_enum-bug-keys');\nvar IE_PROTO = require('./_shared-key')('IE_PROTO');\nvar Empty = function () { /* empty */ };\nvar PROTOTYPE = 'prototype';\n\n// Create object with fake `null` prototype: use iframe Object with cleared prototype\nvar createDict = function () {\n // Thrash, waste and sodomy: IE GC bug\n var iframe = require('./_dom-create')('iframe');\n var i = enumBugKeys.length;\n var lt = '<';\n var gt = '>';\n var iframeDocument;\n iframe.style.display = 'none';\n require('./_html').appendChild(iframe);\n iframe.src = 'javascript:'; // eslint-disable-line no-script-url\n // createDict = iframe.contentWindow.Object;\n // html.removeChild(iframe);\n iframeDocument = iframe.contentWindow.document;\n iframeDocument.open();\n iframeDocument.write(lt + 'script' + gt + 'document.F=Object' + lt + '/script' + gt);\n iframeDocument.close();\n createDict = iframeDocument.F;\n while (i--) delete createDict[PROTOTYPE][enumBugKeys[i]];\n return createDict();\n};\n\nmodule.exports = Object.create || function create(O, Properties) {\n var result;\n if (O !== null) {\n Empty[PROTOTYPE] = anObject(O);\n result = new Empty();\n Empty[PROTOTYPE] = null;\n // add \"__proto__\" for Object.getPrototypeOf polyfill\n result[IE_PROTO] = O;\n } else result = createDict();\n return Properties === undefined ? result : dPs(result, Properties);\n};\n","var anObject = require('./_an-object');\nvar IE8_DOM_DEFINE = require('./_ie8-dom-define');\nvar toPrimitive = require('./_to-primitive');\nvar dP = Object.defineProperty;\n\nexports.f = require('./_descriptors') ? Object.defineProperty : function defineProperty(O, P, Attributes) {\n anObject(O);\n P = toPrimitive(P, true);\n anObject(Attributes);\n if (IE8_DOM_DEFINE) try {\n return dP(O, P, Attributes);\n } catch (e) { /* empty */ }\n if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported!');\n if ('value' in Attributes) O[P] = Attributes.value;\n return O;\n};\n","var dP = require('./_object-dp');\nvar anObject = require('./_an-object');\nvar getKeys = require('./_object-keys');\n\nmodule.exports = require('./_descriptors') ? Object.defineProperties : function defineProperties(O, Properties) {\n anObject(O);\n var keys = getKeys(Properties);\n var length = keys.length;\n var i = 0;\n var P;\n while (length > i) dP.f(O, P = keys[i++], Properties[P]);\n return O;\n};\n","var pIE = require('./_object-pie');\nvar createDesc = require('./_property-desc');\nvar toIObject = require('./_to-iobject');\nvar toPrimitive = require('./_to-primitive');\nvar has = require('./_has');\nvar IE8_DOM_DEFINE = require('./_ie8-dom-define');\nvar gOPD = Object.getOwnPropertyDescriptor;\n\nexports.f = require('./_descriptors') ? gOPD : function getOwnPropertyDescriptor(O, P) {\n O = toIObject(O);\n P = toPrimitive(P, true);\n if (IE8_DOM_DEFINE) try {\n return gOPD(O, P);\n } catch (e) { /* empty */ }\n if (has(O, P)) return createDesc(!pIE.f.call(O, P), O[P]);\n};\n","exports.f = Object.getOwnPropertySymbols;\n","// 19.1.2.9 / 15.2.3.2 Object.getPrototypeOf(O)\nvar has = require('./_has');\nvar toObject = require('./_to-object');\nvar IE_PROTO = require('./_shared-key')('IE_PROTO');\nvar ObjectProto = Object.prototype;\n\nmodule.exports = Object.getPrototypeOf || function (O) {\n O = toObject(O);\n if (has(O, IE_PROTO)) return O[IE_PROTO];\n if (typeof O.constructor == 'function' && O instanceof O.constructor) {\n return O.constructor.prototype;\n } return O instanceof Object ? ObjectProto : null;\n};\n","var has = require('./_has');\nvar toIObject = require('./_to-iobject');\nvar arrayIndexOf = require('./_array-includes')(false);\nvar IE_PROTO = require('./_shared-key')('IE_PROTO');\n\nmodule.exports = function (object, names) {\n var O = toIObject(object);\n var i = 0;\n var result = [];\n var key;\n for (key in O) if (key != IE_PROTO) has(O, key) && result.push(key);\n // Don't enum bug & hidden keys\n while (names.length > i) if (has(O, key = names[i++])) {\n ~arrayIndexOf(result, key) || result.push(key);\n }\n return result;\n};\n","// 19.1.2.14 / 15.2.3.14 Object.keys(O)\nvar $keys = require('./_object-keys-internal');\nvar enumBugKeys = require('./_enum-bug-keys');\n\nmodule.exports = Object.keys || function keys(O) {\n return $keys(O, enumBugKeys);\n};\n","exports.f = {}.propertyIsEnumerable;\n","module.exports = function (bitmap, value) {\n return {\n enumerable: !(bitmap & 1),\n configurable: !(bitmap & 2),\n writable: !(bitmap & 4),\n value: value\n };\n};\n","var redefine = require('./_redefine');\nmodule.exports = function (target, src, safe) {\n for (var key in src) redefine(target, key, src[key], safe);\n return target;\n};\n","var global = require('./_global');\nvar hide = require('./_hide');\nvar has = require('./_has');\nvar SRC = require('./_uid')('src');\nvar TO_STRING = 'toString';\nvar $toString = Function[TO_STRING];\nvar TPL = ('' + $toString).split(TO_STRING);\n\nrequire('./_core').inspectSource = function (it) {\n return $toString.call(it);\n};\n\n(module.exports = function (O, key, val, safe) {\n var isFunction = typeof val == 'function';\n if (isFunction) has(val, 'name') || hide(val, 'name', key);\n if (O[key] === val) return;\n if (isFunction) has(val, SRC) || hide(val, SRC, O[key] ? '' + O[key] : TPL.join(String(key)));\n if (O === global) {\n O[key] = val;\n } else if (!safe) {\n delete O[key];\n hide(O, key, val);\n } else if (O[key]) {\n O[key] = val;\n } else {\n hide(O, key, val);\n }\n// add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative\n})(Function.prototype, TO_STRING, function toString() {\n return typeof this == 'function' && this[SRC] || $toString.call(this);\n});\n","// Works with __proto__ only. Old v8 can't work with null proto objects.\n/* eslint-disable no-proto */\nvar isObject = require('./_is-object');\nvar anObject = require('./_an-object');\nvar check = function (O, proto) {\n anObject(O);\n if (!isObject(proto) && proto !== null) throw TypeError(proto + \": can't set as prototype!\");\n};\nmodule.exports = {\n set: Object.setPrototypeOf || ('__proto__' in {} ? // eslint-disable-line\n function (test, buggy, set) {\n try {\n set = require('./_ctx')(Function.call, require('./_object-gopd').f(Object.prototype, '__proto__').set, 2);\n set(test, []);\n buggy = !(test instanceof Array);\n } catch (e) { buggy = true; }\n return function setPrototypeOf(O, proto) {\n check(O, proto);\n if (buggy) O.__proto__ = proto;\n else set(O, proto);\n return O;\n };\n }({}, false) : undefined),\n check: check\n};\n","'use strict';\nvar global = require('./_global');\nvar dP = require('./_object-dp');\nvar DESCRIPTORS = require('./_descriptors');\nvar SPECIES = require('./_wks')('species');\n\nmodule.exports = function (KEY) {\n var C = global[KEY];\n if (DESCRIPTORS && C && !C[SPECIES]) dP.f(C, SPECIES, {\n configurable: true,\n get: function () { return this; }\n });\n};\n","var def = require('./_object-dp').f;\nvar has = require('./_has');\nvar TAG = require('./_wks')('toStringTag');\n\nmodule.exports = function (it, tag, stat) {\n if (it && !has(it = stat ? it : it.prototype, TAG)) def(it, TAG, { configurable: true, value: tag });\n};\n","var shared = require('./_shared')('keys');\nvar uid = require('./_uid');\nmodule.exports = function (key) {\n return shared[key] || (shared[key] = uid(key));\n};\n","var core = require('./_core');\nvar global = require('./_global');\nvar SHARED = '__core-js_shared__';\nvar store = global[SHARED] || (global[SHARED] = {});\n\n(module.exports = function (key, value) {\n return store[key] || (store[key] = value !== undefined ? value : {});\n})('versions', []).push({\n version: core.version,\n mode: require('./_library') ? 'pure' : 'global',\n copyright: '© 2018 Denis Pushkarev (zloirock.ru)'\n});\n","var toInteger = require('./_to-integer');\nvar max = Math.max;\nvar min = Math.min;\nmodule.exports = function (index, length) {\n index = toInteger(index);\n return index < 0 ? max(index + length, 0) : min(index, length);\n};\n","// 7.1.4 ToInteger\nvar ceil = Math.ceil;\nvar floor = Math.floor;\nmodule.exports = function (it) {\n return isNaN(it = +it) ? 0 : (it > 0 ? floor : ceil)(it);\n};\n","// to indexed object, toObject with fallback for non-array-like ES3 strings\nvar IObject = require('./_iobject');\nvar defined = require('./_defined');\nmodule.exports = function (it) {\n return IObject(defined(it));\n};\n","// 7.1.15 ToLength\nvar toInteger = require('./_to-integer');\nvar min = Math.min;\nmodule.exports = function (it) {\n return it > 0 ? min(toInteger(it), 0x1fffffffffffff) : 0; // pow(2, 53) - 1 == 9007199254740991\n};\n","// 7.1.13 ToObject(argument)\nvar defined = require('./_defined');\nmodule.exports = function (it) {\n return Object(defined(it));\n};\n","// 7.1.1 ToPrimitive(input [, PreferredType])\nvar isObject = require('./_is-object');\n// instead of the ES6 spec version, we didn't implement @@toPrimitive case\n// and the second argument - flag - preferred type is a string\nmodule.exports = function (it, S) {\n if (!isObject(it)) return it;\n var fn, val;\n if (S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it))) return val;\n if (typeof (fn = it.valueOf) == 'function' && !isObject(val = fn.call(it))) return val;\n if (!S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it))) return val;\n throw TypeError(\"Can't convert object to primitive value\");\n};\n","var id = 0;\nvar px = Math.random();\nmodule.exports = function (key) {\n return 'Symbol('.concat(key === undefined ? '' : key, ')_', (++id + px).toString(36));\n};\n","var isObject = require('./_is-object');\nmodule.exports = function (it, TYPE) {\n if (!isObject(it) || it._t !== TYPE) throw TypeError('Incompatible receiver, ' + TYPE + ' required!');\n return it;\n};\n","var store = require('./_shared')('wks');\nvar uid = require('./_uid');\nvar Symbol = require('./_global').Symbol;\nvar USE_SYMBOL = typeof Symbol == 'function';\n\nvar $exports = module.exports = function (name) {\n return store[name] || (store[name] =\n USE_SYMBOL && Symbol[name] || (USE_SYMBOL ? Symbol : uid)('Symbol.' + name));\n};\n\n$exports.store = store;\n","var classof = require('./_classof');\nvar ITERATOR = require('./_wks')('iterator');\nvar Iterators = require('./_iterators');\nmodule.exports = require('./_core').getIteratorMethod = function (it) {\n if (it != undefined) return it[ITERATOR]\n || it['@@iterator']\n || Iterators[classof(it)];\n};\n","'use strict';\nvar strong = require('./_collection-strong');\nvar validate = require('./_validate-collection');\nvar MAP = 'Map';\n\n// 23.1 Map Objects\nmodule.exports = require('./_collection')(MAP, function (get) {\n return function Map() { return get(this, arguments.length > 0 ? arguments[0] : undefined); };\n}, {\n // 23.1.3.6 Map.prototype.get(key)\n get: function get(key) {\n var entry = strong.getEntry(validate(this, MAP), key);\n return entry && entry.v;\n },\n // 23.1.3.9 Map.prototype.set(key, value)\n set: function set(key, value) {\n return strong.def(validate(this, MAP), key === 0 ? 0 : key, value);\n }\n}, strong, true);\n","'use strict';\nvar strong = require('./_collection-strong');\nvar validate = require('./_validate-collection');\nvar SET = 'Set';\n\n// 23.2 Set Objects\nmodule.exports = require('./_collection')(SET, function (get) {\n return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); };\n}, {\n // 23.2.3.1 Set.prototype.add(value)\n add: function add(value) {\n return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value);\n }\n}, strong);\n","'use strict';\nvar each = require('./_array-methods')(0);\nvar redefine = require('./_redefine');\nvar meta = require('./_meta');\nvar assign = require('./_object-assign');\nvar weak = require('./_collection-weak');\nvar isObject = require('./_is-object');\nvar fails = require('./_fails');\nvar validate = require('./_validate-collection');\nvar WEAK_MAP = 'WeakMap';\nvar getWeak = meta.getWeak;\nvar isExtensible = Object.isExtensible;\nvar uncaughtFrozenStore = weak.ufstore;\nvar tmp = {};\nvar InternalMap;\n\nvar wrapper = function (get) {\n return function WeakMap() {\n return get(this, arguments.length > 0 ? arguments[0] : undefined);\n };\n};\n\nvar methods = {\n // 23.3.3.3 WeakMap.prototype.get(key)\n get: function get(key) {\n if (isObject(key)) {\n var data = getWeak(key);\n if (data === true) return uncaughtFrozenStore(validate(this, WEAK_MAP)).get(key);\n return data ? data[this._i] : undefined;\n }\n },\n // 23.3.3.5 WeakMap.prototype.set(key, value)\n set: function set(key, value) {\n return weak.def(validate(this, WEAK_MAP), key, value);\n }\n};\n\n// 23.3 WeakMap Objects\nvar $WeakMap = module.exports = require('./_collection')(WEAK_MAP, wrapper, methods, weak, true, true);\n\n// IE11 WeakMap frozen keys fix\nif (fails(function () { return new $WeakMap().set((Object.freeze || Object)(tmp), 7).get(tmp) != 7; })) {\n InternalMap = weak.getConstructor(wrapper, WEAK_MAP);\n assign(InternalMap.prototype, methods);\n meta.NEED = true;\n each(['delete', 'has', 'get', 'set'], function (key) {\n var proto = $WeakMap.prototype;\n var method = proto[key];\n redefine(proto, key, function (a, b) {\n // store frozen objects on internal weakmap shim\n if (isObject(a) && !isExtensible(a)) {\n if (!this._f) this._f = new InternalMap();\n var result = this._f[key](a, b);\n return key == 'set' ? this : result;\n // store all the rest on native weakmap\n } return method.call(this, a, b);\n });\n });\n}\n","var metadata = require('./_metadata');\nvar anObject = require('./_an-object');\nvar toMetaKey = metadata.key;\nvar ordinaryDefineOwnMetadata = metadata.set;\n\nmetadata.exp({ defineMetadata: function defineMetadata(metadataKey, metadataValue, target, targetKey) {\n ordinaryDefineOwnMetadata(metadataKey, metadataValue, anObject(target), toMetaKey(targetKey));\n} });\n","var metadata = require('./_metadata');\nvar anObject = require('./_an-object');\nvar toMetaKey = metadata.key;\nvar getOrCreateMetadataMap = metadata.map;\nvar store = metadata.store;\n\nmetadata.exp({ deleteMetadata: function deleteMetadata(metadataKey, target /* , targetKey */) {\n var targetKey = arguments.length < 3 ? undefined : toMetaKey(arguments[2]);\n var metadataMap = getOrCreateMetadataMap(anObject(target), targetKey, false);\n if (metadataMap === undefined || !metadataMap['delete'](metadataKey)) return false;\n if (metadataMap.size) return true;\n var targetMetadata = store.get(target);\n targetMetadata['delete'](targetKey);\n return !!targetMetadata.size || store['delete'](target);\n} });\n","var Set = require('./es6.set');\nvar from = require('./_array-from-iterable');\nvar metadata = require('./_metadata');\nvar anObject = require('./_an-object');\nvar getPrototypeOf = require('./_object-gpo');\nvar ordinaryOwnMetadataKeys = metadata.keys;\nvar toMetaKey = metadata.key;\n\nvar ordinaryMetadataKeys = function (O, P) {\n var oKeys = ordinaryOwnMetadataKeys(O, P);\n var parent = getPrototypeOf(O);\n if (parent === null) return oKeys;\n var pKeys = ordinaryMetadataKeys(parent, P);\n return pKeys.length ? oKeys.length ? from(new Set(oKeys.concat(pKeys))) : pKeys : oKeys;\n};\n\nmetadata.exp({ getMetadataKeys: function getMetadataKeys(target /* , targetKey */) {\n return ordinaryMetadataKeys(anObject(target), arguments.length < 2 ? undefined : toMetaKey(arguments[1]));\n} });\n","var metadata = require('./_metadata');\nvar anObject = require('./_an-object');\nvar getPrototypeOf = require('./_object-gpo');\nvar ordinaryHasOwnMetadata = metadata.has;\nvar ordinaryGetOwnMetadata = metadata.get;\nvar toMetaKey = metadata.key;\n\nvar ordinaryGetMetadata = function (MetadataKey, O, P) {\n var hasOwn = ordinaryHasOwnMetadata(MetadataKey, O, P);\n if (hasOwn) return ordinaryGetOwnMetadata(MetadataKey, O, P);\n var parent = getPrototypeOf(O);\n return parent !== null ? ordinaryGetMetadata(MetadataKey, parent, P) : undefined;\n};\n\nmetadata.exp({ getMetadata: function getMetadata(metadataKey, target /* , targetKey */) {\n return ordinaryGetMetadata(metadataKey, anObject(target), arguments.length < 3 ? undefined : toMetaKey(arguments[2]));\n} });\n","var metadata = require('./_metadata');\nvar anObject = require('./_an-object');\nvar ordinaryOwnMetadataKeys = metadata.keys;\nvar toMetaKey = metadata.key;\n\nmetadata.exp({ getOwnMetadataKeys: function getOwnMetadataKeys(target /* , targetKey */) {\n return ordinaryOwnMetadataKeys(anObject(target), arguments.length < 2 ? undefined : toMetaKey(arguments[1]));\n} });\n","var metadata = require('./_metadata');\nvar anObject = require('./_an-object');\nvar ordinaryGetOwnMetadata = metadata.get;\nvar toMetaKey = metadata.key;\n\nmetadata.exp({ getOwnMetadata: function getOwnMetadata(metadataKey, target /* , targetKey */) {\n return ordinaryGetOwnMetadata(metadataKey, anObject(target)\n , arguments.length < 3 ? undefined : toMetaKey(arguments[2]));\n} });\n","var metadata = require('./_metadata');\nvar anObject = require('./_an-object');\nvar getPrototypeOf = require('./_object-gpo');\nvar ordinaryHasOwnMetadata = metadata.has;\nvar toMetaKey = metadata.key;\n\nvar ordinaryHasMetadata = function (MetadataKey, O, P) {\n var hasOwn = ordinaryHasOwnMetadata(MetadataKey, O, P);\n if (hasOwn) return true;\n var parent = getPrototypeOf(O);\n return parent !== null ? ordinaryHasMetadata(MetadataKey, parent, P) : false;\n};\n\nmetadata.exp({ hasMetadata: function hasMetadata(metadataKey, target /* , targetKey */) {\n return ordinaryHasMetadata(metadataKey, anObject(target), arguments.length < 3 ? undefined : toMetaKey(arguments[2]));\n} });\n","var metadata = require('./_metadata');\nvar anObject = require('./_an-object');\nvar ordinaryHasOwnMetadata = metadata.has;\nvar toMetaKey = metadata.key;\n\nmetadata.exp({ hasOwnMetadata: function hasOwnMetadata(metadataKey, target /* , targetKey */) {\n return ordinaryHasOwnMetadata(metadataKey, anObject(target)\n , arguments.length < 3 ? undefined : toMetaKey(arguments[2]));\n} });\n","var $metadata = require('./_metadata');\nvar anObject = require('./_an-object');\nvar aFunction = require('./_a-function');\nvar toMetaKey = $metadata.key;\nvar ordinaryDefineOwnMetadata = $metadata.set;\n\n$metadata.exp({ metadata: function metadata(metadataKey, metadataValue) {\n return function decorator(target, targetKey) {\n ordinaryDefineOwnMetadata(\n metadataKey, metadataValue,\n (targetKey !== undefined ? anObject : aFunction)(target),\n toMetaKey(targetKey)\n );\n };\n} });\n","/**\n* @license\n* Copyright Google Inc. All Rights Reserved.\n*\n* Use of this source code is governed by an MIT-style license that can be\n* found in the LICENSE file at https://angular.io/license\n*/\n(function (global, factory) {\n\ttypeof exports === 'object' && typeof module !== 'undefined' ? factory() :\n\ttypeof define === 'function' && define.amd ? define(factory) :\n\t(factory());\n}(this, (function () { 'use strict';\n\n/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\nvar Zone$1 = (function (global) {\n var FUNCTION = 'function';\n var performance = global['performance'];\n function mark(name) {\n performance && performance['mark'] && performance['mark'](name);\n }\n function performanceMeasure(name, label) {\n performance && performance['measure'] && performance['measure'](name, label);\n }\n mark('Zone');\n if (global['Zone']) {\n throw new Error('Zone already loaded.');\n }\n var Zone = /** @class */ (function () {\n function Zone(parent, zoneSpec) {\n this._properties = null;\n this._parent = parent;\n this._name = zoneSpec ? zoneSpec.name || 'unnamed' : '';\n this._properties = zoneSpec && zoneSpec.properties || {};\n this._zoneDelegate =\n new ZoneDelegate(this, this._parent && this._parent._zoneDelegate, zoneSpec);\n }\n Zone.assertZonePatched = function () {\n if (global['Promise'] !== patches['ZoneAwarePromise']) {\n throw new Error('Zone.js has detected that ZoneAwarePromise `(window|global).Promise` ' +\n 'has been overwritten.\\n' +\n 'Most likely cause is that a Promise polyfill has been loaded ' +\n 'after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. ' +\n 'If you must load one, do so before loading zone.js.)');\n }\n };\n Object.defineProperty(Zone, \"root\", {\n get: function () {\n var zone = Zone.current;\n while (zone.parent) {\n zone = zone.parent;\n }\n return zone;\n },\n enumerable: true,\n configurable: true\n });\n Object.defineProperty(Zone, \"current\", {\n get: function () {\n return _currentZoneFrame.zone;\n },\n enumerable: true,\n configurable: true\n });\n Object.defineProperty(Zone, \"currentTask\", {\n get: function () {\n return _currentTask;\n },\n enumerable: true,\n configurable: true\n });\n Zone.__load_patch = function (name, fn) {\n if (patches.hasOwnProperty(name)) {\n throw Error('Already loaded patch: ' + name);\n }\n else if (!global['__Zone_disable_' + name]) {\n var perfName = 'Zone:' + name;\n mark(perfName);\n patches[name] = fn(global, Zone, _api);\n performanceMeasure(perfName, perfName);\n }\n };\n Object.defineProperty(Zone.prototype, \"parent\", {\n get: function () {\n return this._parent;\n },\n enumerable: true,\n configurable: true\n });\n Object.defineProperty(Zone.prototype, \"name\", {\n get: function () {\n return this._name;\n },\n enumerable: true,\n configurable: true\n });\n Zone.prototype.get = function (key) {\n var zone = this.getZoneWith(key);\n if (zone)\n return zone._properties[key];\n };\n Zone.prototype.getZoneWith = function (key) {\n var current = this;\n while (current) {\n if (current._properties.hasOwnProperty(key)) {\n return current;\n }\n current = current._parent;\n }\n return null;\n };\n Zone.prototype.fork = function (zoneSpec) {\n if (!zoneSpec)\n throw new Error('ZoneSpec required!');\n return this._zoneDelegate.fork(this, zoneSpec);\n };\n Zone.prototype.wrap = function (callback, source) {\n if (typeof callback !== FUNCTION) {\n throw new Error('Expecting function got: ' + callback);\n }\n var _callback = this._zoneDelegate.intercept(this, callback, source);\n var zone = this;\n return function () {\n return zone.runGuarded(_callback, this, arguments, source);\n };\n };\n Zone.prototype.run = function (callback, applyThis, applyArgs, source) {\n if (applyThis === void 0) { applyThis = undefined; }\n if (applyArgs === void 0) { applyArgs = null; }\n if (source === void 0) { source = null; }\n _currentZoneFrame = { parent: _currentZoneFrame, zone: this };\n try {\n return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source);\n }\n finally {\n _currentZoneFrame = _currentZoneFrame.parent;\n }\n };\n Zone.prototype.runGuarded = function (callback, applyThis, applyArgs, source) {\n if (applyThis === void 0) { applyThis = null; }\n if (applyArgs === void 0) { applyArgs = null; }\n if (source === void 0) { source = null; }\n _currentZoneFrame = { parent: _currentZoneFrame, zone: this };\n try {\n try {\n return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source);\n }\n catch (error) {\n if (this._zoneDelegate.handleError(this, error)) {\n throw error;\n }\n }\n }\n finally {\n _currentZoneFrame = _currentZoneFrame.parent;\n }\n };\n Zone.prototype.runTask = function (task, applyThis, applyArgs) {\n if (task.zone != this) {\n throw new Error('A task can only be run in the zone of creation! (Creation: ' +\n (task.zone || NO_ZONE).name + '; Execution: ' + this.name + ')');\n }\n // https://github.com/angular/zone.js/issues/778, sometimes eventTask\n // will run in notScheduled(canceled) state, we should not try to\n // run such kind of task but just return\n // we have to define an variable here, if not\n // typescript compiler will complain below\n var isNotScheduled = task.state === notScheduled;\n if (isNotScheduled && task.type === eventTask) {\n return;\n }\n var reEntryGuard = task.state != running;\n reEntryGuard && task._transitionTo(running, scheduled);\n task.runCount++;\n var previousTask = _currentTask;\n _currentTask = task;\n _currentZoneFrame = { parent: _currentZoneFrame, zone: this };\n try {\n if (task.type == macroTask && task.data && !task.data.isPeriodic) {\n task.cancelFn = null;\n }\n try {\n return this._zoneDelegate.invokeTask(this, task, applyThis, applyArgs);\n }\n catch (error) {\n if (this._zoneDelegate.handleError(this, error)) {\n throw error;\n }\n }\n }\n finally {\n // if the task's state is notScheduled or unknown, then it has already been cancelled\n // we should not reset the state to scheduled\n if (task.state !== notScheduled && task.state !== unknown) {\n if (task.type == eventTask || (task.data && task.data.isPeriodic)) {\n reEntryGuard && task._transitionTo(scheduled, running);\n }\n else {\n task.runCount = 0;\n this._updateTaskCount(task, -1);\n reEntryGuard &&\n task._transitionTo(notScheduled, running, notScheduled);\n }\n }\n _currentZoneFrame = _currentZoneFrame.parent;\n _currentTask = previousTask;\n }\n };\n Zone.prototype.scheduleTask = function (task) {\n if (task.zone && task.zone !== this) {\n // check if the task was rescheduled, the newZone\n // should not be the children of the original zone\n var newZone = this;\n while (newZone) {\n if (newZone === task.zone) {\n throw Error(\"can not reschedule task to \" + this\n .name + \" which is descendants of the original zone \" + task.zone.name);\n }\n newZone = newZone.parent;\n }\n }\n task._transitionTo(scheduling, notScheduled);\n var zoneDelegates = [];\n task._zoneDelegates = zoneDelegates;\n task._zone = this;\n try {\n task = this._zoneDelegate.scheduleTask(this, task);\n }\n catch (err) {\n // should set task's state to unknown when scheduleTask throw error\n // because the err may from reschedule, so the fromState maybe notScheduled\n task._transitionTo(unknown, scheduling, notScheduled);\n // TODO: @JiaLiPassion, should we check the result from handleError?\n this._zoneDelegate.handleError(this, err);\n throw err;\n }\n if (task._zoneDelegates === zoneDelegates) {\n // we have to check because internally the delegate can reschedule the task.\n this._updateTaskCount(task, 1);\n }\n if (task.state == scheduling) {\n task._transitionTo(scheduled, scheduling);\n }\n return task;\n };\n Zone.prototype.scheduleMicroTask = function (source, callback, data, customSchedule) {\n return this.scheduleTask(new ZoneTask(microTask, source, callback, data, customSchedule, null));\n };\n Zone.prototype.scheduleMacroTask = function (source, callback, data, customSchedule, customCancel) {\n return this.scheduleTask(new ZoneTask(macroTask, source, callback, data, customSchedule, customCancel));\n };\n Zone.prototype.scheduleEventTask = function (source, callback, data, customSchedule, customCancel) {\n return this.scheduleTask(new ZoneTask(eventTask, source, callback, data, customSchedule, customCancel));\n };\n Zone.prototype.cancelTask = function (task) {\n if (task.zone != this)\n throw new Error('A task can only be cancelled in the zone of creation! (Creation: ' +\n (task.zone || NO_ZONE).name + '; Execution: ' + this.name + ')');\n task._transitionTo(canceling, scheduled, running);\n try {\n this._zoneDelegate.cancelTask(this, task);\n }\n catch (err) {\n // if error occurs when cancelTask, transit the state to unknown\n task._transitionTo(unknown, canceling);\n this._zoneDelegate.handleError(this, err);\n throw err;\n }\n this._updateTaskCount(task, -1);\n task._transitionTo(notScheduled, canceling);\n task.runCount = 0;\n return task;\n };\n Zone.prototype._updateTaskCount = function (task, count) {\n var zoneDelegates = task._zoneDelegates;\n if (count == -1) {\n task._zoneDelegates = null;\n }\n for (var i = 0; i < zoneDelegates.length; i++) {\n zoneDelegates[i]._updateTaskCount(task.type, count);\n }\n };\n Zone.__symbol__ = __symbol__;\n return Zone;\n }());\n var DELEGATE_ZS = {\n name: '',\n onHasTask: function (delegate, _, target, hasTaskState) {\n return delegate.hasTask(target, hasTaskState);\n },\n onScheduleTask: function (delegate, _, target, task) {\n return delegate.scheduleTask(target, task);\n },\n onInvokeTask: function (delegate, _, target, task, applyThis, applyArgs) { return delegate.invokeTask(target, task, applyThis, applyArgs); },\n onCancelTask: function (delegate, _, target, task) {\n return delegate.cancelTask(target, task);\n }\n };\n var ZoneDelegate = /** @class */ (function () {\n function ZoneDelegate(zone, parentDelegate, zoneSpec) {\n this._taskCounts = { 'microTask': 0, 'macroTask': 0, 'eventTask': 0 };\n this.zone = zone;\n this._parentDelegate = parentDelegate;\n this._forkZS = zoneSpec && (zoneSpec && zoneSpec.onFork ? zoneSpec : parentDelegate._forkZS);\n this._forkDlgt = zoneSpec && (zoneSpec.onFork ? parentDelegate : parentDelegate._forkDlgt);\n this._forkCurrZone = zoneSpec && (zoneSpec.onFork ? this.zone : parentDelegate.zone);\n this._interceptZS =\n zoneSpec && (zoneSpec.onIntercept ? zoneSpec : parentDelegate._interceptZS);\n this._interceptDlgt =\n zoneSpec && (zoneSpec.onIntercept ? parentDelegate : parentDelegate._interceptDlgt);\n this._interceptCurrZone =\n zoneSpec && (zoneSpec.onIntercept ? this.zone : parentDelegate.zone);\n this._invokeZS = zoneSpec && (zoneSpec.onInvoke ? zoneSpec : parentDelegate._invokeZS);\n this._invokeDlgt =\n zoneSpec && (zoneSpec.onInvoke ? parentDelegate : parentDelegate._invokeDlgt);\n this._invokeCurrZone = zoneSpec && (zoneSpec.onInvoke ? this.zone : parentDelegate.zone);\n this._handleErrorZS =\n zoneSpec && (zoneSpec.onHandleError ? zoneSpec : parentDelegate._handleErrorZS);\n this._handleErrorDlgt =\n zoneSpec && (zoneSpec.onHandleError ? parentDelegate : parentDelegate._handleErrorDlgt);\n this._handleErrorCurrZone =\n zoneSpec && (zoneSpec.onHandleError ? this.zone : parentDelegate.zone);\n this._scheduleTaskZS =\n zoneSpec && (zoneSpec.onScheduleTask ? zoneSpec : parentDelegate._scheduleTaskZS);\n this._scheduleTaskDlgt =\n zoneSpec && (zoneSpec.onScheduleTask ? parentDelegate : parentDelegate._scheduleTaskDlgt);\n this._scheduleTaskCurrZone =\n zoneSpec && (zoneSpec.onScheduleTask ? this.zone : parentDelegate.zone);\n this._invokeTaskZS =\n zoneSpec && (zoneSpec.onInvokeTask ? zoneSpec : parentDelegate._invokeTaskZS);\n this._invokeTaskDlgt =\n zoneSpec && (zoneSpec.onInvokeTask ? parentDelegate : parentDelegate._invokeTaskDlgt);\n this._invokeTaskCurrZone =\n zoneSpec && (zoneSpec.onInvokeTask ? this.zone : parentDelegate.zone);\n this._cancelTaskZS =\n zoneSpec && (zoneSpec.onCancelTask ? zoneSpec : parentDelegate._cancelTaskZS);\n this._cancelTaskDlgt =\n zoneSpec && (zoneSpec.onCancelTask ? parentDelegate : parentDelegate._cancelTaskDlgt);\n this._cancelTaskCurrZone =\n zoneSpec && (zoneSpec.onCancelTask ? this.zone : parentDelegate.zone);\n this._hasTaskZS = null;\n this._hasTaskDlgt = null;\n this._hasTaskDlgtOwner = null;\n this._hasTaskCurrZone = null;\n var zoneSpecHasTask = zoneSpec && zoneSpec.onHasTask;\n var parentHasTask = parentDelegate && parentDelegate._hasTaskZS;\n if (zoneSpecHasTask || parentHasTask) {\n // If we need to report hasTask, than this ZS needs to do ref counting on tasks. In such\n // a case all task related interceptors must go through this ZD. We can't short circuit it.\n this._hasTaskZS = zoneSpecHasTask ? zoneSpec : DELEGATE_ZS;\n this._hasTaskDlgt = parentDelegate;\n this._hasTaskDlgtOwner = this;\n this._hasTaskCurrZone = zone;\n if (!zoneSpec.onScheduleTask) {\n this._scheduleTaskZS = DELEGATE_ZS;\n this._scheduleTaskDlgt = parentDelegate;\n this._scheduleTaskCurrZone = this.zone;\n }\n if (!zoneSpec.onInvokeTask) {\n this._invokeTaskZS = DELEGATE_ZS;\n this._invokeTaskDlgt = parentDelegate;\n this._invokeTaskCurrZone = this.zone;\n }\n if (!zoneSpec.onCancelTask) {\n this._cancelTaskZS = DELEGATE_ZS;\n this._cancelTaskDlgt = parentDelegate;\n this._cancelTaskCurrZone = this.zone;\n }\n }\n }\n ZoneDelegate.prototype.fork = function (targetZone, zoneSpec) {\n return this._forkZS ? this._forkZS.onFork(this._forkDlgt, this.zone, targetZone, zoneSpec) :\n new Zone(targetZone, zoneSpec);\n };\n ZoneDelegate.prototype.intercept = function (targetZone, callback, source) {\n return this._interceptZS ?\n this._interceptZS.onIntercept(this._interceptDlgt, this._interceptCurrZone, targetZone, callback, source) :\n callback;\n };\n ZoneDelegate.prototype.invoke = function (targetZone, callback, applyThis, applyArgs, source) {\n return this._invokeZS ?\n this._invokeZS.onInvoke(this._invokeDlgt, this._invokeCurrZone, targetZone, callback, applyThis, applyArgs, source) :\n callback.apply(applyThis, applyArgs);\n };\n ZoneDelegate.prototype.handleError = function (targetZone, error) {\n return this._handleErrorZS ?\n this._handleErrorZS.onHandleError(this._handleErrorDlgt, this._handleErrorCurrZone, targetZone, error) :\n true;\n };\n ZoneDelegate.prototype.scheduleTask = function (targetZone, task) {\n var returnTask = task;\n if (this._scheduleTaskZS) {\n if (this._hasTaskZS) {\n returnTask._zoneDelegates.push(this._hasTaskDlgtOwner);\n }\n returnTask = this._scheduleTaskZS.onScheduleTask(this._scheduleTaskDlgt, this._scheduleTaskCurrZone, targetZone, task);\n if (!returnTask)\n returnTask = task;\n }\n else {\n if (task.scheduleFn) {\n task.scheduleFn(task);\n }\n else if (task.type == microTask) {\n scheduleMicroTask(task);\n }\n else {\n throw new Error('Task is missing scheduleFn.');\n }\n }\n return returnTask;\n };\n ZoneDelegate.prototype.invokeTask = function (targetZone, task, applyThis, applyArgs) {\n return this._invokeTaskZS ?\n this._invokeTaskZS.onInvokeTask(this._invokeTaskDlgt, this._invokeTaskCurrZone, targetZone, task, applyThis, applyArgs) :\n task.callback.apply(applyThis, applyArgs);\n };\n ZoneDelegate.prototype.cancelTask = function (targetZone, task) {\n var value;\n if (this._cancelTaskZS) {\n value = this._cancelTaskZS.onCancelTask(this._cancelTaskDlgt, this._cancelTaskCurrZone, targetZone, task);\n }\n else {\n if (!task.cancelFn) {\n throw Error('Task is not cancelable');\n }\n value = task.cancelFn(task);\n }\n return value;\n };\n ZoneDelegate.prototype.hasTask = function (targetZone, isEmpty) {\n // hasTask should not throw error so other ZoneDelegate\n // can still trigger hasTask callback\n try {\n return this._hasTaskZS &&\n this._hasTaskZS.onHasTask(this._hasTaskDlgt, this._hasTaskCurrZone, targetZone, isEmpty);\n }\n catch (err) {\n this.handleError(targetZone, err);\n }\n };\n ZoneDelegate.prototype._updateTaskCount = function (type, count) {\n var counts = this._taskCounts;\n var prev = counts[type];\n var next = counts[type] = prev + count;\n if (next < 0) {\n throw new Error('More tasks executed then were scheduled.');\n }\n if (prev == 0 || next == 0) {\n var isEmpty = {\n microTask: counts['microTask'] > 0,\n macroTask: counts['macroTask'] > 0,\n eventTask: counts['eventTask'] > 0,\n change: type\n };\n this.hasTask(this.zone, isEmpty);\n }\n };\n return ZoneDelegate;\n }());\n var ZoneTask = /** @class */ (function () {\n function ZoneTask(type, source, callback, options, scheduleFn, cancelFn) {\n this._zone = null;\n this.runCount = 0;\n this._zoneDelegates = null;\n this._state = 'notScheduled';\n this.type = type;\n this.source = source;\n this.data = options;\n this.scheduleFn = scheduleFn;\n this.cancelFn = cancelFn;\n this.callback = callback;\n var self = this;\n // TODO: @JiaLiPassion options should have interface\n if (type === eventTask && options && options.useG) {\n this.invoke = ZoneTask.invokeTask;\n }\n else {\n this.invoke = function () {\n return ZoneTask.invokeTask.call(global, self, this, arguments);\n };\n }\n }\n ZoneTask.invokeTask = function (task, target, args) {\n if (!task) {\n task = this;\n }\n _numberOfNestedTaskFrames++;\n try {\n task.runCount++;\n return task.zone.runTask(task, target, args);\n }\n finally {\n if (_numberOfNestedTaskFrames == 1) {\n drainMicroTaskQueue();\n }\n _numberOfNestedTaskFrames--;\n }\n };\n Object.defineProperty(ZoneTask.prototype, \"zone\", {\n get: function () {\n return this._zone;\n },\n enumerable: true,\n configurable: true\n });\n Object.defineProperty(ZoneTask.prototype, \"state\", {\n get: function () {\n return this._state;\n },\n enumerable: true,\n configurable: true\n });\n ZoneTask.prototype.cancelScheduleRequest = function () {\n this._transitionTo(notScheduled, scheduling);\n };\n ZoneTask.prototype._transitionTo = function (toState, fromState1, fromState2) {\n if (this._state === fromState1 || this._state === fromState2) {\n this._state = toState;\n if (toState == notScheduled) {\n this._zoneDelegates = null;\n }\n }\n else {\n throw new Error(this.type + \" '\" + this.source + \"': can not transition to '\" + toState + \"', expecting state '\" + fromState1 + \"'\" + (fromState2 ?\n ' or \\'' + fromState2 + '\\'' :\n '') + \", was '\" + this._state + \"'.\");\n }\n };\n ZoneTask.prototype.toString = function () {\n if (this.data && typeof this.data.handleId !== 'undefined') {\n return this.data.handleId;\n }\n else {\n return Object.prototype.toString.call(this);\n }\n };\n // add toJSON method to prevent cyclic error when\n // call JSON.stringify(zoneTask)\n ZoneTask.prototype.toJSON = function () {\n return {\n type: this.type,\n state: this.state,\n source: this.source,\n zone: this.zone.name,\n runCount: this.runCount\n };\n };\n return ZoneTask;\n }());\n //////////////////////////////////////////////////////\n //////////////////////////////////////////////////////\n /// MICROTASK QUEUE\n //////////////////////////////////////////////////////\n //////////////////////////////////////////////////////\n var symbolSetTimeout = __symbol__('setTimeout');\n var symbolPromise = __symbol__('Promise');\n var symbolThen = __symbol__('then');\n var _microTaskQueue = [];\n var _isDrainingMicrotaskQueue = false;\n var nativeMicroTaskQueuePromise;\n function scheduleMicroTask(task) {\n // if we are not running in any task, and there has not been anything scheduled\n // we must bootstrap the initial task creation by manually scheduling the drain\n if (_numberOfNestedTaskFrames === 0 && _microTaskQueue.length === 0) {\n // We are not running in Task, so we need to kickstart the microtask queue.\n if (!nativeMicroTaskQueuePromise) {\n if (global[symbolPromise]) {\n nativeMicroTaskQueuePromise = global[symbolPromise].resolve(0);\n }\n }\n if (nativeMicroTaskQueuePromise) {\n nativeMicroTaskQueuePromise[symbolThen](drainMicroTaskQueue);\n }\n else {\n global[symbolSetTimeout](drainMicroTaskQueue, 0);\n }\n }\n task && _microTaskQueue.push(task);\n }\n function drainMicroTaskQueue() {\n if (!_isDrainingMicrotaskQueue) {\n _isDrainingMicrotaskQueue = true;\n while (_microTaskQueue.length) {\n var queue = _microTaskQueue;\n _microTaskQueue = [];\n for (var i = 0; i < queue.length; i++) {\n var task = queue[i];\n try {\n task.zone.runTask(task, null, null);\n }\n catch (error) {\n _api.onUnhandledError(error);\n }\n }\n }\n _api.microtaskDrainDone();\n _isDrainingMicrotaskQueue = false;\n }\n }\n //////////////////////////////////////////////////////\n //////////////////////////////////////////////////////\n /// BOOTSTRAP\n //////////////////////////////////////////////////////\n //////////////////////////////////////////////////////\n var NO_ZONE = { name: 'NO ZONE' };\n var notScheduled = 'notScheduled', scheduling = 'scheduling', scheduled = 'scheduled', running = 'running', canceling = 'canceling', unknown = 'unknown';\n var microTask = 'microTask', macroTask = 'macroTask', eventTask = 'eventTask';\n var patches = {};\n var _api = {\n symbol: __symbol__,\n currentZoneFrame: function () { return _currentZoneFrame; },\n onUnhandledError: noop,\n microtaskDrainDone: noop,\n scheduleMicroTask: scheduleMicroTask,\n showUncaughtError: function () { return !Zone[__symbol__('ignoreConsoleErrorUncaughtError')]; },\n patchEventTarget: function () { return []; },\n patchOnProperties: noop,\n patchMethod: function () { return noop; },\n bindArguments: function () { return null; },\n setNativePromise: function (NativePromise) {\n // sometimes NativePromise.resolve static function\n // is not ready yet, (such as core-js/es6.promise)\n // so we need to check here.\n if (NativePromise && typeof NativePromise.resolve === FUNCTION) {\n nativeMicroTaskQueuePromise = NativePromise.resolve(0);\n }\n },\n };\n var _currentZoneFrame = { parent: null, zone: new Zone(null, null) };\n var _currentTask = null;\n var _numberOfNestedTaskFrames = 0;\n function noop() { }\n function __symbol__(name) {\n return '__zone_symbol__' + name;\n }\n performanceMeasure('Zone', 'Zone');\n return global['Zone'] = Zone;\n})(typeof window !== 'undefined' && window || typeof self !== 'undefined' && self || global);\n\nZone.__load_patch('ZoneAwarePromise', function (global, Zone, api) {\n var ObjectGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;\n var ObjectDefineProperty = Object.defineProperty;\n function readableObjectToString(obj) {\n if (obj && obj.toString === Object.prototype.toString) {\n var className = obj.constructor && obj.constructor.name;\n return (className ? className : '') + ': ' + JSON.stringify(obj);\n }\n return obj ? obj.toString() : Object.prototype.toString.call(obj);\n }\n var __symbol__ = api.symbol;\n var _uncaughtPromiseErrors = [];\n var symbolPromise = __symbol__('Promise');\n var symbolThen = __symbol__('then');\n var creationTrace = '__creationTrace__';\n api.onUnhandledError = function (e) {\n if (api.showUncaughtError()) {\n var rejection = e && e.rejection;\n if (rejection) {\n console.error('Unhandled Promise rejection:', rejection instanceof Error ? rejection.message : rejection, '; Zone:', e.zone.name, '; Task:', e.task && e.task.source, '; Value:', rejection, rejection instanceof Error ? rejection.stack : undefined);\n }\n else {\n console.error(e);\n }\n }\n };\n api.microtaskDrainDone = function () {\n while (_uncaughtPromiseErrors.length) {\n var _loop_1 = function () {\n var uncaughtPromiseError = _uncaughtPromiseErrors.shift();\n try {\n uncaughtPromiseError.zone.runGuarded(function () {\n throw uncaughtPromiseError;\n });\n }\n catch (error) {\n handleUnhandledRejection(error);\n }\n };\n while (_uncaughtPromiseErrors.length) {\n _loop_1();\n }\n }\n };\n var UNHANDLED_PROMISE_REJECTION_HANDLER_SYMBOL = __symbol__('unhandledPromiseRejectionHandler');\n function handleUnhandledRejection(e) {\n api.onUnhandledError(e);\n try {\n var handler = Zone[UNHANDLED_PROMISE_REJECTION_HANDLER_SYMBOL];\n if (handler && typeof handler === 'function') {\n handler.call(this, e);\n }\n }\n catch (err) {\n }\n }\n function isThenable(value) {\n return value && value.then;\n }\n function forwardResolution(value) {\n return value;\n }\n function forwardRejection(rejection) {\n return ZoneAwarePromise.reject(rejection);\n }\n var symbolState = __symbol__('state');\n var symbolValue = __symbol__('value');\n var symbolFinally = __symbol__('finally');\n var symbolParentPromiseValue = __symbol__('parentPromiseValue');\n var symbolParentPromiseState = __symbol__('parentPromiseState');\n var source = 'Promise.then';\n var UNRESOLVED = null;\n var RESOLVED = true;\n var REJECTED = false;\n var REJECTED_NO_CATCH = 0;\n function makeResolver(promise, state) {\n return function (v) {\n try {\n resolvePromise(promise, state, v);\n }\n catch (err) {\n resolvePromise(promise, false, err);\n }\n // Do not return value or you will break the Promise spec.\n };\n }\n var once = function () {\n var wasCalled = false;\n return function wrapper(wrappedFunction) {\n return function () {\n if (wasCalled) {\n return;\n }\n wasCalled = true;\n wrappedFunction.apply(null, arguments);\n };\n };\n };\n var TYPE_ERROR = 'Promise resolved with itself';\n var CURRENT_TASK_TRACE_SYMBOL = __symbol__('currentTaskTrace');\n // Promise Resolution\n function resolvePromise(promise, state, value) {\n var onceWrapper = once();\n if (promise === value) {\n throw new TypeError(TYPE_ERROR);\n }\n if (promise[symbolState] === UNRESOLVED) {\n // should only get value.then once based on promise spec.\n var then = null;\n try {\n if (typeof value === 'object' || typeof value === 'function') {\n then = value && value.then;\n }\n }\n catch (err) {\n onceWrapper(function () {\n resolvePromise(promise, false, err);\n })();\n return promise;\n }\n // if (value instanceof ZoneAwarePromise) {\n if (state !== REJECTED && value instanceof ZoneAwarePromise &&\n value.hasOwnProperty(symbolState) && value.hasOwnProperty(symbolValue) &&\n value[symbolState] !== UNRESOLVED) {\n clearRejectedNoCatch(value);\n resolvePromise(promise, value[symbolState], value[symbolValue]);\n }\n else if (state !== REJECTED && typeof then === 'function') {\n try {\n then.call(value, onceWrapper(makeResolver(promise, state)), onceWrapper(makeResolver(promise, false)));\n }\n catch (err) {\n onceWrapper(function () {\n resolvePromise(promise, false, err);\n })();\n }\n }\n else {\n promise[symbolState] = state;\n var queue = promise[symbolValue];\n promise[symbolValue] = value;\n if (promise[symbolFinally] === symbolFinally) {\n // the promise is generated by Promise.prototype.finally \n if (state === RESOLVED) {\n // the state is resolved, should ignore the value\n // and use parent promise value\n promise[symbolState] = promise[symbolParentPromiseState];\n promise[symbolValue] = promise[symbolParentPromiseValue];\n }\n }\n // record task information in value when error occurs, so we can\n // do some additional work such as render longStackTrace\n if (state === REJECTED && value instanceof Error) {\n // check if longStackTraceZone is here\n var trace = Zone.currentTask && Zone.currentTask.data &&\n Zone.currentTask.data[creationTrace];\n if (trace) {\n // only keep the long stack trace into error when in longStackTraceZone\n ObjectDefineProperty(value, CURRENT_TASK_TRACE_SYMBOL, { configurable: true, enumerable: false, writable: true, value: trace });\n }\n }\n for (var i = 0; i < queue.length;) {\n scheduleResolveOrReject(promise, queue[i++], queue[i++], queue[i++], queue[i++]);\n }\n if (queue.length == 0 && state == REJECTED) {\n promise[symbolState] = REJECTED_NO_CATCH;\n try {\n // try to print more readable error log\n throw new Error('Uncaught (in promise): ' + readableObjectToString(value) +\n (value && value.stack ? '\\n' + value.stack : ''));\n }\n catch (err) {\n var error_1 = err;\n error_1.rejection = value;\n error_1.promise = promise;\n error_1.zone = Zone.current;\n error_1.task = Zone.currentTask;\n _uncaughtPromiseErrors.push(error_1);\n api.scheduleMicroTask(); // to make sure that it is running\n }\n }\n }\n }\n // Resolving an already resolved promise is a noop.\n return promise;\n }\n var REJECTION_HANDLED_HANDLER = __symbol__('rejectionHandledHandler');\n function clearRejectedNoCatch(promise) {\n if (promise[symbolState] === REJECTED_NO_CATCH) {\n // if the promise is rejected no catch status\n // and queue.length > 0, means there is a error handler\n // here to handle the rejected promise, we should trigger\n // windows.rejectionhandled eventHandler or nodejs rejectionHandled\n // eventHandler\n try {\n var handler = Zone[REJECTION_HANDLED_HANDLER];\n if (handler && typeof handler === 'function') {\n handler.call(this, { rejection: promise[symbolValue], promise: promise });\n }\n }\n catch (err) {\n }\n promise[symbolState] = REJECTED;\n for (var i = 0; i < _uncaughtPromiseErrors.length; i++) {\n if (promise === _uncaughtPromiseErrors[i].promise) {\n _uncaughtPromiseErrors.splice(i, 1);\n }\n }\n }\n }\n function scheduleResolveOrReject(promise, zone, chainPromise, onFulfilled, onRejected) {\n clearRejectedNoCatch(promise);\n var promiseState = promise[symbolState];\n var delegate = promiseState ?\n (typeof onFulfilled === 'function') ? onFulfilled : forwardResolution :\n (typeof onRejected === 'function') ? onRejected : forwardRejection;\n zone.scheduleMicroTask(source, function () {\n try {\n var parentPromiseValue = promise[symbolValue];\n var isFinallyPromise = chainPromise && symbolFinally === chainPromise[symbolFinally];\n if (isFinallyPromise) {\n // if the promise is generated from finally call, keep parent promise's state and value\n chainPromise[symbolParentPromiseValue] = parentPromiseValue;\n chainPromise[symbolParentPromiseState] = promiseState;\n }\n // should not pass value to finally callback\n var value = zone.run(delegate, undefined, isFinallyPromise && delegate !== forwardRejection && delegate !== forwardResolution ? [] : [parentPromiseValue]);\n resolvePromise(chainPromise, true, value);\n }\n catch (error) {\n // if error occurs, should always return this error\n resolvePromise(chainPromise, false, error);\n }\n }, chainPromise);\n }\n var ZONE_AWARE_PROMISE_TO_STRING = 'function ZoneAwarePromise() { [native code] }';\n var ZoneAwarePromise = /** @class */ (function () {\n function ZoneAwarePromise(executor) {\n var promise = this;\n if (!(promise instanceof ZoneAwarePromise)) {\n throw new Error('Must be an instanceof Promise.');\n }\n promise[symbolState] = UNRESOLVED;\n promise[symbolValue] = []; // queue;\n try {\n executor && executor(makeResolver(promise, RESOLVED), makeResolver(promise, REJECTED));\n }\n catch (error) {\n resolvePromise(promise, false, error);\n }\n }\n ZoneAwarePromise.toString = function () {\n return ZONE_AWARE_PROMISE_TO_STRING;\n };\n ZoneAwarePromise.resolve = function (value) {\n return resolvePromise(new this(null), RESOLVED, value);\n };\n ZoneAwarePromise.reject = function (error) {\n return resolvePromise(new this(null), REJECTED, error);\n };\n ZoneAwarePromise.race = function (values) {\n var resolve;\n var reject;\n var promise = new this(function (res, rej) {\n resolve = res;\n reject = rej;\n });\n function onResolve(value) {\n promise && (promise = null || resolve(value));\n }\n function onReject(error) {\n promise && (promise = null || reject(error));\n }\n for (var _i = 0, values_1 = values; _i < values_1.length; _i++) {\n var value = values_1[_i];\n if (!isThenable(value)) {\n value = this.resolve(value);\n }\n value.then(onResolve, onReject);\n }\n return promise;\n };\n ZoneAwarePromise.all = function (values) {\n var resolve;\n var reject;\n var promise = new this(function (res, rej) {\n resolve = res;\n reject = rej;\n });\n var count = 0;\n var resolvedValues = [];\n for (var _i = 0, values_2 = values; _i < values_2.length; _i++) {\n var value = values_2[_i];\n if (!isThenable(value)) {\n value = this.resolve(value);\n }\n value.then((function (index) { return function (value) {\n resolvedValues[index] = value;\n count--;\n if (!count) {\n resolve(resolvedValues);\n }\n }; })(count), reject);\n count++;\n }\n if (!count)\n resolve(resolvedValues);\n return promise;\n };\n ZoneAwarePromise.prototype.then = function (onFulfilled, onRejected) {\n var chainPromise = new this.constructor(null);\n var zone = Zone.current;\n if (this[symbolState] == UNRESOLVED) {\n this[symbolValue].push(zone, chainPromise, onFulfilled, onRejected);\n }\n else {\n scheduleResolveOrReject(this, zone, chainPromise, onFulfilled, onRejected);\n }\n return chainPromise;\n };\n ZoneAwarePromise.prototype.catch = function (onRejected) {\n return this.then(null, onRejected);\n };\n ZoneAwarePromise.prototype.finally = function (onFinally) {\n var chainPromise = new this.constructor(null);\n chainPromise[symbolFinally] = symbolFinally;\n var zone = Zone.current;\n if (this[symbolState] == UNRESOLVED) {\n this[symbolValue].push(zone, chainPromise, onFinally, onFinally);\n }\n else {\n scheduleResolveOrReject(this, zone, chainPromise, onFinally, onFinally);\n }\n return chainPromise;\n };\n return ZoneAwarePromise;\n }());\n // Protect against aggressive optimizers dropping seemingly unused properties.\n // E.g. Closure Compiler in advanced mode.\n ZoneAwarePromise['resolve'] = ZoneAwarePromise.resolve;\n ZoneAwarePromise['reject'] = ZoneAwarePromise.reject;\n ZoneAwarePromise['race'] = ZoneAwarePromise.race;\n ZoneAwarePromise['all'] = ZoneAwarePromise.all;\n var NativePromise = global[symbolPromise] = global['Promise'];\n var ZONE_AWARE_PROMISE = Zone.__symbol__('ZoneAwarePromise');\n var desc = ObjectGetOwnPropertyDescriptor(global, 'Promise');\n if (!desc || desc.configurable) {\n desc && delete desc.writable;\n desc && delete desc.value;\n if (!desc) {\n desc = { configurable: true, enumerable: true };\n }\n desc.get = function () {\n // if we already set ZoneAwarePromise, use patched one\n // otherwise return native one.\n return global[ZONE_AWARE_PROMISE] ? global[ZONE_AWARE_PROMISE] : global[symbolPromise];\n };\n desc.set = function (NewNativePromise) {\n if (NewNativePromise === ZoneAwarePromise) {\n // if the NewNativePromise is ZoneAwarePromise\n // save to global\n global[ZONE_AWARE_PROMISE] = NewNativePromise;\n }\n else {\n // if the NewNativePromise is not ZoneAwarePromise\n // for example: after load zone.js, some library just\n // set es6-promise to global, if we set it to global\n // directly, assertZonePatched will fail and angular\n // will not loaded, so we just set the NewNativePromise\n // to global[symbolPromise], so the result is just like\n // we load ES6 Promise before zone.js\n global[symbolPromise] = NewNativePromise;\n if (!NewNativePromise.prototype[symbolThen]) {\n patchThen(NewNativePromise);\n }\n api.setNativePromise(NewNativePromise);\n }\n };\n ObjectDefineProperty(global, 'Promise', desc);\n }\n global['Promise'] = ZoneAwarePromise;\n var symbolThenPatched = __symbol__('thenPatched');\n function patchThen(Ctor) {\n var proto = Ctor.prototype;\n var prop = ObjectGetOwnPropertyDescriptor(proto, 'then');\n if (prop && (prop.writable === false || !prop.configurable)) {\n // check Ctor.prototype.then propertyDescriptor is writable or not\n // in meteor env, writable is false, we should ignore such case\n return;\n }\n var originalThen = proto.then;\n // Keep a reference to the original method.\n proto[symbolThen] = originalThen;\n Ctor.prototype.then = function (onResolve, onReject) {\n var _this = this;\n var wrapped = new ZoneAwarePromise(function (resolve, reject) {\n originalThen.call(_this, resolve, reject);\n });\n return wrapped.then(onResolve, onReject);\n };\n Ctor[symbolThenPatched] = true;\n }\n function zoneify(fn) {\n return function () {\n var resultPromise = fn.apply(this, arguments);\n if (resultPromise instanceof ZoneAwarePromise) {\n return resultPromise;\n }\n var ctor = resultPromise.constructor;\n if (!ctor[symbolThenPatched]) {\n patchThen(ctor);\n }\n return resultPromise;\n };\n }\n if (NativePromise) {\n patchThen(NativePromise);\n var fetch_1 = global['fetch'];\n if (typeof fetch_1 == 'function') {\n global['fetch'] = zoneify(fetch_1);\n }\n }\n // This is not part of public API, but it is useful for tests, so we expose it.\n Promise[Zone.__symbol__('uncaughtPromiseErrors')] = _uncaughtPromiseErrors;\n return ZoneAwarePromise;\n});\n\n/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\n/**\n * Suppress closure compiler errors about unknown 'Zone' variable\n * @fileoverview\n * @suppress {undefinedVars,globalThis,missingRequire}\n */\n// issue #989, to reduce bundle size, use short name\n/** Object.getOwnPropertyDescriptor */\nvar ObjectGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;\n/** Object.defineProperty */\nvar ObjectDefineProperty = Object.defineProperty;\n/** Object.getPrototypeOf */\nvar ObjectGetPrototypeOf = Object.getPrototypeOf;\n/** Object.create */\nvar ObjectCreate = Object.create;\n/** Array.prototype.slice */\nvar ArraySlice = Array.prototype.slice;\n/** addEventListener string const */\nvar ADD_EVENT_LISTENER_STR = 'addEventListener';\n/** removeEventListener string const */\nvar REMOVE_EVENT_LISTENER_STR = 'removeEventListener';\n/** zoneSymbol addEventListener */\nvar ZONE_SYMBOL_ADD_EVENT_LISTENER = Zone.__symbol__(ADD_EVENT_LISTENER_STR);\n/** zoneSymbol removeEventListener */\nvar ZONE_SYMBOL_REMOVE_EVENT_LISTENER = Zone.__symbol__(REMOVE_EVENT_LISTENER_STR);\n/** true string const */\nvar TRUE_STR = 'true';\n/** false string const */\nvar FALSE_STR = 'false';\n/** __zone_symbol__ string const */\nvar ZONE_SYMBOL_PREFIX = '__zone_symbol__';\nfunction wrapWithCurrentZone(callback, source) {\n return Zone.current.wrap(callback, source);\n}\nfunction scheduleMacroTaskWithCurrentZone(source, callback, data, customSchedule, customCancel) {\n return Zone.current.scheduleMacroTask(source, callback, data, customSchedule, customCancel);\n}\nvar zoneSymbol = Zone.__symbol__;\nvar isWindowExists = typeof window !== 'undefined';\nvar internalWindow = isWindowExists ? window : undefined;\nvar _global = isWindowExists && internalWindow || typeof self === 'object' && self || global;\nvar REMOVE_ATTRIBUTE = 'removeAttribute';\nvar NULL_ON_PROP_VALUE = [null];\nfunction bindArguments(args, source) {\n for (var i = args.length - 1; i >= 0; i--) {\n if (typeof args[i] === 'function') {\n args[i] = wrapWithCurrentZone(args[i], source + '_' + i);\n }\n }\n return args;\n}\nfunction patchPrototype(prototype, fnNames) {\n var source = prototype.constructor['name'];\n var _loop_1 = function (i) {\n var name_1 = fnNames[i];\n var delegate = prototype[name_1];\n if (delegate) {\n var prototypeDesc = ObjectGetOwnPropertyDescriptor(prototype, name_1);\n if (!isPropertyWritable(prototypeDesc)) {\n return \"continue\";\n }\n prototype[name_1] = (function (delegate) {\n var patched = function () {\n return delegate.apply(this, bindArguments(arguments, source + '.' + name_1));\n };\n attachOriginToPatched(patched, delegate);\n return patched;\n })(delegate);\n }\n };\n for (var i = 0; i < fnNames.length; i++) {\n _loop_1(i);\n }\n}\nfunction isPropertyWritable(propertyDesc) {\n if (!propertyDesc) {\n return true;\n }\n if (propertyDesc.writable === false) {\n return false;\n }\n return !(typeof propertyDesc.get === 'function' && typeof propertyDesc.set === 'undefined');\n}\nvar isWebWorker = (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope);\n// Make sure to access `process` through `_global` so that WebPack does not accidentally browserify\n// this code.\nvar isNode = (!('nw' in _global) && typeof _global.process !== 'undefined' &&\n {}.toString.call(_global.process) === '[object process]');\nvar isBrowser = !isNode && !isWebWorker && !!(isWindowExists && internalWindow['HTMLElement']);\n// we are in electron of nw, so we are both browser and nodejs\n// Make sure to access `process` through `_global` so that WebPack does not accidentally browserify\n// this code.\nvar isMix = typeof _global.process !== 'undefined' &&\n {}.toString.call(_global.process) === '[object process]' && !isWebWorker &&\n !!(isWindowExists && internalWindow['HTMLElement']);\nvar zoneSymbolEventNames = {};\nvar wrapFn = function (event) {\n // https://github.com/angular/zone.js/issues/911, in IE, sometimes\n // event will be undefined, so we need to use window.event\n event = event || _global.event;\n if (!event) {\n return;\n }\n var eventNameSymbol = zoneSymbolEventNames[event.type];\n if (!eventNameSymbol) {\n eventNameSymbol = zoneSymbolEventNames[event.type] = zoneSymbol('ON_PROPERTY' + event.type);\n }\n var target = this || event.target || _global;\n var listener = target[eventNameSymbol];\n var result = listener && listener.apply(this, arguments);\n if (result != undefined && !result) {\n event.preventDefault();\n }\n return result;\n};\nfunction patchProperty(obj, prop, prototype) {\n var desc = ObjectGetOwnPropertyDescriptor(obj, prop);\n if (!desc && prototype) {\n // when patch window object, use prototype to check prop exist or not\n var prototypeDesc = ObjectGetOwnPropertyDescriptor(prototype, prop);\n if (prototypeDesc) {\n desc = { enumerable: true, configurable: true };\n }\n }\n // if the descriptor not exists or is not configurable\n // just return\n if (!desc || !desc.configurable) {\n return;\n }\n // A property descriptor cannot have getter/setter and be writable\n // deleting the writable and value properties avoids this error:\n //\n // TypeError: property descriptors must not specify a value or be writable when a\n // getter or setter has been specified\n delete desc.writable;\n delete desc.value;\n var originalDescGet = desc.get;\n var originalDescSet = desc.set;\n // substr(2) cuz 'onclick' -> 'click', etc\n var eventName = prop.substr(2);\n var eventNameSymbol = zoneSymbolEventNames[eventName];\n if (!eventNameSymbol) {\n eventNameSymbol = zoneSymbolEventNames[eventName] = zoneSymbol('ON_PROPERTY' + eventName);\n }\n desc.set = function (newValue) {\n // in some of windows's onproperty callback, this is undefined\n // so we need to check it\n var target = this;\n if (!target && obj === _global) {\n target = _global;\n }\n if (!target) {\n return;\n }\n var previousValue = target[eventNameSymbol];\n if (previousValue) {\n target.removeEventListener(eventName, wrapFn);\n }\n // issue #978, when onload handler was added before loading zone.js\n // we should remove it with originalDescSet\n if (originalDescSet) {\n originalDescSet.apply(target, NULL_ON_PROP_VALUE);\n }\n if (typeof newValue === 'function') {\n target[eventNameSymbol] = newValue;\n target.addEventListener(eventName, wrapFn, false);\n }\n else {\n target[eventNameSymbol] = null;\n }\n };\n // The getter would return undefined for unassigned properties but the default value of an\n // unassigned property is null\n desc.get = function () {\n // in some of windows's onproperty callback, this is undefined\n // so we need to check it\n var target = this;\n if (!target && obj === _global) {\n target = _global;\n }\n if (!target) {\n return null;\n }\n var listener = target[eventNameSymbol];\n if (listener) {\n return listener;\n }\n else if (originalDescGet) {\n // result will be null when use inline event attribute,\n // such as \n // because the onclick function is internal raw uncompiled handler\n // the onclick will be evaluated when first time event was triggered or\n // the property is accessed, https://github.com/angular/zone.js/issues/525\n // so we should use original native get to retrieve the handler\n var value = originalDescGet && originalDescGet.call(this);\n if (value) {\n desc.set.call(this, value);\n if (typeof target[REMOVE_ATTRIBUTE] === 'function') {\n target.removeAttribute(prop);\n }\n return value;\n }\n }\n return null;\n };\n ObjectDefineProperty(obj, prop, desc);\n}\nfunction patchOnProperties(obj, properties, prototype) {\n if (properties) {\n for (var i = 0; i < properties.length; i++) {\n patchProperty(obj, 'on' + properties[i], prototype);\n }\n }\n else {\n var onProperties = [];\n for (var prop in obj) {\n if (prop.substr(0, 2) == 'on') {\n onProperties.push(prop);\n }\n }\n for (var j = 0; j < onProperties.length; j++) {\n patchProperty(obj, onProperties[j], prototype);\n }\n }\n}\nvar originalInstanceKey = zoneSymbol('originalInstance');\n// wrap some native API on `window`\nfunction patchClass(className) {\n var OriginalClass = _global[className];\n if (!OriginalClass)\n return;\n // keep original class in global\n _global[zoneSymbol(className)] = OriginalClass;\n _global[className] = function () {\n var a = bindArguments(arguments, className);\n switch (a.length) {\n case 0:\n this[originalInstanceKey] = new OriginalClass();\n break;\n case 1:\n this[originalInstanceKey] = new OriginalClass(a[0]);\n break;\n case 2:\n this[originalInstanceKey] = new OriginalClass(a[0], a[1]);\n break;\n case 3:\n this[originalInstanceKey] = new OriginalClass(a[0], a[1], a[2]);\n break;\n case 4:\n this[originalInstanceKey] = new OriginalClass(a[0], a[1], a[2], a[3]);\n break;\n default:\n throw new Error('Arg list too long.');\n }\n };\n // attach original delegate to patched function\n attachOriginToPatched(_global[className], OriginalClass);\n var instance = new OriginalClass(function () { });\n var prop;\n for (prop in instance) {\n // https://bugs.webkit.org/show_bug.cgi?id=44721\n if (className === 'XMLHttpRequest' && prop === 'responseBlob')\n continue;\n (function (prop) {\n if (typeof instance[prop] === 'function') {\n _global[className].prototype[prop] = function () {\n return this[originalInstanceKey][prop].apply(this[originalInstanceKey], arguments);\n };\n }\n else {\n ObjectDefineProperty(_global[className].prototype, prop, {\n set: function (fn) {\n if (typeof fn === 'function') {\n this[originalInstanceKey][prop] = wrapWithCurrentZone(fn, className + '.' + prop);\n // keep callback in wrapped function so we can\n // use it in Function.prototype.toString to return\n // the native one.\n attachOriginToPatched(this[originalInstanceKey][prop], fn);\n }\n else {\n this[originalInstanceKey][prop] = fn;\n }\n },\n get: function () {\n return this[originalInstanceKey][prop];\n }\n });\n }\n }(prop));\n }\n for (prop in OriginalClass) {\n if (prop !== 'prototype' && OriginalClass.hasOwnProperty(prop)) {\n _global[className][prop] = OriginalClass[prop];\n }\n }\n}\nfunction patchMethod(target, name, patchFn) {\n var proto = target;\n while (proto && !proto.hasOwnProperty(name)) {\n proto = ObjectGetPrototypeOf(proto);\n }\n if (!proto && target[name]) {\n // somehow we did not find it, but we can see it. This happens on IE for Window properties.\n proto = target;\n }\n var delegateName = zoneSymbol(name);\n var delegate;\n if (proto && !(delegate = proto[delegateName])) {\n delegate = proto[delegateName] = proto[name];\n // check whether proto[name] is writable\n // some property is readonly in safari, such as HtmlCanvasElement.prototype.toBlob\n var desc = proto && ObjectGetOwnPropertyDescriptor(proto, name);\n if (isPropertyWritable(desc)) {\n var patchDelegate_1 = patchFn(delegate, delegateName, name);\n proto[name] = function () {\n return patchDelegate_1(this, arguments);\n };\n attachOriginToPatched(proto[name], delegate);\n }\n }\n return delegate;\n}\n// TODO: @JiaLiPassion, support cancel task later if necessary\nfunction patchMacroTask(obj, funcName, metaCreator) {\n var setNative = null;\n function scheduleTask(task) {\n var data = task.data;\n data.args[data.cbIdx] = function () {\n task.invoke.apply(this, arguments);\n };\n setNative.apply(data.target, data.args);\n return task;\n }\n setNative = patchMethod(obj, funcName, function (delegate) { return function (self, args) {\n var meta = metaCreator(self, args);\n if (meta.cbIdx >= 0 && typeof args[meta.cbIdx] === 'function') {\n return scheduleMacroTaskWithCurrentZone(meta.name, args[meta.cbIdx], meta, scheduleTask, null);\n }\n else {\n // cause an error by calling it directly.\n return delegate.apply(self, args);\n }\n }; });\n}\n\nfunction attachOriginToPatched(patched, original) {\n patched[zoneSymbol('OriginalDelegate')] = original;\n}\nvar isDetectedIEOrEdge = false;\nvar ieOrEdge = false;\nfunction isIEOrEdge() {\n if (isDetectedIEOrEdge) {\n return ieOrEdge;\n }\n isDetectedIEOrEdge = true;\n try {\n var ua = internalWindow.navigator.userAgent;\n if (ua.indexOf('MSIE ') !== -1 || ua.indexOf('Trident/') !== -1 || ua.indexOf('Edge/') !== -1) {\n ieOrEdge = true;\n }\n return ieOrEdge;\n }\n catch (error) {\n }\n}\n\n/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\n// override Function.prototype.toString to make zone.js patched function\n// look like native function\nZone.__load_patch('toString', function (global) {\n // patch Func.prototype.toString to let them look like native\n var originalFunctionToString = Function.prototype.toString;\n var ORIGINAL_DELEGATE_SYMBOL = zoneSymbol('OriginalDelegate');\n var PROMISE_SYMBOL = zoneSymbol('Promise');\n var ERROR_SYMBOL = zoneSymbol('Error');\n var newFunctionToString = function toString() {\n if (typeof this === 'function') {\n var originalDelegate = this[ORIGINAL_DELEGATE_SYMBOL];\n if (originalDelegate) {\n if (typeof originalDelegate === 'function') {\n return originalFunctionToString.apply(this[ORIGINAL_DELEGATE_SYMBOL], arguments);\n }\n else {\n return Object.prototype.toString.call(originalDelegate);\n }\n }\n if (this === Promise) {\n var nativePromise = global[PROMISE_SYMBOL];\n if (nativePromise) {\n return originalFunctionToString.apply(nativePromise, arguments);\n }\n }\n if (this === Error) {\n var nativeError = global[ERROR_SYMBOL];\n if (nativeError) {\n return originalFunctionToString.apply(nativeError, arguments);\n }\n }\n }\n return originalFunctionToString.apply(this, arguments);\n };\n newFunctionToString[ORIGINAL_DELEGATE_SYMBOL] = originalFunctionToString;\n Function.prototype.toString = newFunctionToString;\n // patch Object.prototype.toString to let them look like native\n var originalObjectToString = Object.prototype.toString;\n var PROMISE_OBJECT_TO_STRING = '[object Promise]';\n Object.prototype.toString = function () {\n if (this instanceof Promise) {\n return PROMISE_OBJECT_TO_STRING;\n }\n return originalObjectToString.apply(this, arguments);\n };\n});\n\n/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\n/**\n * @fileoverview\n * @suppress {missingRequire}\n */\n// an identifier to tell ZoneTask do not create a new invoke closure\nvar OPTIMIZED_ZONE_EVENT_TASK_DATA = {\n useG: true\n};\nvar zoneSymbolEventNames$1 = {};\nvar globalSources = {};\nvar EVENT_NAME_SYMBOL_REGX = /^__zone_symbol__(\\w+)(true|false)$/;\nvar IMMEDIATE_PROPAGATION_SYMBOL = ('__zone_symbol__propagationStopped');\nfunction patchEventTarget(_global, apis, patchOptions) {\n var ADD_EVENT_LISTENER = (patchOptions && patchOptions.add) || ADD_EVENT_LISTENER_STR;\n var REMOVE_EVENT_LISTENER = (patchOptions && patchOptions.rm) || REMOVE_EVENT_LISTENER_STR;\n var LISTENERS_EVENT_LISTENER = (patchOptions && patchOptions.listeners) || 'eventListeners';\n var REMOVE_ALL_LISTENERS_EVENT_LISTENER = (patchOptions && patchOptions.rmAll) || 'removeAllListeners';\n var zoneSymbolAddEventListener = zoneSymbol(ADD_EVENT_LISTENER);\n var ADD_EVENT_LISTENER_SOURCE = '.' + ADD_EVENT_LISTENER + ':';\n var PREPEND_EVENT_LISTENER = 'prependListener';\n var PREPEND_EVENT_LISTENER_SOURCE = '.' + PREPEND_EVENT_LISTENER + ':';\n var invokeTask = function (task, target, event) {\n // for better performance, check isRemoved which is set\n // by removeEventListener\n if (task.isRemoved) {\n return;\n }\n var delegate = task.callback;\n if (typeof delegate === 'object' && delegate.handleEvent) {\n // create the bind version of handleEvent when invoke\n task.callback = function (event) { return delegate.handleEvent(event); };\n task.originalDelegate = delegate;\n }\n // invoke static task.invoke\n task.invoke(task, target, [event]);\n var options = task.options;\n if (options && typeof options === 'object' && options.once) {\n // if options.once is true, after invoke once remove listener here\n // only browser need to do this, nodejs eventEmitter will cal removeListener\n // inside EventEmitter.once\n var delegate_1 = task.originalDelegate ? task.originalDelegate : task.callback;\n target[REMOVE_EVENT_LISTENER].call(target, event.type, delegate_1, options);\n }\n };\n // global shared zoneAwareCallback to handle all event callback with capture = false\n var globalZoneAwareCallback = function (event) {\n // https://github.com/angular/zone.js/issues/911, in IE, sometimes\n // event will be undefined, so we need to use window.event\n event = event || _global.event;\n if (!event) {\n return;\n }\n // event.target is needed for Samsung TV and SourceBuffer\n // || global is needed https://github.com/angular/zone.js/issues/190\n var target = this || event.target || _global;\n var tasks = target[zoneSymbolEventNames$1[event.type][FALSE_STR]];\n if (tasks) {\n // invoke all tasks which attached to current target with given event.type and capture = false\n // for performance concern, if task.length === 1, just invoke\n if (tasks.length === 1) {\n invokeTask(tasks[0], target, event);\n }\n else {\n // https://github.com/angular/zone.js/issues/836\n // copy the tasks array before invoke, to avoid\n // the callback will remove itself or other listener\n var copyTasks = tasks.slice();\n for (var i = 0; i < copyTasks.length; i++) {\n if (event && event[IMMEDIATE_PROPAGATION_SYMBOL] === true) {\n break;\n }\n invokeTask(copyTasks[i], target, event);\n }\n }\n }\n };\n // global shared zoneAwareCallback to handle all event callback with capture = true\n var globalZoneAwareCaptureCallback = function (event) {\n // https://github.com/angular/zone.js/issues/911, in IE, sometimes\n // event will be undefined, so we need to use window.event\n event = event || _global.event;\n if (!event) {\n return;\n }\n // event.target is needed for Samsung TV and SourceBuffer\n // || global is needed https://github.com/angular/zone.js/issues/190\n var target = this || event.target || _global;\n var tasks = target[zoneSymbolEventNames$1[event.type][TRUE_STR]];\n if (tasks) {\n // invoke all tasks which attached to current target with given event.type and capture = false\n // for performance concern, if task.length === 1, just invoke\n if (tasks.length === 1) {\n invokeTask(tasks[0], target, event);\n }\n else {\n // https://github.com/angular/zone.js/issues/836\n // copy the tasks array before invoke, to avoid\n // the callback will remove itself or other listener\n var copyTasks = tasks.slice();\n for (var i = 0; i < copyTasks.length; i++) {\n if (event && event[IMMEDIATE_PROPAGATION_SYMBOL] === true) {\n break;\n }\n invokeTask(copyTasks[i], target, event);\n }\n }\n }\n };\n function patchEventTargetMethods(obj, patchOptions) {\n if (!obj) {\n return false;\n }\n var useGlobalCallback = true;\n if (patchOptions && patchOptions.useG !== undefined) {\n useGlobalCallback = patchOptions.useG;\n }\n var validateHandler = patchOptions && patchOptions.vh;\n var checkDuplicate = true;\n if (patchOptions && patchOptions.chkDup !== undefined) {\n checkDuplicate = patchOptions.chkDup;\n }\n var returnTarget = false;\n if (patchOptions && patchOptions.rt !== undefined) {\n returnTarget = patchOptions.rt;\n }\n var proto = obj;\n while (proto && !proto.hasOwnProperty(ADD_EVENT_LISTENER)) {\n proto = ObjectGetPrototypeOf(proto);\n }\n if (!proto && obj[ADD_EVENT_LISTENER]) {\n // somehow we did not find it, but we can see it. This happens on IE for Window properties.\n proto = obj;\n }\n if (!proto) {\n return false;\n }\n if (proto[zoneSymbolAddEventListener]) {\n return false;\n }\n // a shared global taskData to pass data for scheduleEventTask\n // so we do not need to create a new object just for pass some data\n var taskData = {};\n var nativeAddEventListener = proto[zoneSymbolAddEventListener] = proto[ADD_EVENT_LISTENER];\n var nativeRemoveEventListener = proto[zoneSymbol(REMOVE_EVENT_LISTENER)] =\n proto[REMOVE_EVENT_LISTENER];\n var nativeListeners = proto[zoneSymbol(LISTENERS_EVENT_LISTENER)] =\n proto[LISTENERS_EVENT_LISTENER];\n var nativeRemoveAllListeners = proto[zoneSymbol(REMOVE_ALL_LISTENERS_EVENT_LISTENER)] =\n proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER];\n var nativePrependEventListener;\n if (patchOptions && patchOptions.prepend) {\n nativePrependEventListener = proto[zoneSymbol(patchOptions.prepend)] =\n proto[patchOptions.prepend];\n }\n var customScheduleGlobal = function () {\n // if there is already a task for the eventName + capture,\n // just return, because we use the shared globalZoneAwareCallback here.\n if (taskData.isExisting) {\n return;\n }\n return nativeAddEventListener.call(taskData.target, taskData.eventName, taskData.capture ? globalZoneAwareCaptureCallback : globalZoneAwareCallback, taskData.options);\n };\n var customCancelGlobal = function (task) {\n // if task is not marked as isRemoved, this call is directly\n // from Zone.prototype.cancelTask, we should remove the task\n // from tasksList of target first\n if (!task.isRemoved) {\n var symbolEventNames = zoneSymbolEventNames$1[task.eventName];\n var symbolEventName = void 0;\n if (symbolEventNames) {\n symbolEventName = symbolEventNames[task.capture ? TRUE_STR : FALSE_STR];\n }\n var existingTasks = symbolEventName && task.target[symbolEventName];\n if (existingTasks) {\n for (var i = 0; i < existingTasks.length; i++) {\n var existingTask = existingTasks[i];\n if (existingTask === task) {\n existingTasks.splice(i, 1);\n // set isRemoved to data for faster invokeTask check\n task.isRemoved = true;\n if (existingTasks.length === 0) {\n // all tasks for the eventName + capture have gone,\n // remove globalZoneAwareCallback and remove the task cache from target\n task.allRemoved = true;\n task.target[symbolEventName] = null;\n }\n break;\n }\n }\n }\n }\n // if all tasks for the eventName + capture have gone,\n // we will really remove the global event callback,\n // if not, return\n if (!task.allRemoved) {\n return;\n }\n return nativeRemoveEventListener.call(task.target, task.eventName, task.capture ? globalZoneAwareCaptureCallback : globalZoneAwareCallback, task.options);\n };\n var customScheduleNonGlobal = function (task) {\n return nativeAddEventListener.call(taskData.target, taskData.eventName, task.invoke, taskData.options);\n };\n var customSchedulePrepend = function (task) {\n return nativePrependEventListener.call(taskData.target, taskData.eventName, task.invoke, taskData.options);\n };\n var customCancelNonGlobal = function (task) {\n return nativeRemoveEventListener.call(task.target, task.eventName, task.invoke, task.options);\n };\n var customSchedule = useGlobalCallback ? customScheduleGlobal : customScheduleNonGlobal;\n var customCancel = useGlobalCallback ? customCancelGlobal : customCancelNonGlobal;\n var compareTaskCallbackVsDelegate = function (task, delegate) {\n var typeOfDelegate = typeof delegate;\n return (typeOfDelegate === 'function' && task.callback === delegate) ||\n (typeOfDelegate === 'object' && task.originalDelegate === delegate);\n };\n var compare = (patchOptions && patchOptions.diff) ? patchOptions.diff : compareTaskCallbackVsDelegate;\n var blackListedEvents = Zone[Zone.__symbol__('BLACK_LISTED_EVENTS')];\n var makeAddListener = function (nativeListener, addSource, customScheduleFn, customCancelFn, returnTarget, prepend) {\n if (returnTarget === void 0) { returnTarget = false; }\n if (prepend === void 0) { prepend = false; }\n return function () {\n var target = this || _global;\n var delegate = arguments[1];\n if (!delegate) {\n return nativeListener.apply(this, arguments);\n }\n // don't create the bind delegate function for handleEvent\n // case here to improve addEventListener performance\n // we will create the bind delegate when invoke\n var isHandleEvent = false;\n if (typeof delegate !== 'function') {\n if (!delegate.handleEvent) {\n return nativeListener.apply(this, arguments);\n }\n isHandleEvent = true;\n }\n if (validateHandler && !validateHandler(nativeListener, delegate, target, arguments)) {\n return;\n }\n var eventName = arguments[0];\n var options = arguments[2];\n if (blackListedEvents) {\n // check black list\n for (var i = 0; i < blackListedEvents.length; i++) {\n if (eventName === blackListedEvents[i]) {\n return nativeListener.apply(this, arguments);\n }\n }\n }\n var capture;\n var once = false;\n if (options === undefined) {\n capture = false;\n }\n else if (options === true) {\n capture = true;\n }\n else if (options === false) {\n capture = false;\n }\n else {\n capture = options ? !!options.capture : false;\n once = options ? !!options.once : false;\n }\n var zone = Zone.current;\n var symbolEventNames = zoneSymbolEventNames$1[eventName];\n var symbolEventName;\n if (!symbolEventNames) {\n // the code is duplicate, but I just want to get some better performance\n var falseEventName = eventName + FALSE_STR;\n var trueEventName = eventName + TRUE_STR;\n var symbol = ZONE_SYMBOL_PREFIX + falseEventName;\n var symbolCapture = ZONE_SYMBOL_PREFIX + trueEventName;\n zoneSymbolEventNames$1[eventName] = {};\n zoneSymbolEventNames$1[eventName][FALSE_STR] = symbol;\n zoneSymbolEventNames$1[eventName][TRUE_STR] = symbolCapture;\n symbolEventName = capture ? symbolCapture : symbol;\n }\n else {\n symbolEventName = symbolEventNames[capture ? TRUE_STR : FALSE_STR];\n }\n var existingTasks = target[symbolEventName];\n var isExisting = false;\n if (existingTasks) {\n // already have task registered\n isExisting = true;\n if (checkDuplicate) {\n for (var i = 0; i < existingTasks.length; i++) {\n if (compare(existingTasks[i], delegate)) {\n // same callback, same capture, same event name, just return\n return;\n }\n }\n }\n }\n else {\n existingTasks = target[symbolEventName] = [];\n }\n var source;\n var constructorName = target.constructor['name'];\n var targetSource = globalSources[constructorName];\n if (targetSource) {\n source = targetSource[eventName];\n }\n if (!source) {\n source = constructorName + addSource + eventName;\n }\n // do not create a new object as task.data to pass those things\n // just use the global shared one\n taskData.options = options;\n if (once) {\n // if addEventListener with once options, we don't pass it to\n // native addEventListener, instead we keep the once setting\n // and handle ourselves.\n taskData.options.once = false;\n }\n taskData.target = target;\n taskData.capture = capture;\n taskData.eventName = eventName;\n taskData.isExisting = isExisting;\n var data = useGlobalCallback ? OPTIMIZED_ZONE_EVENT_TASK_DATA : null;\n // keep taskData into data to allow onScheduleEventTask to access the task information\n if (data) {\n data.taskData = taskData;\n }\n var task = zone.scheduleEventTask(source, delegate, data, customScheduleFn, customCancelFn);\n // should clear taskData.target to avoid memory leak\n // issue, https://github.com/angular/angular/issues/20442\n taskData.target = null;\n // need to clear up taskData because it is a global object\n if (data) {\n data.taskData = null;\n }\n // have to save those information to task in case\n // application may call task.zone.cancelTask() directly\n if (once) {\n options.once = true;\n }\n task.options = options;\n task.target = target;\n task.capture = capture;\n task.eventName = eventName;\n if (isHandleEvent) {\n // save original delegate for compare to check duplicate\n task.originalDelegate = delegate;\n }\n if (!prepend) {\n existingTasks.push(task);\n }\n else {\n existingTasks.unshift(task);\n }\n if (returnTarget) {\n return target;\n }\n };\n };\n proto[ADD_EVENT_LISTENER] = makeAddListener(nativeAddEventListener, ADD_EVENT_LISTENER_SOURCE, customSchedule, customCancel, returnTarget);\n if (nativePrependEventListener) {\n proto[PREPEND_EVENT_LISTENER] = makeAddListener(nativePrependEventListener, PREPEND_EVENT_LISTENER_SOURCE, customSchedulePrepend, customCancel, returnTarget, true);\n }\n proto[REMOVE_EVENT_LISTENER] = function () {\n var target = this || _global;\n var eventName = arguments[0];\n var options = arguments[2];\n var capture;\n if (options === undefined) {\n capture = false;\n }\n else if (options === true) {\n capture = true;\n }\n else if (options === false) {\n capture = false;\n }\n else {\n capture = options ? !!options.capture : false;\n }\n var delegate = arguments[1];\n if (!delegate) {\n return nativeRemoveEventListener.apply(this, arguments);\n }\n if (validateHandler &&\n !validateHandler(nativeRemoveEventListener, delegate, target, arguments)) {\n return;\n }\n var symbolEventNames = zoneSymbolEventNames$1[eventName];\n var symbolEventName;\n if (symbolEventNames) {\n symbolEventName = symbolEventNames[capture ? TRUE_STR : FALSE_STR];\n }\n var existingTasks = symbolEventName && target[symbolEventName];\n if (existingTasks) {\n for (var i = 0; i < existingTasks.length; i++) {\n var existingTask = existingTasks[i];\n if (compare(existingTask, delegate)) {\n existingTasks.splice(i, 1);\n // set isRemoved to data for faster invokeTask check\n existingTask.isRemoved = true;\n if (existingTasks.length === 0) {\n // all tasks for the eventName + capture have gone,\n // remove globalZoneAwareCallback and remove the task cache from target\n existingTask.allRemoved = true;\n target[symbolEventName] = null;\n }\n existingTask.zone.cancelTask(existingTask);\n if (returnTarget) {\n return target;\n }\n return;\n }\n }\n }\n // issue 930, didn't find the event name or callback\n // from zone kept existingTasks, the callback maybe\n // added outside of zone, we need to call native removeEventListener\n // to try to remove it.\n return nativeRemoveEventListener.apply(this, arguments);\n };\n proto[LISTENERS_EVENT_LISTENER] = function () {\n var target = this || _global;\n var eventName = arguments[0];\n var listeners = [];\n var tasks = findEventTasks(target, eventName);\n for (var i = 0; i < tasks.length; i++) {\n var task = tasks[i];\n var delegate = task.originalDelegate ? task.originalDelegate : task.callback;\n listeners.push(delegate);\n }\n return listeners;\n };\n proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER] = function () {\n var target = this || _global;\n var eventName = arguments[0];\n if (!eventName) {\n var keys = Object.keys(target);\n for (var i = 0; i < keys.length; i++) {\n var prop = keys[i];\n var match = EVENT_NAME_SYMBOL_REGX.exec(prop);\n var evtName = match && match[1];\n // in nodejs EventEmitter, removeListener event is\n // used for monitoring the removeListener call,\n // so just keep removeListener eventListener until\n // all other eventListeners are removed\n if (evtName && evtName !== 'removeListener') {\n this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, evtName);\n }\n }\n // remove removeListener listener finally\n this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, 'removeListener');\n }\n else {\n var symbolEventNames = zoneSymbolEventNames$1[eventName];\n if (symbolEventNames) {\n var symbolEventName = symbolEventNames[FALSE_STR];\n var symbolCaptureEventName = symbolEventNames[TRUE_STR];\n var tasks = target[symbolEventName];\n var captureTasks = target[symbolCaptureEventName];\n if (tasks) {\n var removeTasks = tasks.slice();\n for (var i = 0; i < removeTasks.length; i++) {\n var task = removeTasks[i];\n var delegate = task.originalDelegate ? task.originalDelegate : task.callback;\n this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options);\n }\n }\n if (captureTasks) {\n var removeTasks = captureTasks.slice();\n for (var i = 0; i < removeTasks.length; i++) {\n var task = removeTasks[i];\n var delegate = task.originalDelegate ? task.originalDelegate : task.callback;\n this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options);\n }\n }\n }\n }\n if (returnTarget) {\n return this;\n }\n };\n // for native toString patch\n attachOriginToPatched(proto[ADD_EVENT_LISTENER], nativeAddEventListener);\n attachOriginToPatched(proto[REMOVE_EVENT_LISTENER], nativeRemoveEventListener);\n if (nativeRemoveAllListeners) {\n attachOriginToPatched(proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER], nativeRemoveAllListeners);\n }\n if (nativeListeners) {\n attachOriginToPatched(proto[LISTENERS_EVENT_LISTENER], nativeListeners);\n }\n return true;\n }\n var results = [];\n for (var i = 0; i < apis.length; i++) {\n results[i] = patchEventTargetMethods(apis[i], patchOptions);\n }\n return results;\n}\nfunction findEventTasks(target, eventName) {\n var foundTasks = [];\n for (var prop in target) {\n var match = EVENT_NAME_SYMBOL_REGX.exec(prop);\n var evtName = match && match[1];\n if (evtName && (!eventName || evtName === eventName)) {\n var tasks = target[prop];\n if (tasks) {\n for (var i = 0; i < tasks.length; i++) {\n foundTasks.push(tasks[i]);\n }\n }\n }\n }\n return foundTasks;\n}\nfunction patchEventPrototype(global, api) {\n var Event = global['Event'];\n if (Event && Event.prototype) {\n api.patchMethod(Event.prototype, 'stopImmediatePropagation', function (delegate) { return function (self, args) {\n self[IMMEDIATE_PROPAGATION_SYMBOL] = true;\n // we need to call the native stopImmediatePropagation\n // in case in some hybrid application, some part of\n // application will be controlled by zone, some are not\n delegate && delegate.apply(self, args);\n }; });\n }\n}\n\n/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\n/**\n * @fileoverview\n * @suppress {missingRequire}\n */\nvar taskSymbol = zoneSymbol('zoneTask');\nfunction patchTimer(window, setName, cancelName, nameSuffix) {\n var setNative = null;\n var clearNative = null;\n setName += nameSuffix;\n cancelName += nameSuffix;\n var tasksByHandleId = {};\n function scheduleTask(task) {\n var data = task.data;\n function timer() {\n try {\n task.invoke.apply(this, arguments);\n }\n finally {\n // issue-934, task will be cancelled\n // even it is a periodic task such as\n // setInterval\n if (!(task.data && task.data.isPeriodic)) {\n if (typeof data.handleId === 'number') {\n // in non-nodejs env, we remove timerId\n // from local cache\n delete tasksByHandleId[data.handleId];\n }\n else if (data.handleId) {\n // Node returns complex objects as handleIds\n // we remove task reference from timer object\n data.handleId[taskSymbol] = null;\n }\n }\n }\n }\n data.args[0] = timer;\n data.handleId = setNative.apply(window, data.args);\n return task;\n }\n function clearTask(task) {\n return clearNative(task.data.handleId);\n }\n setNative =\n patchMethod(window, setName, function (delegate) { return function (self, args) {\n if (typeof args[0] === 'function') {\n var options = {\n handleId: null,\n isPeriodic: nameSuffix === 'Interval',\n delay: (nameSuffix === 'Timeout' || nameSuffix === 'Interval') ? args[1] || 0 : null,\n args: args\n };\n var task = scheduleMacroTaskWithCurrentZone(setName, args[0], options, scheduleTask, clearTask);\n if (!task) {\n return task;\n }\n // Node.js must additionally support the ref and unref functions.\n var handle = task.data.handleId;\n if (typeof handle === 'number') {\n // for non nodejs env, we save handleId: task\n // mapping in local cache for clearTimeout\n tasksByHandleId[handle] = task;\n }\n else if (handle) {\n // for nodejs env, we save task\n // reference in timerId Object for clearTimeout\n handle[taskSymbol] = task;\n }\n // check whether handle is null, because some polyfill or browser\n // may return undefined from setTimeout/setInterval/setImmediate/requestAnimationFrame\n if (handle && handle.ref && handle.unref && typeof handle.ref === 'function' &&\n typeof handle.unref === 'function') {\n task.ref = handle.ref.bind(handle);\n task.unref = handle.unref.bind(handle);\n }\n if (typeof handle === 'number' || handle) {\n return handle;\n }\n return task;\n }\n else {\n // cause an error by calling it directly.\n return delegate.apply(window, args);\n }\n }; });\n clearNative =\n patchMethod(window, cancelName, function (delegate) { return function (self, args) {\n var id = args[0];\n var task;\n if (typeof id === 'number') {\n // non nodejs env.\n task = tasksByHandleId[id];\n }\n else {\n // nodejs env.\n task = id && id[taskSymbol];\n // other environments.\n if (!task) {\n task = id;\n }\n }\n if (task && typeof task.type === 'string') {\n if (task.state !== 'notScheduled' &&\n (task.cancelFn && task.data.isPeriodic || task.runCount === 0)) {\n if (typeof id === 'number') {\n delete tasksByHandleId[id];\n }\n else if (id) {\n id[taskSymbol] = null;\n }\n // Do not cancel already canceled functions\n task.zone.cancelTask(task);\n }\n }\n else {\n // cause an error by calling it directly.\n delegate.apply(window, args);\n }\n }; });\n}\n\n/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\n/*\n * This is necessary for Chrome and Chrome mobile, to enable\n * things like redefining `createdCallback` on an element.\n */\nvar _defineProperty = Object[zoneSymbol('defineProperty')] = Object.defineProperty;\nvar _getOwnPropertyDescriptor = Object[zoneSymbol('getOwnPropertyDescriptor')] =\n Object.getOwnPropertyDescriptor;\nvar _create = Object.create;\nvar unconfigurablesKey = zoneSymbol('unconfigurables');\nfunction propertyPatch() {\n Object.defineProperty = function (obj, prop, desc) {\n if (isUnconfigurable(obj, prop)) {\n throw new TypeError('Cannot assign to read only property \\'' + prop + '\\' of ' + obj);\n }\n var originalConfigurableFlag = desc.configurable;\n if (prop !== 'prototype') {\n desc = rewriteDescriptor(obj, prop, desc);\n }\n return _tryDefineProperty(obj, prop, desc, originalConfigurableFlag);\n };\n Object.defineProperties = function (obj, props) {\n Object.keys(props).forEach(function (prop) {\n Object.defineProperty(obj, prop, props[prop]);\n });\n return obj;\n };\n Object.create = function (obj, proto) {\n if (typeof proto === 'object' && !Object.isFrozen(proto)) {\n Object.keys(proto).forEach(function (prop) {\n proto[prop] = rewriteDescriptor(obj, prop, proto[prop]);\n });\n }\n return _create(obj, proto);\n };\n Object.getOwnPropertyDescriptor = function (obj, prop) {\n var desc = _getOwnPropertyDescriptor(obj, prop);\n if (isUnconfigurable(obj, prop)) {\n desc.configurable = false;\n }\n return desc;\n };\n}\nfunction _redefineProperty(obj, prop, desc) {\n var originalConfigurableFlag = desc.configurable;\n desc = rewriteDescriptor(obj, prop, desc);\n return _tryDefineProperty(obj, prop, desc, originalConfigurableFlag);\n}\nfunction isUnconfigurable(obj, prop) {\n return obj && obj[unconfigurablesKey] && obj[unconfigurablesKey][prop];\n}\nfunction rewriteDescriptor(obj, prop, desc) {\n // issue-927, if the desc is frozen, don't try to change the desc\n if (!Object.isFrozen(desc)) {\n desc.configurable = true;\n }\n if (!desc.configurable) {\n // issue-927, if the obj is frozen, don't try to set the desc to obj\n if (!obj[unconfigurablesKey] && !Object.isFrozen(obj)) {\n _defineProperty(obj, unconfigurablesKey, { writable: true, value: {} });\n }\n if (obj[unconfigurablesKey]) {\n obj[unconfigurablesKey][prop] = true;\n }\n }\n return desc;\n}\nfunction _tryDefineProperty(obj, prop, desc, originalConfigurableFlag) {\n try {\n return _defineProperty(obj, prop, desc);\n }\n catch (error) {\n if (desc.configurable) {\n // In case of errors, when the configurable flag was likely set by rewriteDescriptor(), let's\n // retry with the original flag value\n if (typeof originalConfigurableFlag == 'undefined') {\n delete desc.configurable;\n }\n else {\n desc.configurable = originalConfigurableFlag;\n }\n try {\n return _defineProperty(obj, prop, desc);\n }\n catch (error) {\n var descJson = null;\n try {\n descJson = JSON.stringify(desc);\n }\n catch (error) {\n descJson = desc.toString();\n }\n console.log(\"Attempting to configure '\" + prop + \"' with descriptor '\" + descJson + \"' on object '\" + obj + \"' and got error, giving up: \" + error);\n }\n }\n else {\n throw error;\n }\n }\n}\n\n/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\n// we have to patch the instance since the proto is non-configurable\nfunction apply(api, _global) {\n var WS = _global.WebSocket;\n // On Safari window.EventTarget doesn't exist so need to patch WS add/removeEventListener\n // On older Chrome, no need since EventTarget was already patched\n if (!_global.EventTarget) {\n patchEventTarget(_global, [WS.prototype]);\n }\n _global.WebSocket = function (x, y) {\n var socket = arguments.length > 1 ? new WS(x, y) : new WS(x);\n var proxySocket;\n var proxySocketProto;\n // Safari 7.0 has non-configurable own 'onmessage' and friends properties on the socket instance\n var onmessageDesc = ObjectGetOwnPropertyDescriptor(socket, 'onmessage');\n if (onmessageDesc && onmessageDesc.configurable === false) {\n proxySocket = ObjectCreate(socket);\n // socket have own property descriptor 'onopen', 'onmessage', 'onclose', 'onerror'\n // but proxySocket not, so we will keep socket as prototype and pass it to\n // patchOnProperties method\n proxySocketProto = socket;\n [ADD_EVENT_LISTENER_STR, REMOVE_EVENT_LISTENER_STR, 'send', 'close'].forEach(function (propName) {\n proxySocket[propName] = function () {\n var args = ArraySlice.call(arguments);\n if (propName === ADD_EVENT_LISTENER_STR || propName === REMOVE_EVENT_LISTENER_STR) {\n var eventName = args.length > 0 ? args[0] : undefined;\n if (eventName) {\n var propertySymbol = Zone.__symbol__('ON_PROPERTY' + eventName);\n socket[propertySymbol] = proxySocket[propertySymbol];\n }\n }\n return socket[propName].apply(socket, args);\n };\n });\n }\n else {\n // we can patch the real socket\n proxySocket = socket;\n }\n patchOnProperties(proxySocket, ['close', 'error', 'message', 'open'], proxySocketProto);\n return proxySocket;\n };\n var globalWebSocket = _global['WebSocket'];\n for (var prop in WS) {\n globalWebSocket[prop] = WS[prop];\n }\n}\n\n/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\n/**\n * @fileoverview\n * @suppress {globalThis}\n */\nvar globalEventHandlersEventNames = [\n 'abort',\n 'animationcancel',\n 'animationend',\n 'animationiteration',\n 'auxclick',\n 'beforeinput',\n 'blur',\n 'cancel',\n 'canplay',\n 'canplaythrough',\n 'change',\n 'compositionstart',\n 'compositionupdate',\n 'compositionend',\n 'cuechange',\n 'click',\n 'close',\n 'contextmenu',\n 'curechange',\n 'dblclick',\n 'drag',\n 'dragend',\n 'dragenter',\n 'dragexit',\n 'dragleave',\n 'dragover',\n 'drop',\n 'durationchange',\n 'emptied',\n 'ended',\n 'error',\n 'focus',\n 'focusin',\n 'focusout',\n 'gotpointercapture',\n 'input',\n 'invalid',\n 'keydown',\n 'keypress',\n 'keyup',\n 'load',\n 'loadstart',\n 'loadeddata',\n 'loadedmetadata',\n 'lostpointercapture',\n 'mousedown',\n 'mouseenter',\n 'mouseleave',\n 'mousemove',\n 'mouseout',\n 'mouseover',\n 'mouseup',\n 'mousewheel',\n 'orientationchange',\n 'pause',\n 'play',\n 'playing',\n 'pointercancel',\n 'pointerdown',\n 'pointerenter',\n 'pointerleave',\n 'pointerlockchange',\n 'mozpointerlockchange',\n 'webkitpointerlockerchange',\n 'pointerlockerror',\n 'mozpointerlockerror',\n 'webkitpointerlockerror',\n 'pointermove',\n 'pointout',\n 'pointerover',\n 'pointerup',\n 'progress',\n 'ratechange',\n 'reset',\n 'resize',\n 'scroll',\n 'seeked',\n 'seeking',\n 'select',\n 'selectionchange',\n 'selectstart',\n 'show',\n 'sort',\n 'stalled',\n 'submit',\n 'suspend',\n 'timeupdate',\n 'volumechange',\n 'touchcancel',\n 'touchmove',\n 'touchstart',\n 'touchend',\n 'transitioncancel',\n 'transitionend',\n 'waiting',\n 'wheel'\n];\nvar documentEventNames = [\n 'afterscriptexecute', 'beforescriptexecute', 'DOMContentLoaded', 'fullscreenchange',\n 'mozfullscreenchange', 'webkitfullscreenchange', 'msfullscreenchange', 'fullscreenerror',\n 'mozfullscreenerror', 'webkitfullscreenerror', 'msfullscreenerror', 'readystatechange',\n 'visibilitychange'\n];\nvar windowEventNames = [\n 'absolutedeviceorientation',\n 'afterinput',\n 'afterprint',\n 'appinstalled',\n 'beforeinstallprompt',\n 'beforeprint',\n 'beforeunload',\n 'devicelight',\n 'devicemotion',\n 'deviceorientation',\n 'deviceorientationabsolute',\n 'deviceproximity',\n 'hashchange',\n 'languagechange',\n 'message',\n 'mozbeforepaint',\n 'offline',\n 'online',\n 'paint',\n 'pageshow',\n 'pagehide',\n 'popstate',\n 'rejectionhandled',\n 'storage',\n 'unhandledrejection',\n 'unload',\n 'userproximity',\n 'vrdisplyconnected',\n 'vrdisplaydisconnected',\n 'vrdisplaypresentchange'\n];\nvar htmlElementEventNames = [\n 'beforecopy', 'beforecut', 'beforepaste', 'copy', 'cut', 'paste', 'dragstart', 'loadend',\n 'animationstart', 'search', 'transitionrun', 'transitionstart', 'webkitanimationend',\n 'webkitanimationiteration', 'webkitanimationstart', 'webkittransitionend'\n];\nvar mediaElementEventNames = ['encrypted', 'waitingforkey', 'msneedkey', 'mozinterruptbegin', 'mozinterruptend'];\nvar ieElementEventNames = [\n 'activate',\n 'afterupdate',\n 'ariarequest',\n 'beforeactivate',\n 'beforedeactivate',\n 'beforeeditfocus',\n 'beforeupdate',\n 'cellchange',\n 'controlselect',\n 'dataavailable',\n 'datasetchanged',\n 'datasetcomplete',\n 'errorupdate',\n 'filterchange',\n 'layoutcomplete',\n 'losecapture',\n 'move',\n 'moveend',\n 'movestart',\n 'propertychange',\n 'resizeend',\n 'resizestart',\n 'rowenter',\n 'rowexit',\n 'rowsdelete',\n 'rowsinserted',\n 'command',\n 'compassneedscalibration',\n 'deactivate',\n 'help',\n 'mscontentzoom',\n 'msmanipulationstatechanged',\n 'msgesturechange',\n 'msgesturedoubletap',\n 'msgestureend',\n 'msgesturehold',\n 'msgesturestart',\n 'msgesturetap',\n 'msgotpointercapture',\n 'msinertiastart',\n 'mslostpointercapture',\n 'mspointercancel',\n 'mspointerdown',\n 'mspointerenter',\n 'mspointerhover',\n 'mspointerleave',\n 'mspointermove',\n 'mspointerout',\n 'mspointerover',\n 'mspointerup',\n 'pointerout',\n 'mssitemodejumplistitemremoved',\n 'msthumbnailclick',\n 'stop',\n 'storagecommit'\n];\nvar webglEventNames = ['webglcontextrestored', 'webglcontextlost', 'webglcontextcreationerror'];\nvar formEventNames = ['autocomplete', 'autocompleteerror'];\nvar detailEventNames = ['toggle'];\nvar frameEventNames = ['load'];\nvar frameSetEventNames = ['blur', 'error', 'focus', 'load', 'resize', 'scroll', 'messageerror'];\nvar marqueeEventNames = ['bounce', 'finish', 'start'];\nvar XMLHttpRequestEventNames = [\n 'loadstart', 'progress', 'abort', 'error', 'load', 'progress', 'timeout', 'loadend',\n 'readystatechange'\n];\nvar IDBIndexEventNames = ['upgradeneeded', 'complete', 'abort', 'success', 'error', 'blocked', 'versionchange', 'close'];\nvar websocketEventNames = ['close', 'error', 'open', 'message'];\nvar workerEventNames = ['error', 'message'];\nvar eventNames = globalEventHandlersEventNames.concat(webglEventNames, formEventNames, detailEventNames, documentEventNames, windowEventNames, htmlElementEventNames, ieElementEventNames);\nfunction filterProperties(target, onProperties, ignoreProperties) {\n if (!ignoreProperties) {\n return onProperties;\n }\n var tip = ignoreProperties.filter(function (ip) { return ip.target === target; });\n if (!tip || tip.length === 0) {\n return onProperties;\n }\n var targetIgnoreProperties = tip[0].ignoreProperties;\n return onProperties.filter(function (op) { return targetIgnoreProperties.indexOf(op) === -1; });\n}\nfunction patchFilteredProperties(target, onProperties, ignoreProperties, prototype) {\n // check whether target is available, sometimes target will be undefined\n // because different browser or some 3rd party plugin.\n if (!target) {\n return;\n }\n var filteredProperties = filterProperties(target, onProperties, ignoreProperties);\n patchOnProperties(target, filteredProperties, prototype);\n}\nfunction propertyDescriptorPatch(api, _global) {\n if (isNode && !isMix) {\n return;\n }\n var supportsWebSocket = typeof WebSocket !== 'undefined';\n if (canPatchViaPropertyDescriptor()) {\n var ignoreProperties = _global.__Zone_ignore_on_properties;\n // for browsers that we can patch the descriptor: Chrome & Firefox\n if (isBrowser) {\n var internalWindow = window;\n // in IE/Edge, onProp not exist in window object, but in WindowPrototype\n // so we need to pass WindowPrototype to check onProp exist or not\n patchFilteredProperties(internalWindow, eventNames.concat(['messageerror']), ignoreProperties, ObjectGetPrototypeOf(internalWindow));\n patchFilteredProperties(Document.prototype, eventNames, ignoreProperties);\n if (typeof internalWindow['SVGElement'] !== 'undefined') {\n patchFilteredProperties(internalWindow['SVGElement'].prototype, eventNames, ignoreProperties);\n }\n patchFilteredProperties(Element.prototype, eventNames, ignoreProperties);\n patchFilteredProperties(HTMLElement.prototype, eventNames, ignoreProperties);\n patchFilteredProperties(HTMLMediaElement.prototype, mediaElementEventNames, ignoreProperties);\n patchFilteredProperties(HTMLFrameSetElement.prototype, windowEventNames.concat(frameSetEventNames), ignoreProperties);\n patchFilteredProperties(HTMLBodyElement.prototype, windowEventNames.concat(frameSetEventNames), ignoreProperties);\n patchFilteredProperties(HTMLFrameElement.prototype, frameEventNames, ignoreProperties);\n patchFilteredProperties(HTMLIFrameElement.prototype, frameEventNames, ignoreProperties);\n var HTMLMarqueeElement_1 = internalWindow['HTMLMarqueeElement'];\n if (HTMLMarqueeElement_1) {\n patchFilteredProperties(HTMLMarqueeElement_1.prototype, marqueeEventNames, ignoreProperties);\n }\n var Worker_1 = internalWindow['Worker'];\n if (Worker_1) {\n patchFilteredProperties(Worker_1.prototype, workerEventNames, ignoreProperties);\n }\n }\n patchFilteredProperties(XMLHttpRequest.prototype, XMLHttpRequestEventNames, ignoreProperties);\n var XMLHttpRequestEventTarget = _global['XMLHttpRequestEventTarget'];\n if (XMLHttpRequestEventTarget) {\n patchFilteredProperties(XMLHttpRequestEventTarget && XMLHttpRequestEventTarget.prototype, XMLHttpRequestEventNames, ignoreProperties);\n }\n if (typeof IDBIndex !== 'undefined') {\n patchFilteredProperties(IDBIndex.prototype, IDBIndexEventNames, ignoreProperties);\n patchFilteredProperties(IDBRequest.prototype, IDBIndexEventNames, ignoreProperties);\n patchFilteredProperties(IDBOpenDBRequest.prototype, IDBIndexEventNames, ignoreProperties);\n patchFilteredProperties(IDBDatabase.prototype, IDBIndexEventNames, ignoreProperties);\n patchFilteredProperties(IDBTransaction.prototype, IDBIndexEventNames, ignoreProperties);\n patchFilteredProperties(IDBCursor.prototype, IDBIndexEventNames, ignoreProperties);\n }\n if (supportsWebSocket) {\n patchFilteredProperties(WebSocket.prototype, websocketEventNames, ignoreProperties);\n }\n }\n else {\n // Safari, Android browsers (Jelly Bean)\n patchViaCapturingAllTheEvents();\n patchClass('XMLHttpRequest');\n if (supportsWebSocket) {\n apply(api, _global);\n }\n }\n}\nfunction canPatchViaPropertyDescriptor() {\n if ((isBrowser || isMix) && !ObjectGetOwnPropertyDescriptor(HTMLElement.prototype, 'onclick') &&\n typeof Element !== 'undefined') {\n // WebKit https://bugs.webkit.org/show_bug.cgi?id=134364\n // IDL interface attributes are not configurable\n var desc = ObjectGetOwnPropertyDescriptor(Element.prototype, 'onclick');\n if (desc && !desc.configurable)\n return false;\n }\n var ON_READY_STATE_CHANGE = 'onreadystatechange';\n var XMLHttpRequestPrototype = XMLHttpRequest.prototype;\n var xhrDesc = ObjectGetOwnPropertyDescriptor(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE);\n // add enumerable and configurable here because in opera\n // by default XMLHttpRequest.prototype.onreadystatechange is undefined\n // without adding enumerable and configurable will cause onreadystatechange\n // non-configurable\n // and if XMLHttpRequest.prototype.onreadystatechange is undefined,\n // we should set a real desc instead a fake one\n if (xhrDesc) {\n ObjectDefineProperty(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE, {\n enumerable: true,\n configurable: true,\n get: function () {\n return true;\n }\n });\n var req = new XMLHttpRequest();\n var result = !!req.onreadystatechange;\n // restore original desc\n ObjectDefineProperty(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE, xhrDesc || {});\n return result;\n }\n else {\n var SYMBOL_FAKE_ONREADYSTATECHANGE_1 = zoneSymbol('fake');\n ObjectDefineProperty(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE, {\n enumerable: true,\n configurable: true,\n get: function () {\n return this[SYMBOL_FAKE_ONREADYSTATECHANGE_1];\n },\n set: function (value) {\n this[SYMBOL_FAKE_ONREADYSTATECHANGE_1] = value;\n }\n });\n var req = new XMLHttpRequest();\n var detectFunc = function () { };\n req.onreadystatechange = detectFunc;\n var result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc;\n req.onreadystatechange = null;\n return result;\n }\n}\nvar unboundKey = zoneSymbol('unbound');\n// Whenever any eventListener fires, we check the eventListener target and all parents\n// for `onwhatever` properties and replace them with zone-bound functions\n// - Chrome (for now)\nfunction patchViaCapturingAllTheEvents() {\n var _loop_1 = function (i) {\n var property = eventNames[i];\n var onproperty = 'on' + property;\n self.addEventListener(property, function (event) {\n var elt = event.target, bound, source;\n if (elt) {\n source = elt.constructor['name'] + '.' + onproperty;\n }\n else {\n source = 'unknown.' + onproperty;\n }\n while (elt) {\n if (elt[onproperty] && !elt[onproperty][unboundKey]) {\n bound = wrapWithCurrentZone(elt[onproperty], source);\n bound[unboundKey] = elt[onproperty];\n elt[onproperty] = bound;\n }\n elt = elt.parentElement;\n }\n }, true);\n };\n for (var i = 0; i < eventNames.length; i++) {\n _loop_1(i);\n }\n}\n\n/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\nfunction eventTargetPatch(_global, api) {\n var WTF_ISSUE_555 = 'Anchor,Area,Audio,BR,Base,BaseFont,Body,Button,Canvas,Content,DList,Directory,Div,Embed,FieldSet,Font,Form,Frame,FrameSet,HR,Head,Heading,Html,IFrame,Image,Input,Keygen,LI,Label,Legend,Link,Map,Marquee,Media,Menu,Meta,Meter,Mod,OList,Object,OptGroup,Option,Output,Paragraph,Pre,Progress,Quote,Script,Select,Source,Span,Style,TableCaption,TableCell,TableCol,Table,TableRow,TableSection,TextArea,Title,Track,UList,Unknown,Video';\n var NO_EVENT_TARGET = 'ApplicationCache,EventSource,FileReader,InputMethodContext,MediaController,MessagePort,Node,Performance,SVGElementInstance,SharedWorker,TextTrack,TextTrackCue,TextTrackList,WebKitNamedFlow,Window,Worker,WorkerGlobalScope,XMLHttpRequest,XMLHttpRequestEventTarget,XMLHttpRequestUpload,IDBRequest,IDBOpenDBRequest,IDBDatabase,IDBTransaction,IDBCursor,DBIndex,WebSocket'\n .split(',');\n var EVENT_TARGET = 'EventTarget';\n var apis = [];\n var isWtf = _global['wtf'];\n var WTF_ISSUE_555_ARRAY = WTF_ISSUE_555.split(',');\n if (isWtf) {\n // Workaround for: https://github.com/google/tracing-framework/issues/555\n apis = WTF_ISSUE_555_ARRAY.map(function (v) { return 'HTML' + v + 'Element'; }).concat(NO_EVENT_TARGET);\n }\n else if (_global[EVENT_TARGET]) {\n apis.push(EVENT_TARGET);\n }\n else {\n // Note: EventTarget is not available in all browsers,\n // if it's not available, we instead patch the APIs in the IDL that inherit from EventTarget\n apis = NO_EVENT_TARGET;\n }\n var isDisableIECheck = _global['__Zone_disable_IE_check'] || false;\n var isEnableCrossContextCheck = _global['__Zone_enable_cross_context_check'] || false;\n var ieOrEdge = isIEOrEdge();\n var ADD_EVENT_LISTENER_SOURCE = '.addEventListener:';\n var FUNCTION_WRAPPER = '[object FunctionWrapper]';\n var BROWSER_TOOLS = 'function __BROWSERTOOLS_CONSOLE_SAFEFUNC() { [native code] }';\n // predefine all __zone_symbol__ + eventName + true/false string\n for (var i = 0; i < eventNames.length; i++) {\n var eventName = eventNames[i];\n var falseEventName = eventName + FALSE_STR;\n var trueEventName = eventName + TRUE_STR;\n var symbol = ZONE_SYMBOL_PREFIX + falseEventName;\n var symbolCapture = ZONE_SYMBOL_PREFIX + trueEventName;\n zoneSymbolEventNames$1[eventName] = {};\n zoneSymbolEventNames$1[eventName][FALSE_STR] = symbol;\n zoneSymbolEventNames$1[eventName][TRUE_STR] = symbolCapture;\n }\n // predefine all task.source string\n for (var i = 0; i < WTF_ISSUE_555.length; i++) {\n var target = WTF_ISSUE_555_ARRAY[i];\n var targets = globalSources[target] = {};\n for (var j = 0; j < eventNames.length; j++) {\n var eventName = eventNames[j];\n targets[eventName] = target + ADD_EVENT_LISTENER_SOURCE + eventName;\n }\n }\n var checkIEAndCrossContext = function (nativeDelegate, delegate, target, args) {\n if (!isDisableIECheck && ieOrEdge) {\n if (isEnableCrossContextCheck) {\n try {\n var testString = delegate.toString();\n if ((testString === FUNCTION_WRAPPER || testString == BROWSER_TOOLS)) {\n nativeDelegate.apply(target, args);\n return false;\n }\n }\n catch (error) {\n nativeDelegate.apply(target, args);\n return false;\n }\n }\n else {\n var testString = delegate.toString();\n if ((testString === FUNCTION_WRAPPER || testString == BROWSER_TOOLS)) {\n nativeDelegate.apply(target, args);\n return false;\n }\n }\n }\n else if (isEnableCrossContextCheck) {\n try {\n delegate.toString();\n }\n catch (error) {\n nativeDelegate.apply(target, args);\n return false;\n }\n }\n return true;\n };\n var apiTypes = [];\n for (var i = 0; i < apis.length; i++) {\n var type = _global[apis[i]];\n apiTypes.push(type && type.prototype);\n }\n // vh is validateHandler to check event handler\n // is valid or not(for security check)\n patchEventTarget(_global, apiTypes, { vh: checkIEAndCrossContext });\n api.patchEventTarget = patchEventTarget;\n return true;\n}\nfunction patchEvent(global, api) {\n patchEventPrototype(global, api);\n}\n\n/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\nfunction registerElementPatch(_global) {\n if ((!isBrowser && !isMix) || !('registerElement' in _global.document)) {\n return;\n }\n var _registerElement = document.registerElement;\n var callbacks = ['createdCallback', 'attachedCallback', 'detachedCallback', 'attributeChangedCallback'];\n document.registerElement = function (name, opts) {\n if (opts && opts.prototype) {\n callbacks.forEach(function (callback) {\n var source = 'Document.registerElement::' + callback;\n var prototype = opts.prototype;\n if (prototype.hasOwnProperty(callback)) {\n var descriptor = ObjectGetOwnPropertyDescriptor(prototype, callback);\n if (descriptor && descriptor.value) {\n descriptor.value = wrapWithCurrentZone(descriptor.value, source);\n _redefineProperty(opts.prototype, callback, descriptor);\n }\n else {\n prototype[callback] = wrapWithCurrentZone(prototype[callback], source);\n }\n }\n else if (prototype[callback]) {\n prototype[callback] = wrapWithCurrentZone(prototype[callback], source);\n }\n });\n }\n return _registerElement.call(document, name, opts);\n };\n attachOriginToPatched(document.registerElement, _registerElement);\n}\n\n/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\n/**\n * @fileoverview\n * @suppress {missingRequire}\n */\nZone.__load_patch('util', function (global, Zone, api) {\n api.patchOnProperties = patchOnProperties;\n api.patchMethod = patchMethod;\n api.bindArguments = bindArguments;\n});\nZone.__load_patch('timers', function (global) {\n var set = 'set';\n var clear = 'clear';\n patchTimer(global, set, clear, 'Timeout');\n patchTimer(global, set, clear, 'Interval');\n patchTimer(global, set, clear, 'Immediate');\n});\nZone.__load_patch('requestAnimationFrame', function (global) {\n patchTimer(global, 'request', 'cancel', 'AnimationFrame');\n patchTimer(global, 'mozRequest', 'mozCancel', 'AnimationFrame');\n patchTimer(global, 'webkitRequest', 'webkitCancel', 'AnimationFrame');\n});\nZone.__load_patch('blocking', function (global, Zone) {\n var blockingMethods = ['alert', 'prompt', 'confirm'];\n for (var i = 0; i < blockingMethods.length; i++) {\n var name_1 = blockingMethods[i];\n patchMethod(global, name_1, function (delegate, symbol, name) {\n return function (s, args) {\n return Zone.current.run(delegate, global, args, name);\n };\n });\n }\n});\nZone.__load_patch('EventTarget', function (global, Zone, api) {\n // load blackListEvents from global\n var SYMBOL_BLACK_LISTED_EVENTS = Zone.__symbol__('BLACK_LISTED_EVENTS');\n if (global[SYMBOL_BLACK_LISTED_EVENTS]) {\n Zone[SYMBOL_BLACK_LISTED_EVENTS] = global[SYMBOL_BLACK_LISTED_EVENTS];\n }\n patchEvent(global, api);\n eventTargetPatch(global, api);\n // patch XMLHttpRequestEventTarget's addEventListener/removeEventListener\n var XMLHttpRequestEventTarget = global['XMLHttpRequestEventTarget'];\n if (XMLHttpRequestEventTarget && XMLHttpRequestEventTarget.prototype) {\n api.patchEventTarget(global, [XMLHttpRequestEventTarget.prototype]);\n }\n patchClass('MutationObserver');\n patchClass('WebKitMutationObserver');\n patchClass('IntersectionObserver');\n patchClass('FileReader');\n});\nZone.__load_patch('on_property', function (global, Zone, api) {\n propertyDescriptorPatch(api, global);\n propertyPatch();\n registerElementPatch(global);\n});\nZone.__load_patch('canvas', function (global) {\n var HTMLCanvasElement = global['HTMLCanvasElement'];\n if (typeof HTMLCanvasElement !== 'undefined' && HTMLCanvasElement.prototype &&\n HTMLCanvasElement.prototype.toBlob) {\n patchMacroTask(HTMLCanvasElement.prototype, 'toBlob', function (self, args) {\n return { name: 'HTMLCanvasElement.toBlob', target: self, cbIdx: 0, args: args };\n });\n }\n});\nZone.__load_patch('XHR', function (global, Zone) {\n // Treat XMLHttpRequest as a macrotask.\n patchXHR(global);\n var XHR_TASK = zoneSymbol('xhrTask');\n var XHR_SYNC = zoneSymbol('xhrSync');\n var XHR_LISTENER = zoneSymbol('xhrListener');\n var XHR_SCHEDULED = zoneSymbol('xhrScheduled');\n var XHR_URL = zoneSymbol('xhrURL');\n function patchXHR(window) {\n var XMLHttpRequestPrototype = XMLHttpRequest.prototype;\n function findPendingTask(target) {\n return target[XHR_TASK];\n }\n var oriAddListener = XMLHttpRequestPrototype[ZONE_SYMBOL_ADD_EVENT_LISTENER];\n var oriRemoveListener = XMLHttpRequestPrototype[ZONE_SYMBOL_REMOVE_EVENT_LISTENER];\n if (!oriAddListener) {\n var XMLHttpRequestEventTarget = window['XMLHttpRequestEventTarget'];\n if (XMLHttpRequestEventTarget) {\n var XMLHttpRequestEventTargetPrototype = XMLHttpRequestEventTarget.prototype;\n oriAddListener = XMLHttpRequestEventTargetPrototype[ZONE_SYMBOL_ADD_EVENT_LISTENER];\n oriRemoveListener = XMLHttpRequestEventTargetPrototype[ZONE_SYMBOL_REMOVE_EVENT_LISTENER];\n }\n }\n var READY_STATE_CHANGE = 'readystatechange';\n var SCHEDULED = 'scheduled';\n function scheduleTask(task) {\n XMLHttpRequest[XHR_SCHEDULED] = false;\n var data = task.data;\n var target = data.target;\n // remove existing event listener\n var listener = target[XHR_LISTENER];\n if (!oriAddListener) {\n oriAddListener = target[ZONE_SYMBOL_ADD_EVENT_LISTENER];\n oriRemoveListener = target[ZONE_SYMBOL_REMOVE_EVENT_LISTENER];\n }\n if (listener) {\n oriRemoveListener.call(target, READY_STATE_CHANGE, listener);\n }\n var newListener = target[XHR_LISTENER] = function () {\n if (target.readyState === target.DONE) {\n // sometimes on some browsers XMLHttpRequest will fire onreadystatechange with\n // readyState=4 multiple times, so we need to check task state here\n if (!data.aborted && XMLHttpRequest[XHR_SCHEDULED] && task.state === SCHEDULED) {\n task.invoke();\n }\n }\n };\n oriAddListener.call(target, READY_STATE_CHANGE, newListener);\n var storedTask = target[XHR_TASK];\n if (!storedTask) {\n target[XHR_TASK] = task;\n }\n sendNative.apply(target, data.args);\n XMLHttpRequest[XHR_SCHEDULED] = true;\n return task;\n }\n function placeholderCallback() { }\n function clearTask(task) {\n var data = task.data;\n // Note - ideally, we would call data.target.removeEventListener here, but it's too late\n // to prevent it from firing. So instead, we store info for the event listener.\n data.aborted = true;\n return abortNative.apply(data.target, data.args);\n }\n var openNative = patchMethod(XMLHttpRequestPrototype, 'open', function () { return function (self, args) {\n self[XHR_SYNC] = args[2] == false;\n self[XHR_URL] = args[1];\n return openNative.apply(self, args);\n }; });\n var XMLHTTPREQUEST_SOURCE = 'XMLHttpRequest.send';\n var sendNative = patchMethod(XMLHttpRequestPrototype, 'send', function () { return function (self, args) {\n if (self[XHR_SYNC]) {\n // if the XHR is sync there is no task to schedule, just execute the code.\n return sendNative.apply(self, args);\n }\n else {\n var options = {\n target: self,\n url: self[XHR_URL],\n isPeriodic: false,\n delay: null,\n args: args,\n aborted: false\n };\n return scheduleMacroTaskWithCurrentZone(XMLHTTPREQUEST_SOURCE, placeholderCallback, options, scheduleTask, clearTask);\n }\n }; });\n var abortNative = patchMethod(XMLHttpRequestPrototype, 'abort', function () { return function (self) {\n var task = findPendingTask(self);\n if (task && typeof task.type == 'string') {\n // If the XHR has already completed, do nothing.\n // If the XHR has already been aborted, do nothing.\n // Fix #569, call abort multiple times before done will cause\n // macroTask task count be negative number\n if (task.cancelFn == null || (task.data && task.data.aborted)) {\n return;\n }\n task.zone.cancelTask(task);\n }\n // Otherwise, we are trying to abort an XHR which has not yet been sent, so there is no\n // task\n // to cancel. Do nothing.\n }; });\n }\n});\nZone.__load_patch('geolocation', function (global) {\n /// GEO_LOCATION\n if (global['navigator'] && global['navigator'].geolocation) {\n patchPrototype(global['navigator'].geolocation, ['getCurrentPosition', 'watchPosition']);\n }\n});\nZone.__load_patch('PromiseRejectionEvent', function (global, Zone) {\n // handle unhandled promise rejection\n function findPromiseRejectionHandler(evtName) {\n return function (e) {\n var eventTasks = findEventTasks(global, evtName);\n eventTasks.forEach(function (eventTask) {\n // windows has added unhandledrejection event listener\n // trigger the event listener\n var PromiseRejectionEvent = global['PromiseRejectionEvent'];\n if (PromiseRejectionEvent) {\n var evt = new PromiseRejectionEvent(evtName, { promise: e.promise, reason: e.rejection });\n eventTask.invoke(evt);\n }\n });\n };\n }\n if (global['PromiseRejectionEvent']) {\n Zone[zoneSymbol('unhandledPromiseRejectionHandler')] =\n findPromiseRejectionHandler('unhandledrejection');\n Zone[zoneSymbol('rejectionHandledHandler')] =\n findPromiseRejectionHandler('rejectionhandled');\n }\n});\n\n/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\n\n})));\n","/**\r\n * This file includes polyfills needed by Angular and is loaded before the app.\r\n * You can add your own extra polyfills to this file.\r\n *\r\n * This file is divided into 2 sections:\r\n * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.\r\n * 2. Application imports. Files imported after ZoneJS that should be loaded before your main\r\n * file.\r\n *\r\n * The current setup is for so-called \"evergreen\" browsers; the last versions of browsers that\r\n * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),\r\n * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.\r\n *\r\n * Learn more in https://angular.io/guide/browser-support\r\n */\r\n\r\n/***************************************************************************************************\r\n * BROWSER POLYFILLS\r\n */\r\n\r\n/** IE9, IE10 and IE11 requires all of the following polyfills. **/\r\n// import 'core-js/es6/symbol';\r\n// import 'core-js/es6/object';\r\n// import 'core-js/es6/function';\r\n// import 'core-js/es6/parse-int';\r\n// import 'core-js/es6/parse-float';\r\n// import 'core-js/es6/number';\r\n// import 'core-js/es6/math';\r\n// import 'core-js/es6/string';\r\n// import 'core-js/es6/date';\r\n// import 'core-js/es6/array';\r\n// import 'core-js/es6/regexp';\r\n// import 'core-js/es6/map';\r\n// import 'core-js/es6/weak-map';\r\n// import 'core-js/es6/set';\r\n\r\n/**\r\n * If the application will be indexed by Google Search, the following is required.\r\n * Googlebot uses a renderer based on Chrome 41.\r\n * https://developers.google.com/search/docs/guides/rendering\r\n **/\r\n// import 'core-js/es6/array';\r\n\r\n/** IE10 and IE11 requires the following for NgClass support on SVG elements */\r\n// import 'classlist.js'; // Run `npm install --save classlist.js`.\r\n\r\n/** IE10 and IE11 requires the following for the Reflect API. */\r\n// import 'core-js/es6/reflect';\r\n\r\n/**\r\n * Web Animations `@angular/platform-browser/animations`\r\n * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.\r\n * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).\r\n **/\r\n// import 'web-animations-js'; // Run `npm install --save web-animations-js`.\r\n\r\n/**\r\n * By default, zone.js will patch all possible macroTask and DomEvents\r\n * user can disable parts of macroTask/DomEvents patch by setting following flags\r\n */\r\n\r\n // (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame\r\n // (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick\r\n // (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames\r\n\r\n /*\r\n * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js\r\n * with the following flag, it will bypass `zone.js` patch for IE/Edge\r\n */\r\n// (window as any).__Zone_enable_cross_context_check = true;\r\n\r\n/***************************************************************************************************\r\n * Zone JS is required by default for Angular itself.\r\n */\r\nimport 'zone.js/dist/zone'; // Included with Angular CLI.\r\n\r\n\r\n/***************************************************************************************************\r\n * APPLICATION IMPORTS\r\n */\r\n"],"sourceRoot":""} \ No newline at end of file diff --git a/src/gui/qt-daemon/html/purchase.svg b/src/gui/qt-daemon/html/purchase.svg new file mode 100644 index 00000000..46e904fc --- /dev/null +++ b/src/gui/qt-daemon/html/purchase.svg @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/src/gui/qt-daemon/html/receive.svg b/src/gui/qt-daemon/html/receive.svg new file mode 100644 index 00000000..fd7e85a9 --- /dev/null +++ b/src/gui/qt-daemon/html/receive.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/src/gui/qt-daemon/html/runtime.js b/src/gui/qt-daemon/html/runtime.js new file mode 100644 index 00000000..fd2c03c8 --- /dev/null +++ b/src/gui/qt-daemon/html/runtime.js @@ -0,0 +1,154 @@ +/******/ (function(modules) { // webpackBootstrap +/******/ // install a JSONP callback for chunk loading +/******/ function webpackJsonpCallback(data) { +/******/ var chunkIds = data[0]; +/******/ var moreModules = data[1]; +/******/ var executeModules = data[2]; +/******/ +/******/ // add "moreModules" to the modules object, +/******/ // then flag all "chunkIds" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0, resolves = []; +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(installedChunks[chunkId]) { +/******/ resolves.push(installedChunks[chunkId][0]); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ for(moduleId in moreModules) { +/******/ if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) { +/******/ modules[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(parentJsonpFunction) parentJsonpFunction(data); +/******/ +/******/ while(resolves.length) { +/******/ resolves.shift()(); +/******/ } +/******/ +/******/ // add entry modules from loaded chunk to deferred list +/******/ deferredModules.push.apply(deferredModules, executeModules || []); +/******/ +/******/ // run deferred modules when all chunks ready +/******/ return checkDeferredModules(); +/******/ }; +/******/ function checkDeferredModules() { +/******/ var result; +/******/ for(var i = 0; i < deferredModules.length; i++) { +/******/ var deferredModule = deferredModules[i]; +/******/ var fulfilled = true; +/******/ for(var j = 1; j < deferredModule.length; j++) { +/******/ var depId = deferredModule[j]; +/******/ if(installedChunks[depId] !== 0) fulfilled = false; +/******/ } +/******/ if(fulfilled) { +/******/ deferredModules.splice(i--, 1); +/******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]); +/******/ } +/******/ } +/******/ return result; +/******/ } +/******/ +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // Promise = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ "runtime": 0 +/******/ }; +/******/ +/******/ var deferredModules = []; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || []; +/******/ var oldJsonpFunction = jsonpArray.push.bind(jsonpArray); +/******/ jsonpArray.push = webpackJsonpCallback; +/******/ jsonpArray = jsonpArray.slice(); +/******/ for(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]); +/******/ var parentJsonpFunction = oldJsonpFunction; +/******/ +/******/ +/******/ // run deferred modules from other chunks +/******/ checkDeferredModules(); +/******/ }) +/************************************************************************/ +/******/ ([]); +//# sourceMappingURL=runtime.js.map \ No newline at end of file diff --git a/src/gui/qt-daemon/html/runtime.js.map b/src/gui/qt-daemon/html/runtime.js.map new file mode 100644 index 00000000..c9491c19 --- /dev/null +++ b/src/gui/qt-daemon/html/runtime.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack:///webpack/bootstrap"],"names":[],"mappings":";AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,gBAAQ,oBAAoB;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,yBAAiB,4BAA4B;AAC7C;AACA;AACA,0BAAkB,2BAA2B;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,kDAA0C,gCAAgC;AAC1E;AACA;;AAEA;AACA;AACA;AACA,gEAAwD,kBAAkB;AAC1E;AACA,yDAAiD,cAAc;AAC/D;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iDAAyC,iCAAiC;AAC1E,wHAAgH,mBAAmB,EAAE;AACrI;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;AACA;AACA;AACA,wBAAgB,uBAAuB;AACvC;;;AAGA;AACA","file":"runtime.js","sourcesContent":[" \t// install a JSONP callback for chunk loading\n \tfunction webpackJsonpCallback(data) {\n \t\tvar chunkIds = data[0];\n \t\tvar moreModules = data[1];\n \t\tvar executeModules = data[2];\n\n \t\t// add \"moreModules\" to the modules object,\n \t\t// then flag all \"chunkIds\" as loaded and fire callback\n \t\tvar moduleId, chunkId, i = 0, resolves = [];\n \t\tfor(;i < chunkIds.length; i++) {\n \t\t\tchunkId = chunkIds[i];\n \t\t\tif(installedChunks[chunkId]) {\n \t\t\t\tresolves.push(installedChunks[chunkId][0]);\n \t\t\t}\n \t\t\tinstalledChunks[chunkId] = 0;\n \t\t}\n \t\tfor(moduleId in moreModules) {\n \t\t\tif(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {\n \t\t\t\tmodules[moduleId] = moreModules[moduleId];\n \t\t\t}\n \t\t}\n \t\tif(parentJsonpFunction) parentJsonpFunction(data);\n\n \t\twhile(resolves.length) {\n \t\t\tresolves.shift()();\n \t\t}\n\n \t\t// add entry modules from loaded chunk to deferred list\n \t\tdeferredModules.push.apply(deferredModules, executeModules || []);\n\n \t\t// run deferred modules when all chunks ready\n \t\treturn checkDeferredModules();\n \t};\n \tfunction checkDeferredModules() {\n \t\tvar result;\n \t\tfor(var i = 0; i < deferredModules.length; i++) {\n \t\t\tvar deferredModule = deferredModules[i];\n \t\t\tvar fulfilled = true;\n \t\t\tfor(var j = 1; j < deferredModule.length; j++) {\n \t\t\t\tvar depId = deferredModule[j];\n \t\t\t\tif(installedChunks[depId] !== 0) fulfilled = false;\n \t\t\t}\n \t\t\tif(fulfilled) {\n \t\t\t\tdeferredModules.splice(i--, 1);\n \t\t\t\tresult = __webpack_require__(__webpack_require__.s = deferredModule[0]);\n \t\t\t}\n \t\t}\n \t\treturn result;\n \t}\n\n \t// The module cache\n \tvar installedModules = {};\n\n \t// object to store loaded and loading chunks\n \t// undefined = chunk not loaded, null = chunk preloaded/prefetched\n \t// Promise = chunk loading, 0 = chunk loaded\n \tvar installedChunks = {\n \t\t\"runtime\": 0\n \t};\n\n \tvar deferredModules = [];\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \tvar jsonpArray = window[\"webpackJsonp\"] = window[\"webpackJsonp\"] || [];\n \tvar oldJsonpFunction = jsonpArray.push.bind(jsonpArray);\n \tjsonpArray.push = webpackJsonpCallback;\n \tjsonpArray = jsonpArray.slice();\n \tfor(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);\n \tvar parentJsonpFunction = oldJsonpFunction;\n\n\n \t// run deferred modules from other chunks\n \tcheckDeferredModules();\n"],"sourceRoot":""} \ No newline at end of file diff --git a/src/gui/qt-daemon/html/sell.svg b/src/gui/qt-daemon/html/sell.svg new file mode 100644 index 00000000..f28f0a20 --- /dev/null +++ b/src/gui/qt-daemon/html/sell.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/src/gui/qt-daemon/html/send.svg b/src/gui/qt-daemon/html/send.svg new file mode 100644 index 00000000..0c7e6136 --- /dev/null +++ b/src/gui/qt-daemon/html/send.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/src/gui/qt-daemon/html/settings.svg b/src/gui/qt-daemon/html/settings.svg new file mode 100644 index 00000000..105d2282 --- /dev/null +++ b/src/gui/qt-daemon/html/settings.svg @@ -0,0 +1,17 @@ + + + + + + + + + diff --git a/src/gui/qt-daemon/html/staking.svg b/src/gui/qt-daemon/html/staking.svg new file mode 100644 index 00000000..2f4337f6 --- /dev/null +++ b/src/gui/qt-daemon/html/staking.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/src/gui/qt-daemon/html/styles.js b/src/gui/qt-daemon/html/styles.js new file mode 100644 index 00000000..1c6c47eb --- /dev/null +++ b/src/gui/qt-daemon/html/styles.js @@ -0,0 +1,564 @@ +(window["webpackJsonp"] = window["webpackJsonp"] || []).push([["styles"],{ + +/***/ "./node_modules/@angular-devkit/build-angular/src/angular-cli-files/plugins/raw-css-loader.js!./node_modules/postcss-loader/lib/index.js?!./node_modules/sass-loader/lib/loader.js?!./src/styles.scss": +/*!**********************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/@angular-devkit/build-angular/src/angular-cli-files/plugins/raw-css-loader.js!./node_modules/postcss-loader/lib??embedded!./node_modules/sass-loader/lib/loader.js??ref--14-3!./src/styles.scss ***! + \**********************************************************************************************************************************************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = [[module.i, "/*\r\n* Implementation of themes\r\n*/\nhtml {\n box-sizing: border-box;\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box; }\n*, *:before, *:after {\n box-sizing: inherit;\n -webkit-box-sizing: inherit;\n -moz-box-sizing: inherit;\n margin: 0;\n padding: 0;\n -webkit-touch-collout: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none; }\nhtml, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header, hgroup,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n border: 0;\n font-size: 100%;\n font: inherit;\n vertical-align: baseline; }\narticle, aside, details, figcaption, figure,\nfooter, header, hgroup, menu, nav, section {\n display: block; }\nbody {\n line-height: 1;\n font-style: normal; }\nol, ul {\n list-style: none; }\nblockquote, q {\n quotes: none; }\nblockquote:before, blockquote:after,\nq:before, q:after {\n content: none; }\ntable {\n border-collapse: collapse;\n border-spacing: 0; }\ntd,\nth {\n padding: 0; }\ninput {\n outline: none; }\ninput:-webkit-autofill {\n -webkit-box-shadow: 0 0 0 1000px white inset; }\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button;\n cursor: pointer;\n outline: none; }\nbutton[disabled],\nhtml input[disabled] {\n cursor: default; }\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0; }\ninput {\n line-height: normal; }\ninput[type=\"search\"] {\n -webkit-appearance: textfield;\n box-sizing: content-box; }\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none; }\na {\n text-decoration: none; }\na:active, a:hover, a:focus {\n outline: 0; }\ni {\n font-style: italic; }\nb, strong {\n font-weight: 700; }\nimg {\n width: auto;\n max-width: 100%;\n height: auto;\n vertical-align: top;\n border: 0; }\n.hidden {\n display: none !important; }\nbutton {\n border: none;\n font-family: 'Open Sans', sans-serif;\n font-size: 1.5rem;\n font-weight: 600;\n outline: none;\n padding: 0 1rem;\n height: 4.2rem; }\n.theme-dark button:disabled:not(.transparent-button) {\n background-color: #90a4ae;\n color: #111921; }\n.theme-gray button:disabled:not(.transparent-button) {\n background-color: #79848f;\n color: #1a1a1a; }\n.theme-white button:disabled:not(.transparent-button) {\n background-color: #90a4ae;\n color: #fefefe; }\n.theme-dark button:disabled:not(.transparent-button):hover {\n background-color: #9bb0ba; }\n.theme-gray button:disabled:not(.transparent-button):hover {\n background-color: #85909b; }\n.theme-white button:disabled:not(.transparent-button):hover {\n background-color: #9baeb7; }\n.theme-dark button.blue-button:not(:disabled) {\n background-color: #4db1ff;\n color: #111921; }\n.theme-gray button.blue-button:not(:disabled) {\n background-color: #42a5f5;\n color: #1a1a1a; }\n.theme-white button.blue-button:not(:disabled) {\n background-color: #2c95f1;\n color: #fefefe; }\n.theme-dark button.blue-button:not(:disabled):hover {\n background-color: #60b9ff; }\n.theme-gray button.blue-button:not(:disabled):hover {\n background-color: #4dafff; }\n.theme-white button.blue-button:not(:disabled):hover {\n background-color: #379ffa; }\n.theme-dark button.green-button:not(:disabled) {\n background-color: #5cda9d;\n color: #111921; }\n.theme-gray button.green-button:not(:disabled) {\n background-color: #47cf8d;\n color: #1a1a1a; }\n.theme-white button.green-button:not(:disabled) {\n background-color: #46c172;\n color: #fefefe; }\n.theme-dark button.green-button:not(:disabled):hover {\n background-color: #5ce2a1; }\n.theme-gray button.green-button:not(:disabled):hover {\n background-color: #49d993; }\n.theme-white button.green-button:not(:disabled):hover {\n background-color: #46ca75; }\n.theme-dark button.turquoise-button:not(:disabled) {\n background-color: #4dd0e1;\n color: #111921; }\n.theme-gray button.turquoise-button:not(:disabled) {\n background-color: #3ec5d7;\n color: #1a1a1a; }\n.theme-white button.turquoise-button:not(:disabled) {\n background-color: #26b6c7;\n color: #fefefe; }\n.theme-dark button.turquoise-button:not(:disabled):hover {\n background-color: #52d9ea; }\n.theme-gray button.turquoise-button:not(:disabled):hover {\n background-color: #43cee0; }\n.theme-white button.turquoise-button:not(:disabled):hover {\n background-color: #2bbdcf; }\nbutton.transparent-button {\n display: flex;\n align-items: center;\n justify-content: center; }\n.theme-dark button.transparent-button {\n background-color: transparent;\n border: 0.2rem solid #2b3644;\n color: #e0e0e0; }\n.theme-gray button.transparent-button {\n background-color: transparent;\n border: 0.2rem solid #2f3438;\n color: #e0e0e0; }\n.theme-white button.transparent-button {\n background-color: transparent;\n border: 0.2rem solid #ebebeb;\n color: #43454b; }\nbutton.transparent-button .icon {\n margin-right: 1rem;\n -webkit-mask: url('complete-testwallet.svg') no-repeat center;\n mask: url('complete-testwallet.svg') no-repeat center;\n width: 1.7rem;\n height: 1.7rem; }\n.theme-dark button.transparent-button .icon {\n background-color: #e0e0e0; }\n.theme-gray button.transparent-button .icon {\n background-color: #e0e0e0; }\n.theme-white button.transparent-button .icon {\n background-color: #43454b; }\n.input-block {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n margin-bottom: 0.4rem;\n height: 6.6rem; }\n.input-block .wrap-label {\n display: flex;\n align-items: center;\n justify-content: flex-start;\n min-height: 2.4rem; }\n.input-block label {\n font-size: 1.3rem;\n line-height: 2.4rem; }\n.theme-dark .input-block label {\n color: #556576; }\n.theme-gray .input-block label {\n color: #565c62; }\n.theme-white .input-block label {\n color: #a0a5ab; }\n.input-block input[type='text'], .input-block input[type='password'] {\n border: none;\n font-size: 1.4rem;\n outline: none;\n padding: 0 1rem;\n width: 100%;\n height: 100%; }\n.theme-dark .input-block input[type='text'], .theme-dark .input-block input[type='password'] {\n background-color: #171e27;\n color: #e0e0e0; }\n.theme-gray .input-block input[type='text'], .theme-gray .input-block input[type='password'] {\n background-color: #292d31;\n color: #e0e0e0; }\n.theme-white .input-block input[type='text'], .theme-white .input-block input[type='password'] {\n background-color: #e6e6e6;\n color: #43454b; }\n.input-block.textarea {\n height: auto; }\n.input-block.textarea textarea {\n font-family: 'Open Sans', sans-serif;\n border: none;\n font-size: 1.4rem;\n outline: none;\n padding: 1rem;\n width: 100%;\n min-width: 100%;\n height: 100%;\n min-height: 7rem;\n max-height: 7rem;\n overflow: hidden;\n resize: none; }\n.theme-dark .input-block.textarea textarea {\n background-color: #171e27;\n color: #e0e0e0; }\n.theme-gray .input-block.textarea textarea {\n background-color: #292d31;\n color: #e0e0e0; }\n.theme-white .input-block.textarea textarea {\n background-color: #e6e6e6;\n color: #43454b; }\ninput[type='radio'].style-radio + label {\n display: flex;\n align-items: center;\n cursor: pointer;\n font-weight: 400;\n padding-left: 2.4rem;\n -webkit-touch-collout: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none; }\n.theme-dark input[type='radio'].style-radio + label {\n color: #556576; }\n.theme-gray input[type='radio'].style-radio + label {\n color: #565c62; }\n.theme-white input[type='radio'].style-radio + label {\n color: #a0a5ab; }\ninput[type='radio'].style-radio:not(checked) {\n position: absolute;\n opacity: 0; }\ninput[type='radio'].style-radio:not(checked) + label {\n position: relative; }\ninput[type='radio'].style-radio:not(checked) + label:before {\n content: '';\n position: absolute;\n top: 0.7rem;\n left: 0;\n background: transparent;\n border-radius: 50%;\n width: 1.4rem;\n height: 1.4rem; }\n.theme-dark input[type='radio'].style-radio:not(checked) + label:before {\n border: 0.1rem solid #4db1ff; }\n.theme-gray input[type='radio'].style-radio:not(checked) + label:before {\n border: 0.1rem solid #42a5f5; }\n.theme-white input[type='radio'].style-radio:not(checked) + label:before {\n border: 0.1rem solid #2c95f1; }\ninput[type='radio'].style-radio:not(checked) + label:after {\n content: '';\n position: absolute;\n top: 1rem;\n left: 0.3rem;\n border-radius: 50%;\n opacity: 0;\n width: 0.8rem;\n height: 0.8rem; }\n.theme-dark input[type='radio'].style-radio:not(checked) + label:after {\n background-color: #4db1ff; }\n.theme-gray input[type='radio'].style-radio:not(checked) + label:after {\n background-color: #42a5f5; }\n.theme-white input[type='radio'].style-radio:not(checked) + label:after {\n background-color: #2c95f1; }\ninput[type='radio'].style-radio:checked + label:after {\n opacity: 1; }\ninput[type='checkbox'].style-checkbox + label {\n display: flex;\n align-items: center;\n cursor: pointer;\n font-weight: 400;\n padding-left: 3.6rem;\n -webkit-touch-collout: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none; }\n.theme-dark input[type='checkbox'].style-checkbox + label {\n color: #556576; }\n.theme-gray input[type='checkbox'].style-checkbox + label {\n color: #565c62; }\n.theme-white input[type='checkbox'].style-checkbox + label {\n color: #a0a5ab; }\ninput[type='checkbox'].style-checkbox:not(checked) {\n position: absolute;\n top: 50%;\n left: 1.6rem;\n -webkit-transform: translateY(-50%);\n transform: translateY(-50%);\n visibility: hidden; }\ninput[type='checkbox'].style-checkbox:not(checked) + label {\n position: relative; }\ninput[type='checkbox'].style-checkbox:not(checked) + label:before {\n content: '';\n position: absolute;\n top: 50%;\n left: 1.6rem;\n -webkit-transform: translateY(-50%);\n transform: translateY(-50%);\n background: transparent;\n width: 1.4rem;\n height: 1.4rem; }\n.theme-dark input[type='checkbox'].style-checkbox:not(checked) + label:before {\n border: 0.1rem solid #4db1ff; }\n.theme-gray input[type='checkbox'].style-checkbox:not(checked) + label:before {\n border: 0.1rem solid #42a5f5; }\n.theme-white input[type='checkbox'].style-checkbox:not(checked) + label:before {\n border: 0.1rem solid #2c95f1; }\ninput[type='checkbox'].style-checkbox:checked + label:before {\n background: url('complete-testwallet.svg'); }\n.theme-dark input[type='checkbox'].style-checkbox:checked + label:before {\n background-color: #4db1ff; }\n.theme-gray input[type='checkbox'].style-checkbox:checked + label:before {\n background-color: #42a5f5; }\n.theme-white input[type='checkbox'].style-checkbox:checked + label:before {\n background-color: #2c95f1; }\n.error-block {\n font-size: 1.2rem;\n text-align: right; }\n.theme-dark .error-block {\n color: #ff5252; }\n.theme-gray .error-block {\n color: #ff5252; }\n.theme-white .error-block {\n color: #ff5252; }\n.history-tooltip {\n font-size: 1.3rem;\n padding: 1rem 2rem; }\n.theme-dark .history-tooltip {\n background: #42505f;\n box-shadow: 0 0 1rem rgba(0, 0, 0, 0.5);\n color: #e0e0e0; }\n.theme-gray .history-tooltip {\n background: #3e464c;\n box-shadow: 0 0 1rem rgba(0, 0, 0, 0.5);\n color: #e0e0e0; }\n.theme-white .history-tooltip {\n background: #ffffff;\n box-shadow: 0 0 1rem rgba(120, 120, 120, 0.5);\n color: #43454b; }\n.history-tooltip.ng-tooltip-top {\n margin-top: -1rem; }\n.history-tooltip.ng-tooltip-top:before {\n content: \"\";\n position: absolute;\n bottom: -1rem;\n left: 0.7rem;\n border-width: 1rem 1rem 0 0;\n border-style: solid; }\n.theme-dark .history-tooltip.ng-tooltip-top:before {\n border-color: #42505f transparent transparent transparent; }\n.theme-gray .history-tooltip.ng-tooltip-top:before {\n border-color: #3e464c transparent transparent transparent; }\n.theme-white .history-tooltip.ng-tooltip-top:before {\n border-color: #ffffff transparent transparent transparent; }\n.history-tooltip.ng-tooltip-bottom {\n margin-top: 1rem; }\n.history-tooltip.ng-tooltip-bottom:before {\n content: \"\";\n position: absolute;\n top: -1rem;\n left: 0.7rem;\n border-width: 1rem 0 0 1rem;\n border-style: solid; }\n.theme-dark .history-tooltip.ng-tooltip-bottom:before {\n border-color: transparent transparent transparent #42505f; }\n.theme-gray .history-tooltip.ng-tooltip-bottom:before {\n border-color: transparent transparent transparent #3e464c; }\n.theme-white .history-tooltip.ng-tooltip-bottom:before {\n border-color: transparent transparent transparent #ffffff; }\n.history-tooltip.ng-tooltip-left {\n margin-left: -1rem; }\n.history-tooltip.ng-tooltip-left:before {\n content: \"\";\n position: absolute;\n top: 0;\n right: -1rem;\n border-width: 1rem 1rem 0 0;\n border-style: solid; }\n.theme-dark .history-tooltip.ng-tooltip-left:before {\n border-color: #42505f transparent transparent transparent; }\n.theme-gray .history-tooltip.ng-tooltip-left:before {\n border-color: #3e464c transparent transparent transparent; }\n.theme-white .history-tooltip.ng-tooltip-left:before {\n border-color: #ffffff transparent transparent transparent; }\n.history-tooltip.ng-tooltip-right {\n margin-left: 1rem; }\n.history-tooltip.ng-tooltip-right:before {\n content: \"\";\n position: absolute;\n top: 0;\n left: -1rem;\n border-width: 1rem 0 0 1rem;\n border-style: solid; }\n.theme-dark .history-tooltip.ng-tooltip-right:before {\n border-color: #42505f transparent transparent transparent; }\n.theme-gray .history-tooltip.ng-tooltip-right:before {\n border-color: #3e464c transparent transparent transparent; }\n.theme-white .history-tooltip.ng-tooltip-right:before {\n border-color: #ffffff transparent transparent transparent; }\n.theme-dark .modal {\n background: #42505f;\n color: #e0e0e0; }\n.theme-gray .modal {\n background: #3e464c;\n color: #e0e0e0; }\n.theme-white .modal {\n background: #ffffff;\n color: #43454b; }\n.theme-dark .modal .action-button {\n background-color: #4db1ff;\n color: #111921; }\n.theme-gray .modal .action-button {\n background-color: #42a5f5;\n color: #1a1a1a; }\n.theme-white .modal .action-button {\n background-color: #2c95f1;\n color: #fefefe; }\napp-main, app-create-wallet, app-open-wallet, app-restore-wallet, app-seed-phrase, app-wallet-details, app-settings, app-login {\n flex: 1 1 auto;\n padding: 3rem;\n min-width: 85rem; }\napp-main .content, app-create-wallet .content, app-open-wallet .content, app-restore-wallet .content, app-seed-phrase .content, app-wallet-details .content, app-settings .content, app-login .content {\n position: relative;\n padding: 3rem;\n min-height: 100%; }\n.theme-dark app-main .content, .theme-dark app-create-wallet .content, .theme-dark app-open-wallet .content, .theme-dark app-restore-wallet .content, .theme-dark app-seed-phrase .content, .theme-dark app-wallet-details .content, .theme-dark app-settings .content, .theme-dark app-login .content {\n background-color: rgba(43, 54, 68, 0.5);\n color: #e0e0e0; }\n.theme-gray app-main .content, .theme-gray app-create-wallet .content, .theme-gray app-open-wallet .content, .theme-gray app-restore-wallet .content, .theme-gray app-seed-phrase .content, .theme-gray app-wallet-details .content, .theme-gray app-settings .content, .theme-gray app-login .content {\n background-color: rgba(37, 40, 43, 0.5);\n color: #e0e0e0; }\n.theme-white app-main .content, .theme-white app-create-wallet .content, .theme-white app-open-wallet .content, .theme-white app-restore-wallet .content, .theme-white app-seed-phrase .content, .theme-white app-wallet-details .content, .theme-white app-settings .content, .theme-white app-login .content {\n background-color: rgba(255, 255, 255, 0.5);\n color: #43454b; }\napp-main .content .head, app-create-wallet .content .head, app-open-wallet .content .head, app-restore-wallet .content .head, app-seed-phrase .content .head, app-wallet-details .content .head, app-settings .content .head, app-login .content .head {\n position: absolute;\n top: 0;\n left: 0; }\n.theme-dark app-main .content .add-wallet .add-wallet-help {\n color: #4db1ff; }\n.theme-gray app-main .content .add-wallet .add-wallet-help {\n color: #42a5f5; }\n.theme-white app-main .content .add-wallet .add-wallet-help {\n color: #2c95f1; }\n.theme-dark app-main .content .add-wallet .add-wallet-help .icon {\n background-color: #4db1ff; }\n.theme-gray app-main .content .add-wallet .add-wallet-help .icon {\n background-color: #42a5f5; }\n.theme-white app-main .content .add-wallet .add-wallet-help .icon {\n background-color: #2c95f1; }\n.theme-dark app-seed-phrase .seed-phrase-content {\n background-color: #171e27;\n color: #e0e0e0; }\n.theme-gray app-seed-phrase .seed-phrase-content {\n background-color: #292d31;\n color: #e0e0e0; }\n.theme-white app-seed-phrase .seed-phrase-content {\n background-color: #e6e6e6;\n color: #43454b; }\n.theme-dark app-wallet-details .seed-phrase {\n background-color: #171e27; }\n.theme-gray app-wallet-details .seed-phrase {\n background-color: #292d31; }\n.theme-white app-wallet-details .seed-phrase {\n background-color: #e6e6e6; }\n.theme-dark app-settings .content .theme-selection {\n color: #556576; }\n.theme-gray app-settings .content .theme-selection {\n color: #565c62; }\n.theme-white app-settings .content .theme-selection {\n color: #a0a5ab; }\napp-login {\n min-width: inherit; }\n.theme-dark .switch {\n background-color: #000000; }\n.theme-gray .switch {\n background-color: #000000; }\n.theme-white .switch {\n background-color: #e0e0e0; }\n.theme-dark .switch .circle.on {\n background-color: #4db1ff; }\n.theme-gray .switch .circle.on {\n background-color: #42a5f5; }\n.theme-white .switch .circle.on {\n background-color: #2c95f1; }\n.theme-dark .switch .circle.off {\n background-color: #556576; }\n.theme-gray .switch .circle.off {\n background-color: #565c62; }\n.theme-white .switch .circle.off {\n background-color: #a0a5ab; }\n.theme-dark app-sidebar {\n background-color: rgba(23, 31, 39, 0.5); }\n.theme-gray app-sidebar {\n background-color: rgba(23, 25, 27, 0.5); }\n.theme-white app-sidebar {\n background-color: rgba(255, 255, 255, 0.5); }\n.theme-dark app-sidebar .sidebar-accounts .sidebar-accounts-header h3 {\n color: #e0e0e0; }\n.theme-gray app-sidebar .sidebar-accounts .sidebar-accounts-header h3 {\n color: #e0e0e0; }\n.theme-white app-sidebar .sidebar-accounts .sidebar-accounts-header h3 {\n color: #43454b; }\n.theme-dark app-sidebar .sidebar-accounts .sidebar-accounts-header button {\n color: #4db1ff; }\n.theme-gray app-sidebar .sidebar-accounts .sidebar-accounts-header button {\n color: #42a5f5; }\n.theme-white app-sidebar .sidebar-accounts .sidebar-accounts-header button {\n color: #2c95f1; }\n.theme-dark app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account {\n background-color: transparent;\n color: #e0e0e0; }\n.theme-gray app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account {\n background-color: transparent;\n color: #e0e0e0; }\n.theme-white app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account {\n background-color: transparent;\n color: #43454b; }\n.theme-dark app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row .text {\n color: #556576; }\n.theme-gray app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row .text {\n color: #565c62; }\n.theme-white app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row .text {\n color: #a0a5ab; }\n.theme-dark app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row .indicator {\n background-color: #4db1ff;\n color: #111921; }\n.theme-gray app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row .indicator {\n background-color: #42a5f5;\n color: #1a1a1a; }\n.theme-white app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row .indicator {\n background-color: #2c95f1;\n color: #fefefe; }\n.theme-dark app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row .progress-bar-container .progress-bar {\n background-color: #343f4a; }\n.theme-gray app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row .progress-bar-container .progress-bar {\n background-color: #363a3e; }\n.theme-white app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row .progress-bar-container .progress-bar {\n background-color: #dcdcdc; }\n.theme-dark app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row .progress-bar-container .progress-bar .fill {\n background-color: #5cda9d; }\n.theme-gray app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row .progress-bar-container .progress-bar .fill {\n background-color: #47cf8d; }\n.theme-white app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row .progress-bar-container .progress-bar .fill {\n background-color: #46c172; }\n.theme-dark app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-synchronization {\n color: #556576; }\n.theme-gray app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-synchronization {\n color: #565c62; }\n.theme-white app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account .sidebar-account-row.account-synchronization {\n color: #a0a5ab; }\n.theme-dark app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account.active {\n background-color: rgba(43, 54, 68, 0.5);\n color: #e0e0e0; }\n.theme-gray app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account.active {\n background-color: rgba(37, 40, 43, 0.5);\n color: #e0e0e0; }\n.theme-white app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account.active {\n background-color: #1e88e5;\n color: #ffffff; }\n.theme-dark app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account.active .sidebar-account-row .text {\n color: #556576; }\n.theme-gray app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account.active .sidebar-account-row .text {\n color: #565c62; }\n.theme-white app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account.active .sidebar-account-row .text {\n color: #91baf1; }\n.theme-dark app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account.active .sidebar-account-row .indicator {\n background-color: #4db1ff;\n color: #111921; }\n.theme-gray app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account.active .sidebar-account-row .indicator {\n background-color: #42a5f5;\n color: #1a1a1a; }\n.theme-white app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account.active .sidebar-account-row .indicator {\n background-color: #ffffff;\n color: #43454b; }\n.theme-dark app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account.active .sidebar-account-row .switch {\n background-color: #000000;\n color: #e0e0e0; }\n.theme-gray app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account.active .sidebar-account-row .switch {\n background-color: #000000;\n color: #e0e0e0; }\n.theme-white app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account.active .sidebar-account-row .switch {\n background-color: #ffffff;\n color: #43454b; }\n.theme-dark app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account.active .sidebar-account-row.account-synchronization {\n color: #556576; }\n.theme-gray app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account.active .sidebar-account-row.account-synchronization {\n color: #565c62; }\n.theme-white app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account.active .sidebar-account-row.account-synchronization {\n color: #91baf1; }\n.theme-dark app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account:hover:not(.active) {\n background-color: rgba(58, 72, 90, 0.5); }\n.theme-gray app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account:hover:not(.active) {\n background-color: rgba(70, 76, 81, 0.5); }\n.theme-white app-sidebar .sidebar-accounts .sidebar-accounts-list .sidebar-account:hover:not(.active) {\n background-color: rgba(240, 240, 240, 0.5); }\n.theme-dark app-sidebar .sidebar-settings {\n border-bottom: 0.2rem solid #1f2833; }\n.theme-gray app-sidebar .sidebar-settings {\n border-bottom: 0.2rem solid #2e3337; }\n.theme-white app-sidebar .sidebar-settings {\n border-bottom: 0.2rem solid #ebebeb; }\n.theme-dark app-sidebar .sidebar-settings button {\n color: #e0e0e0; }\n.theme-gray app-sidebar .sidebar-settings button {\n color: #e0e0e0; }\n.theme-white app-sidebar .sidebar-settings button {\n color: #43454b; }\n.theme-dark app-sidebar .sidebar-settings button .icon {\n background-color: #4db1ff; }\n.theme-gray app-sidebar .sidebar-settings button .icon {\n background-color: #42a5f5; }\n.theme-white app-sidebar .sidebar-settings button .icon {\n background-color: #2c95f1; }\n.theme-dark app-sidebar .sidebar-synchronization-status {\n color: #556576; }\n.theme-gray app-sidebar .sidebar-synchronization-status {\n color: #565c62; }\n.theme-white app-sidebar .sidebar-synchronization-status {\n color: #a0a5ab; }\n.theme-dark app-sidebar .sidebar-synchronization-status .status-container .offline:before {\n background-color: #fe5252; }\n.theme-gray app-sidebar .sidebar-synchronization-status .status-container .offline:before {\n background-color: #ff5252; }\n.theme-white app-sidebar .sidebar-synchronization-status .status-container .offline:before {\n background-color: #ff5252; }\n.theme-dark app-sidebar .sidebar-synchronization-status .status-container .online:before {\n background-color: #5cda9d; }\n.theme-gray app-sidebar .sidebar-synchronization-status .status-container .online:before {\n background-color: #47cf8d; }\n.theme-white app-sidebar .sidebar-synchronization-status .status-container .online:before {\n background-color: #46c172; }\n.theme-dark app-sidebar .sidebar-synchronization-status .progress-bar-container .syncing .progress-bar {\n background-color: #343f4a; }\n.theme-gray app-sidebar .sidebar-synchronization-status .progress-bar-container .syncing .progress-bar {\n background-color: #363a3e; }\n.theme-white app-sidebar .sidebar-synchronization-status .progress-bar-container .syncing .progress-bar {\n background-color: #dcdcdc; }\n.theme-dark app-sidebar .sidebar-synchronization-status .progress-bar-container .syncing .progress-bar .fill {\n background-color: #5cda9d; }\n.theme-gray app-sidebar .sidebar-synchronization-status .progress-bar-container .syncing .progress-bar .fill {\n background-color: #47cf8d; }\n.theme-white app-sidebar .sidebar-synchronization-status .progress-bar-container .syncing .progress-bar .fill {\n background-color: #46c172; }\n.theme-dark app-sidebar .sidebar-synchronization-status .progress-bar-container .loading {\n background-color: #5cda9d; }\n.theme-gray app-sidebar .sidebar-synchronization-status .progress-bar-container .loading {\n background-color: #47cf8d; }\n.theme-white app-sidebar .sidebar-synchronization-status .progress-bar-container .loading {\n background-color: #46c172; }\n.theme-dark app-wallet {\n color: #e0e0e0; }\n.theme-gray app-wallet {\n color: #e0e0e0; }\n.theme-white app-wallet {\n color: #43454b; }\n.theme-dark app-wallet .header button {\n color: #e0e0e0; }\n.theme-gray app-wallet .header button {\n color: #e0e0e0; }\n.theme-white app-wallet .header button {\n color: #43454b; }\n.theme-dark app-wallet .header button .icon {\n background-color: #4db1ff; }\n.theme-gray app-wallet .header button .icon {\n background-color: #42a5f5; }\n.theme-white app-wallet .header button .icon {\n background-color: #2c95f1; }\n.theme-dark app-wallet .address {\n color: #4db1ff; }\n.theme-gray app-wallet .address {\n color: #42a5f5; }\n.theme-white app-wallet .address {\n color: #2c95f1; }\n.theme-dark app-wallet .address .icon {\n background-color: #4db1ff; }\n.theme-gray app-wallet .address .icon {\n background-color: #42a5f5; }\n.theme-white app-wallet .address .icon {\n background-color: #2c95f1; }\n.theme-dark app-wallet .tabs .tabs-header .tab {\n background-color: rgba(23, 31, 39, 0.5); }\n.theme-gray app-wallet .tabs .tabs-header .tab {\n background-color: rgba(23, 25, 27, 0.5); }\n.theme-white app-wallet .tabs .tabs-header .tab {\n background-color: rgba(224, 224, 224, 0.5); }\n.theme-dark app-wallet .tabs .tabs-header .tab .icon {\n background-color: #4db1ff; }\n.theme-gray app-wallet .tabs .tabs-header .tab .icon {\n background-color: #42a5f5; }\n.theme-white app-wallet .tabs .tabs-header .tab .icon {\n background-color: #2c95f1; }\n.theme-dark app-wallet .tabs .tabs-header .tab .indicator {\n background-color: #4db1ff;\n color: #111921; }\n.theme-gray app-wallet .tabs .tabs-header .tab .indicator {\n background-color: #42a5f5;\n color: #1a1a1a; }\n.theme-white app-wallet .tabs .tabs-header .tab .indicator {\n background-color: #ffffff;\n color: #43454b; }\n.theme-dark app-wallet .tabs .tabs-header .tab.active {\n background-color: rgba(43, 54, 68, 0.5); }\n.theme-gray app-wallet .tabs .tabs-header .tab.active {\n background-color: rgba(37, 40, 43, 0.5); }\n.theme-white app-wallet .tabs .tabs-header .tab.active {\n background-color: rgba(255, 255, 255, 0.5); }\n.theme-dark app-wallet .tabs .tabs-content {\n background-color: rgba(43, 54, 68, 0.5); }\n.theme-gray app-wallet .tabs .tabs-content {\n background-color: rgba(37, 40, 43, 0.5); }\n.theme-white app-wallet .tabs .tabs-content {\n background-color: rgba(255, 255, 255, 0.5); }\n.theme-dark app-send .form-send .send-select {\n color: #e0e0e0; }\n.theme-gray app-send .form-send .send-select {\n color: #e0e0e0; }\n.theme-white app-send .form-send .send-select {\n color: #43454b; }\n.theme-dark app-send .form-send .send-select .icon {\n background-color: #4db1ff; }\n.theme-gray app-send .form-send .send-select .icon {\n background-color: #42a5f5; }\n.theme-white app-send .form-send .send-select .icon {\n background-color: #2c95f1; }\n.theme-dark app-send .form-send .additional-details {\n border: 0.2rem solid #2b3644; }\n.theme-gray app-send .form-send .additional-details {\n border: 0.2rem solid #2f3438; }\n.theme-white app-send .form-send .additional-details {\n border: 0.2rem solid #ebebeb; }\n.theme-dark app-receive .btn-copy-address {\n background-color: #4db1ff; }\n.theme-gray app-receive .btn-copy-address {\n background-color: #42a5f5; }\n.theme-white app-receive .btn-copy-address {\n background-color: #2c95f1; }\n.theme-dark app-history table tbody tr .status .confirmation {\n background-color: #343f4a; }\n.theme-gray app-history table tbody tr .status .confirmation {\n background-color: #363a3e; }\n.theme-white app-history table tbody tr .status .confirmation {\n background-color: #dcdcdc; }\n.theme-dark app-history table tbody tr .status .confirmation .fill {\n background-color: #5cda9d; }\n.theme-gray app-history table tbody tr .status .confirmation .fill {\n background-color: #47cf8d; }\n.theme-white app-history table tbody tr .status .confirmation .fill {\n background-color: #46c172; }\napp-history table tbody tr .status.send .icon {\n background-color: #ff5252; }\napp-history table tbody tr .status.received .icon {\n background-color: #00c853; }\n.theme-dark app-contracts .wrap-table .contract .icon.new, .theme-dark app-contracts .wrap-table .contract .icon.alert {\n background-color: #ff5252; }\n.theme-gray app-contracts .wrap-table .contract .icon.new, .theme-gray app-contracts .wrap-table .contract .icon.alert {\n background-color: #ff5252; }\n.theme-white app-contracts .wrap-table .contract .icon.new, .theme-white app-contracts .wrap-table .contract .icon.alert {\n background-color: #ff5252; }\n.theme-dark app-contracts .wrap-table .contract .icon.purchase, .theme-dark app-contracts .wrap-table .contract .icon.sell {\n background-color: #4db1ff; }\n.theme-gray app-contracts .wrap-table .contract .icon.purchase, .theme-gray app-contracts .wrap-table .contract .icon.sell {\n background-color: #42a5f5; }\n.theme-white app-contracts .wrap-table .contract .icon.purchase, .theme-white app-contracts .wrap-table .contract .icon.sell {\n background-color: #2c95f1; }\n.theme-dark app-purchase .form-purchase .purchase-select {\n color: #e0e0e0; }\n.theme-gray app-purchase .form-purchase .purchase-select {\n color: #e0e0e0; }\n.theme-white app-purchase .form-purchase .purchase-select {\n color: #43454b; }\n.theme-dark app-purchase .form-purchase .purchase-select .icon {\n background-color: #4db1ff; }\n.theme-gray app-purchase .form-purchase .purchase-select .icon {\n background-color: #42a5f5; }\n.theme-white app-purchase .form-purchase .purchase-select .icon {\n background-color: #2c95f1; }\n.theme-dark app-purchase .form-purchase .purchase-states {\n color: #4db1ff; }\n.theme-gray app-purchase .form-purchase .purchase-states {\n color: #42a5f5; }\n.theme-white app-purchase .form-purchase .purchase-states {\n color: #2c95f1; }\n.theme-dark app-purchase .form-purchase .additional-details {\n border: 0.2rem solid #2b3644; }\n.theme-gray app-purchase .form-purchase .additional-details {\n border: 0.2rem solid #2f3438; }\n.theme-white app-purchase .form-purchase .additional-details {\n border: 0.2rem solid #ebebeb; }\n.theme-dark app-purchase .progress-bar-container .progress-bar {\n background-color: #343f4a; }\n.theme-gray app-purchase .progress-bar-container .progress-bar {\n background-color: #363a3e; }\n.theme-white app-purchase .progress-bar-container .progress-bar {\n background-color: #dcdcdc; }\n.theme-dark app-purchase .progress-bar-container .progress-bar .progress-bar-full {\n background-color: #5cda9d; }\n.theme-gray app-purchase .progress-bar-container .progress-bar .progress-bar-full {\n background-color: #47cf8d; }\n.theme-white app-purchase .progress-bar-container .progress-bar .progress-bar-full {\n background-color: #46c172; }\napp-messages table tbody tr td:first-child span {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap; }\n.theme-dark app-messages table tbody tr td:first-child .icon {\n background-color: #ff5252; }\n.theme-gray app-messages table tbody tr td:first-child .icon {\n background-color: #ff5252; }\n.theme-white app-messages table tbody tr td:first-child .icon {\n background-color: #ff5252; }\n.theme-dark app-typing-message .head .interlocutor {\n color: #4db1ff; }\n.theme-gray app-typing-message .head .interlocutor {\n color: #42a5f5; }\n.theme-white app-typing-message .head .interlocutor {\n color: #2c95f1; }\n.theme-dark app-typing-message .messages-content .messages-list div.date {\n color: #556576; }\n.theme-gray app-typing-message .messages-content .messages-list div.date {\n color: #565c62; }\n.theme-white app-typing-message .messages-content .messages-list div.date {\n color: #a0a5ab; }\n.theme-dark app-typing-message .messages-content .messages-list div.my {\n background-color: #2a3544; }\n.theme-gray app-typing-message .messages-content .messages-list div.my {\n background-color: #30363c; }\n.theme-white app-typing-message .messages-content .messages-list div.my {\n background-color: #fff; }\napp-typing-message .messages-content .messages-list div.my:before {\n content: \"\";\n display: block;\n position: absolute;\n top: 0;\n left: -1.1rem;\n border: 1.2rem solid transparent; }\n.theme-dark app-typing-message .messages-content .messages-list div.my:before {\n border-top-color: #2a3544; }\n.theme-gray app-typing-message .messages-content .messages-list div.my:before {\n border-top-color: #30363c; }\n.theme-white app-typing-message .messages-content .messages-list div.my:before {\n border-top-color: #fff; }\n.theme-dark app-typing-message .messages-content .messages-list div.buddy {\n background-color: #18202a; }\n.theme-gray app-typing-message .messages-content .messages-list div.buddy {\n background-color: #25292d; }\n.theme-white app-typing-message .messages-content .messages-list div.buddy {\n background-color: #ededed; }\napp-typing-message .messages-content .messages-list div.buddy:after {\n content: \"\";\n display: block;\n position: absolute;\n right: -1.1rem;\n top: 0;\n border: 1.2rem solid transparent; }\n.theme-dark app-typing-message .messages-content .messages-list div.buddy:after {\n border-top-color: #18202a; }\n.theme-gray app-typing-message .messages-content .messages-list div.buddy:after {\n border-top-color: #25292d; }\n.theme-white app-typing-message .messages-content .messages-list div.buddy:after {\n border-top-color: #ededed; }\n.theme-dark app-staking .chart-header .general .label {\n color: #556576; }\n.theme-gray app-staking .chart-header .general .label {\n color: #565c62; }\n.theme-white app-staking .chart-header .general .label {\n color: #a0a5ab; }\n.theme-dark app-staking .chart-header .general .options {\n color: #e0e0e0; }\n.theme-gray app-staking .chart-header .general .options {\n color: #e0e0e0; }\n.theme-white app-staking .chart-header .general .options {\n color: #43454b; }\napp-staking .chart-header .selected {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n flex-grow: 1;\n font-size: 1.6rem; }\n.theme-dark app-staking .chart-options .title {\n color: #556576; }\n.theme-gray app-staking .chart-options .title {\n color: #565c62; }\n.theme-white app-staking .chart-options .title {\n color: #a0a5ab; }\n.theme-dark app-staking .chart-options .options button {\n color: #e0e0e0;\n background-color: #2b3644; }\n.theme-gray app-staking .chart-options .options button {\n color: #e0e0e0;\n background-color: #292d31; }\n.theme-white app-staking .chart-options .options button {\n color: #43454b;\n background-color: #e0e0e0; }\n.theme-dark app-staking .chart-options .options button.active {\n background-color: #556576; }\n.theme-gray app-staking .chart-options .options button.active {\n background-color: #515960; }\n.theme-white app-staking .chart-options .options button.active {\n background-color: #ffffff; }\n.head {\n display: flex;\n align-items: flex-end;\n justify-content: space-between;\n font-size: 1.3rem;\n padding: 0 3rem;\n width: 100%;\n height: 3rem; }\n.theme-dark .head {\n color: #4db1ff; }\n.theme-gray .head {\n color: #42a5f5; }\n.theme-white .head {\n color: #2c95f1; }\n.head .breadcrumbs > span:not(:last-child), .head .breadcrumbs a:not(:last-child) {\n position: relative;\n margin-right: 20px; }\n.head .breadcrumbs > span:not(:last-child):after, .head .breadcrumbs a:not(:last-child):after {\n content: \"\";\n display: block;\n position: absolute;\n top: 0.5rem;\n right: -1.5rem;\n width: 0.9rem;\n height: 0.9rem;\n -webkit-mask: url('arrow-right.svg') no-repeat center;\n mask: url('arrow-right.svg') no-repeat center;\n -webkit-mask-size: cover;\n mask-size: cover; }\n.theme-dark .head .breadcrumbs > span:not(:last-child):after, .theme-dark .head .breadcrumbs a:not(:last-child):after {\n background-color: #4db1ff; }\n.theme-gray .head .breadcrumbs > span:not(:last-child):after, .theme-gray .head .breadcrumbs a:not(:last-child):after {\n background-color: #42a5f5; }\n.theme-white .head .breadcrumbs > span:not(:last-child):after, .theme-white .head .breadcrumbs a:not(:last-child):after {\n background-color: #2c95f1; }\n.head .back-btn {\n display: flex;\n align-items: center;\n background-color: transparent;\n color: #4db1ff;\n font-size: inherit;\n font-weight: 400;\n line-height: 1.3rem;\n padding: 0;\n height: auto; }\n.head .back-btn .icon {\n margin-right: 0.7rem;\n -webkit-mask: url('back.svg') no-repeat center;\n mask: url('back.svg') no-repeat center;\n width: 0.9rem;\n height: 0.9rem; }\n.theme-dark .head .back-btn .icon {\n background-color: #4db1ff; }\n.theme-gray .head .back-btn .icon {\n background-color: #42a5f5; }\n.theme-white .head .back-btn .icon {\n background-color: #2c95f1; }\n.scrolled-content::-webkit-scrollbar {\n background-color: transparent;\n cursor: default;\n width: 1rem;\n height: 1rem; }\n.scrolled-content::-webkit-scrollbar-track {\n background: transparent; }\n.scrolled-content::-webkit-scrollbar-thumb {\n background-color: #556576;\n background-clip: padding-box;\n border: 0.25rem solid transparent;\n border-radius: 0.5rem; }\n.scrolled-content::-webkit-scrollbar-thumb:hover {\n background-color: #556576; }\ntable {\n font-size: 1.3rem;\n width: 100%; }\ntable thead {\n text-align: left; }\n.theme-dark table thead {\n color: #556576; }\n.theme-gray table thead {\n color: #565c62; }\n.theme-white table thead {\n color: #a0a5ab; }\ntable thead tr {\n height: 4rem; }\ntable thead tr th {\n padding: 1rem;\n vertical-align: bottom; }\ntable thead tr th:first-child {\n padding-left: 3rem; }\ntable thead tr th:last-child {\n padding-right: 3rem; }\ntable tbody {\n text-align: left; }\n.theme-dark table tbody {\n color: #e0e0e0; }\n.theme-gray table tbody {\n color: #e0e0e0; }\n.theme-white table tbody {\n color: #43454b; }\ntable tbody tr {\n height: 3.5rem; }\n.theme-dark table tbody tr:nth-child(odd) {\n background-color: #18202a; }\n.theme-gray table tbody tr:nth-child(odd) {\n background-color: #25292d; }\n.theme-white table tbody tr:nth-child(odd) {\n background-color: #ffffff; }\ntable tbody tr td {\n line-height: 1.7rem;\n padding: 0 1rem;\n vertical-align: middle;\n white-space: nowrap; }\ntable tbody tr td:first-child {\n padding-left: 3rem; }\ntable tbody tr td:last-child {\n padding-right: 3rem; }\nhtml {\n font-family: 'Open Sans', sans-serif;\n font-size: 10px; }\nbody {\n font-family: 'Open Sans', sans-serif;\n font-size: 1.6rem;\n width: 100vw;\n height: 100vh; }\nbody.theme-dark {\n background: #131921 url('background-dark.png') no-repeat center;\n background-size: cover; }\nbody.theme-gray {\n background: #101417 url('background-gray.png') no-repeat center;\n background-size: cover; }\nbody.theme-white {\n background: #eeeeee url('background-white.png') no-repeat center;\n background-size: cover; }\nbody app-root {\n display: flex;\n width: 100%;\n height: 100%; }\n.ngx-contextmenu .dropdown-menu {\n border: solid 1px chartreuse;\n background-color: darkgreen;\n padding: 0; }\n.ngx-contextmenu li {\n display: block;\n border-top: solid 1px chartreuse;\n text-transform: uppercase;\n text-align: center; }\n.ngx-contextmenu li:first-child {\n border-top: none; }\n.ngx-contextmenu a {\n color: chartreuse;\n display: block;\n padding: 0.5em 1em; }\n.ngx-contextmenu a:hover {\n color: darkgreen;\n background-color: chartreuse; }\n\r\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9EOlxcemFuby9zcmNcXGFzc2V0c1xcc2Nzc1xcYmFzZVxcX21peGlucy5zY3NzIiwic3JjL0Q6XFx6YW5vL3NyY1xcYXNzZXRzXFxzY3NzXFxiYXNlXFxfbnVsbC5zY3NzIiwic3JjL0Q6XFx6YW5vL3NyY1xcYXNzZXRzXFxzY3NzXFxiYXNlXFxfYmFzZS5zY3NzIiwic3JjL0Q6XFx6YW5vL3NyY1xcYXNzZXRzXFxzY3NzXFxiYXNlXFxfdGhlbWUuc2NzcyIsInNyYy9EOlxcemFuby9zcmNcXGFzc2V0c1xcc2Nzc1xcbGF5b3V0XFxfbWFpbi5zY3NzIiwic3JjL0Q6XFx6YW5vL3NyY1xcYXNzZXRzXFxzY3NzXFxsYXlvdXRcXF9zaWRlYmFyLnNjc3MiLCJzcmMvRDpcXHphbm8vc3JjXFxhc3NldHNcXHNjc3NcXGxheW91dFxcX3dhbGxldC5zY3NzIiwic3JjL0Q6XFx6YW5vL3NyY1xcYXNzZXRzXFxzY3NzXFxtb2R1bGVzXFxfaGVhZC5zY3NzIiwic3JjL0Q6XFx6YW5vL3NyY1xcYXNzZXRzXFxzY3NzXFxtb2R1bGVzXFxfc2Nyb2xsLnNjc3MiLCJzcmMvRDpcXHphbm8vc3JjXFxhc3NldHNcXHNjc3NcXG1vZHVsZXNcXF90YWJsZS5zY3NzIiwic3JjL0Q6XFx6YW5vL3NyY1xcc3R5bGVzLnNjc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBOEVBOztFQUVFO0FDN0VGO0VBQ0UsdUJBQXNCO0VBQ3RCLCtCQUE4QjtFQUM5Qiw0QkFBMkIsRUFDNUI7QUFDRDtFQUNFLG9CQUFtQjtFQUNuQiw0QkFBMkI7RUFDM0IseUJBQXdCO0VBQ3hCLFVBQVM7RUFDVCxXQUFVO0VEOEJYLDRCQUEyQjtFQUMxQiwwQkFBeUI7RUFFekIsdUJBQXNCO0VBQ3RCLHNCQUFxQjtFQUNyQixrQkFBaUIsRUNqQ2xCO0FBRUQ7Ozs7Ozs7Ozs7Ozs7RUFhSSxVQUFTO0VBQ1QsZ0JBQWU7RUFDZixjQUFhO0VBQ2IseUJBQXdCLEVBQzNCO0FBQ0Q7O0VBRUksZUFBYyxFQUNqQjtBQUVEO0VBQ0csZUFBYztFQUNkLG1CQUFrQixFQUNwQjtBQUNEO0VBQ0ksaUJBQWdCLEVBQ25CO0FBQ0Q7RUFDSSxhQUFZLEVBQ2Y7QUFDRDs7RUFFSSxjQUFhLEVBQ2hCO0FBR0Q7RUFDSSwwQkFBeUI7RUFDekIsa0JBQWlCLEVBQ3BCO0FBQ0Q7O0VBRUUsV0FBVSxFQUNYO0FBR0Q7RUFDSSxjQUFhLEVBSWhCO0FBTEQ7SUFHTSw2Q0FBNEMsRUFDN0M7QUFHTDs7OztFQUlFLDJCQUEwQjtFQUMxQixnQkFBZTtFQUNmLGNBQWEsRUFDZDtBQUNEOztFQUVFLGdCQUFlLEVBQ2hCO0FBQ0Q7O0VBRUUsVUFBUztFQUNULFdBQVUsRUFDWDtBQUNEO0VBQ0Usb0JBQW1CLEVBQ3BCO0FBQ0Q7RUFDRSw4QkFBNkI7RUFDN0Isd0JBQXVCLEVBQ3hCO0FBQ0Q7O0VBRUUseUJBQXdCLEVBQ3pCO0FBSUQ7RUFDQyxzQkFBcUIsRUFNckI7QUFQRDtJQUtFLFdBQVUsRUFDVjtBQUdGO0VBQUksbUJBQWtCLEVBQUk7QUFDMUI7RUFBWSxpQkFBZ0IsRUFBTTtBQUdsQztFQUNDLFlBQVc7RUFDWCxnQkFBZTtFQUNmLGFBQVk7RUFDWCxvQkFBbUI7RUFDcEIsVUFBUyxFQUNUO0FBRUQ7RUFDRSx5QkFBd0IsRUFDekI7QUMvSEQ7RUFDRSxhQUFZO0VBQ1oscUNBQW9DO0VBQ3BDLGtCQUFpQjtFQUNqQixpQkFBZ0I7RUFDaEIsY0FBYTtFQUNiLGdCQUFlO0VBQ2YsZUFBYyxFQXNGZjtBRlZHO0lFdkVFLDBCQ0dvQztJREZwQyxlQ0oyQixFSGtGNUI7QUFSRDtJRXZFRSwwQkM0Q29DO0lEM0NwQyxlQ3FDMkIsRUh5QzVCO0FBUkQ7SUV2RUUsMEJDcUZvQztJRHBGcEMsZUM4RTJCLEVIQTVCO0FBUkQ7SUVoRUksMEJDSDZCLEVIMkVoQztBQVJEO0lFaEVJLDBCQ3NDNkIsRUhrQ2hDO0FBUkQ7SUVoRUksMEJDK0U2QixFSFBoQztBQVJEO0lFeERFLDBCQ2RnQztJRGVoQyxlQ25CMkIsRUhrRjVCO0FBUkQ7SUV4REUsMEJDMkJnQztJRDFCaEMsZUNzQjJCLEVIeUM1QjtBQVJEO0lFeERFLDBCQ29FZ0M7SURuRWhDLGVDK0QyQixFSEE1QjtBQVJEO0lFakRJLDBCQ3BCeUIsRUg2RTVCO0FBUkQ7SUVqREksMEJDcUJ5QixFSG9DNUI7QUFSRDtJRWpESSwwQkM4RHlCLEVITDVCO0FBUkQ7SUV6Q0UsMEJDekJpQztJRDBCakMsZUNsQzJCLEVIa0Y1QjtBQVJEO0lFekNFLDBCQ2dCaUM7SURmakMsZUNPMkIsRUh5QzVCO0FBUkQ7SUV6Q0UsMEJDeURpQztJRHhEakMsZUNnRDJCLEVIQTVCO0FBUkQ7SUVsQ0ksMEJDL0IwQixFSHlFN0I7QUFSRDtJRWxDSSwwQkNVMEIsRUhnQzdCO0FBUkQ7SUVsQ0ksMEJDbUQwQixFSFQ3QjtBQVJEO0lFMUJFLDBCQ3RDcUM7SUR1Q3JDLGVDakQyQixFSGtGNUI7QUFSRDtJRTFCRSwwQkNHcUM7SURGckMsZUNSMkIsRUh5QzVCO0FBUkQ7SUUxQkUsMEJDNENxQztJRDNDckMsZUNpQzJCLEVIQTVCO0FBUkQ7SUVuQkksMEJDNUM4QixFSHVFakM7QUFSRDtJRW5CSSwwQkNIOEIsRUg4QmpDO0FBUkQ7SUVuQkksMEJDc0M4QixFSFhqQztBRTNGTDtJQXNFSSxjQUFhO0lBQ2Isb0JBQW1CO0lBQ25CLHdCQUF1QixFQW1CeEI7QUZSQztNRVJFLDhCQUE2QjtNQUM3Qiw2QkN2RG1DO01Ed0RuQyxlQ3JFb0IsRUhtRnJCO0FBUkQ7TUVSRSw4QkFBNkI7TUFDN0IsNkJDZG1DO01EZW5DLGVDNUJvQixFSDBDckI7QUFSRDtNRVJFLDhCQUE2QjtNQUM3Qiw2QkMyQm1DO01EMUJuQyxlQ2FvQixFSENyQjtBRTNGTDtNQXNGTSxtQkFBa0I7TUFDbEIsOERBQXFFO2NBQXJFLHNEQUFxRTtNQUNyRSxjQUFhO01BQ2IsZUFBYyxFQUNmO0FGUEQ7UUVBSSwwQkMzRWtCLEVIbUZyQjtBQVJEO1FFQUksMEJDbENrQixFSDBDckI7QUFSRDtRRUFJLDBCQ09rQixFSENyQjtBRUlMO0VBQ0UsY0FBYTtFQUNiLHVCQUFzQjtFQUN0Qix3QkFBdUI7RUFDdkIsc0JBQXFCO0VBQ3JCLGVBQWMsRUF1RGY7QUE1REQ7SUFRSSxjQUFhO0lBQ2Isb0JBQW1CO0lBQ25CLDRCQUEyQjtJQUMzQixtQkFBa0IsRUFDbkI7QUFaSDtJQWVJLGtCQUFpQjtJQUNqQixvQkFBbUIsRUFLcEI7QUZqQ0M7TUUrQkUsZUN4R3dCLEVIaUZ6QjtBQVJEO01FK0JFLGVDL0R3QixFSHdDekI7QUFSRDtNRStCRSxlQ3RCd0IsRUhEekI7QUVJTDtJQXdCSSxhQUFZO0lBQ1osa0JBQWlCO0lBQ2pCLGNBQWE7SUFDYixnQkFBZTtJQUNmLFlBQVc7SUFDWCxhQUFZLEVBTWI7QUYvQ0M7TUU0Q0UsMEJDekcyQjtNRDBHM0IsZUN4SG9CLEVIbUZyQjtBQVJEO01FNENFLDBCQ2hFMkI7TURpRTNCLGVDL0VvQixFSDBDckI7QUFSRDtNRTRDRSwwQkN2QjJCO01Ed0IzQixlQ3RDb0IsRUhDckI7QUVJTDtJQXNDSSxhQUFZLEVBcUJiO0FBM0RIO01BeUNNLHFDQUFvQztNQUNwQyxhQUFZO01BQ1osa0JBQWlCO01BQ2pCLGNBQWE7TUFDYixjQUFhO01BQ2IsWUFBVztNQUNYLGdCQUFlO01BQ2YsYUFBWTtNQUNaLGlCQUFnQjtNQUNoQixpQkFBZ0I7TUFDaEIsaUJBQWdCO01BQ2hCLGFBQVksRUFNYjtBRnRFRDtRRW1FSSwwQkNoSXlCO1FEaUl6QixlQy9Ja0IsRUhtRnJCO0FBUkQ7UUVtRUksMEJDdkZ5QjtRRHdGekIsZUN0R2tCLEVIMENyQjtBQVJEO1FFbUVJLDBCQzlDeUI7UUQrQ3pCLGVDN0RrQixFSENyQjtBRWtFTDtFQUdJLGNBQWE7RUFDYixvQkFBbUI7RUFDbkIsZ0JBQWU7RUFDZixpQkFBZ0I7RUFDaEIscUJBQW9CO0VGekh2Qiw0QkFBMkI7RUFDMUIsMEJBQXlCO0VBRXpCLHVCQUFzQjtFQUN0QixzQkFBcUI7RUFDckIsa0JBQWlCLEVFMkhoQjtBRnhGQztJRW9GRSxlQzdKd0IsRUhpRnpCO0FBUkQ7SUVvRkUsZUNwSHdCLEVId0N6QjtBQVJEO0lFb0ZFLGVDM0V3QixFSER6QjtBRWtFTDtFQWlCSSxtQkFBa0I7RUFDbEIsV0FBVSxFQW1DWDtBQXJESDtJQXFCTSxtQkFBa0IsRUFDbkI7QUF0Qkw7SUF5Qk0sWUFBVztJQUNYLG1CQUFrQjtJQUNsQixZQUFXO0lBQ1gsUUFBTztJQUNQLHdCQUF1QjtJQUN2QixtQkFBa0I7SUFDbEIsY0FBYTtJQUNiLGVBQWMsRUFLZjtBRi9HRDtNRTZHSSw2QkNyTGtCLEVIZ0ZyQjtBQVJEO01FNkdJLDZCQzVJa0IsRUh1Q3JCO0FBUkQ7TUU2R0ksNkJDbkdrQixFSEZyQjtBRWtFTDtJQXdDTSxZQUFXO0lBQ1gsbUJBQWtCO0lBQ2xCLFVBQVM7SUFDVCxhQUFZO0lBQ1osbUJBQWtCO0lBQ2xCLFdBQVU7SUFDVixjQUFhO0lBQ2IsZUFBYyxFQUtmO0FGOUhEO01FNEhJLDBCQ3BNa0IsRUhnRnJCO0FBUkQ7TUU0SEksMEJDM0prQixFSHVDckI7QUFSRDtNRTRISSwwQkNsSGtCLEVIRnJCO0FFa0VMO0VBMERNLFdBQVUsRUFDWDtBQUlMO0VBR0ksY0FBYTtFQUNiLG9CQUFtQjtFQUNuQixnQkFBZTtFQUNmLGlCQUFnQjtFQUNoQixxQkFBb0I7RUZ4THZCLDRCQUEyQjtFQUMxQiwwQkFBeUI7RUFFekIsdUJBQXNCO0VBQ3RCLHNCQUFxQjtFQUNyQixrQkFBaUIsRUUwTGhCO0FGdkpDO0lFbUpFLGVDNU53QixFSGlGekI7QUFSRDtJRW1KRSxlQ25Md0IsRUh3Q3pCO0FBUkQ7SUVtSkUsZUMxSXdCLEVIRHpCO0FFaUlMO0VBaUJJLG1CQUFrQjtFQUNsQixTQUFRO0VBQ1IsYUFBWTtFQUNaLG9DQUEyQjtVQUEzQiw0QkFBMkI7RUFDM0IsbUJBQWtCLEVBb0JuQjtBQXpDSDtJQXdCTSxtQkFBa0IsRUFDbkI7QUF6Qkw7SUE0Qk0sWUFBVztJQUNYLG1CQUFrQjtJQUNsQixTQUFRO0lBQ1IsYUFBWTtJQUNaLG9DQUEyQjtZQUEzQiw0QkFBMkI7SUFDM0Isd0JBQXVCO0lBQ3ZCLGNBQWE7SUFDYixlQUFjLEVBS2Y7QUZqTEQ7TUUrS0ksNkJDdlBrQixFSGdGckI7QUFSRDtNRStLSSw2QkM5TWtCLEVIdUNyQjtBQVJEO01FK0tJLDZCQ3JLa0IsRUhGckI7QUVpSUw7RUE4Q00sMkNBQTBELEVBSzNEO0FGNUxEO0lFMExJLDBCQ2xRa0IsRUhnRnJCO0FBUkQ7SUUwTEksMEJDek5rQixFSHVDckI7QUFSRDtJRTBMSSwwQkNoTGtCLEVIRnJCO0FFd0xMO0VBQ0Usa0JBQWlCO0VBQ2pCLGtCQUFpQixFQUtsQjtBRnZNRztJRXFNQSxlQzVRcUIsRUgrRXBCO0FBUkQ7SUVxTUEsZUNuT3FCLEVIc0NwQjtBQVJEO0lFcU1BLGVDMUxxQixFSEhwQjtBRWlNTDtFQUNFLGtCQUFpQjtFQUNqQixtQkFBa0IsRUEyRW5CO0FGdFJHO0lFOE1BLG9CQzFQK0I7SUQyUC9CLHdDQzFQMEM7SUQyUDFDLGVDM1JzQixFSG1GckI7QUFSRDtJRThNQSxvQkNqTitCO0lEa04vQix3Q0NqTjBDO0lEa04xQyxlQ2xQc0IsRUgwQ3JCO0FBUkQ7SUU4TUEsb0JDeEsrQjtJRHlLL0IsOENDeEtnRDtJRHlLaEQsZUN6TXNCLEVIQ3JCO0FFaU1MO0lBV0ksa0JBQWlCLEVBY2xCO0FBekJIO01BY00sWUFBVztNQUNYLG1CQUFrQjtNQUNsQixjQUFhO01BQ2IsYUFBWTtNQUNaLDRCQUEyQjtNQUMzQixvQkFBbUIsRUFLcEI7QUZqT0Q7UUUrTkksMERBQWdGLEVGdk5uRjtBQVJEO1FFK05JLDBEQUFnRixFRnZObkY7QUFSRDtRRStOSSwwREFBZ0YsRUZ2Tm5GO0FFaU1MO0lBNEJJLGlCQUFnQixFQWNqQjtBQTFDSDtNQStCTSxZQUFXO01BQ1gsbUJBQWtCO01BQ2xCLFdBQVU7TUFDVixhQUFZO01BQ1osNEJBQTJCO01BQzNCLG9CQUFtQixFQUtwQjtBRmxQRDtRRWdQSSwwREM1UjJCLEVIb0Q5QjtBQVJEO1FFZ1BJLDBEQ25QMkIsRUhXOUI7QUFSRDtRRWdQSSwwREMxTTJCLEVIOUI5QjtBRWlNTDtJQTZDSSxtQkFBa0IsRUFjbkI7QUEzREg7TUFnRE0sWUFBVztNQUNYLG1CQUFrQjtNQUNsQixPQUFNO01BQ04sYUFBWTtNQUNaLDRCQUEyQjtNQUMzQixvQkFBbUIsRUFLcEI7QUZuUUQ7UUVpUUksMERBQWdGLEVGelBuRjtBQVJEO1FFaVFJLDBEQUFnRixFRnpQbkY7QUFSRDtRRWlRSSwwREFBZ0YsRUZ6UG5GO0FFaU1MO0lBOERJLGtCQUFpQixFQWNsQjtBQTVFSDtNQWlFTSxZQUFXO01BQ1gsbUJBQWtCO01BQ2xCLE9BQU07TUFDTixZQUFXO01BQ1gsNEJBQTJCO01BQzNCLG9CQUFtQixFQUtwQjtBRnBSRDtRRWtSSSwwREFBZ0YsRUYxUW5GO0FBUkQ7UUVrUkksMERBQWdGLEVGMVFuRjtBQVJEO1FFa1JJLDBEQUFnRixFRjFRbkY7QUFSRDtFRTJSQSxvQkN2VStCO0VEd1UvQixlQ3ZXc0IsRUhtRnJCO0FBUkQ7RUUyUkEsb0JDOVIrQjtFRCtSL0IsZUM5VHNCLEVIMENyQjtBQVJEO0VFMlJBLG9CQ3JQK0I7RURzUC9CLGVDclJzQixFSENyQjtBQVJEO0VFc1NFLDBCQzlXb0I7RUQrV3BCLGVDalgyQixFSGtGNUI7QUFSRDtFRXNTRSwwQkNyVW9CO0VEc1VwQixlQ3hVMkIsRUh5QzVCO0FBUkQ7RUVzU0UsMEJDNVJvQjtFRDZScEIsZUMvUjJCLEVIQTVCO0FJM0ZMO0VBQ0UsZUFBYztFQUNkLGNBQWE7RUFDYixpQkFBZ0IsRUFrQmpCO0FBckJEO0lBTUksbUJBQWtCO0lBQ2xCLGNBQWE7SUFDYixpQkFBZ0IsRUFZakI7QUorREM7TUl4RUUsd0NESjJDO01DSzNDLGVESm9CLEVIbUZyQjtBQVJEO01JeEVFLHdDRHFDMkM7TUNwQzNDLGVEcUNvQixFSDBDckI7QUFSRDtNSXhFRSwyQ0Q4RThDO01DN0U5QyxlRDhFb0IsRUhDckI7QUkzRkw7TUFnQk0sbUJBQWtCO01BQ2xCLE9BQU07TUFDTixRQUFPLEVBQ1I7QUpnRUQ7RUluRE0sZURyQmdCLEVIZ0ZyQjtBQVJEO0VJbkRNLGVEb0JnQixFSHVDckI7QUFSRDtFSW5ETSxlRDZEZ0IsRUhGckI7QUFSRDtFSTdDUSwwQkQzQmMsRUhnRnJCO0FBUkQ7RUk3Q1EsMEJEY2MsRUh1Q3JCO0FBUkQ7RUk3Q1EsMEJEdURjLEVIRnJCO0FBUkQ7RUloQ0UsMEJEN0IyQjtFQzhCM0IsZUQ1Q29CLEVIbUZyQjtBQVJEO0VJaENFLDBCRFkyQjtFQ1gzQixlREhvQixFSDBDckI7QUFSRDtFSWhDRSwwQkRxRDJCO0VDcEQzQixlRHNDb0IsRUhDckI7QUFSRDtFSXJCRSwwQkR4QzJCLEVIcUU1QjtBQVJEO0VJckJFLDBCREMyQixFSDRCNUI7QUFSRDtFSXJCRSwwQkQwQzJCLEVIYjVCO0FBUkQ7RUlUSSxlRGhFc0IsRUhpRnpCO0FBUkQ7RUlUSSxlRHZCc0IsRUh3Q3pCO0FBUkQ7RUlUSSxlRGtCc0IsRUhEekI7QUlYTDtFQUNFLG1CQUFrQixFQUNuQjtBSkNHO0VJSUEsMEJEaEU4QixFSG9FN0I7QUFSRDtFSUlBLDBCRHZCOEIsRUgyQjdCO0FBUkQ7RUlJQSwwQkRrQjhCLEVIZDdCO0FBUkQ7RUlZSSwwQkRwRmtCLEVIZ0ZyQjtBQVJEO0VJWUksMEJEM0NrQixFSHVDckI7QUFSRDtFSVlJLDBCREZrQixFSEZyQjtBQVJEO0VJbUJJLDBCRDVGc0IsRUhpRnpCO0FBUkQ7RUltQkksMEJEbkRzQixFSHdDekI7QUFSRDtFSW1CSSwwQkRWc0IsRUhEekI7QUFSRDtFS2hGQSx3Q0ZBNkMsRUh3RjVDO0FBUkQ7RUtoRkEsd0NGeUM2QyxFSCtDNUM7QUFSRDtFS2hGQSwyQ0ZrRmdELEVITS9DO0FBUkQ7RUt0RU0sZUZMZ0IsRUhtRnJCO0FBUkQ7RUt0RU0sZUZvQ2dCLEVIMENyQjtBQVJEO0VLdEVNLGVGNkVnQixFSENyQjtBQVJEO0VLL0RNLGVGVGdCLEVIZ0ZyQjtBQVJEO0VLL0RNLGVGZ0NnQixFSHVDckI7QUFSRDtFSy9ETSxlRnlFZ0IsRUhGckI7QUFSRDtFS3JETSw4QkFBNkI7RUFDN0IsZUZ2QmdCLEVIbUZyQjtBQVJEO0VLckRNLDhCQUE2QjtFQUM3QixlRmtCZ0IsRUgwQ3JCO0FBUkQ7RUtyRE0sOEJBQTZCO0VBQzdCLGVGMkRnQixFSENyQjtBQVJEO0VLNUNVLGVGN0JnQixFSGlGekI7QUFSRDtFSzVDVSxlRllnQixFSHdDekI7QUFSRDtFSzVDVSxlRnFEZ0IsRUhEekI7QUFSRDtFS3JDVSwwQkZqQ3dCO0VFa0N4QixlRnRDbUIsRUhrRjVCO0FBUkQ7RUtyQ1UsMEJGUXdCO0VFUHhCLGVGR21CLEVIeUM1QjtBQVJEO0VLckNVLDBCRmlEd0I7RUVoRHhCLGVGNENtQixFSEE1QjtBQVJEO0VLM0JZLDBCRnJCdUIsRUh3RGxDO0FBUkQ7RUszQlksMEJGb0J1QixFSGVsQztBQVJEO0VLM0JZLDBCRjZEdUIsRUgxQmxDO0FBUkQ7RUtyQmMsMEJGMUJ5QixFSHVEdEM7QUFSRDtFS3JCYywwQkZleUIsRUhjdEM7QUFSRDtFS3JCYywwQkZ3RHlCLEVIM0J0QztBQVJEO0VLWlUsZUY3RGdCLEVIaUZ6QjtBQVJEO0VLWlUsZUZwQmdCLEVId0N6QjtBQVJEO0VLWlUsZUZxQmdCLEVIRHpCO0FBUkQ7RUtKUSx3Q0Z2RHFDO0VFd0RyQyxlRnREcUIsRUhpRTVCO0FBUkQ7RUtKUSx3Q0ZkcUM7RUVlckMsZUZicUIsRUh3QjVCO0FBUkQ7RUtKUSwwQkYyQnFDO0VFMUJyQyxlRjRCcUIsRUhqQjVCO0FBUkQ7RUtLWSxlRjdEcUIsRUhnRWhDO0FBUkQ7RUtLWSxlRnBCcUIsRUh1QmhDO0FBUkQ7RUtLWSxlRnFCcUIsRUhsQmhDO0FBUkQ7RUtZWSwwQkZqRTRCO0VFa0U1QixlRnBFc0IsRUgrRGpDO0FBUkQ7RUtZWSwwQkZ4QjRCO0VFeUI1QixlRjNCc0IsRUhzQmpDO0FBUkQ7RUtZWSwwQkZpQjRCO0VFaEI1QixlRmNzQixFSG5CakM7QUFSRDtFS29CWSwwQkYxRXlCO0VFMkV6QixlRmhHVSxFSG1GckI7QUFSRDtFS29CWSwwQkZqQ3lCO0VFa0N6QixlRnZEVSxFSDBDckI7QUFSRDtFS29CWSwwQkZReUI7RUVQekIsZUZkVSxFSENyQjtBQVJEO0VLNEJZLGVGcEZxQixFSGdFaEM7QUFSRDtFSzRCWSxlRjNDcUIsRUh1QmhDO0FBUkQ7RUs0QlksZUZGcUIsRUhsQmhDO0FBUkQ7RUtxQ1Esd0NGL0YwQyxFSGtFakQ7QUFSRDtFS3FDUSx3Q0Z0RDBDLEVIeUJqRDtBQVJEO0VLcUNRLDJDRmI2QyxFSGhCcEQ7QUFSRDtFSytDRSxvQ0Y5SHlCLEVIdUYxQjtBQVJEO0VLK0NFLG9DRnJGeUIsRUg4QzFCO0FBUkQ7RUsrQ0Usb0NGNUN5QixFSEsxQjtBQVJEO0VLcURJLGVGaElrQixFSG1GckI7QUFSRDtFS3FESSxlRnZGa0IsRUgwQ3JCO0FBUkQ7RUtxREksZUY5Q2tCLEVIQ3JCO0FBUkQ7RUsyRE0sMEJGbklnQixFSGdGckI7QUFSRDtFSzJETSwwQkYxRmdCLEVIdUNyQjtBQVJEO0VLMkRNLDBCRmpEZ0IsRUhGckI7QUFSRDtFS29FRSxlRjdJd0IsRUhpRnpCO0FBUkQ7RUtvRUUsZUZwR3dCLEVId0N6QjtBQVJEO0VLb0VFLGVGM0R3QixFSER6QjtBQVJEO0VLNEVNLDBCRnpKZSxFSHFGcEI7QUFSRDtFSzRFTSwwQkZoSGUsRUg0Q3BCO0FBUkQ7RUs0RU0sMEJGdkVlLEVIR3BCO0FBUkQ7RUttRk0sMEJGaktjLEVIc0ZuQjtBQVJEO0VLbUZNLDBCRnhIYyxFSDZDbkI7QUFSRDtFS21GTSwwQkYvRWMsRUhJbkI7QUFSRDtFSytGUSwwQkYvSTJCLEVId0RsQztBQVJEO0VLK0ZRLDBCRnRHMkIsRUhlbEM7QUFSRDtFSytGUSwwQkY3RDJCLEVIMUJsQztBQVJEO0VLcUdVLDBCRnBKNkIsRUh1RHRDO0FBUkQ7RUtxR1UsMEJGM0c2QixFSGN0QztBQVJEO0VLcUdVLDBCRmxFNkIsRUgzQnRDO0FBUkQ7RUs4R00sMEJGN0ppQyxFSHVEdEM7QUFSRDtFSzhHTSwwQkZwSGlDLEVIY3RDO0FBUkQ7RUs4R00sMEJGM0VpQyxFSDNCdEM7QUFSRDtFTWhGQSxlSEtzQixFSG1GckI7QUFSRDtFTWhGQSxlSDhDc0IsRUgwQ3JCO0FBUkQ7RU1oRkEsZUh1RnNCLEVIQ3JCO0FBUkQ7RU14RUksZUhIa0IsRUhtRnJCO0FBUkQ7RU14RUksZUhzQ2tCLEVIMENyQjtBQVJEO0VNeEVJLGVIK0VrQixFSENyQjtBQVJEO0VNbEVNLDBCSE5nQixFSGdGckI7QUFSRDtFTWxFTSwwQkhtQ2dCLEVIdUNyQjtBQVJEO0VNbEVNLDBCSDRFZ0IsRUhGckI7QUFSRDtFTXpERSxlSGZvQixFSGdGckI7QUFSRDtFTXpERSxlSDBCb0IsRUh1Q3JCO0FBUkQ7RU16REUsZUhtRW9CLEVIRnJCO0FBUkQ7RU1uREksMEJIckJrQixFSGdGckI7QUFSRDtFTW5ESSwwQkhvQmtCLEVIdUNyQjtBQVJEO0VNbkRJLDBCSDZEa0IsRUhGckI7QUFSRDtFTXZDTSx3Q0hiMkMsRUg0RGhEO0FBUkQ7RU12Q00sd0NINEIyQyxFSG1CaEQ7QUFSRDtFTXZDTSwyQ0hxRThDLEVIdEJuRDtBQVJEO0VNakNRLDBCSHZDYyxFSGdGckI7QUFSRDtFTWpDUSwwQkhFYyxFSHVDckI7QUFSRDtFTWpDUSwwQkgyQ2MsRUhGckI7QUFSRDtFTTFCUSwwQkgzQmdDO0VHNEJoQyxlSDlCMEIsRUgrRGpDO0FBUkQ7RU0xQlEsMEJIY2dDO0VHYmhDLGVIVzBCLEVIc0JqQztBQVJEO0VNMUJRLDBCSHVEZ0M7RUd0RGhDLGVIb0QwQixFSG5CakM7QUFSRDtFTWxCUSx3Q0gxRHFDLEVIb0Y1QztBQVJEO0VNbEJRLHdDSGpCcUMsRUgyQzVDO0FBUkQ7RU1sQlEsMkNId0J3QyxFSEUvQztBQVJEO0VNVEksd0NIbkV5QyxFSG9GNUM7QUFSRDtFTVRJLHdDSDFCeUMsRUgyQzVDO0FBUkQ7RU1USSwyQ0hlNEMsRUhFL0M7QUFSRDtFTUlJLGVIL0VrQixFSG1GckI7QUFSRDtFTUlJLGVIdENrQixFSDBDckI7QUFSRDtFTUlJLGVIR2tCLEVIQ3JCO0FBUkQ7RU1VTSwwQkhsRmdCLEVIZ0ZyQjtBQVJEO0VNVU0sMEJIekNnQixFSHVDckI7QUFSRDtFTVVNLDBCSEFnQixFSEZyQjtBQVJEO0VNa0JJLDZCSGhGaUMsRUhzRXBDO0FBUkQ7RU1rQkksNkJIdkNpQyxFSDZCcEM7QUFSRDtFTWtCSSw2QkhFaUMsRUhacEM7QUFSRDtFTTZCRSwwQkhyR29CLEVIZ0ZyQjtBQVJEO0VNNkJFLDBCSDVEb0IsRUh1Q3JCO0FBUkQ7RU02QkUsMEJIbkJvQixFSEZyQjtBQVJEO0VNK0NVLDBCSC9GeUIsRUh3RGxDO0FBUkQ7RU0rQ1UsMEJIdER5QixFSGVsQztBQVJEO0VNK0NVLDBCSGJ5QixFSDFCbEM7QUFSRDtFTXFEWSwwQkhwRzJCLEVIdUR0QztBQVJEO0VNcURZLDBCSDNEMkIsRUhjdEM7QUFSRDtFTXFEWSwwQkhsQjJCLEVIM0J0QztBTTBCTDtFQTRCWSwwQkFBeUIsRUFDMUI7QUE3Qlg7RUFtQ1ksMEJBQXlCLEVBQzFCO0FOdEVQO0VNd0ZRLDBCSC9KYSxFSCtFcEI7QUFSRDtFTXdGUSwwQkh0SGEsRUhzQ3BCO0FBUkQ7RU13RlEsMEJIN0VhLEVISHBCO0FBUkQ7RU0rRlEsMEJIdktjLEVIZ0ZyQjtBQVJEO0VNK0ZRLDBCSDlIYyxFSHVDckI7QUFSRDtFTStGUSwwQkhyRmMsRUhGckI7QUFSRDtFTThHSSxlSHpMa0IsRUhtRnJCO0FBUkQ7RU04R0ksZUhoSmtCLEVIMENyQjtBQVJEO0VNOEdJLGVIdkdrQixFSENyQjtBQVJEO0VNb0hNLDBCSDVMZ0IsRUhnRnJCO0FBUkQ7RU1vSE0sMEJIbkpnQixFSHVDckI7QUFSRDtFTW9ITSwwQkgxR2dCLEVIRnJCO0FBUkQ7RU00SEksZUhwTWtCLEVIZ0ZyQjtBQVJEO0VNNEhJLGVIM0prQixFSHVDckI7QUFSRDtFTTRISSxlSGxIa0IsRUhGckI7QUFSRDtFTW1JSSw2QkhqTWlDLEVIc0VwQztBQVJEO0VNbUlJLDZCSHhKaUMsRUg2QnBDO0FBUkQ7RU1tSUksNkJIL0dpQyxFSFpwQztBQVJEO0VNNklJLDBCSDdMK0IsRUh3RGxDO0FBUkQ7RU02SUksMEJIcEorQixFSGVsQztBQVJEO0VNNklJLDBCSDNHK0IsRUgxQmxDO0FBUkQ7RU1tSk0sMEJIbE1pQyxFSHVEdEM7QUFSRDtFTW1KTSwwQkh6SmlDLEVIY3RDO0FBUkQ7RU1tSk0sMEJIaEhpQyxFSDNCdEM7QU1rSkw7RU41T0UsaUJBQWdCO0VBQ2hCLHdCQUF1QjtFQUN2QixvQkFBbUIsRU1zUFY7QU50S1A7RU0yS1UsMEJIbFBXLEVIK0VwQjtBQVJEO0VNMktVLDBCSHpNVyxFSHNDcEI7QUFSRDtFTTJLVSwwQkhoS1csRUhIcEI7QUFSRDtFTTJMSSxlSG5Ra0IsRUhnRnJCO0FBUkQ7RU0yTEksZUgxTmtCLEVIdUNyQjtBQVJEO0VNMkxJLGVIakxrQixFSEZyQjtBQVJEO0VNeU1RLGVIbFJrQixFSGlGekI7QUFSRDtFTXlNUSxlSHpPa0IsRUh3Q3pCO0FBUkQ7RU15TVEsZUhoTWtCLEVIRHpCO0FBUkQ7RU1nTlEsMEJIbFF5QixFSDBEaEM7QUFSRDtFTWdOUSwwQkh6TnlCLEVIaUJoQztBQVJEO0VNZ05RLHVCSGhMc0IsRUh4QjdCO0FNNEtMO0VOOUxFLFlBRDBEO0VBRTFELGVBRjRCO0VBRzVCLG1CQUg0QztFTWlPbEMsT0FBTTtFQUNOLGNBQWE7RUFDYixpQ0FBZ0MsRUFLakM7QU43TlA7SU0yTlUsMEJIN1F1QixFSDBEaEM7QUFSRDtJTTJOVSwwQkhwT3VCLEVIaUJoQztBQVJEO0lNMk5VLHVCSDNMb0IsRUh4QjdCO0FBUkQ7RU1tT1EsMEJIcFI0QixFSHlEbkM7QUFSRDtFTW1PUSwwQkgzTzRCLEVIZ0JuQztBQVJEO0VNbU9RLDBCSGxNNEIsRUh6Qm5DO0FNNEtMO0VOOUxFLFlBRDBEO0VBRTFELGVBRjRCO0VBRzVCLG1CQUg0QztFTW9QbEMsZUFBYztFQUNkLE9BQU07RUFDTixpQ0FBZ0MsRUFLakM7QU5oUFA7SU04T1UsMEJIL1IwQixFSHlEbkM7QUFSRDtJTThPVSwwQkh0UDBCLEVIZ0JuQztBQVJEO0lNOE9VLDBCSDdNMEIsRUh6Qm5DO0FBUkQ7RU1nUU0sZUh6VW9CLEVIaUZ6QjtBQVJEO0VNZ1FNLGVIaFNvQixFSHdDekI7QUFSRDtFTWdRTSxlSHZQb0IsRUhEekI7QUFSRDtFTXVRTSxlSGxWZ0IsRUhtRnJCO0FBUkQ7RU11UU0sZUh6U2dCLEVIMENyQjtBQVJEO0VNdVFNLGVIaFFnQixFSENyQjtBTStPTDtFQXNCTSxjQUFhO0VBQ2Isb0JBQW1CO0VBQ25CLDBCQUF5QjtFQUN6QixhQUFZO0VBQ1osa0JBQWlCLEVBQ2xCO0FObFJEO0VNMFJJLGVIbldzQixFSGlGekI7QUFSRDtFTTBSSSxlSDFUc0IsRUh3Q3pCO0FBUkQ7RU0wUkksZUhqUnNCLEVIRHpCO0FBUkQ7RU1tU00sZUg5V2dCO0VHK1doQiwwQkhsVjhCLEVIc0RuQztBQVJEO0VNbVNNLGVIclVnQjtFR3NVaEIsMEJIelM4QixFSGFuQztBQVJEO0VNbVNNLGVINVJnQjtFRzZSaEIsMEJIaFE4QixFSDVCbkM7QUFSRDtFTTBTUSwwQkh2VnVCLEVIcUQ5QjtBQVJEO0VNMFNRLDBCSDlTdUIsRUhZOUI7QUFSRDtFTTBTUSwwQkhyUXVCLEVIN0I5QjtBTzNGTDtFQUNFLGNBQWE7RUFDYixzQkFBcUI7RUFDckIsK0JBQThCO0VBQzlCLGtCQUFpQjtFQUNqQixnQkFBZTtFQUNmLFlBQVc7RUFDWCxhQUFZLEVBc0RiO0FQc0JHO0lPekVBLGVKQ3NCLEVIZ0ZyQjtBQVJEO0lPekVBLGVKMENzQixFSHVDckI7QUFSRDtJT3pFQSxlSm1Gc0IsRUhGckI7QU8zRkw7SUFrQlEsbUJBQWtCO0lBQ2xCLG1CQUFrQixFQWdCbkI7QUFuQ1A7TVB5RUUsWUFEMEQ7TUFFMUQsZUFGNEI7TUFHNUIsbUJBSDRDO01PaERwQyxZQUFXO01BQ1gsZUFBYztNQUNkLGNBQWE7TUFDYixlQUFjO01BQ2Qsc0RBQTZEO2NBQTdELDhDQUE2RDtNQUM3RCx5QkFBZ0I7Y0FBaEIsaUJBQWdCLEVBS2pCO0FQaURMO1FPbkRRLDBCSnJCYyxFSGdGckI7QUFSRDtRT25EUSwwQkpvQmMsRUh1Q3JCO0FBUkQ7UU9uRFEsMEJKNkRjLEVIRnJCO0FPM0ZMO0lBd0NJLGNBQWE7SUFDYixvQkFBbUI7SUFDbkIsOEJBQTZCO0lBQzdCLGVBQWM7SUFDZCxtQkFBa0I7SUFDbEIsaUJBQWdCO0lBQ2hCLG9CQUFtQjtJQUNuQixXQUFVO0lBQ1YsYUFBWSxFQVliO0FBNURIO01BbURNLHFCQUFvQjtNQUNwQiwrQ0FBc0Q7Y0FBdEQsdUNBQXNEO01BQ3RELGNBQWE7TUFDYixlQUFjLEVBS2Y7QVB3QkQ7UU8xQkksMEJKOUNrQixFSGdGckI7QUFSRDtRTzFCSSwwQkpMa0IsRUh1Q3JCO0FBUkQ7UU8xQkksMEJKb0NrQixFSEZyQjtBUTNGTDtFQUdJLDhCQUE2QjtFQUM3QixnQkFBZTtFQUNmLFlBQVc7RUFDWCxhQUFZLEVBQ2I7QUFQSDtFQVVJLHdCQUF1QixFQUN4QjtBQVhIO0VBY0ksMEJBQXlCO0VBQ3pCLDZCQUE0QjtFQUM1QixrQ0FBaUM7RUFDakMsc0JBQXFCLEVBQ3RCO0FBbEJIO0VBcUJJLDBCQUF5QixFQUMxQjtBQ3RCSDtFQUNFLGtCQUFpQjtFQUNqQixZQUFXLEVBNERaO0FBOUREO0lBS0ksaUJBQWdCLEVBc0JqQjtBVHdEQztNUzNFRSxlTkV3QixFSGlGekI7QUFSRDtNUzNFRSxlTjJDd0IsRUh3Q3pCO0FBUkQ7TVMzRUUsZU5vRndCLEVIRHpCO0FTM0ZMO01BWU0sYUFBWSxFQWNiO0FBMUJMO1FBZVEsY0FBYTtRQUNiLHVCQUFzQixFQVN2QjtBQXpCUDtVQW1CVSxtQkFBa0IsRUFDbkI7QUFwQlQ7VUF1QlUsb0JBQW1CLEVBQ3BCO0FBeEJUO0lBOEJJLGlCQUFnQixFQStCakI7QVRzQkM7TVNsREUsZU56Qm9CLEVIbUZyQjtBQVJEO01TbERFLGVOZ0JvQixFSDBDckI7QUFSRDtNU2xERSxlTnlEb0IsRUhDckI7QVMzRkw7TUFxQ00sZUFBYyxFQXVCZjtBVHVCRDtRU3pDTSwwQk5WdUIsRUgyRDVCO0FBUkQ7UVN6Q00sMEJOK0J1QixFSGtCNUI7QUFSRDtRU3pDTSwwQk53RXVCLEVIdkI1QjtBUzNGTDtRQStDUSxvQkFBbUI7UUFDbkIsZ0JBQWU7UUFDZix1QkFBc0I7UUFDdEIsb0JBQW1CLEVBU3BCO0FBM0RQO1VBcURVLG1CQUFrQixFQUNuQjtBQXREVDtVQXlEVSxvQkFBbUIsRUFDcEI7QUN4Q1Q7RUFDRSxxQ0FBb0M7RUFDcEMsZ0JBQWUsRUFDaEI7QUFFRDtFQUNFLHFDQUFvQztFQUNwQyxrQkFBaUI7RUFDakIsYUFBWTtFQUNaLGNBQWEsRUFzQmQ7QUExQkQ7SUFPSSxnRUFBNkU7SUFDN0UsdUJBQXNCLEVBQ3ZCO0FBVEg7SUFZSSxnRUFBNkU7SUFDN0UsdUJBQXNCLEVBQ3ZCO0FBZEg7SUFpQkksaUVBQThFO0lBQzlFLHVCQUFzQixFQUN2QjtBQW5CSDtJQXNCSSxjQUFhO0lBQ2IsWUFBVztJQUNYLGFBQVksRUFDYjtBQU1IO0VBQ0UsNkJBQTRCO0VBQzVCLDRCQUEyQjtFQUMzQixXQUFVLEVBQ1g7QUFDRDtFQUNFLGVBQWM7RUFDZCxpQ0FBZ0M7RUFDaEMsMEJBQXlCO0VBQ3pCLG1CQUFrQixFQUNuQjtBQUNEO0VBQ0UsaUJBQWUsRUFDaEI7QUFDRDtFQUNFLGtCQUFnQjtFQUNoQixlQUFjO0VBQ2QsbUJBQWtCLEVBQ25CO0FBQ0Q7RUFDRSxpQkFBZTtFQUNmLDZCQUEyQixFQUM1QiIsImZpbGUiOiJzcmMvc3R5bGVzLnNjc3MiLCJzb3VyY2VzQ29udGVudCI6WyJAbWl4aW4gdGV4dC10cnVuY2F0ZSB7XHJcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcclxuICB0ZXh0LW92ZXJmbG93OiBlbGxpcHNpcztcclxuICB3aGl0ZS1zcGFjZTogbm93cmFwO1xyXG59XHJcbkBtaXhpbiB0ZXh0V3JhcCB7XHJcbiAgd2hpdGUtc3BhY2U6IG5vcm1hbDtcclxuICBvdmVyZmxvdy13cmFwOiBicmVhay13b3JkO1xyXG4gIHdvcmQtd3JhcDogYnJlYWstd29yZDtcclxuICB3b3JkLWJyZWFrOiBicmVhay1hbGw7XHJcbiAgbGluZS1icmVhazogc3RyaWN0O1xyXG4gIC13ZWJraXQtaHlwaGVuczogYXV0bztcclxuICAtbXMtaHlwaGVuczogYXV0bztcclxuICBoeXBoZW5zOiBhdXRvO1xyXG59XHJcbkBtaXhpbiBjb3ZlckJveCB7XHJcblx0cG9zaXRpb246IGFic29sdXRlO1xyXG5cdHRvcDogMDtcclxuXHRsZWZ0OiAwO1xyXG5cdHdpZHRoOiAxMDAlO1xyXG5cdGhlaWdodDogMTAwJTtcclxufVxyXG5AbWl4aW4gYWJzICgkdG9wOiBhdXRvLCAkcmlnaHQ6IGF1dG8sICRib3R0b206IGF1dG8sICRsZWZ0OiBhdXRvKSB7XHJcbiAgdG9wOiAkdG9wO1xyXG4gIHJpZ2h0OiAkcmlnaHQ7XHJcbiAgYm90dG9tOiAkYm90dG9tO1xyXG4gIGxlZnQ6ICRsZWZ0O1xyXG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcclxufVxyXG5AbWl4aW4gY292ZXJJbWcge1xyXG5cdGJhY2tncm91bmQtcmVwZWF0OiBuby1yZXBlYXQ7XHJcblx0LXdlYmtpdC1iYWNrZ3JvdW5kLXNpemU6IGNvdmVyO1xyXG5cdC1vLWJhY2tncm91bmQtc2l6ZTogY292ZXI7XHJcblx0YmFja2dyb3VuZC1zaXplOiBjb3ZlcjtcclxuXHRiYWNrZ3JvdW5kLXBvc2l0aW9uOiA1MCUgNTAlO1xyXG59XHJcbkBtaXhpbiB2YWxpbmdCb3gge1xyXG5cdHBvc2l0aW9uOiBhYnNvbHV0ZTtcclxuXHR0b3A6ICA1MCU7XHJcblx0bGVmdDogNTAlO1xyXG5cdHRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUsIC01MCUpO1xyXG59XHJcbkBtaXhpbiB1blNlbGVjdCB7XHJcblx0LXdlYmtpdC10b3VjaC1jb2xsb3V0OiBub25lO1xyXG4gIC13ZWJraXQtdXNlci1zZWxlY3Q6IG5vbmU7XHJcbiAgLWtodG1sLXVzZXItc2VsZWN0OiBub25lO1xyXG4gIC1tb3otdXNlci1zZWxlY3Q6IG5vbmU7XHJcbiAgLW1zLXVzZXItc2VsZWN0OiBub25lO1xyXG4gIHVzZXItc2VsZWN0OiBub25lO1xyXG59XHJcbkBtaXhpbiBtYXgxMTk5IHsgLy8gbWFrZXQgMTE3MVxyXG4gIEBtZWRpYSAobWF4LXdpZHRoOiAxMTk5cHgpIHsgQGNvbnRlbnQ7IH1cclxufVxyXG5AbWl4aW4gbWF4MTE3MCB7IC8vIG1ha2V0cyA5OTJcclxuICBAbWVkaWEgKG1heC13aWR0aDogMTE3MHB4KSB7IEBjb250ZW50OyB9XHJcbn1cclxuQG1peGluIG1heDk5MSB7IC8vIG1ha2V0cyA3NjJcclxuICBAbWVkaWEgKG1heC13aWR0aDogOTkxcHgpIHsgQGNvbnRlbnQ7IH1cclxufVxyXG5AbWl4aW4gbWF4NzYxIHsgLy8gbWFrZXRzIDU3NlxyXG4gIEBtZWRpYSAobWF4LXdpZHRoOiA3NjFweCkgeyBAY29udGVudDsgfVxyXG59XHJcbkBtaXhpbiBtYXg1NzUgeyAvLyBtYWtldHMgNDAwXHJcbiAgQG1lZGlhIChtYXgtd2lkdGg6IDU3NXB4KSB7IEBjb250ZW50OyB9XHJcbn1cclxuQG1peGluIG1vYmlsZSB7XHJcbiAgQG1lZGlhIChtYXgtd2lkdGg6IDM5OXB4KSB7IEBjb250ZW50OyB9XHJcbn1cclxuQG1peGluIGljb0NlbnRlciB7XHJcbiAgICBiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0O1xyXG4gICAgYmFja2dyb3VuZC1wb3NpdGlvbjogY2VudGVyIGNlbnRlcjtcclxufVxyXG5AbWl4aW4gcHNldWRvICgkZGlzcGxheTogYmxvY2ssICRwb3M6IGFic29sdXRlLCAkY29udGVudDogJycpe1xyXG4gIGNvbnRlbnQ6ICRjb250ZW50O1xyXG4gIGRpc3BsYXk6ICRkaXNwbGF5O1xyXG4gIHBvc2l0aW9uOiAkcG9zO1xyXG59XHJcblxyXG4vKlxyXG4qIEltcGxlbWVudGF0aW9uIG9mIHRoZW1lc1xyXG4qL1xyXG5AbWl4aW4gdGhlbWlmeSgkdGhlbWVzOiAkdGhlbWVzKSB7XHJcbiAgQGVhY2ggJHRoZW1lLCAkbWFwIGluICR0aGVtZXMge1xyXG4gICAgLnRoZW1lLSN7JHRoZW1lfSAmIHtcclxuICAgICAgJHRoZW1lLW1hcDogKCkgIWdsb2JhbDtcclxuICAgICAgQGVhY2ggJGtleSwgJHN1Ym1hcCBpbiAkbWFwIHtcclxuICAgICAgICAkdmFsdWU6IG1hcC1nZXQobWFwLWdldCgkdGhlbWVzLCAkdGhlbWUpLCAnI3ska2V5fScpO1xyXG4gICAgICAgICR0aGVtZS1tYXA6IG1hcC1tZXJnZSgkdGhlbWUtbWFwLCAoJGtleTogJHZhbHVlKSkgIWdsb2JhbDtcclxuICAgICAgfVxyXG4gICAgICBAY29udGVudDtcclxuICAgICAgJHRoZW1lLW1hcDogbnVsbCAhZ2xvYmFsO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuQGZ1bmN0aW9uIHRoZW1lZCgka2V5KSB7XHJcbiAgQHJldHVybiBtYXAtZ2V0KCR0aGVtZS1tYXAsICRrZXkpO1xyXG59XHJcbiIsIi8vKiAqKioqKioqIHJlc2V0ICYgbm9ybWFsaXplICoqKioqKiogICovL1xyXG5cclxuLy8gYm94LXNpemluZyB0aGUgc2FtZSBmb3IgYWxsIGVsZW1lbnRzXHJcbmh0bWwge1xyXG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XHJcbiAgLXdlYmtpdC1ib3gtc2l6aW5nOiBib3JkZXItYm94O1xyXG4gIC1tb3otYm94LXNpemluZzogYm9yZGVyLWJveDtcclxufVxyXG4qLCAqOmJlZm9yZSwgKjphZnRlciB7XHJcbiAgYm94LXNpemluZzogaW5oZXJpdDtcclxuICAtd2Via2l0LWJveC1zaXppbmc6IGluaGVyaXQ7XHJcbiAgLW1vei1ib3gtc2l6aW5nOiBpbmhlcml0O1xyXG4gIG1hcmdpbjogMDtcclxuICBwYWRkaW5nOiAwO1xyXG4gIEBpbmNsdWRlIHVuU2VsZWN0O1xyXG59XHJcblxyXG5odG1sLCBib2R5LCBkaXYsIHNwYW4sIGFwcGxldCwgb2JqZWN0LCBpZnJhbWUsXHJcbmgxLCBoMiwgaDMsIGg0LCBoNSwgaDYsIHAsIGJsb2NrcXVvdGUsIHByZSxcclxuYSwgYWJiciwgYWNyb255bSwgYWRkcmVzcywgYmlnLCBjaXRlLCBjb2RlLFxyXG5kZWwsIGRmbiwgZW0sIGltZywgaW5zLCBrYmQsIHEsIHMsIHNhbXAsXHJcbnNtYWxsLCBzdHJpa2UsIHN0cm9uZywgc3ViLCBzdXAsIHR0LCB2YXIsXHJcbmIsIHUsIGksIGNlbnRlcixcclxuZGwsIGR0LCBkZCwgb2wsIHVsLCBsaSxcclxuZmllbGRzZXQsIGZvcm0sIGxhYmVsLCBsZWdlbmQsXHJcbnRhYmxlLCBjYXB0aW9uLCB0Ym9keSwgdGZvb3QsIHRoZWFkLCB0ciwgdGgsIHRkLFxyXG5hcnRpY2xlLCBhc2lkZSwgY2FudmFzLCBkZXRhaWxzLCBlbWJlZCxcclxuZmlndXJlLCBmaWdjYXB0aW9uLCBmb290ZXIsIGhlYWRlciwgaGdyb3VwLFxyXG5tZW51LCBuYXYsIG91dHB1dCwgcnVieSwgc2VjdGlvbiwgc3VtbWFyeSxcclxudGltZSwgbWFyaywgYXVkaW8sIHZpZGVvIHtcclxuICAgIGJvcmRlcjogMDtcclxuICAgIGZvbnQtc2l6ZTogMTAwJTtcclxuICAgIGZvbnQ6IGluaGVyaXQ7XHJcbiAgICB2ZXJ0aWNhbC1hbGlnbjogYmFzZWxpbmU7XHJcbn1cclxuYXJ0aWNsZSwgYXNpZGUsIGRldGFpbHMsIGZpZ2NhcHRpb24sIGZpZ3VyZSxcclxuZm9vdGVyLCBoZWFkZXIsIGhncm91cCwgbWVudSwgbmF2LCBzZWN0aW9uIHtcclxuICAgIGRpc3BsYXk6IGJsb2NrO1xyXG59XHJcblxyXG5ib2R5IHtcclxuICAgbGluZS1oZWlnaHQ6IDE7XHJcbiAgIGZvbnQtc3R5bGU6IG5vcm1hbDtcclxufVxyXG5vbCwgdWwge1xyXG4gICAgbGlzdC1zdHlsZTogbm9uZTtcclxufVxyXG5ibG9ja3F1b3RlLCBxIHtcclxuICAgIHF1b3Rlczogbm9uZTtcclxufVxyXG5ibG9ja3F1b3RlOmJlZm9yZSwgYmxvY2txdW90ZTphZnRlcixcclxucTpiZWZvcmUsIHE6YWZ0ZXIge1xyXG4gICAgY29udGVudDogbm9uZTtcclxufVxyXG5cclxuLy90YWJsZVxyXG50YWJsZSB7XHJcbiAgICBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlO1xyXG4gICAgYm9yZGVyLXNwYWNpbmc6IDA7XHJcbn1cclxudGQsXHJcbnRoIHtcclxuICBwYWRkaW5nOiAwO1xyXG59XHJcblxyXG4vL2Zvcm1zIGVsZW1lbnRcclxuaW5wdXQge1xyXG4gICAgb3V0bGluZTogbm9uZTtcclxuICAgICY6LXdlYmtpdC1hdXRvZmlsbCB7XHJcbiAgICAgIC13ZWJraXQtYm94LXNoYWRvdzogMCAwIDAgMTAwMHB4IHdoaXRlIGluc2V0O1xyXG4gICAgfVxyXG59XHJcblxyXG5idXR0b24sXHJcbmh0bWwgaW5wdXRbdHlwZT1cImJ1dHRvblwiXSxcclxuaW5wdXRbdHlwZT1cInJlc2V0XCJdLFxyXG5pbnB1dFt0eXBlPVwic3VibWl0XCJdIHtcclxuICAtd2Via2l0LWFwcGVhcmFuY2U6IGJ1dHRvbjtcclxuICBjdXJzb3I6IHBvaW50ZXI7XHJcbiAgb3V0bGluZTogbm9uZTtcclxufVxyXG5idXR0b25bZGlzYWJsZWRdLFxyXG5odG1sIGlucHV0W2Rpc2FibGVkXSB7XHJcbiAgY3Vyc29yOiBkZWZhdWx0O1xyXG59XHJcbmJ1dHRvbjo6LW1vei1mb2N1cy1pbm5lcixcclxuaW5wdXQ6Oi1tb3otZm9jdXMtaW5uZXIge1xyXG4gIGJvcmRlcjogMDtcclxuICBwYWRkaW5nOiAwO1xyXG59XHJcbmlucHV0IHtcclxuICBsaW5lLWhlaWdodDogbm9ybWFsO1xyXG59XHJcbmlucHV0W3R5cGU9XCJzZWFyY2hcIl0ge1xyXG4gIC13ZWJraXQtYXBwZWFyYW5jZTogdGV4dGZpZWxkO1xyXG4gIGJveC1zaXppbmc6IGNvbnRlbnQtYm94O1xyXG59XHJcbmlucHV0W3R5cGU9XCJzZWFyY2hcIl06Oi13ZWJraXQtc2VhcmNoLWNhbmNlbC1idXR0b24sXHJcbmlucHV0W3R5cGU9XCJzZWFyY2hcIl06Oi13ZWJraXQtc2VhcmNoLWRlY29yYXRpb24ge1xyXG4gIC13ZWJraXQtYXBwZWFyYW5jZTogbm9uZTtcclxufVxyXG5cclxuXHJcbi8vbGlua1xyXG5hIHtcclxuXHR0ZXh0LWRlY29yYXRpb246IG5vbmU7XHJcblx0JjphY3RpdmUsXHJcblx0Jjpob3ZlcixcclxuXHQmOmZvY3VzIHtcclxuXHRcdG91dGxpbmU6IDA7XHJcblx0fVxyXG59XHJcblxyXG5pIHsgZm9udC1zdHlsZTogaXRhbGljOyB9XHJcbmIsIHN0cm9uZyB7IGZvbnQtd2VpZ2h0OiA3MDA7ICAgfVxyXG5cclxuLy8gaW1hZ2VzXHJcbmltZyB7XHJcblx0d2lkdGg6IGF1dG87XHJcblx0bWF4LXdpZHRoOiAxMDAlO1xyXG5cdGhlaWdodDogYXV0bztcclxuICB2ZXJ0aWNhbC1hbGlnbjogdG9wO1xyXG5cdGJvcmRlcjogMDtcclxufVxyXG5cclxuLmhpZGRlbiB7XHJcbiAgZGlzcGxheTogbm9uZSAhaW1wb3J0YW50O1xyXG59XHJcbiIsImJ1dHRvbiB7XHJcbiAgYm9yZGVyOiBub25lO1xyXG4gIGZvbnQtZmFtaWx5OiAnT3BlbiBTYW5zJywgc2Fucy1zZXJpZjtcclxuICBmb250LXNpemU6IDEuNXJlbTtcclxuICBmb250LXdlaWdodDogNjAwO1xyXG4gIG91dGxpbmU6IG5vbmU7XHJcbiAgcGFkZGluZzogMCAxcmVtO1xyXG4gIGhlaWdodDogNC4ycmVtO1xyXG5cclxuICAmOmRpc2FibGVkOm5vdCgudHJhbnNwYXJlbnQtYnV0dG9uKSB7XHJcblxyXG4gICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgIGJhY2tncm91bmQtY29sb3I6IHRoZW1lZChkaXNhYmxlZEJ1dHRvbkJhY2tncm91bmRDb2xvcik7XHJcbiAgICAgIGNvbG9yOiB0aGVtZWQoYWx0ZXJuYXRpdmVUZXh0Q29sb3IpO1xyXG4gICAgfVxyXG5cclxuICAgICY6aG92ZXIge1xyXG5cclxuICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogdGhlbWVkKGRpc2FibGVkQnV0dG9uSG92ZXJDb2xvcik7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gICYuYmx1ZS1idXR0b246bm90KDpkaXNhYmxlZCkge1xyXG5cclxuICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0aGVtZWQoYmx1ZUJ1dHRvbkJhY2tncm91bmRDb2xvcik7XHJcbiAgICAgIGNvbG9yOiB0aGVtZWQoYWx0ZXJuYXRpdmVUZXh0Q29sb3IpO1xyXG4gICAgfVxyXG5cclxuICAgICY6aG92ZXIge1xyXG5cclxuICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogdGhlbWVkKGJsdWVCdXR0b25Ib3ZlckNvbG9yKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgJi5ncmVlbi1idXR0b246bm90KDpkaXNhYmxlZCkge1xyXG5cclxuICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0aGVtZWQoZ3JlZW5CdXR0b25CYWNrZ3JvdW5kQ29sb3IpO1xyXG4gICAgICBjb2xvcjogdGhlbWVkKGFsdGVybmF0aXZlVGV4dENvbG9yKTtcclxuICAgIH1cclxuXHJcbiAgICAmOmhvdmVyIHtcclxuXHJcbiAgICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICAgIGJhY2tncm91bmQtY29sb3I6IHRoZW1lZChncmVlbkJ1dHRvbkhvdmVyQ29sb3IpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAmLnR1cnF1b2lzZS1idXR0b246bm90KDpkaXNhYmxlZCkge1xyXG5cclxuICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0aGVtZWQodHVycXVvaXNlQnV0dG9uQmFja2dyb3VuZENvbG9yKTtcclxuICAgICAgY29sb3I6IHRoZW1lZChhbHRlcm5hdGl2ZVRleHRDb2xvcik7XHJcbiAgICB9XHJcblxyXG4gICAgJjpob3ZlciB7XHJcblxyXG4gICAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0aGVtZWQodHVycXVvaXNlQnV0dG9uSG92ZXJDb2xvcik7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gICYudHJhbnNwYXJlbnQtYnV0dG9uIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XHJcblxyXG4gICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgIGJhY2tncm91bmQtY29sb3I6IHRyYW5zcGFyZW50O1xyXG4gICAgICBib3JkZXI6IDAuMnJlbSBzb2xpZCB0aGVtZWQodHJhbnNwYXJlbnRCdXR0b25Cb3JkZXJDb2xvcik7XHJcbiAgICAgIGNvbG9yOiB0aGVtZWQobWFpblRleHRDb2xvcik7XHJcbiAgICB9XHJcblxyXG4gICAgLmljb24ge1xyXG5cclxuICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogdGhlbWVkKG1haW5UZXh0Q29sb3IpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBtYXJnaW4tcmlnaHQ6IDFyZW07XHJcbiAgICAgIG1hc2s6IHVybCh+c3JjL2Fzc2V0cy9pY29ucy9jb21wbGV0ZS10ZXN0d2FsbGV0LnN2Zykgbm8tcmVwZWF0IGNlbnRlcjtcclxuICAgICAgd2lkdGg6IDEuN3JlbTtcclxuICAgICAgaGVpZ2h0OiAxLjdyZW07XHJcbiAgICB9XHJcbiAgfVxyXG5cclxufVxyXG5cclxuLmlucHV0LWJsb2NrIHtcclxuICBkaXNwbGF5OiBmbGV4O1xyXG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XHJcbiAgYWxpZ24taXRlbXM6IGZsZXgtc3RhcnQ7XHJcbiAgbWFyZ2luLWJvdHRvbTogMC40cmVtO1xyXG4gIGhlaWdodDogNi42cmVtO1xyXG5cclxuICAud3JhcC1sYWJlbCB7XHJcbiAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuICAgIGp1c3RpZnktY29udGVudDogZmxleC1zdGFydDtcclxuICAgIG1pbi1oZWlnaHQ6IDIuNHJlbTtcclxuICB9XHJcblxyXG4gIGxhYmVsIHtcclxuICAgIGZvbnQtc2l6ZTogMS4zcmVtO1xyXG4gICAgbGluZS1oZWlnaHQ6IDIuNHJlbTtcclxuXHJcbiAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgY29sb3I6IHRoZW1lZChvcHRpb25hbFRleHRDb2xvcik7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBpbnB1dFt0eXBlPSd0ZXh0J10sIGlucHV0W3R5cGU9J3Bhc3N3b3JkJ10ge1xyXG4gICAgYm9yZGVyOiBub25lO1xyXG4gICAgZm9udC1zaXplOiAxLjRyZW07XHJcbiAgICBvdXRsaW5lOiBub25lO1xyXG4gICAgcGFkZGluZzogMCAxcmVtO1xyXG4gICAgd2lkdGg6IDEwMCU7XHJcbiAgICBoZWlnaHQ6IDEwMCU7XHJcblxyXG4gICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgIGJhY2tncm91bmQtY29sb3I6IHRoZW1lZChpbnB1dEJhY2tncm91bmRDb2xvcik7XHJcbiAgICAgIGNvbG9yOiB0aGVtZWQobWFpblRleHRDb2xvcik7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAmLnRleHRhcmVhIHtcclxuICAgIGhlaWdodDogYXV0bztcclxuXHJcbiAgICB0ZXh0YXJlYSB7XHJcbiAgICAgIGZvbnQtZmFtaWx5OiAnT3BlbiBTYW5zJywgc2Fucy1zZXJpZjtcclxuICAgICAgYm9yZGVyOiBub25lO1xyXG4gICAgICBmb250LXNpemU6IDEuNHJlbTtcclxuICAgICAgb3V0bGluZTogbm9uZTtcclxuICAgICAgcGFkZGluZzogMXJlbTtcclxuICAgICAgd2lkdGg6IDEwMCU7XHJcbiAgICAgIG1pbi13aWR0aDogMTAwJTtcclxuICAgICAgaGVpZ2h0OiAxMDAlO1xyXG4gICAgICBtaW4taGVpZ2h0OiA3cmVtO1xyXG4gICAgICBtYXgtaGVpZ2h0OiA3cmVtO1xyXG4gICAgICBvdmVyZmxvdzogaGlkZGVuO1xyXG4gICAgICByZXNpemU6IG5vbmU7XHJcblxyXG4gICAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0aGVtZWQoaW5wdXRCYWNrZ3JvdW5kQ29sb3IpO1xyXG4gICAgICAgIGNvbG9yOiB0aGVtZWQobWFpblRleHRDb2xvcik7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbmlucHV0W3R5cGU9J3JhZGlvJ10uc3R5bGUtcmFkaW8ge1xyXG5cclxuICAmICsgbGFiZWwge1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAgICBjdXJzb3I6IHBvaW50ZXI7XHJcbiAgICBmb250LXdlaWdodDogNDAwO1xyXG4gICAgcGFkZGluZy1sZWZ0OiAyLjRyZW07XHJcblxyXG4gICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgIGNvbG9yOiB0aGVtZWQob3B0aW9uYWxUZXh0Q29sb3IpO1xyXG4gICAgfVxyXG5cclxuICAgIEBpbmNsdWRlIHVuU2VsZWN0O1xyXG4gIH1cclxuXHJcbiAgJjpub3QoY2hlY2tlZCkge1xyXG4gICAgcG9zaXRpb246IGFic29sdXRlO1xyXG4gICAgb3BhY2l0eTogMDtcclxuXHJcbiAgICAmICsgbGFiZWwge1xyXG4gICAgICBwb3NpdGlvbjogcmVsYXRpdmU7XHJcbiAgICB9XHJcblxyXG4gICAgJiArIGxhYmVsOmJlZm9yZSB7XHJcbiAgICAgIGNvbnRlbnQ6ICcnO1xyXG4gICAgICBwb3NpdGlvbjogYWJzb2x1dGU7XHJcbiAgICAgIHRvcDogMC43cmVtO1xyXG4gICAgICBsZWZ0OiAwO1xyXG4gICAgICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudDtcclxuICAgICAgYm9yZGVyLXJhZGl1czogNTAlO1xyXG4gICAgICB3aWR0aDogMS40cmVtO1xyXG4gICAgICBoZWlnaHQ6IDEuNHJlbTtcclxuXHJcbiAgICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICAgIGJvcmRlcjogMC4xcmVtIHNvbGlkIHRoZW1lZChibHVlVGV4dENvbG9yKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgICYgKyBsYWJlbDphZnRlciB7XHJcbiAgICAgIGNvbnRlbnQ6ICcnO1xyXG4gICAgICBwb3NpdGlvbjogYWJzb2x1dGU7XHJcbiAgICAgIHRvcDogMXJlbTtcclxuICAgICAgbGVmdDogMC4zcmVtO1xyXG4gICAgICBib3JkZXItcmFkaXVzOiA1MCU7XHJcbiAgICAgIG9wYWNpdHk6IDA7XHJcbiAgICAgIHdpZHRoOiAwLjhyZW07XHJcbiAgICAgIGhlaWdodDogMC44cmVtO1xyXG5cclxuICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogdGhlbWVkKGJsdWVUZXh0Q29sb3IpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAmOmNoZWNrZWQge1xyXG5cclxuICAgICYgKyBsYWJlbDphZnRlciB7XHJcbiAgICAgIG9wYWNpdHk6IDE7XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcblxyXG5pbnB1dFt0eXBlPSdjaGVja2JveCddLnN0eWxlLWNoZWNrYm94IHtcclxuXHJcbiAgJiArIGxhYmVsIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAgY3Vyc29yOiBwb2ludGVyO1xyXG4gICAgZm9udC13ZWlnaHQ6IDQwMDtcclxuICAgIHBhZGRpbmctbGVmdDogMy42cmVtO1xyXG5cclxuICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICBjb2xvcjogdGhlbWVkKG9wdGlvbmFsVGV4dENvbG9yKTtcclxuICAgIH1cclxuXHJcbiAgICBAaW5jbHVkZSB1blNlbGVjdDtcclxuICB9XHJcblxyXG4gICY6bm90KGNoZWNrZWQpIHtcclxuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcclxuICAgIHRvcDogNTAlO1xyXG4gICAgbGVmdDogMS42cmVtO1xyXG4gICAgdHJhbnNmb3JtOiB0cmFuc2xhdGVZKC01MCUpO1xyXG4gICAgdmlzaWJpbGl0eTogaGlkZGVuO1xyXG5cclxuICAgICYgKyBsYWJlbCB7XHJcbiAgICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcclxuICAgIH1cclxuXHJcbiAgICAmICsgbGFiZWw6YmVmb3JlIHtcclxuICAgICAgY29udGVudDogJyc7XHJcbiAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcclxuICAgICAgdG9wOiA1MCU7XHJcbiAgICAgIGxlZnQ6IDEuNnJlbTtcclxuICAgICAgdHJhbnNmb3JtOiB0cmFuc2xhdGVZKC01MCUpO1xyXG4gICAgICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudDtcclxuICAgICAgd2lkdGg6IDEuNHJlbTtcclxuICAgICAgaGVpZ2h0OiAxLjRyZW07XHJcblxyXG4gICAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgICBib3JkZXI6IDAuMXJlbSBzb2xpZCB0aGVtZWQoYmx1ZVRleHRDb2xvcik7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gICY6Y2hlY2tlZCB7XHJcblxyXG4gICAgJiArIGxhYmVsOmJlZm9yZSB7XHJcbiAgICAgIGJhY2tncm91bmQ6IHVybCh+c3JjL2Fzc2V0cy9pY29ucy9jb21wbGV0ZS10ZXN0d2FsbGV0LnN2Zyk7XHJcblxyXG4gICAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0aGVtZWQoYmx1ZVRleHRDb2xvcik7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbi5lcnJvci1ibG9jayB7XHJcbiAgZm9udC1zaXplOiAxLjJyZW07XHJcbiAgdGV4dC1hbGlnbjogcmlnaHQ7XHJcblxyXG4gIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgY29sb3I6IHRoZW1lZChyZWRUZXh0Q29sb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLmhpc3RvcnktdG9vbHRpcCB7XHJcbiAgZm9udC1zaXplOiAxLjNyZW07XHJcbiAgcGFkZGluZzogMXJlbSAycmVtO1xyXG5cclxuICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgIGJhY2tncm91bmQ6IHRoZW1lZCh0b29sdGlwQmFja2dyb3VuZENvbG9yKTtcclxuICAgIGJveC1zaGFkb3c6IHRoZW1lZCh0b29sdGlwU2hhZG93KTtcclxuICAgIGNvbG9yOiB0aGVtZWQobWFpblRleHRDb2xvcik7XHJcbiAgfVxyXG5cclxuICAmLm5nLXRvb2x0aXAtdG9wIHtcclxuICAgIG1hcmdpbi10b3A6IC0xcmVtO1xyXG5cclxuICAgICY6YmVmb3JlIHtcclxuICAgICAgY29udGVudDogXCJcIjtcclxuICAgICAgcG9zaXRpb246IGFic29sdXRlO1xyXG4gICAgICBib3R0b206IC0xcmVtO1xyXG4gICAgICBsZWZ0OiAwLjdyZW07XHJcbiAgICAgIGJvcmRlci13aWR0aDogMXJlbSAxcmVtIDAgMDtcclxuICAgICAgYm9yZGVyLXN0eWxlOiBzb2xpZDtcclxuXHJcbiAgICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICAgIGJvcmRlci1jb2xvcjogdGhlbWVkKHRvb2x0aXBCYWNrZ3JvdW5kQ29sb3IpIHRyYW5zcGFyZW50IHRyYW5zcGFyZW50IHRyYW5zcGFyZW50O1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAmLm5nLXRvb2x0aXAtYm90dG9tIHtcclxuICAgIG1hcmdpbi10b3A6IDFyZW07XHJcblxyXG4gICAgJjpiZWZvcmUge1xyXG4gICAgICBjb250ZW50OiBcIlwiO1xyXG4gICAgICBwb3NpdGlvbjogYWJzb2x1dGU7XHJcbiAgICAgIHRvcDogLTFyZW07XHJcbiAgICAgIGxlZnQ6IDAuN3JlbTtcclxuICAgICAgYm9yZGVyLXdpZHRoOiAxcmVtIDAgMCAxcmVtO1xyXG4gICAgICBib3JkZXItc3R5bGU6IHNvbGlkO1xyXG5cclxuICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgYm9yZGVyLWNvbG9yOiB0cmFuc3BhcmVudCB0cmFuc3BhcmVudCB0cmFuc3BhcmVudCB0aGVtZWQodG9vbHRpcEJhY2tncm91bmRDb2xvcik7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gICYubmctdG9vbHRpcC1sZWZ0IHtcclxuICAgIG1hcmdpbi1sZWZ0OiAtMXJlbTtcclxuXHJcbiAgICAmOmJlZm9yZSB7XHJcbiAgICAgIGNvbnRlbnQ6IFwiXCI7XHJcbiAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcclxuICAgICAgdG9wOiAwO1xyXG4gICAgICByaWdodDogLTFyZW07XHJcbiAgICAgIGJvcmRlci13aWR0aDogMXJlbSAxcmVtIDAgMDtcclxuICAgICAgYm9yZGVyLXN0eWxlOiBzb2xpZDtcclxuXHJcbiAgICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICAgIGJvcmRlci1jb2xvcjogdGhlbWVkKHRvb2x0aXBCYWNrZ3JvdW5kQ29sb3IpIHRyYW5zcGFyZW50IHRyYW5zcGFyZW50IHRyYW5zcGFyZW50O1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAmLm5nLXRvb2x0aXAtcmlnaHQge1xyXG4gICAgbWFyZ2luLWxlZnQ6IDFyZW07XHJcblxyXG4gICAgJjpiZWZvcmUge1xyXG4gICAgICBjb250ZW50OiBcIlwiO1xyXG4gICAgICBwb3NpdGlvbjogYWJzb2x1dGU7XHJcbiAgICAgIHRvcDogMDtcclxuICAgICAgbGVmdDogLTFyZW07XHJcbiAgICAgIGJvcmRlci13aWR0aDogMXJlbSAwIDAgMXJlbTtcclxuICAgICAgYm9yZGVyLXN0eWxlOiBzb2xpZDtcclxuXHJcbiAgICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICAgIGJvcmRlci1jb2xvcjogdGhlbWVkKHRvb2x0aXBCYWNrZ3JvdW5kQ29sb3IpIHRyYW5zcGFyZW50IHRyYW5zcGFyZW50IHRyYW5zcGFyZW50O1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcblxyXG4ubW9kYWwge1xyXG5cclxuICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgIGJhY2tncm91bmQ6IHRoZW1lZCh0b29sdGlwQmFja2dyb3VuZENvbG9yKTtcclxuICAgIGNvbG9yOiB0aGVtZWQobWFpblRleHRDb2xvcik7XHJcbiAgfVxyXG5cclxuICAuY29udGVudCB7XHJcblxyXG4gIH1cclxuXHJcbiAgLmFjdGlvbi1idXR0b24ge1xyXG5cclxuICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0aGVtZWQoYmx1ZVRleHRDb2xvcik7XHJcbiAgICAgIGNvbG9yOiB0aGVtZWQoYWx0ZXJuYXRpdmVUZXh0Q29sb3IpO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG4iLCIkdGhlbWVzOiAoXHJcbiAgZGFyazogKFxyXG4gICAgYm9keUJhY2tncm91bmRDb2xvcjogIzEzMTkyMSxcclxuICAgIHNpZGViYXJCYWNrZ3JvdW5kQ29sb3I6IHJnYmEoMjMsIDMxLCAzOSwgMC41KSxcclxuICAgIHNpZGViYXJCb3JkZXJDb2xvcjogIzFmMjgzMyxcclxuICAgIG9ubGluZUNvbG9yOiAjNWNkYTlkLFxyXG4gICAgb2ZmbGluZUNvbG9yOiAjZmU1MjUyLFxyXG4gICAgY29udGVudEJhY2tncm91bmRDb2xvcjogcmdiYSg0MywgNTQsIDY4LCAwLjUpLFxyXG4gICAgbWFpblRleHRDb2xvcjogI2UwZTBlMCxcclxuICAgIGFsdGVybmF0aXZlVGV4dENvbG9yOiAjMTExOTIxLFxyXG4gICAgb3B0aW9uYWxUZXh0Q29sb3I6ICM1NTY1NzYsXHJcbiAgICBibHVlVGV4dENvbG9yOiAjNGRiMWZmLFxyXG4gICAgcmVkVGV4dENvbG9yOiAjZmY1MjUyLFxyXG4gICAgYmx1ZUJ1dHRvbkJhY2tncm91bmRDb2xvcjogIzRkYjFmZixcclxuICAgIGJsdWVCdXR0b25Ib3ZlckNvbG9yOiAjNjBiOWZmLFxyXG4gICAgZGlzYWJsZWRCdXR0b25CYWNrZ3JvdW5kQ29sb3I6ICM5MGE0YWUsXHJcbiAgICBkaXNhYmxlZEJ1dHRvbkhvdmVyQ29sb3I6ICM5YmIwYmEsXHJcbiAgICBncmVlbkJ1dHRvbkJhY2tncm91bmRDb2xvcjogIzVjZGE5ZCxcclxuICAgIGdyZWVuQnV0dG9uSG92ZXJDb2xvcjogIzVjZTJhMSxcclxuICAgIHR1cnF1b2lzZUJ1dHRvbkJhY2tncm91bmRDb2xvcjogIzRkZDBlMSxcclxuICAgIHR1cnF1b2lzZUJ1dHRvbkhvdmVyQ29sb3I6ICM1MmQ5ZWEsXHJcbiAgICB0cmFuc3BhcmVudEJ1dHRvbkJvcmRlckNvbG9yOiAjMmIzNjQ0LFxyXG4gICAgaW5wdXRCYWNrZ3JvdW5kQ29sb3I6ICMxNzFlMjcsXHJcbiAgICBzd2l0Y2hCYWNrZ3JvdW5kQ29sb3I6ICMwMDAwMDAsXHJcbiAgICBhY2NvdW50QmFja2dyb3VuZENvbG9yOiByZ2JhKDQzLCA1NCwgNjgsIDAuNSksXHJcbiAgICBhY2NvdW50SG92ZXJCYWNrZ3JvdW5kQ29sb3I6IHJnYmEoNTgsIDcyLCA5MCwgMC41KSxcclxuICAgIGFjY291bnRNYWluVGV4dENvbG9yOiAjZTBlMGUwLFxyXG4gICAgYWNjb3VudE9wdGlvbmFsVGV4dENvbG9yOiAjNTU2NTc2LFxyXG4gICAgYWNjb3VudEluZGljYXRvclRleHRDb2xvcjogIzExMTkyMSxcclxuICAgIGFjY291bnRTd2l0Y2hCYWNrZ3JvdW5kQ29sb3I6ICMwMDAwMDAsXHJcbiAgICBhY2NvdW50SW5kaWNhdG9yQmFja2dyb3VuZENvbG9yOiAjNGRiMWZmLFxyXG4gICAgdGFiSW5hY3RpdmVCYWNrZ3JvdW5kQ29sb3I6IHJnYmEoMjMsIDMxLCAzOSwgMC41KSxcclxuICAgIHRhYmxlQmFja2dyb3VuZENvbG9yOiAjMTgyMDJhLFxyXG4gICAgbWVzc2FnZU15QmFja2dyb3VuZENvbG9yOiAjMmEzNTQ0LFxyXG4gICAgbWVzc2FnZUJ1ZGR5QmFja2dyb3VuZENvbG9yOiAjMTgyMDJhLFxyXG4gICAgcHJvZ3Jlc3NCYXJCYWNrZ3JvdW5kQ29sb3I6ICMzNDNmNGEsXHJcbiAgICBwcm9ncmVzc0JhckZ1bGxCYWNrZ3JvdW5kQ29sb3I6ICM1Y2RhOWQsXHJcbiAgICBjaGFydE9wdGlvbnNCYWNrZ3JvdW5kQ29sb3I6ICMyYjM2NDQsXHJcbiAgICBjaGFydE9wdGlvbnNIb3ZlckNvbG9yOiAjNTU2NTc2LFxyXG4gICAgdG9vbHRpcEJhY2tncm91bmRDb2xvcjogIzQyNTA1ZixcclxuICAgIHRvb2x0aXBTaGFkb3c6IDAgMCAxcmVtIHJnYmEoMCwgMCwgMCwgMC41KVxyXG4gICksXHJcbiAgZ3JheTogKFxyXG4gICAgYm9keUJhY2tncm91bmRDb2xvcjogIzEwMTQxNyxcclxuICAgIHNpZGViYXJCYWNrZ3JvdW5kQ29sb3I6IHJnYmEoMjMsIDI1LCAyNywgMC41KSxcclxuICAgIHNpZGViYXJCb3JkZXJDb2xvcjogIzJlMzMzNyxcclxuICAgIG9ubGluZUNvbG9yOiAjNDdjZjhkLFxyXG4gICAgb2ZmbGluZUNvbG9yOiAjZmY1MjUyLFxyXG4gICAgY29udGVudEJhY2tncm91bmRDb2xvcjogcmdiYSgzNywgNDAsIDQzLCAwLjUpLFxyXG4gICAgbWFpblRleHRDb2xvcjogI2UwZTBlMCxcclxuICAgIGFsdGVybmF0aXZlVGV4dENvbG9yOiAjMWExYTFhLFxyXG4gICAgb3B0aW9uYWxUZXh0Q29sb3I6ICM1NjVjNjIsXHJcbiAgICBibHVlVGV4dENvbG9yOiAjNDJhNWY1LFxyXG4gICAgcmVkVGV4dENvbG9yOiAjZmY1MjUyLFxyXG4gICAgYmx1ZUJ1dHRvbkJhY2tncm91bmRDb2xvcjogIzQyYTVmNSxcclxuICAgIGJsdWVCdXR0b25Ib3ZlckNvbG9yOiAjNGRhZmZmLFxyXG4gICAgZGlzYWJsZWRCdXR0b25CYWNrZ3JvdW5kQ29sb3I6ICM3OTg0OGYsXHJcbiAgICBkaXNhYmxlZEJ1dHRvbkhvdmVyQ29sb3I6ICM4NTkwOWIsXHJcbiAgICBncmVlbkJ1dHRvbkJhY2tncm91bmRDb2xvcjogIzQ3Y2Y4ZCxcclxuICAgIGdyZWVuQnV0dG9uSG92ZXJDb2xvcjogIzQ5ZDk5MyxcclxuICAgIHR1cnF1b2lzZUJ1dHRvbkJhY2tncm91bmRDb2xvcjogIzNlYzVkNyxcclxuICAgIHR1cnF1b2lzZUJ1dHRvbkhvdmVyQ29sb3I6ICM0M2NlZTAsXHJcbiAgICB0cmFuc3BhcmVudEJ1dHRvbkJvcmRlckNvbG9yOiAjMmYzNDM4LFxyXG4gICAgaW5wdXRCYWNrZ3JvdW5kQ29sb3I6ICMyOTJkMzEsXHJcbiAgICBzd2l0Y2hCYWNrZ3JvdW5kQ29sb3I6ICMwMDAwMDAsXHJcbiAgICBhY2NvdW50QmFja2dyb3VuZENvbG9yOiByZ2JhKDM3LCA0MCwgNDMsIDAuNSksXHJcbiAgICBhY2NvdW50SG92ZXJCYWNrZ3JvdW5kQ29sb3I6IHJnYmEoNzAsIDc2LCA4MSwgMC41KSxcclxuICAgIGFjY291bnRNYWluVGV4dENvbG9yOiAjZTBlMGUwLFxyXG4gICAgYWNjb3VudE9wdGlvbmFsVGV4dENvbG9yOiAjNTY1YzYyLFxyXG4gICAgYWNjb3VudEluZGljYXRvclRleHRDb2xvcjogIzFhMWExYSxcclxuICAgIGFjY291bnRTd2l0Y2hCYWNrZ3JvdW5kQ29sb3I6ICMwMDAwMDAsXHJcbiAgICBhY2NvdW50SW5kaWNhdG9yQmFja2dyb3VuZENvbG9yOiAjNDJhNWY1LFxyXG4gICAgdGFiSW5hY3RpdmVCYWNrZ3JvdW5kQ29sb3I6IHJnYmEoMjMsIDI1LCAyNywgMC41KSxcclxuICAgIHRhYmxlQmFja2dyb3VuZENvbG9yOiAjMjUyOTJkLFxyXG4gICAgbWVzc2FnZU15QmFja2dyb3VuZENvbG9yOiAjMzAzNjNjLFxyXG4gICAgbWVzc2FnZUJ1ZGR5QmFja2dyb3VuZENvbG9yOiAjMjUyOTJkLFxyXG4gICAgcHJvZ3Jlc3NCYXJCYWNrZ3JvdW5kQ29sb3I6ICMzNjNhM2UsXHJcbiAgICBwcm9ncmVzc0JhckZ1bGxCYWNrZ3JvdW5kQ29sb3I6ICM0N2NmOGQsXHJcbiAgICBjaGFydE9wdGlvbnNCYWNrZ3JvdW5kQ29sb3I6ICMyOTJkMzEsXHJcbiAgICBjaGFydE9wdGlvbnNIb3ZlckNvbG9yOiAjNTE1OTYwLFxyXG4gICAgdG9vbHRpcEJhY2tncm91bmRDb2xvcjogIzNlNDY0YyxcclxuICAgIHRvb2x0aXBTaGFkb3c6IDAgMCAxcmVtIHJnYmEoMCwgMCwgMCwgMC41KVxyXG4gICksXHJcbiAgd2hpdGU6IChcclxuICAgIGJvZHlCYWNrZ3JvdW5kQ29sb3I6ICNlZWVlZWUsXHJcbiAgICBzaWRlYmFyQmFja2dyb3VuZENvbG9yOiByZ2JhKDI1NSwgMjU1LCAyNTUsIDAuNSksXHJcbiAgICBzaWRlYmFyQm9yZGVyQ29sb3I6ICNlYmViZWIsXHJcbiAgICBvbmxpbmVDb2xvcjogIzQ2YzE3MixcclxuICAgIG9mZmxpbmVDb2xvcjogI2ZmNTI1MixcclxuICAgIGNvbnRlbnRCYWNrZ3JvdW5kQ29sb3I6IHJnYmEoMjU1LCAyNTUsIDI1NSwgMC41KSxcclxuICAgIG1haW5UZXh0Q29sb3I6ICM0MzQ1NGIsXHJcbiAgICBhbHRlcm5hdGl2ZVRleHRDb2xvcjogI2ZlZmVmZSxcclxuICAgIG9wdGlvbmFsVGV4dENvbG9yOiAjYTBhNWFiLFxyXG4gICAgYmx1ZVRleHRDb2xvcjogIzJjOTVmMSxcclxuICAgIHJlZFRleHRDb2xvcjogI2ZmNTI1MixcclxuICAgIGJsdWVCdXR0b25CYWNrZ3JvdW5kQ29sb3I6ICMyYzk1ZjEsXHJcbiAgICBibHVlQnV0dG9uSG92ZXJDb2xvcjogIzM3OWZmYSxcclxuICAgIGRpc2FibGVkQnV0dG9uQmFja2dyb3VuZENvbG9yOiAjOTBhNGFlLFxyXG4gICAgZGlzYWJsZWRCdXR0b25Ib3ZlckNvbG9yOiAjOWJhZWI3LFxyXG4gICAgZ3JlZW5CdXR0b25CYWNrZ3JvdW5kQ29sb3I6ICM0NmMxNzIsXHJcbiAgICBncmVlbkJ1dHRvbkhvdmVyQ29sb3I6ICM0NmNhNzUsXHJcbiAgICB0dXJxdW9pc2VCdXR0b25CYWNrZ3JvdW5kQ29sb3I6ICMyNmI2YzcsXHJcbiAgICB0dXJxdW9pc2VCdXR0b25Ib3ZlckNvbG9yOiAjMmJiZGNmLFxyXG4gICAgdHJhbnNwYXJlbnRCdXR0b25Cb3JkZXJDb2xvcjogI2ViZWJlYixcclxuICAgIGlucHV0QmFja2dyb3VuZENvbG9yOiAjZTZlNmU2LFxyXG4gICAgc3dpdGNoQmFja2dyb3VuZENvbG9yOiAjZTBlMGUwLFxyXG4gICAgYWNjb3VudEJhY2tncm91bmRDb2xvcjogcmdiYSgzMCwgMTM2LCAyMjksIDEpLFxyXG4gICAgYWNjb3VudEhvdmVyQmFja2dyb3VuZENvbG9yOiByZ2JhKDI0MCwgMjQwLCAyNDAsIDAuNSksXHJcbiAgICBhY2NvdW50TWFpblRleHRDb2xvcjogI2ZmZmZmZixcclxuICAgIGFjY291bnRPcHRpb25hbFRleHRDb2xvcjogIzkxYmFmMSxcclxuICAgIGFjY291bnRJbmRpY2F0b3JUZXh0Q29sb3I6ICM0MzQ1NGIsXHJcbiAgICBhY2NvdW50U3dpdGNoQmFja2dyb3VuZENvbG9yOiAjZmZmZmZmLFxyXG4gICAgYWNjb3VudEluZGljYXRvckJhY2tncm91bmRDb2xvcjogI2ZmZmZmZixcclxuICAgIHRhYkluYWN0aXZlQmFja2dyb3VuZENvbG9yOiByZ2JhKDIyNCwgMjI0LCAyMjQsIDAuNSksXHJcbiAgICB0YWJsZUJhY2tncm91bmRDb2xvcjogI2ZmZmZmZixcclxuICAgIG1lc3NhZ2VNeUJhY2tncm91bmRDb2xvcjogI2ZmZixcclxuICAgIG1lc3NhZ2VCdWRkeUJhY2tncm91bmRDb2xvcjogI2VkZWRlZCxcclxuICAgIHByb2dyZXNzQmFyQmFja2dyb3VuZENvbG9yOiAjZGNkY2RjLFxyXG4gICAgcHJvZ3Jlc3NCYXJGdWxsQmFja2dyb3VuZENvbG9yOiAjNDZjMTcyLFxyXG4gICAgY2hhcnRPcHRpb25zQmFja2dyb3VuZENvbG9yOiAjZTBlMGUwLFxyXG4gICAgY2hhcnRPcHRpb25zSG92ZXJDb2xvcjogI2ZmZmZmZixcclxuICAgIHRvb2x0aXBCYWNrZ3JvdW5kQ29sb3I6ICNmZmZmZmYsXHJcbiAgICB0b29sdGlwU2hhZG93OiAwIDAgMXJlbSByZ2JhKDEyMCwgMTIwLCAxMjAsIDAuNSlcclxuICApXHJcbik7XHJcblxyXG5cclxuXHJcblxyXG5cclxuIiwiYXBwLW1haW4sIGFwcC1jcmVhdGUtd2FsbGV0LCBhcHAtb3Blbi13YWxsZXQsIGFwcC1yZXN0b3JlLXdhbGxldCwgYXBwLXNlZWQtcGhyYXNlLCBhcHAtd2FsbGV0LWRldGFpbHMsIGFwcC1zZXR0aW5ncywgYXBwLWxvZ2luIHtcclxuICBmbGV4OiAxIDEgYXV0bztcclxuICBwYWRkaW5nOiAzcmVtO1xyXG4gIG1pbi13aWR0aDogODVyZW07XHJcblxyXG4gIC5jb250ZW50IHtcclxuICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcclxuICAgIHBhZGRpbmc6IDNyZW07XHJcbiAgICBtaW4taGVpZ2h0OiAxMDAlO1xyXG5cclxuICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0aGVtZWQoY29udGVudEJhY2tncm91bmRDb2xvcik7XHJcbiAgICAgIGNvbG9yOiB0aGVtZWQobWFpblRleHRDb2xvcik7XHJcbiAgICB9XHJcblxyXG4gICAgLmhlYWQge1xyXG4gICAgICBwb3NpdGlvbjogYWJzb2x1dGU7XHJcbiAgICAgIHRvcDogMDtcclxuICAgICAgbGVmdDogMDtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbmFwcC1tYWluIHtcclxuXHJcbiAgLmNvbnRlbnQge1xyXG5cclxuICAgIC5hZGQtd2FsbGV0IHtcclxuXHJcbiAgICAgIC5hZGQtd2FsbGV0LWhlbHAge1xyXG5cclxuICAgICAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgICAgIGNvbG9yOiB0aGVtZWQoYmx1ZVRleHRDb2xvcik7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAuaWNvbiB7XHJcblxyXG4gICAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IHRoZW1lZChibHVlVGV4dENvbG9yKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbmFwcC1zZWVkLXBocmFzZSB7XHJcblxyXG4gIC5zZWVkLXBocmFzZS1jb250ZW50IHtcclxuXHJcbiAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgYmFja2dyb3VuZC1jb2xvcjogdGhlbWVkKGlucHV0QmFja2dyb3VuZENvbG9yKTtcclxuICAgICAgY29sb3I6IHRoZW1lZChtYWluVGV4dENvbG9yKVxyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuYXBwLXdhbGxldC1kZXRhaWxzIHtcclxuXHJcbiAgLnNlZWQtcGhyYXNlIHtcclxuXHJcbiAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgYmFja2dyb3VuZC1jb2xvcjogdGhlbWVkKGlucHV0QmFja2dyb3VuZENvbG9yKTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbmFwcC1zZXR0aW5ncyB7XHJcblxyXG4gIC5jb250ZW50IHtcclxuXHJcbiAgICAudGhlbWUtc2VsZWN0aW9uIHtcclxuXHJcbiAgICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICAgIGNvbG9yOiB0aGVtZWQob3B0aW9uYWxUZXh0Q29sb3IpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcblxyXG5hcHAtbG9naW4ge1xyXG4gIG1pbi13aWR0aDogaW5oZXJpdDtcclxufVxyXG5cclxuLnN3aXRjaCB7XHJcblxyXG4gIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgYmFja2dyb3VuZC1jb2xvcjogdGhlbWVkKHN3aXRjaEJhY2tncm91bmRDb2xvcik7XHJcbiAgfVxyXG5cclxuICAuY2lyY2xlIHtcclxuXHJcbiAgICAmLm9uIHtcclxuXHJcbiAgICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICAgIGJhY2tncm91bmQtY29sb3I6IHRoZW1lZChibHVlVGV4dENvbG9yKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgICYub2ZmIHtcclxuXHJcbiAgICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICAgIGJhY2tncm91bmQtY29sb3I6IHRoZW1lZChvcHRpb25hbFRleHRDb2xvcik7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbn1cclxuIiwiYXBwLXNpZGViYXIge1xyXG5cclxuICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgIGJhY2tncm91bmQtY29sb3I6IHRoZW1lZChzaWRlYmFyQmFja2dyb3VuZENvbG9yKTtcclxuICB9XHJcblxyXG4gIC5zaWRlYmFyLWFjY291bnRzIHtcclxuXHJcbiAgICAuc2lkZWJhci1hY2NvdW50cy1oZWFkZXIge1xyXG5cclxuICAgICAgaDMge1xyXG5cclxuICAgICAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgICAgIGNvbG9yOiB0aGVtZWQobWFpblRleHRDb2xvcik7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBidXR0b24ge1xyXG5cclxuICAgICAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgICAgIGNvbG9yOiB0aGVtZWQoYmx1ZVRleHRDb2xvcik7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLnNpZGViYXItYWNjb3VudHMtbGlzdCB7XHJcblxyXG4gICAgICAuc2lkZWJhci1hY2NvdW50IHtcclxuXHJcbiAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0cmFuc3BhcmVudDtcclxuICAgICAgICAgIGNvbG9yOiB0aGVtZWQobWFpblRleHRDb2xvcik7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAuc2lkZWJhci1hY2NvdW50LXJvdyB7XHJcblxyXG4gICAgICAgICAgLnRleHQge1xyXG5cclxuICAgICAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICAgICAgY29sb3I6IHRoZW1lZChvcHRpb25hbFRleHRDb2xvcik7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAuaW5kaWNhdG9yIHtcclxuXHJcbiAgICAgICAgICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IHRoZW1lZChibHVlQnV0dG9uQmFja2dyb3VuZENvbG9yKTtcclxuICAgICAgICAgICAgICBjb2xvcjogdGhlbWVkKGFsdGVybmF0aXZlVGV4dENvbG9yKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIC5wcm9ncmVzcy1iYXItY29udGFpbmVyIHtcclxuXHJcbiAgICAgICAgICAgIC5wcm9ncmVzcy1iYXIge1xyXG5cclxuICAgICAgICAgICAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IHRoZW1lZChwcm9ncmVzc0JhckJhY2tncm91bmRDb2xvcik7XHJcbiAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAuZmlsbCB7XHJcblxyXG4gICAgICAgICAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IHRoZW1lZChwcm9ncmVzc0JhckZ1bGxCYWNrZ3JvdW5kQ29sb3IpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICYuYWNjb3VudC1zeW5jaHJvbml6YXRpb24ge1xyXG5cclxuICAgICAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICAgICAgY29sb3I6IHRoZW1lZChvcHRpb25hbFRleHRDb2xvcik7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgICYuYWN0aXZlIHtcclxuXHJcbiAgICAgICAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogdGhlbWVkKGFjY291bnRCYWNrZ3JvdW5kQ29sb3IpO1xyXG4gICAgICAgICAgICBjb2xvcjogdGhlbWVkKGFjY291bnRNYWluVGV4dENvbG9yKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAuc2lkZWJhci1hY2NvdW50LXJvdyB7XHJcblxyXG4gICAgICAgICAgICAudGV4dCB7XHJcblxyXG4gICAgICAgICAgICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICAgICAgICAgICAgY29sb3I6IHRoZW1lZChhY2NvdW50T3B0aW9uYWxUZXh0Q29sb3IpO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLmluZGljYXRvciB7XHJcblxyXG4gICAgICAgICAgICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICAgICAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogdGhlbWVkKGFjY291bnRJbmRpY2F0b3JCYWNrZ3JvdW5kQ29sb3IpO1xyXG4gICAgICAgICAgICAgICAgY29sb3I6IHRoZW1lZChhY2NvdW50SW5kaWNhdG9yVGV4dENvbG9yKTtcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC5zd2l0Y2gge1xyXG5cclxuICAgICAgICAgICAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IHRoZW1lZChhY2NvdW50U3dpdGNoQmFja2dyb3VuZENvbG9yKTtcclxuICAgICAgICAgICAgICAgIGNvbG9yOiB0aGVtZWQobWFpblRleHRDb2xvcik7XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAmLmFjY291bnQtc3luY2hyb25pemF0aW9uIHtcclxuXHJcbiAgICAgICAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICAgICAgICBjb2xvcjogdGhlbWVkKGFjY291bnRPcHRpb25hbFRleHRDb2xvcik7XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAmOmhvdmVyOm5vdCguYWN0aXZlKSB7XHJcblxyXG4gICAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IHRoZW1lZChhY2NvdW50SG92ZXJCYWNrZ3JvdW5kQ29sb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLnNpZGViYXItc2V0dGluZ3Mge1xyXG5cclxuICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICBib3JkZXItYm90dG9tOiAwLjJyZW0gc29saWQgdGhlbWVkKHNpZGViYXJCb3JkZXJDb2xvcik7XHJcbiAgICB9XHJcblxyXG4gICAgYnV0dG9uIHtcclxuXHJcbiAgICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICAgIGNvbG9yOiB0aGVtZWQobWFpblRleHRDb2xvcik7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC5pY29uIHtcclxuXHJcbiAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0aGVtZWQoYmx1ZVRleHRDb2xvcik7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAuc2lkZWJhci1zeW5jaHJvbml6YXRpb24tc3RhdHVzIHtcclxuXHJcbiAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgY29sb3I6IHRoZW1lZChvcHRpb25hbFRleHRDb2xvcik7XHJcbiAgICB9XHJcblxyXG4gICAgLnN0YXR1cy1jb250YWluZXIge1xyXG5cclxuICAgICAgLm9mZmxpbmU6YmVmb3JlIHtcclxuXHJcbiAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0aGVtZWQob2ZmbGluZUNvbG9yKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC5vbmxpbmU6YmVmb3JlIHtcclxuXHJcbiAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0aGVtZWQob25saW5lQ29sb3IpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC5wcm9ncmVzcy1iYXItY29udGFpbmVyIHtcclxuXHJcbiAgICAgIC5zeW5jaW5nIHtcclxuXHJcbiAgICAgICAgLnByb2dyZXNzLWJhciB7XHJcblxyXG4gICAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IHRoZW1lZChwcm9ncmVzc0JhckJhY2tncm91bmRDb2xvcik7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgLmZpbGwge1xyXG5cclxuICAgICAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogdGhlbWVkKHByb2dyZXNzQmFyRnVsbEJhY2tncm91bmRDb2xvcik7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC5sb2FkaW5nIHtcclxuXHJcbiAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0aGVtZWQocHJvZ3Jlc3NCYXJGdWxsQmFja2dyb3VuZENvbG9yKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbn1cclxuIiwiYXBwLXdhbGxldCB7XHJcblxyXG4gIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgY29sb3I6IHRoZW1lZChtYWluVGV4dENvbG9yKTtcclxuICB9XHJcblxyXG4gIC5oZWFkZXIge1xyXG5cclxuICAgIGJ1dHRvbiB7XHJcblxyXG4gICAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgICBjb2xvcjogdGhlbWVkKG1haW5UZXh0Q29sb3IpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAuaWNvbiB7XHJcblxyXG4gICAgICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogdGhlbWVkKGJsdWVUZXh0Q29sb3IpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLmFkZHJlc3Mge1xyXG5cclxuICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICBjb2xvcjogdGhlbWVkKGJsdWVUZXh0Q29sb3IpO1xyXG4gICAgfVxyXG5cclxuICAgIC5pY29uIHtcclxuXHJcbiAgICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICAgIGJhY2tncm91bmQtY29sb3I6IHRoZW1lZChibHVlVGV4dENvbG9yKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLnRhYnMge1xyXG5cclxuICAgIC50YWJzLWhlYWRlciB7XHJcblxyXG4gICAgICAudGFiIHtcclxuXHJcbiAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0aGVtZWQodGFiSW5hY3RpdmVCYWNrZ3JvdW5kQ29sb3IpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLmljb24ge1xyXG5cclxuICAgICAgICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0aGVtZWQoYmx1ZVRleHRDb2xvcik7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAuaW5kaWNhdG9yIHtcclxuXHJcbiAgICAgICAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogdGhlbWVkKGFjY291bnRJbmRpY2F0b3JCYWNrZ3JvdW5kQ29sb3IpO1xyXG4gICAgICAgICAgICBjb2xvcjogdGhlbWVkKGFjY291bnRJbmRpY2F0b3JUZXh0Q29sb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgJi5hY3RpdmUge1xyXG5cclxuICAgICAgICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0aGVtZWQoY29udGVudEJhY2tncm91bmRDb2xvcik7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLnRhYnMtY29udGVudCB7XHJcblxyXG4gICAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0aGVtZWQoY29udGVudEJhY2tncm91bmRDb2xvcik7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbmFwcC1zZW5kIHtcclxuXHJcbiAgLmZvcm0tc2VuZCB7XHJcblxyXG4gICAgLnNlbmQtc2VsZWN0IHtcclxuXHJcbiAgICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICAgIGNvbG9yOiB0aGVtZWQobWFpblRleHRDb2xvcik7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC5pY29uIHtcclxuXHJcbiAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0aGVtZWQoYmx1ZVRleHRDb2xvcik7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLmFkZGl0aW9uYWwtZGV0YWlscyB7XHJcblxyXG4gICAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgICBib3JkZXI6IDAuMnJlbSBzb2xpZCB0aGVtZWQodHJhbnNwYXJlbnRCdXR0b25Cb3JkZXJDb2xvcik7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbmFwcC1yZWNlaXZlIHtcclxuXHJcbiAgLmJ0bi1jb3B5LWFkZHJlc3Mge1xyXG5cclxuICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0aGVtZWQoYmx1ZVRleHRDb2xvcik7XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcblxyXG5hcHAtaGlzdG9yeSB7XHJcblxyXG4gIHRhYmxlIHtcclxuXHJcbiAgICB0Ym9keSB7XHJcblxyXG4gICAgICB0ciB7XHJcblxyXG4gICAgICAgIC5zdGF0dXMge1xyXG5cclxuICAgICAgICAgIC5jb25maXJtYXRpb24ge1xyXG5cclxuICAgICAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogdGhlbWVkKHByb2dyZXNzQmFyQmFja2dyb3VuZENvbG9yKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLmZpbGwge1xyXG5cclxuICAgICAgICAgICAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IHRoZW1lZChwcm9ncmVzc0JhckZ1bGxCYWNrZ3JvdW5kQ29sb3IpO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLnN0YXR1cy5zZW5kICB7XHJcblxyXG4gICAgICAgICAgLmljb24ge1xyXG4gICAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjZmY1MjUyO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLnN0YXR1cy5yZWNlaXZlZCB7XHJcblxyXG4gICAgICAgICAgLmljb24ge1xyXG4gICAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjMDBjODUzO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuYXBwLWNvbnRyYWN0cyB7XHJcblxyXG4gIC53cmFwLXRhYmxlIHtcclxuXHJcbiAgICAuY29udHJhY3Qge1xyXG5cclxuICAgICAgLmljb24ge1xyXG5cclxuICAgICAgICAmLm5ldywgJi5hbGVydCB7XHJcblxyXG4gICAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IHRoZW1lZChyZWRUZXh0Q29sb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgJi5wdXJjaGFzZSwgJi5zZWxsIHtcclxuXHJcbiAgICAgICAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogdGhlbWVkKGJsdWVUZXh0Q29sb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuYXBwLXB1cmNoYXNlIHtcclxuXHJcbiAgLmZvcm0tcHVyY2hhc2Uge1xyXG5cclxuICAgIC5wdXJjaGFzZS1zZWxlY3Qge1xyXG5cclxuICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgY29sb3I6IHRoZW1lZChtYWluVGV4dENvbG9yKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLmljb24ge1xyXG5cclxuICAgICAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IHRoZW1lZChibHVlVGV4dENvbG9yKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAucHVyY2hhc2Utc3RhdGVzIHtcclxuXHJcbiAgICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICAgIGNvbG9yOiB0aGVtZWQoYmx1ZVRleHRDb2xvcik7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAuYWRkaXRpb25hbC1kZXRhaWxzIHtcclxuXHJcbiAgICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICAgIGJvcmRlcjogMC4ycmVtIHNvbGlkIHRoZW1lZCh0cmFuc3BhcmVudEJ1dHRvbkJvcmRlckNvbG9yKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLnByb2dyZXNzLWJhci1jb250YWluZXIge1xyXG5cclxuICAgIC5wcm9ncmVzcy1iYXIge1xyXG5cclxuICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogdGhlbWVkKHByb2dyZXNzQmFyQmFja2dyb3VuZENvbG9yKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLnByb2dyZXNzLWJhci1mdWxsIHtcclxuXHJcbiAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0aGVtZWQocHJvZ3Jlc3NCYXJGdWxsQmFja2dyb3VuZENvbG9yKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbmFwcC1tZXNzYWdlcyB7XHJcblxyXG4gIHRhYmxlIHtcclxuXHJcbiAgICB0Ym9keSB7XHJcblxyXG4gICAgICB0ciB7XHJcblxyXG4gICAgICAgIHRkOmZpcnN0LWNoaWxkIHtcclxuXHJcbiAgICAgICAgICBzcGFuIHtcclxuICAgICAgICAgICAgQGluY2x1ZGUgdGV4dC10cnVuY2F0ZTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAuaWNvbiB7XHJcblxyXG4gICAgICAgICAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0aGVtZWQocmVkVGV4dENvbG9yKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuYXBwLXR5cGluZy1tZXNzYWdlIHtcclxuXHJcbiAgLmhlYWQge1xyXG5cclxuICAgIC5pbnRlcmxvY3V0b3Ige1xyXG5cclxuICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgY29sb3I6IHRoZW1lZChibHVlVGV4dENvbG9yKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLm1lc3NhZ2VzLWNvbnRlbnQge1xyXG5cclxuICAgIC5tZXNzYWdlcy1saXN0IHtcclxuXHJcbiAgICAgIGRpdiB7XHJcblxyXG4gICAgICAgICYuZGF0ZSB7XHJcblxyXG4gICAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICAgIGNvbG9yOiB0aGVtZWQob3B0aW9uYWxUZXh0Q29sb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgJi5teSB7XHJcblxyXG4gICAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IHRoZW1lZChtZXNzYWdlTXlCYWNrZ3JvdW5kQ29sb3IpO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICY6YmVmb3JlIHtcclxuXHJcbiAgICAgICAgICAgIEBpbmNsdWRlIHBzZXVkbztcclxuICAgICAgICAgICAgdG9wOiAwO1xyXG4gICAgICAgICAgICBsZWZ0OiAtMS4xcmVtO1xyXG4gICAgICAgICAgICBib3JkZXI6IDEuMnJlbSBzb2xpZCB0cmFuc3BhcmVudDtcclxuXHJcbiAgICAgICAgICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICAgICAgICAgIGJvcmRlci10b3AtY29sb3I6IHRoZW1lZChtZXNzYWdlTXlCYWNrZ3JvdW5kQ29sb3IpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAmLmJ1ZGR5IHtcclxuXHJcbiAgICAgICAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogdGhlbWVkKG1lc3NhZ2VCdWRkeUJhY2tncm91bmRDb2xvcik7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgJjphZnRlciB7XHJcblxyXG4gICAgICAgICAgICBAaW5jbHVkZSBwc2V1ZG87XHJcbiAgICAgICAgICAgIHJpZ2h0OiAtMS4xcmVtO1xyXG4gICAgICAgICAgICB0b3A6IDA7XHJcbiAgICAgICAgICAgIGJvcmRlcjogMS4ycmVtIHNvbGlkIHRyYW5zcGFyZW50O1xyXG5cclxuICAgICAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICAgICAgYm9yZGVyLXRvcC1jb2xvcjogdGhlbWVkKG1lc3NhZ2VCdWRkeUJhY2tncm91bmRDb2xvcik7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbmFwcC1zdGFraW5nIHtcclxuXHJcbiAgLmNoYXJ0LWhlYWRlciB7XHJcblxyXG4gICAgLmdlbmVyYWwge1xyXG5cclxuICAgICAgLmxhYmVsIHtcclxuXHJcbiAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICBjb2xvcjogdGhlbWVkKG9wdGlvbmFsVGV4dENvbG9yKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC5vcHRpb25zIHtcclxuXHJcbiAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICBjb2xvcjogdGhlbWVkKG1haW5UZXh0Q29sb3IpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC5zZWxlY3RlZCB7XHJcbiAgICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAgICAgIGp1c3RpZnktY29udGVudDogZmxleC1lbmQ7XHJcbiAgICAgIGZsZXgtZ3JvdzogMTtcclxuICAgICAgZm9udC1zaXplOiAxLjZyZW07XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAuY2hhcnQtb3B0aW9ucyB7XHJcblxyXG4gICAgLnRpdGxlIHtcclxuXHJcbiAgICAgIEBpbmNsdWRlIHRoZW1pZnkoJHRoZW1lcykge1xyXG4gICAgICAgIGNvbG9yOiB0aGVtZWQob3B0aW9uYWxUZXh0Q29sb3IpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLm9wdGlvbnMge1xyXG5cclxuICAgICAgYnV0dG9uIHtcclxuXHJcbiAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICBjb2xvcjogdGhlbWVkKG1haW5UZXh0Q29sb3IpO1xyXG4gICAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogdGhlbWVkKGNoYXJ0T3B0aW9uc0JhY2tncm91bmRDb2xvcik7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAmLmFjdGl2ZSB7XHJcblxyXG4gICAgICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IHRoZW1lZChjaGFydE9wdGlvbnNIb3ZlckNvbG9yKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbn1cclxuIiwiLmhlYWQge1xyXG4gIGRpc3BsYXk6IGZsZXg7XHJcbiAgYWxpZ24taXRlbXM6IGZsZXgtZW5kO1xyXG4gIGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjtcclxuICBmb250LXNpemU6IDEuM3JlbTtcclxuICBwYWRkaW5nOiAwIDNyZW07XHJcbiAgd2lkdGg6IDEwMCU7XHJcbiAgaGVpZ2h0OiAzcmVtO1xyXG5cclxuICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgIGNvbG9yOiB0aGVtZWQoYmx1ZVRleHRDb2xvcik7XHJcbiAgfVxyXG5cclxuICAuYnJlYWRjcnVtYnMge1xyXG5cclxuICAgID4gc3BhbiwgYSB7XHJcblxyXG4gICAgICAmOm5vdCg6bGFzdC1jaGlsZCkge1xyXG4gICAgICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcclxuICAgICAgICBtYXJnaW4tcmlnaHQ6IDIwcHg7XHJcblxyXG4gICAgICAgICY6YWZ0ZXIge1xyXG5cclxuICAgICAgICAgIEBpbmNsdWRlIHBzZXVkbztcclxuICAgICAgICAgIHRvcDogMC41cmVtO1xyXG4gICAgICAgICAgcmlnaHQ6IC0xLjVyZW07XHJcbiAgICAgICAgICB3aWR0aDogMC45cmVtO1xyXG4gICAgICAgICAgaGVpZ2h0OiAwLjlyZW07XHJcbiAgICAgICAgICBtYXNrOiB1cmwofnNyYy9hc3NldHMvaWNvbnMvYXJyb3ctcmlnaHQuc3ZnKSBuby1yZXBlYXQgY2VudGVyO1xyXG4gICAgICAgICAgbWFzay1zaXplOiBjb3ZlcjtcclxuXHJcbiAgICAgICAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogdGhlbWVkKGJsdWVUZXh0Q29sb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLmJhY2stYnRuIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAgYmFja2dyb3VuZC1jb2xvcjogdHJhbnNwYXJlbnQ7XHJcbiAgICBjb2xvcjogIzRkYjFmZjtcclxuICAgIGZvbnQtc2l6ZTogaW5oZXJpdDtcclxuICAgIGZvbnQtd2VpZ2h0OiA0MDA7XHJcbiAgICBsaW5lLWhlaWdodDogMS4zcmVtO1xyXG4gICAgcGFkZGluZzogMDtcclxuICAgIGhlaWdodDogYXV0bztcclxuXHJcbiAgICAuaWNvbiB7XHJcbiAgICAgIG1hcmdpbi1yaWdodDogMC43cmVtO1xyXG4gICAgICBtYXNrOiB1cmwofnNyYy9hc3NldHMvaWNvbnMvYmFjay5zdmcpIG5vLXJlcGVhdCBjZW50ZXI7XHJcbiAgICAgIHdpZHRoOiAwLjlyZW07XHJcbiAgICAgIGhlaWdodDogMC45cmVtO1xyXG5cclxuICAgICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogdGhlbWVkKGJsdWVUZXh0Q29sb3IpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcbiIsIi5zY3JvbGxlZC1jb250ZW50IHtcclxuXHJcbiAgJjo6LXdlYmtpdC1zY3JvbGxiYXIge1xyXG4gICAgYmFja2dyb3VuZC1jb2xvcjogdHJhbnNwYXJlbnQ7XHJcbiAgICBjdXJzb3I6IGRlZmF1bHQ7XHJcbiAgICB3aWR0aDogMXJlbTtcclxuICAgIGhlaWdodDogMXJlbTtcclxuICB9XHJcblxyXG4gICY6Oi13ZWJraXQtc2Nyb2xsYmFyLXRyYWNrIHtcclxuICAgIGJhY2tncm91bmQ6IHRyYW5zcGFyZW50O1xyXG4gIH1cclxuXHJcbiAgJjo6LXdlYmtpdC1zY3JvbGxiYXItdGh1bWIge1xyXG4gICAgYmFja2dyb3VuZC1jb2xvcjogIzU1NjU3NjtcclxuICAgIGJhY2tncm91bmQtY2xpcDogcGFkZGluZy1ib3g7XHJcbiAgICBib3JkZXI6IDAuMjVyZW0gc29saWQgdHJhbnNwYXJlbnQ7XHJcbiAgICBib3JkZXItcmFkaXVzOiAwLjVyZW07XHJcbiAgfVxyXG5cclxuICAmOjotd2Via2l0LXNjcm9sbGJhci10aHVtYjpob3ZlciB7XHJcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjNTU2NTc2O1xyXG4gIH1cclxufVxyXG4iLCJ0YWJsZSB7XHJcbiAgZm9udC1zaXplOiAxLjNyZW07XHJcbiAgd2lkdGg6IDEwMCU7XHJcblxyXG4gIHRoZWFkIHtcclxuICAgIHRleHQtYWxpZ246IGxlZnQ7XHJcblxyXG4gICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgIGNvbG9yOiB0aGVtZWQob3B0aW9uYWxUZXh0Q29sb3IpO1xyXG4gICAgfVxyXG5cclxuICAgIHRyIHtcclxuICAgICAgaGVpZ2h0OiA0cmVtO1xyXG5cclxuICAgICAgdGgge1xyXG4gICAgICAgIHBhZGRpbmc6IDFyZW07XHJcbiAgICAgICAgdmVydGljYWwtYWxpZ246IGJvdHRvbTtcclxuXHJcbiAgICAgICAgJjpmaXJzdC1jaGlsZCB7XHJcbiAgICAgICAgICBwYWRkaW5nLWxlZnQ6IDNyZW07XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAmOmxhc3QtY2hpbGQge1xyXG4gICAgICAgICAgcGFkZGluZy1yaWdodDogM3JlbTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIHRib2R5IHtcclxuICAgIHRleHQtYWxpZ246IGxlZnQ7XHJcblxyXG4gICAgQGluY2x1ZGUgdGhlbWlmeSgkdGhlbWVzKSB7XHJcbiAgICAgIGNvbG9yOiB0aGVtZWQobWFpblRleHRDb2xvcik7XHJcbiAgICB9XHJcblxyXG4gICAgdHIge1xyXG4gICAgICBoZWlnaHQ6IDMuNXJlbTtcclxuXHJcbiAgICAgICY6bnRoLWNoaWxkKG9kZCkge1xyXG5cclxuICAgICAgICBAaW5jbHVkZSB0aGVtaWZ5KCR0aGVtZXMpIHtcclxuICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IHRoZW1lZCh0YWJsZUJhY2tncm91bmRDb2xvcik7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICB0ZCB7XHJcbiAgICAgICAgbGluZS1oZWlnaHQ6IDEuN3JlbTtcclxuICAgICAgICBwYWRkaW5nOiAwIDFyZW07XHJcbiAgICAgICAgdmVydGljYWwtYWxpZ246IG1pZGRsZTtcclxuICAgICAgICB3aGl0ZS1zcGFjZTogbm93cmFwO1xyXG5cclxuICAgICAgICAmOmZpcnN0LWNoaWxkIHtcclxuICAgICAgICAgIHBhZGRpbmctbGVmdDogM3JlbTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgICY6bGFzdC1jaGlsZCB7XHJcbiAgICAgICAgICBwYWRkaW5nLXJpZ2h0OiAzcmVtO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxufVxyXG4iLCIvLyBCQVNFXHJcbkBpbXBvcnQgJ2Fzc2V0cy9zY3NzL2Jhc2UvbWl4aW5zJztcclxuQGltcG9ydCAnYXNzZXRzL3Njc3MvYmFzZS9udWxsJztcclxuQGltcG9ydCAnYXNzZXRzL3Njc3MvYmFzZS90aGVtZSc7XHJcbkBpbXBvcnQgJ2Fzc2V0cy9zY3NzL2Jhc2UvYmFzZSc7XHJcblxyXG4vLyBMQVlPVVRcclxuQGltcG9ydCAnYXNzZXRzL3Njc3MvbGF5b3V0L21haW4nO1xyXG5AaW1wb3J0ICdhc3NldHMvc2Nzcy9sYXlvdXQvc2V0dGluZ3MnO1xyXG5AaW1wb3J0ICdhc3NldHMvc2Nzcy9sYXlvdXQvc2lkZWJhcic7XHJcbkBpbXBvcnQgJ2Fzc2V0cy9zY3NzL2xheW91dC93YWxsZXQnO1xyXG5cclxuLy8gTU9EVUxFU1xyXG5AaW1wb3J0ICdhc3NldHMvc2Nzcy9tb2R1bGVzL2hlYWQnO1xyXG5AaW1wb3J0ICdhc3NldHMvc2Nzcy9tb2R1bGVzL3Njcm9sbCc7XHJcbkBpbXBvcnQgJ2Fzc2V0cy9zY3NzL21vZHVsZXMvdGFibGUnO1xyXG5cclxuXHJcbmh0bWwge1xyXG4gIGZvbnQtZmFtaWx5OiAnT3BlbiBTYW5zJywgc2Fucy1zZXJpZjtcclxuICBmb250LXNpemU6IDEwcHg7XHJcbn1cclxuXHJcbmJvZHkge1xyXG4gIGZvbnQtZmFtaWx5OiAnT3BlbiBTYW5zJywgc2Fucy1zZXJpZjtcclxuICBmb250LXNpemU6IDEuNnJlbTtcclxuICB3aWR0aDogMTAwdnc7XHJcbiAgaGVpZ2h0OiAxMDB2aDtcclxuXHJcbiAgJi50aGVtZS1kYXJrIHtcclxuICAgIGJhY2tncm91bmQ6ICMxMzE5MjEgdXJsKFwiYXNzZXRzL2ltYWdlcy9iYWNrZ3JvdW5kLWRhcmsucG5nXCIpIG5vLXJlcGVhdCBjZW50ZXI7XHJcbiAgICBiYWNrZ3JvdW5kLXNpemU6IGNvdmVyO1xyXG4gIH1cclxuXHJcbiAgJi50aGVtZS1ncmF5IHtcclxuICAgIGJhY2tncm91bmQ6ICMxMDE0MTcgdXJsKFwiYXNzZXRzL2ltYWdlcy9iYWNrZ3JvdW5kLWdyYXkucG5nXCIpIG5vLXJlcGVhdCBjZW50ZXI7XHJcbiAgICBiYWNrZ3JvdW5kLXNpemU6IGNvdmVyO1xyXG4gIH1cclxuXHJcbiAgJi50aGVtZS13aGl0ZSB7XHJcbiAgICBiYWNrZ3JvdW5kOiAjZWVlZWVlIHVybChcImFzc2V0cy9pbWFnZXMvYmFja2dyb3VuZC13aGl0ZS5wbmdcIikgbm8tcmVwZWF0IGNlbnRlcjtcclxuICAgIGJhY2tncm91bmQtc2l6ZTogY292ZXI7XHJcbiAgfVxyXG5cclxuICBhcHAtcm9vdCB7XHJcbiAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgd2lkdGg6IDEwMCU7XHJcbiAgICBoZWlnaHQ6IDEwMCU7XHJcbiAgfVxyXG59XHJcblxyXG5cclxuXHJcblxyXG4ubmd4LWNvbnRleHRtZW51IC5kcm9wZG93bi1tZW51IHtcclxuICBib3JkZXI6IHNvbGlkIDFweCBjaGFydHJldXNlO1xyXG4gIGJhY2tncm91bmQtY29sb3I6IGRhcmtncmVlbjtcclxuICBwYWRkaW5nOiAwO1xyXG59XHJcbi5uZ3gtY29udGV4dG1lbnUgbGkge1xyXG4gIGRpc3BsYXk6IGJsb2NrO1xyXG4gIGJvcmRlci10b3A6IHNvbGlkIDFweCBjaGFydHJldXNlO1xyXG4gIHRleHQtdHJhbnNmb3JtOiB1cHBlcmNhc2U7XHJcbiAgdGV4dC1hbGlnbjogY2VudGVyO1xyXG59XHJcbi5uZ3gtY29udGV4dG1lbnUgbGk6Zmlyc3QtY2hpbGQge1xyXG4gIGJvcmRlci10b3A6bm9uZTtcclxufVxyXG4ubmd4LWNvbnRleHRtZW51IGEge1xyXG4gIGNvbG9yOmNoYXJ0cmV1c2U7XHJcbiAgZGlzcGxheTogYmxvY2s7XHJcbiAgcGFkZGluZzogMC41ZW0gMWVtO1xyXG59XHJcbi5uZ3gtY29udGV4dG1lbnUgYTpob3ZlciB7XHJcbiAgY29sb3I6ZGFya2dyZWVuO1xyXG4gIGJhY2tncm91bmQtY29sb3I6Y2hhcnRyZXVzZTtcclxufVxyXG4iXX0= */", '', '']] + +/***/ }), + +/***/ "./node_modules/style-loader/lib/addStyles.js": +/*!****************************************************!*\ + !*** ./node_modules/style-loader/lib/addStyles.js ***! + \****************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +var stylesInDom = {}; + +var memoize = function (fn) { + var memo; + + return function () { + if (typeof memo === "undefined") memo = fn.apply(this, arguments); + return memo; + }; +}; + +var isOldIE = memoize(function () { + // Test for IE <= 9 as proposed by Browserhacks + // @see http://browserhacks.com/#hack-e71d8692f65334173fee715c222cb805 + // Tests for existence of standard globals is to allow style-loader + // to operate correctly into non-standard environments + // @see https://github.com/webpack-contrib/style-loader/issues/177 + return window && document && document.all && !window.atob; +}); + +var getTarget = function (target, parent) { + if (parent){ + return parent.querySelector(target); + } + return document.querySelector(target); +}; + +var getElement = (function (fn) { + var memo = {}; + + return function(target, parent) { + // If passing function in options, then use it for resolve "head" element. + // Useful for Shadow Root style i.e + // { + // insertInto: function () { return document.querySelector("#foo").shadowRoot } + // } + if (typeof target === 'function') { + return target(); + } + if (typeof memo[target] === "undefined") { + var styleTarget = getTarget.call(this, target, parent); + // Special case to return head of iframe instead of iframe itself + if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) { + try { + // This will throw an exception if access to iframe is blocked + // due to cross-origin restrictions + styleTarget = styleTarget.contentDocument.head; + } catch(e) { + styleTarget = null; + } + } + memo[target] = styleTarget; + } + return memo[target] + }; +})(); + +var singleton = null; +var singletonCounter = 0; +var stylesInsertedAtTop = []; + +var fixUrls = __webpack_require__(/*! ./urls */ "./node_modules/style-loader/lib/urls.js"); + +module.exports = function(list, options) { + if (typeof DEBUG !== "undefined" && DEBUG) { + if (typeof document !== "object") throw new Error("The style-loader cannot be used in a non-browser environment"); + } + + options = options || {}; + + options.attrs = typeof options.attrs === "object" ? options.attrs : {}; + + // Force single-tag solution on IE6-9, which has a hard limit on the # of + + + could become: + + +
+ +
+ + Note the use of @polyfill in the comment above a ShadowDOM specific style + declaration. This is a directive to the styling shim to use the selector + in comments in lieu of the next selector when running under polyfill. +*/ +var ShadowCss = /** @class */ (function () { + function ShadowCss() { + this.strictStyling = true; + } + /* + * Shim some cssText with the given selector. Returns cssText that can + * be included in the document via WebComponents.ShadowCSS.addCssToDocument(css). + * + * When strictStyling is true: + * - selector is the attribute added to all elements inside the host, + * - hostSelector is the attribute added to the host itself. + */ + ShadowCss.prototype.shimCssText = function (cssText, selector, hostSelector) { + if (hostSelector === void 0) { hostSelector = ''; } + var commentsWithHash = extractCommentsWithHash(cssText); + cssText = stripComments(cssText); + cssText = this._insertDirectives(cssText); + var scopedCssText = this._scopeCssText(cssText, selector, hostSelector); + return Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__spread"])([scopedCssText], commentsWithHash).join('\n'); + }; + ShadowCss.prototype._insertDirectives = function (cssText) { + cssText = this._insertPolyfillDirectivesInCssText(cssText); + return this._insertPolyfillRulesInCssText(cssText); + }; + /* + * Process styles to convert native ShadowDOM rules that will trip + * up the css parser; we rely on decorating the stylesheet with inert rules. + * + * For example, we convert this rule: + * + * polyfill-next-selector { content: ':host menu-item'; } + * ::content menu-item { + * + * to this: + * + * scopeName menu-item { + * + **/ + ShadowCss.prototype._insertPolyfillDirectivesInCssText = function (cssText) { + // Difference with webcomponents.js: does not handle comments + return cssText.replace(_cssContentNextSelectorRe, function () { + var m = []; + for (var _i = 0; _i < arguments.length; _i++) { + m[_i] = arguments[_i]; + } + return m[2] + '{'; + }); + }; + /* + * Process styles to add rules which will only apply under the polyfill + * + * For example, we convert this rule: + * + * polyfill-rule { + * content: ':host menu-item'; + * ... + * } + * + * to this: + * + * scopeName menu-item {...} + * + **/ + ShadowCss.prototype._insertPolyfillRulesInCssText = function (cssText) { + // Difference with webcomponents.js: does not handle comments + return cssText.replace(_cssContentRuleRe, function () { + var m = []; + for (var _i = 0; _i < arguments.length; _i++) { + m[_i] = arguments[_i]; + } + var rule = m[0].replace(m[1], '').replace(m[2], ''); + return m[4] + rule; + }); + }; + /* Ensure styles are scoped. Pseudo-scoping takes a rule like: + * + * .foo {... } + * + * and converts this to + * + * scopeName .foo { ... } + */ + ShadowCss.prototype._scopeCssText = function (cssText, scopeSelector, hostSelector) { + var unscopedRules = this._extractUnscopedRulesFromCssText(cssText); + // replace :host and :host-context -shadowcsshost and -shadowcsshost respectively + cssText = this._insertPolyfillHostInCssText(cssText); + cssText = this._convertColonHost(cssText); + cssText = this._convertColonHostContext(cssText); + cssText = this._convertShadowDOMSelectors(cssText); + if (scopeSelector) { + cssText = this._scopeSelectors(cssText, scopeSelector, hostSelector); + } + cssText = cssText + '\n' + unscopedRules; + return cssText.trim(); + }; + /* + * Process styles to add rules which will only apply under the polyfill + * and do not process via CSSOM. (CSSOM is destructive to rules on rare + * occasions, e.g. -webkit-calc on Safari.) + * For example, we convert this rule: + * + * @polyfill-unscoped-rule { + * content: 'menu-item'; + * ... } + * + * to this: + * + * menu-item {...} + * + **/ + ShadowCss.prototype._extractUnscopedRulesFromCssText = function (cssText) { + // Difference with webcomponents.js: does not handle comments + var r = ''; + var m; + _cssContentUnscopedRuleRe.lastIndex = 0; + while ((m = _cssContentUnscopedRuleRe.exec(cssText)) !== null) { + var rule = m[0].replace(m[2], '').replace(m[1], m[4]); + r += rule + '\n\n'; + } + return r; + }; + /* + * convert a rule like :host(.foo) > .bar { } + * + * to + * + * .foo > .bar + */ + ShadowCss.prototype._convertColonHost = function (cssText) { + return this._convertColonRule(cssText, _cssColonHostRe, this._colonHostPartReplacer); + }; + /* + * convert a rule like :host-context(.foo) > .bar { } + * + * to + * + * .foo > .bar, .foo scopeName > .bar { } + * + * and + * + * :host-context(.foo:host) .bar { ... } + * + * to + * + * .foo .bar { ... } + */ + ShadowCss.prototype._convertColonHostContext = function (cssText) { + return this._convertColonRule(cssText, _cssColonHostContextRe, this._colonHostContextPartReplacer); + }; + ShadowCss.prototype._convertColonRule = function (cssText, regExp, partReplacer) { + // m[1] = :host(-context), m[2] = contents of (), m[3] rest of rule + return cssText.replace(regExp, function () { + var m = []; + for (var _i = 0; _i < arguments.length; _i++) { + m[_i] = arguments[_i]; + } + if (m[2]) { + var parts = m[2].split(','); + var r = []; + for (var i = 0; i < parts.length; i++) { + var p = parts[i].trim(); + if (!p) + break; + r.push(partReplacer(_polyfillHostNoCombinator, p, m[3])); + } + return r.join(','); + } + else { + return _polyfillHostNoCombinator + m[3]; + } + }); + }; + ShadowCss.prototype._colonHostContextPartReplacer = function (host, part, suffix) { + if (part.indexOf(_polyfillHost) > -1) { + return this._colonHostPartReplacer(host, part, suffix); + } + else { + return host + part + suffix + ', ' + part + ' ' + host + suffix; + } + }; + ShadowCss.prototype._colonHostPartReplacer = function (host, part, suffix) { + return host + part.replace(_polyfillHost, '') + suffix; + }; + /* + * Convert combinators like ::shadow and pseudo-elements like ::content + * by replacing with space. + */ + ShadowCss.prototype._convertShadowDOMSelectors = function (cssText) { + return _shadowDOMSelectorsRe.reduce(function (result, pattern) { return result.replace(pattern, ' '); }, cssText); + }; + // change a selector like 'div' to 'name div' + ShadowCss.prototype._scopeSelectors = function (cssText, scopeSelector, hostSelector) { + var _this = this; + return processRules(cssText, function (rule) { + var selector = rule.selector; + var content = rule.content; + if (rule.selector[0] != '@') { + selector = + _this._scopeSelector(rule.selector, scopeSelector, hostSelector, _this.strictStyling); + } + else if (rule.selector.startsWith('@media') || rule.selector.startsWith('@supports') || + rule.selector.startsWith('@page') || rule.selector.startsWith('@document')) { + content = _this._scopeSelectors(rule.content, scopeSelector, hostSelector); + } + return new CssRule(selector, content); + }); + }; + ShadowCss.prototype._scopeSelector = function (selector, scopeSelector, hostSelector, strict) { + var _this = this; + return selector.split(',') + .map(function (part) { return part.trim().split(_shadowDeepSelectors); }) + .map(function (deepParts) { + var _a = Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__read"])(deepParts), shallowPart = _a[0], otherParts = _a.slice(1); + var applyScope = function (shallowPart) { + if (_this._selectorNeedsScoping(shallowPart, scopeSelector)) { + return strict ? + _this._applyStrictSelectorScope(shallowPart, scopeSelector, hostSelector) : + _this._applySelectorScope(shallowPart, scopeSelector, hostSelector); + } + else { + return shallowPart; + } + }; + return Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__spread"])([applyScope(shallowPart)], otherParts).join(' '); + }) + .join(', '); + }; + ShadowCss.prototype._selectorNeedsScoping = function (selector, scopeSelector) { + var re = this._makeScopeMatcher(scopeSelector); + return !re.test(selector); + }; + ShadowCss.prototype._makeScopeMatcher = function (scopeSelector) { + var lre = /\[/g; + var rre = /\]/g; + scopeSelector = scopeSelector.replace(lre, '\\[').replace(rre, '\\]'); + return new RegExp('^(' + scopeSelector + ')' + _selectorReSuffix, 'm'); + }; + ShadowCss.prototype._applySelectorScope = function (selector, scopeSelector, hostSelector) { + // Difference from webcomponents.js: scopeSelector could not be an array + return this._applySimpleSelectorScope(selector, scopeSelector, hostSelector); + }; + // scope via name and [is=name] + ShadowCss.prototype._applySimpleSelectorScope = function (selector, scopeSelector, hostSelector) { + // In Android browser, the lastIndex is not reset when the regex is used in String.replace() + _polyfillHostRe.lastIndex = 0; + if (_polyfillHostRe.test(selector)) { + var replaceBy_1 = this.strictStyling ? "[" + hostSelector + "]" : scopeSelector; + return selector + .replace(_polyfillHostNoCombinatorRe, function (hnc, selector) { + return selector.replace(/([^:]*)(:*)(.*)/, function (_, before, colon, after) { + return before + replaceBy_1 + colon + after; + }); + }) + .replace(_polyfillHostRe, replaceBy_1 + ' '); + } + return scopeSelector + ' ' + selector; + }; + // return a selector with [name] suffix on each simple selector + // e.g. .foo.bar > .zot becomes .foo[name].bar[name] > .zot[name] /** @internal */ + ShadowCss.prototype._applyStrictSelectorScope = function (selector, scopeSelector, hostSelector) { + var _this = this; + var isRe = /\[is=([^\]]*)\]/g; + scopeSelector = scopeSelector.replace(isRe, function (_) { + var parts = []; + for (var _i = 1; _i < arguments.length; _i++) { + parts[_i - 1] = arguments[_i]; + } + return parts[0]; + }); + var attrName = '[' + scopeSelector + ']'; + var _scopeSelectorPart = function (p) { + var scopedP = p.trim(); + if (!scopedP) { + return ''; + } + if (p.indexOf(_polyfillHostNoCombinator) > -1) { + scopedP = _this._applySimpleSelectorScope(p, scopeSelector, hostSelector); + } + else { + // remove :host since it should be unnecessary + var t = p.replace(_polyfillHostRe, ''); + if (t.length > 0) { + var matches = t.match(/([^:]*)(:*)(.*)/); + if (matches) { + scopedP = matches[1] + attrName + matches[2] + matches[3]; + } + } + } + return scopedP; + }; + var safeContent = new SafeSelector(selector); + selector = safeContent.content(); + var scopedSelector = ''; + var startIndex = 0; + var res; + var sep = /( |>|\+|~(?!=))\s*/g; + // If a selector appears before :host it should not be shimmed as it + // matches on ancestor elements and not on elements in the host's shadow + // `:host-context(div)` is transformed to + // `-shadowcsshost-no-combinatordiv, div -shadowcsshost-no-combinator` + // the `div` is not part of the component in the 2nd selectors and should not be scoped. + // Historically `component-tag:host` was matching the component so we also want to preserve + // this behavior to avoid breaking legacy apps (it should not match). + // The behavior should be: + // - `tag:host` -> `tag[h]` (this is to avoid breaking legacy apps, should not match anything) + // - `tag :host` -> `tag [h]` (`tag` is not scoped because it's considered part of a + // `:host-context(tag)`) + var hasHost = selector.indexOf(_polyfillHostNoCombinator) > -1; + // Only scope parts after the first `-shadowcsshost-no-combinator` when it is present + var shouldScope = !hasHost; + while ((res = sep.exec(selector)) !== null) { + var separator = res[1]; + var part_1 = selector.slice(startIndex, res.index).trim(); + shouldScope = shouldScope || part_1.indexOf(_polyfillHostNoCombinator) > -1; + var scopedPart = shouldScope ? _scopeSelectorPart(part_1) : part_1; + scopedSelector += scopedPart + " " + separator + " "; + startIndex = sep.lastIndex; + } + var part = selector.substring(startIndex); + shouldScope = shouldScope || part.indexOf(_polyfillHostNoCombinator) > -1; + scopedSelector += shouldScope ? _scopeSelectorPart(part) : part; + // replace the placeholders with their original values + return safeContent.restore(scopedSelector); + }; + ShadowCss.prototype._insertPolyfillHostInCssText = function (selector) { + return selector.replace(_colonHostContextRe, _polyfillHostContext) + .replace(_colonHostRe, _polyfillHost); + }; + return ShadowCss; +}()); +var SafeSelector = /** @class */ (function () { + function SafeSelector(selector) { + var _this = this; + this.placeholders = []; + this.index = 0; + // Replaces attribute selectors with placeholders. + // The WS in [attr="va lue"] would otherwise be interpreted as a selector separator. + selector = selector.replace(/(\[[^\]]*\])/g, function (_, keep) { + var replaceBy = "__ph-" + _this.index + "__"; + _this.placeholders.push(keep); + _this.index++; + return replaceBy; + }); + // Replaces the expression in `:nth-child(2n + 1)` with a placeholder. + // WS and "+" would otherwise be interpreted as selector separators. + this._content = selector.replace(/(:nth-[-\w]+)(\([^)]+\))/g, function (_, pseudo, exp) { + var replaceBy = "__ph-" + _this.index + "__"; + _this.placeholders.push(exp); + _this.index++; + return pseudo + replaceBy; + }); + } + SafeSelector.prototype.restore = function (content) { + var _this = this; + return content.replace(/__ph-(\d+)__/g, function (ph, index) { return _this.placeholders[+index]; }); + }; + SafeSelector.prototype.content = function () { return this._content; }; + return SafeSelector; +}()); +var _cssContentNextSelectorRe = /polyfill-next-selector[^}]*content:[\s]*?(['"])(.*?)\1[;\s]*}([^{]*?){/gim; +var _cssContentRuleRe = /(polyfill-rule)[^}]*(content:[\s]*(['"])(.*?)\3)[;\s]*[^}]*}/gim; +var _cssContentUnscopedRuleRe = /(polyfill-unscoped-rule)[^}]*(content:[\s]*(['"])(.*?)\3)[;\s]*[^}]*}/gim; +var _polyfillHost = '-shadowcsshost'; +// note: :host-context pre-processed to -shadowcsshostcontext. +var _polyfillHostContext = '-shadowcsscontext'; +var _parenSuffix = ')(?:\\((' + + '(?:\\([^)(]*\\)|[^)(]*)+?' + + ')\\))?([^,{]*)'; +var _cssColonHostRe = new RegExp('(' + _polyfillHost + _parenSuffix, 'gim'); +var _cssColonHostContextRe = new RegExp('(' + _polyfillHostContext + _parenSuffix, 'gim'); +var _polyfillHostNoCombinator = _polyfillHost + '-no-combinator'; +var _polyfillHostNoCombinatorRe = /-shadowcsshost-no-combinator([^\s]*)/; +var _shadowDOMSelectorsRe = [ + /::shadow/g, + /::content/g, + // Deprecated selectors + /\/shadow-deep\//g, + /\/shadow\//g, +]; +// The deep combinator is deprecated in the CSS spec +// Support for `>>>`, `deep`, `::ng-deep` is then also deprecated and will be removed in the future. +// see https://github.com/angular/angular/pull/17677 +var _shadowDeepSelectors = /(?:>>>)|(?:\/deep\/)|(?:::ng-deep)/g; +var _selectorReSuffix = '([>\\s~+\[.,{:][\\s\\S]*)?$'; +var _polyfillHostRe = /-shadowcsshost/gim; +var _colonHostRe = /:host/gim; +var _colonHostContextRe = /:host-context/gim; +var _commentRe = /\/\*\s*[\s\S]*?\*\//g; +function stripComments(input) { + return input.replace(_commentRe, ''); +} +var _commentWithHashRe = /\/\*\s*#\s*source(Mapping)?URL=[\s\S]+?\*\//g; +function extractCommentsWithHash(input) { + return input.match(_commentWithHashRe) || []; +} +var _ruleRe = /(\s*)([^;\{\}]+?)(\s*)((?:{%BLOCK%}?\s*;?)|(?:\s*;))/g; +var _curlyRe = /([{}])/g; +var OPEN_CURLY = '{'; +var CLOSE_CURLY = '}'; +var BLOCK_PLACEHOLDER = '%BLOCK%'; +var CssRule = /** @class */ (function () { + function CssRule(selector, content) { + this.selector = selector; + this.content = content; + } + return CssRule; +}()); +function processRules(input, ruleCallback) { + var inputWithEscapedBlocks = escapeBlocks(input); + var nextBlockIndex = 0; + return inputWithEscapedBlocks.escapedString.replace(_ruleRe, function () { + var m = []; + for (var _i = 0; _i < arguments.length; _i++) { + m[_i] = arguments[_i]; + } + var selector = m[2]; + var content = ''; + var suffix = m[4]; + var contentPrefix = ''; + if (suffix && suffix.startsWith('{' + BLOCK_PLACEHOLDER)) { + content = inputWithEscapedBlocks.blocks[nextBlockIndex++]; + suffix = suffix.substring(BLOCK_PLACEHOLDER.length + 1); + contentPrefix = '{'; + } + var rule = ruleCallback(new CssRule(selector, content)); + return "" + m[1] + rule.selector + m[3] + contentPrefix + rule.content + suffix; + }); +} +var StringWithEscapedBlocks = /** @class */ (function () { + function StringWithEscapedBlocks(escapedString, blocks) { + this.escapedString = escapedString; + this.blocks = blocks; + } + return StringWithEscapedBlocks; +}()); +function escapeBlocks(input) { + var inputParts = input.split(_curlyRe); + var resultParts = []; + var escapedBlocks = []; + var bracketCount = 0; + var currentBlockParts = []; + for (var partIndex = 0; partIndex < inputParts.length; partIndex++) { + var part = inputParts[partIndex]; + if (part == CLOSE_CURLY) { + bracketCount--; + } + if (bracketCount > 0) { + currentBlockParts.push(part); + } + else { + if (currentBlockParts.length > 0) { + escapedBlocks.push(currentBlockParts.join('')); + resultParts.push(BLOCK_PLACEHOLDER); + currentBlockParts = []; + } + resultParts.push(part); + } + if (part == OPEN_CURLY) { + bracketCount++; + } + } + if (currentBlockParts.length > 0) { + escapedBlocks.push(currentBlockParts.join('')); + resultParts.push(BLOCK_PLACEHOLDER); + } + return new StringWithEscapedBlocks(resultParts.join(''), escapedBlocks); +} + +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +var COMPONENT_VARIABLE = '%COMP%'; +var HOST_ATTR = "_nghost-" + COMPONENT_VARIABLE; +var CONTENT_ATTR = "_ngcontent-" + COMPONENT_VARIABLE; +var StylesCompileDependency = /** @class */ (function () { + function StylesCompileDependency(name, moduleUrl, setValue) { + this.name = name; + this.moduleUrl = moduleUrl; + this.setValue = setValue; + } + return StylesCompileDependency; +}()); +var CompiledStylesheet = /** @class */ (function () { + function CompiledStylesheet(outputCtx, stylesVar, dependencies, isShimmed, meta) { + this.outputCtx = outputCtx; + this.stylesVar = stylesVar; + this.dependencies = dependencies; + this.isShimmed = isShimmed; + this.meta = meta; + } + return CompiledStylesheet; +}()); +var StyleCompiler = /** @class */ (function () { + function StyleCompiler(_urlResolver) { + this._urlResolver = _urlResolver; + this._shadowCss = new ShadowCss(); + } + StyleCompiler.prototype.compileComponent = function (outputCtx, comp) { + var template = comp.template; + return this._compileStyles(outputCtx, comp, new CompileStylesheetMetadata({ + styles: template.styles, + styleUrls: template.styleUrls, + moduleUrl: identifierModuleUrl(comp.type) + }), this.needsStyleShim(comp), true); + }; + StyleCompiler.prototype.compileStyles = function (outputCtx, comp, stylesheet, shim) { + if (shim === void 0) { shim = this.needsStyleShim(comp); } + return this._compileStyles(outputCtx, comp, stylesheet, shim, false); + }; + StyleCompiler.prototype.needsStyleShim = function (comp) { + return comp.template.encapsulation === ViewEncapsulation.Emulated; + }; + StyleCompiler.prototype._compileStyles = function (outputCtx, comp, stylesheet, shim, isComponentStylesheet) { + var _this = this; + var styleExpressions = stylesheet.styles.map(function (plainStyle) { return literal(_this._shimIfNeeded(plainStyle, shim)); }); + var dependencies = []; + stylesheet.styleUrls.forEach(function (styleUrl) { + var exprIndex = styleExpressions.length; + // Note: This placeholder will be filled later. + styleExpressions.push(null); + dependencies.push(new StylesCompileDependency(getStylesVarName(null), styleUrl, function (value) { return styleExpressions[exprIndex] = outputCtx.importExpr(value); })); + }); + // styles variable contains plain strings and arrays of other styles arrays (recursive), + // so we set its type to dynamic. + var stylesVar = getStylesVarName(isComponentStylesheet ? comp : null); + var stmt = variable(stylesVar) + .set(literalArr(styleExpressions, new ArrayType(DYNAMIC_TYPE, [TypeModifier.Const]))) + .toDeclStmt(null, isComponentStylesheet ? [StmtModifier.Final] : [ + StmtModifier.Final, StmtModifier.Exported + ]); + outputCtx.statements.push(stmt); + return new CompiledStylesheet(outputCtx, stylesVar, dependencies, shim, stylesheet); + }; + StyleCompiler.prototype._shimIfNeeded = function (style, shim) { + return shim ? this._shadowCss.shimCssText(style, CONTENT_ATTR, HOST_ATTR) : style; + }; + return StyleCompiler; +}()); +function getStylesVarName(component) { + var result = "styles"; + if (component) { + result += "_" + identifierName(component.type); + } + return result; +} + +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +var PRESERVE_WS_ATTR_NAME = 'ngPreserveWhitespaces'; +var SKIP_WS_TRIM_TAGS = new Set(['pre', 'template', 'textarea', 'script', 'style']); +// Equivalent to \s with \u00a0 (non-breaking space) excluded. +// Based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp +var WS_CHARS = ' \f\n\r\t\v\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff'; +var NO_WS_REGEXP = new RegExp("[^" + WS_CHARS + "]"); +var WS_REPLACE_REGEXP = new RegExp("[" + WS_CHARS + "]{2,}", 'g'); +function hasPreserveWhitespacesAttr(attrs) { + return attrs.some(function (attr) { return attr.name === PRESERVE_WS_ATTR_NAME; }); +} +/** + * Angular Dart introduced &ngsp; as a placeholder for non-removable space, see: + * https://github.com/dart-lang/angular/blob/0bb611387d29d65b5af7f9d2515ab571fd3fbee4/_tests/test/compiler/preserve_whitespace_test.dart#L25-L32 + * In Angular Dart &ngsp; is converted to the 0xE500 PUA (Private Use Areas) unicode character + * and later on replaced by a space. We are re-implementing the same idea here. + */ +function replaceNgsp(value) { + // lexer is replacing the &ngsp; pseudo-entity with NGSP_UNICODE + return value.replace(new RegExp(NGSP_UNICODE, 'g'), ' '); +} +/** + * This visitor can walk HTML parse tree and remove / trim text nodes using the following rules: + * - consider spaces, tabs and new lines as whitespace characters; + * - drop text nodes consisting of whitespace characters only; + * - for all other text nodes replace consecutive whitespace characters with one space; + * - convert &ngsp; pseudo-entity to a single space; + * + * Removal and trimming of whitespaces have positive performance impact (less code to generate + * while compiling templates, faster view creation). At the same time it can be "destructive" + * in some cases (whitespaces can influence layout). Because of the potential of breaking layout + * this visitor is not activated by default in Angular 5 and people need to explicitly opt-in for + * whitespace removal. The default option for whitespace removal will be revisited in Angular 6 + * and might be changed to "on" by default. + */ +var WhitespaceVisitor = /** @class */ (function () { + function WhitespaceVisitor() { + } + WhitespaceVisitor.prototype.visitElement = function (element, context) { + if (SKIP_WS_TRIM_TAGS.has(element.name) || hasPreserveWhitespacesAttr(element.attrs)) { + // don't descent into elements where we need to preserve whitespaces + // but still visit all attributes to eliminate one used as a market to preserve WS + return new Element(element.name, visitAll(this, element.attrs), element.children, element.sourceSpan, element.startSourceSpan, element.endSourceSpan); + } + return new Element(element.name, element.attrs, visitAll(this, element.children), element.sourceSpan, element.startSourceSpan, element.endSourceSpan); + }; + WhitespaceVisitor.prototype.visitAttribute = function (attribute, context) { + return attribute.name !== PRESERVE_WS_ATTR_NAME ? attribute : null; + }; + WhitespaceVisitor.prototype.visitText = function (text, context) { + var isNotBlank = text.value.match(NO_WS_REGEXP); + if (isNotBlank) { + return new Text(replaceNgsp(text.value).replace(WS_REPLACE_REGEXP, ' '), text.sourceSpan); + } + return null; + }; + WhitespaceVisitor.prototype.visitComment = function (comment, context) { return comment; }; + WhitespaceVisitor.prototype.visitExpansion = function (expansion, context) { return expansion; }; + WhitespaceVisitor.prototype.visitExpansionCase = function (expansionCase, context) { return expansionCase; }; + return WhitespaceVisitor; +}()); +function removeWhitespaces(htmlAstWithErrors) { + return new ParseTreeResult(visitAll(new WhitespaceVisitor(), htmlAstWithErrors.rootNodes), htmlAstWithErrors.errors); +} + +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +// http://cldr.unicode.org/index/cldr-spec/plural-rules +var PLURAL_CASES = ['zero', 'one', 'two', 'few', 'many', 'other']; +/** + * Expands special forms into elements. + * + * For example, + * + * ``` + * { messages.length, plural, + * =0 {zero} + * =1 {one} + * other {more than one} + * } + * ``` + * + * will be expanded into + * + * ``` + * + * zero + * one + * more than one + * + * ``` + */ +function expandNodes(nodes) { + var expander = new _Expander(); + return new ExpansionResult(visitAll(expander, nodes), expander.isExpanded, expander.errors); +} +var ExpansionResult = /** @class */ (function () { + function ExpansionResult(nodes, expanded, errors) { + this.nodes = nodes; + this.expanded = expanded; + this.errors = errors; + } + return ExpansionResult; +}()); +var ExpansionError = /** @class */ (function (_super) { + Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(ExpansionError, _super); + function ExpansionError(span, errorMsg) { + return _super.call(this, span, errorMsg) || this; + } + return ExpansionError; +}(ParseError)); +/** + * Expand expansion forms (plural, select) to directives + * + * @internal + */ +var _Expander = /** @class */ (function () { + function _Expander() { + this.isExpanded = false; + this.errors = []; + } + _Expander.prototype.visitElement = function (element, context) { + return new Element(element.name, element.attrs, visitAll(this, element.children), element.sourceSpan, element.startSourceSpan, element.endSourceSpan); + }; + _Expander.prototype.visitAttribute = function (attribute, context) { return attribute; }; + _Expander.prototype.visitText = function (text, context) { return text; }; + _Expander.prototype.visitComment = function (comment, context) { return comment; }; + _Expander.prototype.visitExpansion = function (icu, context) { + this.isExpanded = true; + return icu.type == 'plural' ? _expandPluralForm(icu, this.errors) : + _expandDefaultForm(icu, this.errors); + }; + _Expander.prototype.visitExpansionCase = function (icuCase, context) { + throw new Error('Should not be reached'); + }; + return _Expander; +}()); +// Plural forms are expanded to `NgPlural` and `NgPluralCase`s +function _expandPluralForm(ast, errors) { + var children = ast.cases.map(function (c) { + if (PLURAL_CASES.indexOf(c.value) == -1 && !c.value.match(/^=\d+$/)) { + errors.push(new ExpansionError(c.valueSourceSpan, "Plural cases should be \"=\" or one of " + PLURAL_CASES.join(", "))); + } + var expansionResult = expandNodes(c.expression); + errors.push.apply(errors, Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__spread"])(expansionResult.errors)); + return new Element("ng-template", [new Attribute('ngPluralCase', "" + c.value, c.valueSourceSpan)], expansionResult.nodes, c.sourceSpan, c.sourceSpan, c.sourceSpan); + }); + var switchAttr = new Attribute('[ngPlural]', ast.switchValue, ast.switchValueSourceSpan); + return new Element('ng-container', [switchAttr], children, ast.sourceSpan, ast.sourceSpan, ast.sourceSpan); +} +// ICU messages (excluding plural form) are expanded to `NgSwitch` and `NgSwitchCase`s +function _expandDefaultForm(ast, errors) { + var children = ast.cases.map(function (c) { + var expansionResult = expandNodes(c.expression); + errors.push.apply(errors, Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__spread"])(expansionResult.errors)); + if (c.value === 'other') { + // other is the default case when no values match + return new Element("ng-template", [new Attribute('ngSwitchDefault', '', c.valueSourceSpan)], expansionResult.nodes, c.sourceSpan, c.sourceSpan, c.sourceSpan); + } + return new Element("ng-template", [new Attribute('ngSwitchCase', "" + c.value, c.valueSourceSpan)], expansionResult.nodes, c.sourceSpan, c.sourceSpan, c.sourceSpan); + }); + var switchAttr = new Attribute('[ngSwitch]', ast.switchValue, ast.switchValueSourceSpan); + return new Element('ng-container', [switchAttr], children, ast.sourceSpan, ast.sourceSpan, ast.sourceSpan); +} + +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +var PROPERTY_PARTS_SEPARATOR = '.'; +var ATTRIBUTE_PREFIX = 'attr'; +var CLASS_PREFIX = 'class'; +var STYLE_PREFIX = 'style'; +var ANIMATE_PROP_PREFIX = 'animate-'; +/** + * Parses bindings in templates and in the directive host area. + */ +var BindingParser = /** @class */ (function () { + function BindingParser(_exprParser, _interpolationConfig, _schemaRegistry, pipes, errors) { + this._exprParser = _exprParser; + this._interpolationConfig = _interpolationConfig; + this._schemaRegistry = _schemaRegistry; + this.errors = errors; + this.pipesByName = null; + this._usedPipes = new Map(); + // When the `pipes` parameter is `null`, do not check for used pipes + // This is used in IVY when we might not know the available pipes at compile time + if (pipes) { + var pipesByName_1 = new Map(); + pipes.forEach(function (pipe) { return pipesByName_1.set(pipe.name, pipe); }); + this.pipesByName = pipesByName_1; + } + } + BindingParser.prototype.getUsedPipes = function () { return Array.from(this._usedPipes.values()); }; + BindingParser.prototype.createBoundHostProperties = function (dirMeta, sourceSpan) { + var _this = this; + if (dirMeta.hostProperties) { + var boundProps_1 = []; + Object.keys(dirMeta.hostProperties).forEach(function (propName) { + var expression = dirMeta.hostProperties[propName]; + if (typeof expression === 'string') { + _this.parsePropertyBinding(propName, expression, true, sourceSpan, [], boundProps_1); + } + else { + _this._reportError("Value of the host property binding \"" + propName + "\" needs to be a string representing an expression but got \"" + expression + "\" (" + typeof expression + ")", sourceSpan); + } + }); + return boundProps_1; + } + return null; + }; + BindingParser.prototype.createDirectiveHostPropertyAsts = function (dirMeta, elementSelector, sourceSpan) { + var _this = this; + var boundProps = this.createBoundHostProperties(dirMeta, sourceSpan); + return boundProps && + boundProps.map(function (prop) { return _this.createBoundElementProperty(elementSelector, prop); }); + }; + BindingParser.prototype.createDirectiveHostEventAsts = function (dirMeta, sourceSpan) { + var _this = this; + if (dirMeta.hostListeners) { + var targetEvents_1 = []; + Object.keys(dirMeta.hostListeners).forEach(function (propName) { + var expression = dirMeta.hostListeners[propName]; + if (typeof expression === 'string') { + _this.parseEvent(propName, expression, sourceSpan, [], targetEvents_1); + } + else { + _this._reportError("Value of the host listener \"" + propName + "\" needs to be a string representing an expression but got \"" + expression + "\" (" + typeof expression + ")", sourceSpan); + } + }); + return targetEvents_1; + } + return null; + }; + BindingParser.prototype.parseInterpolation = function (value, sourceSpan) { + var sourceInfo = sourceSpan.start.toString(); + try { + var ast = this._exprParser.parseInterpolation(value, sourceInfo, this._interpolationConfig); + if (ast) + this._reportExpressionParserErrors(ast.errors, sourceSpan); + this._checkPipes(ast, sourceSpan); + return ast; + } + catch (e) { + this._reportError("" + e, sourceSpan); + return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo); + } + }; + // Parse an inline template binding. ie `` + BindingParser.prototype.parseInlineTemplateBinding = function (tplKey, tplValue, sourceSpan, targetMatchableAttrs, targetProps, targetVars) { + var bindings = this._parseTemplateBindings(tplKey, tplValue, sourceSpan); + for (var i = 0; i < bindings.length; i++) { + var binding = bindings[i]; + if (binding.keyIsVar) { + targetVars.push(new ParsedVariable(binding.key, binding.name, sourceSpan)); + } + else if (binding.expression) { + this._parsePropertyAst(binding.key, binding.expression, sourceSpan, targetMatchableAttrs, targetProps); + } + else { + targetMatchableAttrs.push([binding.key, '']); + this.parseLiteralAttr(binding.key, null, sourceSpan, targetMatchableAttrs, targetProps); + } + } + }; + BindingParser.prototype._parseTemplateBindings = function (tplKey, tplValue, sourceSpan) { + var _this = this; + var sourceInfo = sourceSpan.start.toString(); + try { + var bindingsResult = this._exprParser.parseTemplateBindings(tplKey, tplValue, sourceInfo); + this._reportExpressionParserErrors(bindingsResult.errors, sourceSpan); + bindingsResult.templateBindings.forEach(function (binding) { + if (binding.expression) { + _this._checkPipes(binding.expression, sourceSpan); + } + }); + bindingsResult.warnings.forEach(function (warning) { _this._reportError(warning, sourceSpan, ParseErrorLevel.WARNING); }); + return bindingsResult.templateBindings; + } + catch (e) { + this._reportError("" + e, sourceSpan); + return []; + } + }; + BindingParser.prototype.parseLiteralAttr = function (name, value, sourceSpan, targetMatchableAttrs, targetProps) { + if (isAnimationLabel(name)) { + name = name.substring(1); + if (value) { + this._reportError("Assigning animation triggers via @prop=\"exp\" attributes with an expression is invalid." + + " Use property bindings (e.g. [@prop]=\"exp\") or use an attribute without a value (e.g. @prop) instead.", sourceSpan, ParseErrorLevel.ERROR); + } + this._parseAnimation(name, value, sourceSpan, targetMatchableAttrs, targetProps); + } + else { + targetProps.push(new ParsedProperty(name, this._exprParser.wrapLiteralPrimitive(value, ''), ParsedPropertyType.LITERAL_ATTR, sourceSpan)); + } + }; + BindingParser.prototype.parsePropertyBinding = function (name, expression, isHost, sourceSpan, targetMatchableAttrs, targetProps) { + var isAnimationProp = false; + if (name.startsWith(ANIMATE_PROP_PREFIX)) { + isAnimationProp = true; + name = name.substring(ANIMATE_PROP_PREFIX.length); + } + else if (isAnimationLabel(name)) { + isAnimationProp = true; + name = name.substring(1); + } + if (isAnimationProp) { + this._parseAnimation(name, expression, sourceSpan, targetMatchableAttrs, targetProps); + } + else { + this._parsePropertyAst(name, this._parseBinding(expression, isHost, sourceSpan), sourceSpan, targetMatchableAttrs, targetProps); + } + }; + BindingParser.prototype.parsePropertyInterpolation = function (name, value, sourceSpan, targetMatchableAttrs, targetProps) { + var expr = this.parseInterpolation(value, sourceSpan); + if (expr) { + this._parsePropertyAst(name, expr, sourceSpan, targetMatchableAttrs, targetProps); + return true; + } + return false; + }; + BindingParser.prototype._parsePropertyAst = function (name, ast, sourceSpan, targetMatchableAttrs, targetProps) { + targetMatchableAttrs.push([name, ast.source]); + targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.DEFAULT, sourceSpan)); + }; + BindingParser.prototype._parseAnimation = function (name, expression, sourceSpan, targetMatchableAttrs, targetProps) { + // This will occur when a @trigger is not paired with an expression. + // For animations it is valid to not have an expression since */void + // states will be applied by angular when the element is attached/detached + var ast = this._parseBinding(expression || 'undefined', false, sourceSpan); + targetMatchableAttrs.push([name, ast.source]); + targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.ANIMATION, sourceSpan)); + }; + BindingParser.prototype._parseBinding = function (value, isHostBinding, sourceSpan) { + var sourceInfo = (sourceSpan && sourceSpan.start || '(unknown)').toString(); + try { + var ast = isHostBinding ? + this._exprParser.parseSimpleBinding(value, sourceInfo, this._interpolationConfig) : + this._exprParser.parseBinding(value, sourceInfo, this._interpolationConfig); + if (ast) + this._reportExpressionParserErrors(ast.errors, sourceSpan); + this._checkPipes(ast, sourceSpan); + return ast; + } + catch (e) { + this._reportError("" + e, sourceSpan); + return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo); + } + }; + BindingParser.prototype.createBoundElementProperty = function (elementSelector, boundProp) { + if (boundProp.isAnimation) { + return new BoundElementProperty(boundProp.name, 4 /* Animation */, SecurityContext.NONE, boundProp.expression, null, boundProp.sourceSpan); + } + var unit = null; + var bindingType = undefined; + var boundPropertyName = null; + var parts = boundProp.name.split(PROPERTY_PARTS_SEPARATOR); + var securityContexts = undefined; + // Check check for special cases (prefix style, attr, class) + if (parts.length > 1) { + if (parts[0] == ATTRIBUTE_PREFIX) { + boundPropertyName = parts[1]; + this._validatePropertyOrAttributeName(boundPropertyName, boundProp.sourceSpan, true); + securityContexts = calcPossibleSecurityContexts(this._schemaRegistry, elementSelector, boundPropertyName, true); + var nsSeparatorIdx = boundPropertyName.indexOf(':'); + if (nsSeparatorIdx > -1) { + var ns = boundPropertyName.substring(0, nsSeparatorIdx); + var name_1 = boundPropertyName.substring(nsSeparatorIdx + 1); + boundPropertyName = mergeNsAndName(ns, name_1); + } + bindingType = 1 /* Attribute */; + } + else if (parts[0] == CLASS_PREFIX) { + boundPropertyName = parts[1]; + bindingType = 2 /* Class */; + securityContexts = [SecurityContext.NONE]; + } + else if (parts[0] == STYLE_PREFIX) { + unit = parts.length > 2 ? parts[2] : null; + boundPropertyName = parts[1]; + bindingType = 3 /* Style */; + securityContexts = [SecurityContext.STYLE]; + } + } + // If not a special case, use the full property name + if (boundPropertyName === null) { + boundPropertyName = this._schemaRegistry.getMappedPropName(boundProp.name); + securityContexts = calcPossibleSecurityContexts(this._schemaRegistry, elementSelector, boundPropertyName, false); + bindingType = 0 /* Property */; + this._validatePropertyOrAttributeName(boundPropertyName, boundProp.sourceSpan, false); + } + return new BoundElementProperty(boundPropertyName, bindingType, securityContexts[0], boundProp.expression, unit, boundProp.sourceSpan); + }; + BindingParser.prototype.parseEvent = function (name, expression, sourceSpan, targetMatchableAttrs, targetEvents) { + if (isAnimationLabel(name)) { + name = name.substr(1); + this._parseAnimationEvent(name, expression, sourceSpan, targetEvents); + } + else { + this._parseRegularEvent(name, expression, sourceSpan, targetMatchableAttrs, targetEvents); + } + }; + BindingParser.prototype._parseAnimationEvent = function (name, expression, sourceSpan, targetEvents) { + var matches = splitAtPeriod(name, [name, '']); + var eventName = matches[0]; + var phase = matches[1].toLowerCase(); + if (phase) { + switch (phase) { + case 'start': + case 'done': + var ast = this._parseAction(expression, sourceSpan); + targetEvents.push(new ParsedEvent(eventName, phase, 1 /* Animation */, ast, sourceSpan)); + break; + default: + this._reportError("The provided animation output phase value \"" + phase + "\" for \"@" + eventName + "\" is not supported (use start or done)", sourceSpan); + break; + } + } + else { + this._reportError("The animation trigger output event (@" + eventName + ") is missing its phase value name (start or done are currently supported)", sourceSpan); + } + }; + BindingParser.prototype._parseRegularEvent = function (name, expression, sourceSpan, targetMatchableAttrs, targetEvents) { + // long format: 'target: eventName' + var _a = Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__read"])(splitAtColon(name, [null, name]), 2), target = _a[0], eventName = _a[1]; + var ast = this._parseAction(expression, sourceSpan); + targetMatchableAttrs.push([name, ast.source]); + targetEvents.push(new ParsedEvent(eventName, target, 0 /* Regular */, ast, sourceSpan)); + // Don't detect directives for event names for now, + // so don't add the event name to the matchableAttrs + }; + BindingParser.prototype._parseAction = function (value, sourceSpan) { + var sourceInfo = (sourceSpan && sourceSpan.start || '(unknown').toString(); + try { + var ast = this._exprParser.parseAction(value, sourceInfo, this._interpolationConfig); + if (ast) { + this._reportExpressionParserErrors(ast.errors, sourceSpan); + } + if (!ast || ast.ast instanceof EmptyExpr) { + this._reportError("Empty expressions are not allowed", sourceSpan); + return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo); + } + this._checkPipes(ast, sourceSpan); + return ast; + } + catch (e) { + this._reportError("" + e, sourceSpan); + return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo); + } + }; + BindingParser.prototype._reportError = function (message, sourceSpan, level) { + if (level === void 0) { level = ParseErrorLevel.ERROR; } + this.errors.push(new ParseError(sourceSpan, message, level)); + }; + BindingParser.prototype._reportExpressionParserErrors = function (errors, sourceSpan) { + var e_1, _a; + try { + for (var errors_1 = Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__values"])(errors), errors_1_1 = errors_1.next(); !errors_1_1.done; errors_1_1 = errors_1.next()) { + var error$$1 = errors_1_1.value; + this._reportError(error$$1.message, sourceSpan); + } + } + catch (e_1_1) { e_1 = { error: e_1_1 }; } + finally { + try { + if (errors_1_1 && !errors_1_1.done && (_a = errors_1.return)) _a.call(errors_1); + } + finally { if (e_1) throw e_1.error; } + } + }; + // Make sure all the used pipes are known in `this.pipesByName` + BindingParser.prototype._checkPipes = function (ast, sourceSpan) { + var _this = this; + if (ast && this.pipesByName) { + var collector = new PipeCollector(); + ast.visit(collector); + collector.pipes.forEach(function (ast, pipeName) { + var pipeMeta = _this.pipesByName.get(pipeName); + if (!pipeMeta) { + _this._reportError("The pipe '" + pipeName + "' could not be found", new ParseSourceSpan(sourceSpan.start.moveBy(ast.span.start), sourceSpan.start.moveBy(ast.span.end))); + } + else { + _this._usedPipes.set(pipeName, pipeMeta); + } + }); + } + }; + /** + * @param propName the name of the property / attribute + * @param sourceSpan + * @param isAttr true when binding to an attribute + */ + BindingParser.prototype._validatePropertyOrAttributeName = function (propName, sourceSpan, isAttr) { + var report = isAttr ? this._schemaRegistry.validateAttribute(propName) : + this._schemaRegistry.validateProperty(propName); + if (report.error) { + this._reportError(report.msg, sourceSpan, ParseErrorLevel.ERROR); + } + }; + return BindingParser; +}()); +var PipeCollector = /** @class */ (function (_super) { + Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(PipeCollector, _super); + function PipeCollector() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.pipes = new Map(); + return _this; + } + PipeCollector.prototype.visitPipe = function (ast, context) { + this.pipes.set(ast.name, ast); + ast.exp.visit(this); + this.visitAll(ast.args, context); + return null; + }; + return PipeCollector; +}(RecursiveAstVisitor)); +function isAnimationLabel(name) { + return name[0] == '@'; +} +function calcPossibleSecurityContexts(registry, selector, propName, isAttribute) { + var ctxs = []; + CssSelector.parse(selector).forEach(function (selector) { + var elementNames = selector.element ? [selector.element] : registry.allKnownElementNames(); + var notElementNames = new Set(selector.notSelectors.filter(function (selector) { return selector.isElementSelector(); }) + .map(function (selector) { return selector.element; })); + var possibleElementNames = elementNames.filter(function (elementName) { return !notElementNames.has(elementName); }); + ctxs.push.apply(ctxs, Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__spread"])(possibleElementNames.map(function (elementName) { return registry.securityContext(elementName, propName, isAttribute); }))); + }); + return ctxs.length === 0 ? [SecurityContext.NONE] : Array.from(new Set(ctxs)).sort(); +} + +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +var BIND_NAME_REGEXP = /^(?:(?:(?:(bind-)|(let-)|(ref-|#)|(on-)|(bindon-)|(@))(.+))|\[\(([^\)]+)\)\]|\[([^\]]+)\]|\(([^\)]+)\))$/; +// Group 1 = "bind-" +var KW_BIND_IDX = 1; +// Group 2 = "let-" +var KW_LET_IDX = 2; +// Group 3 = "ref-/#" +var KW_REF_IDX = 3; +// Group 4 = "on-" +var KW_ON_IDX = 4; +// Group 5 = "bindon-" +var KW_BINDON_IDX = 5; +// Group 6 = "@" +var KW_AT_IDX = 6; +// Group 7 = the identifier after "bind-", "let-", "ref-/#", "on-", "bindon-" or "@" +var IDENT_KW_IDX = 7; +// Group 8 = identifier inside [()] +var IDENT_BANANA_BOX_IDX = 8; +// Group 9 = identifier inside [] +var IDENT_PROPERTY_IDX = 9; +// Group 10 = identifier inside () +var IDENT_EVENT_IDX = 10; +var TEMPLATE_ATTR_PREFIX = '*'; +var CLASS_ATTR = 'class'; +var _TEXT_CSS_SELECTOR; +function TEXT_CSS_SELECTOR() { + if (!_TEXT_CSS_SELECTOR) { + _TEXT_CSS_SELECTOR = CssSelector.parse('*')[0]; + } + return _TEXT_CSS_SELECTOR; +} +var TemplateParseError = /** @class */ (function (_super) { + Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(TemplateParseError, _super); + function TemplateParseError(message, span, level) { + return _super.call(this, span, message, level) || this; + } + return TemplateParseError; +}(ParseError)); +var TemplateParseResult = /** @class */ (function () { + function TemplateParseResult(templateAst, usedPipes, errors) { + this.templateAst = templateAst; + this.usedPipes = usedPipes; + this.errors = errors; + } + return TemplateParseResult; +}()); +var TemplateParser = /** @class */ (function () { + function TemplateParser(_config, _reflector, _exprParser, _schemaRegistry, _htmlParser, _console, transforms) { + this._config = _config; + this._reflector = _reflector; + this._exprParser = _exprParser; + this._schemaRegistry = _schemaRegistry; + this._htmlParser = _htmlParser; + this._console = _console; + this.transforms = transforms; + } + Object.defineProperty(TemplateParser.prototype, "expressionParser", { + get: function () { return this._exprParser; }, + enumerable: true, + configurable: true + }); + TemplateParser.prototype.parse = function (component, template, directives, pipes, schemas, templateUrl, preserveWhitespaces) { + var result = this.tryParse(component, template, directives, pipes, schemas, templateUrl, preserveWhitespaces); + var warnings = result.errors.filter(function (error$$1) { return error$$1.level === ParseErrorLevel.WARNING; }); + var errors = result.errors.filter(function (error$$1) { return error$$1.level === ParseErrorLevel.ERROR; }); + if (warnings.length > 0) { + this._console.warn("Template parse warnings:\n" + warnings.join('\n')); + } + if (errors.length > 0) { + var errorString = errors.join('\n'); + throw syntaxError("Template parse errors:\n" + errorString, errors); + } + return { template: result.templateAst, pipes: result.usedPipes }; + }; + TemplateParser.prototype.tryParse = function (component, template, directives, pipes, schemas, templateUrl, preserveWhitespaces) { + var htmlParseResult = typeof template === 'string' ? + this._htmlParser.parse(template, templateUrl, true, this.getInterpolationConfig(component)) : + template; + if (!preserveWhitespaces) { + htmlParseResult = removeWhitespaces(htmlParseResult); + } + return this.tryParseHtml(this.expandHtml(htmlParseResult), component, directives, pipes, schemas); + }; + TemplateParser.prototype.tryParseHtml = function (htmlAstWithErrors, component, directives, pipes, schemas) { + var result; + var errors = htmlAstWithErrors.errors; + var usedPipes = []; + if (htmlAstWithErrors.rootNodes.length > 0) { + var uniqDirectives = removeSummaryDuplicates(directives); + var uniqPipes = removeSummaryDuplicates(pipes); + var providerViewContext = new ProviderViewContext(this._reflector, component); + var interpolationConfig = undefined; + if (component.template && component.template.interpolation) { + interpolationConfig = { + start: component.template.interpolation[0], + end: component.template.interpolation[1] + }; + } + var bindingParser = new BindingParser(this._exprParser, interpolationConfig, this._schemaRegistry, uniqPipes, errors); + var parseVisitor = new TemplateParseVisitor(this._reflector, this._config, providerViewContext, uniqDirectives, bindingParser, this._schemaRegistry, schemas, errors); + result = visitAll(parseVisitor, htmlAstWithErrors.rootNodes, EMPTY_ELEMENT_CONTEXT); + errors.push.apply(errors, Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__spread"])(providerViewContext.errors)); + usedPipes.push.apply(usedPipes, Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__spread"])(bindingParser.getUsedPipes())); + } + else { + result = []; + } + this._assertNoReferenceDuplicationOnTemplate(result, errors); + if (errors.length > 0) { + return new TemplateParseResult(result, usedPipes, errors); + } + if (this.transforms) { + this.transforms.forEach(function (transform) { result = templateVisitAll(transform, result); }); + } + return new TemplateParseResult(result, usedPipes, errors); + }; + TemplateParser.prototype.expandHtml = function (htmlAstWithErrors, forced) { + if (forced === void 0) { forced = false; } + var errors = htmlAstWithErrors.errors; + if (errors.length == 0 || forced) { + // Transform ICU messages to angular directives + var expandedHtmlAst = expandNodes(htmlAstWithErrors.rootNodes); + errors.push.apply(errors, Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__spread"])(expandedHtmlAst.errors)); + htmlAstWithErrors = new ParseTreeResult(expandedHtmlAst.nodes, errors); + } + return htmlAstWithErrors; + }; + TemplateParser.prototype.getInterpolationConfig = function (component) { + if (component.template) { + return InterpolationConfig.fromArray(component.template.interpolation); + } + return undefined; + }; + /** @internal */ + TemplateParser.prototype._assertNoReferenceDuplicationOnTemplate = function (result, errors) { + var existingReferences = []; + result.filter(function (element) { return !!element.references; }) + .forEach(function (element) { return element.references.forEach(function (reference) { + var name = reference.name; + if (existingReferences.indexOf(name) < 0) { + existingReferences.push(name); + } + else { + var error$$1 = new TemplateParseError("Reference \"#" + name + "\" is defined several times", reference.sourceSpan, ParseErrorLevel.ERROR); + errors.push(error$$1); + } + }); }); + }; + return TemplateParser; +}()); +var TemplateParseVisitor = /** @class */ (function () { + function TemplateParseVisitor(reflector, config, providerViewContext, directives, _bindingParser, _schemaRegistry, _schemas, _targetErrors) { + var _this = this; + this.reflector = reflector; + this.config = config; + this.providerViewContext = providerViewContext; + this._bindingParser = _bindingParser; + this._schemaRegistry = _schemaRegistry; + this._schemas = _schemas; + this._targetErrors = _targetErrors; + this.selectorMatcher = new SelectorMatcher(); + this.directivesIndex = new Map(); + this.ngContentCount = 0; + // Note: queries start with id 1 so we can use the number in a Bloom filter! + this.contentQueryStartId = providerViewContext.component.viewQueries.length + 1; + directives.forEach(function (directive, index) { + var selector = CssSelector.parse(directive.selector); + _this.selectorMatcher.addSelectables(selector, directive); + _this.directivesIndex.set(directive, index); + }); + } + TemplateParseVisitor.prototype.visitExpansion = function (expansion, context) { return null; }; + TemplateParseVisitor.prototype.visitExpansionCase = function (expansionCase, context) { return null; }; + TemplateParseVisitor.prototype.visitText = function (text, parent) { + var ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR()); + var valueNoNgsp = replaceNgsp(text.value); + var expr = this._bindingParser.parseInterpolation(valueNoNgsp, text.sourceSpan); + return expr ? new BoundTextAst(expr, ngContentIndex, text.sourceSpan) : + new TextAst(valueNoNgsp, ngContentIndex, text.sourceSpan); + }; + TemplateParseVisitor.prototype.visitAttribute = function (attribute, context) { + return new AttrAst(attribute.name, attribute.value, attribute.sourceSpan); + }; + TemplateParseVisitor.prototype.visitComment = function (comment, context) { return null; }; + TemplateParseVisitor.prototype.visitElement = function (element, parent) { + var _this = this; + var queryStartIndex = this.contentQueryStartId; + var elName = element.name; + var preparsedElement = preparseElement(element); + if (preparsedElement.type === PreparsedElementType.SCRIPT || + preparsedElement.type === PreparsedElementType.STYLE) { + // Skipping + + + + + diff --git a/src/gui/qt-daemon/html_source/src/karma.conf.js b/src/gui/qt-daemon/html_source/src/karma.conf.js new file mode 100644 index 00000000..b6e00421 --- /dev/null +++ b/src/gui/qt-daemon/html_source/src/karma.conf.js @@ -0,0 +1,31 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + dir: require('path').join(__dirname, '../coverage'), + reports: ['html', 'lcovonly'], + fixWebpackSourcePaths: true + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false + }); +}; \ No newline at end of file diff --git a/src/gui/qt-daemon/html_source/src/main.ts b/src/gui/qt-daemon/html_source/src/main.ts new file mode 100644 index 00000000..c7b673cf --- /dev/null +++ b/src/gui/qt-daemon/html_source/src/main.ts @@ -0,0 +1,12 @@ +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; +import { environment } from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic().bootstrapModule(AppModule) + .catch(err => console.error(err)); diff --git a/src/gui/qt-daemon/html_source/src/polyfills.ts b/src/gui/qt-daemon/html_source/src/polyfills.ts new file mode 100644 index 00000000..ee8b84da --- /dev/null +++ b/src/gui/qt-daemon/html_source/src/polyfills.ts @@ -0,0 +1,80 @@ +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE9, IE10 and IE11 requires all of the following polyfills. **/ +// import 'core-js/es6/symbol'; +// import 'core-js/es6/object'; +// import 'core-js/es6/function'; +// import 'core-js/es6/parse-int'; +// import 'core-js/es6/parse-float'; +// import 'core-js/es6/number'; +// import 'core-js/es6/math'; +// import 'core-js/es6/string'; +// import 'core-js/es6/date'; +// import 'core-js/es6/array'; +// import 'core-js/es6/regexp'; +// import 'core-js/es6/map'; +// import 'core-js/es6/weak-map'; +// import 'core-js/es6/set'; + +/** + * If the application will be indexed by Google Search, the following is required. + * Googlebot uses a renderer based on Chrome 41. + * https://developers.google.com/search/docs/guides/rendering + **/ +// import 'core-js/es6/array'; + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** IE10 and IE11 requires the following for the Reflect API. */ +// import 'core-js/es6/reflect'; + +/** + * Web Animations `@angular/platform-browser/animations` + * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. + * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). + **/ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + */ + + // (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame + // (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + // (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + + /* + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + */ +// (window as any).__Zone_enable_cross_context_check = true; + +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +import 'zone.js/dist/zone'; // Included with Angular CLI. + + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ diff --git a/src/gui/qt-daemon/html_source/src/styles.scss b/src/gui/qt-daemon/html_source/src/styles.scss new file mode 100644 index 00000000..e2897c81 --- /dev/null +++ b/src/gui/qt-daemon/html_source/src/styles.scss @@ -0,0 +1,77 @@ +// BASE +@import 'assets/scss/base/mixins'; +@import 'assets/scss/base/null'; +@import 'assets/scss/base/theme'; +@import 'assets/scss/base/base'; + +// LAYOUT +@import 'assets/scss/layout/main'; +@import 'assets/scss/layout/settings'; +@import 'assets/scss/layout/sidebar'; +@import 'assets/scss/layout/wallet'; + +// MODULES +@import 'assets/scss/modules/head'; +@import 'assets/scss/modules/scroll'; +@import 'assets/scss/modules/table'; + + +html { + font-family: 'Open Sans', sans-serif; + font-size: 10px; +} + +body { + font-family: 'Open Sans', sans-serif; + font-size: 1.6rem; + width: 100vw; + height: 100vh; + + &.theme-dark { + background: #131921 url("assets/images/background-dark.png") no-repeat center; + background-size: cover; + } + + &.theme-gray { + background: #101417 url("assets/images/background-gray.png") no-repeat center; + background-size: cover; + } + + &.theme-white { + background: #eeeeee url("assets/images/background-white.png") no-repeat center; + background-size: cover; + } + + app-root { + display: flex; + width: 100%; + height: 100%; + } +} + + + + +.ngx-contextmenu .dropdown-menu { + border: solid 1px chartreuse; + background-color: darkgreen; + padding: 0; +} +.ngx-contextmenu li { + display: block; + border-top: solid 1px chartreuse; + text-transform: uppercase; + text-align: center; +} +.ngx-contextmenu li:first-child { + border-top:none; +} +.ngx-contextmenu a { + color:chartreuse; + display: block; + padding: 0.5em 1em; +} +.ngx-contextmenu a:hover { + color:darkgreen; + background-color:chartreuse; +} diff --git a/src/gui/qt-daemon/html_source/src/test.ts b/src/gui/qt-daemon/html_source/src/test.ts new file mode 100644 index 00000000..16317897 --- /dev/null +++ b/src/gui/qt-daemon/html_source/src/test.ts @@ -0,0 +1,20 @@ +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js/dist/zone-testing'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +declare const require: any; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); diff --git a/src/gui/qt-daemon/html_source/src/tsconfig.app.json b/src/gui/qt-daemon/html_source/src/tsconfig.app.json new file mode 100644 index 00000000..190fd300 --- /dev/null +++ b/src/gui/qt-daemon/html_source/src/tsconfig.app.json @@ -0,0 +1,11 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/app", + "types": [] + }, + "exclude": [ + "test.ts", + "**/*.spec.ts" + ] +} diff --git a/src/gui/qt-daemon/html_source/src/tsconfig.spec.json b/src/gui/qt-daemon/html_source/src/tsconfig.spec.json new file mode 100644 index 00000000..de773363 --- /dev/null +++ b/src/gui/qt-daemon/html_source/src/tsconfig.spec.json @@ -0,0 +1,18 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "test.ts", + "polyfills.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/src/gui/qt-daemon/html_source/src/tslint.json b/src/gui/qt-daemon/html_source/src/tslint.json new file mode 100644 index 00000000..52e2c1a5 --- /dev/null +++ b/src/gui/qt-daemon/html_source/src/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "app", + "camelCase" + ], + "component-selector": [ + true, + "element", + "app", + "kebab-case" + ] + } +} diff --git a/src/gui/qt-daemon/html_source/tsconfig.json b/src/gui/qt-daemon/html_source/tsconfig.json new file mode 100644 index 00000000..46aeded1 --- /dev/null +++ b/src/gui/qt-daemon/html_source/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "./", + "outDir": "./dist/out-tsc", + "sourceMap": true, + "declaration": false, + "module": "es2015", + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "target": "es5", + "typeRoots": [ + "node_modules/@types" + ], + "lib": [ + "es2018", + "dom" + ] + } +} diff --git a/src/gui/qt-daemon/html_source/tslint.json b/src/gui/qt-daemon/html_source/tslint.json new file mode 100644 index 00000000..6ddb6b29 --- /dev/null +++ b/src/gui/qt-daemon/html_source/tslint.json @@ -0,0 +1,131 @@ +{ + "rulesDirectory": [ + "node_modules/codelyzer" + ], + "rules": { + "arrow-return-shorthand": true, + "callable-types": true, + "class-name": true, + "comment-format": [ + true, + "check-space" + ], + "curly": true, + "deprecation": { + "severity": "warn" + }, + "eofline": true, + "forin": true, + "import-blacklist": [ + true, + "rxjs/Rx" + ], + "import-spacing": true, + "indent": [ + true, + "spaces" + ], + "interface-over-type-literal": true, + "label-position": true, + "max-line-length": [ + true, + 140 + ], + "member-access": false, + "member-ordering": [ + true, + { + "order": [ + "static-field", + "instance-field", + "static-method", + "instance-method" + ] + } + ], + "no-arg": true, + "no-bitwise": true, + "no-console": [ + true, + "debug", + "info", + "time", + "timeEnd", + "trace" + ], + "no-construct": true, + "no-debugger": true, + "no-duplicate-super": true, + "no-empty": false, + "no-empty-interface": true, + "no-eval": true, + "no-inferrable-types": [ + true, + "ignore-params" + ], + "no-misused-new": true, + "no-non-null-assertion": true, + "no-redundant-jsdoc": true, + "no-shadowed-variable": true, + "no-string-literal": false, + "no-string-throw": true, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": true, + "no-unnecessary-initializer": true, + "no-unused-expression": true, + "no-use-before-declare": true, + "no-var-keyword": true, + "object-literal-sort-keys": false, + "one-line": [ + true, + "check-open-brace", + "check-catch", + "check-else", + "check-whitespace" + ], + "prefer-const": true, + "quotemark": [ + true, + "single" + ], + "radix": true, + "semicolon": [ + true, + "always" + ], + "triple-equals": [ + true, + "allow-null-check" + ], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "unified-signatures": true, + "variable-name": false, + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type" + ], + "no-output-on-prefix": true, + "use-input-property-decorator": true, + "use-output-property-decorator": true, + "use-host-property-decorator": true, + "no-input-rename": true, + "no-output-rename": true, + "use-life-cycle-interface": true, + "use-pipe-transform-interface": true, + "component-class-suffix": true, + "directive-class-suffix": true + } +} diff --git a/src/gui/qt-daemon/main.cpp b/src/gui/qt-daemon/main.cpp new file mode 100644 index 00000000..41100040 --- /dev/null +++ b/src/gui/qt-daemon/main.cpp @@ -0,0 +1,59 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include "application/mainwindow.h" +#include "qdebug.h" +#include +//#include "qtlogger.h" +#include "include_base_utils.h" +#include "currency_core/currency_config.h" +#include + +// class MyApplication : public QApplication +// { +// +// +// } + +int main(int argc, char *argv[]) +{ +//#if defined(ARCH_CPU_X86_64) && _MSC_VER <= 1800 + // VS2013's CRT only checks the existence of FMA3 instructions, not the + // enabled-ness of them at the OS level (this is fixed in VS2015). We force + // off usage of FMA3 instructions in the CRT to avoid using that path and + // hitting illegal instructions when running on CPUs that support FMA3, but + // OSs that don't. Because we use the static library CRT we have to call + // this function once in each DLL. + // See http://crbug.com/436603. +// _set_FMA3_enable(0); +//#endif // ARCH_CPU_X86_64 && _MSC_VER <= 1800 + +#ifdef _MSC_VER + #ifdef _WIN64 + _set_FMA3_enable(0); + #endif + //mutex to let InnoSetup know about running instance + ::CreateMutex(NULL, FALSE, CURRENCY_NAME_BASE "_instance"); + //::CreateMutex(NULL, FALSE, "Global\\" CURRENCY_NAME_BASE "_instance"); +#endif + + + epee::string_tools::set_module_name_and_folder(argv[0]); + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QApplication app(argc, argv); + MainWindow viewer; + if (!viewer.init_backend(argc, argv)) + { + static_cast(&viewer)->show_msg_box("Failed to initialize backend, check debug logs for more details."); + return 1; + } + app.installNativeEventFilter(&viewer); + viewer.setWindowTitle(CURRENCY_NAME_BASE); + viewer.show_inital(); + + return app.exec(); +} diff --git a/src/gui/qt-daemon/qtlogger.h b/src/gui/qt-daemon/qtlogger.h new file mode 100644 index 00000000..b1ff2e76 --- /dev/null +++ b/src/gui/qt-daemon/qtlogger.h @@ -0,0 +1,133 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include + +//#define QT_CONSOLE_STREAM qDebug() + +#define QT_CONSOLE_STREAM(s) \ +{std::stringstream ss; ss << s; fputs(ss.str().c_str(), stderr); fflush(stderr);} + + + +//fputs(buf.c_str(), stderr); +//fflush(stderr); + + +void customHandler(QtMsgType type, const char* msg) { + fputs(msg, stderr); + fflush(stderr); +} + + +class qt_console_stream : public epee::log_space::ibase_log_stream +{ + QDebug db; +public: + qt_console_stream() : db(qDebug()) + { + // Somewhere in your program + //qInstallMsgHandler(customHandler); + } + + ~qt_console_stream() + { + } + + int get_type(){ return LOGGER_CONSOLE; } + + inline void set_console_color(int color, bool bright) + { + switch (color) + { + case epee::log_space::console_color_default: + if (bright) + {QT_CONSOLE_STREAM("\033[1;37m");} + else + {QT_CONSOLE_STREAM("\033[0m");} + break; + case epee::log_space::console_color_white: + if (bright) + {QT_CONSOLE_STREAM("\033[1;37m");} + else + {QT_CONSOLE_STREAM("\033[0;37m");} + break; + case epee::log_space::console_color_red: + if (bright) + {QT_CONSOLE_STREAM("\033[1;31m");} + else + {QT_CONSOLE_STREAM("\033[0;31m");} + break; + case epee::log_space::console_color_green: + if (bright) + {QT_CONSOLE_STREAM("\033[1;32m");} + else + {QT_CONSOLE_STREAM("\033[0;32m");} + break; + + case epee::log_space::console_color_blue: + if (bright) + {QT_CONSOLE_STREAM("\033[1;34m");} + else + {QT_CONSOLE_STREAM("\033[0;34m");} + break; + + case epee::log_space::console_color_cyan: + if (bright) + {QT_CONSOLE_STREAM("\033[1;36m");} + else + {QT_CONSOLE_STREAM("\033[0;36m");} + break; + + case epee::log_space::console_color_magenta: + if (bright) + {QT_CONSOLE_STREAM("\033[1;35m");} + else + {QT_CONSOLE_STREAM("\033[0;35m");} + break; + + case epee::log_space::console_color_yellow: + if (bright) + {QT_CONSOLE_STREAM("\033[1;33m");} + else + {QT_CONSOLE_STREAM("\033[0;33m");} + break; + + } + } + + inline void reset_console_color() + { + {QT_CONSOLE_STREAM("\033[0m");} + } + + virtual bool out_buffer(const char* buffer, int buffer_len, int log_level, int color, const char* plog_name = NULL) + { + if (plog_name) + return true; //skip alternative logs from console + + set_console_color(color, log_level < 1); + + std::string buf(buffer, buffer_len); + for (size_t i = 0; i != buf.size(); i++) + { + if (buf[i] == 7 || buf[i] == -107) + buf[i] = '^'; + //remove \n + //if (i == buf.size()-1) + // buf[i] = ' '; + } + + QT_CONSOLE_STREAM(buf.c_str()); + + + reset_console_color(); + return true; + } + + +}; diff --git a/src/miner/simpleminer.cpp b/src/miner/simpleminer.cpp new file mode 100644 index 00000000..9ae89e4c --- /dev/null +++ b/src/miner/simpleminer.cpp @@ -0,0 +1,747 @@ +// Copyright (c) 2014-2017 The The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + + +#include "common/command_line.h" +#include "misc_log_ex.h" +#include "simpleminer.h" +#include "target_helper.h" +#include "net/http_server_handlers_map2.h" +#include "rpc/mining_protocol_defs.h" +#include "storages/http_abstract_invoke.h" +#include "string_tools.h" +#include "currency_core/account.h" +#include "currency_core/currency_format_utils.h" +#include "rpc/core_rpc_server_commands_defs.h" +#include "currency_core/miner_common.h" +#ifndef WIN32 +#include +#endif + +using namespace epee; +namespace po = boost::program_options; + +int main(int argc, char** argv) +{ + string_tools::set_module_name_and_folder(argv[0]); +// +// //set up logging options +// log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2); +// log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL); +// log_space::log_singletone::add_logger(LOGGER_FILE, +// log_space::log_singletone::get_default_log_file().c_str(), +// log_space::log_singletone::get_default_log_folder().c_str()); +// +// po::options_description desc("Allowed options"); +// command_line::add_arg(desc, command_line::arg_help); +// mining::simpleminer::init_options(desc); +// +// //uint32_t t = mining::get_target_for_difficulty(700000); +// +// po::variables_map vm; +// bool r = command_line::handle_error_helper(desc, [&]() +// { +// po::store(po::parse_command_line(argc, argv, desc), vm); +// po::notify(vm); +// +// if (command_line::get_arg(vm, command_line::arg_help)) +// { +// std::cout << desc << std::endl; +// return false; +// } +// +// return true; +// }); +// if (!r) +// return 1; +// +// +// while (1) { +// mining::simpleminer miner; +// r = miner.init(vm); +// r = r && miner.run(); // Returns on too many failures +// LOG_PRINT_L0("Excessive failures. Sleeping 10-ish seconds and restarting..."); +// epee::misc_utils::sleep_no_w(10000 + (crypto::rand() % 5000)); +// } + + return 0; +} +// /* +// namespace mining +// { +// const command_line::arg_descriptor arg_pool_addr = {"pool-addr", ""}; +// const command_line::arg_descriptor arg_login = {"login", ""}; +// const command_line::arg_descriptor arg_pass = {"pass", ""}; +// const command_line::arg_descriptor arg_mining_threads = { "mining-threads", "Specify mining threads count", 1, true }; +// const command_line::arg_descriptor arg_scratchpad_url = { "remote-scratchpad", "Specify URL to remote scratchpad"}; +// const command_line::arg_descriptor arg_scratchpad_local = { "local-scratchpad", "Specify URL to remote scratchpad ", "", true }; +// +// static const int attempts_per_loop = 5000; +// +// +// //----------------------------------------------------------------------------------------------------- +// void simpleminer::init_options(boost::program_options::options_description& desc) +// { +// command_line::add_arg(desc, arg_pool_addr); +// command_line::add_arg(desc, arg_login); +// command_line::add_arg(desc, arg_pass); +// command_line::add_arg(desc, arg_mining_threads); +// command_line::add_arg(desc, arg_scratchpad_url); +// command_line::add_arg(desc, arg_scratchpad_local); +// } +// //----------------------------------------------------------------------------------------------------- +// bool try_mkdir_chdir(const std::string& dirn) +// { +// boost::system::error_code ec; +// if(boost::filesystem::exists(dirn, ec)) +// { +// return true; +// } +// +// boost::filesystem::create_directories("/some/path", ec); +// return !ec; +// } +// //----------------------------------------------------------------------------------------------------- +// std::string get_default_local_cache_path() +// { +// #if defined(_WIN64) || defined(_WIN32) +// const char* phome_var_name = "LOCALAPPDATA"; +// #else +// const char* phome_var_name = "HOME"; +// #endif +// if (!getenv(phome_var_name)) +// { +// LOG_ERROR("Env variable " << phome_var_name << " not set"); +// return ""; +// } +// +// std::string default_local_path = getenv(phome_var_name); +// #if !defined(_WIN64) && !defined(_WIN32) +// default_local_path += "/.cache"; +// #else +// default_local_path += "/" CURRENCY_NAME; +// #endif +// if (!try_mkdir_chdir(default_local_path) ) +// { +// LOG_ERROR("Failed to create a dir " << getenv(phome_var_name)); +// return ""; +// } +// return default_local_path + "/" SCRATCHPAD_DEFAULT_FILENAME; +// } +// //-------------------------------------------------------------------------------------------------------------------------------- +// bool simpleminer::reset_scratchpad() +// { +// m_blocks_addendums.clear(); +// m_hi = AUTO_VAL_INIT(m_hi); +// m_scratchpad.clear(); +// return true; +// } +// //-------------------------------------------------------------------------------------------------------------------------------- +// bool simpleminer::store_scratchpad_to_file(const std::string& path) +// { +// std::string buff; +// buff.resize(sizeof(export_scratchpad_file_header) + m_scratchpad.size()*32, 0); +// +// uint8_t* pbuff = const_cast(reinterpret_cast(buff.data())); +// export_scratchpad_file_header* pheader = reinterpret_cast(pbuff); +// pheader->current_hi.height = m_hi.height; +// pheader->current_hi.prevhash = m_hi.id; +// pheader->scratchpad_size = m_scratchpad.size()*4; +// pbuff += sizeof(export_scratchpad_file_header); +// memcpy(pbuff, &m_scratchpad[0], m_scratchpad.size()*32); +// +// if(!file_io_utils::save_string_to_file(path, buff)) +// { +// LOG_ERROR("Failed to save scratchpad local cache to " << path); +// return false; +// } +// m_last_scratchpad_store_time = time(NULL); +// return true; +// } +// //-------------------------------------------------------------------------------------------------------------------------------- +// bool simpleminer::load_scratchpad_from_file(const std::string& path) +// { +// reset_scratchpad(); +// if(!path.size()) +// { +// LOG_ERROR("Empty scratchpad file path"); +// return false; +// } +// boost::system::error_code ec; +// time_t file_time = boost::filesystem::last_write_time(path, ec); +// if(ec) +// { +// LOG_PRINT_L0("Local scratchpad cache (" << path << ") not found"); +// return false; +// } +// +// if(time(NULL) - file_time > LOCAL_SCRATCHPAD_CACHE_EXPIRATION_INTERVAL ) +// { +// /*scratchpad older than 5 days, better to redownload*/ +// LOG_PRINT_L0("Local scratchpad cache (" << path << ") is older that 5 days, downloading new..."); +// return false; +// } +// +// +// std::string buff; +// if(!epee::file_io_utils::load_file_to_string(path, buff)) +// { +// LOG_PRINT_L0("Local scratchpad cache (" << path << ") not found"); +// return false; +// } +// +// if(buff.size() < sizeof(export_scratchpad_file_header)) +// { +// LOG_ERROR("Wrong scratchpad file size: " << buff.size() << " in file " << path); +// return false; +// } +// +// const uint8_t* pbuff = reinterpret_cast(buff.data()); +// const export_scratchpad_file_header* pscr_header = reinterpret_cast(pbuff); +// +// if(pscr_header->scratchpad_size*8 != buff.size()-sizeof(export_scratchpad_file_header) || pscr_header->scratchpad_size%4) +// { +// LOG_ERROR("File size and export_scratchpad_file_header mismatch, " << path); +// return false; +// } +// +// /* +// TODO: refactor copy addendums array +// for(int i = 0; i != WILD_KECCAK_ADDENDUMS_ARRAY_SIZE; i++) +// { +// m_blocks_addendums.push_back(mining::addendum()); +// m_blocks_addendums.back().hi.block_id = pscr_header->add_arr[i].prev_hi +// }*/ +// +// m_hi.height = pscr_header->current_hi.height; +// m_hi.id = pscr_header->current_hi.prevhash; +// m_scratchpad.resize(pscr_header->scratchpad_size/4); +// +// pbuff+= sizeof(export_scratchpad_file_header); +// memcpy(&m_scratchpad[0], pbuff, buff.size()-sizeof(export_scratchpad_file_header)); +// m_last_scratchpad_store_time = file_time; +// +// return true; +// } +// //-------------------------------------------------------------------------------------------------------------------------------- +// bool simpleminer::init_scratchpad() +// { +// //let's try to lookup scratchpad in local cache and then, if it not there - try to fetch it from server +// if(!load_scratchpad_from_file(m_scratchpad_local_path)) +// { +// //failed, try to fetch it from server +// if(!m_scratchpad_url.size()) +// { +// LOG_ERROR("Local scratchpad chache not found, and scratchpad url not found"); +// return false; +// } +// +// epee::net_utils::http::http_simple_client http_client; +// const epee::net_utils::http::http_response_info *prespinfo = NULL; +// LOG_PRINT_L0("Downloading remote scrathcpad from " << m_scratchpad_url << "..."); +// if(!epee::net_utils::http::invoke_request(m_scratchpad_url, http_client, 10000, &prespinfo)) +// { +// LOG_ERROR("Local scratchpad chache not found, and scratchpad url not found"); +// return false; +// } +// LOG_PRINT_L0("Remote scratchpad downloaded, size " << prespinfo->m_body.size()/1024 << "Kb"); +// if(!file_io_utils::save_string_to_file(m_scratchpad_local_path, prespinfo->m_body)) +// { +// LOG_ERROR("Failed to store local scratchpad file to path " << m_scratchpad_local_path); +// return false; +// } +// +// //let's try to load it once again +// if(!load_scratchpad_from_file(m_scratchpad_local_path)) +// { +// LOG_ERROR("Local scratchpad chache not found, and scratchpad url not found"); +// return false; +// } +// } +// update_fast_scratchpad(); +// +// LOG_PRINT_L0("Scratchpad loaded okay, hashes count: " << m_scratchpad.size()); +// return true; +// } +// //-------------------------------------------------------------------------------------------------------------------------------- +// bool simpleminer::init(const boost::program_options::variables_map& vm) +// { +// std::string pool_addr = command_line::get_arg(vm, arg_pool_addr); +// //parse ip and address +// std::string::size_type p = pool_addr.find(':'); +// CHECK_AND_ASSERT_MES(p != std::string::npos && (p + 1 != pool_addr.size()), false, "Wrong srv address syntax"); +// m_pool_ip = pool_addr.substr(0, p); +// m_pool_port = pool_addr.substr(p + 1, pool_addr.size()); +// m_login = command_line::get_arg(vm, arg_login); +// m_threads_total = 1; +// if(command_line::has_arg(vm, arg_mining_threads)) +// { +// m_threads_total = command_line::get_arg(vm, arg_mining_threads); +// LOG_PRINT_L0("Mining with " << m_threads_total << " threads "); +// } +// m_pass = command_line::get_arg(vm, arg_pass); +// m_hi = AUTO_VAL_INIT(m_hi); +// m_last_job_ticks = 0; +// m_last_scratchpad_store_time = 0; +// m_fast_scratchpad_pages = 0; +// m_fast_scratchpad = NULL; +// +// if(command_line::has_arg(vm, arg_scratchpad_url)) +// { +// m_scratchpad_url = command_line::get_arg(vm, arg_scratchpad_url); +// } +// +// if(command_line::has_arg(vm, arg_scratchpad_local)) +// { +// m_scratchpad_local_path = command_line::get_arg(vm, arg_scratchpad_local); +// }else +// { +// m_scratchpad_local_path = get_default_local_cache_path(); +// } +// if(!init_scratchpad()) +// { +// LOG_ERROR("Failed to init scratchpad"); +// return false; +// } +// return true; +// } +// //-------------------------------------------------------------------------------------------------------------------------------- +// bool simpleminer::text_height_info_to_native_height_info(const height_info& hi, height_info_native& hi_native) +// { +// hi_native.height = hi.height; +// bool r = string_tools::hex_to_pod(hi.block_id, hi_native.id); +// CHECK_AND_ASSERT_MES(r, false, "wrong block_id: " << hi.block_id); +// return true; +// } +// //-------------------------------------------------------------------------------------------------------------------------------- +// bool simpleminer::native_height_info_to_text_height_info(height_info& hi, const height_info_native& hi_native) +// { +// hi.height = hi_native.height; +// hi.block_id = string_tools::pod_to_hex(hi_native.id); +// return true; +// } +// //-------------------------------------------------------------------------------------------------------------------------------- +// void simpleminer::worker_thread(uint64_t start_nonce, uint32_t nonce_offset, std::atomic *result, std::atomic *do_reset, std::atomic *done) { +// // printf("Worker thread starting at %lu + %u\n", start_nonce, nonce_offset); +// currency::blobdata blob = m_job.blob; +// while (!*do_reset) { +// m_hashes_done += attempts_per_loop; +// for (int i = 0; i < attempts_per_loop; i++) { +// (*reinterpret_cast(&blob[1])) = (start_nonce+nonce_offset); +// crypto::hash h = currency::null_hash; +// currency::get_blob_longhash(blob, h, m_job.prev_hi.height+1, [&](uint64_t index) -> crypto::hash& +// { +// return m_fast_scratchpad[index%m_scratchpad.size()]; +// }); +// +// if( currency::check_hash(h, m_job.difficulty)) +// { +// (*result) = nonce_offset; +// (*done) = true; +// (*do_reset) = true; +// m_work_done_cond.notify_one(); +// return; +// } +// nonce_offset++; +// } +// nonce_offset += ((m_threads_total-1) * attempts_per_loop); +// } +// } +// +// //-------------------------------------------------------------------------------------------------------------------------------- +// bool simpleminer::run() +// { +// m_job = AUTO_VAL_INIT(m_job); +// uint64_t search_start = epee::misc_utils::get_tick_count(); +// uint64_t hashes_done = 0; +// uint32_t job_submit_failures = 0; +// bool re_get_scratchpad = false; +// +// while(true) +// { +// bool job_received = false; +// //----------------- +// if(!m_http_client.is_connected()) +// { +// LOG_PRINT_L0("Connecting " << m_pool_ip << ":" << m_pool_port << "...."); +// if(!m_http_client.connect(m_pool_ip, m_pool_port, 20000)) +// { +// LOG_PRINT_L0("Failed to connect " << m_pool_ip << ":" << m_pool_port << ", sleep...."); +// epee::misc_utils::sleep_no_w(1000); +// continue; +// } +// m_http_client.get_socket().set_option(boost::asio::ip::tcp::no_delay(true)); +// //DO AUTH +// LOG_PRINT_L0("Connected " << m_pool_ip << ":" << m_pool_port << " OK"); +// COMMAND_RPC_LOGIN::request req = AUTO_VAL_INIT(req); +// req.login = m_login; +// req.pass = m_pass; +// req.agent = "simpleminer/0.1"; +// native_height_info_to_text_height_info(req.hi, m_hi); +// bool job_requested = m_hi.height ? true:false; +// COMMAND_RPC_LOGIN::response resp = AUTO_VAL_INIT(resp); +// if(!epee::net_utils::invoke_http_json_rpc("/json_rpc", req, resp, m_http_client)) +// { +// LOG_PRINT_L0("Failed to invoke login " << m_pool_ip << ":" << m_pool_port << ", disconnect and sleep...."); +// m_http_client.disconnect(); +// epee::misc_utils::sleep_no_w(1000); +// continue; +// } +// if(resp.status != CORE_RPC_STATUS_OK || resp.id.empty()) +// { +// LOG_PRINT_L0("Failed to login " << m_pool_ip << ":" << m_pool_port << ", disconnect and sleep...."); +// m_http_client.disconnect(); +// epee::misc_utils::sleep_no_w(1000); +// continue; +// } +// +// m_pool_session_id = resp.id; +// if (re_get_scratchpad || !m_hi.height || !m_scratchpad.size()) +// { +// if (!reinit_scratchpad()) +// continue; +// re_get_scratchpad = false; +// } +// else if(!apply_addendums(resp.job.addms)) +// { +// LOG_PRINT_L0("Failed to apply_addendum, requesting full scratchpad..."); +// if (!reinit_scratchpad()) +// continue; +// } +// +// if (job_requested && resp.job.blob.empty() && resp.job.difficulty.empty() && resp.job.job_id.empty()) +// { +// LOG_PRINT_L0("Job didn't change"); +// continue; +// } +// else if(job_requested && !text_job_details_to_native_job_details(resp.job, m_job)) +// { +// LOG_PRINT_L0("Failed to text_job_details_to_native_job_details(), disconnect and sleep...."); +// m_http_client.disconnect(); +// epee::misc_utils::sleep_no_w(1000); +// continue; +// } +// if(job_requested) +// { +// m_last_job_ticks = epee::misc_utils::get_tick_count(); +// job_received = true; +// } +// +// } +// +// if(!job_received) +// { +// uint64_t get_job_start_time = epee::misc_utils::get_tick_count(); +// if(!get_job()) /* Next version: Handle this asynchronously */ +// { +// continue; +// } +// +// uint64_t get_job_end_time = epee::misc_utils::get_tick_count(); +// if ((get_job_end_time - get_job_start_time) > 1000) +// { +// LOG_PRINT_L0("slow pool response " << (get_job_end_time - get_job_start_time) << " ms"); +// } +// } +// +// update_fast_scratchpad(); +// +// uint64_t start_nonce = (*reinterpret_cast(&m_job.blob[1])) + 1000000; +// std::list threads; +// std::atomic results[128]; +// std::atomic do_reset(false); +// std::atomic done(false); +// +// if (m_threads_total > 128) { +// LOG_PRINT_L0("Sorry - simpleminer does not support more than 128 threads right now"); +// m_threads_total = 128; +// } +// +// m_hashes_done = 0; /* Used to calculate offset to push back into job */ +// +// uint32_t nonce_offset = 0; +// for (unsigned int i = 0; i < m_threads_total; i++) +// { +// results[i] = 0; +// threads.push_back(boost::thread(&simpleminer::worker_thread, this, start_nonce, nonce_offset, &results[i], &do_reset, &done)); +// nonce_offset += attempts_per_loop; +// } +// +// +// while(!done && epee::misc_utils::get_tick_count() - m_last_job_ticks < 20000) +// { +// std::unique_lock lck(m_work_mutex); +// m_work_done_cond.wait_for(lck, std::chrono::seconds(1)); +// } +// +// do_reset = true; +// BOOST_FOREACH(boost::thread& th, threads) +// { +// th.join(); +// } +// for (unsigned int i = 0; i < m_threads_total; i++) { +// if (results[i] != 0) { +// (*reinterpret_cast(&m_job.blob[1])) = (start_nonce + results[i]); +// crypto::hash h = currency::null_hash; +// currency::get_blob_longhash(m_job.blob, h, m_job.prev_hi.height+1, [&](uint64_t index) -> crypto::hash& +// { +// return m_scratchpad[index%m_scratchpad.size()]; +// }); +// +// if( currency::check_hash(h, m_job.difficulty)) +// { +// //<< ", id" << currency::get_blob_hash(m_job.blob) << ENDL +// //found! +// COMMAND_RPC_SUBMITSHARE::request submit_request = AUTO_VAL_INIT(submit_request); +// COMMAND_RPC_SUBMITSHARE::response submit_response = AUTO_VAL_INIT(submit_response); +// submit_request.id = m_pool_session_id; +// submit_request.job_id = m_job.job_id; +// submit_request.nonce = (*reinterpret_cast(&m_job.blob[1])); +// submit_request.result = string_tools::buff_to_hex_nodelimer(std::string((char*) &h, HASH_SIZE)); +// LOG_PRINT_GREEN("Share found: nonce=" << submit_request.nonce << " for job=" << m_job.job_id << ", diff: " << m_job.difficulty << ENDL +// << ", PoW:" << h << ", height:" << m_job.prev_hi.height+1 << ", submitting...", LOG_LEVEL_0); +// +// //LOG_PRINT_L0("Block hashing blob: " << string_tools::buff_to_hex_nodelimer(m_job.blob)); +// //LOG_PRINT_L0("scratch_pad: " << currency::dump_scratchpad(m_scratchpad)); +// if(!epee::net_utils::invoke_http_json_rpc("/json_rpc", submit_request, submit_response, m_http_client)) +// { +// /* Failed to submit a job. This can happen because of disconnection, +// * server failure, or block expiry. In any event, try to get +// * a new job. If the job fetch fails, get_job will disconnect +// * and sleep for us */ +// LOG_PRINT_L0("Failed to submit share! Updating job."); +// job_submit_failures++; +// } +// else if(submit_response.status != "OK") +// { +// LOG_PRINT_L0("Failed to submit share! (submitted share rejected). Updating job."); +// job_submit_failures++; +// } +// else +// { +// LOG_PRINT_GREEN("Share submitted successfully!", LOG_LEVEL_0); +// job_submit_failures = 0; +// } +// break; /* One submission per job id */ +// } +// else +// { +// LOG_PRINT_L0("share did not pass diff revalidation"); +// } +// } +// } +// +// start_nonce += m_hashes_done; +// hashes_done += m_hashes_done; +// m_hashes_done = 0; +// +// (*reinterpret_cast(&m_job.blob[1])) = start_nonce; +// if (job_submit_failures == 5) +// { +// LOG_PRINT_L0("Too many submission failures. Something is very wrong."); +// free_fast_scratchpad(); +// return false; +// } +// if (job_submit_failures > 3) +// { +// re_get_scratchpad = true; +// /* note fallthrough into next case to also reconnect */ +// } +// if (job_submit_failures > 1) +// { +// m_http_client.disconnect(); +// epee::misc_utils::sleep_no_w(1000); +// } else { +// uint64_t loop_end_time = epee::misc_utils::get_tick_count(); +// uint64_t hash_rate = (hashes_done * 1000) / ((loop_end_time - search_start) + 1); +// LOG_PRINT_L0("avg hr: " << hash_rate); +// } +// } +// free_fast_scratchpad(); +// return true; +// } +// //---------------------------------------------------------------------------------------------------------------------------------- +// bool simpleminer::reinit_scratchpad() +// { +// init_scratchpad(); +// return true; +// } +// //---------------------------------------------------------------------------------------------------------------------------------- +// void simpleminer::free_fast_scratchpad() +// { +// if (m_fast_scratchpad) +// { +// if (m_fast_mmapped) +// { +// #ifndef WIN32 +// munmap(m_fast_scratchpad, m_fast_scratchpad_pages*4096); +// #endif +// } else { +// free(m_fast_scratchpad); +// } +// m_fast_scratchpad = NULL; +// } +// } +// +// void simpleminer::update_fast_scratchpad() +// { +// +// /* Check size - reallocate fast scratch if necessary */ +// size_t cur_scratchpad_size = m_scratchpad.size() * sizeof(crypto::hash); +// size_t cur_scratchpad_pages = (cur_scratchpad_size / 4096) + 1; +// if (cur_scratchpad_pages > m_fast_scratchpad_pages) +// { +// free_fast_scratchpad(); +// void *addr = nullptr; +// size_t mapsize = cur_scratchpad_pages * 4096; +// #ifdef MAP_HUGETLB +// addr = MAP_FAILED; +// addr = mmap(0, mapsize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB|MAP_POPULATE, 0, 0); +// if (addr == MAP_FAILED) +// { +// LOG_PRINT_L0("Unable to mmap huge pages. Enable for faster operation."); +// addr = nullptr; +// } +// #endif +// if (addr == nullptr) { +// addr = malloc(mapsize); +// } else { +// m_fast_mmapped = true; +// } +// m_fast_scratchpad_pages = cur_scratchpad_pages; +// m_fast_scratchpad = (crypto::hash *)addr; +// } +// +// memcpy(m_fast_scratchpad, &m_scratchpad[0], m_scratchpad.size() * sizeof(crypto::hash)); +// } +// +// //---------------------------------------------------------------------------------------------------------------------------------- +// bool simpleminer::pop_addendum(const addendum& add) +// { +// std::vector add_vec; +// bool r = currency::hexstr_to_addendum(add.addm, add_vec); +// CHECK_AND_ASSERT_MES(r, false, "failed to hexstr_to_addendum"); +// CHECK_AND_ASSERT_MES(m_scratchpad.size() > add_vec.size(), false, "error: to big addendum or to small local scratchpad"); +// +// std::map patch; +// currency::get_scratchpad_patch(m_scratchpad.size() - add_vec.size(), +// 0, +// add_vec.size(), +// add_vec, +// patch); +// r = currency::apply_scratchpad_patch(m_scratchpad, patch); +// CHECK_AND_ASSERT_MES(r, false, "failed to apply patch"); +// m_scratchpad.resize(m_scratchpad.size() - add_vec.size()); +// return true; +// } +// //---------------------------------------------------------------------------------------------------------------------------------- +// bool simpleminer::push_addendum(const addendum& add) +// { +// std::vector add_vec; +// bool r = currency::hexstr_to_addendum(add.addm, add_vec); +// CHECK_AND_ASSERT_MES(r, false, "failed to hexstr_to_addendum"); +// +// std::map patch; +// currency::get_scratchpad_patch(m_scratchpad.size(), +// 0, +// add_vec.size(), +// add_vec, +// patch); +// r = currency::apply_scratchpad_patch(m_scratchpad, patch); +// CHECK_AND_ASSERT_MES(r, false, "failed to apply patch"); +// for(const auto& h: add_vec) +// m_scratchpad.push_back(h); +// +// return true; +// } +// //---------------------------------------------------------------------------------------------------------------------------------- +// bool simpleminer::apply_addendums(const std::list& addms) +// { +// if(!addms.size()) +// return true; +// crypto::hash pid = currency::null_hash; +// bool r = string_tools::hex_to_pod(addms.begin()->prev_id, pid); +// CHECK_AND_ASSERT_MES(r, false, "wrong prev_id"); +// if(pid != m_hi.id) +// { +// LOG_PRINT_L0("Split detected, looking for patch"); +// +// auto it = std::find_if(m_blocks_addendums.begin(), m_blocks_addendums.end(),[&](const mining::addendum& a){ +// if(a.hi.block_id == addms.begin()->prev_id) +// return true; +// else +// return false; +// }); +// if(it == m_blocks_addendums.end()) +// return false; +// //unpatch +// size_t count = 0; +// for(auto it_to_patch = --m_blocks_addendums.end(); it_to_patch != it; --it) +// { +// r = pop_addendum(*it_to_patch); +// CHECK_AND_ASSERT_MES(r, false, "failed to pop_addendum()"); +// ++count; +// } +// +// m_blocks_addendums.erase(++it, m_blocks_addendums.end()); +// LOG_PRINT_L0("Numbers of blocks removed from scratchpad: " << count); +// } +// +// //append scratchpad with new blocks +// for(const auto& a: addms) +// { +// r = push_addendum(a); +// CHECK_AND_ASSERT_MES(r, false, "failed to push_addendum()"); +// } +// LOG_PRINT_L0("Numbers of blocks added to scratchpad: " << addms.size()); +// text_height_info_to_native_height_info(addms.back().hi, m_hi); +// return true; +// } +// //---------------------------------------------------------------------------------------------------------------------------------- +// bool simpleminer::get_job() +// { +// //get next job +// COMMAND_RPC_GETJOB::request getjob_request = AUTO_VAL_INIT(getjob_request); +// COMMAND_RPC_GETJOB::response getjob_response = AUTO_VAL_INIT(getjob_response); +// getjob_request.id = m_pool_session_id; +// native_height_info_to_text_height_info(getjob_request.hi, m_hi); +// LOG_PRINT_L0("Getting next job..."); +// if(!epee::net_utils::invoke_http_json_rpc("/json_rpc", getjob_request, getjob_response, m_http_client)) +// { +// LOG_PRINT_L0("Can't get new job! Disconnect and sleep...."); +// m_http_client.disconnect(); +// epee::misc_utils::sleep_no_w(1000); +// return false; +// } +// if (getjob_response.jd.blob.empty() && getjob_response.jd.difficulty.empty() && getjob_response.jd.job_id.empty()) +// { +// LOG_PRINT_L0("Job didn't change"); +// } +// else if(!text_job_details_to_native_job_details(getjob_response.jd, m_job)) +// { +// LOG_PRINT_L0("Failed to text_job_details_to_native_job_details(), disconnect and sleep...."); +// m_http_client.disconnect(); +// epee::misc_utils::sleep_no_w(1000); +// return false; +// } +// //apply addendum +// if(!apply_addendums(getjob_response.jd.addms)) +// { +// LOG_PRINT_L0("Failed to apply_addendum, requesting full scratchpad..."); +// reinit_scratchpad(); +// return true; +// } +// +// if(time(NULL) - m_last_scratchpad_store_time > LOCAL_SCRATCHPAD_CACHE_STORE_INTERVAL) +// { +// store_scratchpad_to_file(m_scratchpad_local_path); +// } +// +// m_last_job_ticks = epee::misc_utils::get_tick_count(); +// +// return true; +// } +// //---------------------------------------------------------------------------------------------------------------------------------- +// } diff --git a/src/miner/simpleminer.h b/src/miner/simpleminer.h new file mode 100644 index 00000000..104afe6f --- /dev/null +++ b/src/miner/simpleminer.h @@ -0,0 +1,98 @@ +// Copyright (c) 2014-2017 The The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include "net/http_client.h" +#include "currency_protocol/blobdatatype.h" +#include "rpc/mining_protocol_defs.h" +#include "currency_core/difficulty.h" +#include +#include + + +#define LOCAL_SCRATCHPAD_CACHE_EXPIRATION_INTERVAL 60*60*24*3 //3 days +#define LOCAL_SCRATCHPAD_CACHE_STORE_INTERVAL 60*60*12 //12 hours + +/* +namespace mining +{ + class simpleminer + { + public: + static void init_options(boost::program_options::options_description& desc); + bool init(const boost::program_options::variables_map& vm); + bool run(); + private: + + struct height_info_native + { + uint64_t height; + crypto::hash id; + }; + + struct job_details_native + { + currency::blobdata blob; + currency::difficulty_type difficulty; + std::string job_id; + height_info_native prev_hi; + }; + + + static bool text_height_info_to_native_height_info(const height_info& job, height_info_native& hi_native); + static bool native_height_info_to_text_height_info(height_info& job, const height_info_native& hi_native); + + template + bool text_job_details_to_native_job_details(const job_details_t& job, simpleminer::job_details_native& native_details) + { + bool r = epee::string_tools::parse_hexstr_to_binbuff(job.blob, native_details.blob); + CHECK_AND_ASSERT_MES(r, false, "wrong buffer sent from pool server"); + r = epee::string_tools::get_xtype_from_string(native_details.difficulty, job.difficulty); + CHECK_AND_ASSERT_MES(r, false, "wrong buffer sent from pool server"); + native_details.job_id = job.job_id; + + return text_height_info_to_native_height_info(job.prev_hi, native_details.prev_hi); + } + + + + bool get_job(); + bool reinit_scratchpad(); + bool apply_addendums(const std::list& addms); + bool pop_addendum(const addendum& add); + bool push_addendum(const addendum& add); + void worker_thread(uint64_t start_nonce, uint32_t nonce_offset, std::atomic *result, std::atomic *do_reset, std::atomic *done); + void update_fast_scratchpad(); + void free_fast_scratchpad(); + bool init_scratchpad(); + bool reset_scratchpad(); + bool load_scratchpad_from_file(const std::string& path); + bool store_scratchpad_to_file(const std::string& path); + + std::vector m_blocks_addendums; //need to handle splits without re-downloading whole scratchpad + height_info_native m_hi; + std::vector m_scratchpad; + crypto::hash *m_fast_scratchpad; + uint32_t m_fast_scratchpad_pages; + uint64_t m_last_job_ticks; + uint64_t m_last_scratchpad_store_time; + bool m_fast_mmapped; + uint32_t m_threads_total; + std::atomic m_hashes_done; + std::string m_pool_session_id; + simpleminer::job_details_native m_job; + std::condition_variable m_work_done_cond; + std::mutex m_work_mutex; + std::string m_scratchpad_url; + std::string m_scratchpad_local_path; + + std::string m_pool_ip; + std::string m_pool_port; + std::string m_login; + std::string m_pass; + epee::net_utils::http::http_simple_client m_http_client; + }; +} +*/ \ No newline at end of file diff --git a/src/miner/target_helper.h b/src/miner/target_helper.h new file mode 100644 index 00000000..54583f6b --- /dev/null +++ b/src/miner/target_helper.h @@ -0,0 +1,19 @@ +// Copyright (c) 2014-2017 The The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include "currency_core/difficulty.h" + + +namespace mining +{ + inline uint32_t get_target_for_difficulty(currency::difficulty_type difficulty) + { + if(!difficulty) + return 0xffffffff; + return 0xffffffff/static_cast(difficulty); + } + +} diff --git a/src/p2p/maintainers_info_boost_serialization.h b/src/p2p/maintainers_info_boost_serialization.h new file mode 100644 index 00000000..fafc659e --- /dev/null +++ b/src/p2p/maintainers_info_boost_serialization.h @@ -0,0 +1,40 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include "p2p_protocol_defs.h" +#include "common/crypto_boost_serialization.h" + +namespace boost +{ + namespace serialization + { + template + inline void serialize(Archive &a, nodetool::alert_condition& ac, const ver_type ver) + { + a & ac.alert_mode; + a & ac.if_build_less_then; + } + + template + inline void serialize(Archive &a, nodetool::maintainers_info& mi, const ver_type ver) + { + a & mi.timestamp; + a & mi.ver_major; + a & mi.ver_minor; + a & mi.ver_revision; + a & mi.build_no; + a & mi.conditions; + } + + template + inline void serialize(Archive &a, nodetool::maintainers_entry& me, const ver_type ver) + { + a & me.maintainers_info_buff; + a & me.sign; + } + } +} diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h new file mode 100644 index 00000000..6ae42925 --- /dev/null +++ b/src/p2p/net_node.h @@ -0,0 +1,285 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "warnings.h" +#include "net/levin_server_cp2.h" +#include "p2p_protocol_defs.h" +#include "storages/levin_abstract_invoke2.h" +#include "net_peerlist.h" +#include "p2p_networks.h" +#include "math_helper.h" +#include "net_node_common.h" +#include "maintainers_info_boost_serialization.h" +#include "currency_core/currency_config.h" +using namespace epee; + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL "p2p" + +#define CURRENT_P2P_STORAGE_ARCHIVE_VER (CURRENCY_FORMATION_VERSION+13) + +PUSH_WARNINGS +DISABLE_VS_WARNINGS(4355) + +namespace nodetool +{ + template + struct p2p_connection_context_t: base_type //t_payload_net_handler::connection_context //public net_utils::connection_context_base + { + peerid_type peer_id; + }; + + template + class node_server: public levin::levin_commands_handler >, + public i_p2p_endpoint, + public net_utils::i_connection_filter + { + struct by_conn_id{}; + struct by_peer_id{}; + struct by_addr{}; + + typedef p2p_connection_context_t p2p_connection_context; + + typedef COMMAND_HANDSHAKE_T COMMAND_HANDSHAKE; + typedef COMMAND_TIMED_SYNC_T COMMAND_TIMED_SYNC; + + public: + typedef t_payload_net_handler payload_net_handler; + // Some code + node_server(t_payload_net_handler& payload_handler):m_payload_handler(payload_handler), + m_allow_local_ip(false), + m_hide_my_port(false), + m_offline_mode(false), + m_alert_mode(0), + m_maintainers_entry_local(AUTO_VAL_INIT(m_maintainers_entry_local)), + m_maintainers_info_local(AUTO_VAL_INIT(m_maintainers_info_local)), + m_startup_time(time(nullptr)) + {} + + static void init_options(boost::program_options::options_description& desc); + + bool run(bool sync_call = true); + bool init(const boost::program_options::variables_map& vm); + bool deinit(); + bool send_stop_signal(); + bool timed_wait_server_stop(size_t mseconds_wait){ return m_net_server.timed_wait_server_stop(mseconds_wait); } + + uint32_t get_this_peer_port(){return m_listenning_port;} + t_payload_net_handler& get_payload_object(); + + template + void serialize(Archive &a, const t_version_type ver) + { + if(ver < CURRENT_P2P_STORAGE_ARCHIVE_VER) + return; + time_t local_time = time(nullptr); + a & local_time; + if(local_time > time(nullptr)) + { + LOG_PRINT_L0("psp network state file have future time, skipped"); + return; + } + a & m_peerlist; + a & m_maintainers_info_local; + a & m_maintainers_entry_local; + a & m_blocked_ips; + } + // debug functions + bool log_peerlist(); + bool log_connections(); + virtual uint64_t get_connections_count(); + size_t get_outgoing_connections_count(); + peerlist_manager& get_peerlist_manager(){return m_peerlist;} + bool handle_maintainers_entry(const maintainers_entry& me); + bool get_maintainers_info(maintainers_info_external& me); + typedef COMMAND_REQUEST_STAT_INFO_T COMMAND_REQUEST_STAT_INFO; + private: + + + CHAIN_LEVIN_INVOKE_MAP2(p2p_connection_context); //move levin_commands_handler interface invoke(...) callbacks into invoke map + CHAIN_LEVIN_NOTIFY_MAP2(p2p_connection_context); //move levin_commands_handler interface notify(...) callbacks into nothing + + BEGIN_INVOKE_MAP2(node_server) + HANDLE_INVOKE_T2(COMMAND_HANDSHAKE, &node_server::handle_handshake) + HANDLE_INVOKE_T2(COMMAND_TIMED_SYNC, &node_server::handle_timed_sync) + HANDLE_INVOKE_T2(COMMAND_PING, &node_server::handle_ping) +#ifdef ALLOW_DEBUG_COMMANDS + HANDLE_INVOKE_T2(COMMAND_REQUEST_STAT_INFO, &node_server::handle_get_stat_info) + HANDLE_INVOKE_T2(COMMAND_REQUEST_NETWORK_STATE, &node_server::handle_get_network_state) + HANDLE_INVOKE_T2(COMMAND_REQUEST_PEER_ID, &node_server::handle_get_peer_id) +#endif + CHAIN_INVOKE_MAP_TO_OBJ_FORCE_CONTEXT(m_payload_handler, typename t_payload_net_handler::connection_context&) + END_INVOKE_MAP2() + + //----------------- commands handlers ---------------------------------------------- + int handle_handshake(int command, typename COMMAND_HANDSHAKE::request& arg, typename COMMAND_HANDSHAKE::response& rsp, p2p_connection_context& context); + int handle_timed_sync(int command, typename COMMAND_TIMED_SYNC::request& arg, typename COMMAND_TIMED_SYNC::response& rsp, p2p_connection_context& context); + int handle_ping(int command, COMMAND_PING::request& arg, COMMAND_PING::response& rsp, p2p_connection_context& context); +#ifdef ALLOW_DEBUG_COMMANDS + public: + int handle_get_stat_info(int command, typename COMMAND_REQUEST_STAT_INFO::request& arg, typename COMMAND_REQUEST_STAT_INFO::response& rsp, p2p_connection_context& context); + int handle_get_network_state(int command, COMMAND_REQUEST_NETWORK_STATE::request& arg, COMMAND_REQUEST_NETWORK_STATE::response& rsp, p2p_connection_context& context); + int handle_get_peer_id(int command, COMMAND_REQUEST_PEER_ID::request& arg, COMMAND_REQUEST_PEER_ID::response& rsp, p2p_connection_context& context); + private: +#endif + bool init_config(); + bool make_default_config(); + bool store_config(); + bool check_trust(const proof_of_trust& tr); + + + //----------------- levin_commands_handler ------------------------------------------------------------- + virtual void on_connection_new(p2p_connection_context& context); + virtual void on_connection_close(p2p_connection_context& context); + virtual void callback(p2p_connection_context& context); + //----------------- i_p2p_endpoint ------------------------------------------------------------- + virtual bool relay_notify_to_all(int command, const std::string& data_buff, const epee::net_utils::connection_context_base& context, std::list& relayed_peers); + virtual bool invoke_command_to_peer(int command, const std::string& req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context); + virtual bool invoke_notify_to_peer(int command, const std::string& req_buff, const epee::net_utils::connection_context_base& context); + virtual bool drop_connection(const epee::net_utils::connection_context_base& context); + virtual void request_callback(const epee::net_utils::connection_context_base& context); + virtual void get_connections(std::list& connections); + virtual void for_each_connection(std::function f); + virtual bool block_ip(uint32_t adress); + virtual bool add_ip_fail(uint32_t address); + virtual bool is_stop_signal_sent(); + //----------------- i_connection_filter -------------------------------------------------------- + virtual bool is_remote_ip_allowed(uint32_t adress); + //----------------------------------------------------------------------------------------------- + bool parse_peer_from_string(nodetool::net_address& pe, const std::string& node_addr); + bool handle_command_line(const boost::program_options::variables_map& vm); + bool idle_worker(); + bool handle_remote_peerlist(const std::list& peerlist, time_t local_time, const net_utils::connection_context_base& context); + bool get_local_node_data(basic_node_data& node_data); + //bool get_local_handshake_data(handshake_data& hshd); + + bool merge_peerlist_with_local(const std::list& bs); + bool fix_time_delta(std::list& local_peerlist, time_t local_time, int64_t& delta); + + bool connections_maker(); + bool peer_sync_idle_maker(); + bool do_handshake_with_peer(peerid_type& pi, p2p_connection_context& context, bool just_take_peerlist = false); + bool do_peer_timed_sync(const net_utils::connection_context_base& context, peerid_type peer_id); + + bool make_new_connection_from_peerlist(bool use_white_list); + bool try_to_connect_and_handshake_with_new_peer(const net_address& na, bool just_take_peerlist = false, uint64_t last_seen_stamp = 0, bool white = true); + size_t get_random_index_with_fixed_probability(size_t max_index); + bool is_peer_used(const peerlist_entry& peer); + bool is_addr_connected(const net_address& peer); + template + bool try_ping(basic_node_data& node_data, p2p_connection_context& context, t_callback cb); + bool make_expected_connections_count(bool white_list, size_t expected_connections); + void cache_connect_fail_info(const net_address& addr); + bool is_addr_recently_failed(const net_address& addr); + bool fill_maintainers_entry(maintainers_entry& me); + bool on_maintainers_entry_update(); + bool handle_alert_conditions(); + /*this code is temporary here(to show regular message if need), until we get normal GUI*/ + bool calm_alert_worker(); + bool urgent_alert_worker(); + bool critical_alert_worker(); + bool remove_dead_connections(); + + + //debug functions + std::string print_connections_container(); + + typedef net_utils::boosted_tcp_server > net_server; + + struct config + { + network_config m_net_config; + uint64_t m_peer_id; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(m_net_config) + KV_SERIALIZE(m_peer_id) + END_KV_SERIALIZE_MAP() + }; + + config m_config; + std::string m_config_folder; + + bool m_have_address; + bool m_first_connection_maker_call; + uint32_t m_listenning_port; + uint32_t m_external_port; + uint32_t m_ip_address; + bool m_allow_local_ip; + bool m_hide_my_port; + bool m_offline_mode; + uint64_t m_startup_time; + + //critical_section m_connections_lock; + //connections_indexed_container m_connections; + + t_payload_net_handler& m_payload_handler; + peerlist_manager m_peerlist; + + math_helper::once_a_time_seconds m_peer_handshake_idle_maker_interval; + math_helper::once_a_time_seconds<1> m_connections_maker_interval; + math_helper::once_a_time_seconds<60*30, false> m_peerlist_store_interval; + math_helper::once_a_time_seconds<60> m_remove_dead_conn_interval; + + /*this code is temporary here(to show regular message if need), until we get normal GUI*/ + math_helper::once_a_time_seconds<60, false> m_calm_alert_interval; + math_helper::once_a_time_seconds<10, false> m_urgent_alert_interval; + math_helper::once_a_time_seconds<1, false> m_critical_alert_interval; + + std::string m_bind_ip; + std::string m_port; +#ifdef ALLOW_DEBUG_COMMANDS + int64_t m_last_stat_request_time; +#endif + std::list m_priority_peers; + bool m_use_only_priority_peers; + std::vector m_seed_nodes; + std::list m_command_line_peers; + int64_t m_peer_livetime; + //keep connections to initiate some interactions + net_server m_net_server; + + std::map m_conn_fails_cache; + critical_section m_conn_fails_cache_lock; + crypto::public_key m_maintainers_pub_key; + + maintainers_info m_maintainers_info_local; + maintainers_entry m_maintainers_entry_local; + uint8_t m_alert_mode; + critical_section m_maintainers_local_lock; + + critical_section m_blocked_ips_lock; + std::map m_blocked_ips; + + critical_section m_ip_fails_score_lock; + std::map m_ip_fails_score; + + }; +} + + + + +#include "net_node.inl" + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL NULL + +POP_WARNINGS diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl new file mode 100644 index 00000000..146d8cd8 --- /dev/null +++ b/src/p2p/net_node.inl @@ -0,0 +1,1355 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include "version.h" +#include "string_tools.h" +#include "common/command_line.h" +#include "common/util.h" +#include "net/net_helper.h" +#include "math_helper.h" +#include "p2p_protocol_defs.h" +#include "net_peerlist_boost_serialization.h" +#include "net/local_ip.h" +#include "crypto/crypto.h" +#include "storages/levin_abstract_invoke2.h" + + +namespace nodetool +{ + //zero network before launch + const static boost::uuids::uuid P2P_NETWORK_ID = { { 0x11, 0x10, 0x01, 0x11, 0x01, 0x01, 0x11, 0x01, 0x10, 0x11, P2P_NETWORK_ID_TESTNET_FLAG, 0x11, 0x01, 0x11, 0x21, P2P_NETWORK_ID_VER} }; + + namespace + { + const command_line::arg_descriptor arg_p2p_bind_ip = {"p2p-bind-ip", "Interface for p2p network protocol", "0.0.0.0"}; + const command_line::arg_descriptor arg_p2p_bind_port = {"p2p-bind-port", "Port for p2p network protocol", boost::to_string(P2P_DEFAULT_PORT)}; + const command_line::arg_descriptor arg_p2p_external_port = {"p2p-external-port", "External port for p2p network protocol (if port forwarding used with NAT)", 0}; + const command_line::arg_descriptor arg_p2p_allow_local_ip = {"allow-local-ip", "Allow local ip add to peer list, mostly in debug purposes"}; + const command_line::arg_descriptor > arg_p2p_add_peer = {"add-peer", "Manually add peer to local peerlist"}; + const command_line::arg_descriptor > arg_p2p_add_priority_node = {"add-priority-node", "Specify list of peers to connect to and attempt to keep the connection open"}; + const command_line::arg_descriptor arg_p2p_use_only_priority_nodes = {"use-only-priority-nodes", "Try to connect only to priority nodes"}; + const command_line::arg_descriptor > arg_p2p_seed_node = {"seed-node", "Connect to a node to retrieve peer addresses, and disconnect"}; + const command_line::arg_descriptor arg_p2p_hide_my_port = {"hide-my-port", "Do not announce yourself as peerlist candidate", false, true}; + const command_line::arg_descriptor arg_p2p_offline_mode = { "offline-mode", "Don't connect to any node and reject any connections", false, true }; +} + + //----------------------------------------------------------------------------------- + template + void node_server::init_options(boost::program_options::options_description& desc) + { + command_line::add_arg(desc, arg_p2p_bind_ip); + command_line::add_arg(desc, arg_p2p_bind_port); + command_line::add_arg(desc, arg_p2p_external_port); + command_line::add_arg(desc, arg_p2p_allow_local_ip); + command_line::add_arg(desc, arg_p2p_add_peer); + command_line::add_arg(desc, arg_p2p_add_priority_node); + command_line::add_arg(desc, arg_p2p_seed_node); + command_line::add_arg(desc, arg_p2p_hide_my_port); + command_line::add_arg(desc, arg_p2p_offline_mode); + command_line::add_arg(desc, arg_p2p_use_only_priority_nodes); + } + //----------------------------------------------------------------------------------- + template + bool node_server::init_config() + { + // + TRY_ENTRY(); + bool r = string_tools::hex_to_pod(P2P_MAINTAINERS_PUB_KEY, m_maintainers_pub_key); + CHECK_AND_ASSERT_MES(r, false, "Failed to parse P2P_MAINTAINERS_PUB_KEY = " << P2P_MAINTAINERS_PUB_KEY); + + std::string state_file_path = m_config_folder + "/" + P2P_NET_DATA_FILENAME; + tools::unserialize_obj_from_file(*this, state_file_path); + + //always use new id, to be able differ cloned computers + m_config.m_peer_id = crypto::rand(); + + handle_alert_conditions(); + + //at this moment we have hardcoded config + m_config.m_net_config.handshake_interval = P2P_DEFAULT_HANDSHAKE_INTERVAL; + m_config.m_net_config.connections_count = P2P_DEFAULT_CONNECTIONS_COUNT; + m_config.m_net_config.packet_max_size = P2P_DEFAULT_PACKET_MAX_SIZE; //20 MB limit + m_config.m_net_config.config_id = 0; // initial config + m_config.m_net_config.connection_timeout = P2P_DEFAULT_CONNECTION_TIMEOUT; + m_config.m_net_config.ping_connection_timeout = P2P_DEFAULT_PING_CONNECTION_TIMEOUT; + m_config.m_net_config.send_peerlist_sz = P2P_DEFAULT_PEERS_IN_HANDSHAKE; + + m_first_connection_maker_call = true; + CATCH_ENTRY_L0("node_server::init_config", false); + return true; + } + //----------------------------------------------------------------------------------- + template + void node_server::for_each_connection(std::function f) + { + m_net_server.get_config_object().foreach_connection([&](p2p_connection_context& cntx){ + return f(cntx, cntx.peer_id); + }); + } + //----------------------------------------------------------------------------------- + template + bool node_server::is_remote_ip_allowed(uint32_t addr) + { + if (m_offline_mode) + return false; + + //@#@ workaround + return true; + + CRITICAL_REGION_LOCAL(m_blocked_ips_lock); + auto it = m_blocked_ips.find(addr); + if(it == m_blocked_ips.end()) + return true; + if(time(nullptr) - it->second > P2P_IP_BLOCKTIME ) + { + m_blocked_ips.erase(it); + LOG_PRINT_CYAN("Ip " << string_tools::get_ip_string_from_int32(addr) << "is unblocked.", LOG_LEVEL_0); + return true; + } + return false; + } + //----------------------------------------------------------------------------------- + template + bool node_server::block_ip(uint32_t addr) + { + CRITICAL_REGION_LOCAL(m_blocked_ips_lock); + m_blocked_ips[addr] = time(nullptr); + LOG_PRINT_CYAN("Ip " << string_tools::get_ip_string_from_int32(addr) << " blocked.", LOG_LEVEL_0); + return true; + } + //----------------------------------------------------------------------------------- + template + bool node_server::add_ip_fail(uint32_t address) + { + CRITICAL_REGION_LOCAL(m_ip_fails_score_lock); + uint64_t fails = ++m_ip_fails_score[address]; + if(fails > P2P_IP_FAILS_BEFOR_BLOCK) + { + auto it = m_ip_fails_score.find(address); + CHECK_AND_ASSERT_MES(it != m_ip_fails_score.end(), false, "internal error"); + it->second = P2P_IP_FAILS_BEFOR_BLOCK/2; + block_ip(address); + } + return true; + } + //----------------------------------------------------------------------------------- + template + bool node_server::is_stop_signal_sent() + { + return m_net_server.is_stop_signal_sent(); + } + //----------------------------------------------------------------------------------- + template + bool node_server::parse_peer_from_string(nodetool::net_address& pe, const std::string& node_addr) + { + return string_tools::parse_peer_from_string(pe.ip, pe.port, node_addr); + } + //----------------------------------------------------------------------------------- + template + bool node_server::handle_command_line(const boost::program_options::variables_map& vm) + { + m_bind_ip = command_line::get_arg(vm, arg_p2p_bind_ip); + m_port = command_line::get_arg(vm, arg_p2p_bind_port); + m_external_port = command_line::get_arg(vm, arg_p2p_external_port); + m_allow_local_ip = command_line::get_arg(vm, arg_p2p_allow_local_ip); + m_offline_mode = command_line::get_arg(vm, arg_p2p_offline_mode); + + if (m_offline_mode) + { + LOG_PRINT_CYAN("Daemon running in offline mode", LOG_LEVEL_0); + } + + if (command_line::has_arg(vm, arg_p2p_add_peer)) + { + std::vector perrs = command_line::get_arg(vm, arg_p2p_add_peer); + for(const std::string& pr_str: perrs) + { + nodetool::peerlist_entry pe = AUTO_VAL_INIT(pe); + pe.id = crypto::rand(); + bool r = parse_peer_from_string(pe.adr, pr_str); + CHECK_AND_ASSERT_MES(r, false, "Failed to parse address from string: " << pr_str); + m_command_line_peers.push_back(pe); + } + } + + if (command_line::has_arg(vm, arg_p2p_add_priority_node)) + { + std::vector perrs = command_line::get_arg(vm, arg_p2p_add_priority_node); + for(const std::string& pr_str: perrs) + { + nodetool::net_address na = AUTO_VAL_INIT(na); + bool r = parse_peer_from_string(na, pr_str); + CHECK_AND_ASSERT_MES(r, false, "Failed to parse address from string: " << pr_str); + m_priority_peers.push_back(na); + } + } + if(command_line::has_arg(vm, arg_p2p_use_only_priority_nodes)) + m_use_only_priority_peers = true; + else + m_use_only_priority_peers = false; + + + if (command_line::has_arg(vm, arg_p2p_seed_node)) + { + std::vector seed_perrs = command_line::get_arg(vm, arg_p2p_seed_node); + for(const std::string& pr_str: seed_perrs) + { + nodetool::net_address na = AUTO_VAL_INIT(na); + bool r = parse_peer_from_string(na, pr_str); + CHECK_AND_ASSERT_MES(r, false, "Failed to parse seed address from string: " << pr_str); + m_seed_nodes.push_back(na); + } + } + if(command_line::has_arg(vm, arg_p2p_hide_my_port)) + m_hide_my_port = true; + + return true; + } + //----------------------------------------------------------------------------------- + namespace + { + + + + template + bool append_net_address(T& nodes, const std::string& addr) + { + using namespace boost::asio; + + size_t pos = addr.find_last_of(':'); + CHECK_AND_ASSERT_MES(std::string::npos != pos && addr.length() - 1 != pos && 0 != pos, false, "Failed to parse seed address from string: '" << addr << '\''); + std::string host = addr.substr(0, pos); + std::string port = addr.substr(pos + 1); + int iport = 0; + bool r = epee::string_tools::get_xtype_from_string(iport, port); + CHECK_AND_ASSERT_MES(r, false, "wrong port string format"); + return append_net_address(nodes, host, iport); + + } + template + bool append_net_address(T& nodes, const std::string& host, int port) + { + using namespace boost::asio; + + std::string portstr = std::to_string(port); + + io_service io_srv; + ip::tcp::resolver resolver(io_srv); + ip::tcp::resolver::query query(host, portstr); + boost::system::error_code ec; + ip::tcp::resolver::iterator i = resolver.resolve(query, ec); + CHECK_AND_NO_ASSERT_MES(!ec, false, "Failed to resolve host name '" << host << "': " << ec.message() << ':' << ec.value()); + + ip::tcp::resolver::iterator iend; + for (; i != iend; ++i) + { + ip::tcp::endpoint endpoint = *i; + if (endpoint.address().is_v4()) + { + nodetool::net_address na; + na.ip = boost::asio::detail::socket_ops::host_to_network_long(endpoint.address().to_v4().to_ulong()); + na.port = endpoint.port(); + nodes.push_back(na); + LOG_PRINT_L4("Added seed node: " << endpoint.address().to_v4().to_string(ec) << ':' << na.port); + } + else + { + LOG_PRINT_L2("IPv6 doesn't supported, skip '" << host << "' -> " << endpoint.address().to_v6().to_string(ec)); + } + } + + return true; + } + } + + #define ADD_HARDCODED_SEED_NODE(host, port) append_net_address(m_seed_nodes, host, port); + //----------------------------------------------------------------------------------- + template + bool node_server::init(const boost::program_options::variables_map& vm) + { +#ifndef TESTNET + //TODO: + //ADD_HARDCODED_SEED_NODE(std::string("0.0.0.0:") + std::to_string(P2P_DEFAULT_PORT)); + ADD_HARDCODED_SEED_NODE("207.154.237.82", P2P_DEFAULT_PORT); + ADD_HARDCODED_SEED_NODE("207.154.240.198", P2P_DEFAULT_PORT); + ADD_HARDCODED_SEED_NODE("207.154.255.10", P2P_DEFAULT_PORT); + ADD_HARDCODED_SEED_NODE("207.154.228.141", P2P_DEFAULT_PORT); +#else + //TODO: + //ADD_HARDCODED_SEED_NODE(std::string("0.0.0.0:") + std::to_string(P2P_DEFAULT_PORT)); +#endif + + bool res = handle_command_line(vm); + CHECK_AND_ASSERT_MES(res, false, "Failed to handle command line"); + m_config_folder = command_line::get_arg(vm, command_line::arg_data_dir); + + res = init_config(); + CHECK_AND_ASSERT_MES(res, false, "Failed to init config."); + + res = m_peerlist.init(m_allow_local_ip); + CHECK_AND_ASSERT_MES(res, false, "Failed to init peerlist."); + + + for(auto& p: m_command_line_peers) + m_peerlist.append_with_peer_white(p); + + //only in case if we really sure that we have external visible ip + m_have_address = true; + m_ip_address = 0; + m_last_stat_request_time = 0; + + //configure self + m_net_server.set_threads_prefix("P2P"); + m_net_server.get_config_object().m_pcommands_handler = this; + m_net_server.get_config_object().m_invoke_timeout = P2P_DEFAULT_INVOKE_TIMEOUT; + m_net_server.set_connection_filter(this); + + //try to bind + LOG_PRINT_L0("Binding on " << m_bind_ip << ":" << m_port); + res = m_net_server.init_server(m_port, m_bind_ip); + CHECK_AND_ASSERT_MES(res, false, "Failed to bind server"); + + m_listenning_port = m_net_server.get_binded_port(); + LOG_PRINT_GREEN("Net service binded on " << m_bind_ip << ":" << m_listenning_port, LOG_LEVEL_0); + if(m_external_port) + LOG_PRINT_L0("External port defined as " << m_external_port); + return res; + } + //----------------------------------------------------------------------------------- + template + typename node_server::payload_net_handler& node_server::get_payload_object() + { + return m_payload_handler; + } + //----------------------------------------------------------------------------------- + template + bool node_server::run(bool sync_call) + { + //here you can set worker threads count + int thrds_count = 10; + + m_net_server.add_idle_handler(boost::bind(&node_server::idle_worker, this), 1000); + m_net_server.add_idle_handler(boost::bind(&t_payload_net_handler::on_idle, &m_payload_handler), 1000); + + //go to loop + LOG_PRINT("Run net_service loop( " << thrds_count << " threads)...", LOG_LEVEL_0); + if(!m_net_server.run_server(thrds_count, sync_call)) + { + LOG_ERROR("Failed to run net tcp server!"); + } + + if(sync_call) + LOG_PRINT("net_service loop stopped.", LOG_LEVEL_0); + return true; + } + + //----------------------------------------------------------------------------------- + template + uint64_t node_server::get_connections_count() + { + return m_net_server.get_config_object().get_connections_count(); + } + //----------------------------------------------------------------------------------- + template + bool node_server::deinit() + { + m_peerlist.deinit(); + m_net_server.deinit_server(); + return store_config(); + } + //----------------------------------------------------------------------------------- + template + bool node_server::store_config() + { + + TRY_ENTRY(); + if (!tools::create_directories_if_necessary(m_config_folder)) + { + LOG_PRINT_L0("Failed to create data directory: " << m_config_folder); + return false; + } + + std::string state_file_path = m_config_folder + "/" + P2P_NET_DATA_FILENAME; + tools::serialize_obj_to_file(*this, state_file_path); + CATCH_ENTRY_L0("node_server::save", false); + return true; + } + //----------------------------------------------------------------------------------- + template + bool node_server::send_stop_signal() + { + m_net_server.send_stop_signal(); + LOG_PRINT_L0("[node] Stop signal sent"); + return true; + } + //----------------------------------------------------------------------------------- + template + bool node_server::get_maintainers_info(maintainers_info_external& me) + { + me.ver_major = m_maintainers_info_local.ver_major; + me.ver_minor = m_maintainers_info_local.ver_minor; + me.ver_revision = m_maintainers_info_local.ver_revision; + me.build_no = m_maintainers_info_local.build_no; + me.mode = m_alert_mode; + return true; + } + //----------------------------------------------------------------------------------- + template + bool node_server::on_maintainers_entry_update() + { + LOG_PRINT_MAGENTA("Fresh maintainers info recieved(timestamp: " << m_maintainers_info_local.timestamp << ")", LOG_LEVEL_0); + if(PROJECT_VERSION_BUILD_NO < m_maintainers_info_local.build_no) + { + LOG_PRINT_MAGENTA("Newer version avaliable: " << static_cast(m_maintainers_info_local.ver_major) << + "." << static_cast(m_maintainers_info_local.ver_minor) << + "." << static_cast(m_maintainers_info_local.ver_revision) << + "." << static_cast(m_maintainers_info_local.build_no) << + ", current version: " << PROJECT_VERSION_LONG, LOG_LEVEL_0); + } + handle_alert_conditions(); + + return true; + } + //----------------------------------------------------------------------------------- + template + bool node_server::handle_maintainers_entry(const maintainers_entry& me) + { + if(me.sign == AUTO_VAL_INIT(me.sign))//todo: make null_sig (and other null_xxx) available out of currency namespace + return true; + + bool r = crypto::check_signature(crypto::cn_fast_hash(me.maintainers_info_buff.data(), me.maintainers_info_buff.size()), m_maintainers_pub_key, me.sign); + CHECK_AND_ASSERT_MES(r, false, "Failed to check signature in maintainers_entry"); + //signature ok, load from blob + maintainers_info mi = AUTO_VAL_INIT(mi); + r = epee::serialization::load_t_from_binary(mi, me.maintainers_info_buff); + CHECK_AND_ASSERT_MES(r, false, "Failed to load maintainers_info from maintainers_entry buff"); + if(mi.timestamp > m_maintainers_info_local.timestamp) + { + //lets update new + CRITICAL_REGION_LOCAL(m_maintainers_local_lock); + m_maintainers_entry_local = me; + m_maintainers_info_local = mi; + on_maintainers_entry_update(); + } + return true; + } + //----------------------------------------------------------------------------------- + template + bool node_server::fill_maintainers_entry(maintainers_entry& me) + { + me = m_maintainers_entry_local; + return true; + } + //----------------------------------------------------------------------------------- + template + bool node_server::do_handshake_with_peer(peerid_type& pi, p2p_connection_context& context_, bool just_take_peerlist) + { + typename COMMAND_HANDSHAKE::request arg = AUTO_VAL_INIT(arg); + typename COMMAND_HANDSHAKE::response rsp = AUTO_VAL_INIT(rsp); + get_local_node_data(arg.node_data); + m_payload_handler.get_payload_sync_data(arg.payload_data); + fill_maintainers_entry(arg.maintrs_entry); + + simple_event ev; + std::atomic hsh_result(false); + + bool r = net_utils::async_invoke_remote_command2(context_.m_connection_id, COMMAND_HANDSHAKE::ID, arg, m_net_server.get_config_object(), + [this, &pi, &ev, &hsh_result, &just_take_peerlist](int code, const typename COMMAND_HANDSHAKE::response& rsp, p2p_connection_context& context) + { + misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler([&](){ev.raise();}); + + if(code < 0) + { + LOG_PRINT_CC_RED(context, "COMMAND_HANDSHAKE invoke failed. (" << code << ", " << levin::get_err_descr(code) << ")", LOG_LEVEL_0); + return; + } + + if(rsp.node_data.network_id != P2P_NETWORK_ID) + { + LOG_ERROR_CCONTEXT("COMMAND_HANDSHAKE Failed, wrong network!, closing connection."); + return; + } + + if(!handle_maintainers_entry(rsp.maintrs_entry)) + { + LOG_ERROR_CCONTEXT("COMMAND_HANDSHAKE Failed, wrong maintainers entry!, closing connection."); + return; + } + + if(!handle_remote_peerlist(rsp.local_peerlist, rsp.node_data.local_time, context)) + { + LOG_ERROR_CCONTEXT("COMMAND_HANDSHAKE: failed to handle_remote_peerlist(...), closing connection."); + add_ip_fail(context.m_remote_ip); + return; + } + hsh_result = true; + if(!just_take_peerlist) + { + if(!m_payload_handler.process_payload_sync_data(rsp.payload_data, context, true)) + { + LOG_ERROR_CCONTEXT("COMMAND_HANDSHAKE invoked, but process_payload_sync_data returned false, dropping connection."); + hsh_result = false; + return; + } + + pi = context.peer_id = rsp.node_data.peer_id; + m_peerlist.set_peer_just_seen(rsp.node_data.peer_id, context.m_remote_ip, context.m_remote_port); + + if(rsp.node_data.peer_id == m_config.m_peer_id) + { + LOG_PRINT_L0("Connection to self detected, dropping connection"); + hsh_result = false; + return; + } + LOG_PRINT_L1(" COMMAND_HANDSHAKE INVOKED OK"); + }else + { + LOG_PRINT_L0(" COMMAND_HANDSHAKE(AND CLOSE) INVOKED OK"); + //m_net_server.get_config_object().close(context_.m_connection_id); + } + }, P2P_DEFAULT_HANDSHAKE_INVOKE_TIMEOUT); + + if(r) + { + ev.wait(); + } + + if(!hsh_result) + { + LOG_PRINT_CC_L0(context_, "COMMAND_HANDSHAKE Failed"); + m_net_server.get_config_object().close(context_.m_connection_id); + } + + return hsh_result; + } + //----------------------------------------------------------------------------------- + template + bool node_server::do_peer_timed_sync(const net_utils::connection_context_base& context_, peerid_type peer_id) + { + typename COMMAND_TIMED_SYNC::request arg = AUTO_VAL_INIT(arg); + m_payload_handler.get_payload_sync_data(arg.payload_data); + fill_maintainers_entry(arg.maintrs_entry); + + bool r = net_utils::async_invoke_remote_command2(context_.m_connection_id, COMMAND_TIMED_SYNC::ID, arg, m_net_server.get_config_object(), + [this](int code, const typename COMMAND_TIMED_SYNC::response& rsp, p2p_connection_context& context) + { + if(code < 0) + { + LOG_PRINT_CC_RED(context, "COMMAND_TIMED_SYNC invoke failed. (" << code << ", " << levin::get_err_descr(code) << ")", LOG_LEVEL_1); + return; + } + + if(!handle_maintainers_entry(rsp.maintrs_entry)) + { + LOG_ERROR_CCONTEXT("COMMAND_HANDSHAKE Failed, wrong maintainers entry!, closing connection."); + return; + } + + if(!handle_remote_peerlist(rsp.local_peerlist, rsp.local_time, context)) + { + LOG_ERROR_CCONTEXT("COMMAND_TIMED_SYNC: failed to handle_remote_peerlist(...), closing connection."); + m_net_server.get_config_object().close(context.m_connection_id ); + add_ip_fail(context.m_remote_ip); + } + if(!context.m_is_income) + m_peerlist.set_peer_just_seen(context.peer_id, context.m_remote_ip, context.m_remote_port); + m_payload_handler.process_payload_sync_data(rsp.payload_data, context, false); + }); + + if(!r) + { + LOG_PRINT_CC_L2(context_, "COMMAND_TIMED_SYNC Failed"); + return false; + } + return true; + } + //----------------------------------------------------------------------------------- + template + size_t node_server::get_random_index_with_fixed_probability(size_t max_index) + { + //divide by zero workaround + if(!max_index) + return 0; + + size_t x = crypto::rand()%(max_index+1); + size_t res = (x*x*x)/(max_index*max_index); //parabola \/ + LOG_PRINT_L3("Random connection index=" << res << "(x="<< x << ", max_index=" << max_index << ")"); + return res; + } + //----------------------------------------------------------------------------------- + template + bool node_server::is_peer_used(const peerlist_entry& peer) + { + + if(m_config.m_peer_id == peer.id) + return true;//dont make connections to ourself + + bool used = false; + m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) + { + if(cntxt.peer_id == peer.id || (!cntxt.m_is_income && peer.adr.ip == cntxt.m_remote_ip && peer.adr.port == cntxt.m_remote_port)) + { + used = true; + return false;//stop enumerating + } + return true; + }); + + return used; + } + //----------------------------------------------------------------------------------- + template + bool node_server::is_addr_connected(const net_address& peer) + { + bool connected = false; + m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) + { + if(!cntxt.m_is_income && peer.ip == cntxt.m_remote_ip && peer.port == cntxt.m_remote_port) + { + connected = true; + return false;//stop enumerating + } + return true; + }); + + return connected; + } + + //----------------------------------------------------------------------------------- + template + bool node_server::try_to_connect_and_handshake_with_new_peer(const net_address& na, bool just_take_peerlist, uint64_t last_seen_stamp, bool white) + { + LOG_PRINT_L0("Connecting to " << string_tools::get_ip_string_from_int32(na.ip) << ":" << string_tools::num_to_string_fast(na.port) << "(white=" << white << ", last_seen: " << (last_seen_stamp?misc_utils::get_time_interval_string(time(NULL) - last_seen_stamp):"never" ) << ")..."); + + typename net_server::t_connection_context con = AUTO_VAL_INIT(con); + bool res = m_net_server.connect(string_tools::get_ip_string_from_int32(na.ip), + string_tools::num_to_string_fast(na.port), + m_config.m_net_config.connection_timeout, + con); + if(!res) + { + LOG_PRINT_L0("Connect failed to " + << string_tools::get_ip_string_from_int32(na.ip) + << ":" << string_tools::num_to_string_fast(na.port) + /*<< ", try " << try_count*/); + //m_peerlist.set_peer_unreachable(pe); + return false; + } + peerid_type pi = AUTO_VAL_INIT(pi); + res = do_handshake_with_peer(pi, con, just_take_peerlist); + if(!res) + { + LOG_PRINT_CC_L0(con, "Failed to HANDSHAKE with peer " + << string_tools::get_ip_string_from_int32(na.ip) + << ":" << string_tools::num_to_string_fast(na.port) + /*<< ", try " << try_count*/); + return false; + } + if(just_take_peerlist) + { + m_net_server.get_config_object().close(con.m_connection_id); + LOG_PRINT_CC_GREEN(con, "CONNECTION HANDSHAKED OK AND CLOSED.", LOG_LEVEL_2); + return true; + } + + peerlist_entry pe_local = AUTO_VAL_INIT(pe_local); + pe_local.adr = na; + pe_local.id = pi; + time(&pe_local.last_seen); + m_peerlist.append_with_peer_white(pe_local); + //update last seen and push it to peerlist manager + + LOG_PRINT_CC_GREEN(con, "CONNECTION HANDSHAKED OK.", LOG_LEVEL_2); + return true; + } + //----------------------------------------------------------------------------------- + template + void node_server::cache_connect_fail_info(const net_address& addr) + { + CRITICAL_REGION_LOCAL(m_conn_fails_cache_lock); + m_conn_fails_cache[addr] = time(NULL); + } + //----------------------------------------------------------------------------------- + template + bool node_server::is_addr_recently_failed(const net_address& addr) + { + CRITICAL_REGION_LOCAL(m_conn_fails_cache_lock); + auto it = m_conn_fails_cache.find(addr); + if(it == m_conn_fails_cache.end()) + return false; + + if(time(NULL) - it->second > P2P_FAILED_ADDR_FORGET_SECONDS) + return false; + else + return true; + } + //----------------------------------------------------------------------------------- + template + bool node_server::make_new_connection_from_peerlist(bool use_white_list) + { + size_t local_peers_count = use_white_list ? m_peerlist.get_white_peers_count():m_peerlist.get_gray_peers_count(); + if(!local_peers_count) + return false;//no peers + + size_t max_random_index = std::min(local_peers_count -1, 50); + + std::set tried_peers; + + size_t try_count = 0; + size_t rand_count = 0; + size_t peer_index = 0; + size_t peers_count = use_white_list ? m_peerlist.get_white_peers_count() : m_peerlist.get_gray_peers_count(); + while (rand_count < (max_random_index + 1) * 3 && try_count < 10 && !m_net_server.is_stop_signal_sent() && peer_index < peers_count) + { + + ++rand_count; + if (peers_count > 15) + peer_index = get_random_index_with_fixed_probability(max_random_index); + + CHECK_AND_ASSERT_MES(peer_index < local_peers_count, false, "random_starter_index < peers_local.size() failed!!"); + + if (tried_peers.count(peer_index)) + { + ++peer_index; + continue; + } + + tried_peers.insert(peer_index); + peerlist_entry pe = AUTO_VAL_INIT(pe); + bool r = use_white_list ? m_peerlist.get_white_peer_by_index(pe, peer_index):m_peerlist.get_gray_peer_by_index(pe, peer_index); + if (!r) return true; + //CHECK_AND_ASSERT_MES(r, false, "Failed to get random peer from peerlist(white:" << use_white_list << ")"); + + ++try_count; + + if (is_peer_used(pe)) + { + ++peer_index; + continue; + } + + if (!is_remote_ip_allowed(pe.adr.ip)) + { + ++peer_index; + continue; + } + + if (is_addr_recently_failed(pe.adr)) + { + ++peer_index; + continue; + } + + LOG_PRINT_L1("Selected peer: " << pe.id << " " << string_tools::get_ip_string_from_int32(pe.adr.ip) << ":" << boost::lexical_cast(pe.adr.port) << "[white=" << use_white_list << "] last_seen: " << (pe.last_seen ? misc_utils::get_time_interval_string(time(NULL) - pe.last_seen) : "never")); + + if(!try_to_connect_and_handshake_with_new_peer(pe.adr, false, pe.last_seen, use_white_list)) + { + cache_connect_fail_info(pe.adr); + ++peer_index; + continue; + } + + return true; + } + return false; + } + //----------------------------------------------------------------------------------- + template + bool node_server::connections_maker() + { + if (m_offline_mode) + return true; + + if(!m_peerlist.get_white_peers_count() && m_seed_nodes.size() && !m_priority_peers.size()) + { + size_t try_count = 0; + size_t current_index = crypto::rand()%m_seed_nodes.size(); + while(true) + { + if(m_net_server.is_stop_signal_sent()) + return false; + + if(try_to_connect_and_handshake_with_new_peer(m_seed_nodes[current_index], true)) + break; + if(++try_count > m_seed_nodes.size()) + { + LOG_PRINT_RED_L0("Failed to connect to any of seed peers, continuing without seeds"); + break; + } + if(++current_index >= m_seed_nodes.size()) + current_index = 0; + } + } + + for(const net_address& na: m_priority_peers) + { + if(m_net_server.is_stop_signal_sent()) + return false; + + if(is_addr_connected(na)) + continue; + try_to_connect_and_handshake_with_new_peer(na); + } + if(m_use_only_priority_peers) + return true; + + size_t expected_white_connections = (m_config.m_net_config.connections_count*P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT)/100; + + size_t conn_count = get_outgoing_connections_count(); + if(conn_count < m_config.m_net_config.connections_count) + { + if(conn_count < expected_white_connections) + { + //start from white list + if(!make_expected_connections_count(true, expected_white_connections)) + return false; + //and then do grey list + if(!make_expected_connections_count(false, m_config.m_net_config.connections_count)) + return false; + }else + { + //start from grey list + if(!make_expected_connections_count(false, m_config.m_net_config.connections_count)) + return false; + //and then do white list + if(!make_expected_connections_count(true, m_config.m_net_config.connections_count)) + return false; + } + } + + return true; + } + //----------------------------------------------------------------------------------- + template + bool node_server::make_expected_connections_count(bool white_list, size_t expected_connections) + { + size_t conn_count = get_outgoing_connections_count(); + //add new connections from white peers + while(conn_count < expected_connections) + { + if(m_net_server.is_stop_signal_sent()) + return false; + + if(!make_new_connection_from_peerlist(white_list)) + break; + conn_count = get_outgoing_connections_count(); + } + return true; + } + + //----------------------------------------------------------------------------------- + template + size_t node_server::get_outgoing_connections_count() + { + size_t count = 0; + m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) + { + if(!cntxt.m_is_income) + ++count; + return true; + }); + + return count; + } + //----------------------------------------------------------------------------------- + template + bool node_server::remove_dead_connections() + { + uint64_t curr_time = time(nullptr); + m_net_server.get_config_object().foreach_connection([&](p2p_connection_context& cntx){ + if(curr_time - cntx.m_last_recv > P2P_IDLE_CONNECTION_KILL_INTERVAL && curr_time - cntx.m_last_send > P2P_IDLE_CONNECTION_KILL_INTERVAL) + { + LOG_PRINT_CC_L1(cntx, "Connection dropped due to idle"); + m_net_server.get_config_object().close(cntx.m_connection_id); + return true; + } + return true; + }); + return true; + } + //----------------------------------------------------------------------------------- + template + bool node_server::idle_worker() + { + m_peer_handshake_idle_maker_interval.do_call(boost::bind(&node_server::peer_sync_idle_maker, this)); + m_connections_maker_interval.do_call(boost::bind(&node_server::connections_maker, this)); + m_peerlist_store_interval.do_call(boost::bind(&node_server::store_config, this)); + m_remove_dead_conn_interval.do_call([this](){return remove_dead_connections();}); + + m_calm_alert_interval.do_call([&](){return calm_alert_worker();}); + m_urgent_alert_interval.do_call([&](){return urgent_alert_worker();}); + m_critical_alert_interval.do_call([&](){return critical_alert_worker();}); + return true; + } + //----------------------------------------------------------------------------------- + template + bool node_server::calm_alert_worker() + { + if(m_alert_mode != ALERT_TYPE_CALM) + return true; + + LOG_PRINT_L0("This software is old, please update."); + return true; + } + //----------------------------------------------------------------------------------- + template + bool node_server::urgent_alert_worker() + { + if(m_alert_mode != ALERT_TYPE_URGENT) + return true; + + LOG_PRINT_CYAN("[URGENT]:This software is old, please update.", LOG_LEVEL_0); + return true; + } + //----------------------------------------------------------------------------------- + template + bool node_server::critical_alert_worker() + { + if(m_alert_mode != ALERT_TYPE_CRITICAL) + return true; + + LOG_PRINT_RED("[CRITICAL]:This software is old, please update.", LOG_LEVEL_0); + return true; + } + //----------------------------------------------------------------------------------- + template + bool node_server::handle_alert_conditions() + { + CRITICAL_REGION_LOCAL(m_maintainers_local_lock); + m_alert_mode = 0; + for(auto c: m_maintainers_info_local.conditions) + { + if(PROJECT_VERSION_BUILD_NO < c.if_build_less_then && c.alert_mode > m_alert_mode) + m_alert_mode = c.alert_mode; + } + return true; + } + //----------------------------------------------------------------------------------- + template + bool node_server::peer_sync_idle_maker() + { + LOG_PRINT_L2("STARTED PEERLIST IDLE HANDSHAKE"); + typedef std::list > local_connects_type; + local_connects_type cncts; + m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) + { + if(cntxt.peer_id) + cncts.push_back(local_connects_type::value_type(cntxt, cntxt.peer_id));//do idle sync only with handshaked connections + return true; + }); + + std::for_each(cncts.begin(), cncts.end(), [&](const typename local_connects_type::value_type& vl){do_peer_timed_sync(vl.first, vl.second);}); + + LOG_PRINT_L2("FINISHED PEERLIST IDLE HANDSHAKE"); + return true; + } + //----------------------------------------------------------------------------------- + template + bool node_server::fix_time_delta(std::list& local_peerlist, time_t local_time, int64_t& delta) + { + //fix time delta + time_t now = 0; + time(&now); + delta = now - local_time; + + BOOST_FOREACH(peerlist_entry& be, local_peerlist) + { + if(be.last_seen > local_time) + { + LOG_PRINT_RED_L0("FOUND FUTURE peerlist for entry " << string_tools::get_ip_string_from_int32(be.adr.ip) << ":" << be.adr.port << " last_seen: " << be.last_seen << ", local_time(on remote node):" << local_time); + return false; + } + be.last_seen += delta; + } + return true; + } + //----------------------------------------------------------------------------------- + template + bool node_server::handle_remote_peerlist(const std::list& peerlist, time_t local_time, const net_utils::connection_context_base& context) + { + int64_t delta = 0; + std::list peerlist_ = peerlist; + if(!fix_time_delta(peerlist_, local_time, delta)) + return false; + LOG_PRINT_L2("REMOTE PEERLIST: TIME_DELTA: " << delta << ", remote peerlist size=" << peerlist_.size()); + LOG_PRINT_L3("REMOTE PEERLIST: " << print_peerlist_to_string(peerlist_)); + return m_peerlist.merge_peerlist(peerlist_); + } + //----------------------------------------------------------------------------------- + template + bool node_server::get_local_node_data(basic_node_data& node_data) + { + node_data.local_time = time(NULL); + node_data.peer_id = m_config.m_peer_id; + if(!m_hide_my_port) + node_data.my_port = m_external_port ? m_external_port : m_listenning_port; + else + node_data.my_port = 0; + node_data.network_id = P2P_NETWORK_ID; + return true; + } + //----------------------------------------------------------------------------------- +#ifdef ALLOW_DEBUG_COMMANDS + template + bool node_server::check_trust(const proof_of_trust& tr) + { + int64_t local_time = time(NULL); + int64_t time_delata = local_time > tr.time ? local_time - tr.time: tr.time - local_time; + if(time_delata > 24*60*60 ) + { + LOG_PRINT_L0("check_trust failed to check time conditions, local_time=" << local_time << ", proof_time=" << tr.time); + return false; + } + if(m_last_stat_request_time >= tr.time ) + { + LOG_PRINT_L0("check_trust failed to check time conditions, last_stat_request_time=" << m_last_stat_request_time << ", proof_time=" << tr.time); + return false; + } + if(m_config.m_peer_id != tr.peer_id) + { + LOG_PRINT_L0("check_trust failed: peer_id mismatch (passed " << tr.peer_id << ", expected " << m_config.m_peer_id<< ")"); + return false; + } + crypto::public_key pk = AUTO_VAL_INIT(pk); + string_tools::hex_to_pod(P2P_MAINTAINERS_PUB_KEY, pk); + crypto::hash h = tools::get_proof_of_trust_hash(tr); + if(!crypto::check_signature(h, pk, tr.sign)) + { + LOG_ERROR("check_trust failed: sign check failed"); + return false; + } + //update last request time + m_last_stat_request_time = tr.time; + return true; + } + //----------------------------------------------------------------------------------- + template + int node_server::handle_get_stat_info(int command, typename COMMAND_REQUEST_STAT_INFO::request& arg, typename COMMAND_REQUEST_STAT_INFO::response& rsp, p2p_connection_context& context) + { + if(!check_trust(arg.tr)) + { + drop_connection(context); + return 1; + } + rsp.connections_count = m_net_server.get_config_object().get_connections_count(); + rsp.incoming_connections_count = rsp.connections_count - get_outgoing_connections_count(); + rsp.version = PROJECT_VERSION_LONG; + m_payload_handler.get_stat_info(arg.pr, rsp.payload_info); + return 1; + } + //----------------------------------------------------------------------------------- + template + int node_server::handle_get_network_state(int command, COMMAND_REQUEST_NETWORK_STATE::request& arg, COMMAND_REQUEST_NETWORK_STATE::response& rsp, p2p_connection_context& context) + { + if(!check_trust(arg.tr)) + { + drop_connection(context); + return 1; + } + m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) + { + connection_entry ce; + ce.adr.ip = cntxt.m_remote_ip; + ce.adr.port = cntxt.m_remote_port; + ce.id = cntxt.peer_id; + ce.is_income = cntxt.m_is_income; + ce.time_started = cntxt.m_started; + ce.last_recv = cntxt.m_last_recv; + ce.last_send = cntxt.m_last_send; + rsp.connections_list.push_back(ce); + return true; + }); + + m_peerlist.get_peerlist_full(rsp.local_peerlist_gray, rsp.local_peerlist_white); + rsp.my_id = m_config.m_peer_id; + rsp.local_time = time(NULL); + rsp.up_time = rsp.local_time - m_startup_time; + return 1; + } + //----------------------------------------------------------------------------------- + template + int node_server::handle_get_peer_id(int command, COMMAND_REQUEST_PEER_ID::request& arg, COMMAND_REQUEST_PEER_ID::response& rsp, p2p_connection_context& context) + { + rsp.my_id = m_config.m_peer_id; + return 1; + } +#endif + //----------------------------------------------------------------------------------- + template + void node_server::request_callback(const epee::net_utils::connection_context_base& context) + { + m_net_server.get_config_object().request_callback(context.m_connection_id); + } + //----------------------------------------------------------------------------------- + template + bool node_server::relay_notify_to_all(int command, const std::string& data_buff, const epee::net_utils::connection_context_base& context, std::list& relayed_peers) + { + relayed_peers.clear(); + m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) + { + if(cntxt.peer_id && context.m_connection_id != cntxt.m_connection_id) + relayed_peers.push_back(cntxt); + return true; + }); + + BOOST_FOREACH(const auto& cntx, relayed_peers) + { + m_net_server.get_config_object().notify(command, data_buff, cntx.m_connection_id); + } + return true; + } + //----------------------------------------------------------------------------------- + template + void node_server::get_connections(std::list& connections) + { + m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) + { + connections.push_back(cntxt); + return true; + }); + } + template + void node_server::callback(p2p_connection_context& context) + { + m_payload_handler.on_callback(context); + } + //----------------------------------------------------------------------------------- + template + bool node_server::invoke_notify_to_peer(int command, const std::string& req_buff, const epee::net_utils::connection_context_base& context) + { + int res = m_net_server.get_config_object().notify(command, req_buff, context.m_connection_id); + return res > 0; + } + //----------------------------------------------------------------------------------- + template + bool node_server::invoke_command_to_peer(int command, const std::string& req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context) + { + int res = m_net_server.get_config_object().invoke(command, req_buff, resp_buff, context.m_connection_id); + return res > 0; + } + //----------------------------------------------------------------------------------- + template + bool node_server::drop_connection(const epee::net_utils::connection_context_base& context) + { + m_net_server.get_config_object().close(context.m_connection_id); + return true; + } + //----------------------------------------------------------------------------------- + template template + bool node_server::try_ping(basic_node_data& node_data, p2p_connection_context& context, t_callback cb) + { + if(!node_data.my_port) + return false; + + uint32_t actual_ip = context.m_remote_ip; + if(!m_peerlist.is_ip_allowed(actual_ip)) + return false; + std::string ip = string_tools::get_ip_string_from_int32(actual_ip); + std::string port = string_tools::num_to_string_fast(node_data.my_port); + peerid_type pr = node_data.peer_id; + bool r = m_net_server.connect_async(ip, port, m_config.m_net_config.ping_connection_timeout, [cb, /*context,*/ ip, port, pr, this]( + const typename net_server::t_connection_context& ping_context, + const boost::system::error_code& ec)->bool + { + if(ec) + { + LOG_PRINT_CC_L2(ping_context, "back ping connect failed to " << ip << ":" << port); + return false; + } + COMMAND_PING::request req; + COMMAND_PING::response rsp; + //vc2010 workaround + /*std::string ip_ = ip; + std::string port_=port; + peerid_type pr_ = pr; + auto cb_ = cb;*/ + bool inv_call_res = net_utils::async_invoke_remote_command2(ping_context.m_connection_id, COMMAND_PING::ID, req, m_net_server.get_config_object(), + [=](int code, const COMMAND_PING::response& rsp, p2p_connection_context& context) + { + if(code <= 0) + { + LOG_PRINT_CC_L2(ping_context, "Failed to invoke COMMAND_PING to " << ip << ":" << port << "(" << code << ", " << levin::get_err_descr(code) << ")"); + m_net_server.get_config_object().close(ping_context.m_connection_id); + return; + } + + if(rsp.status != PING_OK_RESPONSE_STATUS_TEXT || pr != rsp.peer_id) + { + LOG_PRINT_CC_L2(ping_context, "back ping invoke wrong response \"" << rsp.status << "\" from " << ip << ":" << port << ", hsh_peer_id=" << pr << ", rsp.peer_id=" << rsp.peer_id); + m_net_server.get_config_object().close(ping_context.m_connection_id); + return; + } + m_net_server.get_config_object().close(ping_context.m_connection_id); + cb(); + }); + + if(!inv_call_res) + { + LOG_PRINT_CC_L2(ping_context, "back ping invoke failed to " << ip << ":" << port); + m_net_server.get_config_object().close(ping_context.m_connection_id); + return false; + } + return true; + }); + if(!r) + { + LOG_ERROR("Failed to call connect_async, network error."); + } + return r; + } + //----------------------------------------------------------------------------------- + template + int node_server::handle_timed_sync(int command, typename COMMAND_TIMED_SYNC::request& arg, typename COMMAND_TIMED_SYNC::response& rsp, p2p_connection_context& context) + { + if(!handle_maintainers_entry(arg.maintrs_entry)) + { + LOG_ERROR_CCONTEXT("COMMAND_HANDSHAKE Failed, wrong maintainers entry!, closing connection."); + return 1; + } + + if(!m_payload_handler.process_payload_sync_data(arg.payload_data, context, false)) + { + LOG_ERROR_CCONTEXT("Failed to process_payload_sync_data(), dropping connection"); + drop_connection(context); + return 1; + } + + //fill response + rsp.local_time = time(NULL); + m_peerlist.get_peerlist_head(rsp.local_peerlist); + m_payload_handler.get_payload_sync_data(rsp.payload_data); + fill_maintainers_entry(rsp.maintrs_entry); + LOG_PRINT_L3("COMMAND_TIMED_SYNC"); + return 1; + } + //----------------------------------------------------------------------------------- + template + int node_server::handle_handshake(int command, typename COMMAND_HANDSHAKE::request& arg, typename COMMAND_HANDSHAKE::response& rsp, p2p_connection_context& context) + { + if(arg.node_data.network_id != P2P_NETWORK_ID) + { + + LOG_PRINT_L0("WRONG NETWORK AGENT CONNECTED! id=" << string_tools::get_str_from_guid_a(arg.node_data.network_id)); + drop_connection(context); + add_ip_fail(context.m_remote_ip); + return 1; + } + + if(!context.m_is_income) + { + LOG_ERROR_CCONTEXT("COMMAND_HANDSHAKE came not from incoming connection"); + drop_connection(context); + add_ip_fail(context.m_remote_ip); + return 1; + } + + if(context.peer_id) + { + LOG_ERROR_CCONTEXT("COMMAND_HANDSHAKE came, but seems that connection already have associated peer_id (double COMMAND_HANDSHAKE?)"); + drop_connection(context); + return 1; + } + + if(!handle_maintainers_entry(arg.maintrs_entry)) + { + LOG_ERROR_CCONTEXT("COMMAND_HANDSHAKE Failed, wrong maintainers entry!, closing connection."); + return 1; + } + + if(!m_payload_handler.process_payload_sync_data(arg.payload_data, context, true)) + { + LOG_ERROR_CCONTEXT("COMMAND_HANDSHAKE came, but process_payload_sync_data returned false, dropping connection."); + drop_connection(context); + return 1; + } + //associate peer_id with this connection + context.peer_id = arg.node_data.peer_id; + + if(arg.node_data.peer_id != m_config.m_peer_id && arg.node_data.my_port) + { + peerid_type peer_id_l = arg.node_data.peer_id; + uint32_t port_l = arg.node_data.my_port; + //try ping to be sure that we can add this peer to peer_list + try_ping(arg.node_data, context, [peer_id_l, port_l, context, this]() + { + //called only(!) if success pinged, update local peerlist + peerlist_entry pe; + pe.adr.ip = context.m_remote_ip; + pe.adr.port = port_l; + time(&pe.last_seen); + pe.id = peer_id_l; + this->m_peerlist.append_with_peer_white(pe); + LOG_PRINT_L2("PING SUCCESS " << string_tools::get_ip_string_from_int32(context.m_remote_ip) << ":" << port_l); + }); + } + + //fill response + m_peerlist.get_peerlist_head(rsp.local_peerlist); + get_local_node_data(rsp.node_data); + m_payload_handler.get_payload_sync_data(rsp.payload_data); + fill_maintainers_entry(rsp.maintrs_entry); + LOG_PRINT_GREEN("COMMAND_HANDSHAKE", LOG_LEVEL_1); + return 1; + } + //----------------------------------------------------------------------------------- + template + int node_server::handle_ping(int command, COMMAND_PING::request& arg, COMMAND_PING::response& rsp, p2p_connection_context& context) + { + LOG_PRINT_L2("COMMAND_PING"); + rsp.status = PING_OK_RESPONSE_STATUS_TEXT; + rsp.peer_id = m_config.m_peer_id; + return 1; + } + //----------------------------------------------------------------------------------- + template + bool node_server::log_peerlist() + { + std::list pl_wite; + std::list pl_gray; + m_peerlist.get_peerlist_full(pl_gray, pl_wite); + LOG_PRINT_L0(ENDL << "Peerlist white:" << ENDL << print_peerlist_to_string(pl_wite) << ENDL << "Peerlist gray:" << ENDL << print_peerlist_to_string(pl_gray) ); + return true; + } + //----------------------------------------------------------------------------------- + template + bool node_server::log_connections() + { + LOG_PRINT_L0("Connections: \r\n" << print_connections_container() ); + return true; + } + //----------------------------------------------------------------------------------- + template + std::string node_server::print_connections_container() + { + + std::stringstream ss; + m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt) + { + ss << string_tools::get_ip_string_from_int32(cntxt.m_remote_ip) << ":" << cntxt.m_remote_port + << " \t\tpeer_id " << cntxt.peer_id + << " \t\tconn_id " << string_tools::get_str_from_guid_a(cntxt.m_connection_id) << (cntxt.m_is_income ? " INC":" OUT") + << std::endl; + return true; + }); + std::string s = ss.str(); + return s; + } + //----------------------------------------------------------------------------------- + template + void node_server::on_connection_new(p2p_connection_context& context) + { + LOG_PRINT_L2("["<< net_utils::print_connection_context(context) << "] NEW CONNECTION"); + } + //----------------------------------------------------------------------------------- + template + void node_server::on_connection_close(p2p_connection_context& context) + { + LOG_PRINT_L2("["<< net_utils::print_connection_context(context) << "] CLOSE CONNECTION"); + } + //----------------------------------------------------------------------------------- +} diff --git a/src/p2p/net_node_common.h b/src/p2p/net_node_common.h new file mode 100644 index 00000000..12fe6453 --- /dev/null +++ b/src/p2p/net_node_common.h @@ -0,0 +1,84 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include "net/net_utils_base.h" +#include "p2p_protocol_defs.h" + +namespace nodetool +{ + + typedef boost::uuids::uuid uuid; + typedef boost::uuids::uuid net_connection_id; + + template + struct i_p2p_endpoint + { + virtual bool relay_notify_to_all(int command, const std::string& data_buff, const epee::net_utils::connection_context_base& context, std::list& relayed_peers) = 0; + virtual bool invoke_command_to_peer(int command, const std::string& req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)=0; + virtual bool invoke_notify_to_peer(int command, const std::string& req_buff, const epee::net_utils::connection_context_base& context)=0; + virtual bool drop_connection(const epee::net_utils::connection_context_base& context)=0; + virtual void request_callback(const epee::net_utils::connection_context_base& context)=0; + virtual uint64_t get_connections_count()=0; + virtual void get_connections(std::list& connections) = 0; + virtual void for_each_connection(std::function f)=0; + virtual bool block_ip(uint32_t adress)=0; + virtual bool add_ip_fail(uint32_t adress)=0; + virtual bool is_stop_signal_sent() = 0; + }; + + template + struct p2p_endpoint_stub: public i_p2p_endpoint + { + virtual bool relay_notify_to_all(int command, const std::string& data_buff, const epee::net_utils::connection_context_base& context, std::list& relayed_peers) + { + return false; + } + virtual bool invoke_command_to_peer(int command, const std::string& req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context) + { + return false; + } + virtual bool invoke_notify_to_peer(int command, const std::string& req_buff, const epee::net_utils::connection_context_base& context) + { + return true; + } + virtual bool drop_connection(const epee::net_utils::connection_context_base& context) + { + return false; + } + virtual void request_callback(const epee::net_utils::connection_context_base& context) + { + + } + virtual void for_each_connection(std::function f) + { + + } + + virtual uint64_t get_connections_count() + { + return false; + } + virtual void get_connections(std::list& connections) + { + + } + virtual bool block_ip(uint32_t adress) + { + return true; + } + virtual bool add_ip_fail(uint32_t adress) + { + return true; + } + virtual bool is_stop_signal_sent() + { + return false; + } + }; +} diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h new file mode 100644 index 00000000..6fdf437a --- /dev/null +++ b/src/p2p/net_peerlist.h @@ -0,0 +1,398 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include +#include +#include +#include +//#include +//#include +#include +#include +#include + +#include +#include +#include +#include + + +#include "syncobj.h" +#include "net/local_ip.h" +#include "p2p_protocol_defs.h" +#include "currency_core/currency_config.h" +#include "net_peerlist_boost_serialization.h" +#include "common/boost_serialization_helper.h" + +#define CURRENT_PEERLIST_STORAGE_ARCHIVE_VER (CURRENCY_FORMATION_VERSION + 7) + +namespace nodetool +{ + + + /************************************************************************/ + /* */ + /************************************************************************/ + class peerlist_manager + { + public: + bool init(bool allow_local_ip); + bool deinit(); + size_t get_white_peers_count(){CRITICAL_REGION_LOCAL(m_peerlist_lock); return m_peers_white.size();} + size_t get_gray_peers_count(){CRITICAL_REGION_LOCAL(m_peerlist_lock); return m_peers_gray.size();} + bool merge_peerlist(const std::list& outer_bs); + bool get_peerlist_head(std::list& bs_head, uint32_t depth = P2P_DEFAULT_PEERS_IN_HANDSHAKE); + bool get_peerlist_full(std::list& pl_gray, std::list& pl_white); + bool get_white_peer_by_index(peerlist_entry& p, size_t i); + bool get_gray_peer_by_index(peerlist_entry& p, size_t i); + bool append_with_peer_white(const peerlist_entry& pr); + bool append_with_peer_gray(const peerlist_entry& pr); + bool set_peer_just_seen(peerid_type peer, uint32_t ip, uint32_t port); + bool set_peer_just_seen(peerid_type peer, const net_address& addr); + bool set_peer_unreachable(const peerlist_entry& pr); + bool is_ip_allowed(uint32_t ip); + void trim_white_peerlist(); + void trim_gray_peerlist(); + + + private: + struct by_time{}; + struct by_id{}; + struct by_addr{}; + + struct modify_all_but_id + { + modify_all_but_id(const peerlist_entry& ple):m_ple(ple){} + void operator()(peerlist_entry& e) + { + e.id = m_ple.id; + } + private: + const peerlist_entry& m_ple; + }; + + struct modify_all + { + modify_all(const peerlist_entry& ple):m_ple(ple){} + void operator()(peerlist_entry& e) + { + e = m_ple; + } + private: + const peerlist_entry& m_ple; + }; + + struct modify_last_seen + { + modify_last_seen(time_t last_seen):m_last_seen(last_seen){} + void operator()(peerlist_entry& e) + { + e.last_seen = m_last_seen; + } + private: + time_t m_last_seen; + }; + + + typedef boost::multi_index_container< + peerlist_entry, + boost::multi_index::indexed_by< + // access by peerlist_entry::net_adress + boost::multi_index::ordered_unique, boost::multi_index::member >, + // sort by peerlist_entry::last_seen< + boost::multi_index::ordered_non_unique, boost::multi_index::member > + > + > peers_indexed; + + typedef boost::multi_index_container< + peerlist_entry, + boost::multi_index::indexed_by< + // access by peerlist_entry::id< + boost::multi_index::ordered_unique, boost::multi_index::member >, + // access by peerlist_entry::net_adress + boost::multi_index::ordered_unique, boost::multi_index::member >, + // sort by peerlist_entry::last_seen< + boost::multi_index::ordered_non_unique, boost::multi_index::member > + > + > peers_indexed_old; + public: + + template + void serialize(Archive &ar, const t_version_type ver) + { + if(ver < CURRENT_PEERLIST_STORAGE_ARCHIVE_VER) + throw std::runtime_error("not supported storage format"); + CHECK_PROJECT_NAME(); + CRITICAL_REGION_LOCAL(m_peerlist_lock); + ar & m_peers_white; + ar & m_peers_gray; + } + + private: + bool peers_indexed_from_old(const peers_indexed_old& pio, peers_indexed& pi); + + friend class boost::serialization::access; + epee::critical_section m_peerlist_lock; + std::string m_config_folder; + bool m_allow_local_ip; + + + peers_indexed m_peers_gray; + peers_indexed m_peers_white; + }; + //-------------------------------------------------------------------------------------------------- + inline + bool peerlist_manager::init(bool allow_local_ip) + { + time_t now = 0; + time(&now); + m_allow_local_ip = allow_local_ip; + + //adjust local time if it somehow was shifted + CRITICAL_REGION_LOCAL(m_peerlist_lock); + peers_indexed::index::type& by_time_index = m_peers_white.get(); + for(auto& v1: by_time_index) + { + if (v1.last_seen > now) + { + LOG_PRINT_L0("Local m_peers_white entries detected in future, cleaning peerlist."); + by_time_index.clear(); + break; + } + } + + peers_indexed::index::type& by_time_index_g = m_peers_gray.get(); + for (auto& v1 : by_time_index_g) + { + if (v1.last_seen > now) + { + LOG_PRINT_L0("Local m_peers_gray entries detected in future, cleaning peerlist."); + by_time_index_g.clear(); + break; + } + } + + + return true; + } + //-------------------------------------------------------------------------------------------------- + inline + bool peerlist_manager::deinit() + { + return true; + } + //-------------------------------------------------------------------------------------------------- + inline + bool peerlist_manager::peers_indexed_from_old(const peers_indexed_old& pio, peers_indexed& pi) + { + for(auto x: pio) + { + auto by_addr_it = pi.get().find(x.adr); + if(by_addr_it == pi.get().end()) + { + pi.insert(x); + } + } + + return true; + } + //-------------------------------------------------------------------------------------------------- + inline void peerlist_manager::trim_white_peerlist() + { + CRITICAL_REGION_LOCAL(m_peerlist_lock); + while(m_peers_gray.size() > P2P_LOCAL_GRAY_PEERLIST_LIMIT) + { + peers_indexed::index::type& sorted_index=m_peers_gray.get(); + sorted_index.erase(sorted_index.begin()); + } + } + //-------------------------------------------------------------------------------------------------- + inline void peerlist_manager::trim_gray_peerlist() + { + CRITICAL_REGION_LOCAL(m_peerlist_lock); + while(m_peers_white.size() > P2P_LOCAL_WHITE_PEERLIST_LIMIT) + { + peers_indexed::index::type& sorted_index=m_peers_white.get(); + sorted_index.erase(sorted_index.begin()); + } + } + //-------------------------------------------------------------------------------------------------- + inline + bool peerlist_manager::merge_peerlist(const std::list& outer_bs) + { + CRITICAL_REGION_LOCAL(m_peerlist_lock); + BOOST_FOREACH(const peerlist_entry& be, outer_bs) + { + append_with_peer_gray(be); + } + // delete extra elements + trim_gray_peerlist(); + return true; + } + //-------------------------------------------------------------------------------------------------- + inline + bool peerlist_manager::get_white_peer_by_index(peerlist_entry& p, size_t i) + { + CRITICAL_REGION_LOCAL(m_peerlist_lock); + if(i >= m_peers_white.size()) + return false; + + peers_indexed::index::type& by_time_index = m_peers_white.get(); + p = *std::prev(--by_time_index.end(), i); + return true; + } + //-------------------------------------------------------------------------------------------------- + inline + bool peerlist_manager::get_gray_peer_by_index(peerlist_entry& p, size_t i) + { + CRITICAL_REGION_LOCAL(m_peerlist_lock); + if(i >= m_peers_gray.size()) + return false; + + peers_indexed::index::type& by_time_index = m_peers_gray.get(); + p = *std::prev(--by_time_index.end(), i); + return true; + } + //-------------------------------------------------------------------------------------------------- + inline + bool peerlist_manager::is_ip_allowed(uint32_t ip) + { + //never allow loopback ip + if(epee::net_utils::is_ip_loopback(ip)) + return false; + + if(!m_allow_local_ip && epee::net_utils::is_ip_local(ip)) + return false; + + return true; + } + //-------------------------------------------------------------------------------------------------- + inline + bool peerlist_manager::get_peerlist_head(std::list& bs_head, uint32_t depth) + { + + CRITICAL_REGION_LOCAL(m_peerlist_lock); + peers_indexed::index::type& by_time_index=m_peers_white.get(); + uint32_t cnt = 0; + BOOST_REVERSE_FOREACH(const peers_indexed::value_type& vl, by_time_index) + { + if(!vl.last_seen) + continue; + bs_head.push_back(vl); + if(cnt++ > depth) + break; + } + return true; + } + //-------------------------------------------------------------------------------------------------- + inline + bool peerlist_manager::get_peerlist_full(std::list& pl_gray, std::list& pl_white) + { + CRITICAL_REGION_LOCAL(m_peerlist_lock); + peers_indexed::index::type& by_time_index_gr=m_peers_gray.get(); + BOOST_REVERSE_FOREACH(const peers_indexed::value_type& vl, by_time_index_gr) + { + pl_gray.push_back(vl); + } + + peers_indexed::index::type& by_time_index_wt=m_peers_white.get(); + BOOST_REVERSE_FOREACH(const peers_indexed::value_type& vl, by_time_index_wt) + { + pl_white.push_back(vl); + } + + return true; + } + //-------------------------------------------------------------------------------------------------- + inline + bool peerlist_manager::set_peer_just_seen(peerid_type peer, uint32_t ip, uint32_t port) + { + net_address addr; + addr.ip = ip; + addr.port = port; + return set_peer_just_seen(peer, addr); + } + //-------------------------------------------------------------------------------------------------- + inline + bool peerlist_manager::set_peer_just_seen(peerid_type peer, const net_address& addr) + { + TRY_ENTRY(); + CRITICAL_REGION_LOCAL(m_peerlist_lock); + //find in white list + peerlist_entry ple; + ple.adr = addr; + ple.id = peer; + ple.last_seen = time(NULL); + return append_with_peer_white(ple); + CATCH_ENTRY_L0("peerlist_manager::set_peer_just_seen()", false); + } + //-------------------------------------------------------------------------------------------------- + inline + bool peerlist_manager::append_with_peer_white(const peerlist_entry& ple) + { + TRY_ENTRY(); + if(!is_ip_allowed(ple.adr.ip)) + return true; + + CRITICAL_REGION_LOCAL(m_peerlist_lock); + //find in white list + auto by_addr_it_wt = m_peers_white.get().find(ple.adr); + if(by_addr_it_wt == m_peers_white.get().end()) + { + //put new record into white list + m_peers_white.insert(ple); + trim_white_peerlist(); + }else + { + //update record in white list + m_peers_white.replace(by_addr_it_wt, ple); + } + //remove from gray list, if need + auto by_addr_it_gr = m_peers_gray.get().find(ple.adr); + if(by_addr_it_gr != m_peers_gray.get().end()) + { + m_peers_gray.erase(by_addr_it_gr); + } + return true; + CATCH_ENTRY_L0("peerlist_manager::append_with_peer_white()", false); + } + //-------------------------------------------------------------------------------------------------- + inline + bool peerlist_manager::append_with_peer_gray(const peerlist_entry& ple) + { + TRY_ENTRY(); + if(!is_ip_allowed(ple.adr.ip)) + return true; + + CRITICAL_REGION_LOCAL(m_peerlist_lock); + //find in white list + auto by_addr_it_wt = m_peers_white.get().find(ple.adr); + if(by_addr_it_wt != m_peers_white.get().end()) + return true; + + //update gray list + auto by_addr_it_gr = m_peers_gray.get().find(ple.adr); + if(by_addr_it_gr == m_peers_gray.get().end()) + { + //put new record into white list + m_peers_gray.insert(ple); + trim_gray_peerlist(); + }else + { + //update record in white list + m_peers_gray.replace(by_addr_it_gr, ple); + } + return true; + CATCH_ENTRY_L0("peerlist_manager::append_with_peer_gray()", false); + return true; + } + //-------------------------------------------------------------------------------------------------- +} + +BOOST_CLASS_VERSION(nodetool::peerlist_manager, CURRENT_PEERLIST_STORAGE_ARCHIVE_VER) diff --git a/src/p2p/net_peerlist_boost_serialization.h b/src/p2p/net_peerlist_boost_serialization.h new file mode 100644 index 00000000..d10370b2 --- /dev/null +++ b/src/p2p/net_peerlist_boost_serialization.h @@ -0,0 +1,30 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +namespace boost +{ + namespace serialization + { + //BOOST_CLASS_VERSION(odetool::net_adress, 1) + template + inline void serialize(Archive &a, nodetool::net_address& na, const ver_type ver) + { + a & na.ip; + a & na.port; + } + + + template + inline void serialize(Archive &a, nodetool::peerlist_entry& pl, const ver_type ver) + { + a & pl.adr; + a & pl.id; + a & pl.last_seen; + } + } +} diff --git a/src/p2p/p2p_networks.h b/src/p2p/p2p_networks.h new file mode 100644 index 00000000..3f278e92 --- /dev/null +++ b/src/p2p/p2p_networks.h @@ -0,0 +1,21 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +/* + +P2P_NETWORK_ID definition moved to net_node.inl + +namespace nodetool +{ +#ifndef TESTNET + const static boost::uuids::uuid P2P_NETWORK_ID = { { 0x11 ,0x10, 0x01, 0x11 , 0x01, 0x20 , 0x01, 0x01, 0x10, 0x11, 0x00, 0x10, 0x11, 0x11, 0x01, 0x10} }; //Bender's nightmare +#else + const static boost::uuids::uuid P2P_NETWORK_ID = { { 0x11 ,0x10, 0x01, 0x11 , 0x01, 0x02 , 0x01, 0x01, 0x10, 0x11, 0x11, 0x10, 0x11, 0x11, 0x01, 0x10} }; //Another Bender's nightmare +#endif +} +*/ diff --git a/src/p2p/p2p_protocol_defs.h b/src/p2p/p2p_protocol_defs.h new file mode 100644 index 00000000..49d819b4 --- /dev/null +++ b/src/p2p/p2p_protocol_defs.h @@ -0,0 +1,402 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include "serialization/keyvalue_serialization.h" +#include "misc_language.h" +#include "currency_core/currency_config.h" +#include "crypto/crypto.h" + +namespace nodetool +{ + typedef boost::uuids::uuid uuid; + typedef uint64_t peerid_type; + typedef std::string blobdata; + +#pragma pack (push, 1) + + struct net_address + { + uint32_t ip; + uint32_t port; + }; + + struct peerlist_entry + { + net_address adr; + peerid_type id; + time_t last_seen; + }; + + struct connection_entry + { + net_address adr; + peerid_type id; + bool is_income; + uint64_t time_started; + uint64_t last_recv; + uint64_t last_send; + }; + +#pragma pack(pop) + + inline + bool operator < (const net_address& a, const net_address& b) + { + return epee::misc_utils::is_less_as_pod(a, b); + } + + inline + bool operator == (const net_address& a, const net_address& b) + { + return memcmp(&a, &b, sizeof(a)) == 0; + } + inline + std::string print_peerlist_to_string(const std::list& pl) + { + time_t now_time = 0; + time(&now_time); + std::stringstream ss; + ss << std::setfill ('0') << std::setw (8) << std::hex << std::noshowbase; + BOOST_FOREACH(const peerlist_entry& pe, pl) + { + ss << pe.id << "\t" << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << ":" << boost::lexical_cast(pe.adr.port) << " \tlast_seen: " << epee::misc_utils::get_time_interval_string(now_time - pe.last_seen) << std::endl; + } + return ss.str(); + } + + + struct network_config + { + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(connections_count) + KV_SERIALIZE(handshake_interval) + KV_SERIALIZE(packet_max_size) + KV_SERIALIZE(config_id) + END_KV_SERIALIZE_MAP() + + uint32_t connections_count; + uint32_t connection_timeout; + uint32_t ping_connection_timeout; + uint32_t handshake_interval; + uint32_t packet_max_size; + uint32_t config_id; + uint32_t send_peerlist_sz; + }; + + struct basic_node_data + { + uuid network_id; + int64_t local_time; + uint32_t my_port; + peerid_type peer_id; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_VAL_POD_AS_BLOB(network_id) + KV_SERIALIZE(peer_id) + KV_SERIALIZE(local_time) + KV_SERIALIZE(my_port) + END_KV_SERIALIZE_MAP() + }; + + +#define P2P_COMMANDS_POOL_BASE 1000 + + /************************************************************************/ + /* */ + /************************************************************************/ +#define ALERT_TYPE_CALM 1 +#define ALERT_TYPE_URGENT 2 +#define ALERT_TYPE_CRITICAL 3 + + /* + Don't put any strings into maintainers message: if secret key will + be stolen it can be used maliciously. + */ + struct alert_condition + { + uint32_t if_build_less_then; //apply alert if build less then + uint8_t alert_mode; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_N(if_build_less_then, "build") + KV_SERIALIZE_N(alert_mode, "mode") + END_KV_SERIALIZE_MAP() + }; + + struct maintainers_info + { + uint64_t timestamp; + /*actual version*/ + uint8_t ver_major; + uint8_t ver_minor; + uint8_t ver_revision; + uint32_t build_no; + /*conditions for alerting*/ + std::list conditions; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_N(timestamp, "ts") + KV_SERIALIZE_N(ver_major, "maj") + KV_SERIALIZE_N(ver_minor, "min") + KV_SERIALIZE_N(ver_revision, "rev") + KV_SERIALIZE_N(build_no, "build") + KV_SERIALIZE_N(conditions, "cs") + END_KV_SERIALIZE_MAP() + }; + + struct maintainers_entry + { + blobdata maintainers_info_buff; + crypto::signature sign; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(maintainers_info_buff) + KV_SERIALIZE_VAL_POD_AS_BLOB(sign) + END_KV_SERIALIZE_MAP() + }; + + struct maintainers_info_external + { + uint8_t ver_major; + uint8_t ver_minor; + uint8_t ver_revision; + uint32_t build_no; + uint8_t mode; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(ver_major) + KV_SERIALIZE(ver_minor) + KV_SERIALIZE(ver_revision) + KV_SERIALIZE(build_no) + KV_SERIALIZE(mode) + END_KV_SERIALIZE_MAP() + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + template + struct COMMAND_HANDSHAKE_T + { + const static int ID = P2P_COMMANDS_POOL_BASE + 1; + + struct request + { + basic_node_data node_data; + t_playload_type payload_data; + maintainers_entry maintrs_entry; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(node_data) + KV_SERIALIZE(payload_data) + KV_SERIALIZE(maintrs_entry) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + basic_node_data node_data; + t_playload_type payload_data; + std::list local_peerlist; + maintainers_entry maintrs_entry; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(node_data) + KV_SERIALIZE(payload_data) + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(local_peerlist) + KV_SERIALIZE(maintrs_entry) + END_KV_SERIALIZE_MAP() + }; + }; + + + /************************************************************************/ + /* */ + /************************************************************************/ + template + struct COMMAND_TIMED_SYNC_T + { + const static int ID = P2P_COMMANDS_POOL_BASE + 2; + + struct request + { + t_playload_type payload_data; + maintainers_entry maintrs_entry; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(payload_data) + KV_SERIALIZE(maintrs_entry) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + int64_t local_time; + t_playload_type payload_data; + std::list local_peerlist; + maintainers_entry maintrs_entry; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(local_time) + KV_SERIALIZE(payload_data) + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(local_peerlist) + KV_SERIALIZE(maintrs_entry) + END_KV_SERIALIZE_MAP() + }; + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + + struct COMMAND_PING + { + /* + Used to make "callback" connection, to be sure that opponent node + have accessible connection point. Only other nodes can add peer to peerlist, + and ONLY in case when peer has accepted connection and answered to ping. + */ + const static int ID = P2P_COMMANDS_POOL_BASE + 3; + +#define PING_OK_RESPONSE_STATUS_TEXT "OK" + + struct request + { + /*actually we don't need to send any real data*/ + + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + peerid_type peer_id; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(peer_id) + END_KV_SERIALIZE_MAP() + }; + }; + + +#ifdef ALLOW_DEBUG_COMMANDS + //These commands are considered as insecure, and made in debug purposes for a limited lifetime. + //Anyone who feel unsafe with this commands can disable the ALLOW_GET_STAT_COMMAND macro. + + struct proof_of_trust + { + peerid_type peer_id; + int64_t time; + crypto::signature sign; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(peer_id) + KV_SERIALIZE(time) + KV_SERIALIZE_VAL_POD_AS_BLOB(sign) + END_KV_SERIALIZE_MAP() + }; + + + template + struct COMMAND_REQUEST_STAT_INFO_T + { + const static int ID = P2P_COMMANDS_POOL_BASE + 4; + + struct request + { + typename payload_stat_info::params pr; + proof_of_trust tr; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(pr) + KV_SERIALIZE(tr) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string version; + uint64_t connections_count; + uint64_t incoming_connections_count; + payload_stat_info payload_info; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(version) + KV_SERIALIZE(connections_count) + KV_SERIALIZE(incoming_connections_count) + KV_SERIALIZE(payload_info) + END_KV_SERIALIZE_MAP() + }; + }; + + + /************************************************************************/ + /* */ + /************************************************************************/ + struct COMMAND_REQUEST_NETWORK_STATE + { + const static int ID = P2P_COMMANDS_POOL_BASE + 5; + + struct request + { + proof_of_trust tr; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(tr) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::list local_peerlist_white; + std::list local_peerlist_gray; + std::list connections_list; + peerid_type my_id; + uint64_t local_time; + uint64_t up_time; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(local_peerlist_white) + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(local_peerlist_gray) + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(connections_list) + KV_SERIALIZE(my_id) + KV_SERIALIZE(local_time) + KV_SERIALIZE(up_time) + END_KV_SERIALIZE_MAP() + }; + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + struct COMMAND_REQUEST_PEER_ID + { + const static int ID = P2P_COMMANDS_POOL_BASE + 6; + + struct request + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct response + { + peerid_type my_id; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(my_id) + END_KV_SERIALIZE_MAP() + }; + }; + +#endif + +} + + + diff --git a/src/pch/stdafx.cpp b/src/pch/stdafx.cpp new file mode 100644 index 00000000..1577c4e3 --- /dev/null +++ b/src/pch/stdafx.cpp @@ -0,0 +1 @@ +#include "stdafx.h" \ No newline at end of file diff --git a/src/pch/stdafx.h b/src/pch/stdafx.h new file mode 100644 index 00000000..e5396219 --- /dev/null +++ b/src/pch/stdafx.h @@ -0,0 +1,107 @@ +// Copyright (c) 2014-2017 The The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +// +// std +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "warnings.h" // epee header for warnings disable aid + +// +// boost +// +#include +#include +#include +#include +PUSH_WARNINGS + DISABLE_VS_WARNINGS(4800) + #include +POP_WARNINGS +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// epee +// +#include "include_base_utils.h" +#include "misc_language.h" +#include "misc_log_ex.h" + +#include "cache_helper.h" +#include "copyable_atomic.h" +#include "file_io_utils.h" +#include "math_helper.h" +#include "net/net_utils_base.h" +#include "net/rpc_method_name.h" +#include "profile_tools.h" +#include "readwrite_lock.h" +#include "serialization/keyvalue_serialization.h" +#include "storages/portable_storage_template_helper.h" +#include "string_tools.h" +#include "syncobj.h" +#include "zlib_helper.h" + +// +// contrib +// +#include "ethereum/libethash/internal.h" +#include "eos_portable_archive/eos/portable_archive.hpp" +#include "db/liblmdb/lmdb.h" diff --git a/src/platform/mingw/alloca.h b/src/platform/mingw/alloca.h new file mode 100644 index 00000000..9e18ae9e --- /dev/null +++ b/src/platform/mingw/alloca.h @@ -0,0 +1,7 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include diff --git a/src/platform/msc/alloca.h b/src/platform/msc/alloca.h new file mode 100644 index 00000000..918bdd1f --- /dev/null +++ b/src/platform/msc/alloca.h @@ -0,0 +1,7 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +//#define alloca(size) _alloca(size) diff --git a/src/platform/msc/inline_c.h b/src/platform/msc/inline_c.h new file mode 100644 index 00000000..bfd46237 --- /dev/null +++ b/src/platform/msc/inline_c.h @@ -0,0 +1,10 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + + +#ifndef __cplusplus +#define inline __inline +#endif diff --git a/src/platform/msc/stdbool.h b/src/platform/msc/stdbool.h new file mode 100644 index 00000000..2e1a0673 --- /dev/null +++ b/src/platform/msc/stdbool.h @@ -0,0 +1,13 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#if !defined(__cplusplus) + +typedef int bool; +#define true 1 +#define false 0 + +#endif diff --git a/src/platform/msc/sys/param.h b/src/platform/msc/sys/param.h new file mode 100644 index 00000000..b44de84b --- /dev/null +++ b/src/platform/msc/sys/param.h @@ -0,0 +1,10 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#define LITTLE_ENDIAN 1234 +#define BIG_ENDIAN 4321 +#define PDP_ENDIAN 3412 +#define BYTE_ORDER LITTLE_ENDIAN diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp new file mode 100644 index 00000000..92c11ddf --- /dev/null +++ b/src/rpc/core_rpc_server.cpp @@ -0,0 +1,1243 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "include_base_utils.h" +using namespace epee; + +#include "core_rpc_server.h" +#include "common/command_line.h" +#include "currency_core/currency_format_utils.h" +#include "currency_core/account.h" + +#include "misc_language.h" +#include "crypto/hash.h" +#include "core_rpc_server_error_codes.h" + + + +namespace currency +{ + namespace + { + const command_line::arg_descriptor arg_rpc_bind_ip = {"rpc-bind-ip", "", "127.0.0.1"}; + const command_line::arg_descriptor arg_rpc_bind_port = {"rpc-bind-port", "", std::to_string(RPC_DEFAULT_PORT)}; + } + //----------------------------------------------------------------------------------- + void core_rpc_server::init_options(boost::program_options::options_description& desc) + { + command_line::add_arg(desc, arg_rpc_bind_ip); + command_line::add_arg(desc, arg_rpc_bind_port); + } + //------------------------------------------------------------------------------------------------------------------------------ + core_rpc_server::core_rpc_server(core& cr, nodetool::node_server >& p2p, + bc_services::bc_offers_service& of + ) :m_core(cr), m_p2p(p2p), m_of(of), m_session_counter(0) + {} + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::handle_command_line(const boost::program_options::variables_map& vm) + { + m_bind_ip = command_line::get_arg(vm, arg_rpc_bind_ip); + m_port = command_line::get_arg(vm, arg_rpc_bind_port); + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::init(const boost::program_options::variables_map& vm) + { + m_net_server.set_threads_prefix("RPC"); + bool r = handle_command_line(vm); + CHECK_AND_ASSERT_MES(r, false, "Failed to process command line in core_rpc_server"); + return epee::http_server_impl_base::init(m_port, m_bind_ip); + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::check_core_ready_(const std::string& calling_method) + { +#ifndef TESTNET + if(!m_p2p.get_payload_object().is_synchronized()) + { + LOG_PRINT_L0("[" << calling_method << "]Core busy cz is_synchronized"); + return false; + } + #endif + return true; + } +#define check_core_ready() check_core_ready_(LOCAL_FUNCTION_DEF__) +#define CHECK_CORE_READY() if(!check_core_ready()){res.status = CORE_RPC_STATUS_BUSY;return true;} + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_height(const COMMAND_RPC_GET_HEIGHT::request& req, COMMAND_RPC_GET_HEIGHT::response& res, connection_context& cntx) + { + CHECK_CORE_READY(); + res.height = m_core.get_current_blockchain_size(); + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res, connection_context& cntx) + { + //unconditional values + res.height = m_core.get_current_blockchain_size(); + res.tx_count = m_core.get_blockchain_storage().get_total_transactions() - res.height; //without coinbase + res.tx_pool_size = m_core.get_pool_transactions_count(); + res.alt_blocks_count = m_core.get_blockchain_storage().get_alternative_blocks_count(); + uint64_t total_conn = m_p2p.get_connections_count(); + res.outgoing_connections_count = m_p2p.get_outgoing_connections_count(); + res.incoming_connections_count = total_conn - res.outgoing_connections_count; + res.synchronized_connections_count = m_p2p.get_payload_object().get_synchronized_connections_count(); + res.white_peerlist_size = m_p2p.get_peerlist_manager().get_white_peers_count(); + res.grey_peerlist_size = m_p2p.get_peerlist_manager().get_gray_peers_count(); + res.current_blocks_median = m_core.get_blockchain_storage().get_current_comulative_blocksize_limit() / 2; + res.alias_count = m_core.get_blockchain_storage().get_aliases_count(); + res.current_max_allowed_block_size = m_core.get_blockchain_storage().get_current_comulative_blocksize_limit(); + if (!res.outgoing_connections_count) + res.daemon_network_state = COMMAND_RPC_GET_INFO::daemon_network_state_connecting; + else if (res.synchronized_connections_count > total_conn/2 ) /* m_p2p.get_payload_object().is_synchronized()*/ + res.daemon_network_state = COMMAND_RPC_GET_INFO::daemon_network_state_online; + else + res.daemon_network_state = COMMAND_RPC_GET_INFO::daemon_network_state_synchronizing; + res.synchronization_start_height = m_p2p.get_payload_object().get_core_inital_height(); + res.max_net_seen_height = m_p2p.get_payload_object().get_max_seen_height(); + m_p2p.get_maintainers_info(res.mi); + res.pos_allowed = m_core.get_blockchain_storage().is_pos_allowed(); + wide_difficulty_type pos_diff = m_core.get_blockchain_storage().get_cached_next_difficulty(true); + res.pos_difficulty = pos_diff.convert_to(); + res.pow_difficulty = m_core.get_blockchain_storage().get_cached_next_difficulty(false).convert_to(); + res.default_fee = m_core.get_blockchain_storage().get_core_runtime_config().tx_default_fee; + res.minimum_fee = m_core.get_blockchain_storage().get_core_runtime_config().tx_pool_min_fee; + + //conditional values + if (req.flags&COMMAND_RPC_GET_INFO_FLAG_NET_TIME_DELTA_MEDIAN) + res.net_time_delta_median = m_p2p.get_payload_object().get_net_time_delta_median(); + if (req.flags&COMMAND_RPC_GET_INFO_FLAG_CURRENT_NETWORK_HASHRATE_50) + res.current_network_hashrate_50 = m_core.get_blockchain_storage().get_current_hashrate(50); + if (req.flags&COMMAND_RPC_GET_INFO_FLAG_CURRENT_NETWORK_HASHRATE_350) + res.current_network_hashrate_350 = m_core.get_blockchain_storage().get_current_hashrate(350); + if (req.flags&COMMAND_RPC_GET_INFO_FLAG_SECONDS_FOR_10_BLOCKS) + res.seconds_for_10_blocks = m_core.get_blockchain_storage().get_seconds_between_last_n_block(10); + if (req.flags&COMMAND_RPC_GET_INFO_FLAG_SECONDS_FOR_30_BLOCKS) + res.seconds_for_30_blocks = m_core.get_blockchain_storage().get_seconds_between_last_n_block(30); + if (req.flags&COMMAND_RPC_GET_INFO_FLAG_TRANSACTIONS_DAILY_STAT) + m_core.get_blockchain_storage().get_transactions_daily_stat(res.transactions_cnt_per_day, res.transactions_volume_per_day); + if (req.flags&COMMAND_RPC_GET_INFO_FLAG_LAST_POS_TIMESTAMP) + { + auto pos_bl_ptr = m_core.get_blockchain_storage().get_last_block_of_type(true); + if (pos_bl_ptr) + res.last_pos_timestamp = pos_bl_ptr->bl.timestamp; + } + if (req.flags&COMMAND_RPC_GET_INFO_FLAG_LAST_POW_TIMESTAMP) + { + auto pow_bl_ptr = m_core.get_blockchain_storage().get_last_block_of_type(false); + if (pow_bl_ptr) + res.last_pow_timestamp = pow_bl_ptr->bl.timestamp; + } + if (req.flags&COMMAND_RPC_GET_INFO_FLAG_TOTAL_COINS) + res.total_coins = m_core.get_blockchain_storage().total_coins(); + if (req.flags&COMMAND_RPC_GET_INFO_FLAG_LAST_BLOCK_SIZE) + { + std::vector sz; + m_core.get_blockchain_storage().get_last_n_blocks_sizes(sz, 1); + res.last_block_size = sz.size() ? sz.back() : 0; + } + if (req.flags&COMMAND_RPC_GET_INFO_FLAG_TX_COUNT_IN_LAST_BLOCK) + { + currency::block b = AUTO_VAL_INIT(b); + m_core.get_blockchain_storage().get_top_block(b); + res.tx_count_in_last_block = b.tx_hashes.size(); + } + if (req.flags&COMMAND_RPC_GET_INFO_FLAG_POS_SEQUENCE_FACTOR) + res.pos_sequence_factor = m_core.get_blockchain_storage().get_current_sequence_factor(true); + if (req.flags&COMMAND_RPC_GET_INFO_FLAG_POW_SEQUENCE_FACTOR) + res.pow_sequence_factor = m_core.get_blockchain_storage().get_current_sequence_factor(false); + if (req.flags&(COMMAND_RPC_GET_INFO_FLAG_POS_DIFFICULTY | COMMAND_RPC_GET_INFO_FLAG_TOTAL_COINS)) + { + res.block_reward = currency::get_base_block_reward(true, res.total_coins, res.height); + currency::block b = AUTO_VAL_INIT(b); + m_core.get_blockchain_storage().get_top_block(b); + res.last_block_total_reward = currency::get_reward_from_miner_tx(b.miner_tx); + res.pos_diff_total_coins_rate = (pos_diff / (res.total_coins - PREMINE_AMOUNT + 1)).convert_to(); + } + if (req.flags&COMMAND_RPC_GET_INFO_FLAG_POS_BLOCK_TS_SHIFT_VS_ACTUAL) + { + res.pos_block_ts_shift_vs_actual = 0; + auto last_pos_block_ptr = m_core.get_blockchain_storage().get_last_block_of_type(true); + if (last_pos_block_ptr) + res.pos_block_ts_shift_vs_actual = last_pos_block_ptr->bl.timestamp - get_actual_timestamp(last_pos_block_ptr->bl); + } + if (req.flags&COMMAND_RPC_GET_INFO_FLAG_OUTS_STAT) + m_core.get_blockchain_storage().get_outs_index_stat(res.outs_stat); + + if (req.flags&COMMAND_RPC_GET_INFO_FLAG_PERFORMANCE) + { + currency::blockchain_storage::performnce_data& pd = m_core.get_blockchain_storage().get_performnce_data(); + //block processing zone + res.performance_data.block_processing_time_0 = pd.block_processing_time_0_ms.get_avg()*1000; + res.performance_data.block_processing_time_1 = pd.block_processing_time_1.get_avg(); + res.performance_data.target_calculating_time_2 = pd.target_calculating_time_2.get_avg(); + res.performance_data.longhash_calculating_time_3 = pd.longhash_calculating_time_3.get_avg(); + res.performance_data.all_txs_insert_time_5 = pd.all_txs_insert_time_5.get_avg(); + res.performance_data.etc_stuff_6 = pd.etc_stuff_6.get_avg(); + res.performance_data.insert_time_4 = pd.insert_time_4.get_avg(); + res.performance_data.raise_block_core_event = pd.raise_block_core_event.get_avg(); + //tx processing zone + res.performance_data.tx_check_inputs_time = pd.tx_check_inputs_time.get_avg(); + res.performance_data.tx_add_one_tx_time = pd.tx_add_one_tx_time.get_avg(); + res.performance_data.tx_process_extra = pd.tx_process_extra.get_avg(); + res.performance_data.tx_process_attachment = pd.tx_process_attachment.get_avg(); + res.performance_data.tx_process_inputs = pd.tx_process_inputs.get_avg(); + res.performance_data.tx_push_global_index = pd.tx_push_global_index.get_avg(); + res.performance_data.tx_check_exist = pd.tx_check_exist.get_avg(); + res.performance_data.tx_append_time = pd.tx_append_time.get_avg(); + res.performance_data.tx_append_rl_wait = pd.tx_append_rl_wait.get_avg(); + res.performance_data.tx_append_is_expired = pd.tx_append_is_expired.get_avg(); + + + res.performance_data.tx_store_db = pd.tx_store_db.get_avg(); + //db performance count + res.performance_data.map_size = pd.si.map_size; + res.performance_data.tx_count = pd.si.tx_count; + res.performance_data.writer_tx_count = pd.si.write_tx_count; +#define COPY_AVG_TO_BLOCK_CHAIN_PERF_DATA(field_name) res.performance_data.field_name = pd.field_name.get_avg(); + COPY_AVG_TO_BLOCK_CHAIN_PERF_DATA(tx_check_inputs_prefix_hash); + COPY_AVG_TO_BLOCK_CHAIN_PERF_DATA(tx_check_inputs_attachment_check); + COPY_AVG_TO_BLOCK_CHAIN_PERF_DATA(tx_check_inputs_loop); + COPY_AVG_TO_BLOCK_CHAIN_PERF_DATA(tx_check_inputs_loop_kimage_check); + COPY_AVG_TO_BLOCK_CHAIN_PERF_DATA(tx_check_inputs_loop_ch_in_val_sig); + COPY_AVG_TO_BLOCK_CHAIN_PERF_DATA(tx_check_inputs_loop_scan_outputkeys_get_item_size); + COPY_AVG_TO_BLOCK_CHAIN_PERF_DATA(tx_check_inputs_loop_scan_outputkeys_relative_to_absolute); + COPY_AVG_TO_BLOCK_CHAIN_PERF_DATA(tx_check_inputs_loop_scan_outputkeys_loop); + COPY_AVG_TO_BLOCK_CHAIN_PERF_DATA(tx_check_inputs_loop_scan_outputkeys_loop_get_subitem); + COPY_AVG_TO_BLOCK_CHAIN_PERF_DATA(tx_check_inputs_loop_scan_outputkeys_loop_find_tx); + COPY_AVG_TO_BLOCK_CHAIN_PERF_DATA(tx_check_inputs_loop_scan_outputkeys_loop_handle_output); + + //tx pool perfromance stat + const currency::tx_memory_pool::performnce_data& pool_pd = m_core.get_tx_pool().get_performnce_data(); +#define COPY_AVG_TO_POOL_PERF_DATA(field_name) res.tx_pool_performance_data.field_name = pool_pd.field_name.get_avg(); + COPY_AVG_TO_POOL_PERF_DATA(tx_processing_time); + COPY_AVG_TO_POOL_PERF_DATA(check_inputs_types_supported_time); + COPY_AVG_TO_POOL_PERF_DATA(expiration_validate_time); + COPY_AVG_TO_POOL_PERF_DATA(validate_amount_time); + COPY_AVG_TO_POOL_PERF_DATA(validate_alias_time); + COPY_AVG_TO_POOL_PERF_DATA(check_keyimages_ws_ms_time); + COPY_AVG_TO_POOL_PERF_DATA(check_inputs_time); + COPY_AVG_TO_POOL_PERF_DATA(begin_tx_time); + COPY_AVG_TO_POOL_PERF_DATA(update_db_time); + COPY_AVG_TO_POOL_PERF_DATA(db_commit_time); + + } + if (req.flags&COMMAND_RPC_GET_INFO_FLAG_PERFORMANCE) + { + res.offers_count = m_of.get_offers_container().size(); + } + if (req.flags&COMMAND_RPC_GET_INFO_FLAG_EXPIRATIONS_MEDIAN) + { + res.expiration_median_timestamp = m_core.get_blockchain_storage().get_tx_expiration_median(); + } + + + + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_blocks_direct(const COMMAND_RPC_GET_BLOCKS_DIRECT::request& req, COMMAND_RPC_GET_BLOCKS_DIRECT::response& res, connection_context& cntx) + { + CHECK_CORE_READY(); + + if (req.block_ids.back() != m_core.get_blockchain_storage().get_block_id_by_height(0)) + { + //genesis mismatch, return specific + res.status = CORE_RPC_STATUS_GENESIS_MISMATCH; + return true; + } + + blockchain_storage::blocks_direct_container bs; + if(!m_core.get_blockchain_storage().find_blockchain_supplement(req.block_ids, bs, res.current_height, res.start_height, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT)) + { + res.status = CORE_RPC_STATUS_FAILED; + return false; + } + + for(auto& b: bs) + { + res.blocks.resize(res.blocks.size()+1); + res.blocks.back().block_ptr = b.first; + res.blocks.back().txs_ptr = std::move(b.second); + } + + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res, connection_context& cntx) + { + CHECK_CORE_READY(); + + if (req.block_ids.back() != m_core.get_blockchain_storage().get_block_id_by_height(0)) + { + //genesis mismatch, return specific + res.status = CORE_RPC_STATUS_GENESIS_MISMATCH; + return true; + } + + std::list > > bs; + if(!m_core.find_blockchain_supplement(req.block_ids, bs, res.current_height, res.start_height, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT)) + { + res.status = CORE_RPC_STATUS_FAILED; + return false; + } + + BOOST_FOREACH(auto& b, bs) + { + res.blocks.resize(res.blocks.size()+1); + res.blocks.back().block = block_to_blob(b.first); + BOOST_FOREACH(auto& t, b.second) + { + res.blocks.back().txs.push_back(tx_to_blob(t)); + } + } + + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_random_outs(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res, connection_context& cntx) + { + CHECK_CORE_READY(); + res.status = "Failed"; + if(!m_core.get_random_outs_for_amounts(req, res)) + { + return true; + } + + res.status = CORE_RPC_STATUS_OK; + std::stringstream ss; + typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount outs_for_amount; + typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry; + std::for_each(res.outs.begin(), res.outs.end(), [&](outs_for_amount& ofa) + { + ss << "[" << ofa.amount << "]:"; + CHECK_AND_ASSERT_MES(ofa.outs.size(), ;, "internal error: ofa.outs.size() is empty for amount " << ofa.amount); + std::for_each(ofa.outs.begin(), ofa.outs.end(), [&](out_entry& oe) + { + ss << oe.global_amount_index << " "; + }); + ss << ENDL; + }); + std::string s = ss.str(); + LOG_PRINT_L2("COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS: " << ENDL << s); + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res, connection_context& cntx) + { + CHECK_CORE_READY(); + bool r = m_core.get_tx_outputs_gindexs(req.txid, res.o_indexes); + if(!r) + { + res.status = "Failed"; + return true; + } + res.status = CORE_RPC_STATUS_OK; + LOG_PRINT_L2("COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES: [" << res.o_indexes.size() << "]"); + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_set_maintainers_info(const COMMAND_RPC_SET_MAINTAINERS_INFO::request& req, COMMAND_RPC_SET_MAINTAINERS_INFO::response& res, connection_context& cntx) + { + if(!m_p2p.handle_maintainers_entry(req)) + { + res.status = "Failed to get call handle_maintainers_entry()"; + return true; + } + + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_tx_pool(const COMMAND_RPC_GET_TX_POOL::request& req, COMMAND_RPC_GET_TX_POOL::response& res, connection_context& cntx) + { + CHECK_CORE_READY(); + std::list txs; + if (!m_core.get_pool_transactions(txs)) + { + res.status = "Failed to call get_pool_transactions()"; + return true; + } + + for(auto& tx: txs) + { + res.txs.push_back(t_serializable_object_to_blob(tx)); + } + res.status = CORE_RPC_STATUS_OK; + return true; + } + bool core_rpc_server::on_scan_pos(const COMMAND_RPC_SCAN_POS::request& req, COMMAND_RPC_SCAN_POS::response& res, connection_context& cntx) + { + CHECK_CORE_READY(); + m_core.get_blockchain_storage().scan_pos(req, res); + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_check_keyimages(const COMMAND_RPC_CHECK_KEYIMAGES::request& req, COMMAND_RPC_CHECK_KEYIMAGES::response& res, connection_context& cntx) + { + m_core.get_blockchain_storage().check_keyimages(req.images, res.images_stat); + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res, connection_context& cntx) + { + CHECK_CORE_READY(); + std::vector vh; + for(const auto& tx_hex_str : req.txs_hashes) + { + blobdata b; + if(!string_tools::parse_hexstr_to_binbuff(tx_hex_str, b)) + { + res.status = "Failed to parse hex representation of transaction hash"; + return true; + } + if(b.size() != sizeof(crypto::hash)) + { + res.status = "Failed, size of data mismatch"; + return true; + } + vh.push_back(*reinterpret_cast(b.data())); + } + std::list missed_txs; + std::list txs; + bool r = m_core.get_transactions(vh, txs, missed_txs); + if(!r) + { + res.status = "Failed"; + return true; + } + + for(auto& tx : txs) + { + blobdata blob = t_serializable_object_to_blob(tx); + res.txs_as_hex.push_back(string_tools::buff_to_hex_nodelimer(blob)); + } + + for(const auto& miss_tx : missed_txs) + { + res.missed_tx.push_back(string_tools::pod_to_hex(miss_tx)); + } + + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ +// bool core_rpc_server::on_rpc_get_all_offers(const COMMAND_RPC_GET_ALL_OFFERS::request& req, COMMAND_RPC_GET_ALL_OFFERS::response& res, connection_context& cntx) +// { +// m_core.get_blockchain_storage().get_all_offers(res.offers); +// res.status = CORE_RPC_STATUS_OK; +// return true; +// } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_pos_mining_details(const COMMAND_RPC_GET_POS_MINING_DETAILS::request& req, COMMAND_RPC_GET_POS_MINING_DETAILS::response& res, connection_context& cntx) + { + if (!m_p2p.get_connections_count()) + { + res.status = CORE_RPC_STATUS_DISCONNECTED; + return true; + } + res.pos_mining_allowed = m_core.get_blockchain_storage().is_pos_allowed(); + if (!res.pos_mining_allowed) + { + res.status = CORE_RPC_STATUS_NOT_FOUND; + return true; + } + + res.pos_basic_difficulty = m_core.get_blockchain_storage().get_next_diff_conditional(true).convert_to(); + m_core.get_blockchain_storage().build_stake_modifier(res.sm, blockchain_storage::alt_chain_type(), 0, &res.last_block_hash);// , &res.height); + + //TODO: need atomic operation with build_stake_modifier() + res.starter_timestamp = m_core.get_blockchain_storage().get_last_timestamps_check_window_median(); + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_current_core_tx_expiration_median(const COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN::request& req, COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN::response& res, connection_context& cntx) + { + res.expiration_median = m_core.get_blockchain_storage().get_tx_expiration_median(); + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_rpc_get_blocks_details(const COMMAND_RPC_GET_BLOCKS_DETAILS::request& req, COMMAND_RPC_GET_BLOCKS_DETAILS::response& res, connection_context& cntx) + { + m_core.get_blockchain_storage().get_main_blocks_rpc_details(req.height_start, req.count, req.ignore_transactions, res.blocks); + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_tx_details(const COMMAND_RPC_GET_TX_DETAILS::request& req, COMMAND_RPC_GET_TX_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx) + { + crypto::hash h = null_hash; + if(!epee::string_tools::hex_to_pod(req.tx_hash, h)) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; + error_resp.message = "Invalid tx hash given"; + return false; + } + if (!m_core.get_blockchain_storage().get_tx_rpc_details(h, res.tx_info, 0, false)) + { + if (!m_core.get_tx_pool().get_transaction_details(h, res.tx_info)) + { + error_resp.code = CORE_RPC_ERROR_CODE_NOT_FOUND; + error_resp.message = "tx is not found"; + return false; + } + + } + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_search_by_id(const COMMAND_RPC_SERARCH_BY_ID::request& req, COMMAND_RPC_SERARCH_BY_ID::response& res, connection_context& cntx) + { + crypto::hash id = null_hash; + if (!epee::string_tools::hex_to_pod(req.id, id)) + return false; + + m_core.get_blockchain_storage().search_by_id(id, res.types_found); + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_out_info(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES_BY_AMOUNT::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES_BY_AMOUNT::response& res, connection_context& cntx) + { + if (!m_core.get_blockchain_storage().get_global_index_details(req, res)) + res.status = CORE_RPC_STATUS_NOT_FOUND; + else + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_multisig_info(const COMMAND_RPC_GET_MULTISIG_INFO::request& req, COMMAND_RPC_GET_MULTISIG_INFO::response& res, connection_context& cntx) + { + if (!m_core.get_blockchain_storage().get_multisig_id_details(req, res)) + res.status = CORE_RPC_STATUS_NOT_FOUND; + else + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_pool_txs_details(const COMMAND_RPC_GET_POOL_TXS_DETAILS::request& req, COMMAND_RPC_GET_POOL_TXS_DETAILS::response& res, connection_context& cntx) + { + if (!req.ids.size()) + { + m_core.get_tx_pool().get_all_transactions_details(res.txs); + } + else + { + m_core.get_tx_pool().get_transactions_details(req.ids, res.txs); + } + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_pool_txs_brief_details(const COMMAND_RPC_GET_POOL_TXS_BRIEF_DETAILS::request& req, COMMAND_RPC_GET_POOL_TXS_BRIEF_DETAILS::response& res, connection_context& cntx) + { + if (!req.ids.size()) + { + m_core.get_tx_pool().get_all_transactions_brief_details(res.txs); + } + else + { + m_core.get_tx_pool().get_transactions_brief_details(req.ids, res.txs); + } + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_all_pool_tx_list(const COMMAND_RPC_GET_ALL_POOL_TX_LIST::request& req, COMMAND_RPC_GET_ALL_POOL_TX_LIST::response& res, connection_context& cntx) + { + m_core.get_tx_pool().get_all_transactions_list(res.ids); + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_pool_info(const COMMAND_RPC_GET_POOL_INFO::request& req, COMMAND_RPC_GET_POOL_INFO::response& res, connection_context& cntx) + { + std::list al_list; + m_core.get_tx_pool().get_aliases_from_tx_pool(al_list); + for (const auto a : al_list) + { + res.aliases_que.push_back(alias_info_to_rpc_alias_info(a)); + } + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_main_block_details(const COMMAND_RPC_GET_BLOCK_DETAILS::request& req, COMMAND_RPC_GET_BLOCK_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx) + { + if (!m_core.get_blockchain_storage().get_main_block_rpc_details(req.id, res.block_details)) + { + error_resp.code = CORE_RPC_ERROR_CODE_NOT_FOUND; + error_resp.message = "the requested block has not been found"; + return false; + } + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_alt_block_details(const COMMAND_RPC_GET_BLOCK_DETAILS::request& req, COMMAND_RPC_GET_BLOCK_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx) + { + if (!m_core.get_blockchain_storage().get_alt_block_rpc_details(req.id, res.block_details)) + { + error_resp.code = CORE_RPC_ERROR_CODE_NOT_FOUND; + error_resp.message = "the requested block has not been found"; + return false; + } + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_alt_blocks_details(const COMMAND_RPC_GET_ALT_BLOCKS_DETAILS::request& req, COMMAND_RPC_GET_ALT_BLOCKS_DETAILS::response& res, connection_context& cntx) + { + m_core.get_blockchain_storage().get_alt_blocks_rpc_details(req.offset, req.count, res.blocks); + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request& req, COMMAND_RPC_SEND_RAW_TX::response& res, connection_context& cntx) + { + CHECK_CORE_READY(); + + std::string tx_blob; + if(!string_tools::parse_hexstr_to_binbuff(req.tx_as_hex, tx_blob)) + { + LOG_PRINT_L0("[on_send_raw_tx]: Failed to parse tx from hexbuff: " << req.tx_as_hex); + res.status = "Failed"; + return true; + } + + if (!m_p2p.get_payload_object().get_synchronized_connections_count()) + { + LOG_PRINT_L0("[on_send_raw_tx]: Failed to send, daemon not connected to net"); + res.status = CORE_RPC_STATUS_DISCONNECTED; + return true; + } + + currency_connection_context fake_context = AUTO_VAL_INIT(fake_context); + tx_verification_context tvc = AUTO_VAL_INIT(tvc); + if(!m_core.handle_incoming_tx(tx_blob, tvc, false)) + { + LOG_PRINT_L0("[on_send_raw_tx]: Failed to process tx"); + res.status = "Failed"; + return true; + } + + if(tvc.m_verification_failed) + { + LOG_PRINT_L0("[on_send_raw_tx]: tx verification failed"); + res.status = "Failed"; + return true; + } + + if(!tvc.m_should_be_relayed) + { + LOG_PRINT_L0("[on_send_raw_tx]: tx accepted, but not relayed"); + res.status = "Not relayed"; + return true; + } + + + NOTIFY_NEW_TRANSACTIONS::request r; + r.txs.push_back(tx_blob); + m_core.get_protocol()->relay_transactions(r, fake_context); + //TODO: make sure that tx has reached other nodes here, probably wait to receive reflections from other nodes + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_force_relaey_raw_txs(const COMMAND_RPC_FORCE_RELAY_RAW_TXS::request& req, COMMAND_RPC_FORCE_RELAY_RAW_TXS::response& res, connection_context& cntx) + { + CHECK_CORE_READY(); + NOTIFY_NEW_TRANSACTIONS::request r = AUTO_VAL_INIT(r); + + for (const auto& t : req.txs_as_hex) + { + std::string tx_blob; + if (!string_tools::parse_hexstr_to_binbuff(t, tx_blob)) + { + LOG_PRINT_L0("[on_send_raw_tx]: Failed to parse tx from hexbuff: " << t); + res.status = "Failed"; + return true; + } + r.txs.push_back(tx_blob); + } + + currency_connection_context fake_context = AUTO_VAL_INIT(fake_context); + bool call_res = m_core.get_protocol()->relay_transactions(r, fake_context); + if (call_res) + res.status = CORE_RPC_STATUS_OK; + return call_res; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_start_mining(const COMMAND_RPC_START_MINING::request& req, COMMAND_RPC_START_MINING::response& res, connection_context& cntx) + { + CHECK_CORE_READY(); + account_public_address adr; + if(!get_account_address_from_str(adr, req.miner_address)) + { + res.status = "Failed, wrong address"; + return true; + } + + if(!m_core.get_miner().start(adr, static_cast(req.threads_count))) + { + res.status = "Failed, mining not started"; + return true; + } + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_stop_mining(const COMMAND_RPC_STOP_MINING::request& req, COMMAND_RPC_STOP_MINING::response& res, connection_context& cntx) + { + CHECK_CORE_READY(); + if(!m_core.get_miner().stop()) + { + res.status = "Failed, mining not stopped"; + return true; + } + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res, connection_context& cntx) + { + CHECK_CORE_READY(); + res.count = m_core.get_current_blockchain_size(); + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request& req, COMMAND_RPC_GETBLOCKHASH::response& res, epee::json_rpc::error& error_resp, connection_context& cntx) + { + if(!check_core_ready()) + { + error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY; + error_resp.message = "Core is busy"; + return false; + } + if(req.size() != 1) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; + error_resp.message = "Wrong parameters, expected height"; + return false; + } + uint64_t h = req[0]; + if(m_core.get_current_blockchain_size() <= h) + { + error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT; + error_resp.message = std::string("To big height: ") + std::to_string(h) + ", current blockchain size = " + std::to_string(m_core.get_current_blockchain_size()); + } + res = string_tools::pod_to_hex(m_core.get_block_id_by_height(h)); + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request& req, COMMAND_RPC_GETBLOCKTEMPLATE::response& res, epee::json_rpc::error& error_resp, connection_context& cntx) + { + if(!check_core_ready()) + { + error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY; + error_resp.message = "Core is busy"; + return false; + } + + if(req.extra_text.size() > 255) + { + error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_RESERVE_SIZE; + error_resp.message = "Extra text size is to big, maximum 255"; + return false; + } + + currency::account_public_address miner_address = AUTO_VAL_INIT(miner_address); + if(!req.wallet_address.size() || !currency::get_account_address_from_str(miner_address, req.wallet_address)) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_WALLET_ADDRESS; + error_resp.message = "Failed to parse wallet address"; + return false; + } + currency::account_public_address stakeholder_address = AUTO_VAL_INIT(stakeholder_address); + if(req.pos_block && (!req.stakeholder_address.size() || !currency::get_account_address_from_str(stakeholder_address, req.stakeholder_address))) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_WALLET_ADDRESS; + error_resp.message = "Failed to parse stakeholder address"; + return false; + } + + block b = AUTO_VAL_INIT(b); + wide_difficulty_type dt = 0; + currency::pos_entry pe = AUTO_VAL_INIT(pe); + pe.amount = req.pos_amount; + pe.index = req.pos_index; + //pe.keyimage key image will be set in the wallet + //pe.wallet_index is not included in serialization map, TODO: refactoring here + + if (!m_core.get_block_template(b, miner_address, stakeholder_address, dt, res.height, req.extra_text, req.pos_block, pe)) + { + error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; + error_resp.message = "Internal error: failed to create block template"; + LOG_ERROR("Failed to create block template"); + return false; + } + res.difficulty = dt.convert_to(); + blobdata block_blob = t_serializable_object_to_blob(b); + + res.blocktemplate_blob = string_tools::buff_to_hex_nodelimer(block_blob); + res.status = CORE_RPC_STATUS_OK; + + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp, connection_context& cntx) + { + CHECK_CORE_READY(); + if(req.size()!=1) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; + error_resp.message = "Wrong param"; + return false; + } + blobdata blockblob; + if(!string_tools::parse_hexstr_to_binbuff(req[0], blockblob)) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB; + error_resp.message = "Wrong block blob"; + return false; + } + + block b = AUTO_VAL_INIT(b); + if(!parse_and_validate_block_from_blob(blockblob, b)) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB; + error_resp.message = "Wrong block blob"; + return false; + } + + block_verification_context bvc = AUTO_VAL_INIT(bvc); + if(!m_core.handle_block_found(b, &bvc)) + { + if (bvc.added_to_altchain) + { + error_resp.code = CORE_RPC_ERROR_CODE_BLOCK_ADDED_AS_ALTERNATIVE; + error_resp.message = "Block added as alternative"; + return false; + } + error_resp.code = CORE_RPC_ERROR_CODE_BLOCK_NOT_ACCEPTED; + error_resp.message = "Block not accepted"; + return false; + } + //@#@ + //temporary double check timestamp + if (time(NULL) - get_actual_timestamp(b) > 5) + { + LOG_PRINT_RED_L0("Found block (" << get_block_hash(b) << ") timestamp (" << get_actual_timestamp(b) + << ") is suspiciously less (" << time(NULL) - get_actual_timestamp(b) << ") then curren time( " << time(NULL) << ")"); + //mark node to make it easier to find it via scanner + m_core.get_blockchain_storage().get_performnce_data().epic_failure_happend = true; + } + // + + + res.status = "OK"; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + uint64_t core_rpc_server::get_block_reward(const block& blk) + { + uint64_t reward = 0; + BOOST_FOREACH(const tx_out& out, blk.miner_tx.vout) + { + reward += out.amount; + } + return reward; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::fill_block_header_response(const block& blk, bool orphan_status, block_header_response& response) + { + response.major_version = blk.major_version; + response.minor_version = blk.minor_version; + response.timestamp = blk.timestamp; + response.prev_hash = string_tools::pod_to_hex(blk.prev_id); + response.nonce = blk.nonce; + response.orphan_status = orphan_status; + response.height = get_block_height(blk); + response.depth = m_core.get_current_blockchain_size() - response.height - 1; + response.hash = string_tools::pod_to_hex(get_block_hash(blk)); + response.difficulty = m_core.get_blockchain_storage().block_difficulty(response.height).convert_to(); + response.reward = get_block_reward(blk); + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_last_block_header(const COMMAND_RPC_GET_LAST_BLOCK_HEADER::request& req, COMMAND_RPC_GET_LAST_BLOCK_HEADER::response& res, epee::json_rpc::error& error_resp, connection_context& cntx) + { + if(!check_core_ready()) + { + error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY; + error_resp.message = "Core is busy."; + return false; + } + block last_block = AUTO_VAL_INIT(last_block); + bool have_last_block_hash = m_core.get_blockchain_storage().get_top_block(last_block); + if (!have_last_block_hash) + { + error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; + error_resp.message = "Internal error: can't get last block hash."; + return false; + } + bool response_filled = fill_block_header_response(last_block, false, res.block_header); + if (!response_filled) + { + error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; + error_resp.message = "Internal error: can't produce valid response."; + return false; + } + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_block_header_by_hash(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::response& res, epee::json_rpc::error& error_resp, connection_context& cntx){ + if(!check_core_ready()) + { + error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY; + error_resp.message = "Core is busy."; + return false; + } + crypto::hash block_hash; + bool hash_parsed = parse_hash256(req.hash, block_hash); + if(!hash_parsed) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; + error_resp.message = "Failed to parse hex representation of block hash. Hex = " + req.hash + '.'; + return false; + } + block blk; + bool have_block = m_core.get_block_by_hash(block_hash, blk); + if (!have_block) + { + error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; + error_resp.message = "Internal error: can't get block by hash. Hash = " + req.hash + '.'; + return false; + } + if (blk.miner_tx.vin.front().type() != typeid(txin_gen)) + { + error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; + error_resp.message = "Internal error: coinbase transaction in the block has the wrong type"; + return false; + } + //uint64_t block_height = boost::get(blk.miner_tx.vin.front()).height; + bool response_filled = fill_block_header_response(blk, false, res.block_header); + if (!response_filled) + { + error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; + error_resp.message = "Internal error: can't produce valid response."; + return false; + } + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_block_header_by_height(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::response& res, epee::json_rpc::error& error_resp, connection_context& cntx){ + if(!check_core_ready()) + { + error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY; + error_resp.message = "Core is busy."; + return false; + } + if(m_core.get_current_blockchain_size() <= req.height) + { + error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT; + error_resp.message = std::string("To big height: ") + std::to_string(req.height) + ", current blockchain size = " + std::to_string(m_core.get_current_blockchain_size()); + return false; + } + block blk = AUTO_VAL_INIT(blk); + m_core.get_blockchain_storage().get_block_by_height(req.height, blk); + + bool response_filled = fill_block_header_response(blk, false, res.block_header); + if (!response_filled) + { + error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; + error_resp.message = "Internal error: can't produce valid response."; + return false; + } + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_alias_details(const COMMAND_RPC_GET_ALIAS_DETAILS::request& req, COMMAND_RPC_GET_ALIAS_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx) + { + if(!check_core_ready()) + { + error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY; + error_resp.message = "Core is busy."; + return true; + } + extra_alias_entry_base aib = AUTO_VAL_INIT(aib); + if(!validate_alias_name(req.alias)) + { + res.status = "Alias have wrong name"; + return true; + } + if(!m_core.get_blockchain_storage().get_alias_info(req.alias, aib)) + { + res.status = CORE_RPC_STATUS_NOT_FOUND; + return true; + } + res.alias_details.address = currency::get_account_address_as_str(aib.m_address); + res.alias_details.comment = aib.m_text_comment; + if (aib.m_view_key.size()) + res.alias_details.tracking_key = string_tools::pod_to_hex(aib.m_view_key.back()); + + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + + bool core_rpc_server::on_get_all_aliases(const COMMAND_RPC_GET_ALL_ALIASES::request& req, COMMAND_RPC_GET_ALL_ALIASES::response& res, epee::json_rpc::error& error_resp, connection_context& cntx) + { + if(!check_core_ready()) + { + error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY; + error_resp.message = "Core is busy."; + return false; + } + + m_core.get_blockchain_storage().enumerate_aliases([&](uint64_t i, const std::string& alias, const extra_alias_entry_base& alias_entry_base) -> bool + { + res.aliases.push_back(alias_rpc_details()); + alias_info_to_rpc_alias_info(alias, alias_entry_base, res.aliases.back()); + return true; + }); + + res.status = CORE_RPC_STATUS_OK; + return true; + } + + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_aliases(const COMMAND_RPC_GET_ALIASES::request& req, COMMAND_RPC_GET_ALIASES::response& res, epee::json_rpc::error& error_resp, connection_context& cntx) + { + if(!check_core_ready()) + { + error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY; + error_resp.message = "Core is busy."; + return false; + } + + m_core.get_blockchain_storage().get_aliases([&res](const std::string& alias, const currency::extra_alias_entry_base& ai){ + res.aliases.push_back(alias_rpc_details()); + alias_info_to_rpc_alias_info(alias, ai, res.aliases.back()); + }, req.offset, req.count); + + res.status = CORE_RPC_STATUS_OK; + return true; + } + + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::get_current_hi(mining::height_info& hi) + { + block prev_block = AUTO_VAL_INIT(prev_block); + m_core.get_blockchain_storage().get_top_block(prev_block); + hi.block_id = string_tools::pod_to_hex(currency::get_block_hash(prev_block)); + hi.height = get_block_height(prev_block); + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + void core_rpc_server::set_session_blob(const std::string& session_id, const currency::block& blob) + { + CRITICAL_REGION_LOCAL(m_session_jobs_lock); + m_session_jobs[session_id] = blob; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::get_session_blob(const std::string& session_id, currency::block& blob) + { + CRITICAL_REGION_LOCAL(m_session_jobs_lock); + auto it = m_session_jobs.find(session_id); + if(it == m_session_jobs.end()) + return false; + + blob = it->second; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::get_job(const std::string& job_id, mining::job_details& job, epee::json_rpc::error& err, connection_context& cntx) + { + COMMAND_RPC_GETBLOCKTEMPLATE::request bt_req = AUTO_VAL_INIT(bt_req); + COMMAND_RPC_GETBLOCKTEMPLATE::response bt_res = AUTO_VAL_INIT(bt_res); + + // !!!!!!!! SET YOUR WALLET ADDRESS HERE !!!!!!!! + bt_req.wallet_address = "1HNJjUsofq5LYLoXem119dd491yFAb5g4bCHkecV4sPqigmuxw57Ci9am71fEN4CRmA9jgnvo5PDNfaq8QnprWmS5uLqnbq"; + + if(!on_getblocktemplate(bt_req, bt_res, err, cntx)) + return false; + + //patch block blob if you need(bt_res.blocktemplate_blob), and than load block from blob template + //important: you can't change block size, since it could touch reward and block became invalid + + block b = AUTO_VAL_INIT(b); + std::string bin_buff; + bool r = string_tools::parse_hexstr_to_binbuff(bt_res.blocktemplate_blob, bin_buff); + CHECK_AND_ASSERT_MES(r, false, "internal error, failed to parse hex block"); + r = currency::parse_and_validate_block_from_blob(bin_buff, b); + CHECK_AND_ASSERT_MES(r, false, "internal error, failed to parse block"); + + set_session_blob(job_id, b); + job.blob = string_tools::buff_to_hex_nodelimer(currency::get_block_hashing_blob(b)); + //TODO: set up share difficulty here! + job.difficulty = std::to_string(bt_res.difficulty); //difficulty leaved as string field since it will be refactored into 128 bit format + job.job_id = "SOME_JOB_ID"; + get_current_hi(job.prev_hi); + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_login(const mining::COMMAND_RPC_LOGIN::request& req, mining::COMMAND_RPC_LOGIN::response& res, connection_context& cntx) + { + if(!check_core_ready()) + { + res.status = CORE_RPC_STATUS_BUSY; + return true; + } + + //TODO: add login information here + + + res.id = std::to_string(m_session_counter++); //session id + + if(req.hi.height) + { + epee::json_rpc::error err = AUTO_VAL_INIT(err); + if(!get_job(res.id, res.job, err, cntx)) + { + res.status = err.message; + return true; + } + } + + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_getjob(const mining::COMMAND_RPC_GETJOB::request& req, mining::COMMAND_RPC_GETJOB::response& res, connection_context& cntx) + { + if(!check_core_ready()) + { + res.status = CORE_RPC_STATUS_BUSY; + return true; + } + + + + /*epee::json_rpc::error err = AUTO_VAL_INIT(err); + if(!get_job(req.id, res.jd, err, cntx)) + { + res.status = err.message; + return true; + }*/ + + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_alias_reward(const COMMAND_RPC_GET_ALIAS_REWARD::request& req, COMMAND_RPC_GET_ALIAS_REWARD::response& res, epee::json_rpc::error& error_resp, connection_context& cntx) + { + + uint64_t default_tx_fee = m_core.get_blockchain_storage().get_core_runtime_config().tx_default_fee; + uint64_t current_median_fee = m_core.get_blockchain_storage().get_tx_fee_median(); + + res.reward = get_alias_coast_from_fee(req.alias, std::max(default_tx_fee, current_median_fee)); + + if (res.reward) + res.status = CORE_RPC_STATUS_OK; + else + res.status = CORE_RPC_STATUS_NOT_FOUND; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_alias_by_address(const COMMAND_RPC_GET_ALIASES_BY_ADDRESS::request& req, COMMAND_RPC_GET_ALIASES_BY_ADDRESS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx) + { + account_public_address addr = AUTO_VAL_INIT(addr); + if (!get_account_address_from_str(addr, req)) + { + res.status = CORE_RPC_STATUS_FAILED; + return true; + } + //res.alias = m_core.get_blockchain_storage().get_alias_by_address(addr); + COMMAND_RPC_GET_ALIAS_DETAILS::request req2 = AUTO_VAL_INIT(req2); + COMMAND_RPC_GET_ALIAS_DETAILS::response res2 = AUTO_VAL_INIT(res2); + + req2.alias = m_core.get_blockchain_storage().get_alias_by_address(addr); + if (!req2.alias.size()) + { + res.status = CORE_RPC_STATUS_NOT_FOUND; + return true; + } + + bool r = this->on_get_alias_details(req2, res2, error_resp, cntx); + if (!r || res2.status != CORE_RPC_STATUS_OK) + { + res.status = CORE_RPC_STATUS_FAILED; + return true; + } + + res.alias_info.details = res2.alias_details; + res.alias_info.alias = req2.alias; + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_submit(const mining::COMMAND_RPC_SUBMITSHARE::request& req, mining::COMMAND_RPC_SUBMITSHARE::response& res, connection_context& cntx) + { + if(!check_core_ready()) + { + res.status = CORE_RPC_STATUS_BUSY; + return true; + } + block b = AUTO_VAL_INIT(b); + if(!get_session_blob(req.id, b)) + { + res.status = "Wrong session id"; + return true; + } + + b.nonce = req.nonce; + + if(!m_core.handle_block_found(b)) + { + res.status = "Block not accepted"; + LOG_ERROR("Submited block not accepted"); + return true; + } + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_addendums(const COMMAND_RPC_GET_ADDENDUMS::request& req, COMMAND_RPC_GET_ADDENDUMS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx) + { + if (!check_core_ready()) + { + res.status = CORE_RPC_STATUS_BUSY; + return true; + } + + + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_reset_transaction_pool(const COMMAND_RPC_RESET_TX_POOL::request& req, COMMAND_RPC_RESET_TX_POOL::response& res, connection_context& cntx) + { + m_core.get_tx_pool().purge_transactions(); + res.status = CORE_RPC_STATUS_OK; + return true; + } +} + + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL NULL \ No newline at end of file diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h new file mode 100644 index 00000000..53e723c7 --- /dev/null +++ b/src/rpc/core_rpc_server.h @@ -0,0 +1,188 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include + +#include "net/http_server_impl_base.h" +#include "core_rpc_server_commands_defs.h" +#include "currency_core/currency_core.h" +#include "p2p/net_node.h" +#include "currency_protocol/currency_protocol_handler.h" +#include "mining_protocol_defs.h" +#include "currency_core/bc_offers_service.h" + + + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL "rpc" +ENABLE_CHANNEL_BY_DEFAULT("rpc"); + +namespace currency +{ + /************************************************************************/ + /* */ + /************************************************************************/ + class core_rpc_server: public epee::http_server_impl_base + { + public: + typedef epee::net_utils::connection_context_base connection_context; + + core_rpc_server(core& cr, nodetool::node_server >& p2p, bc_services::bc_offers_service& of); + + static void init_options(boost::program_options::options_description& desc); + bool init(const boost::program_options::variables_map& vm); + + bool on_get_blocks_direct(const COMMAND_RPC_GET_BLOCKS_DIRECT::request& req, COMMAND_RPC_GET_BLOCKS_DIRECT::response& res, connection_context& cntx); + + bool on_get_height(const COMMAND_RPC_GET_HEIGHT::request& req, COMMAND_RPC_GET_HEIGHT::response& res, connection_context& cntx); + bool on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res, connection_context& cntx); + bool on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res, connection_context& cntx); + bool on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res, connection_context& cntx); + bool on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request& req, COMMAND_RPC_SEND_RAW_TX::response& res, connection_context& cntx); + bool on_start_mining(const COMMAND_RPC_START_MINING::request& req, COMMAND_RPC_START_MINING::response& res, connection_context& cntx); + bool on_stop_mining(const COMMAND_RPC_STOP_MINING::request& req, COMMAND_RPC_STOP_MINING::response& res, connection_context& cntx); + bool on_get_random_outs(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res, connection_context& cntx); + bool on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res, connection_context& cntx); + bool on_set_maintainers_info(const COMMAND_RPC_SET_MAINTAINERS_INFO::request& req, COMMAND_RPC_SET_MAINTAINERS_INFO::response& res, connection_context& cntx); + bool on_get_tx_pool(const COMMAND_RPC_GET_TX_POOL::request& req, COMMAND_RPC_GET_TX_POOL::response& res, connection_context& cntx); + bool on_check_keyimages(const COMMAND_RPC_CHECK_KEYIMAGES::request& req, COMMAND_RPC_CHECK_KEYIMAGES::response& res, connection_context& cntx); + bool on_scan_pos(const COMMAND_RPC_SCAN_POS::request& req, COMMAND_RPC_SCAN_POS::response& res, connection_context& cntx); + bool on_rpc_get_blocks_details(const COMMAND_RPC_GET_BLOCKS_DETAILS::request& req, COMMAND_RPC_GET_BLOCKS_DETAILS::response& res, connection_context& cntx); + bool on_force_relaey_raw_txs(const COMMAND_RPC_FORCE_RELAY_RAW_TXS::request& req, COMMAND_RPC_FORCE_RELAY_RAW_TXS::response& res, connection_context& cntx); + //bool on_rpc_get_all_offers(const COMMAND_RPC_GET_ALL_OFFERS::request& req, COMMAND_RPC_GET_ALL_OFFERS::response& res, connection_context& cntx); + + + //json_rpc + bool on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res, connection_context& cntx); + bool on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request& req, COMMAND_RPC_GETBLOCKHASH::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); + bool on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request& req, COMMAND_RPC_GETBLOCKTEMPLATE::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); + bool on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); + bool on_get_last_block_header(const COMMAND_RPC_GET_LAST_BLOCK_HEADER::request& req, COMMAND_RPC_GET_LAST_BLOCK_HEADER::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); + bool on_get_block_header_by_hash(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); + bool on_get_block_header_by_height(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); + bool on_get_alias_details(const COMMAND_RPC_GET_ALIAS_DETAILS::request& req, COMMAND_RPC_GET_ALIAS_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); + bool on_get_all_aliases(const COMMAND_RPC_GET_ALL_ALIASES::request& req, COMMAND_RPC_GET_ALL_ALIASES::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); + bool on_get_aliases(const COMMAND_RPC_GET_ALIASES::request& req, COMMAND_RPC_GET_ALIASES::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); + bool on_alias_by_address(const COMMAND_RPC_GET_ALIASES_BY_ADDRESS::request& req, COMMAND_RPC_GET_ALIASES_BY_ADDRESS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); + bool on_get_alias_reward(const COMMAND_RPC_GET_ALIAS_REWARD::request& req, COMMAND_RPC_GET_ALIAS_REWARD::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); + bool on_get_addendums(const COMMAND_RPC_GET_ADDENDUMS::request& req, COMMAND_RPC_GET_ADDENDUMS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); + bool on_reset_transaction_pool(const COMMAND_RPC_RESET_TX_POOL::request& req, COMMAND_RPC_RESET_TX_POOL::response& res, connection_context& cntx); + bool on_get_pos_mining_details(const COMMAND_RPC_GET_POS_MINING_DETAILS::request& req, COMMAND_RPC_GET_POS_MINING_DETAILS::response& res, connection_context& cntx); + bool on_get_current_core_tx_expiration_median(const COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN::request& req, COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN::response& res, connection_context& cntx); + bool on_get_tx_details(const COMMAND_RPC_GET_TX_DETAILS::request& req, COMMAND_RPC_GET_TX_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); + bool on_search_by_id(const COMMAND_RPC_SERARCH_BY_ID::request& req, COMMAND_RPC_SERARCH_BY_ID::response& res, connection_context& cntx); + bool on_get_out_info(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES_BY_AMOUNT::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES_BY_AMOUNT::response& res, connection_context& cntx); + bool on_get_multisig_info(const COMMAND_RPC_GET_MULTISIG_INFO::request& req, COMMAND_RPC_GET_MULTISIG_INFO::response& res, connection_context& cntx); + bool on_get_pool_txs_details(const COMMAND_RPC_GET_POOL_TXS_DETAILS::request& req, COMMAND_RPC_GET_POOL_TXS_DETAILS::response& res, connection_context& cntx); + bool on_get_pool_txs_brief_details(const COMMAND_RPC_GET_POOL_TXS_BRIEF_DETAILS::request& req, COMMAND_RPC_GET_POOL_TXS_BRIEF_DETAILS::response& res, connection_context& cntx); + bool on_get_all_pool_tx_list(const COMMAND_RPC_GET_ALL_POOL_TX_LIST::request& req, COMMAND_RPC_GET_ALL_POOL_TX_LIST::response& res, connection_context& cntx); + bool on_get_pool_info(const COMMAND_RPC_GET_POOL_INFO::request& req, COMMAND_RPC_GET_POOL_INFO::response& res, connection_context& cntx); + + bool on_get_main_block_details(const COMMAND_RPC_GET_BLOCK_DETAILS::request& req, COMMAND_RPC_GET_BLOCK_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); + bool on_get_alt_block_details(const COMMAND_RPC_GET_BLOCK_DETAILS::request& req, COMMAND_RPC_GET_BLOCK_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); + bool on_get_alt_blocks_details(const COMMAND_RPC_GET_ALT_BLOCKS_DETAILS::request& req, COMMAND_RPC_GET_ALT_BLOCKS_DETAILS::response& res, connection_context& cntx); + + + + //mining rpc + bool on_login(const mining::COMMAND_RPC_LOGIN::request& req, mining::COMMAND_RPC_LOGIN::response& res, connection_context& cntx); + bool on_getjob(const mining::COMMAND_RPC_GETJOB::request& req, mining::COMMAND_RPC_GETJOB::response& res, connection_context& cntx); + bool on_submit(const mining::COMMAND_RPC_SUBMITSHARE::request& req, mining::COMMAND_RPC_SUBMITSHARE::response& res, connection_context& cntx); + + + + + + CHAIN_HTTP_TO_MAP2(connection_context); //forward http requests to uri map + + BEGIN_URI_MAP2() + // legacy JSON-alike RPCs + MAP_URI_AUTO_JON2("/getheight", on_get_height, COMMAND_RPC_GET_HEIGHT) + MAP_URI_AUTO_JON2("/gettransactions", on_get_transactions, COMMAND_RPC_GET_TRANSACTIONS) + MAP_URI_AUTO_JON2("/sendrawtransaction", on_send_raw_tx, COMMAND_RPC_SEND_RAW_TX) + MAP_URI_AUTO_JON2("/force_relay", on_force_relaey_raw_txs, COMMAND_RPC_FORCE_RELAY_RAW_TXS) + MAP_URI_AUTO_JON2("/start_mining", on_start_mining, COMMAND_RPC_START_MINING) + MAP_URI_AUTO_JON2("/stop_mining", on_stop_mining, COMMAND_RPC_STOP_MINING) + MAP_URI_AUTO_JON2("/getinfo", on_get_info, COMMAND_RPC_GET_INFO) + // binary RPCs + MAP_URI_AUTO_BIN2("/getblocks.bin", on_get_blocks, COMMAND_RPC_GET_BLOCKS_FAST) + MAP_URI_AUTO_BIN2("/get_o_indexes.bin", on_get_indexes, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES) + MAP_URI_AUTO_BIN2("/getrandom_outs.bin", on_get_random_outs, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS) + MAP_URI_AUTO_BIN2("/set_maintainers_info.bin", on_set_maintainers_info, COMMAND_RPC_SET_MAINTAINERS_INFO) + MAP_URI_AUTO_BIN2("/get_tx_pool.bin", on_get_tx_pool, COMMAND_RPC_GET_TX_POOL) + MAP_URI_AUTO_BIN2("/check_keyimages.bin", on_check_keyimages, COMMAND_RPC_CHECK_KEYIMAGES) + MAP_URI_AUTO_BIN2("/scan_pos.bin", on_scan_pos, COMMAND_RPC_SCAN_POS) + MAP_URI_AUTO_BIN2("/get_pos_details.bin", on_get_pos_mining_details, COMMAND_RPC_GET_POS_MINING_DETAILS) + // JSON RPCs + BEGIN_JSON_RPC_MAP("/json_rpc") + MAP_JON_RPC ("getblockcount", on_getblockcount, COMMAND_RPC_GETBLOCKCOUNT) + MAP_JON_RPC_WE("on_getblockhash", on_getblockhash, COMMAND_RPC_GETBLOCKHASH) + MAP_JON_RPC_WE("getblocktemplate", on_getblocktemplate, COMMAND_RPC_GETBLOCKTEMPLATE) + MAP_JON_RPC_WE("submitblock", on_submitblock, COMMAND_RPC_SUBMITBLOCK) + MAP_JON_RPC_WE("getlastblockheader", on_get_last_block_header, COMMAND_RPC_GET_LAST_BLOCK_HEADER) + MAP_JON_RPC_WE("getblockheaderbyhash", on_get_block_header_by_hash, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH) + MAP_JON_RPC_WE("getblockheaderbyheight", on_get_block_header_by_height, COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT) + MAP_JON_RPC_WE("get_alias_details", on_get_alias_details, COMMAND_RPC_GET_ALIAS_DETAILS) + MAP_JON_RPC_WE("get_alias_by_address", on_alias_by_address, COMMAND_RPC_GET_ALIASES_BY_ADDRESS) + MAP_JON_RPC_WE("get_alias_reward", on_get_alias_reward, COMMAND_RPC_GET_ALIAS_REWARD) + //block explorer api + MAP_JON_RPC ("get_blocks_details", on_rpc_get_blocks_details, COMMAND_RPC_GET_BLOCKS_DETAILS) + MAP_JON_RPC_WE("get_tx_details", on_get_tx_details, COMMAND_RPC_GET_TX_DETAILS) + MAP_JON_RPC ("search_by_id", on_search_by_id, COMMAND_RPC_SERARCH_BY_ID) + MAP_JON_RPC ("getinfo", on_get_info , COMMAND_RPC_GET_INFO) + MAP_JON_RPC ("get_out_info", on_get_out_info, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES_BY_AMOUNT) + MAP_JON_RPC ("get_multisig_info", on_get_multisig_info, COMMAND_RPC_GET_MULTISIG_INFO) + MAP_JON_RPC_WE("get_all_alias_details", on_get_all_aliases, COMMAND_RPC_GET_ALL_ALIASES) + MAP_JON_RPC_WE("get_aliases", on_get_aliases, COMMAND_RPC_GET_ALIASES) + MAP_JON_RPC ("get_pool_txs_details", on_get_pool_txs_details, COMMAND_RPC_GET_POOL_TXS_DETAILS) + MAP_JON_RPC ("get_pool_txs_brief_details", on_get_pool_txs_brief_details, COMMAND_RPC_GET_POOL_TXS_BRIEF_DETAILS) + MAP_JON_RPC ("get_all_pool_tx_list", on_get_all_pool_tx_list, COMMAND_RPC_GET_ALL_POOL_TX_LIST) + MAP_JON_RPC ("get_pool_info", on_get_pool_info, COMMAND_RPC_GET_POOL_INFO) + + MAP_JON_RPC_WE("get_main_block_details", on_get_main_block_details, COMMAND_RPC_GET_BLOCK_DETAILS) + MAP_JON_RPC_WE("get_alt_block_details", on_get_alt_block_details, COMMAND_RPC_GET_BLOCK_DETAILS) + MAP_JON_RPC ("get_alt_blocks_details", on_get_alt_blocks_details, COMMAND_RPC_GET_ALT_BLOCKS_DETAILS) + // + MAP_JON_RPC ("reset_transaction_pool", on_reset_transaction_pool, COMMAND_RPC_RESET_TX_POOL) + MAP_JON_RPC ("get_current_core_tx_expiration_median", on_get_current_core_tx_expiration_median, COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN) + //remote miner rpc + MAP_JON_RPC_N(on_login, mining::COMMAND_RPC_LOGIN) + MAP_JON_RPC_N(on_getjob, mining::COMMAND_RPC_GETJOB) + MAP_JON_RPC_N(on_submit, mining::COMMAND_RPC_SUBMITSHARE) + END_JSON_RPC_MAP() + END_URI_MAP2() + + private: + + //----------------------- + bool handle_command_line(const boost::program_options::variables_map& vm); + bool check_core_ready_(const std::string& calling_method); + bool get_job(const std::string& job_id, mining::job_details& job, epee::json_rpc::error& err, connection_context& cntx); + bool get_current_hi(mining::height_info& hi); + + //utils + uint64_t get_block_reward(const block& blk); + bool fill_block_header_response(const block& blk, bool orphan_status, block_header_response& response); + void set_session_blob(const std::string& session_id, const currency::block& blob); + bool get_session_blob(const std::string& session_id, currency::block& blob); + + core& m_core; + nodetool::node_server >& m_p2p; + bc_services::bc_offers_service& m_of; + std::string m_port; + std::string m_bind_ip; + //mining stuff + epee::critical_section m_session_jobs_lock; + std::map m_session_jobs; //session id -> blob + std::atomic m_session_counter; + }; +} + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL NULL diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h new file mode 100644 index 00000000..5bb6dab6 --- /dev/null +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -0,0 +1,1541 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include "currency_protocol/currency_protocol_defs.h" +#include "currency_core/currency_basic.h" +#include "currency_core/difficulty.h" +#include "crypto/hash.h" +#include "p2p/p2p_protocol_defs.h" +#include "rpc/mining_protocol_defs.h" +#include "storages/portable_storage_base.h" +#include "currency_core/offers_service_basics.h" +#include "currency_core/basic_api_response_codes.h" + +namespace currency +{ + //----------------------------------------------- +#define CORE_RPC_STATUS_OK BASIC_RESPONSE_STATUS_OK +#define CORE_RPC_STATUS_BUSY BASIC_RESPONSE_STATUS_BUSY +#define CORE_RPC_STATUS_NOT_FOUND BASIC_RESPONSE_STATUS_NOT_FOUND +#define CORE_RPC_STATUS_FAILED BASIC_RESPONSE_STATUS_FAILED +#define CORE_RPC_STATUS_GENESIS_MISMATCH "GENESIS_MISMATCH" +#define CORE_RPC_STATUS_DISCONNECTED "DISCONNECTED" + + + struct alias_rpc_details_base + { + std::string address; + std::string tracking_key; + std::string comment; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(address) + KV_SERIALIZE(tracking_key) + KV_SERIALIZE(comment) + END_KV_SERIALIZE_MAP() + }; + + struct alias_rpc_details + { + std::string alias; + alias_rpc_details_base details; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(alias) + KV_CHAIN_MAP(details) + END_KV_SERIALIZE_MAP() + }; + + + struct update_alias_rpc_details + { + std::string old_address; + std::string alias; + alias_rpc_details_base details; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(old_address) + KV_SERIALIZE(alias) + KV_SERIALIZE(details) + END_KV_SERIALIZE_MAP() + }; + + + + + struct COMMAND_RPC_GET_POOL_INFO + { + struct request + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + std::string error_code; + std::list aliases_que; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(error_code) + KV_SERIALIZE(aliases_que) + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_RPC_GET_HEIGHT + { + struct request + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct response + { + uint64_t height; + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(height) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + + template + struct COMMAND_RPC_GET_BLOCKS_FAST_T + { + + struct request + { + std::list block_ids; //*first 10 blocks id goes sequential, next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 and so on, and the last one is always genesis block */ + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(block_ids) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::list blocks; + uint64_t start_height; + uint64_t current_height; + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(blocks) + KV_SERIALIZE(start_height) + KV_SERIALIZE(current_height) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + + typedef COMMAND_RPC_GET_BLOCKS_FAST_T COMMAND_RPC_GET_BLOCKS_FAST; + typedef COMMAND_RPC_GET_BLOCKS_FAST_T COMMAND_RPC_GET_BLOCKS_DIRECT; + + + + //----------------------------------------------- + struct COMMAND_RPC_GET_TRANSACTIONS + { + struct request + { + std::list txs_hashes; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(txs_hashes) + END_KV_SERIALIZE_MAP() + }; + + + struct response + { + std::list txs_as_hex; //transactions blobs as hex + std::list missed_tx; //not found transactions + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(txs_as_hex) + KV_SERIALIZE(missed_tx) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + //----------------------------------------------- + struct COMMAND_RPC_GET_TX_POOL + { + struct request + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::list txs; //transactions blobs + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(txs) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + //----------------------------------------------- + struct COMMAND_RPC_CHECK_KEYIMAGES + { + struct request + { + std::list images; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(images) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::list images_stat; //true - unspent, false - spent + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(images_stat) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + //----------------------------------------------- + struct COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES + { + struct request + { + crypto::hash txid; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_VAL_POD_AS_BLOB(txid) + END_KV_SERIALIZE_MAP() + }; + + + struct response + { + std::vector o_indexes; + std::string status; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(o_indexes) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + + + struct COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES_BY_AMOUNT + { + struct request + { + uint64_t amount; + uint64_t i; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(amount) + KV_SERIALIZE(i) + END_KV_SERIALIZE_MAP() + }; + + + struct response + { + std::string status; + crypto::hash tx_id; + uint64_t out_no; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_POD_AS_HEX_STRING(tx_id) + KV_SERIALIZE(out_no) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + + + struct COMMAND_RPC_GET_MULTISIG_INFO + { + struct request + { + crypto::hash ms_id; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_POD_AS_HEX_STRING(ms_id) + END_KV_SERIALIZE_MAP() + }; + + + struct response + { + std::string status; + crypto::hash tx_id; + uint64_t out_no; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_POD_AS_HEX_STRING(tx_id) + KV_SERIALIZE(out_no) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + //----------------------------------------------- + struct COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS + { + struct request + { + std::list amounts; + uint64_t outs_count; + bool use_forced_mix_outs; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(amounts) + KV_SERIALIZE(outs_count) + KV_SERIALIZE(use_forced_mix_outs) + END_KV_SERIALIZE_MAP() + }; + +#pragma pack (push, 1) + struct out_entry + { + uint64_t global_amount_index; + crypto::public_key out_key; + }; +#pragma pack(pop) + + struct outs_for_amount + { + uint64_t amount; + std::list outs; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(amount) + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(outs) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::vector outs; + std::string status; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(outs) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + + //----------------------------------------------- + struct COMMAND_RPC_SET_MAINTAINERS_INFO + { + typedef nodetool::maintainers_entry request; + + struct response + { + std::string status; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + + //----------------------------------------------- + struct COMMAND_RPC_SEND_RAW_TX + { + struct request + { + std::string tx_as_hex; + + request() {} + explicit request(const transaction &); + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(tx_as_hex) + END_KV_SERIALIZE_MAP() + }; + + + struct response + { + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + + + struct COMMAND_RPC_FORCE_RELAY_RAW_TXS + { + struct request + { + std::vector txs_as_hex; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(txs_as_hex) + END_KV_SERIALIZE_MAP() + }; + + + struct response + { + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + //----------------------------------------------- + struct COMMAND_RPC_START_MINING + { + struct request + { + std::string miner_address; + uint64_t threads_count; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(miner_address) + KV_SERIALIZE(threads_count) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + //----------------------------------------------- + struct outs_index_stat + { + uint64_t amount_0_001; + uint64_t amount_0_01; + uint64_t amount_0_1; + uint64_t amount_1; + uint64_t amount_10; + uint64_t amount_100; + uint64_t amount_1000; + uint64_t amount_10000; + uint64_t amount_100000; + uint64_t amount_1000000; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(amount_0_001) + KV_SERIALIZE(amount_0_01) + KV_SERIALIZE(amount_0_1) + KV_SERIALIZE(amount_1) + KV_SERIALIZE(amount_10) + KV_SERIALIZE(amount_100) + KV_SERIALIZE(amount_1000) + KV_SERIALIZE(amount_10000) + KV_SERIALIZE(amount_100000) + KV_SERIALIZE(amount_1000000) + END_KV_SERIALIZE_MAP() + }; + //----------------------------------------------- + + struct bc_performance_data + { + //block processing zone + uint64_t block_processing_time_0; + uint64_t block_processing_time_1; + uint64_t target_calculating_time_2; + uint64_t longhash_calculating_time_3; + uint64_t all_txs_insert_time_5; + uint64_t etc_stuff_6; + uint64_t insert_time_4; + uint64_t raise_block_core_event; + + //tx processing zone + uint64_t tx_check_inputs_time; + uint64_t tx_add_one_tx_time; + uint64_t tx_process_extra; + uint64_t tx_process_attachment; + uint64_t tx_process_inputs; + uint64_t tx_push_global_index; + uint64_t tx_check_exist; + uint64_t tx_append_time; + uint64_t tx_append_rl_wait; + uint64_t tx_append_is_expired; + uint64_t tx_print_log; + uint64_t tx_prapare_append; + + + uint64_t tx_store_db; + + uint64_t tx_check_inputs_prefix_hash; + uint64_t tx_check_inputs_attachment_check; + uint64_t tx_check_inputs_loop; + uint64_t tx_check_inputs_loop_kimage_check; + uint64_t tx_check_inputs_loop_ch_in_val_sig; + uint64_t tx_check_inputs_loop_scan_outputkeys_get_item_size; + uint64_t tx_check_inputs_loop_scan_outputkeys_relative_to_absolute; + uint64_t tx_check_inputs_loop_scan_outputkeys_loop; + uint64_t tx_check_inputs_loop_scan_outputkeys_loop_get_subitem; + uint64_t tx_check_inputs_loop_scan_outputkeys_loop_find_tx; + uint64_t tx_check_inputs_loop_scan_outputkeys_loop_handle_output; + + + //db performance data + uint64_t map_size; + uint64_t tx_count; + uint64_t writer_tx_count; + + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(block_processing_time_0) + KV_SERIALIZE(block_processing_time_1) + KV_SERIALIZE(target_calculating_time_2) + KV_SERIALIZE(longhash_calculating_time_3) + KV_SERIALIZE(all_txs_insert_time_5) + KV_SERIALIZE(etc_stuff_6) + KV_SERIALIZE(insert_time_4) + KV_SERIALIZE(raise_block_core_event) + + //tx processing zone + KV_SERIALIZE(tx_check_inputs_time) + KV_SERIALIZE(tx_add_one_tx_time) + KV_SERIALIZE(tx_process_extra) + KV_SERIALIZE(tx_process_attachment) + KV_SERIALIZE(tx_process_inputs) + KV_SERIALIZE(tx_push_global_index) + KV_SERIALIZE(tx_check_exist) + KV_SERIALIZE(tx_append_time) + KV_SERIALIZE(tx_append_rl_wait) + KV_SERIALIZE(tx_append_is_expired) + KV_SERIALIZE(tx_store_db) + KV_SERIALIZE(tx_print_log) + KV_SERIALIZE(tx_prapare_append) + + KV_SERIALIZE(tx_check_inputs_prefix_hash) + KV_SERIALIZE(tx_check_inputs_attachment_check) + KV_SERIALIZE(tx_check_inputs_loop) + KV_SERIALIZE(tx_check_inputs_loop_kimage_check) + KV_SERIALIZE(tx_check_inputs_loop_ch_in_val_sig) + KV_SERIALIZE(tx_check_inputs_loop_scan_outputkeys_get_item_size) + KV_SERIALIZE(tx_check_inputs_loop_scan_outputkeys_relative_to_absolute) + KV_SERIALIZE(tx_check_inputs_loop_scan_outputkeys_loop) + KV_SERIALIZE(tx_check_inputs_loop_scan_outputkeys_loop_get_subitem) + KV_SERIALIZE(tx_check_inputs_loop_scan_outputkeys_loop_find_tx) + KV_SERIALIZE(tx_check_inputs_loop_scan_outputkeys_loop_handle_output) + + //db performace data + KV_SERIALIZE(map_size) + KV_SERIALIZE(tx_count) + KV_SERIALIZE(writer_tx_count) + END_KV_SERIALIZE_MAP() + }; + + struct pool_performance_data + { + uint64_t tx_processing_time; + uint64_t check_inputs_types_supported_time; + uint64_t expiration_validate_time; + uint64_t validate_amount_time; + uint64_t validate_alias_time; + uint64_t check_keyimages_ws_ms_time; + uint64_t check_inputs_time; + uint64_t begin_tx_time; + uint64_t update_db_time; + uint64_t db_commit_time; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(tx_processing_time) + KV_SERIALIZE(check_inputs_types_supported_time) + KV_SERIALIZE(expiration_validate_time) + KV_SERIALIZE(validate_amount_time) + KV_SERIALIZE(validate_alias_time) + KV_SERIALIZE(check_keyimages_ws_ms_time) + KV_SERIALIZE(check_inputs_time) + KV_SERIALIZE(begin_tx_time) + KV_SERIALIZE(update_db_time) + KV_SERIALIZE(db_commit_time) + END_KV_SERIALIZE_MAP() + }; + + + //----------------------------------------------- + +#define COMMAND_RPC_GET_INFO_FLAG_POS_DIFFICULTY 0x0000000000000001LL +#define COMMAND_RPC_GET_INFO_FLAG_POW_DIFFICULTY 0x0000000000000002LL +#define COMMAND_RPC_GET_INFO_FLAG_NET_TIME_DELTA_MEDIAN 0x0000000000000004LL +#define COMMAND_RPC_GET_INFO_FLAG_CURRENT_NETWORK_HASHRATE_50 0x0000000000000008LL +#define COMMAND_RPC_GET_INFO_FLAG_CURRENT_NETWORK_HASHRATE_350 0x0000000000000010LL +#define COMMAND_RPC_GET_INFO_FLAG_SECONDS_FOR_10_BLOCKS 0x0000000000000020LL +#define COMMAND_RPC_GET_INFO_FLAG_SECONDS_FOR_30_BLOCKS 0x0000000000000040LL +#define COMMAND_RPC_GET_INFO_FLAG_TRANSACTIONS_DAILY_STAT 0x0000000000000080LL +#define COMMAND_RPC_GET_INFO_FLAG_LAST_POS_TIMESTAMP 0x0000000000000100LL +#define COMMAND_RPC_GET_INFO_FLAG_LAST_POW_TIMESTAMP 0x0000000000000200LL +#define COMMAND_RPC_GET_INFO_FLAG_TOTAL_COINS 0x0000000000000400LL +#define COMMAND_RPC_GET_INFO_FLAG_LAST_BLOCK_SIZE 0x0000000000000800LL +#define COMMAND_RPC_GET_INFO_FLAG_TX_COUNT_IN_LAST_BLOCK 0x0000000000001000LL +#define COMMAND_RPC_GET_INFO_FLAG_POS_SEQUENCE_FACTOR 0x0000000000002000LL +#define COMMAND_RPC_GET_INFO_FLAG_POW_SEQUENCE_FACTOR 0x0000000000004000LL +#define COMMAND_RPC_GET_INFO_FLAG_OUTS_STAT 0x0000000000008000LL +#define COMMAND_RPC_GET_INFO_FLAG_PERFORMANCE 0x0000000000010000LL +#define COMMAND_RPC_GET_INFO_FLAG_POS_BLOCK_TS_SHIFT_VS_ACTUAL 0x0000000000020000LL +#define COMMAND_RPC_GET_INFO_FLAG_MARKET 0x0000000000040000LL +#define COMMAND_RPC_GET_INFO_FLAG_EXPIRATIONS_MEDIAN 0x0000000000080000LL + +#define COMMAND_RPC_GET_INFO_FLAG_ALL_FLAGS 0xffffffffffffffffLL + + + struct COMMAND_RPC_GET_INFO + { + struct request + { + uint64_t flags; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(flags) + END_KV_SERIALIZE_MAP() + }; + + enum + { + daemon_network_state_connecting = 0, + daemon_network_state_synchronizing = 1, + daemon_network_state_online = 2, + daemon_network_state_loading_core = 3, + daemon_network_state_internal_error = 4, + daemon_network_state_unloading_core = 5 + }; + + struct response + { + std::string status; + uint64_t height; + std::string pos_difficulty; + uint64_t pow_difficulty; + uint64_t tx_count; + uint64_t tx_pool_size; + uint64_t alt_blocks_count; + uint64_t outgoing_connections_count; + uint64_t incoming_connections_count; + uint64_t synchronized_connections_count; + int64_t net_time_delta_median; + uint64_t white_peerlist_size; + uint64_t grey_peerlist_size; + uint64_t current_blocks_median; + uint64_t current_network_hashrate_50; + uint64_t current_network_hashrate_350; + uint64_t seconds_for_10_blocks; + uint64_t seconds_for_30_blocks; + uint64_t alias_count; + uint64_t daemon_network_state; + uint64_t synchronization_start_height; + uint64_t max_net_seen_height; + uint64_t transactions_cnt_per_day; + uint64_t transactions_volume_per_day; + nodetool::maintainers_info_external mi; + uint64_t pos_sequence_factor; + uint64_t pow_sequence_factor; + uint64_t last_pow_timestamp; + uint64_t last_pos_timestamp; + uint64_t total_coins; + uint64_t block_reward; + uint64_t last_block_total_reward; + uint64_t pos_diff_total_coins_rate; + int64_t pos_block_ts_shift_vs_actual; + uint64_t expiration_median_timestamp; + outs_index_stat outs_stat; + bc_performance_data performance_data; + pool_performance_data tx_pool_performance_data; + bool pos_allowed; + uint64_t last_block_size; + uint64_t current_max_allowed_block_size; + uint64_t tx_count_in_last_block; + uint64_t default_fee; + uint64_t minimum_fee; + //market + uint64_t offers_count; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(height) + KV_SERIALIZE(pos_difficulty) + KV_SERIALIZE(pow_difficulty) + KV_SERIALIZE(tx_count) + KV_SERIALIZE(tx_pool_size) + KV_SERIALIZE(alt_blocks_count) + KV_SERIALIZE(outgoing_connections_count) + KV_SERIALIZE(incoming_connections_count) + KV_SERIALIZE(synchronized_connections_count) + KV_SERIALIZE(net_time_delta_median) + KV_SERIALIZE(white_peerlist_size) + KV_SERIALIZE(grey_peerlist_size) + KV_SERIALIZE(current_blocks_median) + KV_SERIALIZE(current_network_hashrate_50) + KV_SERIALIZE(current_network_hashrate_350) + KV_SERIALIZE(alias_count) + KV_SERIALIZE(daemon_network_state) + KV_SERIALIZE(synchronization_start_height) + KV_SERIALIZE(max_net_seen_height) + KV_SERIALIZE(transactions_cnt_per_day) + KV_SERIALIZE(transactions_volume_per_day) + KV_SERIALIZE(mi) + KV_SERIALIZE(pos_sequence_factor) + KV_SERIALIZE(pow_sequence_factor) + KV_SERIALIZE(last_pow_timestamp) + KV_SERIALIZE(last_pos_timestamp) + KV_SERIALIZE(seconds_for_10_blocks) + KV_SERIALIZE(seconds_for_30_blocks) + KV_SERIALIZE(total_coins) + KV_SERIALIZE(block_reward) + KV_SERIALIZE(last_block_total_reward) + KV_SERIALIZE(pos_diff_total_coins_rate) + KV_SERIALIZE(pos_block_ts_shift_vs_actual) + KV_SERIALIZE(expiration_median_timestamp) + KV_SERIALIZE(pos_allowed) + KV_SERIALIZE(outs_stat) + KV_SERIALIZE(performance_data) + KV_SERIALIZE(tx_pool_performance_data) + KV_SERIALIZE(last_block_size) + KV_SERIALIZE(current_max_allowed_block_size) + KV_SERIALIZE(tx_count_in_last_block) + KV_SERIALIZE(default_fee) + KV_SERIALIZE(minimum_fee) + KV_SERIALIZE(offers_count) + END_KV_SERIALIZE_MAP() + }; + }; + //----------------------------------------------- + struct COMMAND_RPC_STOP_MINING + { + struct request + { + + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + + struct response + { + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + + + // + struct COMMAND_RPC_GETBLOCKCOUNT + { + typedef std::list request; + + struct response + { + uint64_t count; + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(count) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + + }; + + struct COMMAND_RPC_GETBLOCKHASH + { + typedef std::vector request; + + typedef std::string response; + }; + + + struct COMMAND_RPC_GETBLOCKTEMPLATE + { + struct request + { + //uint64_t reserve_size; //max 255 bytes + std::string extra_text; + std::string wallet_address; + std::string stakeholder_address; + bool pos_block; //is pos block + uint64_t pos_amount; // + uint64_t pos_index; // + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(extra_text) + KV_SERIALIZE(wallet_address) + KV_SERIALIZE(stakeholder_address); + KV_SERIALIZE(pos_block) + KV_SERIALIZE(pos_amount) + KV_SERIALIZE(pos_index) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + uint64_t difficulty; + uint64_t height; + blobdata blocktemplate_blob; + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(difficulty) + KV_SERIALIZE(height) + KV_SERIALIZE(blocktemplate_blob) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_RPC_SUBMITBLOCK + { + typedef std::vector request; + + struct response + { + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + + struct block_header_response + { + uint8_t major_version; + uint8_t minor_version; + uint64_t timestamp; + std::string prev_hash; + uint64_t nonce; + bool orphan_status; + uint64_t height; + uint64_t depth; + std::string hash; + difficulty_type difficulty; + uint64_t reward; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(major_version) + KV_SERIALIZE(minor_version) + KV_SERIALIZE(timestamp) + KV_SERIALIZE(prev_hash) + KV_SERIALIZE(nonce) + KV_SERIALIZE(orphan_status) + KV_SERIALIZE(height) + KV_SERIALIZE(depth) + KV_SERIALIZE(hash) + KV_SERIALIZE(difficulty) + KV_SERIALIZE(reward) + END_KV_SERIALIZE_MAP() + }; + + struct COMMAND_RPC_GET_LAST_BLOCK_HEADER + { + typedef std::list request; + + struct response + { + std::string status; + block_header_response block_header; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(block_header) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + + }; + + struct COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH + { + struct request + { + std::string hash; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(hash) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + block_header_response block_header; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(block_header) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + + }; + + struct COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT + { + struct request + { + uint64_t height; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(height) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + block_header_response block_header; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(block_header) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + + }; + + struct COMMAND_RPC_GET_ALIAS_DETAILS + { + struct request + { + std::string alias; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(alias) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + alias_rpc_details_base alias_details; + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(alias_details) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_RPC_GET_ALIAS_REWARD + { + struct request + { + std::string alias; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(alias) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + uint64_t reward; + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(reward) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + + + struct COMMAND_RPC_GET_ALL_ALIASES + { + struct request + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::list aliases; + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(aliases) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_RPC_GET_ALIASES + { + struct request + { + uint64_t offset; + uint64_t count; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(offset) + KV_SERIALIZE(count) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::list aliases; + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(aliases) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_RPC_GET_ALIASES_BY_ADDRESS + { + + typedef std::string request; + + struct response + { + //std::string alias; + alias_rpc_details alias_info; + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(alias_info) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + + + struct COMMAND_RPC_GET_ADDENDUMS + { + + typedef mining::height_info request; + + struct response + { + std::string status; + std::list addms; + + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(addms) + END_KV_SERIALIZE_MAP() + }; + }; + + + struct COMMAND_RPC_RESET_TX_POOL + { + + struct request + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_RPC_SCAN_POS + { + struct request + { + std::vector pos_entries; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(pos_entries) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + uint64_t index; + uint64_t block_timestamp; + uint64_t height; + uint64_t starter_timestamp; + crypto::hash last_block_hash; + bool is_pos_allowed; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(index) + KV_SERIALIZE(block_timestamp) + KV_SERIALIZE(height) + KV_SERIALIZE(is_pos_allowed) + KV_SERIALIZE(starter_timestamp) + KV_SERIALIZE_VAL_POD_AS_BLOB(last_block_hash); + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_RPC_GET_POS_MINING_DETAILS + { + struct request + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct response + { + stake_modifier_type sm; + uint64_t starter_timestamp; + std::string pos_basic_difficulty; + std::string status; + crypto::hash last_block_hash; + bool pos_mining_allowed; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_VAL_POD_AS_BLOB(sm) + KV_SERIALIZE(pos_basic_difficulty) + KV_SERIALIZE(starter_timestamp) + KV_SERIALIZE(pos_mining_allowed) + KV_SERIALIZE(status) + KV_SERIALIZE_VAL_POD_AS_BLOB(last_block_hash) + END_KV_SERIALIZE_MAP() + }; + }; + + struct tx_out_rpc_entry + { + uint64_t amount; + std::list pub_keys; + uint64_t minimum_sigs; + bool is_spent; + uint64_t global_index; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(amount) + KV_SERIALIZE(pub_keys) + KV_SERIALIZE(minimum_sigs) + KV_SERIALIZE(is_spent) + KV_SERIALIZE(global_index) + END_KV_SERIALIZE_MAP() + }; + + struct tx_in_rpc_entry + { + uint64_t amount; + uint64_t multisig_count; + std::string kimage_or_ms_id; + std::vector global_indexes; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(amount) + KV_SERIALIZE(kimage_or_ms_id) + KV_SERIALIZE(global_indexes) + KV_SERIALIZE(multisig_count) + END_KV_SERIALIZE_MAP() + }; + + struct tx_extra_rpc_entry + { + std::string type; + std::string short_view; + std::string datails_view; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(type) + KV_SERIALIZE(short_view) + KV_SERIALIZE(datails_view) + END_KV_SERIALIZE_MAP() + }; + + + struct tx_rpc_extended_info + { + blobdata blob; + uint64_t blob_size; + uint64_t fee; + uint64_t amount; + uint64_t timestamp; + int64_t keeper_block; // signed int, -1 means unconfirmed transaction + std::string id; + std::string pub_key; + std::vector outs; + std::vector ins; + std::vector extra; + std::vector attachments; + std::string object_in_json; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(blob) + KV_SERIALIZE(blob_size) + KV_SERIALIZE(timestamp) + KV_SERIALIZE(keeper_block) + KV_SERIALIZE(fee) + KV_SERIALIZE(amount) + KV_SERIALIZE(id) + KV_SERIALIZE(pub_key) + KV_SERIALIZE(outs) + KV_SERIALIZE(ins) + KV_SERIALIZE(extra) + KV_SERIALIZE(attachments) + KV_SERIALIZE(object_in_json) + END_KV_SERIALIZE_MAP() + }; + + struct tx_rpc_brief_info + { + std::string id; + uint64_t fee; + uint64_t total_amount; + uint64_t sz; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(id) + KV_SERIALIZE(fee) + KV_SERIALIZE(total_amount) + KV_SERIALIZE(sz) + END_KV_SERIALIZE_MAP() + }; + + struct block_rpc_extended_info + { + std::string blob; + uint64_t height; + uint64_t timestamp; + uint64_t actual_timestamp; + uint64_t block_cumulative_size; + uint64_t total_txs_size; + uint64_t block_tself_size; + uint64_t base_reward; + uint64_t summary_reward; + uint64_t penalty; + uint64_t total_fee; + std::string id; + std::string cumulative_diff_adjusted; + std::string cumulative_diff_precise; + std::string difficulty; + std::string prev_id; + uint64_t type; + bool is_orphan; + uint64_t already_generated_coins; + uint64_t this_block_fee_median; + uint64_t effective_fee_median; + std::list transactions_details; + std::string miner_text_info; + std::string object_in_json; + + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(blob) + KV_SERIALIZE(height) + KV_SERIALIZE(timestamp) + KV_SERIALIZE(actual_timestamp) + KV_SERIALIZE(block_cumulative_size) + KV_SERIALIZE(total_txs_size) + KV_SERIALIZE(block_tself_size) + KV_SERIALIZE(base_reward) + KV_SERIALIZE(summary_reward) + KV_SERIALIZE(total_fee) + KV_SERIALIZE(penalty) + KV_SERIALIZE(id) + KV_SERIALIZE(prev_id) + KV_SERIALIZE(cumulative_diff_adjusted) + KV_SERIALIZE(cumulative_diff_precise) + KV_SERIALIZE(difficulty) + KV_SERIALIZE(already_generated_coins) + KV_SERIALIZE(this_block_fee_median) + KV_SERIALIZE(effective_fee_median) + KV_SERIALIZE(transactions_details) + KV_SERIALIZE(type) + KV_SERIALIZE(is_orphan) + KV_SERIALIZE(miner_text_info) + KV_SERIALIZE(object_in_json) + END_KV_SERIALIZE_MAP() + }; + + + + struct COMMAND_RPC_GET_BLOCKS_DETAILS + { + struct request + { + uint64_t height_start; + uint64_t count; + bool ignore_transactions; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(height_start) + KV_SERIALIZE(count) + KV_SERIALIZE(ignore_transactions) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + std::list blocks; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(blocks) + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_RPC_GET_ALT_BLOCKS_DETAILS + { + struct request + { + uint64_t offset; + uint64_t count; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(offset) + KV_SERIALIZE(count) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + std::vector blocks; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(blocks) + END_KV_SERIALIZE_MAP() + }; + }; + + + struct COMMAND_RPC_GET_BLOCK_DETAILS + { + struct request + { + crypto::hash id; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_POD_AS_HEX_STRING(id) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + block_rpc_extended_info block_details; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(block_details) + END_KV_SERIALIZE_MAP() + }; + }; + + + struct COMMAND_RPC_GET_POOL_TXS_DETAILS + { + struct request + { + std::list ids; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(ids) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + std::list txs; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(txs) + END_KV_SERIALIZE_MAP() + }; + }; + + + struct COMMAND_RPC_GET_POOL_TXS_BRIEF_DETAILS + { + struct request + { + std::list ids; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(ids) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + std::list txs; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(txs) + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_RPC_GET_ALL_POOL_TX_LIST + { + struct request + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + std::list ids; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(ids) + END_KV_SERIALIZE_MAP() + }; + }; + + + struct COMMAND_RPC_GET_GLOBAL_INDEX_INFO + { + struct request + { + uint64_t height_start; + uint64_t count; + bool ignore_transactions; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(height_start) + KV_SERIALIZE(count) + KV_SERIALIZE(ignore_transactions) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + std::list blocks; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(blocks) + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_RPC_GET_TX_DETAILS + { + struct request + { + std::string tx_hash; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(tx_hash) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + tx_rpc_extended_info tx_info; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(tx_info) + END_KV_SERIALIZE_MAP() + }; + }; + + + struct search_entry + { + std::string type; + }; + + struct COMMAND_RPC_SERARCH_BY_ID + { + struct request + { + std::string id; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(id) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + std::list types_found; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(types_found) + END_KV_SERIALIZE_MAP() + }; + }; + + + struct COMMAND_RPC_GET_ALL_OFFERS + { + struct request + { + + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + std::list offers; + uint64_t total_offers; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(offers) + KV_SERIALIZE(total_offers) + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN + { + struct request + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + uint64_t expiration_median; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(expiration_median) + END_KV_SERIALIZE_MAP() + }; + }; + + struct void_struct + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + +} + diff --git a/src/rpc/core_rpc_server_error_codes.h b/src/rpc/core_rpc_server_error_codes.h new file mode 100644 index 00000000..38df7321 --- /dev/null +++ b/src/rpc/core_rpc_server_error_codes.h @@ -0,0 +1,23 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + + +#define CORE_RPC_ERROR_CODE_WRONG_PARAM -1 +#define CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT -2 +#define CORE_RPC_ERROR_CODE_TOO_BIG_RESERVE_SIZE -3 +#define CORE_RPC_ERROR_CODE_WRONG_WALLET_ADDRESS -4 +#define CORE_RPC_ERROR_CODE_INTERNAL_ERROR -5 +#define CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB -6 +#define CORE_RPC_ERROR_CODE_BLOCK_NOT_ACCEPTED -7 +#define CORE_RPC_ERROR_CODE_CORE_BUSY -9 +#define CORE_RPC_ERROR_CODE_INVALID_ALIAS_NAME -10 +#define CORE_RPC_ERROR_CODE_INVALID_ALIAS_ADDRESS -11 +#define CORE_RPC_ERROR_CODE_ALIAS_COMMENT_TO_LONG -12 +#define CORE_RPC_ERROR_CODE_BLOCK_ADDED_AS_ALTERNATIVE -13 +#define CORE_RPC_ERROR_CODE_NOT_FOUND -14 + diff --git a/src/rpc/mining_protocol_defs.h b/src/rpc/mining_protocol_defs.h new file mode 100644 index 00000000..14665583 --- /dev/null +++ b/src/rpc/mining_protocol_defs.h @@ -0,0 +1,207 @@ +// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include "currency_protocol/currency_protocol_defs.h" +#include "currency_core/currency_basic.h" +#include "crypto/hash.h" +#include "net/rpc_method_name.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Seems to be obsolete. Consider removing due to stratum support. +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +namespace mining +{ + struct height_info + { + uint64_t height; + std::string block_id; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(height) + KV_SERIALIZE(block_id) + END_KV_SERIALIZE_MAP() + }; + + + struct addendum + { + height_info hi; + std::string prev_id; + std::string addm; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(hi) + KV_SERIALIZE(prev_id) + KV_SERIALIZE(addm) + END_KV_SERIALIZE_MAP() + }; + + struct job_details + { + std::string blob; + std::string difficulty; + std::string job_id; + height_info prev_hi; + std::list addms; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(blob) + KV_SERIALIZE(difficulty) + KV_SERIALIZE(job_id) + KV_SERIALIZE(prev_hi) + KV_SERIALIZE(addms) + END_KV_SERIALIZE_MAP() + }; + + struct COMMAND_RPC_LOGIN + { + RPC_METHOD_NAME("login"); + + struct request + { + std::string login; + std::string pass; + std::string agent; + height_info hi; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(login) + KV_SERIALIZE(pass) + KV_SERIALIZE(agent) + KV_SERIALIZE(hi) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + std::string id; + job_details job; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(id) + KV_SERIALIZE(job) + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_RPC_GETJOB + { + RPC_METHOD_NAME("getjob"); + + struct request + { + std::string id; + height_info hi; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(id) + KV_SERIALIZE(hi) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + job_details jd; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_CHAIN_MAP(jd) + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_RPC_GET_FULLSCRATCHPAD + { + RPC_METHOD_NAME("getfullscratchpad"); + + struct request + { + std::string id; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(id) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + height_info hi; + std::string scratchpad_hex; + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(hi) + KV_SERIALIZE(scratchpad_hex) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + + + struct COMMAND_RPC_SUBMITSHARE + { + RPC_METHOD_NAME("submit"); + + struct request + { + std::string id; + uint64_t nonce; + std::string job_id; + std::string result; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(id) + KV_SERIALIZE(nonce) + KV_SERIALIZE(job_id) + KV_SERIALIZE(result) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + + + struct COMMAND_RPC_STORE_SCRATCHPAD + { + RPC_METHOD_NAME("store_scratchpad"); + + struct request + { + std::string local_file_path; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(local_file_path) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + + + +} + diff --git a/src/serialization/binary_archive.h b/src/serialization/binary_archive.h new file mode 100644 index 00000000..16ac2074 --- /dev/null +++ b/src/serialization/binary_archive.h @@ -0,0 +1,175 @@ +// Copyright (c) 2014-2017 The The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +/* binary_archive.h + * + * Portable (low-endian) binary archive */ +#pragma once + +#include +#include +#include +#include + +#include "common/varint.h" +#include "warnings.h" + +PUSH_WARNINGS +DISABLE_VS_WARNINGS(4244) +DISABLE_VS_WARNINGS(4100) + +//TODO: fix size_t warning in x32 platform + +template +struct binary_archive_base +{ + typedef Stream stream_type; + typedef binary_archive_base base_type; + typedef boost::mpl::bool_ is_saving; + + typedef uint8_t variant_tag_type; + + explicit binary_archive_base(stream_type &s) : stream_(s) { } + + bool is_saving_arch(){ return IsSaving; } + void tag(const char *) { } + void begin_object() { } + void end_object() { } + void begin_variant() { } + void end_variant() { } + stream_type &stream() { return stream_; } +protected: + stream_type &stream_; +}; + +template +struct binary_archive; + +template <> +struct binary_archive : public binary_archive_base +{ + explicit binary_archive(stream_type &s) : base_type(s) { + stream_type::streampos pos = stream_.tellg(); + stream_.seekg(0, std::ios_base::end); + eof_pos_ = stream_.tellg(); + stream_.seekg(pos); + } + + template + void serialize_int(T &v) + { + serialize_uint(*(typename boost::make_unsigned::type *)&v); + } + + + template + void serialize_uint(T &v, size_t width = sizeof(T)) + { + T ret = 0; + unsigned shift = 0; + for (size_t i = 0; i < width; i++) { + //std::cerr << "tell: " << stream_.tellg() << " value: " << ret << std::endl; + char c; + stream_.get(c); + T b = (unsigned char)c; + ret += (b << shift); + shift += 8; + } + v = ret; + } + void serialize_blob(void *buf, size_t len, const char *delimiter="") { + stream_.read((char *)buf, len); + } + + template + void serialize_varint(T &v) + { + serialize_uvarint(*(typename boost::make_unsigned::type *)(&v)); + } + + template + void serialize_uvarint(T &v) + { + typedef std::istreambuf_iterator it; + tools::read_varint(it(stream_), it(), v); // XXX handle failure + } + void begin_array(size_t &s) + { + serialize_varint(s); + } + void begin_array() { } + + void delimit_array() { } + void end_array() { } + + void begin_string(const char *delimiter="\"") { } + void end_string(const char *delimiter="\"") { } + + void read_variant_tag(variant_tag_type &t) { + serialize_int(t); + } + + size_t remaining_bytes() { + if (!stream_.good()) + return 0; + //std::cerr << "tell: " << stream_.tellg() << std::endl; + assert(stream_.tellg() <= eof_pos_); + return eof_pos_ - stream_.tellg(); + } +protected: + std::streamoff eof_pos_; +}; + +template <> +struct binary_archive : public binary_archive_base +{ + explicit binary_archive(stream_type &s) : base_type(s) { } + + template + void serialize_int(T v) + { + serialize_uint(static_cast::type>(v)); + } + template + void serialize_uint(T v) + { + for (size_t i = 0; i < sizeof(T); i++) { + stream_.put((char)(v & 0xff)); + if (1 < sizeof(T)) { + v >>= 8; + } + } + } + void serialize_blob(void *buf, size_t len, const char *delimiter="") { stream_.write((char *)buf, len); } + + template + void serialize_varint(T &v) + { + serialize_uvarint(*(typename boost::make_unsigned::type *)(&v)); + } + + template + void serialize_uvarint(T &v) + { + typedef std::ostreambuf_iterator it; + tools::write_varint(it(stream_), v); + } + void begin_array(size_t s) + { + serialize_varint(s); + } + void begin_array() { } + void delimit_array() { } + void end_array() { } + + void begin_string(const char *delimiter="\"") { } + void end_string(const char *delimiter="\"") { } + + void write_variant_tag(variant_tag_type t) { + serialize_int(t); + } +}; + +POP_WARNINGS diff --git a/src/serialization/binary_utils.h b/src/serialization/binary_utils.h new file mode 100644 index 00000000..c9b5c31a --- /dev/null +++ b/src/serialization/binary_utils.h @@ -0,0 +1,29 @@ +// Copyright (c) 2014-2017 The The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include "binary_archive.h" + +namespace serialization { + +template +bool parse_binary(const std::string &blob, T &v) +{ + std::istringstream istr(blob); + binary_archive iar(istr); + return ::serialization::serialize(iar, v); +} + +template +bool dump_binary(T& v, std::string& blob) +{ + std::stringstream ostr; + binary_archive oar(ostr); + bool success = ::serialization::serialize(oar, v); + blob = ostr.str(); + return success && ostr.good(); +}; + +} // namespace serialization diff --git a/src/serialization/crypto.h b/src/serialization/crypto.h new file mode 100644 index 00000000..c436b466 --- /dev/null +++ b/src/serialization/crypto.h @@ -0,0 +1,63 @@ +// Copyright (c) 2014-2017 The The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "serialization.h" +#include "debug_archive.h" +#include "crypto/chacha8.h" +#include "crypto/crypto.h" +#include "crypto/hash.h" + +/*// read +template