diff --git a/.clang-format b/.clang-format index 067b805b5..4d376d2a8 100644 --- a/.clang-format +++ b/.clang-format @@ -2,14 +2,14 @@ Language: Cpp # BasedOnStyle: LLVM AccessModifierOffset: -2 -AlignAfterOpenBracket: Align -AlignArrayOfStructures: None +AlignAfterOpenBracket: BlockIndent +AlignArrayOfStructures: Right AlignConsecutiveMacros: None AlignConsecutiveAssignments: None AlignConsecutiveBitFields: None AlignConsecutiveDeclarations: None AlignEscapedNewlines: Right -AlignOperands: Align +AlignOperands: Align AlignTrailingComments: true AllowAllArgumentsOnNextLine: true AllowAllParametersOfDeclarationOnNextLine: true @@ -26,8 +26,8 @@ AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: MultiLine AttributeMacros: - __capability -BinPackArguments: true -BinPackParameters: true +BinPackArguments: false +BinPackParameters: false BraceWrapping: AfterCaseLabel: false AfterClass: false @@ -61,8 +61,8 @@ ColumnLimit: 120 CommentPragmas: '^ IWYU pragma:' QualifierAlignment: Leave CompactNamespaces: false -ConstructorInitializerIndentWidth: 4 -ContinuationIndentWidth: 4 +ConstructorInitializerIndentWidth: 2 +ContinuationIndentWidth: 2 Cpp11BracedListStyle: true DeriveLineEnding: true DerivePointerAlignment: false @@ -136,7 +136,7 @@ ReferenceAlignment: Pointer ReflowComments: true RemoveBracesLLVM: false SeparateDefinitionBlocks: Leave -ShortNamespaceLines: 1 +ShortNamespaceLines: 0 SortIncludes: CaseSensitive SortJavaStaticImport: Before SortUsingDeclarations: true @@ -145,18 +145,18 @@ SpaceAfterLogicalNot: false SpaceAfterTemplateKeyword: true SpaceBeforeAssignmentOperators: true SpaceBeforeCaseColon: false -SpaceBeforeCpp11BracedList: false +SpaceBeforeCpp11BracedList: true SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatements SpaceBeforeParensOptions: AfterControlStatements: true AfterForeachMacros: true - AfterFunctionDefinitionName: false - AfterFunctionDeclarationName: false + AfterFunctionDefinitionName: true + AfterFunctionDeclarationName: true AfterIfMacros: true - AfterOverloadedOperator: false - BeforeNonEmptyParentheses: false + AfterOverloadedOperator: true + BeforeNonEmptyParentheses: true SpaceAroundPointerQualifiers: Default SpaceBeforeRangeBasedForLoopColon: true SpaceInEmptyBlock: false diff --git a/.code-check.json b/.code-check.json deleted file mode 100644 index 5aa224bba..000000000 --- a/.code-check.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "paths": [ - "src/", - "unit-tests.wsjcpp/src/" - ], - "exclude": [ - "src/core/3rdParty", - "src-libhv", - "src/3rdParty/quazip-0.7.3", - "src/resources", - "json.hpp", - ".DS_Store" - ], - "line-checkers": { - "if-format": "err", - "while-format": "err", - "for-format": "err", - "end-brackets": "warn", - "start-bracket-else": "err", - "end-bracket-else": "err", - "tabs": "err", - "TODO": "warn", - "auto": "warn" - } -} diff --git a/.dockerignore b/.dockerignore index 661c6e48a..674b1e9d0 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,5 @@ .git ci -code-check contrib docker_dev fhqjad-store @@ -8,4 +7,9 @@ install tests /web-user/node_modules /web-user/dist -_config.yml \ No newline at end of file +_config.yml +/tmp +/web-user/.angular +/backups +/Dockerfile.build-environment +/Dockerfile.release-environment \ No newline at end of file diff --git a/.gitignore b/.gitignore index 1f86c5417..c05153c62 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ dckr_mysql/* +/build # Compiled Object files *.slo *.lo @@ -52,6 +53,7 @@ lintian.log freehackquest-backend.pro.user /html/* /latex/* +/ci/travis/data/file_storage/db/* .qmake.stash .DS_Store @@ -77,6 +79,7 @@ tests/get-pip.py fhq-server/fhq-server.debian95 .idea /data +/backups /docker_test .wsjcpp fhq-server @@ -89,4 +92,8 @@ contrib/docker_compose_example/nginx/logs/*.log TODO 12.webp __pycache__ -/tmp \ No newline at end of file +/tmp +node_modules +web-user/.angular +Dockerfile.build-environment +Dockerfile.release-environment \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c502fdb0..3febbfbd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,54 @@ All notable changes to fhq-server project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [v0.2.53] - 2025-06-14 + +- Updated wsjcpp-yaml from 0.1.7 to 0.1.8 +- Updated years to -2025 +- Fix remove item from knowledge base +- Moved clean.sh to './pm.py clean' +- Removed empty file SECURITY.md +- Updated wsjcpp-core from v0.2.2 to v0.2.3 +- Updated wsjcpp-validators from v0.1.2 to v0.1.3 +- Added EmployUuids, added models for useful_links, added new handlers `server_uuid_generate`, `server_uuid_info` +- Redesign work with sqlite +- Added src/third-party/easyzip/ https://github.com/winsoft666/easyzip (for replacement quazip-0.7.3 +- Redesign zipping to easyzip and removed quazip-0.7.3 +- Added generate models for pm.py + +## [v0.2.52] - 2024-07-21 (2024 Jule 21) + +### Added + +- Added reading game.info from file_storage/games/ +- Added copyright to any source file + +### Removed + +- [web-user] Removed proposal translate +- Removed github pages theme +- Removed FindPostgreSQL.cmake + +### Fixed + +- Fix knowlwdge base +- Updated email-validator + +### Security + +- [snyk] Updated tslib to 2.4.1 +- Updated to from angular 12 to angular 14 + +### Changed + +- Redesign script rebuild_environment_images.sh to pm.py +- Removed tests/code-check (redesign to libfhqpm) and fix clang-format style +- Prepare example for init sqlite database +- Redesign from ifdef to #pragma once +- Applyed clang-format +- Moved src-libhv to src/third-party/libhv and moved quazip-0.7.3 to third-party + + ## [v0.2.51] - 2023-01-03 (2023 Jan 3) ### Added @@ -38,7 +86,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [v0.2.50] - 2022-10-23 (2022 Oct 23) ### Fixed - + - Fix admin create user - Fix #318 - simplify start server via docker-compose diff --git a/CMakeLists.txt b/CMakeLists.txt index e24dbb053..4a464333e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,12 @@ -#********************************************************************************* -# Project -# __ _ -# / _| |__ __ _ ___ ___ _ ____ _____ _ __ +################################################################################## +# __ _ +# / _| |__ __ _ ___ ___ _ ____ _____ _ __ # | |_| '_ \ / _` | ___ / __|/ _ \ '__\ \ / / _ \ '__| -# | _| | | | (_| ||___|\__ \ __/ | \ V / __/ | -# |_| |_| |_|\__, | |___/\___|_| \_/ \___|_| -# |_| +# | _| | | | (_| ||___|\__ \ __/ | \ V / __/ | +# |_| |_| |_|\__, | |___/\___|_| \_/ \___|_| +# |_| # -# Copyright (c) 2011-2023 FreeHackQuest +# Copyright (c) 2011-2025 FreeHackQuest # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -15,10 +14,10 @@ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: -# +# # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. -# +# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -52,13 +51,12 @@ include_directories(${Qt5Core_INCLUDE_DIRS}) list (APPEND WSJCPP_INCLUDE_DIRS "src") list (APPEND WSJCPP_INCLUDE_DIRS "src/argument_processors") list (APPEND WSJCPP_INCLUDE_DIRS "src/core") +list (APPEND WSJCPP_INCLUDE_DIRS "src/database") list (APPEND WSJCPP_INCLUDE_DIRS "src/core/3rdParty") -list (APPEND WSJCPP_INCLUDE_DIRS "src/3rdParty/quazip-0.7.3/quazip") list (APPEND WSJCPP_INCLUDE_DIRS "src/utils") list (APPEND WSJCPP_INCLUDE_DIRS "src/validators") list (APPEND WSJCPP_INCLUDE_DIRS "src/employees") list (APPEND WSJCPP_INCLUDE_DIRS "src/models") -list (APPEND WSJCPP_INCLUDE_DIRS "src/models/include") list (APPEND WSJCPP_INCLUDE_DIRS "src/server") list (APPEND WSJCPP_INCLUDE_DIRS "src/tasks") list (APPEND WSJCPP_INCLUDE_DIRS "src/storages") @@ -88,82 +86,44 @@ list (APPEND WSJCPP_SOURCES "src/core/employees.cpp") list (APPEND WSJCPP_SOURCES "src/core/wsjcpp_export_libcli_web_js.h") list (APPEND WSJCPP_SOURCES "src/core/wsjcpp_export_libcli_web_js.cpp") -# quazip -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/crypt.h") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/ioapi.h") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/JlCompress.h") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/quaadler32.h") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/quachecksum32.h") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/quacrc32.h") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/quagzipfile.h") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/quaziodevice.h") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/quazipdir.h") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/quazipfile.h") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/quazipfileinfo.h") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/quazip_global.h") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/quazip.h") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/quazipnewinfo.h") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/unzip.h") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/zip.h") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/qioapi.cpp") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/JlCompress.cpp") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/quaadler32.cpp") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/quacrc32.cpp") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/quagzipfile.cpp") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/quaziodevice.cpp") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/quazip.cpp") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/quazipdir.cpp") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/quazipfile.cpp") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/quazipfileinfo.cpp") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/quazipnewinfo.cpp") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/unzip.c") -list (APPEND WSJCPP_SOURCES "src/3rdParty/quazip-0.7.3/quazip/zip.c") +# database +list (APPEND WSJCPP_SOURCES "src/database/fhq_server_database_file.cpp") +list (APPEND WSJCPP_SOURCES "src/database/fhq_server_db_email_delivery.cpp") +list (APPEND WSJCPP_SOURCES "src/database/fhq_server_db_useful_links.cpp") +list (APPEND WSJCPP_SOURCES "src/database/fhq_server_db_uuids.cpp") # cmd -list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_classbook.h") list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_classbook.cpp") -list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_communication.h") list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_communication.cpp") -list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_events.h") list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_events.cpp") -list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_games.h") list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_games.cpp") -list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_leaks.h") list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_leaks.cpp") -list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_lxd.h") list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_lxd.cpp") -list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_mails.h") list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_mails.cpp") -list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_quests_writeups.h") list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_quests_writeups.cpp") -list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_quests.h") list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_quests.cpp") -list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_server.h") list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_server.cpp") -list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_support.h") list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_support.cpp") -list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_useful_links.h") list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_useful_links.cpp") -list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_users.h") list (APPEND WSJCPP_SOURCES "src/cmd/cmd_handlers_users.cpp") # models +list (APPEND WSJCPP_SOURCES "src/models/model_game.cpp") list (APPEND WSJCPP_SOURCES "src/models/model_notification.cpp") list (APPEND WSJCPP_SOURCES "src/models/model_quest_file.cpp") -list (APPEND WSJCPP_SOURCES "src/models/include/model_database_connection.h") -list (APPEND WSJCPP_SOURCES "src/models/sources/model_database_connection.cpp") -list (APPEND WSJCPP_SOURCES "src/models/include/model_leak.h") -list (APPEND WSJCPP_SOURCES "src/models/sources/model_leak.cpp") -list (APPEND WSJCPP_SOURCES "src/models/include/model_game.h") -list (APPEND WSJCPP_SOURCES "src/models/sources/model_game.cpp") -list (APPEND WSJCPP_SOURCES "src/models/include/model_lxd_orchestra.h") -list (APPEND WSJCPP_SOURCES "src/models/sources/model_lxd_orchestra.cpp") +list (APPEND WSJCPP_SOURCES "src/models/model_database_connection.cpp") +list (APPEND WSJCPP_SOURCES "src/models/model_leak.cpp") +list (APPEND WSJCPP_SOURCES "src/models/model_lxd_orchestra.cpp") +list (APPEND WSJCPP_SOURCES "src/models/model_useful_link.cpp") +list (APPEND WSJCPP_SOURCES "src/models/model_useful_link_comment.cpp") +list (APPEND WSJCPP_SOURCES "src/models/model_useful_link_tag.cpp") +list (APPEND WSJCPP_SOURCES "src/models/model_useful_link_user_favorite.cpp") # validators list (APPEND WSJCPP_SOURCES "src/validators/validators.cpp") list (APPEND WSJCPP_SOURCES "src/validators/validators.h") -# TODO include only if libmysqlclient exists +# TODO include only if libmysqlclient exists list (APPEND WSJCPP_INCLUDE_DIRS "src/storages/mysql") list (APPEND WSJCPP_SOURCES "src/storages/mysql/mysql_storage.cpp") list (APPEND WSJCPP_SOURCES "src/storages/mysql/mysql_storage.h") @@ -188,6 +148,7 @@ list (APPEND WSJCPP_SOURCES "src/employees/employ_orchestra.cpp") list (APPEND WSJCPP_SOURCES "src/employees/employ_leaks.cpp") list (APPEND WSJCPP_SOURCES "src/employees/employ_mails.cpp") list (APPEND WSJCPP_SOURCES "src/employees/employ_users.cpp") +list (APPEND WSJCPP_SOURCES "src/employees/employ_uuids.cpp") # tasks list (APPEND WSJCPP_SOURCES "src/tasks/runtasks.h") @@ -258,7 +219,7 @@ endif( ZLIB_FOUND ) ############################ ############################ -##### mysql +##### mysql # Find and make sure the system have the header file find_path(MYSQL_HEADER mysql/mysql.h) if(MYSQL_HEADER STREQUAL "MYSQL_HEADER-NOTFOUND") @@ -277,10 +238,36 @@ list (APPEND WSJCPP_LIBRARIES ${LIBMYSQLCLIENT_LIBRARIES}) ##### ############################ +# easyzip +set(EASYZIP_BUILD_SHARED_LIBS OFF CACHE BOOL "") +add_subdirectory(src/third-party/easyzip) +list (APPEND WSJCPP_LIBRARIES easyzip-static) +list (APPEND WSJCPP_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/src/third-party/easyzip/include/easyzip") +message(STATUS "Easyzip Includes: ${PROJECT_SOURCE_DIR}/src/third-party/easyzip/include/easyzip") + # libhv -add_subdirectory(src-libhv) +set(WITH_OPENSSL OFF CACHE BOOL "") +set(WITH_CURL OFF CACHE BOOL "") +# set(WITH_MQTT OFF CACHE BOOL "") +# set(WITH_EVPP OFF CACHE BOOL "") +set(BUILD_EXAMPLES OFF CACHE BOOL "") +# set(WITH_HTTP_CLIENT OFF CACHE BOOL "") +set(BUILD_SHARED OFF CACHE BOOL "") + +add_subdirectory(src/third-party/libhv) list (APPEND WSJCPP_LIBRARIES hv_static) -list (APPEND WSJCPP_INCLUDE_DIRS "${PROJECT_BINARY_DIR}/src-libhv/include/hv") +list (APPEND WSJCPP_INCLUDE_DIRS "${PROJECT_BINARY_DIR}/src/third-party/libhv/include/hv") + + +add_subdirectory(src/third-party/sqlite3) +# https://www.sqlite.org/threadsafe.html +# target_compile_definitions(sqlite3-static +# PRIVATE +# SQLITE_THREADSAFE=0 +# ) +list (APPEND WSJCPP_LIBRARIES sqlite3-static) +message(STATUS "Sqlite Includes: ${PROJECT_SOURCE_DIR}/src/third-party/sqlite3/src") +list (APPEND WSJCPP_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/src/third-party/sqlite3/src") include_directories(${WSJCPP_INCLUDE_DIRS}) diff --git a/Dockerfile b/Dockerfile index 61f2be50c..68538a389 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM sea5kg/fhq-server-build-environment:latest +FROM sea5kg/fhq-server-build-environment:2025-08-06 WORKDIR /root/ # Fix for building on debian 9.5 system (mysqlclient library) @@ -7,7 +7,7 @@ WORKDIR /root/ # Build server application COPY . /root/fhq-server WORKDIR /root/fhq-server -RUN ./clean.sh && ./build_simple.sh +RUN python3 -u pm.py clean && ./build_simple.sh # Build web COPY ./web-user /root/web-user @@ -15,7 +15,7 @@ RUN cp -rf /root/node_modules_cache/node_modules /root/web-user WORKDIR /root/web-user RUN npm install && npm run build-prod -FROM sea5kg/fhq-server-release-environment:latest +FROM sea5kg/fhq-server-release-environment:2025-08-06 LABEL "maintainer"="Evgenii Sopov " LABEL "repository"="https://github.com/freehackquest/fhq-server" diff --git a/Dockerfile.build-environment b/Dockerfile.build-environment deleted file mode 100644 index 211f52d50..000000000 --- a/Dockerfile.build-environment +++ /dev/null @@ -1,43 +0,0 @@ -FROM debian:11 -WORKDIR /root/ - -LABEL "maintainer"="Evgenii Sopov " -LABEL "repository"="https://github.com/freehackquest/fhq-server" - -RUN apt-get update && \ - apt-get install -y curl - -RUN curl -sL https://deb.nodesource.com/setup_17.x -o setup_node_16x.sh && bash setup_node_16x.sh - -# basic libs -RUN apt-get update && apt-get install -y --no-install-recommends \ - make cmake \ - gcc g++ \ - curl \ - pkg-config \ - libcurl4-openssl-dev \ - zlib1g zlib1g-dev \ - libpng-dev \ - default-libmysqlclient-dev \ - libwebsockets-dev \ - apt-utils \ - gcc g++ \ - build-essential \ - nodejs - -# RUN node --version -# RUN npm --version - -RUN apt-get install -y --no-install-recommends \ - libqt5sql5-mysql \ - libqt5websockets5 \ - libqt5websockets5-dev \ - qtchooser - -# prepare cache for build -RUN mkdir /root/node_modules_cache -COPY web-user/package.json /root/node_modules_cache -COPY web-user/package-lock.json /root/node_modules_cache -COPY web-user/package-lock.json /root/node_modules_cache -WORKDIR /root/node_modules_cache -RUN npm install diff --git a/Dockerfile.release-environment b/Dockerfile.release-environment deleted file mode 100644 index dafd16fe0..000000000 --- a/Dockerfile.release-environment +++ /dev/null @@ -1,30 +0,0 @@ -FROM debian:11 - -LABEL "maintainer"="Evgenii Sopov " -LABEL "repository"="https://github.com/freehackquest/fhq-server" - -RUN apt-get update && \ - apt-get install -y \ - libcurl4 \ - zlib1g \ - libpng16-16 \ - libmariadb3 \ - libpthread-stubs0-dev \ - locales - -# RUN locale-gen en_US.UTF-8 -RUN sed -i -e "s/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/" /etc/locale.gen && \ - echo 'LANG="en_US.UTF-8"'>/etc/default/locale && \ - dpkg-reconfigure --frontend=noninteractive locales && \ - update-locale LANG=en_US.UTF-8 -# RUN update-locale LANG=en_US.UTF-8 - -RUN apt-get install -y \ - libqt5sql5-mysql \ - libqt5websockets5 \ - libqt5core5a \ - libqt5concurrent5 - -# RUN apt-get install -y qt5-default qtchooser \ - -RUN apt-get clean \ No newline at end of file diff --git a/LICENSE b/LICENSE index 616260695..20a3c3b55 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2011-2023 FreeHackQuest +Copyright (c) 2011-2025 FreeHackQuest Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 80a7c1265..26c6dfd66 100644 --- a/README.md +++ b/README.md @@ -121,16 +121,19 @@ $ sudo apt install git-core g++ make cmake qtchooser qt5-default \ libqt5websockets5 libqt5websockets5-dev libqt5sql5-mysql \ libwebsockets-dev libcurl4-openssl-dev \ zlib1g zlib1g-dev \ + python3 python3-pip python3-glob2 python3-pycodestyle \ libpng-dev \ libmysqlclient-dev \ mysql-server mysql-client \ build-essential curl ``` +*qt5-default - no exists on Ubuntu 24.04* + Install latest nodejs (for web-user) ``` -$ curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash - +$ curl -sL https://deb.nodesource.com/setup_22.x | sudo -E bash - $ sudo apt-get install nodejs ``` @@ -138,7 +141,7 @@ Configure database: Run mysql console: ``` -$ mysql -h localhost -u root -p +$ sudo mysql -h localhost -u root ``` Execute next queries for create empty database: @@ -313,7 +316,7 @@ If you wanna fresh enviroment $ ./rebuild_environment_images.sh ``` -Rebuild fresh docker +Rebuild fresh docker ``` $ docker build -t sea5kg/fhq-server:latest . $ docker tag sea5kg/fhq-server:latest sea5kg/fhq-server:v0.2.xx diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index ee69cdd42..000000000 --- a/SECURITY.md +++ /dev/null @@ -1,3 +0,0 @@ -# Security Policy - - diff --git a/_config.yml b/_config.yml deleted file mode 100644 index c74188174..000000000 --- a/_config.yml +++ /dev/null @@ -1 +0,0 @@ -theme: jekyll-theme-slate \ No newline at end of file diff --git a/build_simple.sh b/build_simple.sh index 2ad978243..47da298cb 100755 --- a/build_simple.sh +++ b/build_simple.sh @@ -1,9 +1,26 @@ #!/bin/bash -if [ ! -d tmp ]; then - mkdir -p tmp +check_ret() { + if [ $1 -ne 0 ]; then + echo "" + echo "!!! FAIL: $2" + echo "********************************************************************************" + echo "" + exit $1 + else + echo "" + echo "*** SUCCESS: $2" + echo "********************************************************************************" + echo "" + fi +} + +if [ ! -d ./tmp/release ]; then + mkdir -p ./tmp/release fi -cd tmp -cmake .. -make +cmake -H. -B./tmp/release -DCMAKE_BUILD_TYPE=Release +check_ret $? "configure" + +cmake --build ./tmp/release --config Release +check_ret $? "build" diff --git a/ci/travis/data/config.yml b/ci/travis/data/config.yml index 8f0076f5a..0f2f36aa5 100644 --- a/ci/travis/data/config.yml +++ b/ci/travis/data/config.yml @@ -24,7 +24,7 @@ web_admin_folder: ../../../web-admin web_user_folder: ../../../web-user/dist web_public_folder: ./public/ -web_public_folrer_url: http://localhost:7080/public/ +web_public_folder_url: http://localhost:7080/public/ # Jobs Pool Config jobs_fast_threads: 2 diff --git a/ci/travis/data/file_storage/games/9526c9a6-dd03-4771-9238-dfebada97228/game.json b/ci/travis/data/file_storage/games/9526c9a6-dd03-4771-9238-dfebada97228/game.json index 0e62ef312..9e9fcb15f 100644 --- a/ci/travis/data/file_storage/games/9526c9a6-dd03-4771-9238-dfebada97228/game.json +++ b/ci/travis/data/file_storage/games/9526c9a6-dd03-4771-9238-dfebada97228/game.json @@ -1,5 +1,5 @@ { - "format": 1, + "freehackquest_game_format_version": 1, "uuid": "9526c9a6-dd03-4771-9238-dfebada97228", "date_start": "2015-04-18 03:49:10", "date_stop": "2015-04-19 03:49:10", diff --git a/ci/travis/data/file_storage/quests/db335743-5d78-4c51-a4d7-5f9809d88e8f/quest.json b/ci/travis/data/file_storage/quests/db335743-5d78-4c51-a4d7-5f9809d88e8f/quest.json index 3b91b93ea..565917338 100644 --- a/ci/travis/data/file_storage/quests/db335743-5d78-4c51-a4d7-5f9809d88e8f/quest.json +++ b/ci/travis/data/file_storage/quests/db335743-5d78-4c51-a4d7-5f9809d88e8f/quest.json @@ -1,5 +1,5 @@ { - "format": 1, + "format_version": 1, "uuid": "db335743-5d78-4c51-a4d7-5f9809d88e8f", "score": "100", "min_score": "50", diff --git a/ci/travis/data/public/games/18.png b/ci/travis/data/public/games/18.png new file mode 100644 index 000000000..4e696b379 Binary files /dev/null and b/ci/travis/data/public/games/18.png differ diff --git a/ci/travis/run1_language_cpp.sh b/ci/travis/run1_language_cpp.sh index db8fd4e21..6169f61fc 100755 --- a/ci/travis/run1_language_cpp.sh +++ b/ci/travis/run1_language_cpp.sh @@ -13,15 +13,10 @@ check_ret() { echo "********************************************************************************" echo "" fi -} +} -cd tests/code-check -check_ret $? "change directory to code-check" -./build_simple.sh -check_ret $? "build code-check" -./code-check --show-only-errors ../.. +./pm.py code-check check_ret $? "code-check" -cd ../.. cd unit-tests.wsjcpp check_ret $? "change directory to unit-tests.wsjcpp" diff --git a/clean.sh b/clean.sh deleted file mode 100755 index b870ceac3..000000000 --- a/clean.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -rm -f Makefile -rm -rf build -rm -rf tmp -rm -f fhq-server -rm -f .qmake.stash -rm -f fhq-server.pro.user -rm -f CMakeLists.txt.user -rm -f debian/files - diff --git a/cmake/FindPostgreSQL.cmake b/cmake/FindPostgreSQL.cmake deleted file mode 100644 index 3e71f7dbe..000000000 --- a/cmake/FindPostgreSQL.cmake +++ /dev/null @@ -1,229 +0,0 @@ -# Distributed under the OSI-approved BSD 3-Clause License. See accompanying -# file Copyright.txt or https://cmake.org/licensing for details. - -#[=======================================================================[.rst: -FindPostgreSQL --------------- - -Find the PostgreSQL installation. - -IMPORTED Targets -^^^^^^^^^^^^^^^^ - -This module defines :prop_tgt:`IMPORTED` target ``PostgreSQL::PostgreSQL`` -if PostgreSQL has been found. - -Result Variables -^^^^^^^^^^^^^^^^ - -This module will set the following variables in your project: - -``PostgreSQL_FOUND`` - True if PostgreSQL is found. -``PostgreSQL_LIBRARIES`` - the PostgreSQL libraries needed for linking -``PostgreSQL_INCLUDE_DIRS`` - the directories of the PostgreSQL headers -``PostgreSQL_LIBRARY_DIRS`` - the link directories for PostgreSQL libraries -``PostgreSQL_VERSION_STRING`` - the version of PostgreSQL found -#]=======================================================================] - -# ---------------------------------------------------------------------------- -# History: -# This module is derived from the module originally found in the VTK source tree. -# -# ---------------------------------------------------------------------------- -# Note: -# PostgreSQL_ADDITIONAL_VERSIONS is a variable that can be used to set the -# version number of the implementation of PostgreSQL. -# In Windows the default installation of PostgreSQL uses that as part of the path. -# E.g C:\Program Files\PostgreSQL\8.4. -# Currently, the following version numbers are known to this module: -# "11" "10" "9.6" "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0" -# -# To use this variable just do something like this: -# set(PostgreSQL_ADDITIONAL_VERSIONS "9.2" "8.4.4") -# before calling find_package(PostgreSQL) in your CMakeLists.txt file. -# This will mean that the versions you set here will be found first in the order -# specified before the default ones are searched. -# -# ---------------------------------------------------------------------------- -# You may need to manually set: -# PostgreSQL_INCLUDE_DIR - the path to where the PostgreSQL include files are. -# PostgreSQL_LIBRARY_DIR - The path to where the PostgreSQL library files are. -# If FindPostgreSQL.cmake cannot find the include files or the library files. -# -# ---------------------------------------------------------------------------- -# The following variables are set if PostgreSQL is found: -# PostgreSQL_FOUND - Set to true when PostgreSQL is found. -# PostgreSQL_INCLUDE_DIRS - Include directories for PostgreSQL -# PostgreSQL_LIBRARY_DIRS - Link directories for PostgreSQL libraries -# PostgreSQL_LIBRARIES - The PostgreSQL libraries. -# -# The ``PostgreSQL::PostgreSQL`` imported target is also created. -# -# ---------------------------------------------------------------------------- -# If you have installed PostgreSQL in a non-standard location. -# (Please note that in the following comments, it is assumed that -# points to the root directory of the include directory of PostgreSQL.) -# Then you have three options. -# 1) After CMake runs, set PostgreSQL_INCLUDE_DIR to /include and -# PostgreSQL_LIBRARY_DIR to wherever the library pq (or libpq in windows) is -# 2) Use CMAKE_INCLUDE_PATH to set a path to /PostgreSQL<-version>. This will allow find_path() -# to locate PostgreSQL_INCLUDE_DIR by utilizing the PATH_SUFFIXES option. e.g. In your CMakeLists.txt file -# set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "/include") -# 3) Set an environment variable called ${PostgreSQL_ROOT} that points to the root of where you have -# installed PostgreSQL, e.g. . -# -# ---------------------------------------------------------------------------- - -set(PostgreSQL_INCLUDE_PATH_DESCRIPTION "top-level directory containing the PostgreSQL include directories. E.g /usr/local/include/PostgreSQL/8.4 or C:/Program Files/PostgreSQL/8.4/include") -set(PostgreSQL_INCLUDE_DIR_MESSAGE "Set the PostgreSQL_INCLUDE_DIR cmake cache entry to the ${PostgreSQL_INCLUDE_PATH_DESCRIPTION}") -set(PostgreSQL_LIBRARY_PATH_DESCRIPTION "top-level directory containing the PostgreSQL libraries.") -set(PostgreSQL_LIBRARY_DIR_MESSAGE "Set the PostgreSQL_LIBRARY_DIR cmake cache entry to the ${PostgreSQL_LIBRARY_PATH_DESCRIPTION}") -set(PostgreSQL_ROOT_DIR_MESSAGE "Set the PostgreSQL_ROOT system variable to where PostgreSQL is found on the machine E.g C:/Program Files/PostgreSQL/8.4") - - -set(PostgreSQL_KNOWN_VERSIONS ${PostgreSQL_ADDITIONAL_VERSIONS} - "11" "10" "9.6" "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0") - -# Define additional search paths for root directories. -set( PostgreSQL_ROOT_DIRECTORIES - ENV PostgreSQL_ROOT - ${PostgreSQL_ROOT} -) -foreach(suffix ${PostgreSQL_KNOWN_VERSIONS}) - if(WIN32) - list(APPEND PostgreSQL_LIBRARY_ADDITIONAL_SEARCH_SUFFIXES - "PostgreSQL/${suffix}/lib") - list(APPEND PostgreSQL_INCLUDE_ADDITIONAL_SEARCH_SUFFIXES - "PostgreSQL/${suffix}/include") - list(APPEND PostgreSQL_TYPE_ADDITIONAL_SEARCH_SUFFIXES - "PostgreSQL/${suffix}/include/server") - endif() - if(UNIX) - list(APPEND PostgreSQL_LIBRARY_ADDITIONAL_SEARCH_SUFFIXES - "pgsql-${suffix}/lib") - list(APPEND PostgreSQL_INCLUDE_ADDITIONAL_SEARCH_SUFFIXES - "pgsql-${suffix}/include") - list(APPEND PostgreSQL_TYPE_ADDITIONAL_SEARCH_SUFFIXES - "postgresql/${suffix}/server" - "pgsql-${suffix}/include/server") - endif() -endforeach() - -# -# Look for an installation. -# -find_path(PostgreSQL_INCLUDE_DIR - NAMES libpq-fe.h - PATHS - # Look in other places. - ${PostgreSQL_ROOT_DIRECTORIES} - PATH_SUFFIXES - pgsql - postgresql - include - ${PostgreSQL_INCLUDE_ADDITIONAL_SEARCH_SUFFIXES} - # Help the user find it if we cannot. - DOC "The ${PostgreSQL_INCLUDE_DIR_MESSAGE}" -) - -find_path(PostgreSQL_TYPE_INCLUDE_DIR - NAMES catalog/pg_type.h - PATHS - # Look in other places. - ${PostgreSQL_ROOT_DIRECTORIES} - PATH_SUFFIXES - postgresql - pgsql/server - postgresql/server - include/server - ${PostgreSQL_TYPE_ADDITIONAL_SEARCH_SUFFIXES} - # Help the user find it if we cannot. - DOC "The ${PostgreSQL_INCLUDE_DIR_MESSAGE}" -) - -# The PostgreSQL library. -set (PostgreSQL_LIBRARY_TO_FIND pq) -# Setting some more prefixes for the library -set (PostgreSQL_LIB_PREFIX "") -if ( WIN32 ) - set (PostgreSQL_LIB_PREFIX ${PostgreSQL_LIB_PREFIX} "lib") - set (PostgreSQL_LIBRARY_TO_FIND ${PostgreSQL_LIB_PREFIX}${PostgreSQL_LIBRARY_TO_FIND}) -endif() - -find_library(PostgreSQL_LIBRARY - NAMES ${PostgreSQL_LIBRARY_TO_FIND} - PATHS - ${PostgreSQL_ROOT_DIRECTORIES} - PATH_SUFFIXES - lib - ${PostgreSQL_LIBRARY_ADDITIONAL_SEARCH_SUFFIXES} - # Help the user find it if we cannot. - DOC "The ${PostgreSQL_LIBRARY_DIR_MESSAGE}" -) -get_filename_component(PostgreSQL_LIBRARY_DIR ${PostgreSQL_LIBRARY} PATH) - -if (PostgreSQL_INCLUDE_DIR) - # Some platforms include multiple pg_config.hs for multi-lib configurations - # This is a temporary workaround. A better solution would be to compile - # a dummy c file and extract the value of the symbol. - file(GLOB _PG_CONFIG_HEADERS "${PostgreSQL_INCLUDE_DIR}/pg_config*.h") - foreach(_PG_CONFIG_HEADER ${_PG_CONFIG_HEADERS}) - if(EXISTS "${_PG_CONFIG_HEADER}") - file(STRINGS "${_PG_CONFIG_HEADER}" pgsql_version_str - REGEX "^#define[\t ]+PG_VERSION_NUM[\t ]+.*") - if(pgsql_version_str) - string(REGEX REPLACE "^#define[\t ]+PG_VERSION_NUM[\t ]+([0-9]*).*" - "\\1" _PostgreSQL_VERSION_NUM "${pgsql_version_str}") - break() - endif() - endif() - endforeach() - if (_PostgreSQL_VERSION_NUM) - math(EXPR _PostgreSQL_major_version "${_PostgreSQL_VERSION_NUM} / 10000") - math(EXPR _PostgreSQL_minor_version "${_PostgreSQL_VERSION_NUM} % 10000") - set(PostgreSQL_VERSION_STRING "${_PostgreSQL_major_version}.${_PostgreSQL_minor_version}") - unset(_PostgreSQL_major_version) - unset(_PostgreSQL_minor_version) - else () - foreach(_PG_CONFIG_HEADER ${_PG_CONFIG_HEADERS}) - if(EXISTS "${_PG_CONFIG_HEADER}") - file(STRINGS "${_PG_CONFIG_HEADER}" pgsql_version_str - REGEX "^#define[\t ]+PG_VERSION[\t ]+\".*\"") - if(pgsql_version_str) - string(REGEX REPLACE "^#define[\t ]+PG_VERSION[\t ]+\"([^\"]*)\".*" - "\\1" PostgreSQL_VERSION_STRING "${pgsql_version_str}") - break() - endif() - endif() - endforeach() - endif () - unset(_PostgreSQL_VERSION_NUM) - unset(pgsql_version_str) -endif() - -# Did we find anything? -include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) -find_package_handle_standard_args(PostgreSQL - REQUIRED_VARS PostgreSQL_LIBRARY PostgreSQL_INCLUDE_DIR PostgreSQL_TYPE_INCLUDE_DIR - VERSION_VAR PostgreSQL_VERSION_STRING) -set(PostgreSQL_FOUND ${POSTGRESQL_FOUND}) - -# Now try to get the include and library path. -if(PostgreSQL_FOUND) - if (NOT TARGET PostgreSQL::PostgreSQL) - add_library(PostgreSQL::PostgreSQL UNKNOWN IMPORTED) - set_target_properties(PostgreSQL::PostgreSQL PROPERTIES - IMPORTED_LOCATION "${PostgreSQL_LIBRARY}" - INTERFACE_INCLUDE_DIRECTORIES "${PostgreSQL_INCLUDE_DIR};${PostgreSQL_TYPE_INCLUDE_DIR}") - endif () - set(PostgreSQL_INCLUDE_DIRS ${PostgreSQL_INCLUDE_DIR} ${PostgreSQL_TYPE_INCLUDE_DIR} ) - set(PostgreSQL_LIBRARY_DIRS ${PostgreSQL_LIBRARY_DIR} ) - set(PostgreSQL_LIBRARIES ${PostgreSQL_LIBRARY}) -endif() - -mark_as_advanced(PostgreSQL_INCLUDE_DIR PostgreSQL_TYPE_INCLUDE_DIR PostgreSQL_LIBRARY ) \ No newline at end of file diff --git a/contrib/code_stats/stats.sh b/contrib/code_stats/stats.sh deleted file mode 100755 index 1884f9800..000000000 --- a/contrib/code_stats/stats.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash - -function calculateLinesInFiles() { - LINES=0 - LINES_CPP=$((find $1 -name "*.cpp" -print0 | xargs -0 cat ) | wc -l) - LINES=$(( $LINES + $LINES_CPP)) - LINES_H=$((find $1 -name "*.h" -print0 | xargs -0 cat ) | wc -l) - LINES=$(( $LINES + $LINES_H)) - LINES_HPP=$((find $1 -name "*.hpp" -print0 | xargs -0 cat ) | wc -l) - LINES=$(( $LINES + $LINES_HPP)) - LINES_C=$((find $1 -name "*.c" -print0 | xargs -0 cat ) | wc -l) - LINES=$(( $LINES + $LINES_C)) - LINES_CC=$((find $1 -name "*.cc" -print0 | xargs -0 cat ) | wc -l) - LINES=$(( $LINES + $LINES_CC)) - echo $LINES -} - -LINES_SRC=$(calculateLinesInFiles "../../src") -LINES_SRC_3RDPARTY=$(calculateLinesInFiles "../../src/3rdParty") -LINES_WSJCPP=$(calculateLinesInFiles "../../src.wsjcpp") - -echo "Lines in src: $LINES_SRC" -echo "Lines in src/3rdParty: $LINES_SRC_3RDPARTY" -echo "Lines in src.wsjcpp: $LINES_WSJCPP" - -LINES_FHQ_SERVER=$(($LINES_SRC - $LINES_SRC_3RDPARTY)) -echo "Lines in development files for fhq-server: $LINES_FHQ_SERVER" diff --git a/docker_dev/Dockerfile.dev b/docker_dev/Dockerfile.dev index 3f85cd502..108a28e4d 100644 --- a/docker_dev/Dockerfile.dev +++ b/docker_dev/Dockerfile.dev @@ -1,4 +1,4 @@ -FROM debian:buster-20220328 +FROM debian:10.13 LABEL "maintainer"="FreeHackQuest Team " LABEL "repository"="https://github.com/freehackquest/fhq-server" diff --git a/libfhqpm/__init__.py b/libfhqpm/__init__.py index 414e28ab1..231e9bd95 100644 --- a/libfhqpm/__init__.py +++ b/libfhqpm/__init__.py @@ -1,6 +1,47 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# Copyright (c) 2020-2023 FreeHackQuest Team +################################################################################## +# __ _ +# / _| |__ __ _ ___ ___ _ ____ _____ _ __ +# | |_| '_ \ / _` | ___ / __|/ _ \ '__\ \ / / _ \ '__| +# | _| | | | (_| ||___|\__ \ __/ | \ V / __/ | +# |_| |_| |_|\__, | |___/\___|_| \_/ \___|_| +# |_| +# +# Copyright (c) 2011-2025 FreeHackQuest +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +################################################################################## -from .commands_helper import CommandsHelper -from .create_storage_update import CreateStorageUpdate +""" init module for libfhqpm (Project Manager) helper lib for a handling processes in project """ + +from .pm_config import PmConfig +from .command_rebuild_environment_images import CommandRebuildEnvironmentImages +from .command_clang_format import CommandClangFormat +from .command_clean import CommandClean +from .command_code_check import CommandCodeCheck +from .command_code_stats import CommandCodeStats +from .command_create_storage_update import CommandCreateStorageUpdate +from .command_generate_models import CommandGenerateModels +from .command_py_check import CommandPyCheck +from .utils_copyrights import UtilsCopyrights +from .utils_log import UtilsLog +from .utils_files import UtilsFiles +from .utils_shell import UtilsShell +from .utils_strings import UtilsStrings diff --git a/libfhqpm/command_clang_format.py b/libfhqpm/command_clang_format.py new file mode 100644 index 000000000..a86802795 --- /dev/null +++ b/libfhqpm/command_clang_format.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +################################################################################## +# __ _ +# / _| |__ __ _ ___ ___ _ ____ _____ _ __ +# | |_| '_ \ / _` | ___ / __|/ _ \ '__\ \ / / _ \ '__| +# | _| | | | (_| ||___|\__ \ __/ | \ V / __/ | +# |_| |_| |_|\__, | |___/\___|_| \_/ \___|_| +# |_| +# +# Copyright (c) 2011-2025 FreeHackQuest +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +################################################################################## + +""" Command for format c++ code by clang-format """ + +import os +import sys +import logging +from .utils_files import UtilsFiles +from .pm_config import PmConfig +from .utils_shell import UtilsShell + +logging.basicConfig() + + +class CommandClangFormat: + """ CommandClangFormat """ + def __init__(self, config: PmConfig): + self.__log = logging.getLogger("CommandClangFormat") + self.__log.setLevel(logging.DEBUG) + self.__config = config + self.__subcomamnd_name = "clang-format" + + def get_name(self): + """ return subcommand name """ + return self.__subcomamnd_name + + def do_registry(self, subparsers): + """ registring sub command """ + _parser_clang_format = subparsers.add_parser( + name=self.__subcomamnd_name, + description='Fix cpp and h files use a clang format' + ) + _parser_clang_format.set_defaults(subparser=self.__subcomamnd_name) + + def execute(self, _): + """ executing """ + self.__log.info("Clang-format...") + root_dir = self.__config.get_root_dir() + src_dir = os.path.join(root_dir, "src") + + files = UtilsFiles.get_all_files(src_dir) + for _file in files: + if 'third-party' in _file: + continue + if _file.lower().endswith(".json"): + continue + command = ["clang-format", '-style=file', '-i', _file] + UtilsShell.run_command(command) + sys.exit(0) diff --git a/libfhqpm/command_clean.py b/libfhqpm/command_clean.py new file mode 100644 index 000000000..cea19209e --- /dev/null +++ b/libfhqpm/command_clean.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 +################################################################################## +# __ _ +# / _| |__ __ _ ___ ___ _ ____ _____ _ __ +# | |_| '_ \ / _` | ___ / __|/ _ \ '__\ \ / / _ \ '__| +# | _| | | | (_| ||___|\__ \ __/ | \ V / __/ | +# |_| |_| |_|\__, | |___/\___|_| \_/ \___|_| +# |_| +# +# Copyright (c) 2011-2025 FreeHackQuest +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +################################################################################## + +""" subcommand clean removed temporary files """ + +import sys +import os +from .utils_files import UtilsFiles +from .utils_log import UtilsLog +from .pm_config import PmConfig + + +class CommandClean: + """ CommandClean """ + def __init__(self, config: PmConfig): + self.__log = UtilsLog("CommandClean").get_logger() + self.__config = config + self.__subcomamnd_name = "clean" + + def get_name(self): + """ return subcommand name """ + return self.__subcomamnd_name + + def do_registry(self, subparsers): + """ registring sub command """ + _parser_clean = subparsers.add_parser( + name=self.__subcomamnd_name, + description='Clean temporary build files' + ) + _parser_clean.set_defaults(subparser=self.__subcomamnd_name) + + def execute(self, _): + """ executing """ + self.__log.info("Cleaning...") + dir_or_files_to_remove = [ + "Makefile", + "build", + "Makefile", + "build", + "Dockerfile.build-environment", + "Dockerfile.release-environment", + "tmp", + "fhq-server", + ".qmake.stash", + "fhq-server.pro.user", + "CMakeLists.txt.user", + "debian/files", + ] + root_dir = self.__config.get_root_dir() + for _path in dir_or_files_to_remove: + _fullpath = os.path.join(root_dir, _path) + self.__log.info("Removing %s", _fullpath) + if os.path.isfile(_fullpath): + self.__log.info("Removing file %s", _fullpath) + os.remove(_fullpath) + elif os.path.isdir(_fullpath): + self.__log.info("Removing dir %s", _fullpath) + UtilsFiles.recoursive_remove_files(_fullpath) + else: + self.__log.info("Not found") + sys.exit(0) diff --git a/libfhqpm/command_code_check.py b/libfhqpm/command_code_check.py new file mode 100644 index 000000000..d5683649f --- /dev/null +++ b/libfhqpm/command_code_check.py @@ -0,0 +1,214 @@ +#!/usr/bin/env python3 +################################################################################## +# __ _ +# / _| |__ __ _ ___ ___ _ ____ _____ _ __ +# | |_| '_ \ / _` | ___ / __|/ _ \ '__\ \ / / _ \ '__| +# | _| | | | (_| ||___|\__ \ __/ | \ V / __/ | +# |_| |_| |_|\__, | |___/\___|_| \_/ \___|_| +# |_| +# +# Copyright (c) 2011-2025 FreeHackQuest +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +################################################################################## + +""" code c++ check """ + +import os +import re +import logging + +from .utils_files import UtilsFiles +from .pm_config import PmConfig + +logging.basicConfig() + + +class CommandCodeCheck: + """ Code check - scan code problems""" + + def __init__(self, config: PmConfig): + self.__log = logging.getLogger("CommandCodeCheck") + self.__log.setLevel(logging.DEBUG) + self.__config = config + self.__subcomamnd_name = "code-check" + self.__result = { + "tabs": [], + "todo": [], + "if-format": [], + "for-format": [], + "while-format": [], + "end-brackets": [], + "start-bracket-else": [], + "end-bracket-else": [], + "auto": [], + } + self.__processed_files = 0 + self.__processed_lines = 0 + self.__ignore_dirs = [ + '/third-party/', + '/tmp/', + '/logs/', + ] + + def get_name(self): + """ return subcommand name """ + return self.__subcomamnd_name + + def do_registry(self, subparsers): + """ registring sub command """ + _parser_code_check = subparsers.add_parser( + name=self.__subcomamnd_name, + description='Check c++ files format' + ) + _parser_code_check.set_defaults(subparser=self.__subcomamnd_name) + + def __is_ignore_path(self, _filepath): + """ ignore path or extension """ + for _dir in self.__ignore_dirs: + if _dir in _filepath: + return True + if _filepath.endswith("unit-tests"): + return True + if _filepath.endswith(".png") or _filepath.endswith(".sh"): + return True + if _filepath.endswith("CMakeLists.txt") or _filepath.endswith("CMakeLists.user-custom.txt"): + return True + return False + + def __check_tabs(self, _line, _filepath, _line_number): + if '\t' in _line: + error_msg = "ERROR: Found tab in " + _filepath + ":" + str(_line_number) + self.__log.error(error_msg) + self.__result["tabs"].append(error_msg) + + def __check_todo(self, _line, _filepath, _line_number): + if 'TODO' in _line: + error_msg = "WARNING: Found TODO in " + _filepath + ":" + str(_line_number) + # self.__log.error(error_msg) + self.__result["todo"].append(error_msg) + + def __check_if_format(self, _line, _filepath, _line_number): + _pattern = r'.*[ ]+if[ ]*\(.*' + if re.match(_pattern, _line) and 'if (' not in _line: + error_msg = "ERROR: Found wrong if-format (expected 'if (...)' )" + error_msg += "in " + _filepath + ":" + str(_line_number) + self.__log.error(error_msg) + self.__result["if-format"].append(error_msg) + + def __check_for_format(self, _line, _filepath, _line_number): + _pattern = r'.*[ ]+for[ ]*\(.*' + if re.match(_pattern, _line) and 'for (' not in _line: + error_msg = "ERROR: Found wrong for-format (expected 'for (...)' )" + error_msg += " in " + _filepath + ":" + str(_line_number) + self.__log.error(error_msg) + self.__result["for-format"].append(error_msg) + + def __check_while_format(self, _line, _filepath, _line_number): + _pattern = r'.*[ ]+while[ ]*\(.*' + if re.match(_pattern, _line) and 'while (' not in _line: + error_msg = "ERROR: Found wrong while-format (expected 'while (...)' )" + error_msg += " in " + _filepath + ":" + str(_line_number) + self.__log.error(error_msg) + self.__result["while-format"].append(error_msg) + + def __check_end_brackets(self, _line, _filepath, _line_number): + _pattern = r'.*\)[ ]*\{.*' + if re.match(_pattern, _line) and ') {' not in _line: + error_msg = "ERROR: Found wrong end-brackets (expected '...) {...' )" + error_msg += " in " + _filepath + ":" + str(_line_number) + self.__log.error(error_msg) + self.__result["end-brackets"].append(error_msg) + + def __check_start_bracket_else(self, _line, _filepath, _line_number): + _pattern = r'.*\}[ ]*else.*' + if re.match(_pattern, _line) and '} else' not in _line: + error_msg = "ERROR: Found wrong start-bracket-else (expected '...} else...' )" + error_msg += " in " + _filepath + ":" + str(_line_number) + self.__log.error(error_msg) + self.__result["start-bracket-else"].append(error_msg) + + def __check_end_bracket_else(self, _line, _filepath, _line_number): + _pattern = r'.*else[ ]*\{.*' + if re.match(_pattern, _line) and 'else {' not in _line: + error_msg = "ERROR: Found wrong end-bracket-else (expected '...else {...' )" + error_msg += " in " + _filepath + ":" + str(_line_number) + self.__log.error(error_msg) + self.__result["end-bracket-else"].append(error_msg) + + def __check_auto(self, _line, _filepath, _line_number): + + _pattern = r'.*[^\w]+auto[^\w]+.*' + if re.match(_pattern, _line): + if ' = new ' in _line: # skip if used new constructor + return + if ' = findWsjcppEmploy<' in _line: # skip if used findWsjcppEmploy + return + error_msg = "WARNING: Found auto in " + _filepath + ":" + str(_line_number) + self.__log.error(error_msg) + self.__result["auto"].append(error_msg) + + def __print_result(self): + self.__log.info("\n ---- result ----") + self.__log.info("Processed files: %s", self.__processed_files) + self.__log.info("Processed lines: %s", self.__processed_lines) + for _stat in self.__result: + self.__log.info("%s %s %s", _stat, str(len(self.__result[_stat])), "times in code") + + def execute(self, _): + """ executing """ + self.__log.info("Start...") + _dirs = [ + os.path.join(self.__config.get_root_dir(), "src"), + os.path.join(self.__config.get_root_dir(), "unit-tests.wsjcpp"), + ] + _files = [] + for _dir in _dirs: + _files.extend(UtilsFiles.get_all_files(_dir)) + + for _filepath in _files: + if self.__is_ignore_path(_filepath): # skip + continue + if os.path.isdir(_filepath): + continue + self.__processed_files += 1 + # self.__log.info(_filepath) + with open(_filepath, "rt", encoding="utf-8") as _file: + _lines = _file.readlines() + _line_number = 0 + for _line in _lines: + _line_number += 1 + self.__processed_lines += 1 + self.__check_tabs(_line, _filepath, _line_number) + self.__check_todo(_line, _filepath, _line_number) + self.__check_if_format(_line, _filepath, _line_number) + self.__check_for_format(_line, _filepath, _line_number) + self.__check_while_format(_line, _filepath, _line_number) + self.__check_end_brackets(_line, _filepath, _line_number) + self.__check_start_bracket_else(_line, _filepath, _line_number) + self.__check_end_bracket_else(_line, _filepath, _line_number) + self.__check_auto(_line, _filepath, _line_number) + self.__print_result() + _errors = 0 + for _stat in self.__result: + for _msg in self.__result[_stat]: + if "ERROR" in _msg: + _errors += 1 + return _errors diff --git a/libfhqpm/command_code_stats.py b/libfhqpm/command_code_stats.py new file mode 100644 index 000000000..41e800b94 --- /dev/null +++ b/libfhqpm/command_code_stats.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python3 +################################################################################## +# __ _ +# / _| |__ __ _ ___ ___ _ ____ _____ _ __ +# | |_| '_ \ / _` | ___ / __|/ _ \ '__\ \ / / _ \ '__| +# | _| | | | (_| ||___|\__ \ __/ | \ V / __/ | +# |_| |_| |_|\__, | |___/\___|_| \_/ \___|_| +# |_| +# +# Copyright (c) 2011-2025 FreeHackQuest +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +################################################################################## + +""" subcommand calculate statistics by source code """ + +import os +import sys +import logging + +from .pm_config import PmConfig +from .utils_files import UtilsFiles + +logging.basicConfig() + + +class CommandCodeStats: + """ CommandCodeStats """ + def __init__(self, config: PmConfig): + self.__log = logging.getLogger("CommandCodeStats") + self.__log.setLevel(logging.DEBUG) + self.__config = config + self.__subcomamnd_name = "code-stats" + + def get_name(self): + """ return subcommand name """ + return self.__subcomamnd_name + + def do_registry(self, subparsers): + """ registring sub command """ + _parser_code_stats = subparsers.add_parser( + name=self.__subcomamnd_name, + description='Calculate statistics by source code' + ) + _parser_code_stats.set_defaults(subparser=self.__subcomamnd_name) + + def execute(self, _): + """ executing """ + self.__log.info("Start...") + root_dir = self.__config.get_root_dir() + src_dir = os.path.join(root_dir, "src") + src_wsjcpp_dir = os.path.join(root_dir, "src.wsjcpp") + src_resources_dir = os.path.join(root_dir, "src-resources.wsjcpp") + + all_code_lines = 0 + fhq_code_lines = 0 + thirdparty_code_lines = 0 + wsjcpp_code_lines = 0 + + files = UtilsFiles.get_all_files(src_dir) + for filepath in files: + _fp = filepath.lower() + is_header = _fp.endswith(".h") or _fp.endswith(".hpp") + is_source_code = _fp.endswith(".cpp") or _fp.endswith(".c") or _fp.endswith(".cc") + if is_source_code or is_header: + lines = UtilsFiles.safe_read_file(filepath) + all_code_lines += len(lines) + if "third-party" not in _fp: + fhq_code_lines += len(lines) + else: + thirdparty_code_lines += len(lines) + + files = UtilsFiles.get_all_files(src_resources_dir) + for filepath in files: + lines = UtilsFiles.safe_read_file(filepath) + all_code_lines += len(lines) + fhq_code_lines += len(lines) + + files = UtilsFiles.get_all_files(src_wsjcpp_dir) + for filepath in files: + lines = UtilsFiles.safe_read_file(filepath) + is_header = _fp.endswith(".h") or _fp.endswith(".hpp") + is_source_code = _fp.endswith(".cpp") or _fp.endswith(".c") or _fp.endswith(".cc") + if is_source_code or is_header: + lines = UtilsFiles.safe_read_file(filepath) + all_code_lines += len(lines) + wsjcpp_code_lines += len(lines) + + self.__log.info( + "\n\n" + "fhq-server code lines: %s\n" + "wsjcpp code lines: %s\n" + "third-party code lines: %s\n" + "all code lines: %s\n", + str(fhq_code_lines), + str(wsjcpp_code_lines), + str(thirdparty_code_lines), + str(all_code_lines), + ) + + sys.exit(0) diff --git a/libfhqpm/command_create_storage_update.py b/libfhqpm/command_create_storage_update.py new file mode 100644 index 000000000..375937731 --- /dev/null +++ b/libfhqpm/command_create_storage_update.py @@ -0,0 +1,199 @@ +#!/usr/bin/env python3 +################################################################################## +# __ _ +# / _| |__ __ _ ___ ___ _ ____ _____ _ __ +# | |_| '_ \ / _` | ___ / __|/ _ \ '__\ \ / / _ \ '__| +# | _| | | | (_| ||___|\__ \ __/ | \ V / __/ | +# |_| |_| |_|\__, | |___/\___|_| \_/ \___|_| +# |_| +# +# Copyright (c) 2011-2025 FreeHackQuest +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +################################################################################## + +""" preapre update for database - deprecated """ + +import re +import os +import sys +import random +import string +import logging + +from .utils_copyrights import UtilsCopyrights +from .utils_files import UtilsFiles +from .pm_config import PmConfig + +logging.basicConfig() + + +class CommandCreateStorageUpdate: + """ CommandCreateStorageUpdate """ + + def __init__(self, config: PmConfig): + self.__log = logging.getLogger("CommandCodeCheck") + self.__log.setLevel(logging.DEBUG) + self.__config = config + self.__subcomamnd_name = "create-storage-update" + self.__updates = [] + self.__end_points = [] + self.__max_weight = 0 + + def get_name(self): + """ return subcommand name """ + return self.__subcomamnd_name + + def do_registry(self, subparsers): + """ registring sub command """ + _parser_create_storage_update = subparsers.add_parser( + name=self.__subcomamnd_name, + description='DEPRECATED: Create storage update (for change struct of database)' + ) + _parser_create_storage_update.set_defaults(subparser=self.__subcomamnd_name) + + def __recoursive_search_endpoints(self, spoint, weight): + found = False + for _item in self.__updates: + if _item["from"] == spoint: + found = True + self.__recoursive_search_endpoints(_item["to"], weight + 1) + if not found: + if weight > self.__max_weight: + self.__max_weight = weight + self.__end_points.append({ + "point": spoint, + "weight": weight + }) + + def __get_cpp_files_with_updates(self, updates_dir): + files = UtilsFiles.get_all_files(updates_dir) + _cpp_files = [] + for filepath in files: + if filepath.lower().endswith(".cpp"): + _cpp_files.append(filepath) + self.__log.info("Found updates: %s", str(len(_cpp_files))) + return _cpp_files + + def __find_new_points(self, updates_dir): + + self.__max_weight = 0 + self.__updates = [] + self.__end_points = [] + + _cpp_files = self.__get_cpp_files_with_updates(updates_dir) + + pattern = r'.*WsjcppStorageUpdateBase.*\(.*"([a-zA-Z0-9]*)".*,.*"([a-zA-Z0-9]*)".*,.*\).*' + + for filepath in _cpp_files: + # print(filepath) + with open(filepath) as _file: + line = _file.readline() + while line: + line = line.strip() + if re.match(pattern, line): + versions = re.search(pattern, line, re.IGNORECASE) + if versions: + self.__updates.append({ + "from": versions.group(1), + "to": versions.group(2), + }) + line = _file.readline() + + # print(self.__updates) + # print all updates + for _item in self.__updates: + print("[" + _item["from"] + "] -> [" + _item["to"] + "]") + + # find the ends in graph + self.__recoursive_search_endpoints("", 0) + + # print(self.__end_points) + + if len(self.__end_points) == 0: + print("Not found updates") + sys.exit(-1) + + endpoint = "" + + for i in self.__end_points: + if i["weight"] == self.__max_weight and endpoint == "": + endpoint = i["point"] + elif i["weight"] == self.__max_weight and endpoint != "": + print( + "WARNING: Found points with same weights, will be used first. " + + "Ignored: " + i["point"] + ) + + self.__log.info("Found point: %s, weight: %s", endpoint, str(self.__max_weight)) + newpoint = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(10)) + return endpoint, newpoint + + def execute(self, _): + """ executing """ + self.__log.info("Creating storage update...") + + updates_dir = os.path.join(self.__config.get_root_dir(), "src", "storages", "updates") + + endpoint, newpoint = self.__find_new_points(updates_dir) + + filename_h = "update_" + endpoint + "_" + newpoint + ".h" + filename_cpp = "update_" + endpoint + "_" + newpoint + ".cpp" + + filename_h = os.path.join(updates_dir, filename_h) + filename_cpp = os.path.join(updates_dir, filename_cpp) + classname_update = "Update_" + endpoint + "_" + newpoint + + self.__log.info("Generate header file: %s", filename_h) + with open(filename_h, 'wt', encoding="utf-8", newline="\n") as f_h: + f_h.write(UtilsCopyrights.get_cpp_copyright()) + f_h.write("\n") + f_h.write("#pragma once\n") + f_h.write("\n") + f_h.write("#include \n") + f_h.write("\n") + f_h.write( + "class " + classname_update + " : public WsjcppStorageUpdateBase {\n" + + " public:\n" + + " " + classname_update + "();\n" + + "};\n" + ) + f_h.write("\n") + + self.__log.info("Generate source file: %s", filename_cpp) + + with open(filename_cpp, "wt", encoding="utf-8", newline="\n") as f_cpp: + f_cpp.write(UtilsCopyrights.get_cpp_copyright()) + f_cpp.write("\n") + f_cpp.write( + "#include \"" + classname_update.lower() + ".h\"\n" + + "\n" + + "REGISTRY_WSJCPP_STORAGE_UPDATE(" + classname_update + ")\n" + + "\n" + ) + f_cpp.write( + classname_update + "::" + classname_update + "()\n" + " : WsjcppStorageUpdateBase(\"" + endpoint + "\", \"" + + newpoint + "\", \"TODO\") {\n" + ) + f_cpp.write(" \n") + f_cpp.write(" // fill the array with struct changes\n") + f_cpp.write("}\n") + f_cpp.write("\n") diff --git a/libfhqpm/command_generate_models.py b/libfhqpm/command_generate_models.py new file mode 100644 index 000000000..ab6c8f11d --- /dev/null +++ b/libfhqpm/command_generate_models.py @@ -0,0 +1,247 @@ +#!/usr/bin/env python3 +################################################################################## +# __ _ +# / _| |__ __ _ ___ ___ _ ____ _____ _ __ +# | |_| '_ \ / _` | ___ / __|/ _ \ '__\ \ / / _ \ '__| +# | _| | | | (_| ||___|\__ \ __/ | \ V / __/ | +# |_| |_| |_|\__, | |___/\___|_| \_/ \___|_| +# |_| +# +# Copyright (c) 2011-2025 FreeHackQuest +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +################################################################################## + +""" subcommand calculate statistics by source code """ + +import os +import sys +import logging +import json + +from .pm_config import PmConfig +from .utils_copyrights import UtilsCopyrights +from .utils_strings import UtilsStrings + +logging.basicConfig() + + +class CommandGenerateModels: + """ CommandGenerateModels """ + def __init__(self, config: PmConfig): + self.__log = logging.getLogger("CommandGenerateModels") + self.__log.setLevel(logging.DEBUG) + self.__config = config + self.__subcomamnd_name = "generate-models" + + def get_name(self): + """ return subcommand name """ + return self.__subcomamnd_name + + def do_registry(self, subparsers): + """ registring sub command """ + _parser_gen_models = subparsers.add_parser( + name=self.__subcomamnd_name, + description='Generate models by src/models.json to src/models/' + ) + _parser_gen_models.set_defaults(subparser=self.__subcomamnd_name) + + def __update_file(self, filepath, content): + prev_content = "" + if os.path.isfile(filepath): + with open(filepath, "rt", encoding="utf-8", newline="\n") as _file_cpp: + _lines = _file_cpp.readlines() + prev_content = "".join(_lines) + if prev_content != content: + with open(filepath, "wt", encoding="utf-8", newline="\n") as _file_cpp: + _file_cpp.write(content) + self.__log.info("Updated file %s", filepath) + else: + self.__log.info("NO need Update file %s", filepath) + + def __generate_cpp(self, src_models_dir, modelname, model_fields): + classname = "Model" + UtilsStrings.snakecase_to_camelcase(modelname) + content_cpp = [ + UtilsCopyrights.get_cpp_copyright(), + "// automaticly generated by models.json", + "", + "#include \"model_" + modelname + ".h\"", + "", + "#include ", + "#include ", + "#include ", + "", + classname + "::" + classname + "() {", + " TAG = \"" + classname + "\";" + ] + content_cpp_methods = [] + content_cpp_copy = [] + content_cpp_tojson = [] + for fieldname in model_fields: + field = model_fields[fieldname] + varname = UtilsStrings.snakecase_to_camelcase(fieldname) + if 'varname' in field: + varname = field['varname'] + typefield = field["type"] + + content_cpp_copy.append(" this->set" + varname + "(m.get" + varname + "());") + if typefield in ("int", "long"): + content_cpp.append(" m_n" + varname + " = 0;") + content_cpp_methods.extend([ + typefield + " " + classname + "::get" + varname + "() const {" + " return m_n" + varname + "; }", + "void " + classname + "::set" + varname + "(" + typefield + " nVal) {" + " m_n" + varname + " = nVal; }", + "", + ]) + content_cpp_tojson.append(" jsonRet[\"" + fieldname + "\"] = m_n" + varname + ";") + elif typefield == "string": + content_cpp.append(" m_s" + varname + " = \"\";") + _const_str = "const std::string &sVal" + content_cpp_methods.extend([ + "const std::string &" + classname + "::get" + varname + "() const {" + " return m_s" + varname + "; }", + "void " + classname + "::set" + varname + "(const std::string &sVal) {", + " m_s" + varname + " = sVal;", + " m_s" + varname + "_lowercase = WsjcppCore::toLower(sVal);", + "}", + "bool " + classname + "::hasIn" + varname + "_lowercase(" + _const_str + ") {", + " return m_s" + varname + "_lowercase.find(sVal) != std::string::npos;", + "}", + "", + ]) + content_cpp_tojson.append(" jsonRet[\"" + fieldname + "\"] = m_s" + varname + ";") + else: + sys.exit("Unknown type '" + typefield + "'") + content_cpp.extend([ + "}", + "", + classname + "::~" + classname + "() {", + " //", + "}", + "", + ]) + content_cpp.extend(content_cpp_methods) + content_cpp.append("void " + classname + "::copy(const " + classname + " &m) {") + content_cpp.extend(content_cpp_copy) + content_cpp.extend([ + "}", + "", + classname + " *" + classname + "::clone() const {", + " " + classname + " *pModel = new " + classname + "();", + " pModel->copy(*this);", + " return pModel;", + "}", + "", + "nlohmann::json " + classname + "::toJson() {", + " nlohmann::json jsonRet;" + ]) + + content_cpp.extend(content_cpp_tojson) + content_cpp.extend([ + " return jsonRet;", + "}", + "", + ]) + filepath_cpp = os.path.join(src_models_dir, "model_" + modelname + ".cpp") + self.__update_file(filepath_cpp, "\n".join(content_cpp)) + + def __generate_h(self, src_models_dir, modelname, model_fields): + classname = "Model" + UtilsStrings.snakecase_to_camelcase(modelname) + content_h = [ + UtilsCopyrights.get_cpp_copyright(), + "// automaticly generated by models.json", + "", + "#pragma once", + "", + "#include ", + "#include ", + "#include ", + "", + "class " + classname + " {", + "public:", + " " + classname + "();", + " ~" + classname + "();", + "", + ] + content_h_private = [] + for fieldname in model_fields: + field = model_fields[fieldname] + varname = UtilsStrings.snakecase_to_camelcase(fieldname) + if 'varname' in field: + varname = field['varname'] + typefield = field["type"] + + if typefield in ("int", "long"): + content_h.extend([ + " " + typefield + " get" + varname + "() const;", + " void set" + varname + "(" + typefield + " nVal);", + "", + ]) + content_h_private.append(" " + typefield + " m_n" + varname + ";") + elif typefield == "string": + content_h.extend([ + " const std::string &get" + varname + "() const;", + " void set" + varname + "(const std::string &sVal);", + " bool hasIn" + varname + "_lowercase(const std::string &sVal);", + "", + ]) + content_h_private.extend([ + " std::string m_s" + varname + ";", + " std::string m_s" + varname + "_lowercase;", + ]) + else: + sys.exit("Unknown type '" + typefield + "'") + content_h.extend([ + " void copy(const " + classname + " &m);", + " " + classname + " *clone() const;", + " nlohmann::json toJson();", + "", + "private:", + " std::string TAG;", + ]) + content_h.extend(content_h_private) + content_h.extend([ + "};", + "", + ]) + filepath_h = os.path.join(src_models_dir, "model_" + modelname + ".h") + self.__update_file(filepath_h, "\n".join(content_h)) + + def __generate_model(self, src_models_dir, modelname, model_fields): + self.__log.info("Processing model %s ...", modelname) + self.__generate_cpp(src_models_dir, modelname, model_fields) + self.__generate_h(src_models_dir, modelname, model_fields) + + def execute(self, _): + """ executing """ + self.__log.info("Start generating models code...") + root_dir = self.__config.get_root_dir() + models_json = os.path.join(root_dir, "src", "models.json") + src_models_dir = os.path.join(root_dir, "src", "models") + + models = None + with open(models_json, 'rt', encoding="utf-8") as _file: + models = json.load(_file) + + for modelname in models: + self.__generate_model(src_models_dir, modelname, models[modelname]) + + sys.exit(0) diff --git a/libfhqpm/command_py_check.py b/libfhqpm/command_py_check.py new file mode 100644 index 000000000..c525c7935 --- /dev/null +++ b/libfhqpm/command_py_check.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +################################################################################## +# __ _ +# / _| |__ __ _ ___ ___ _ ____ _____ _ __ +# | |_| '_ \ / _` | ___ / __|/ _ \ '__\ \ / / _ \ '__| +# | _| | | | (_| ||___|\__ \ __/ | \ V / __/ | +# |_| |_| |_|\__, | |___/\___|_| \_/ \___|_| +# |_| +# +# Copyright (c) 2011-2025 FreeHackQuest +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +################################################################################## + +""" Command for linting python scripts """ + +import os +import sys +import logging + +from .pm_config import PmConfig + +logging.basicConfig() + + +class CommandPyCheck: + """ CommandPyCheck """ + def __init__(self, config: PmConfig): + self.__log = logging.getLogger("CommandPyCheck") + self.__log.setLevel(logging.DEBUG) + self.__config = config + self.__subcomamnd_name = "py-check" + + def get_name(self): + """ return subcommand name """ + return self.__subcomamnd_name + + def do_registry(self, subparsers): + """ registring sub command """ + _parser = subparsers.add_parser( + name=self.__subcomamnd_name, + description='Check python files' + ) + _parser.set_defaults(subparser=self.__subcomamnd_name) + + def execute(self, _): + """ executing """ + self.__log.info("Starting py-check...") + ret_pep8 = os.system("python3 -m pycodestyle libfhqpm --max-line-length=100") + ret_pylint = os.system("python3 -m pylint libfhqpm --max-line-length=100") + if ret_pep8 != 0 or ret_pylint != 0: + sys.exit(1) + sys.exit(0) diff --git a/libfhqpm/command_rebuild_environment_images.py b/libfhqpm/command_rebuild_environment_images.py new file mode 100644 index 000000000..59c655a8c --- /dev/null +++ b/libfhqpm/command_rebuild_environment_images.py @@ -0,0 +1,222 @@ +#!/usr/bin/env python +################################################################################## +# __ _ +# / _| |__ __ _ ___ ___ _ ____ _____ _ __ +# | |_| '_ \ / _` | ___ / __|/ _ \ '__\ \ / / _ \ '__| +# | _| | | | (_| ||___|\__ \ __/ | \ V / __/ | +# |_| |_| |_|\__, | |___/\___|_| \_/ \___|_| +# |_| +# +# Copyright (c) 2011-2025 FreeHackQuest +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +################################################################################## + +""" rebuild images """ + +import os +import sys +import logging +import datetime +from .utils_shell import UtilsShell +from .utils_log import UtilsLog +from .pm_config import PmConfig + + +class CommandRebuildEnvironmentImages: + """ CommandRebuildEnvironmentImages """ + + def __init__(self, config: PmConfig): + self.__log = UtilsLog("CommandRebuildEnvironmentImages").get_logger() + self.__log.setLevel(logging.DEBUG) + self.__config = config + now = datetime.datetime.now() + self.__dt_tag = now.strftime("%Y-%m-%d") + self.__subcomamnd_name = "rebuild-environment-images" + self.__debian_version = "12" + self.__node_version = "24" + self.__build_packages = [ + "make", + "cmake", + "gcc", + "g++", + "curl", + "pkg-config", + "libcurl4-openssl-dev", + "zlib1g-dev", + "libpng-dev", + "default-libmysqlclient-dev", + "libwebsockets-dev", + "apt-utils", + "build-essential", + "nodejs", + ] + self.__release_packages = [ + "libcurl4", + "zlib1g", + "libpng16-16", + "libmariadb3", + "libpthread-stubs0-dev", + "locales", + ] + + def get_name(self): + """ return subcommand name """ + return self.__subcomamnd_name + + def do_registry(self, subparsers): + """ registring sub command """ + descr = "Rebuild environment images" + descr += " (Dockerfile.build-environment && Dockerfile.release-environment)" + _parser_rebuild_env_images = subparsers.add_parser( + name=self.__subcomamnd_name, + description=descr + ) + _parser_rebuild_env_images.set_defaults(subparser=self.__subcomamnd_name) + + def __build_docker_image(self, tag, filename): + cmd = "docker build --rm --tag " + tag + " -f " + filename + " ." + ret = os.system(cmd) + if ret != 0: + self.__log.error("ERROR: Could not build image by command: %s", cmd) + sys.exit(1) + + def __has_image(self, fulltag): + retcode, output = UtilsShell.run_command_get_output(self.__log, [ + "docker", "images", fulltag, "--format", "{{json . }}" + ]) + if retcode != 0: + # self.__log.info("retcode: %s", retcode) + self.__log.error("Could not execute command 'docker images...', output %s", output) + sys.exit(-1) + # self.__log.info("output: %s", output) + return output != "" # output not empty... so has image + + def __update_dockerfile_build_env(self): + _filename = "Dockerfile.build-environment" + self.__log.info("Update file %s", _filename) + os.chdir(self.__config.get_root_dir()) + command_node = "curl -sL https://deb.nodesource.com/setup_" + self.__node_version + ".x" + command_node += " -o setup_node.sh && bash setup_node.sh" + + with open(_filename, "wt", encoding="utf-8", newline="\n") as _file: + _file.write("""FROM debian:""" + self.__debian_version + """ +WORKDIR /root/ + +LABEL "maintainer"="Evgenii Sopov " +LABEL "repository"="https://github.com/freehackquest/fhq-server" + +RUN apt-get update && \\ + apt-get install -y curl && \\ + apt-get clean + +RUN """ + command_node + """ + +# basic libs +RUN apt-get update && apt-get install -y --no-install-recommends \\ + """ + " \\\n ".join(self.__build_packages) + """ \\ + """ + " \\\n ".join(self.__release_packages) + """ + +# RUN node --version +# RUN npm --version + +RUN apt-get install -y --no-install-recommends \\ + libqt5sql5-mysql \\ + libqt5websockets5 \\ + libqt5websockets5-dev \\ + qtchooser + +# prepare cache for build +RUN mkdir /root/node_modules_cache +COPY web-user/package.json /root/node_modules_cache +COPY web-user/package-lock.json /root/node_modules_cache +COPY web-user/package-lock.json /root/node_modules_cache +WORKDIR /root/node_modules_cache +RUN npm install +""") + return _filename + + def __update_dockerfile_release_env(self): + _filename = "Dockerfile.release-environment" + self.__log.info("Update file %s", _filename) + os.chdir(self.__config.get_root_dir()) + with open(_filename, "wt", encoding="utf-8", newline="\n") as _file: + _file.write("""FROM debian:""" + self.__debian_version + """ + +LABEL "maintainer"="Evgenii Sopov " +LABEL "repository"="https://github.com/freehackquest/fhq-server" + +RUN apt-get update && \\ + apt-get install -y \\ + """ + " \\\n ".join(self.__release_packages) + """ + +# RUN locale-gen en_US.UTF-8 +RUN sed -i -e "s/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/" /etc/locale.gen && \\ + echo 'LANG="en_US.UTF-8"'>/etc/default/locale && \\ + dpkg-reconfigure --frontend=noninteractive locales && \\ + update-locale LANG=en_US.UTF-8 +# RUN update-locale LANG=en_US.UTF-8 + +RUN apt-get install -y \\ + libqt5sql5-mysql \\ + libqt5websockets5 \\ + libqt5core5a \\ + libqt5concurrent5 + +# RUN apt-get install -y qt5-default qtchooser \\ + +RUN apt-get clean +""") + return _filename + + def __silent_remove_image(self, image_tag): + if self.__has_image(image_tag): + self.__log.info("Found image %s, try removing...", image_tag) + ret = os.system("docker rmi " + image_tag) + if ret != 0: + self.__log.error("Could not remove %s", image_tag) + sys.exit(1) + + def execute(self, _): + """ executing """ + os.chdir(self.__config.get_root_dir()) + build_env = self.__update_dockerfile_build_env() + release_env = self.__update_dockerfile_release_env() + self.__log.info("Rebuild environment images...") + + tag_build = "sea5kg/fhq-server-build-environment" + tag_build_today = tag_build + ":" + self.__dt_tag + tag_build_latest = tag_build + ":latest" + tag_release = "sea5kg/fhq-server-release-environment" + tag_release_today = tag_release + ":" + self.__dt_tag + tag_release_latest = tag_release + ":latest" + + self.__silent_remove_image(tag_build_today) + self.__build_docker_image(tag_build_today, build_env) + + self.__silent_remove_image(tag_build_latest) + self.__build_docker_image(tag_build_latest, build_env) + + self.__silent_remove_image(tag_release_today) + self.__build_docker_image(tag_release_today, release_env) + + self.__silent_remove_image(tag_release_latest) + self.__build_docker_image(tag_release_latest, release_env) + sys.exit(0) diff --git a/libfhqpm/commands_helper.py b/libfhqpm/commands_helper.py deleted file mode 100644 index e522ccc62..000000000 --- a/libfhqpm/commands_helper.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# Copyright (C) 2011-2023, Evgenii Sopov - -""" run all tests """ - -import sys -import subprocess -import glob2 - -class CommandsHelper: - def __init__(self): - pass - - def run_command(self, _command, _output=None): - """ run_command """ - print("Run command: " + " ".join(_command)) - if _output is not None: - _output.write("Run command: " + " ".join(_command) + "\n") - with subprocess.Popen( - _command, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - shell=False - ) as _proc: - _returncode = _proc.poll() - while _returncode is None: - _returncode = _proc.poll() - _line = _proc.stdout.readline() - if _line: - _line = _line.decode("utf-8").strip() - print(_line) - if _output is not None: - _output.write(_line + "\n") - while _line: - _line = _proc.stdout.readline() - if _line: - _line = _line.decode("utf-8").strip() - print(_line) - if _output is not None: - _output.write(_line + "\n") - else: - break - if _returncode != 0: - print("ERROR: returncode " + str(_returncode)) - if _output is not None: - _output.write("ERROR: returncode " + str(_returncode) + "\n") - sys.exit(_returncode) - return - sys.exit("Could not start process") \ No newline at end of file diff --git a/libfhqpm/create_storage_update.py b/libfhqpm/create_storage_update.py deleted file mode 100644 index 4f06f8257..000000000 --- a/libfhqpm/create_storage_update.py +++ /dev/null @@ -1,171 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import re -import os -import sys -import random -import glob2 -import string - - -class CreateStorageUpdate: - def __init__(self): - self.__updates = [] - self.__end_points = [] - self.__max_weight = 0 - - def recoursive_search_endpoints(self, spoint, weight): - found = False - for v in self.__updates: - if v["from"] == spoint: - found = True - self.recoursive_search_endpoints(v["to"], weight + 1) - if not found: - if weight > self.__max_weight: - self.__max_weight = weight - self.__end_points.append({ - "point": spoint, - "weight": weight - }) - - def create(self): - self.__max_weight = 0 - self.__updates = [] - self.__end_points = [] - - updatespath = os.path.join("src", "storages", "updates") - - _cpp_files = glob2.glob( - os.path.join(updatespath, "*.cpp") - ) - - # print(_cpp_files) - - pattern = r'.*WsjcppStorageUpdateBase.*\(.*"([a-zA-Z0-9]*)".*,.*"([a-zA-Z0-9]*)".*,.*\).*' - - for filepath in _cpp_files: - # print(filepath) - with open(filepath) as f: - line = f.readline() - while line: - line = line.strip() - if re.match(pattern, line): - versions = re.search(pattern, line, re.IGNORECASE) - if versions: - self.__updates.append({ - "from": versions.group(1), - "to": versions.group(2), - }) - line = f.readline() - - # print(self.__updates) - # print all updates - for v in self.__updates: - print("[" + v["from"] + "] -> [" + v["to"] + "]") - - # find the ends in graph - self.recoursive_search_endpoints("", 0) - - # print(self.__end_points) - - if len(self.__end_points) == 0: - print("Not found updates") - sys.exit(-1) - - endpoint = "" - - for i in self.__end_points: - if i["weight"] == self.__max_weight and endpoint == "": - endpoint = i["point"] - elif i["weight"] == self.__max_weight and endpoint != "": - print("WARNING: Found points with same weights, will be used first. Ignored: " + i["point"]) - - print("Found point: " + endpoint + " weight: " + str(self.__max_weight)) - newpoint = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(10)) - - newpoint_upper = newpoint.upper() - endpoint_upper = endpoint.upper() - - filename_h = "update_" + endpoint + "_" + newpoint + ".h" - filename_cpp = "update_" + endpoint + "_" + newpoint + ".cpp" - - filename_h = os.path.join(updatespath, filename_h) - filename_cpp = os.path.join(updatespath, filename_cpp) - - print("Generate header file: " + filename_h) - - f_h = open(filename_h, 'w') - f_h.write("/*\n") - f_h.write("MIT License\n") - f_h.write("\n") - f_h.write("Copyright (c) 2011-2023 FreeHackQuest \n") - f_h.write("\n") - f_h.write("Permission is hereby granted, free of charge, to any person obtaining a copy\n") - f_h.write("of this software and associated documentation files (the \"Software\"), to deal\n") - f_h.write("in the Software without restriction, including without limitation the rights\n") - f_h.write("to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n") - f_h.write("copies of the Software, and to permit persons to whom the Software is\n") - f_h.write("furnished to do so, subject to the following conditions:\n") - f_h.write("\n") - f_h.write("The above copyright notice and this permission notice shall be included in all\n") - f_h.write("copies or substantial portions of the Software.\n") - f_h.write("\n") - f_h.write("THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n") - f_h.write("IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n") - f_h.write("FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n") - f_h.write("AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n") - f_h.write("LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n") - f_h.write("OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n") - f_h.write("SOFTWARE.\n") - f_h.write("*/\n\n") - f_h.write("#ifndef UPDATE_" + endpoint_upper + "_" + newpoint_upper + "_H\n") - f_h.write("#define UPDATE_" + endpoint_upper + "_" + newpoint_upper + "_H\n") - f_h.write("\n") - f_h.write("#include \n") - f_h.write("\n") - f_h.write("class Update_" + endpoint + "_" + newpoint + " : public WsjcppStorageUpdateBase {\n") - f_h.write(" public:\n") - f_h.write(" Update_" + endpoint + "_" + newpoint + "();\n") - f_h.write("};\n") - f_h.write("\n") - f_h.write("#endif // UPDATE_" + endpoint_upper + "_" + newpoint_upper + "_H\n") - f_h.close() - - print("Generate source file: " + filename_cpp) - - f_cpp = open(filename_cpp, 'w') - f_cpp.write("/*\n") - f_cpp.write("MIT License\n") - f_cpp.write("\n") - f_cpp.write("Copyright (c) 2011-2023 FreeHackQuest \n") - f_cpp.write("\n") - f_cpp.write("Permission is hereby granted, free of charge, to any person obtaining a copy\n") - f_cpp.write("of this software and associated documentation files (the \"Software\"), to deal\n") - f_cpp.write("in the Software without restriction, including without limitation the rights\n") - f_cpp.write("to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n") - f_cpp.write("copies of the Software, and to permit persons to whom the Software is\n") - f_cpp.write("furnished to do so, subject to the following conditions:\n") - f_cpp.write("\n") - f_cpp.write("The above copyright notice and this permission notice shall be included in all\n") - f_cpp.write("copies or substantial portions of the Software.\n") - f_cpp.write("\n") - f_cpp.write("THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n") - f_cpp.write("IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n") - f_cpp.write("FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n") - f_cpp.write("AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n") - f_cpp.write("LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n") - f_cpp.write("OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n") - f_cpp.write("SOFTWARE.\n") - f_cpp.write("*/\n\n") - f_cpp.write("#include \"update_" + endpoint + "_" + newpoint + ".h\"\n") - f_cpp.write("\n") - f_cpp.write("REGISTRY_WSJCPP_STORAGE_UPDATE(Update_" + endpoint + "_" + newpoint + ")\n") - f_cpp.write("\n") - f_cpp.write("Update_" + endpoint + "_" + newpoint + "::Update_" + endpoint + "_" + newpoint + "()\n") - f_cpp.write(" : WsjcppStorageUpdateBase(\"" + endpoint + "\", \"" + newpoint + "\", \"TODO\") {\n") - f_cpp.write(" \n") - f_cpp.write(" // fill the array with struct changes\n") - f_cpp.write("}\n") - f_cpp.write("\n") - f_cpp.close() diff --git a/libfhqpm/pm_config.py b/libfhqpm/pm_config.py new file mode 100644 index 000000000..533383826 --- /dev/null +++ b/libfhqpm/pm_config.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +################################################################################## +# __ _ +# / _| |__ __ _ ___ ___ _ ____ _____ _ __ +# | |_| '_ \ / _` | ___ / __|/ _ \ '__\ \ / / _ \ '__| +# | _| | | | (_| ||___|\__ \ __/ | \ V / __/ | +# |_| |_| |_|\__, | |___/\___|_| \_/ \___|_| +# |_| +# +# Copyright (c) 2011-2025 FreeHackQuest +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +################################################################################## + +""" Config for a pm """ +import re + + +class PmConfig: + """ PmConfig """ + + def __init__(self, root_dir): + self.__root_dir = root_dir + self.__re_uuid = re.compile( + r'.*\"([0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12})\".*' + ) + + def get_root_dir(self): + """ return root dir """ + return self.__root_dir + + def get_re_uuid(self): + """ return regular expression for a search uuid in string """ + return self.__re_uuid diff --git a/libfhqpm/utils_copyrights.py b/libfhqpm/utils_copyrights.py new file mode 100644 index 000000000..055fb9a22 --- /dev/null +++ b/libfhqpm/utils_copyrights.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 +################################################################################## +# __ _ +# / _| |__ __ _ ___ ___ _ ____ _____ _ __ +# | |_| '_ \ / _` | ___ / __|/ _ \ '__\ \ / / _ \ '__| +# | _| | | | (_| ||___|\__ \ __/ | \ V / __/ | +# |_| |_| |_|\__, | |___/\___|_| \_/ \___|_| +# |_| +# +# Copyright (c) 2011-2025 FreeHackQuest +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +################################################################################## + + +""" Utils Copyrights """ + +import datetime + + +class UtilsCopyrights: + """ UtilsCopyrights """ + + @staticmethod + def get_cpp_copyright(): + """ return c++ file header copyright text """ + now = datetime.datetime.now() + year_now = now.strftime("%Y") + + lines = """/*****************************""" + lines += """***************************************************** + * Project + * __ _ + * / _| |__ __ _ ___ ___ _ ____ _____ _ __ + * | |_| '_ \\ / _` | ___ / __|/ _ \\ '__\\ \\ / / _ \\ '__| + * | _| | | | (_| ||___|\\__ \\ __/ | \\ V / __/ | + * |_| |_| |_|\\__, | |___/\\___|_| \\_/ \\___|_| + * |_| + * + * MIT License + * + * Copyright (c) 2011-""" + year_now + """ FreeHackQuest + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + ***********************************************************************************/ +""" + return lines + + @staticmethod + def get_py_copyright(): + """ return python file header copyright text """ + now = datetime.datetime.now() + year_now = now.strftime("%Y") + + lines = """#!/usr/bin/env python3 +################################################################################## +# __ _ +# / _| |__ __ _ ___ ___ _ ____ _____ _ __ +# | |_| '_ \\ / _` | ___ / __|/ _ \\ '__\\ \\ / / _ \\ '__| +# | _| | | | (_| ||___|\\__ \\ __/ | \\ V / __/ | +# |_| |_| |_|\\__, | |___/\\___|_| \\_/ \\___|_| +# |_| +# +# Copyright (c) 2011-""" + year_now + """ FreeHackQuest +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +################################################################################## +""" + return lines diff --git a/libfhqpm/utils_files.py b/libfhqpm/utils_files.py new file mode 100644 index 000000000..9bb81c2ab --- /dev/null +++ b/libfhqpm/utils_files.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +################################################################################## +# __ _ +# / _| |__ __ _ ___ ___ _ ____ _____ _ __ +# | |_| '_ \ / _` | ___ / __|/ _ \ '__\ \ / / _ \ '__| +# | _| | | | (_| ||___|\__ \ __/ | \ V / __/ | +# |_| |_| |_|\__, | |___/\___|_| \_/ \___|_| +# |_| +# +# Copyright (c) 2011-2025 FreeHackQuest +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +################################################################################## + + +""" Utils Files """ + +import sys +import os + + +class UtilsFiles: + """ UtilsFiles """ + + @staticmethod + def get_all_files(_startdir): + """ recursive find all files in dir """ + _ret = [] + _rec = [_startdir] + while len(_rec) > 0: + _dirpath = _rec[0] + del _rec[0] + for _file in os.listdir(_dirpath): + _filepath = os.path.join(_dirpath, _file) + if os.path.isdir(_filepath): + _rec.append(_filepath) + continue + if os.path.isfile(_filepath): + _ret.append(_filepath) + return _ret + + @staticmethod + def human_readable_size(size, decimal_places=2): + """ convert bytes to humanable view """ + for unit in ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB']: + if size < 1024.0 or unit == 'PiB': + break + size /= 1024.0 + return f"{size:.{decimal_places}f} {unit}" + + @staticmethod + def safe_read_file(_filepath, exit_on_error=True): + """ __test_utf8_encoding """ + # print(_filepath) + _lines = [] + try: + with open(_filepath, "rt", encoding="utf-8") as _file: + _lines = _file.readlines() + except UnicodeDecodeError as _err: + print(_err) + if exit_on_error: + sys.exit("Problem with encoding in file: " + _filepath) + return [] + return _lines + + @staticmethod + def recoursive_remove_files(_dir): + """ recoursive_remove_files """ + for _file in os.listdir(_dir): + _fullpath = os.path.join(_dir, _file) + if os.path.isfile(_fullpath): + os.remove(_fullpath) + elif os.path.isdir(_fullpath): + UtilsFiles.recoursive_remove_files(_fullpath) + os.rmdir(_dir) diff --git a/libfhqpm/utils_log.py b/libfhqpm/utils_log.py new file mode 100644 index 000000000..9ab31d8fe --- /dev/null +++ b/libfhqpm/utils_log.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +################################################################################## +# __ _ +# / _| |__ __ _ ___ ___ _ ____ _____ _ __ +# | |_| '_ \ / _` | ___ / __|/ _ \ '__\ \ / / _ \ '__| +# | _| | | | (_| ||___|\__ \ __/ | \ V / __/ | +# |_| |_| |_|\__, | |___/\___|_| \_/ \___|_| +# |_| +# +# Copyright (c) 2011-2025 FreeHackQuest +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +################################################################################## + +""" Example logger for commands """ + +import logging +import sys + + +class UtilsLog: + """ UtilsLog """ + def __init__(self, name): + self.__log = logging.getLogger(name) + self.__log.setLevel(logging.DEBUG) + formatter = logging.Formatter( + '[%(asctime)s] %(levelname)s [%(filename)s.%(funcName)s:%(lineno)d] %(message)s', + datefmt='%Y-%m-%d %H:%M:%S' + ) + self.__shellout = logging.StreamHandler(sys.stdout) + self.__shellout.setLevel(logging.DEBUG) + self.__shellout.setFormatter(formatter) + self.__log.addHandler(self.__shellout) + self.__log.propagate = False + + def get_logger(self): + """ return configured logger """ + return self.__log + + def set_level(self, level): + """ set level """ + self.__log.setLevel(level) + self.__shellout.setLevel(level) diff --git a/libfhqpm/utils_shell.py b/libfhqpm/utils_shell.py new file mode 100644 index 000000000..8346cadf9 --- /dev/null +++ b/libfhqpm/utils_shell.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 +################################################################################## +# __ _ +# / _| |__ __ _ ___ ___ _ ____ _____ _ __ +# | |_| '_ \ / _` | ___ / __|/ _ \ '__\ \ / / _ \ '__| +# | _| | | | (_| ||___|\__ \ __/ | \ V / __/ | +# |_| |_| |_|\__, | |___/\___|_| \_/ \___|_| +# |_| +# +# Copyright (c) 2011-2025 FreeHackQuest +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +################################################################################## + +""" Helpers for run shell """ + +import os +import sys +import subprocess + + +class UtilsShell: + """ UtilsShell """ + + @staticmethod + def run_command(_command, _output=None): + """ run_command """ + print("Run command: " + " ".join(_command)) + if _output is not None: + _output.write("Run command: " + " ".join(_command) + "\n") + with subprocess.Popen( + _command, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + shell=False + ) as _proc: + _returncode = _proc.poll() + while _returncode is None: + _returncode = _proc.poll() + _line = _proc.stdout.readline() + if _line: + _line = _line.decode("utf-8").strip() + print(_line) + if _output is not None: + _output.write(_line + "\n") + while _line: + _line = _proc.stdout.readline() + if _line: + _line = _line.decode("utf-8").strip() + print(_line) + if _output is not None: + _output.write(_line + "\n") + else: + break + if _returncode != 0: + print("ERROR: returncode " + str(_returncode)) + if _output is not None: + _output.write("ERROR: returncode " + str(_returncode) + "\n") + sys.exit(_returncode) + return + sys.exit("Could not start process") + + @staticmethod + def run_command_get_output(_log, _command): + """ run_command_get_output """ + # _log.info("Run command: " + " ".join(_command)) + _output = "" + _returncode = -1 + with subprocess.Popen( + _command, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + shell=False + ) as _proc: + _returncode = _proc.poll() + while _returncode is None: + _returncode = _proc.poll() + _line = _proc.stdout.readline() + if _line: + _line = _line.decode("utf-8").strip() + _output += _line + "\n" + while _line: + _line = _proc.stdout.readline() + if _line: + _line = _line.decode("utf-8").strip() + _output += _line + "\n" + else: + break + if _returncode != 0: + _log.error("ERROR: returncode %s", str(_returncode)) + return _returncode, _output + return _returncode, _output + + @staticmethod + def current_script_path(): + """ current_script_path """ + _dir = os.path.dirname(__file__) + _dir = os.path.join(_dir, "..") + _dir = os.path.normpath(_dir) + return _dir diff --git a/libfhqpm/utils_strings.py b/libfhqpm/utils_strings.py new file mode 100644 index 000000000..30c6454b9 --- /dev/null +++ b/libfhqpm/utils_strings.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +################################################################################## +# __ _ +# / _| |__ __ _ ___ ___ _ ____ _____ _ __ +# | |_| '_ \ / _` | ___ / __|/ _ \ '__\ \ / / _ \ '__| +# | _| | | | (_| ||___|\__ \ __/ | \ V / __/ | +# |_| |_| |_|\__, | |___/\___|_| \_/ \___|_| +# |_| +# +# Copyright (c) 2011-2025 FreeHackQuest +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +################################################################################## + +""" Helpers for processing strings """ + + +class UtilsStrings: + """ UtilsStrings """ + + @staticmethod + def to_camel_case(snake_str): + """ + to_camel_case + + by https://stackoverflow.com/users/487903/jbaiter + from stackoverflow + """ + return "".join(x.capitalize() for x in snake_str.lower().split("_")) + + @staticmethod + def snakecase_to_camelcase(snake_str): + """ + We capitalize the first letter of each component except the first one + with the 'capitalize' method and join them together. + + by https://stackoverflow.com/users/487903/jbaiter + from stackoverflow + """ + + camel_string = UtilsStrings.to_camel_case(snake_str) + return snake_str[0].upper() + camel_string[1:] diff --git a/pm.py b/pm.py index 6de6b55ef..a4c24c4dc 100755 --- a/pm.py +++ b/pm.py @@ -6,61 +6,99 @@ import os import argparse import libfhqpm -import glob2 -main_parser = argparse.ArgumentParser( - prog='pm.py', - description='What the program does', - epilog='Text at the bottom of help' -) +ROOT_DIR = os.path.dirname(os.path.realpath(__file__)) +# find the root dir (dir which contains dir 'libfhqpm') +PM_DIR = os.path.join(ROOT_DIR, 'libfhqpm') +PM_FILE = os.path.join(ROOT_DIR, 'pm.py') +while not os.path.isdir(PM_DIR) and not os.path.isfile(PM_FILE): + ROOT_DIR = os.path.join(ROOT_DIR, '..') + ROOT_DIR = os.path.normpath(ROOT_DIR) + PM_DIR = os.path.join(ROOT_DIR, 'libfhqpm') + PM_FILE = os.path.join(ROOT_DIR, 'pm.py') + if ROOT_DIR == "/": + sys.exit("Could not find rood dir") +# print("ROOT_DIR =", ROOT_DIR) -subparsers = main_parser.add_subparsers( - title='subcommands', -) +CONFIG = libfhqpm.PmConfig(ROOT_DIR) -# clang-format -CLANG_FORMAT = 'clang-format' -clang_format_parser = subparsers.add_parser( - name=CLANG_FORMAT, - description='Run clang-format' -) -clang_format_parser.set_defaults(subparser=CLANG_FORMAT) +COMMANDS = [ + libfhqpm.CommandClean(CONFIG), + libfhqpm.CommandCodeStats(CONFIG), + libfhqpm.CommandPyCheck(CONFIG), + libfhqpm.CommandClangFormat(CONFIG), + libfhqpm.CommandRebuildEnvironmentImages(CONFIG), + libfhqpm.CommandCodeCheck(CONFIG), + libfhqpm.CommandCreateStorageUpdate(CONFIG), + libfhqpm.CommandGenerateModels(CONFIG), +] -# new storage upgrade -CREATE_STORAGE_UPDATE = 'create-storage-update' -clang_format_parser = subparsers.add_parser( - name=CREATE_STORAGE_UPDATE, - description='Create storage update (for change struct of database)' -) -clang_format_parser.set_defaults(subparser=CREATE_STORAGE_UPDATE) +def print_custom_help(parser): + """ print more comfortabl help with subcomamnds""" + parser.print_help() + # retrieve subparsers from parser + subparsers_actions = [ + action for action in parser._actions # pylint: disable=protected-access + if isinstance(action, argparse._SubParsersAction) # pylint: disable=protected-access + ] + print("") + subcommand_name_maxlen = 0 + for subparsers_action in subparsers_actions: + for choice, subparser in subparsers_action.choices.items(): + subcommand_name_maxlen = max(subcommand_name_maxlen, len(choice)) + subcommand_name_maxlen += 3 + for subparsers_action in subparsers_actions: + for choice, subparser in subparsers_action.choices.items(): + subcommand_short_help = " " + choice.ljust(subcommand_name_maxlen, " ") + subcommand_short_help += subparser.description + print(subcommand_short_help) + # print(subparser.format_help()) + print("") + parser.exit() -# main -arguments = main_parser.parse_args() -if 'subparser' not in arguments: - main_parser.print_help(sys.stderr) - sys.exit(1) +class CustomActionHelp(argparse._HelpAction): # pylint: disable=protected-access + """ custom help action """ + def __call__(self, parser, namespace, values, option_string=None): + print_custom_help(parser) -if arguments.subparser == CLANG_FORMAT: - cmd = libfhqpm.CommandsHelper() - files = [] - files.extend(glob2.glob(os.path.join("src", "**", "*.cpp"))) - files.extend(glob2.glob(os.path.join("src", "**", "*.h"))) - for _file in files: - if '3rdParty' in _file: - continue - command = ["clang-format", '-style=file', '-i', _file] - cmd.run_command(command) -elif arguments.subparser == CREATE_STORAGE_UPDATE: - upgarde = libfhqpm.CreateStorageUpdate() - upgarde.create() -else: - main_parser.print_help(sys.stderr) - sys.exit(1) +if __name__ == "__main__": + MAIN_PARSER = argparse.ArgumentParser( + prog='stxpm', + description='Project manager for c++ projects', + epilog='Helper tools for work with c++ projects', + add_help=False + ) + MAIN_PARSER.add_argument('--help', '-h', action=CustomActionHelp, help='help') + SUBCOMMANDS = MAIN_PARSER.add_subparsers(title='subcommands') + for _comamnd in COMMANDS: + _comamnd.do_registry(SUBCOMMANDS) + ARGS = MAIN_PARSER.parse_args() + if 'subparser' not in ARGS: + print_custom_help(MAIN_PARSER) + sys.exit(1) + SUBCOMMAND = ARGS.subparser + for _comamnd in COMMANDS: + if _comamnd.get_name() == SUBCOMMAND: + _comamnd.execute(ARGS) -# TODO -# https://clang.llvm.org/extra/clang-tidy/ -# clang-tidy src/main.cpp -checks=-*,clang-analyzer-*,-clang-analyzer-cplusplus* +# # new storage upgrade +# CREATE_STORAGE_UPDATE = 'create-storage-update' +# clang_format_parser = subparsers.add_parser( +# name=CREATE_STORAGE_UPDATE, +# description='' +# ) +# clang_format_parser.set_defaults(subparser=CREATE_STORAGE_UPDATE) +# +# elif arguments.subparser == CREATE_STORAGE_UPDATE: +# upgarde = libfhqpm.CreateStorageUpdate() +# upgarde.create() +# else: +# main_parser.print_help(sys.stderr) +# sys.exit(1) +# # TODO +# # https://clang.llvm.org/extra/clang-tidy/ +# # clang-tidy src/main.cpp -checks=-*,clang-analyzer-*,-clang-analyzer-cplusplus* diff --git a/rebuild_environment_images.sh b/rebuild_environment_images.sh deleted file mode 100755 index 700add98b..000000000 --- a/rebuild_environment_images.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash - -check_ret() { - if [ $1 -ne 0 ]; then - echo "" - echo "!!! FAIL: $2" - echo "********************************************************************************" - echo "" - exit $1 - else - echo "" - echo "*** SUCCESS: $2" - echo "********************************************************************************" - echo "" - fi -} - -TAG=v$(date +"%Y-%m-%d") - -docker build --rm --tag sea5kg/fhq-server-build-environment:$TAG -f Dockerfile.build-environment . -check_ret $? "Could not build fhq-server-build-environment" -docker build --rm --tag sea5kg/fhq-server-build-environment:latest -f Dockerfile.build-environment . -docker build --rm --tag sea5kg/fhq-server-release-environment:$TAG -f Dockerfile.release-environment . -check_ret $? "Could not build fhq-server-release-environment" -docker build --rm --tag sea5kg/fhq-server-release-environment:latest -f Dockerfile.release-environment . diff --git a/src-libhv/base/hbase.c b/src-libhv/base/hbase.c deleted file mode 100644 index 63a65fa88..000000000 --- a/src-libhv/base/hbase.c +++ /dev/null @@ -1,293 +0,0 @@ -#include "hbase.h" - -#ifdef OS_DARWIN -#include // for _NSGetExecutablePath -#endif - -#include "hatomic.h" - -static hatomic_t s_alloc_cnt = HATOMIC_VAR_INIT(0); -static hatomic_t s_free_cnt = HATOMIC_VAR_INIT(0); - -long hv_alloc_cnt() { - return s_alloc_cnt; -} - -long hv_free_cnt() { - return s_free_cnt; -} - -void* safe_malloc(size_t size) { - hatomic_inc(&s_alloc_cnt); - void* ptr = malloc(size); - if (!ptr) { - fprintf(stderr, "malloc failed!\n"); - exit(-1); - } - return ptr; -} - -void* safe_realloc(void* oldptr, size_t newsize, size_t oldsize) { - hatomic_inc(&s_alloc_cnt); - hatomic_inc(&s_free_cnt); - void* ptr = realloc(oldptr, newsize); - if (!ptr) { - fprintf(stderr, "realloc failed!\n"); - exit(-1); - } - if (newsize > oldsize) { - memset((char*)ptr + oldsize, 0, newsize - oldsize); - } - return ptr; -} - -void* safe_calloc(size_t nmemb, size_t size) { - hatomic_inc(&s_alloc_cnt); - void* ptr = calloc(nmemb, size); - if (!ptr) { - fprintf(stderr, "calloc failed!\n"); - exit(-1); - } - return ptr; -} - -void* safe_zalloc(size_t size) { - hatomic_inc(&s_alloc_cnt); - void* ptr = malloc(size); - if (!ptr) { - fprintf(stderr, "malloc failed!\n"); - exit(-1); - } - memset(ptr, 0, size); - return ptr; -} - -void safe_free(void* ptr) { - if (ptr) { - free(ptr); - ptr = NULL; - hatomic_inc(&s_free_cnt); - } -} - -char* strupper(char* str) { - char* p = str; - while (*p != '\0') { - if (*p >= 'a' && *p <= 'z') { - *p &= ~0x20; - } - ++p; - } - return str; -} - -char* strlower(char* str) { - char* p = str; - while (*p != '\0') { - if (*p >= 'A' && *p <= 'Z') { - *p |= 0x20; - } - ++p; - } - return str; -} - -char* strreverse(char* str) { - if (str == NULL) return NULL; - char* b = str; - char* e = str; - while(*e) {++e;} - --e; - char tmp; - while (e > b) { - tmp = *e; - *e = *b; - *b = tmp; - --e; - ++b; - } - return str; -} - -// n = sizeof(dest_buf) -char* safe_strncpy(char* dest, const char* src, size_t n) { - assert(dest != NULL && src != NULL); - char* ret = dest; - while (*src != '\0' && --n > 0) { - *dest++ = *src++; - } - *dest = '\0'; - return ret; -} - -// n = sizeof(dest_buf) -char* safe_strncat(char* dest, const char* src, size_t n) { - assert(dest != NULL && src != NULL); - char* ret = dest; - while (*dest) {++dest;--n;} - while (*src != '\0' && --n > 0) { - *dest++ = *src++; - } - *dest = '\0'; - return ret; -} - -bool strstartswith(const char* str, const char* start) { - assert(str != NULL && start != NULL); - while (*str && *start && *str == *start) { - ++str; - ++start; - } - return *start == '\0'; -} - -bool strendswith(const char* str, const char* end) { - assert(str != NULL && end != NULL); - int len1 = 0; - int len2 = 0; - while (*str) {++str; ++len1;} - while (*end) {++end; ++len2;} - if (len1 < len2) return false; - while (len2-- > 0) { - --str; - --end; - if (*str != *end) { - return false; - } - } - return true; -} - -bool strcontains(const char* str, const char* sub) { - assert(str != NULL && sub != NULL); - return strstr(str, sub) != NULL; -} - -char* strrchr_dir(const char* filepath) { - char* p = (char*)filepath; - while (*p) ++p; - while (--p >= filepath) { -#ifdef OS_WIN - if (*p == '/' || *p == '\\') -#else - if (*p == '/') -#endif - return p; - } - return NULL; -} - -const char* hv_basename(const char* filepath) { - const char* pos = strrchr_dir(filepath); - return pos ? pos+1 : filepath; -} - -const char* hv_suffixname(const char* filename) { - const char* pos = strrchr_dot(filename); - return pos ? pos+1 : ""; -} - -int hv_mkdir_p(const char* dir) { - if (access(dir, 0) == 0) { - return EEXIST; - } - char tmp[MAX_PATH]; - safe_strncpy(tmp, dir, sizeof(tmp)); - char* p = tmp; - char delim = '/'; - while (*p) { -#ifdef OS_WIN - if (*p == '/' || *p == '\\') { - delim = *p; -#else - if (*p == '/') { -#endif - *p = '\0'; - hv_mkdir(tmp); - *p = delim; - } - ++p; - } - if (hv_mkdir(tmp) != 0) { - return EPERM; - } - return 0; -} - -int hv_rmdir_p(const char* dir) { - if (access(dir, 0) != 0) { - return ENOENT; - } - if (rmdir(dir) != 0) { - return EPERM; - } - char tmp[MAX_PATH]; - safe_strncpy(tmp, dir, sizeof(tmp)); - char* p = tmp; - while (*p) ++p; - while (--p >= tmp) { -#ifdef OS_WIN - if (*p == '/' || *p == '\\') { -#else - if (*p == '/') { -#endif - *p = '\0'; - if (rmdir(tmp) != 0) { - return 0; - } - } - } - return 0; -} - -bool getboolean(const char* str) { - if (str == NULL) return false; - int len = strlen(str); - if (len == 0) return false; - switch (len) { - case 1: return *str == '1' || *str == 'y' || *str == 'Y'; - case 2: return stricmp(str, "on") == 0; - case 3: return stricmp(str, "yes") == 0; - case 4: return stricmp(str, "true") == 0; - case 6: return stricmp(str, "enable") == 0; - default: return false; - } -} - -char* get_executable_path(char* buf, int size) { -#ifdef OS_WIN - GetModuleFileName(NULL, buf, size); -#elif defined(OS_LINUX) - if (readlink("/proc/self/exe", buf, size) == -1) { - return NULL; - } -#elif defined(OS_DARWIN) - _NSGetExecutablePath(buf, (uint32_t*)&size); -#endif - return buf; -} - -char* get_executable_dir(char* buf, int size) { - char filepath[MAX_PATH]; - get_executable_path(filepath, sizeof(filepath)); - char* pos = strrchr_dir(filepath); - if (pos) { - *pos = '\0'; - strncpy(buf, filepath, size); - } - return buf; -} - -char* get_executable_file(char* buf, int size) { - char filepath[MAX_PATH]; - get_executable_path(filepath, sizeof(filepath)); - char* pos = strrchr_dir(filepath); - if (pos) { - strncpy(buf, pos+1, size); - } - return buf; -} - -char* get_run_dir(char* buf, int size) { - return getcwd(buf, size); -} diff --git a/src-libhv/base/hbase.h b/src-libhv/base/hbase.h deleted file mode 100644 index 1ad5bdefc..000000000 --- a/src-libhv/base/hbase.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef HV_BASE_H_ -#define HV_BASE_H_ - -#include "hexport.h" -#include "hplatform.h" // for bool -#include "hdef.h" // for printd - -BEGIN_EXTERN_C - -//--------------------safe alloc/free--------------------------- -HV_EXPORT void* safe_malloc(size_t size); -HV_EXPORT void* safe_realloc(void* oldptr, size_t newsize, size_t oldsize); -HV_EXPORT void* safe_calloc(size_t nmemb, size_t size); -HV_EXPORT void* safe_zalloc(size_t size); -HV_EXPORT void safe_free(void* ptr); - -#define HV_ALLOC(ptr, size)\ - do {\ - *(void**)&(ptr) = safe_zalloc(size);\ - printd("alloc(%p, size=%llu)\tat [%s:%d:%s]\n", ptr, (unsigned long long)size, __FILE__, __LINE__, __FUNCTION__);\ - } while(0) - -#define HV_ALLOC_SIZEOF(ptr) HV_ALLOC(ptr, sizeof(*(ptr))) - -#define HV_FREE(ptr)\ - do {\ - if (ptr) {\ - safe_free(ptr);\ - printd("free( %p )\tat [%s:%d:%s]\n", ptr, __FILE__, __LINE__, __FUNCTION__);\ - ptr = NULL;\ - }\ - } while(0) - -HV_EXPORT long hv_alloc_cnt(); -HV_EXPORT long hv_free_cnt(); -HV_INLINE void hv_memcheck() { - printf("Memcheck => alloc:%ld free:%ld\n", hv_alloc_cnt(), hv_free_cnt()); -} -#define HV_MEMCHECK atexit(hv_memcheck); - -//--------------------safe string------------------------------- -HV_EXPORT char* strupper(char* str); -HV_EXPORT char* strlower(char* str); -HV_EXPORT char* strreverse(char* str); - -HV_EXPORT bool strstartswith(const char* str, const char* start); -HV_EXPORT bool strendswith(const char* str, const char* end); -HV_EXPORT bool strcontains(const char* str, const char* sub); - -// strncpy n = sizeof(dest_buf)-1 -// safe_strncpy n = sizeof(dest_buf) -HV_EXPORT char* safe_strncpy(char* dest, const char* src, size_t n); - -// strncat n = sizeof(dest_buf)-1-strlen(dest) -// safe_strncpy n = sizeof(dest_buf) -HV_EXPORT char* safe_strncat(char* dest, const char* src, size_t n); - -#if !HAVE_STRLCPY -#define strlcpy safe_strncpy -#endif - -#if !HAVE_STRLCAT -#define strlcat safe_strncat -#endif - -#define strrchr_dot(str) strrchr(str, '.') -HV_EXPORT char* strrchr_dir(const char* filepath); - -// basename -HV_EXPORT const char* hv_basename(const char* filepath); -HV_EXPORT const char* hv_suffixname(const char* filename); -// mkdir -p -HV_EXPORT int hv_mkdir_p(const char* dir); -// rmdir -p -HV_EXPORT int hv_rmdir_p(const char* dir); - -// 1 y on yes true enable -HV_EXPORT bool getboolean(const char* str); - -HV_EXPORT char* get_executable_path(char* buf, int size); -HV_EXPORT char* get_executable_dir(char* buf, int size); -HV_EXPORT char* get_executable_file(char* buf, int size); -HV_EXPORT char* get_run_dir(char* buf, int size); - -END_EXTERN_C - -#endif // HV_BASE_H_ diff --git a/src-libhv/base/hmath.h b/src-libhv/base/hmath.h deleted file mode 100644 index 993a7b994..000000000 --- a/src-libhv/base/hmath.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef HV_MATH_H_ -#define HV_MATH_H_ - -#include - -static inline unsigned long floor2e(unsigned long num) { - unsigned long n = num; - int e = 0; - while (n>>=1) ++e; - unsigned long ret = 1; - while (e--) ret<<=1; - return ret; -} - -static inline unsigned long ceil2e(unsigned long num) { - // 2**0 = 1 - if (num == 0 || num == 1) return 1; - unsigned long n = num - 1; - int e = 1; - while (n>>=1) ++e; - unsigned long ret = 1; - while (e--) ret<<=1; - return ret; -} - -#endif // HV_MATH_H_ diff --git a/src-libhv/build_simple.sh b/src-libhv/build_simple.sh deleted file mode 100755 index 8b35d10fe..000000000 --- a/src-libhv/build_simple.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -if [ ! -d tmp ]; then - mkdir -p tmp -fi - -cd tmp -cmake .. -make - diff --git a/src-libhv/cpputil/hstring.cpp b/src-libhv/cpputil/hstring.cpp deleted file mode 100644 index a67e638ef..000000000 --- a/src-libhv/cpputil/hstring.cpp +++ /dev/null @@ -1,197 +0,0 @@ -#include "hstring.h" - -#include -#include -#include -#include - -static inline int vscprintf(const char* fmt, va_list ap) { - return vsnprintf(NULL, 0, fmt, ap); -} - -string asprintf(const char* fmt, ...) { - va_list ap; - va_start(ap, fmt); - int len = vscprintf(fmt, ap); - va_end(ap); - - string str; - str.reserve(len+1); - // must resize to set str.size - str.resize(len); - // must recall va_start on unix - va_start(ap, fmt); - vsnprintf((char*)str.data(), len+1, fmt, ap); - va_end(ap); - - return str; -} - -StringList split(const string& str, char delim) { - /* - std::stringstream ss; - ss << str; - string item; - StringList res; - while (std::getline(ss, item, delim)) { - res.push_back(item); - } - return res; - */ - const char* p = str.c_str(); - const char* value = p; - StringList res; - while (*p != '\0') { - if (*p == delim) { - res.push_back(std::string(value, p-value)); - value = p+1; - } - ++p; - } - res.push_back(value); - return res; -} - -hv::KeyValue splitKV(const string& str, char kv_kv, char k_v) { - enum { - s_key, - s_value, - } state = s_key; - const char* p = str.c_str(); - const char* key = p; - const char* value = NULL; - int key_len = 0; - int value_len = 0; - hv::KeyValue kvs; - while (*p != '\0') { - if (*p == kv_kv) { - if (key_len && value_len) { - kvs[std::string(key, key_len)] = std::string(value, value_len); - key_len = value_len = 0; - } - state = s_key; - key = p+1; - } - else if (*p == k_v) { - state = s_value; - value = p+1; - } - else { - state == s_key ? ++key_len : ++value_len; - } - ++p; - } - if (key_len && value_len) { - kvs[std::string(key, key_len)] = std::string(value, value_len); - } - return kvs; -} - -string trim(const string& str, const char* chars) { - string::size_type pos1 = str.find_first_not_of(chars); - if (pos1 == string::npos) return ""; - - string::size_type pos2 = str.find_last_not_of(chars); - return str.substr(pos1, pos2-pos1+1); -} - -string trimL(const string& str, const char* chars) { - string::size_type pos = str.find_first_not_of(chars); - if (pos == string::npos) return ""; - return str.substr(pos); -} - -string trimR(const string& str, const char* chars) { - string::size_type pos = str.find_last_not_of(chars); - return str.substr(0, pos+1); -} - -string trim_pairs(const string& str, const char* pairs) { - const char* s = str.c_str(); - const char* e = str.c_str() + str.size() - 1; - const char* p = pairs; - bool is_pair = false; - while (*p != '\0' && *(p+1) != '\0') { - if (*s == *p && *e == *(p+1)) { - is_pair = true; - break; - } - p += 2; - } - return is_pair ? str.substr(1, str.size()-2) : str; -} - -string replace(const string& str, const string& find, const string& rep) { - string::size_type pos = 0; - string::size_type a = find.size(); - string::size_type b = rep.size(); - - string res(str); - while ((pos = res.find(find, pos)) != string::npos) { - res.replace(pos, a, rep); - pos += b; - } - return res; -} - -string basename(const string& str) { - string::size_type pos1 = str.find_last_not_of("/\\"); - if (pos1 == string::npos) { - return "/"; - } - string::size_type pos2 = str.find_last_of("/\\", pos1); - if (pos2 == string::npos) { - pos2 = 0; - } else { - pos2++; - } - - return str.substr(pos2, pos1-pos2+1); -} - -string dirname(const string& str) { - string::size_type pos1 = str.find_last_not_of("/\\"); - if (pos1 == string::npos) { - return "/"; - } - string::size_type pos2 = str.find_last_of("/\\", pos1); - if (pos2 == string::npos) { - return "."; - } else if (pos2 == 0) { - pos2 = 1; - } - - return str.substr(0, pos2); -} - -string filename(const string& str) { - string::size_type pos1 = str.find_last_of("/\\"); - if (pos1 == string::npos) { - pos1 = 0; - } else { - pos1++; - } - string file = str.substr(pos1, -1); - - string::size_type pos2 = file.find_last_of("."); - if (pos2 == string::npos) { - return file; - } - return file.substr(0, pos2); -} - -string suffixname(const string& str) { - string::size_type pos1 = str.find_last_of("/\\"); - if (pos1 == string::npos) { - pos1 = 0; - } else { - pos1++; - } - string file = str.substr(pos1, -1); - - string::size_type pos2 = file.find_last_of("."); - if (pos2 == string::npos) { - return ""; - } - return file.substr(pos2+1, -1); -} diff --git a/src-libhv/cpputil/hstring.h b/src-libhv/cpputil/hstring.h deleted file mode 100644 index f1f23bdd5..000000000 --- a/src-libhv/cpputil/hstring.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef HV_STRING_H_ -#define HV_STRING_H_ - -#include -#include -#include - -#include "hexport.h" -#include "hbase.h" -#include "hmap.h" - -using std::string; -typedef std::vector StringList; - -// std::map -class StringCaseLess : public std::less { -public: - bool operator()(const std::string& lhs, const std::string& rhs) const { - return strcasecmp(lhs.c_str(), rhs.c_str()) < 0; - } -}; - -namespace hv { -// NOTE: low-version NDK not provide std::to_string -template -HV_INLINE std::string to_string(const T& t) { - std::ostringstream oss; - oss << t; - return oss.str(); -} - -template -HV_INLINE T from_string(const std::string& str) { - T t; - std::istringstream iss(str); - iss >> t; - return t; -} -} - -#define SPACE_CHARS " \t\r\n" -#define PAIR_CHARS "{}[]()<>\"\"\'\'``" - -HV_EXPORT string asprintf(const char* fmt, ...); -// x,y,z -HV_EXPORT StringList split(const string& str, char delim = ','); -// user=amdin&pswd=123456 -HV_EXPORT hv::KeyValue splitKV(const string& str, char kv_kv = '&', char k_v = '='); -HV_EXPORT string trim(const string& str, const char* chars = SPACE_CHARS); -HV_EXPORT string trimL(const string& str, const char* chars = SPACE_CHARS); -HV_EXPORT string trimR(const string& str, const char* chars = SPACE_CHARS); -HV_EXPORT string trim_pairs(const string& str, const char* pairs = PAIR_CHARS); -HV_EXPORT string replace(const string& str, const string& find, const string& rep); - -// str=/mnt/share/image/test.jpg -// basename=test.jpg -// dirname=/mnt/share/image -// filename=test -// suffixname=jpg -HV_EXPORT string basename(const string& str); -HV_EXPORT string dirname(const string& str); -HV_EXPORT string filename(const string& str); -HV_EXPORT string suffixname(const string& str); - -#endif // HV_STRING_H_ diff --git a/src-libhv/cpputil/hthreadpool.h b/src-libhv/cpputil/hthreadpool.h deleted file mode 100644 index 8c5d4d731..000000000 --- a/src-libhv/cpputil/hthreadpool.h +++ /dev/null @@ -1,135 +0,0 @@ -#ifndef HV_THREAD_POOL_H_ -#define HV_THREAD_POOL_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -class HThreadPool { -public: - using Task = std::function; - - HThreadPool(int size = std::thread::hardware_concurrency()) - : pool_size(size), idle_num(size), status(STOP) { - } - - ~HThreadPool() { - stop(); - } - - int start() { - if (status == STOP) { - status = RUNNING; - for (int i = 0; i < pool_size; ++i) { - workers.emplace_back(std::thread([this]{ - while (status != STOP) { - while (status == PAUSE) { - std::this_thread::yield(); - } - - Task task; - { - std::unique_lock locker(_mutex); - _cond.wait(locker, [this]{ - return status == STOP || !tasks.empty(); - }); - - if (status == STOP) return; - - if (!tasks.empty()) { - --idle_num; - task = std::move(tasks.front()); - tasks.pop(); - } - } - - task(); - ++idle_num; - } - })); - } - } - return 0; - } - - int stop() { - if (status != STOP) { - status = STOP; - _cond.notify_all(); - for (auto& worker : workers) { - worker.join(); - } - } - return 0; - } - - int pause() { - if (status == RUNNING) { - status = PAUSE; - } - return 0; - } - - int resume() { - if (status == PAUSE) { - status = RUNNING; - } - return 0; - } - - int wait() { - while (1) { - if (status == STOP || (tasks.empty() && idle_num == pool_size)) { - break; - } - std::this_thread::yield(); - } - return 0; - } - - // return a future, calling future.get() will wait task done and return RetType. - // commit(fn, args...) - // commit(std::bind(&Class::mem_fn, &obj)) - // commit(std::mem_fn(&Class::mem_fn, &obj)) - template - auto commit(Fn&& fn, Args&&... args) -> std::future { - using RetType = decltype(fn(args...)); - auto task = std::make_shared >( - std::bind(std::forward(fn), std::forward(args)...)); - std::future future = task->get_future(); - { - std::lock_guard locker(_mutex); - tasks.emplace([task]{ - (*task)(); - }); - } - - _cond.notify_one(); - return future; - } - -public: - enum Status { - STOP, - RUNNING, - PAUSE, - }; - int pool_size; - std::atomic idle_num; - std::atomic status; - std::vector workers; - std::queue tasks; - -protected: - std::mutex _mutex; - std::condition_variable _cond; -}; - -#endif // HV_THREAD_POOL_H_ diff --git a/src-libhv/cpputil/hurl.cpp b/src-libhv/cpputil/hurl.cpp deleted file mode 100644 index 011eadad9..000000000 --- a/src-libhv/cpputil/hurl.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "hurl.h" - -#include "hdef.h" - -/* -static bool Curl_isunreserved(unsigned char in) -{ - switch(in) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - case 'a': case 'b': case 'c': case 'd': case 'e': - case 'f': case 'g': case 'h': case 'i': case 'j': - case 'k': case 'l': case 'm': case 'n': case 'o': - case 'p': case 'q': case 'r': case 's': case 't': - case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': - case 'A': case 'B': case 'C': case 'D': case 'E': - case 'F': case 'G': case 'H': case 'I': case 'J': - case 'K': case 'L': case 'M': case 'N': case 'O': - case 'P': case 'Q': case 'R': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': - case '-': case '.': case '_': case '~': - return TRUE; - default: - break; - } - return FLASE; -} -*/ - -static inline bool is_unambiguous(char c) { - return IS_ALPHANUM(c) || - c == '-' || - c == '_' || - c == '.' || - c == '~'; -} - -static inline unsigned char hex2i(char hex) { - return hex <= '9' ? hex - '0' : - hex <= 'F' ? hex - 'A' + 10 : hex - 'a' + 10; -} - -std::string url_escape(const char* istr) { - std::string ostr; - const char* p = istr; - char szHex[4] = {0}; - while (*p != '\0') { - if (is_unambiguous(*p)) { - ostr += *p; - } - else { - sprintf(szHex, "%%%02X", *p); - ostr += szHex; - } - ++p; - } - return ostr; -} - -std::string url_unescape(const char* istr) { - std::string ostr; - const char* p = istr; - while (*p != '\0') { - if (*p == '%' && - IS_HEX(p[1]) && - IS_HEX(p[2])) { - ostr += ((hex2i(p[1]) << 4) | hex2i(p[2])); - p += 3; - } - else { - ostr += *p; - ++p; - } - } - return ostr; -} diff --git a/src-libhv/cpputil/hurl.h b/src-libhv/cpputil/hurl.h deleted file mode 100644 index 08253ecff..000000000 --- a/src-libhv/cpputil/hurl.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef HV_URL_H_ -#define HV_URL_H_ - -#include - -#include "hexport.h" - -HV_EXPORT std::string url_escape(const char* istr); -HV_EXPORT std::string url_unescape(const char* istr); - -#endif // HV_URL_H_ diff --git a/src-libhv/cpputil/iniparser.h b/src-libhv/cpputil/iniparser.h deleted file mode 100644 index f8dc970fa..000000000 --- a/src-libhv/cpputil/iniparser.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef HV_INI_PARSER_H_ -#define HV_INI_PARSER_H_ - -#include -using std::string; - -#include "hexport.h" - -#define DEFAULT_INI_COMMENT "#" -#define DEFAULT_INI_DELIM "=" - -// fwd -class IniNode; - -class HV_EXPORT IniParser { -public: - IniParser(); - ~IniParser(); - - int LoadFromFile(const char* filepath); - int LoadFromMem(const char* data); - int Unload(); - int Reload(); - - string DumpString(); - int Save(); - int SaveAs(const char* filepath); - - string GetValue(const string& key, const string& section = ""); - void SetValue(const string& key, const string& value, const string& section = ""); - - // T = [bool, int, float] - template - T Get(const string& key, const string& section = "", T defvalue = 0); - - // T = [bool, int, float] - template - void Set(const string& key, const T& value, const string& section = ""); - -protected: - void DumpString(IniNode* pNode, string& str); - -public: - string _comment; - string _delim; - string _filepath; -private: - IniNode* root_; -}; - -#endif // HV_INI_PARSER_H_ diff --git a/src-libhv/cpputil/json.hpp b/src-libhv/cpputil/json.hpp deleted file mode 100644 index 92308c557..000000000 --- a/src-libhv/cpputil/json.hpp +++ /dev/null @@ -1,22100 +0,0 @@ -/* - __ _____ _____ _____ - __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 3.10.5 -|_____|_____|_____|_|___| https://github.com/nlohmann/json - -Licensed under the MIT License . -SPDX-License-Identifier: MIT -Copyright (c) 2013-2022 Niels Lohmann . - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -/****************************************************************************\ - * Note on documentation: The source files contain links to the online * - * documentation of the public API at https://json.nlohmann.me. This URL * - * contains the most recent documentation and should also be applicable to * - * previous versions; documentation for deprecated functions is not * - * removed, but marked deprecated. See "Generate documentation" section in * - * file doc/README.md. * -\****************************************************************************/ - -#ifndef INCLUDE_NLOHMANN_JSON_HPP_ -#define INCLUDE_NLOHMANN_JSON_HPP_ - -#define NLOHMANN_JSON_VERSION_MAJOR 3 -#define NLOHMANN_JSON_VERSION_MINOR 10 -#define NLOHMANN_JSON_VERSION_PATCH 5 - -#include // all_of, find, for_each -#include // nullptr_t, ptrdiff_t, size_t -#include // hash, less -#include // initializer_list -#ifndef JSON_NO_IO - #include // istream, ostream -#endif // JSON_NO_IO -#include // random_access_iterator_tag -#include // unique_ptr -#include // accumulate -#include // string, stoi, to_string -#include // declval, forward, move, pair, swap -#include // vector - -// #include - - -#include -#include - -// #include - - -#include // transform -#include // array -#include // forward_list -#include // inserter, front_inserter, end -#include // map -#include // string -#include // tuple, make_tuple -#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible -#include // unordered_map -#include // pair, declval -#include // valarray - -// #include - - -#include // exception -#include // runtime_error -#include // to_string -#include // vector - -// #include - - -#include // array -#include // size_t -#include // uint8_t -#include // string - -namespace nlohmann -{ -namespace detail -{ -/////////////////////////// -// JSON type enumeration // -/////////////////////////// - -/*! -@brief the JSON type enumeration - -This enumeration collects the different JSON types. It is internally used to -distinguish the stored values, and the functions @ref basic_json::is_null(), -@ref basic_json::is_object(), @ref basic_json::is_array(), -@ref basic_json::is_string(), @ref basic_json::is_boolean(), -@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), -@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), -@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and -@ref basic_json::is_structured() rely on it. - -@note There are three enumeration entries (number_integer, number_unsigned, and -number_float), because the library distinguishes these three types for numbers: -@ref basic_json::number_unsigned_t is used for unsigned integers, -@ref basic_json::number_integer_t is used for signed integers, and -@ref basic_json::number_float_t is used for floating-point numbers or to -approximate integers which do not fit in the limits of their respective type. - -@sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON -value with the default value for a given type - -@since version 1.0.0 -*/ -enum class value_t : std::uint8_t -{ - null, ///< null value - object, ///< object (unordered set of name/value pairs) - array, ///< array (ordered collection of values) - string, ///< string value - boolean, ///< boolean value - number_integer, ///< number value (signed integer) - number_unsigned, ///< number value (unsigned integer) - number_float, ///< number value (floating-point) - binary, ///< binary array (ordered collection of bytes) - discarded ///< discarded by the parser callback function -}; - -/*! -@brief comparison operator for JSON types - -Returns an ordering that is similar to Python: -- order: null < boolean < number < object < array < string < binary -- furthermore, each type is not smaller than itself -- discarded values are not comparable -- binary is represented as a b"" string in python and directly comparable to a - string; however, making a binary array directly comparable with a string would - be surprising behavior in a JSON file. - -@since version 1.0.0 -*/ -inline bool operator<(const value_t lhs, const value_t rhs) noexcept -{ - static constexpr std::array order = {{ - 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, - 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */, - 6 /* binary */ - } - }; - - const auto l_index = static_cast(lhs); - const auto r_index = static_cast(rhs); - return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index]; -} -} // namespace detail -} // namespace nlohmann - -// #include - - -#include -// #include - - -#include // declval, pair -// #include - - -/* Hedley - https://nemequ.github.io/hedley - * Created by Evan Nemerson - * - * To the extent possible under law, the author(s) have dedicated all - * copyright and related and neighboring rights to this software to - * the public domain worldwide. This software is distributed without - * any warranty. - * - * For details, see . - * SPDX-License-Identifier: CC0-1.0 - */ - -#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 15) -#if defined(JSON_HEDLEY_VERSION) - #undef JSON_HEDLEY_VERSION -#endif -#define JSON_HEDLEY_VERSION 15 - -#if defined(JSON_HEDLEY_STRINGIFY_EX) - #undef JSON_HEDLEY_STRINGIFY_EX -#endif -#define JSON_HEDLEY_STRINGIFY_EX(x) #x - -#if defined(JSON_HEDLEY_STRINGIFY) - #undef JSON_HEDLEY_STRINGIFY -#endif -#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x) - -#if defined(JSON_HEDLEY_CONCAT_EX) - #undef JSON_HEDLEY_CONCAT_EX -#endif -#define JSON_HEDLEY_CONCAT_EX(a,b) a##b - -#if defined(JSON_HEDLEY_CONCAT) - #undef JSON_HEDLEY_CONCAT -#endif -#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b) - -#if defined(JSON_HEDLEY_CONCAT3_EX) - #undef JSON_HEDLEY_CONCAT3_EX -#endif -#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c - -#if defined(JSON_HEDLEY_CONCAT3) - #undef JSON_HEDLEY_CONCAT3 -#endif -#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c) - -#if defined(JSON_HEDLEY_VERSION_ENCODE) - #undef JSON_HEDLEY_VERSION_ENCODE -#endif -#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) - -#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR) - #undef JSON_HEDLEY_VERSION_DECODE_MAJOR -#endif -#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) - -#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR) - #undef JSON_HEDLEY_VERSION_DECODE_MINOR -#endif -#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) - -#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION) - #undef JSON_HEDLEY_VERSION_DECODE_REVISION -#endif -#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) - -#if defined(JSON_HEDLEY_GNUC_VERSION) - #undef JSON_HEDLEY_GNUC_VERSION -#endif -#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) - #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) -#elif defined(__GNUC__) - #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) -#endif - -#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK) - #undef JSON_HEDLEY_GNUC_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_GNUC_VERSION) - #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_MSVC_VERSION) - #undef JSON_HEDLEY_MSVC_VERSION -#endif -#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL) - #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) -#elif defined(_MSC_FULL_VER) && !defined(__ICL) - #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) -#elif defined(_MSC_VER) && !defined(__ICL) - #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) -#endif - -#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK) - #undef JSON_HEDLEY_MSVC_VERSION_CHECK -#endif -#if !defined(JSON_HEDLEY_MSVC_VERSION) - #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) -#elif defined(_MSC_VER) && (_MSC_VER >= 1400) - #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) -#elif defined(_MSC_VER) && (_MSC_VER >= 1200) - #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) -#else - #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) -#endif - -#if defined(JSON_HEDLEY_INTEL_VERSION) - #undef JSON_HEDLEY_INTEL_VERSION -#endif -#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL) - #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) -#elif defined(__INTEL_COMPILER) && !defined(__ICL) - #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) -#endif - -#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK) - #undef JSON_HEDLEY_INTEL_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_INTEL_VERSION) - #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_INTEL_CL_VERSION) - #undef JSON_HEDLEY_INTEL_CL_VERSION -#endif -#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL) - #define JSON_HEDLEY_INTEL_CL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0) -#endif - -#if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK) - #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_INTEL_CL_VERSION) - #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_CL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_PGI_VERSION) - #undef JSON_HEDLEY_PGI_VERSION -#endif -#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) - #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) -#endif - -#if defined(JSON_HEDLEY_PGI_VERSION_CHECK) - #undef JSON_HEDLEY_PGI_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_PGI_VERSION) - #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_SUNPRO_VERSION) - #undef JSON_HEDLEY_SUNPRO_VERSION -#endif -#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) - #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) -#elif defined(__SUNPRO_C) - #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) -#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) - #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) -#elif defined(__SUNPRO_CC) - #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) -#endif - -#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK) - #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_SUNPRO_VERSION) - #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) - #undef JSON_HEDLEY_EMSCRIPTEN_VERSION -#endif -#if defined(__EMSCRIPTEN__) - #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) -#endif - -#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK) - #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) - #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_ARM_VERSION) - #undef JSON_HEDLEY_ARM_VERSION -#endif -#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) - #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) -#elif defined(__CC_ARM) && defined(__ARMCC_VERSION) - #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) -#endif - -#if defined(JSON_HEDLEY_ARM_VERSION_CHECK) - #undef JSON_HEDLEY_ARM_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_ARM_VERSION) - #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_IBM_VERSION) - #undef JSON_HEDLEY_IBM_VERSION -#endif -#if defined(__ibmxl__) - #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) -#elif defined(__xlC__) && defined(__xlC_ver__) - #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) -#elif defined(__xlC__) - #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) -#endif - -#if defined(JSON_HEDLEY_IBM_VERSION_CHECK) - #undef JSON_HEDLEY_IBM_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_IBM_VERSION) - #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_TI_VERSION) - #undef JSON_HEDLEY_TI_VERSION -#endif -#if \ - defined(__TI_COMPILER_VERSION__) && \ - ( \ - defined(__TMS470__) || defined(__TI_ARM__) || \ - defined(__MSP430__) || \ - defined(__TMS320C2000__) \ - ) -#if (__TI_COMPILER_VERSION__ >= 16000000) - #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) -#endif -#endif - -#if defined(JSON_HEDLEY_TI_VERSION_CHECK) - #undef JSON_HEDLEY_TI_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_TI_VERSION) - #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_TI_CL2000_VERSION) - #undef JSON_HEDLEY_TI_CL2000_VERSION -#endif -#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) - #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) -#endif - -#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK) - #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_TI_CL2000_VERSION) - #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_TI_CL430_VERSION) - #undef JSON_HEDLEY_TI_CL430_VERSION -#endif -#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) - #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) -#endif - -#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK) - #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_TI_CL430_VERSION) - #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) - #undef JSON_HEDLEY_TI_ARMCL_VERSION -#endif -#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__)) - #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) -#endif - -#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK) - #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) - #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_TI_CL6X_VERSION) - #undef JSON_HEDLEY_TI_CL6X_VERSION -#endif -#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) - #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) -#endif - -#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK) - #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_TI_CL6X_VERSION) - #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_TI_CL7X_VERSION) - #undef JSON_HEDLEY_TI_CL7X_VERSION -#endif -#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) - #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) -#endif - -#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK) - #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_TI_CL7X_VERSION) - #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) - #undef JSON_HEDLEY_TI_CLPRU_VERSION -#endif -#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) - #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) -#endif - -#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK) - #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) - #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_CRAY_VERSION) - #undef JSON_HEDLEY_CRAY_VERSION -#endif -#if defined(_CRAYC) - #if defined(_RELEASE_PATCHLEVEL) - #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) - #else - #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) - #endif -#endif - -#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK) - #undef JSON_HEDLEY_CRAY_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_CRAY_VERSION) - #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_IAR_VERSION) - #undef JSON_HEDLEY_IAR_VERSION -#endif -#if defined(__IAR_SYSTEMS_ICC__) - #if __VER__ > 1000 - #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) - #else - #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0) - #endif -#endif - -#if defined(JSON_HEDLEY_IAR_VERSION_CHECK) - #undef JSON_HEDLEY_IAR_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_IAR_VERSION) - #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_TINYC_VERSION) - #undef JSON_HEDLEY_TINYC_VERSION -#endif -#if defined(__TINYC__) - #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) -#endif - -#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK) - #undef JSON_HEDLEY_TINYC_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_TINYC_VERSION) - #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_DMC_VERSION) - #undef JSON_HEDLEY_DMC_VERSION -#endif -#if defined(__DMC__) - #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) -#endif - -#if defined(JSON_HEDLEY_DMC_VERSION_CHECK) - #undef JSON_HEDLEY_DMC_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_DMC_VERSION) - #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_COMPCERT_VERSION) - #undef JSON_HEDLEY_COMPCERT_VERSION -#endif -#if defined(__COMPCERT_VERSION__) - #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) -#endif - -#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK) - #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_COMPCERT_VERSION) - #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_PELLES_VERSION) - #undef JSON_HEDLEY_PELLES_VERSION -#endif -#if defined(__POCC__) - #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) -#endif - -#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK) - #undef JSON_HEDLEY_PELLES_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_PELLES_VERSION) - #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_MCST_LCC_VERSION) - #undef JSON_HEDLEY_MCST_LCC_VERSION -#endif -#if defined(__LCC__) && defined(__LCC_MINOR__) - #define JSON_HEDLEY_MCST_LCC_VERSION JSON_HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__) -#endif - -#if defined(JSON_HEDLEY_MCST_LCC_VERSION_CHECK) - #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_MCST_LCC_VERSION) - #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_MCST_LCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_GCC_VERSION) - #undef JSON_HEDLEY_GCC_VERSION -#endif -#if \ - defined(JSON_HEDLEY_GNUC_VERSION) && \ - !defined(__clang__) && \ - !defined(JSON_HEDLEY_INTEL_VERSION) && \ - !defined(JSON_HEDLEY_PGI_VERSION) && \ - !defined(JSON_HEDLEY_ARM_VERSION) && \ - !defined(JSON_HEDLEY_CRAY_VERSION) && \ - !defined(JSON_HEDLEY_TI_VERSION) && \ - !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \ - !defined(JSON_HEDLEY_TI_CL430_VERSION) && \ - !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \ - !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \ - !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \ - !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \ - !defined(__COMPCERT__) && \ - !defined(JSON_HEDLEY_MCST_LCC_VERSION) - #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION -#endif - -#if defined(JSON_HEDLEY_GCC_VERSION_CHECK) - #undef JSON_HEDLEY_GCC_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_GCC_VERSION) - #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_HAS_ATTRIBUTE) - #undef JSON_HEDLEY_HAS_ATTRIBUTE -#endif -#if \ - defined(__has_attribute) && \ - ( \ - (!defined(JSON_HEDLEY_IAR_VERSION) || JSON_HEDLEY_IAR_VERSION_CHECK(8,5,9)) \ - ) -# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) -#else -# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) -#endif - -#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE) - #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE -#endif -#if defined(__has_attribute) - #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) -#else - #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE) - #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE -#endif -#if defined(__has_attribute) - #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) -#else - #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) - #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE -#endif -#if \ - defined(__has_cpp_attribute) && \ - defined(__cplusplus) && \ - (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) - #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) -#else - #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) -#endif - -#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) - #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS -#endif -#if !defined(__cplusplus) || !defined(__has_cpp_attribute) - #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) -#elif \ - !defined(JSON_HEDLEY_PGI_VERSION) && \ - !defined(JSON_HEDLEY_IAR_VERSION) && \ - (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ - (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) - #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) -#else - #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) -#endif - -#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) - #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE -#endif -#if defined(__has_cpp_attribute) && defined(__cplusplus) - #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) -#else - #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE) - #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE -#endif -#if defined(__has_cpp_attribute) && defined(__cplusplus) - #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) -#else - #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_HAS_BUILTIN) - #undef JSON_HEDLEY_HAS_BUILTIN -#endif -#if defined(__has_builtin) - #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) -#else - #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) -#endif - -#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN) - #undef JSON_HEDLEY_GNUC_HAS_BUILTIN -#endif -#if defined(__has_builtin) - #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) -#else - #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN) - #undef JSON_HEDLEY_GCC_HAS_BUILTIN -#endif -#if defined(__has_builtin) - #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) -#else - #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_HAS_FEATURE) - #undef JSON_HEDLEY_HAS_FEATURE -#endif -#if defined(__has_feature) - #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) -#else - #define JSON_HEDLEY_HAS_FEATURE(feature) (0) -#endif - -#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE) - #undef JSON_HEDLEY_GNUC_HAS_FEATURE -#endif -#if defined(__has_feature) - #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) -#else - #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_GCC_HAS_FEATURE) - #undef JSON_HEDLEY_GCC_HAS_FEATURE -#endif -#if defined(__has_feature) - #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) -#else - #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_HAS_EXTENSION) - #undef JSON_HEDLEY_HAS_EXTENSION -#endif -#if defined(__has_extension) - #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) -#else - #define JSON_HEDLEY_HAS_EXTENSION(extension) (0) -#endif - -#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION) - #undef JSON_HEDLEY_GNUC_HAS_EXTENSION -#endif -#if defined(__has_extension) - #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) -#else - #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION) - #undef JSON_HEDLEY_GCC_HAS_EXTENSION -#endif -#if defined(__has_extension) - #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) -#else - #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE) - #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE -#endif -#if defined(__has_declspec_attribute) - #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) -#else - #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) -#endif - -#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) - #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE -#endif -#if defined(__has_declspec_attribute) - #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) -#else - #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) - #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE -#endif -#if defined(__has_declspec_attribute) - #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) -#else - #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_HAS_WARNING) - #undef JSON_HEDLEY_HAS_WARNING -#endif -#if defined(__has_warning) - #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) -#else - #define JSON_HEDLEY_HAS_WARNING(warning) (0) -#endif - -#if defined(JSON_HEDLEY_GNUC_HAS_WARNING) - #undef JSON_HEDLEY_GNUC_HAS_WARNING -#endif -#if defined(__has_warning) - #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) -#else - #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_GCC_HAS_WARNING) - #undef JSON_HEDLEY_GCC_HAS_WARNING -#endif -#if defined(__has_warning) - #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) -#else - #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ - defined(__clang__) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ - JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) - #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value) -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) - #define JSON_HEDLEY_PRAGMA(value) __pragma(value) -#else - #define JSON_HEDLEY_PRAGMA(value) -#endif - -#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH) - #undef JSON_HEDLEY_DIAGNOSTIC_PUSH -#endif -#if defined(JSON_HEDLEY_DIAGNOSTIC_POP) - #undef JSON_HEDLEY_DIAGNOSTIC_POP -#endif -#if defined(__clang__) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") - #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") - #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") -#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") - #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) - #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) -#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") - #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") -#elif \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") - #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") - #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") -#else - #define JSON_HEDLEY_DIAGNOSTIC_PUSH - #define JSON_HEDLEY_DIAGNOSTIC_POP -#endif - -/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for - HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ -#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ -#endif -#if defined(__cplusplus) -# if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") -# if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions") -# if JSON_HEDLEY_HAS_WARNING("-Wc++1z-extensions") -# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ - _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ - _Pragma("clang diagnostic ignored \"-Wc++1z-extensions\"") \ - xpr \ - JSON_HEDLEY_DIAGNOSTIC_POP -# else -# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ - _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ - xpr \ - JSON_HEDLEY_DIAGNOSTIC_POP -# endif -# else -# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ - xpr \ - JSON_HEDLEY_DIAGNOSTIC_POP -# endif -# endif -#endif -#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x -#endif - -#if defined(JSON_HEDLEY_CONST_CAST) - #undef JSON_HEDLEY_CONST_CAST -#endif -#if defined(__cplusplus) -# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) -#elif \ - JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ - ((T) (expr)); \ - JSON_HEDLEY_DIAGNOSTIC_POP \ - })) -#else -# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) -#endif - -#if defined(JSON_HEDLEY_REINTERPRET_CAST) - #undef JSON_HEDLEY_REINTERPRET_CAST -#endif -#if defined(__cplusplus) - #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) -#else - #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr)) -#endif - -#if defined(JSON_HEDLEY_STATIC_CAST) - #undef JSON_HEDLEY_STATIC_CAST -#endif -#if defined(__cplusplus) - #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) -#else - #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) -#endif - -#if defined(JSON_HEDLEY_CPP_CAST) - #undef JSON_HEDLEY_CPP_CAST -#endif -#if defined(__cplusplus) -# if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast") -# define JSON_HEDLEY_CPP_CAST(T, expr) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ - ((T) (expr)) \ - JSON_HEDLEY_DIAGNOSTIC_POP -# elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0) -# define JSON_HEDLEY_CPP_CAST(T, expr) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("diag_suppress=Pe137") \ - JSON_HEDLEY_DIAGNOSTIC_POP -# else -# define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr)) -# endif -#else -# define JSON_HEDLEY_CPP_CAST(T, expr) (expr) -#endif - -#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED -#endif -#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") -#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786)) -#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1216,1444,1445") -#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") -#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) -#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") -#elif \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") -#else - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED -#endif - -#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS -#endif -#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") -#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161)) -#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") -#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) -#elif \ - JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") -#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") -#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 161") -#else - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS -#endif - -#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES -#endif -#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") -#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") -#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292)) -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) -#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097,1098") -#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") -#elif \ - JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") -#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") -#else - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES -#endif - -#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL -#endif -#if JSON_HEDLEY_HAS_WARNING("-Wcast-qual") - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") -#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") -#else - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL -#endif - -#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION -#endif -#if JSON_HEDLEY_HAS_WARNING("-Wunused-function") - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("clang diagnostic ignored \"-Wunused-function\"") -#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("GCC diagnostic ignored \"-Wunused-function\"") -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(1,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable:4505)) -#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("diag_suppress 3142") -#else - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION -#endif - -#if defined(JSON_HEDLEY_DEPRECATED) - #undef JSON_HEDLEY_DEPRECATED -#endif -#if defined(JSON_HEDLEY_DEPRECATED_FOR) - #undef JSON_HEDLEY_DEPRECATED_FOR -#endif -#if \ - JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) -#elif \ - (JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) -#elif defined(__cplusplus) && (__cplusplus >= 201402L) - #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) -#elif \ - JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ - JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) - #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ - JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") -#else - #define JSON_HEDLEY_DEPRECATED(since) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) -#endif - -#if defined(JSON_HEDLEY_UNAVAILABLE) - #undef JSON_HEDLEY_UNAVAILABLE -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) -#else - #define JSON_HEDLEY_UNAVAILABLE(available_since) -#endif - -#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) - #undef JSON_HEDLEY_WARN_UNUSED_RESULT -#endif -#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG) - #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) - #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) -#elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) - #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) - #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) -#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) - #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) - #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) -#elif defined(_Check_return_) /* SAL */ - #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ - #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ -#else - #define JSON_HEDLEY_WARN_UNUSED_RESULT - #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) -#endif - -#if defined(JSON_HEDLEY_SENTINEL) - #undef JSON_HEDLEY_SENTINEL -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) -#else - #define JSON_HEDLEY_SENTINEL(position) -#endif - -#if defined(JSON_HEDLEY_NO_RETURN) - #undef JSON_HEDLEY_NO_RETURN -#endif -#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_NO_RETURN __noreturn -#elif \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) -#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L - #define JSON_HEDLEY_NO_RETURN _Noreturn -#elif defined(__cplusplus) && (__cplusplus >= 201103L) - #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) -#elif \ - JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) - #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) - #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) -#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) - #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") -#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) - #define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) - #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) -#else - #define JSON_HEDLEY_NO_RETURN -#endif - -#if defined(JSON_HEDLEY_NO_ESCAPE) - #undef JSON_HEDLEY_NO_ESCAPE -#endif -#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) - #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) -#else - #define JSON_HEDLEY_NO_ESCAPE -#endif - -#if defined(JSON_HEDLEY_UNREACHABLE) - #undef JSON_HEDLEY_UNREACHABLE -#endif -#if defined(JSON_HEDLEY_UNREACHABLE_RETURN) - #undef JSON_HEDLEY_UNREACHABLE_RETURN -#endif -#if defined(JSON_HEDLEY_ASSUME) - #undef JSON_HEDLEY_ASSUME -#endif -#if \ - JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_ASSUME(expr) __assume(expr) -#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) - #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) -#elif \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) - #if defined(__cplusplus) - #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) - #else - #define JSON_HEDLEY_ASSUME(expr) _nassert(expr) - #endif -#endif -#if \ - (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) || \ - JSON_HEDLEY_CRAY_VERSION_CHECK(10,0,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() -#elif defined(JSON_HEDLEY_ASSUME) - #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) -#endif -#if !defined(JSON_HEDLEY_ASSUME) - #if defined(JSON_HEDLEY_UNREACHABLE) - #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1))) - #else - #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr) - #endif -#endif -#if defined(JSON_HEDLEY_UNREACHABLE) - #if \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) - #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value)) - #else - #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() - #endif -#else - #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value) -#endif -#if !defined(JSON_HEDLEY_UNREACHABLE) - #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) -#endif - -JSON_HEDLEY_DIAGNOSTIC_PUSH -#if JSON_HEDLEY_HAS_WARNING("-Wpedantic") - #pragma clang diagnostic ignored "-Wpedantic" -#endif -#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) - #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" -#endif -#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) - #if defined(__clang__) - #pragma clang diagnostic ignored "-Wvariadic-macros" - #elif defined(JSON_HEDLEY_GCC_VERSION) - #pragma GCC diagnostic ignored "-Wvariadic-macros" - #endif -#endif -#if defined(JSON_HEDLEY_NON_NULL) - #undef JSON_HEDLEY_NON_NULL -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) - #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) -#else - #define JSON_HEDLEY_NON_NULL(...) -#endif -JSON_HEDLEY_DIAGNOSTIC_POP - -#if defined(JSON_HEDLEY_PRINTF_FORMAT) - #undef JSON_HEDLEY_PRINTF_FORMAT -#endif -#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) - #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) -#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) - #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) -#elif \ - JSON_HEDLEY_HAS_ATTRIBUTE(format) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) - #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) -#else - #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) -#endif - -#if defined(JSON_HEDLEY_CONSTEXPR) - #undef JSON_HEDLEY_CONSTEXPR -#endif -#if defined(__cplusplus) - #if __cplusplus >= 201103L - #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) - #endif -#endif -#if !defined(JSON_HEDLEY_CONSTEXPR) - #define JSON_HEDLEY_CONSTEXPR -#endif - -#if defined(JSON_HEDLEY_PREDICT) - #undef JSON_HEDLEY_PREDICT -#endif -#if defined(JSON_HEDLEY_LIKELY) - #undef JSON_HEDLEY_LIKELY -#endif -#if defined(JSON_HEDLEY_UNLIKELY) - #undef JSON_HEDLEY_UNLIKELY -#endif -#if defined(JSON_HEDLEY_UNPREDICTABLE) - #undef JSON_HEDLEY_UNPREDICTABLE -#endif -#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) - #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) -#endif -#if \ - (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(JSON_HEDLEY_PGI_VERSION)) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) -# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) -# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) -# define JSON_HEDLEY_LIKELY(expr) __builtin_expect (!!(expr), 1 ) -# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) -#elif \ - (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \ - JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define JSON_HEDLEY_PREDICT(expr, expected, probability) \ - (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))) -# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ - (__extension__ ({ \ - double hedley_probability_ = (probability); \ - ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ - })) -# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ - (__extension__ ({ \ - double hedley_probability_ = (probability); \ - ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ - })) -# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) -# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) -#else -# define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)) -# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) -# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) -# define JSON_HEDLEY_LIKELY(expr) (!!(expr)) -# define JSON_HEDLEY_UNLIKELY(expr) (!!(expr)) -#endif -#if !defined(JSON_HEDLEY_UNPREDICTABLE) - #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5) -#endif - -#if defined(JSON_HEDLEY_MALLOC) - #undef JSON_HEDLEY_MALLOC -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) - #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_MALLOC __declspec(restrict) -#else - #define JSON_HEDLEY_MALLOC -#endif - -#if defined(JSON_HEDLEY_PURE) - #undef JSON_HEDLEY_PURE -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define JSON_HEDLEY_PURE __attribute__((__pure__)) -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) -# define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") -#elif defined(__cplusplus) && \ - ( \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \ - ) -# define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") -#else -# define JSON_HEDLEY_PURE -#endif - -#if defined(JSON_HEDLEY_CONST) - #undef JSON_HEDLEY_CONST -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(const) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_CONST __attribute__((__const__)) -#elif \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) - #define JSON_HEDLEY_CONST _Pragma("no_side_effect") -#else - #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE -#endif - -#if defined(JSON_HEDLEY_RESTRICT) - #undef JSON_HEDLEY_RESTRICT -#endif -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) - #define JSON_HEDLEY_RESTRICT restrict -#elif \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ - JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ - JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ - defined(__clang__) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_RESTRICT __restrict -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) - #define JSON_HEDLEY_RESTRICT _Restrict -#else - #define JSON_HEDLEY_RESTRICT -#endif - -#if defined(JSON_HEDLEY_INLINE) - #undef JSON_HEDLEY_INLINE -#endif -#if \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ - (defined(__cplusplus) && (__cplusplus >= 199711L)) - #define JSON_HEDLEY_INLINE inline -#elif \ - defined(JSON_HEDLEY_GCC_VERSION) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0) - #define JSON_HEDLEY_INLINE __inline__ -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_INLINE __inline -#else - #define JSON_HEDLEY_INLINE -#endif - -#if defined(JSON_HEDLEY_ALWAYS_INLINE) - #undef JSON_HEDLEY_ALWAYS_INLINE -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ - JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) -# define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) -# define JSON_HEDLEY_ALWAYS_INLINE __forceinline -#elif defined(__cplusplus) && \ - ( \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \ - ) -# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) -# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") -#else -# define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE -#endif - -#if defined(JSON_HEDLEY_NEVER_INLINE) - #undef JSON_HEDLEY_NEVER_INLINE -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ - JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) - #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) -#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) - #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") -#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) - #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") -#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) - #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) - #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) -#else - #define JSON_HEDLEY_NEVER_INLINE -#endif - -#if defined(JSON_HEDLEY_PRIVATE) - #undef JSON_HEDLEY_PRIVATE -#endif -#if defined(JSON_HEDLEY_PUBLIC) - #undef JSON_HEDLEY_PUBLIC -#endif -#if defined(JSON_HEDLEY_IMPORT) - #undef JSON_HEDLEY_IMPORT -#endif -#if defined(_WIN32) || defined(__CYGWIN__) -# define JSON_HEDLEY_PRIVATE -# define JSON_HEDLEY_PUBLIC __declspec(dllexport) -# define JSON_HEDLEY_IMPORT __declspec(dllimport) -#else -# if \ - JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ - ( \ - defined(__TI_EABI__) && \ - ( \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \ - ) \ - ) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) -# define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) -# else -# define JSON_HEDLEY_PRIVATE -# define JSON_HEDLEY_PUBLIC -# endif -# define JSON_HEDLEY_IMPORT extern -#endif - -#if defined(JSON_HEDLEY_NO_THROW) - #undef JSON_HEDLEY_NO_THROW -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) - #define JSON_HEDLEY_NO_THROW __declspec(nothrow) -#else - #define JSON_HEDLEY_NO_THROW -#endif - -#if defined(JSON_HEDLEY_FALL_THROUGH) - #undef JSON_HEDLEY_FALL_THROUGH -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) -#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) - #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) -#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) - #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) -#elif defined(__fallthrough) /* SAL */ - #define JSON_HEDLEY_FALL_THROUGH __fallthrough -#else - #define JSON_HEDLEY_FALL_THROUGH -#endif - -#if defined(JSON_HEDLEY_RETURNS_NON_NULL) - #undef JSON_HEDLEY_RETURNS_NON_NULL -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) -#elif defined(_Ret_notnull_) /* SAL */ - #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ -#else - #define JSON_HEDLEY_RETURNS_NON_NULL -#endif - -#if defined(JSON_HEDLEY_ARRAY_PARAM) - #undef JSON_HEDLEY_ARRAY_PARAM -#endif -#if \ - defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ - !defined(__STDC_NO_VLA__) && \ - !defined(__cplusplus) && \ - !defined(JSON_HEDLEY_PGI_VERSION) && \ - !defined(JSON_HEDLEY_TINYC_VERSION) - #define JSON_HEDLEY_ARRAY_PARAM(name) (name) -#else - #define JSON_HEDLEY_ARRAY_PARAM(name) -#endif - -#if defined(JSON_HEDLEY_IS_CONSTANT) - #undef JSON_HEDLEY_IS_CONSTANT -#endif -#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) - #undef JSON_HEDLEY_REQUIRE_CONSTEXPR -#endif -/* JSON_HEDLEY_IS_CONSTEXPR_ is for - HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ -#if defined(JSON_HEDLEY_IS_CONSTEXPR_) - #undef JSON_HEDLEY_IS_CONSTEXPR_ -#endif -#if \ - JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ - (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ - JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) -#endif -#if !defined(__cplusplus) -# if \ - JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ - JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ - JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) -#if defined(__INTPTR_TYPE__) - #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) -#else - #include - #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) -#endif -# elif \ - ( \ - defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ - !defined(JSON_HEDLEY_SUNPRO_VERSION) && \ - !defined(JSON_HEDLEY_PGI_VERSION) && \ - !defined(JSON_HEDLEY_IAR_VERSION)) || \ - (JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) -#if defined(__INTPTR_TYPE__) - #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) -#else - #include - #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) -#endif -# elif \ - defined(JSON_HEDLEY_GCC_VERSION) || \ - defined(JSON_HEDLEY_INTEL_VERSION) || \ - defined(JSON_HEDLEY_TINYC_VERSION) || \ - defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \ - defined(JSON_HEDLEY_TI_CL2000_VERSION) || \ - defined(JSON_HEDLEY_TI_CL6X_VERSION) || \ - defined(JSON_HEDLEY_TI_CL7X_VERSION) || \ - defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \ - defined(__clang__) -# define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ - sizeof(void) != \ - sizeof(*( \ - 1 ? \ - ((void*) ((expr) * 0L) ) : \ -((struct { char v[sizeof(void) * 2]; } *) 1) \ - ) \ - ) \ - ) -# endif -#endif -#if defined(JSON_HEDLEY_IS_CONSTEXPR_) - #if !defined(JSON_HEDLEY_IS_CONSTANT) - #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) - #endif - #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) -#else - #if !defined(JSON_HEDLEY_IS_CONSTANT) - #define JSON_HEDLEY_IS_CONSTANT(expr) (0) - #endif - #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) -#endif - -#if defined(JSON_HEDLEY_BEGIN_C_DECLS) - #undef JSON_HEDLEY_BEGIN_C_DECLS -#endif -#if defined(JSON_HEDLEY_END_C_DECLS) - #undef JSON_HEDLEY_END_C_DECLS -#endif -#if defined(JSON_HEDLEY_C_DECL) - #undef JSON_HEDLEY_C_DECL -#endif -#if defined(__cplusplus) - #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" { - #define JSON_HEDLEY_END_C_DECLS } - #define JSON_HEDLEY_C_DECL extern "C" -#else - #define JSON_HEDLEY_BEGIN_C_DECLS - #define JSON_HEDLEY_END_C_DECLS - #define JSON_HEDLEY_C_DECL -#endif - -#if defined(JSON_HEDLEY_STATIC_ASSERT) - #undef JSON_HEDLEY_STATIC_ASSERT -#endif -#if \ - !defined(__cplusplus) && ( \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ - (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - defined(_Static_assert) \ - ) -# define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) -#elif \ - (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ - JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) -# define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) -#else -# define JSON_HEDLEY_STATIC_ASSERT(expr, message) -#endif - -#if defined(JSON_HEDLEY_NULL) - #undef JSON_HEDLEY_NULL -#endif -#if defined(__cplusplus) - #if __cplusplus >= 201103L - #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) - #elif defined(NULL) - #define JSON_HEDLEY_NULL NULL - #else - #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0) - #endif -#elif defined(NULL) - #define JSON_HEDLEY_NULL NULL -#else - #define JSON_HEDLEY_NULL ((void*) 0) -#endif - -#if defined(JSON_HEDLEY_MESSAGE) - #undef JSON_HEDLEY_MESSAGE -#endif -#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") -# define JSON_HEDLEY_MESSAGE(msg) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ - JSON_HEDLEY_PRAGMA(message msg) \ - JSON_HEDLEY_DIAGNOSTIC_POP -#elif \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) -#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) -# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) -# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0) -# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) -#else -# define JSON_HEDLEY_MESSAGE(msg) -#endif - -#if defined(JSON_HEDLEY_WARNING) - #undef JSON_HEDLEY_WARNING -#endif -#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") -# define JSON_HEDLEY_WARNING(msg) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ - JSON_HEDLEY_PRAGMA(clang warning msg) \ - JSON_HEDLEY_DIAGNOSTIC_POP -#elif \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) -# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) -#else -# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) -#endif - -#if defined(JSON_HEDLEY_REQUIRE) - #undef JSON_HEDLEY_REQUIRE -#endif -#if defined(JSON_HEDLEY_REQUIRE_MSG) - #undef JSON_HEDLEY_REQUIRE_MSG -#endif -#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) -# if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") -# define JSON_HEDLEY_REQUIRE(expr) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ - __attribute__((diagnose_if(!(expr), #expr, "error"))) \ - JSON_HEDLEY_DIAGNOSTIC_POP -# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ - __attribute__((diagnose_if(!(expr), msg, "error"))) \ - JSON_HEDLEY_DIAGNOSTIC_POP -# else -# define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) -# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) -# endif -#else -# define JSON_HEDLEY_REQUIRE(expr) -# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) -#endif - -#if defined(JSON_HEDLEY_FLAGS) - #undef JSON_HEDLEY_FLAGS -#endif -#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) && (!defined(__cplusplus) || JSON_HEDLEY_HAS_WARNING("-Wbitfield-enum-conversion")) - #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) -#else - #define JSON_HEDLEY_FLAGS -#endif - -#if defined(JSON_HEDLEY_FLAGS_CAST) - #undef JSON_HEDLEY_FLAGS_CAST -#endif -#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0) -# define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("warning(disable:188)") \ - ((T) (expr)); \ - JSON_HEDLEY_DIAGNOSTIC_POP \ - })) -#else -# define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) -#endif - -#if defined(JSON_HEDLEY_EMPTY_BASES) - #undef JSON_HEDLEY_EMPTY_BASES -#endif -#if \ - (JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) -#else - #define JSON_HEDLEY_EMPTY_BASES -#endif - -/* Remaining macros are deprecated. */ - -#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) - #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK -#endif -#if defined(__clang__) - #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) -#else - #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE) - #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE -#endif -#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) - -#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) - #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE -#endif -#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) - -#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN) - #undef JSON_HEDLEY_CLANG_HAS_BUILTIN -#endif -#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin) - -#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE) - #undef JSON_HEDLEY_CLANG_HAS_FEATURE -#endif -#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature) - -#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION) - #undef JSON_HEDLEY_CLANG_HAS_EXTENSION -#endif -#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension) - -#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) - #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE -#endif -#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) - -#if defined(JSON_HEDLEY_CLANG_HAS_WARNING) - #undef JSON_HEDLEY_CLANG_HAS_WARNING -#endif -#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning) - -#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ - -// #include - - -#include - -// #include - - -namespace nlohmann -{ -namespace detail -{ -template struct make_void -{ - using type = void; -}; -template using void_t = typename make_void::type; -} // namespace detail -} // namespace nlohmann - - -// https://en.cppreference.com/w/cpp/experimental/is_detected -namespace nlohmann -{ -namespace detail -{ -struct nonesuch -{ - nonesuch() = delete; - ~nonesuch() = delete; - nonesuch(nonesuch const&) = delete; - nonesuch(nonesuch const&&) = delete; - void operator=(nonesuch const&) = delete; - void operator=(nonesuch&&) = delete; -}; - -template class Op, - class... Args> -struct detector -{ - using value_t = std::false_type; - using type = Default; -}; - -template class Op, class... Args> -struct detector>, Op, Args...> -{ - using value_t = std::true_type; - using type = Op; -}; - -template class Op, class... Args> -using is_detected = typename detector::value_t; - -template class Op, class... Args> -struct is_detected_lazy : is_detected { }; - -template class Op, class... Args> -using detected_t = typename detector::type; - -template class Op, class... Args> -using detected_or = detector; - -template class Op, class... Args> -using detected_or_t = typename detected_or::type; - -template class Op, class... Args> -using is_detected_exact = std::is_same>; - -template class Op, class... Args> -using is_detected_convertible = - std::is_convertible, To>; -} // namespace detail -} // namespace nlohmann - - -// This file contains all internal macro definitions -// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them - -// exclude unsupported compilers -#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) - #if defined(__clang__) - #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 - #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" - #endif - #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) - #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 - #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" - #endif - #endif -#endif - -// C++ language standard detection -// if the user manually specified the used c++ version this is skipped -#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) - #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) - #define JSON_HAS_CPP_20 - #define JSON_HAS_CPP_17 - #define JSON_HAS_CPP_14 - #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 - #define JSON_HAS_CPP_17 - #define JSON_HAS_CPP_14 - #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) - #define JSON_HAS_CPP_14 - #endif - // the cpp 11 flag is always specified because it is the minimal required version - #define JSON_HAS_CPP_11 -#endif - -#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM) - #ifdef JSON_HAS_CPP_17 - #if defined(__cpp_lib_filesystem) - #define JSON_HAS_FILESYSTEM 1 - #elif defined(__cpp_lib_experimental_filesystem) - #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 - #elif !defined(__has_include) - #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 - #elif __has_include() - #define JSON_HAS_FILESYSTEM 1 - #elif __has_include() - #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 - #endif - - // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/ - #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8 - #undef JSON_HAS_FILESYSTEM - #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM - #endif - - // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support - #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 8 - #undef JSON_HAS_FILESYSTEM - #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM - #endif - - // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support - #if defined(__clang_major__) && __clang_major__ < 7 - #undef JSON_HAS_FILESYSTEM - #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM - #endif - - // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support - #if defined(_MSC_VER) && _MSC_VER < 1914 - #undef JSON_HAS_FILESYSTEM - #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM - #endif - - // no filesystem support before iOS 13 - #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 - #undef JSON_HAS_FILESYSTEM - #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM - #endif - - // no filesystem support before macOS Catalina - #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 - #undef JSON_HAS_FILESYSTEM - #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM - #endif - #endif -#endif - -#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM - #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0 -#endif - -#ifndef JSON_HAS_FILESYSTEM - #define JSON_HAS_FILESYSTEM 0 -#endif - -// disable documentation warnings on clang -#if defined(__clang__) - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wdocumentation" - #pragma clang diagnostic ignored "-Wdocumentation-unknown-command" -#endif - -// allow disabling exceptions -#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) - #define JSON_THROW(exception) throw exception - #define JSON_TRY try - #define JSON_CATCH(exception) catch(exception) - #define JSON_INTERNAL_CATCH(exception) catch(exception) -#else - #include - #define JSON_THROW(exception) std::abort() - #define JSON_TRY if(true) - #define JSON_CATCH(exception) if(false) - #define JSON_INTERNAL_CATCH(exception) if(false) -#endif - -// override exception macros -#if defined(JSON_THROW_USER) - #undef JSON_THROW - #define JSON_THROW JSON_THROW_USER -#endif -#if defined(JSON_TRY_USER) - #undef JSON_TRY - #define JSON_TRY JSON_TRY_USER -#endif -#if defined(JSON_CATCH_USER) - #undef JSON_CATCH - #define JSON_CATCH JSON_CATCH_USER - #undef JSON_INTERNAL_CATCH - #define JSON_INTERNAL_CATCH JSON_CATCH_USER -#endif -#if defined(JSON_INTERNAL_CATCH_USER) - #undef JSON_INTERNAL_CATCH - #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER -#endif - -// allow overriding assert -#if !defined(JSON_ASSERT) - #include // assert - #define JSON_ASSERT(x) assert(x) -#endif - -// allow to access some private functions (needed by the test suite) -#if defined(JSON_TESTS_PRIVATE) - #define JSON_PRIVATE_UNLESS_TESTED public -#else - #define JSON_PRIVATE_UNLESS_TESTED private -#endif - -/*! -@brief macro to briefly define a mapping between an enum and JSON -@def NLOHMANN_JSON_SERIALIZE_ENUM -@since version 3.4.0 -*/ -#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ - template \ - inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ - { \ - static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ - static const std::pair m[] = __VA_ARGS__; \ - auto it = std::find_if(std::begin(m), std::end(m), \ - [e](const std::pair& ej_pair) -> bool \ - { \ - return ej_pair.first == e; \ - }); \ - j = ((it != std::end(m)) ? it : std::begin(m))->second; \ - } \ - template \ - inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ - { \ - static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ - static const std::pair m[] = __VA_ARGS__; \ - auto it = std::find_if(std::begin(m), std::end(m), \ - [&j](const std::pair& ej_pair) -> bool \ - { \ - return ej_pair.second == j; \ - }); \ - e = ((it != std::end(m)) ? it : std::begin(m))->first; \ - } - -// Ugly macros to avoid uglier copy-paste when specializing basic_json. They -// may be removed in the future once the class is split. - -#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ - template class ObjectType, \ - template class ArrayType, \ - class StringType, class BooleanType, class NumberIntegerType, \ - class NumberUnsignedType, class NumberFloatType, \ - template class AllocatorType, \ - template class JSONSerializer, \ - class BinaryType> - -#define NLOHMANN_BASIC_JSON_TPL \ - basic_json - -// Macros to simplify conversion from/to types - -#define NLOHMANN_JSON_EXPAND( x ) x -#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME -#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \ - NLOHMANN_JSON_PASTE64, \ - NLOHMANN_JSON_PASTE63, \ - NLOHMANN_JSON_PASTE62, \ - NLOHMANN_JSON_PASTE61, \ - NLOHMANN_JSON_PASTE60, \ - NLOHMANN_JSON_PASTE59, \ - NLOHMANN_JSON_PASTE58, \ - NLOHMANN_JSON_PASTE57, \ - NLOHMANN_JSON_PASTE56, \ - NLOHMANN_JSON_PASTE55, \ - NLOHMANN_JSON_PASTE54, \ - NLOHMANN_JSON_PASTE53, \ - NLOHMANN_JSON_PASTE52, \ - NLOHMANN_JSON_PASTE51, \ - NLOHMANN_JSON_PASTE50, \ - NLOHMANN_JSON_PASTE49, \ - NLOHMANN_JSON_PASTE48, \ - NLOHMANN_JSON_PASTE47, \ - NLOHMANN_JSON_PASTE46, \ - NLOHMANN_JSON_PASTE45, \ - NLOHMANN_JSON_PASTE44, \ - NLOHMANN_JSON_PASTE43, \ - NLOHMANN_JSON_PASTE42, \ - NLOHMANN_JSON_PASTE41, \ - NLOHMANN_JSON_PASTE40, \ - NLOHMANN_JSON_PASTE39, \ - NLOHMANN_JSON_PASTE38, \ - NLOHMANN_JSON_PASTE37, \ - NLOHMANN_JSON_PASTE36, \ - NLOHMANN_JSON_PASTE35, \ - NLOHMANN_JSON_PASTE34, \ - NLOHMANN_JSON_PASTE33, \ - NLOHMANN_JSON_PASTE32, \ - NLOHMANN_JSON_PASTE31, \ - NLOHMANN_JSON_PASTE30, \ - NLOHMANN_JSON_PASTE29, \ - NLOHMANN_JSON_PASTE28, \ - NLOHMANN_JSON_PASTE27, \ - NLOHMANN_JSON_PASTE26, \ - NLOHMANN_JSON_PASTE25, \ - NLOHMANN_JSON_PASTE24, \ - NLOHMANN_JSON_PASTE23, \ - NLOHMANN_JSON_PASTE22, \ - NLOHMANN_JSON_PASTE21, \ - NLOHMANN_JSON_PASTE20, \ - NLOHMANN_JSON_PASTE19, \ - NLOHMANN_JSON_PASTE18, \ - NLOHMANN_JSON_PASTE17, \ - NLOHMANN_JSON_PASTE16, \ - NLOHMANN_JSON_PASTE15, \ - NLOHMANN_JSON_PASTE14, \ - NLOHMANN_JSON_PASTE13, \ - NLOHMANN_JSON_PASTE12, \ - NLOHMANN_JSON_PASTE11, \ - NLOHMANN_JSON_PASTE10, \ - NLOHMANN_JSON_PASTE9, \ - NLOHMANN_JSON_PASTE8, \ - NLOHMANN_JSON_PASTE7, \ - NLOHMANN_JSON_PASTE6, \ - NLOHMANN_JSON_PASTE5, \ - NLOHMANN_JSON_PASTE4, \ - NLOHMANN_JSON_PASTE3, \ - NLOHMANN_JSON_PASTE2, \ - NLOHMANN_JSON_PASTE1)(__VA_ARGS__)) -#define NLOHMANN_JSON_PASTE2(func, v1) func(v1) -#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2) -#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3) -#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4) -#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5) -#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6) -#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7) -#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8) -#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9) -#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10) -#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) -#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) -#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) -#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) -#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) -#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) -#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) -#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) -#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) -#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) -#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) -#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) -#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) -#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) -#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) -#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) -#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) -#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) -#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) -#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) -#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) -#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) -#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) -#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) -#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) -#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) -#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) -#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) -#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) -#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) -#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) -#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) -#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) -#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) -#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) -#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) -#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) -#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) -#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) -#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) -#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) -#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) -#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) -#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) -#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) -#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) -#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) -#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) -#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) -#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) -#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) -#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) -#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) - -#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; -#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); - -/*! -@brief macro -@def NLOHMANN_DEFINE_TYPE_INTRUSIVE -@since version 3.9.0 -*/ -#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ - friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ - friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } - -/*! -@brief macro -@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE -@since version 3.9.0 -*/ -#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ - inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ - inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } - - -// inspired from https://stackoverflow.com/a/26745591 -// allows to call any std function as if (e.g. with begin): -// using std::begin; begin(x); -// -// it allows using the detected idiom to retrieve the return type -// of such an expression -#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \ - namespace detail { \ - using std::std_name; \ - \ - template \ - using result_of_##std_name = decltype(std_name(std::declval()...)); \ - } \ - \ - namespace detail2 { \ - struct std_name##_tag \ - { \ - }; \ - \ - template \ - std_name##_tag std_name(T&&...); \ - \ - template \ - using result_of_##std_name = decltype(std_name(std::declval()...)); \ - \ - template \ - struct would_call_std_##std_name \ - { \ - static constexpr auto const value = ::nlohmann::detail:: \ - is_detected_exact::value; \ - }; \ - } /* namespace detail2 */ \ - \ - template \ - struct would_call_std_##std_name : detail2::would_call_std_##std_name \ - { \ - } - -#ifndef JSON_USE_IMPLICIT_CONVERSIONS - #define JSON_USE_IMPLICIT_CONVERSIONS 1 -#endif - -#if JSON_USE_IMPLICIT_CONVERSIONS - #define JSON_EXPLICIT -#else - #define JSON_EXPLICIT explicit -#endif - -#ifndef JSON_DIAGNOSTICS - #define JSON_DIAGNOSTICS 0 -#endif - - -namespace nlohmann -{ -namespace detail -{ - -/*! -@brief replace all occurrences of a substring by another string - -@param[in,out] s the string to manipulate; changed so that all - occurrences of @a f are replaced with @a t -@param[in] f the substring to replace with @a t -@param[in] t the string to replace @a f - -@pre The search string @a f must not be empty. **This precondition is -enforced with an assertion.** - -@since version 2.0.0 -*/ -inline void replace_substring(std::string& s, const std::string& f, - const std::string& t) -{ - JSON_ASSERT(!f.empty()); - for (auto pos = s.find(f); // find first occurrence of f - pos != std::string::npos; // make sure f was found - s.replace(pos, f.size(), t), // replace with t, and - pos = s.find(f, pos + t.size())) // find next occurrence of f - {} -} - -/*! - * @brief string escaping as described in RFC 6901 (Sect. 4) - * @param[in] s string to escape - * @return escaped string - * - * Note the order of escaping "~" to "~0" and "/" to "~1" is important. - */ -inline std::string escape(std::string s) -{ - replace_substring(s, "~", "~0"); - replace_substring(s, "/", "~1"); - return s; -} - -/*! - * @brief string unescaping as described in RFC 6901 (Sect. 4) - * @param[in] s string to unescape - * @return unescaped string - * - * Note the order of escaping "~1" to "/" and "~0" to "~" is important. - */ -static void unescape(std::string& s) -{ - replace_substring(s, "~1", "/"); - replace_substring(s, "~0", "~"); -} - -} // namespace detail -} // namespace nlohmann - -// #include - - -#include // size_t - -namespace nlohmann -{ -namespace detail -{ -/// struct to capture the start position of the current token -struct position_t -{ - /// the total number of characters read - std::size_t chars_read_total = 0; - /// the number of characters read in the current line - std::size_t chars_read_current_line = 0; - /// the number of lines read - std::size_t lines_read = 0; - - /// conversion to size_t to preserve SAX interface - constexpr operator size_t() const - { - return chars_read_total; - } -}; - -} // namespace detail -} // namespace nlohmann - -// #include - - -namespace nlohmann -{ -namespace detail -{ -//////////////// -// exceptions // -//////////////// - -/// @brief general exception of the @ref basic_json class -/// @sa https://json.nlohmann.me/api/basic_json/exception/ -class exception : public std::exception -{ - public: - /// returns the explanatory string - const char* what() const noexcept override - { - return m.what(); - } - - /// the id of the exception - const int id; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes) - - protected: - JSON_HEDLEY_NON_NULL(3) - exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} // NOLINT(bugprone-throw-keyword-missing) - - static std::string name(const std::string& ename, int id_) - { - return "[json.exception." + ename + "." + std::to_string(id_) + "] "; - } - - template - static std::string diagnostics(const BasicJsonType& leaf_element) - { -#if JSON_DIAGNOSTICS - std::vector tokens; - for (const auto* current = &leaf_element; current->m_parent != nullptr; current = current->m_parent) - { - switch (current->m_parent->type()) - { - case value_t::array: - { - for (std::size_t i = 0; i < current->m_parent->m_value.array->size(); ++i) - { - if (¤t->m_parent->m_value.array->operator[](i) == current) - { - tokens.emplace_back(std::to_string(i)); - break; - } - } - break; - } - - case value_t::object: - { - for (const auto& element : *current->m_parent->m_value.object) - { - if (&element.second == current) - { - tokens.emplace_back(element.first.c_str()); - break; - } - } - break; - } - - case value_t::null: // LCOV_EXCL_LINE - case value_t::string: // LCOV_EXCL_LINE - case value_t::boolean: // LCOV_EXCL_LINE - case value_t::number_integer: // LCOV_EXCL_LINE - case value_t::number_unsigned: // LCOV_EXCL_LINE - case value_t::number_float: // LCOV_EXCL_LINE - case value_t::binary: // LCOV_EXCL_LINE - case value_t::discarded: // LCOV_EXCL_LINE - default: // LCOV_EXCL_LINE - break; // LCOV_EXCL_LINE - } - } - - if (tokens.empty()) - { - return ""; - } - - return "(" + std::accumulate(tokens.rbegin(), tokens.rend(), std::string{}, - [](const std::string & a, const std::string & b) - { - return a + "/" + detail::escape(b); - }) + ") "; -#else - static_cast(leaf_element); - return ""; -#endif - } - - private: - /// an exception object as storage for error messages - std::runtime_error m; -}; - -/// @brief exception indicating a parse error -/// @sa https://json.nlohmann.me/api/basic_json/parse_error/ -class parse_error : public exception -{ - public: - /*! - @brief create a parse error exception - @param[in] id_ the id of the exception - @param[in] pos the position where the error occurred (or with - chars_read_total=0 if the position cannot be - determined) - @param[in] what_arg the explanatory string - @return parse_error object - */ - template - static parse_error create(int id_, const position_t& pos, const std::string& what_arg, const BasicJsonType& context) - { - std::string w = exception::name("parse_error", id_) + "parse error" + - position_string(pos) + ": " + exception::diagnostics(context) + what_arg; - return {id_, pos.chars_read_total, w.c_str()}; - } - - template - static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, const BasicJsonType& context) - { - std::string w = exception::name("parse_error", id_) + "parse error" + - (byte_ != 0 ? (" at byte " + std::to_string(byte_)) : "") + - ": " + exception::diagnostics(context) + what_arg; - return {id_, byte_, w.c_str()}; - } - - /*! - @brief byte index of the parse error - - The byte index of the last read character in the input file. - - @note For an input with n bytes, 1 is the index of the first character and - n+1 is the index of the terminating null byte or the end of file. - This also holds true when reading a byte vector (CBOR or MessagePack). - */ - const std::size_t byte; - - private: - parse_error(int id_, std::size_t byte_, const char* what_arg) - : exception(id_, what_arg), byte(byte_) {} - - static std::string position_string(const position_t& pos) - { - return " at line " + std::to_string(pos.lines_read + 1) + - ", column " + std::to_string(pos.chars_read_current_line); - } -}; - -/// @brief exception indicating errors with iterators -/// @sa https://json.nlohmann.me/api/basic_json/invalid_iterator/ -class invalid_iterator : public exception -{ - public: - template - static invalid_iterator create(int id_, const std::string& what_arg, const BasicJsonType& context) - { - std::string w = exception::name("invalid_iterator", id_) + exception::diagnostics(context) + what_arg; - return {id_, w.c_str()}; - } - - private: - JSON_HEDLEY_NON_NULL(3) - invalid_iterator(int id_, const char* what_arg) - : exception(id_, what_arg) {} -}; - -/// @brief exception indicating executing a member function with a wrong type -/// @sa https://json.nlohmann.me/api/basic_json/type_error/ -class type_error : public exception -{ - public: - template - static type_error create(int id_, const std::string& what_arg, const BasicJsonType& context) - { - std::string w = exception::name("type_error", id_) + exception::diagnostics(context) + what_arg; - return {id_, w.c_str()}; - } - - private: - JSON_HEDLEY_NON_NULL(3) - type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; - -/// @brief exception indicating access out of the defined range -/// @sa https://json.nlohmann.me/api/basic_json/out_of_range/ -class out_of_range : public exception -{ - public: - template - static out_of_range create(int id_, const std::string& what_arg, const BasicJsonType& context) - { - std::string w = exception::name("out_of_range", id_) + exception::diagnostics(context) + what_arg; - return {id_, w.c_str()}; - } - - private: - JSON_HEDLEY_NON_NULL(3) - out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; - -/// @brief exception indicating other library errors -/// @sa https://json.nlohmann.me/api/basic_json/other_error/ -class other_error : public exception -{ - public: - template - static other_error create(int id_, const std::string& what_arg, const BasicJsonType& context) - { - std::string w = exception::name("other_error", id_) + exception::diagnostics(context) + what_arg; - return {id_, w.c_str()}; - } - - private: - JSON_HEDLEY_NON_NULL(3) - other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; - -} // namespace detail -} // namespace nlohmann - -// #include - -// #include - - -#include // size_t -#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type -#include // index_sequence, make_index_sequence, index_sequence_for - -// #include - - -namespace nlohmann -{ -namespace detail -{ - -template -using uncvref_t = typename std::remove_cv::type>::type; - -#ifdef JSON_HAS_CPP_14 - -// the following utilities are natively available in C++14 -using std::enable_if_t; -using std::index_sequence; -using std::make_index_sequence; -using std::index_sequence_for; - -#else - -// alias templates to reduce boilerplate -template -using enable_if_t = typename std::enable_if::type; - -// The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h -// which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0. - -//// START OF CODE FROM GOOGLE ABSEIL - -// integer_sequence -// -// Class template representing a compile-time integer sequence. An instantiation -// of `integer_sequence` has a sequence of integers encoded in its -// type through its template arguments (which is a common need when -// working with C++11 variadic templates). `absl::integer_sequence` is designed -// to be a drop-in replacement for C++14's `std::integer_sequence`. -// -// Example: -// -// template< class T, T... Ints > -// void user_function(integer_sequence); -// -// int main() -// { -// // user_function's `T` will be deduced to `int` and `Ints...` -// // will be deduced to `0, 1, 2, 3, 4`. -// user_function(make_integer_sequence()); -// } -template -struct integer_sequence -{ - using value_type = T; - static constexpr std::size_t size() noexcept - { - return sizeof...(Ints); - } -}; - -// index_sequence -// -// A helper template for an `integer_sequence` of `size_t`, -// `absl::index_sequence` is designed to be a drop-in replacement for C++14's -// `std::index_sequence`. -template -using index_sequence = integer_sequence; - -namespace utility_internal -{ - -template -struct Extend; - -// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency. -template -struct Extend, SeqSize, 0> -{ - using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >; -}; - -template -struct Extend, SeqSize, 1> -{ - using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >; -}; - -// Recursion helper for 'make_integer_sequence'. -// 'Gen::type' is an alias for 'integer_sequence'. -template -struct Gen -{ - using type = - typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type; -}; - -template -struct Gen -{ - using type = integer_sequence; -}; - -} // namespace utility_internal - -// Compile-time sequences of integers - -// make_integer_sequence -// -// This template alias is equivalent to -// `integer_sequence`, and is designed to be a drop-in -// replacement for C++14's `std::make_integer_sequence`. -template -using make_integer_sequence = typename utility_internal::Gen::type; - -// make_index_sequence -// -// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`, -// and is designed to be a drop-in replacement for C++14's -// `std::make_index_sequence`. -template -using make_index_sequence = make_integer_sequence; - -// index_sequence_for -// -// Converts a typename pack into an index sequence of the same length, and -// is designed to be a drop-in replacement for C++14's -// `std::index_sequence_for()` -template -using index_sequence_for = make_index_sequence; - -//// END OF CODE FROM GOOGLE ABSEIL - -#endif - -// dispatch utility (taken from ranges-v3) -template struct priority_tag : priority_tag < N - 1 > {}; -template<> struct priority_tag<0> {}; - -// taken from ranges-v3 -template -struct static_const -{ - static constexpr T value{}; -}; - -template -constexpr T static_const::value; // NOLINT(readability-redundant-declaration) - -} // namespace detail -} // namespace nlohmann - -// #include - - -namespace nlohmann -{ -namespace detail -{ -// dispatching helper struct -template struct identity_tag {}; -} // namespace detail -} // namespace nlohmann - -// #include - - -#include // numeric_limits -#include // false_type, is_constructible, is_integral, is_same, true_type -#include // declval -#include // tuple - -// #include - - -// #include - - -#include // random_access_iterator_tag - -// #include - -// #include - - -namespace nlohmann -{ -namespace detail -{ -template -struct iterator_types {}; - -template -struct iterator_types < - It, - void_t> -{ - using difference_type = typename It::difference_type; - using value_type = typename It::value_type; - using pointer = typename It::pointer; - using reference = typename It::reference; - using iterator_category = typename It::iterator_category; -}; - -// This is required as some compilers implement std::iterator_traits in a way that -// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. -template -struct iterator_traits -{ -}; - -template -struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> - : iterator_types -{ -}; - -template -struct iterator_traits::value>> -{ - using iterator_category = std::random_access_iterator_tag; - using value_type = T; - using difference_type = ptrdiff_t; - using pointer = T*; - using reference = T&; -}; -} // namespace detail -} // namespace nlohmann - -// #include - - -// #include - - -namespace nlohmann -{ -NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin); -} // namespace nlohmann - -// #include - - -// #include - - -namespace nlohmann -{ -NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end); -} // namespace nlohmann - -// #include - -// #include - -// #include -#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ -#define INCLUDE_NLOHMANN_JSON_FWD_HPP_ - -#include // int64_t, uint64_t -#include // map -#include // allocator -#include // string -#include // vector - -/*! -@brief namespace for Niels Lohmann -@see https://github.com/nlohmann -@since version 1.0.0 -*/ -namespace nlohmann -{ -/*! -@brief default JSONSerializer template argument - -This serializer ignores the template arguments and uses ADL -([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) -for serialization. -*/ -template -struct adl_serializer; - -/// a class to store JSON values -/// @sa https://json.nlohmann.me/api/basic_json/ -template class ObjectType = - std::map, - template class ArrayType = std::vector, - class StringType = std::string, class BooleanType = bool, - class NumberIntegerType = std::int64_t, - class NumberUnsignedType = std::uint64_t, - class NumberFloatType = double, - template class AllocatorType = std::allocator, - template class JSONSerializer = - adl_serializer, - class BinaryType = std::vector> -class basic_json; - -/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document -/// @sa https://json.nlohmann.me/api/json_pointer/ -template -class json_pointer; - -/*! -@brief default specialization -@sa https://json.nlohmann.me/api/json/ -*/ -using json = basic_json<>; - -/// @brief a minimal map-like container that preserves insertion order -/// @sa https://json.nlohmann.me/api/ordered_map/ -template -struct ordered_map; - -/// @brief specialization that maintains the insertion order of object keys -/// @sa https://json.nlohmann.me/api/ordered_json/ -using ordered_json = basic_json; - -} // namespace nlohmann - -#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ - - -namespace nlohmann -{ -/*! -@brief detail namespace with internal helper functions - -This namespace collects functions that should not be exposed, -implementations of some @ref basic_json methods, and meta-programming helpers. - -@since version 2.1.0 -*/ -namespace detail -{ -///////////// -// helpers // -///////////// - -// Note to maintainers: -// -// Every trait in this file expects a non CV-qualified type. -// The only exceptions are in the 'aliases for detected' section -// (i.e. those of the form: decltype(T::member_function(std::declval()))) -// -// In this case, T has to be properly CV-qualified to constraint the function arguments -// (e.g. to_json(BasicJsonType&, const T&)) - -template struct is_basic_json : std::false_type {}; - -NLOHMANN_BASIC_JSON_TPL_DECLARATION -struct is_basic_json : std::true_type {}; - -////////////////////// -// json_ref helpers // -////////////////////// - -template -class json_ref; - -template -struct is_json_ref : std::false_type {}; - -template -struct is_json_ref> : std::true_type {}; - -////////////////////////// -// aliases for detected // -////////////////////////// - -template -using mapped_type_t = typename T::mapped_type; - -template -using key_type_t = typename T::key_type; - -template -using value_type_t = typename T::value_type; - -template -using difference_type_t = typename T::difference_type; - -template -using pointer_t = typename T::pointer; - -template -using reference_t = typename T::reference; - -template -using iterator_category_t = typename T::iterator_category; - -template -using to_json_function = decltype(T::to_json(std::declval()...)); - -template -using from_json_function = decltype(T::from_json(std::declval()...)); - -template -using get_template_function = decltype(std::declval().template get()); - -// trait checking if JSONSerializer::from_json(json const&, udt&) exists -template -struct has_from_json : std::false_type {}; - -// trait checking if j.get is valid -// use this trait instead of std::is_constructible or std::is_convertible, -// both rely on, or make use of implicit conversions, and thus fail when T -// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958) -template -struct is_getable -{ - static constexpr bool value = is_detected::value; -}; - -template -struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> -{ - using serializer = typename BasicJsonType::template json_serializer; - - static constexpr bool value = - is_detected_exact::value; -}; - -// This trait checks if JSONSerializer::from_json(json const&) exists -// this overload is used for non-default-constructible user-defined-types -template -struct has_non_default_from_json : std::false_type {}; - -template -struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> -{ - using serializer = typename BasicJsonType::template json_serializer; - - static constexpr bool value = - is_detected_exact::value; -}; - -// This trait checks if BasicJsonType::json_serializer::to_json exists -// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. -template -struct has_to_json : std::false_type {}; - -template -struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> -{ - using serializer = typename BasicJsonType::template json_serializer; - - static constexpr bool value = - is_detected_exact::value; -}; - - -/////////////////// -// is_ functions // -/////////////////// - -// https://en.cppreference.com/w/cpp/types/conjunction -template struct conjunction : std::true_type { }; -template struct conjunction : B1 { }; -template -struct conjunction -: std::conditional, B1>::type {}; - -// https://en.cppreference.com/w/cpp/types/negation -template struct negation : std::integral_constant < bool, !B::value > { }; - -// Reimplementation of is_constructible and is_default_constructible, due to them being broken for -// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367). -// This causes compile errors in e.g. clang 3.5 or gcc 4.9. -template -struct is_default_constructible : std::is_default_constructible {}; - -template -struct is_default_constructible> - : conjunction, is_default_constructible> {}; - -template -struct is_default_constructible> - : conjunction, is_default_constructible> {}; - -template -struct is_default_constructible> - : conjunction...> {}; - -template -struct is_default_constructible> - : conjunction...> {}; - - -template -struct is_constructible : std::is_constructible {}; - -template -struct is_constructible> : is_default_constructible> {}; - -template -struct is_constructible> : is_default_constructible> {}; - -template -struct is_constructible> : is_default_constructible> {}; - -template -struct is_constructible> : is_default_constructible> {}; - - -template -struct is_iterator_traits : std::false_type {}; - -template -struct is_iterator_traits> -{ - private: - using traits = iterator_traits; - - public: - static constexpr auto value = - is_detected::value && - is_detected::value && - is_detected::value && - is_detected::value && - is_detected::value; -}; - -template -struct is_range -{ - private: - using t_ref = typename std::add_lvalue_reference::type; - - using iterator = detected_t; - using sentinel = detected_t; - - // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator - // and https://en.cppreference.com/w/cpp/iterator/sentinel_for - // but reimplementing these would be too much work, as a lot of other concepts are used underneath - static constexpr auto is_iterator_begin = - is_iterator_traits>::value; - - public: - static constexpr bool value = !std::is_same::value && !std::is_same::value && is_iterator_begin; -}; - -template -using iterator_t = enable_if_t::value, result_of_begin())>>; - -template -using range_value_t = value_type_t>>; - -// The following implementation of is_complete_type is taken from -// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ -// and is written by Xiang Fan who agreed to using it in this library. - -template -struct is_complete_type : std::false_type {}; - -template -struct is_complete_type : std::true_type {}; - -template -struct is_compatible_object_type_impl : std::false_type {}; - -template -struct is_compatible_object_type_impl < - BasicJsonType, CompatibleObjectType, - enable_if_t < is_detected::value&& - is_detected::value >> -{ - using object_t = typename BasicJsonType::object_t; - - // macOS's is_constructible does not play well with nonesuch... - static constexpr bool value = - is_constructible::value && - is_constructible::value; -}; - -template -struct is_compatible_object_type - : is_compatible_object_type_impl {}; - -template -struct is_constructible_object_type_impl : std::false_type {}; - -template -struct is_constructible_object_type_impl < - BasicJsonType, ConstructibleObjectType, - enable_if_t < is_detected::value&& - is_detected::value >> -{ - using object_t = typename BasicJsonType::object_t; - - static constexpr bool value = - (is_default_constructible::value && - (std::is_move_assignable::value || - std::is_copy_assignable::value) && - (is_constructible::value && - std::is_same < - typename object_t::mapped_type, - typename ConstructibleObjectType::mapped_type >::value)) || - (has_from_json::value || - has_non_default_from_json < - BasicJsonType, - typename ConstructibleObjectType::mapped_type >::value); -}; - -template -struct is_constructible_object_type - : is_constructible_object_type_impl {}; - -template -struct is_compatible_string_type -{ - static constexpr auto value = - is_constructible::value; -}; - -template -struct is_constructible_string_type -{ - static constexpr auto value = - is_constructible::value; -}; - -template -struct is_compatible_array_type_impl : std::false_type {}; - -template -struct is_compatible_array_type_impl < - BasicJsonType, CompatibleArrayType, - enable_if_t < - is_detected::value&& - is_iterator_traits>>::value&& -// special case for types like std::filesystem::path whose iterator's value_type are themselves -// c.f. https://github.com/nlohmann/json/pull/3073 - !std::is_same>::value >> -{ - static constexpr bool value = - is_constructible>::value; -}; - -template -struct is_compatible_array_type - : is_compatible_array_type_impl {}; - -template -struct is_constructible_array_type_impl : std::false_type {}; - -template -struct is_constructible_array_type_impl < - BasicJsonType, ConstructibleArrayType, - enable_if_t::value >> - : std::true_type {}; - -template -struct is_constructible_array_type_impl < - BasicJsonType, ConstructibleArrayType, - enable_if_t < !std::is_same::value&& - !is_compatible_string_type::value&& - is_default_constructible::value&& -(std::is_move_assignable::value || - std::is_copy_assignable::value)&& -is_detected::value&& -is_iterator_traits>>::value&& -is_detected::value&& -// special case for types like std::filesystem::path whose iterator's value_type are themselves -// c.f. https://github.com/nlohmann/json/pull/3073 -!std::is_same>::value&& - is_complete_type < - detected_t>::value >> -{ - using value_type = range_value_t; - - static constexpr bool value = - std::is_same::value || - has_from_json::value || - has_non_default_from_json < - BasicJsonType, - value_type >::value; -}; - -template -struct is_constructible_array_type - : is_constructible_array_type_impl {}; - -template -struct is_compatible_integer_type_impl : std::false_type {}; - -template -struct is_compatible_integer_type_impl < - RealIntegerType, CompatibleNumberIntegerType, - enable_if_t < std::is_integral::value&& - std::is_integral::value&& - !std::is_same::value >> -{ - // is there an assert somewhere on overflows? - using RealLimits = std::numeric_limits; - using CompatibleLimits = std::numeric_limits; - - static constexpr auto value = - is_constructible::value && - CompatibleLimits::is_integer && - RealLimits::is_signed == CompatibleLimits::is_signed; -}; - -template -struct is_compatible_integer_type - : is_compatible_integer_type_impl {}; - -template -struct is_compatible_type_impl: std::false_type {}; - -template -struct is_compatible_type_impl < - BasicJsonType, CompatibleType, - enable_if_t::value >> -{ - static constexpr bool value = - has_to_json::value; -}; - -template -struct is_compatible_type - : is_compatible_type_impl {}; - -template -struct is_constructible_tuple : std::false_type {}; - -template -struct is_constructible_tuple> : conjunction...> {}; - -// a naive helper to check if a type is an ordered_map (exploits the fact that -// ordered_map inherits capacity() from std::vector) -template -struct is_ordered_map -{ - using one = char; - - struct two - { - char x[2]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - }; - - template static one test( decltype(&C::capacity) ) ; - template static two test(...); - - enum { value = sizeof(test(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) -}; - -// to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324) -template < typename T, typename U, enable_if_t < !std::is_same::value, int > = 0 > -T conditional_static_cast(U value) -{ - return static_cast(value); -} - -template::value, int> = 0> -T conditional_static_cast(U value) -{ - return value; -} - -} // namespace detail -} // namespace nlohmann - -// #include - - -#if JSON_HAS_EXPERIMENTAL_FILESYSTEM -#include -namespace nlohmann::detail -{ -namespace std_fs = std::experimental::filesystem; -} // namespace nlohmann::detail -#elif JSON_HAS_FILESYSTEM -#include -namespace nlohmann::detail -{ -namespace std_fs = std::filesystem; -} // namespace nlohmann::detail -#endif - -namespace nlohmann -{ -namespace detail -{ -template -void from_json(const BasicJsonType& j, typename std::nullptr_t& n) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_null())) - { - JSON_THROW(type_error::create(302, "type must be null, but is " + std::string(j.type_name()), j)); - } - n = nullptr; -} - -// overloads for basic_json template parameters -template < typename BasicJsonType, typename ArithmeticType, - enable_if_t < std::is_arithmetic::value&& - !std::is_same::value, - int > = 0 > -void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) -{ - switch (static_cast(j)) - { - case value_t::number_unsigned: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::number_integer: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::number_float: - { - val = static_cast(*j.template get_ptr()); - break; - } - - case value_t::null: - case value_t::object: - case value_t::array: - case value_t::string: - case value_t::boolean: - case value_t::binary: - case value_t::discarded: - default: - JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()), j)); - } -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_boolean())) - { - JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()), j)); - } - b = *j.template get_ptr(); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_string())) - { - JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()), j)); - } - s = *j.template get_ptr(); -} - -template < - typename BasicJsonType, typename ConstructibleStringType, - enable_if_t < - is_constructible_string_type::value&& - !std::is_same::value, - int > = 0 > -void from_json(const BasicJsonType& j, ConstructibleStringType& s) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_string())) - { - JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()), j)); - } - - s = *j.template get_ptr(); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) -{ - get_arithmetic_value(j, val); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) -{ - get_arithmetic_value(j, val); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) -{ - get_arithmetic_value(j, val); -} - -template::value, int> = 0> -void from_json(const BasicJsonType& j, EnumType& e) -{ - typename std::underlying_type::type val; - get_arithmetic_value(j, val); - e = static_cast(val); -} - -// forward_list doesn't have an insert method -template::value, int> = 0> -void from_json(const BasicJsonType& j, std::forward_list& l) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); - } - l.clear(); - std::transform(j.rbegin(), j.rend(), - std::front_inserter(l), [](const BasicJsonType & i) - { - return i.template get(); - }); -} - -// valarray doesn't have an insert method -template::value, int> = 0> -void from_json(const BasicJsonType& j, std::valarray& l) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); - } - l.resize(j.size()); - std::transform(j.begin(), j.end(), std::begin(l), - [](const BasicJsonType & elem) - { - return elem.template get(); - }); -} - -template -auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) --> decltype(j.template get(), void()) -{ - for (std::size_t i = 0; i < N; ++i) - { - arr[i] = j.at(i).template get(); - } -} - -template -void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/) -{ - arr = *j.template get_ptr(); -} - -template -auto from_json_array_impl(const BasicJsonType& j, std::array& arr, - priority_tag<2> /*unused*/) --> decltype(j.template get(), void()) -{ - for (std::size_t i = 0; i < N; ++i) - { - arr[i] = j.at(i).template get(); - } -} - -template::value, - int> = 0> -auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/) --> decltype( - arr.reserve(std::declval()), - j.template get(), - void()) -{ - using std::end; - - ConstructibleArrayType ret; - ret.reserve(j.size()); - std::transform(j.begin(), j.end(), - std::inserter(ret, end(ret)), [](const BasicJsonType & i) - { - // get() returns *this, this won't call a from_json - // method when value_type is BasicJsonType - return i.template get(); - }); - arr = std::move(ret); -} - -template::value, - int> = 0> -void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, - priority_tag<0> /*unused*/) -{ - using std::end; - - ConstructibleArrayType ret; - std::transform( - j.begin(), j.end(), std::inserter(ret, end(ret)), - [](const BasicJsonType & i) - { - // get() returns *this, this won't call a from_json - // method when value_type is BasicJsonType - return i.template get(); - }); - arr = std::move(ret); -} - -template < typename BasicJsonType, typename ConstructibleArrayType, - enable_if_t < - is_constructible_array_type::value&& - !is_constructible_object_type::value&& - !is_constructible_string_type::value&& - !std::is_same::value&& - !is_basic_json::value, - int > = 0 > -auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr) --> decltype(from_json_array_impl(j, arr, priority_tag<3> {}), -j.template get(), -void()) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); - } - - from_json_array_impl(j, arr, priority_tag<3> {}); -} - -template < typename BasicJsonType, typename T, std::size_t... Idx > -std::array from_json_inplace_array_impl(BasicJsonType&& j, - identity_tag> /*unused*/, index_sequence /*unused*/) -{ - return { { std::forward(j).at(Idx).template get()... } }; -} - -template < typename BasicJsonType, typename T, std::size_t N > -auto from_json(BasicJsonType&& j, identity_tag> tag) --> decltype(from_json_inplace_array_impl(std::forward(j), tag, make_index_sequence {})) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); - } - - return from_json_inplace_array_impl(std::forward(j), tag, make_index_sequence {}); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_binary())) - { - JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(j.type_name()), j)); - } - - bin = *j.template get_ptr(); -} - -template::value, int> = 0> -void from_json(const BasicJsonType& j, ConstructibleObjectType& obj) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_object())) - { - JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()), j)); - } - - ConstructibleObjectType ret; - const auto* inner_object = j.template get_ptr(); - using value_type = typename ConstructibleObjectType::value_type; - std::transform( - inner_object->begin(), inner_object->end(), - std::inserter(ret, ret.begin()), - [](typename BasicJsonType::object_t::value_type const & p) - { - return value_type(p.first, p.second.template get()); - }); - obj = std::move(ret); -} - -// overload for arithmetic types, not chosen for basic_json template arguments -// (BooleanType, etc..); note: Is it really necessary to provide explicit -// overloads for boolean_t etc. in case of a custom BooleanType which is not -// an arithmetic type? -template < typename BasicJsonType, typename ArithmeticType, - enable_if_t < - std::is_arithmetic::value&& - !std::is_same::value&& - !std::is_same::value&& - !std::is_same::value&& - !std::is_same::value, - int > = 0 > -void from_json(const BasicJsonType& j, ArithmeticType& val) -{ - switch (static_cast(j)) - { - case value_t::number_unsigned: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::number_integer: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::number_float: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::boolean: - { - val = static_cast(*j.template get_ptr()); - break; - } - - case value_t::null: - case value_t::object: - case value_t::array: - case value_t::string: - case value_t::binary: - case value_t::discarded: - default: - JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()), j)); - } -} - -template -std::tuple from_json_tuple_impl_base(BasicJsonType&& j, index_sequence /*unused*/) -{ - return std::make_tuple(std::forward(j).at(Idx).template get()...); -} - -template < typename BasicJsonType, class A1, class A2 > -std::pair from_json_tuple_impl(BasicJsonType&& j, identity_tag> /*unused*/, priority_tag<0> /*unused*/) -{ - return {std::forward(j).at(0).template get(), - std::forward(j).at(1).template get()}; -} - -template -void from_json_tuple_impl(BasicJsonType&& j, std::pair& p, priority_tag<1> /*unused*/) -{ - p = from_json_tuple_impl(std::forward(j), identity_tag> {}, priority_tag<0> {}); -} - -template -std::tuple from_json_tuple_impl(BasicJsonType&& j, identity_tag> /*unused*/, priority_tag<2> /*unused*/) -{ - return from_json_tuple_impl_base(std::forward(j), index_sequence_for {}); -} - -template -void from_json_tuple_impl(BasicJsonType&& j, std::tuple& t, priority_tag<3> /*unused*/) -{ - t = from_json_tuple_impl_base(std::forward(j), index_sequence_for {}); -} - -template -auto from_json(BasicJsonType&& j, TupleRelated&& t) --> decltype(from_json_tuple_impl(std::forward(j), std::forward(t), priority_tag<3> {})) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); - } - - return from_json_tuple_impl(std::forward(j), std::forward(t), priority_tag<3> {}); -} - -template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator, - typename = enable_if_t < !std::is_constructible < - typename BasicJsonType::string_t, Key >::value >> -void from_json(const BasicJsonType& j, std::map& m) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); - } - m.clear(); - for (const auto& p : j) - { - if (JSON_HEDLEY_UNLIKELY(!p.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()), j)); - } - m.emplace(p.at(0).template get(), p.at(1).template get()); - } -} - -template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator, - typename = enable_if_t < !std::is_constructible < - typename BasicJsonType::string_t, Key >::value >> -void from_json(const BasicJsonType& j, std::unordered_map& m) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); - } - m.clear(); - for (const auto& p : j) - { - if (JSON_HEDLEY_UNLIKELY(!p.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()), j)); - } - m.emplace(p.at(0).template get(), p.at(1).template get()); - } -} - -#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM -template -void from_json(const BasicJsonType& j, std_fs::path& p) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_string())) - { - JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()), j)); - } - p = *j.template get_ptr(); -} -#endif - -struct from_json_fn -{ - template - auto operator()(const BasicJsonType& j, T&& val) const - noexcept(noexcept(from_json(j, std::forward(val)))) - -> decltype(from_json(j, std::forward(val))) - { - return from_json(j, std::forward(val)); - } -}; -} // namespace detail - -/// namespace to hold default `from_json` function -/// to see why this is required: -/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html -namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces) -{ -constexpr const auto& from_json = detail::static_const::value; // NOLINT(misc-definitions-in-headers) -} // namespace -} // namespace nlohmann - -// #include - - -#include // copy -#include // begin, end -#include // string -#include // tuple, get -#include // is_same, is_constructible, is_floating_point, is_enum, underlying_type -#include // move, forward, declval, pair -#include // valarray -#include // vector - -// #include - -// #include - - -#include // size_t -#include // input_iterator_tag -#include // string, to_string -#include // tuple_size, get, tuple_element -#include // move - -// #include - -// #include - - -namespace nlohmann -{ -namespace detail -{ -template -void int_to_string( string_type& target, std::size_t value ) -{ - // For ADL - using std::to_string; - target = to_string(value); -} -template class iteration_proxy_value -{ - public: - using difference_type = std::ptrdiff_t; - using value_type = iteration_proxy_value; - using pointer = value_type * ; - using reference = value_type & ; - using iterator_category = std::input_iterator_tag; - using string_type = typename std::remove_cv< typename std::remove_reference().key() ) >::type >::type; - - private: - /// the iterator - IteratorType anchor; - /// an index for arrays (used to create key names) - std::size_t array_index = 0; - /// last stringified array index - mutable std::size_t array_index_last = 0; - /// a string representation of the array index - mutable string_type array_index_str = "0"; - /// an empty string (to return a reference for primitive values) - const string_type empty_str{}; - - public: - explicit iteration_proxy_value(IteratorType it) noexcept - : anchor(std::move(it)) - {} - - /// dereference operator (needed for range-based for) - iteration_proxy_value& operator*() - { - return *this; - } - - /// increment operator (needed for range-based for) - iteration_proxy_value& operator++() - { - ++anchor; - ++array_index; - - return *this; - } - - /// equality operator (needed for InputIterator) - bool operator==(const iteration_proxy_value& o) const - { - return anchor == o.anchor; - } - - /// inequality operator (needed for range-based for) - bool operator!=(const iteration_proxy_value& o) const - { - return anchor != o.anchor; - } - - /// return key of the iterator - const string_type& key() const - { - JSON_ASSERT(anchor.m_object != nullptr); - - switch (anchor.m_object->type()) - { - // use integer array index as key - case value_t::array: - { - if (array_index != array_index_last) - { - int_to_string( array_index_str, array_index ); - array_index_last = array_index; - } - return array_index_str; - } - - // use key from the object - case value_t::object: - return anchor.key(); - - // use an empty key for all primitive types - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - return empty_str; - } - } - - /// return value of the iterator - typename IteratorType::reference value() const - { - return anchor.value(); - } -}; - -/// proxy class for the items() function -template class iteration_proxy -{ - private: - /// the container to iterate - typename IteratorType::reference container; - - public: - /// construct iteration proxy from a container - explicit iteration_proxy(typename IteratorType::reference cont) noexcept - : container(cont) {} - - /// return iterator begin (needed for range-based for) - iteration_proxy_value begin() noexcept - { - return iteration_proxy_value(container.begin()); - } - - /// return iterator end (needed for range-based for) - iteration_proxy_value end() noexcept - { - return iteration_proxy_value(container.end()); - } -}; -// Structured Bindings Support -// For further reference see https://blog.tartanllama.xyz/structured-bindings/ -// And see https://github.com/nlohmann/json/pull/1391 -template = 0> -auto get(const nlohmann::detail::iteration_proxy_value& i) -> decltype(i.key()) -{ - return i.key(); -} -// Structured Bindings Support -// For further reference see https://blog.tartanllama.xyz/structured-bindings/ -// And see https://github.com/nlohmann/json/pull/1391 -template = 0> -auto get(const nlohmann::detail::iteration_proxy_value& i) -> decltype(i.value()) -{ - return i.value(); -} -} // namespace detail -} // namespace nlohmann - -// The Addition to the STD Namespace is required to add -// Structured Bindings Support to the iteration_proxy_value class -// For further reference see https://blog.tartanllama.xyz/structured-bindings/ -// And see https://github.com/nlohmann/json/pull/1391 -namespace std -{ -#if defined(__clang__) - // Fix: https://github.com/nlohmann/json/issues/1401 - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wmismatched-tags" -#endif -template -class tuple_size<::nlohmann::detail::iteration_proxy_value> - : public std::integral_constant {}; - -template -class tuple_element> -{ - public: - using type = decltype( - get(std::declval < - ::nlohmann::detail::iteration_proxy_value> ())); -}; -#if defined(__clang__) - #pragma clang diagnostic pop -#endif -} // namespace std - -// #include - -// #include - -// #include - - -#if JSON_HAS_EXPERIMENTAL_FILESYSTEM -#include -namespace nlohmann::detail -{ -namespace std_fs = std::experimental::filesystem; -} // namespace nlohmann::detail -#elif JSON_HAS_FILESYSTEM -#include -namespace nlohmann::detail -{ -namespace std_fs = std::filesystem; -} // namespace nlohmann::detail -#endif - -namespace nlohmann -{ -namespace detail -{ -////////////////// -// constructors // -////////////////// - -/* - * Note all external_constructor<>::construct functions need to call - * j.m_value.destroy(j.m_type) to avoid a memory leak in case j contains an - * allocated value (e.g., a string). See bug issue - * https://github.com/nlohmann/json/issues/2865 for more information. - */ - -template struct external_constructor; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept - { - j.m_value.destroy(j.m_type); - j.m_type = value_t::boolean; - j.m_value = b; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) - { - j.m_value.destroy(j.m_type); - j.m_type = value_t::string; - j.m_value = s; - j.assert_invariant(); - } - - template - static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) - { - j.m_value.destroy(j.m_type); - j.m_type = value_t::string; - j.m_value = std::move(s); - j.assert_invariant(); - } - - template < typename BasicJsonType, typename CompatibleStringType, - enable_if_t < !std::is_same::value, - int > = 0 > - static void construct(BasicJsonType& j, const CompatibleStringType& str) - { - j.m_value.destroy(j.m_type); - j.m_type = value_t::string; - j.m_value.string = j.template create(str); - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b) - { - j.m_value.destroy(j.m_type); - j.m_type = value_t::binary; - j.m_value = typename BasicJsonType::binary_t(b); - j.assert_invariant(); - } - - template - static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b) - { - j.m_value.destroy(j.m_type); - j.m_type = value_t::binary; - j.m_value = typename BasicJsonType::binary_t(std::move(b)); - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept - { - j.m_value.destroy(j.m_type); - j.m_type = value_t::number_float; - j.m_value = val; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept - { - j.m_value.destroy(j.m_type); - j.m_type = value_t::number_unsigned; - j.m_value = val; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept - { - j.m_value.destroy(j.m_type); - j.m_type = value_t::number_integer; - j.m_value = val; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) - { - j.m_value.destroy(j.m_type); - j.m_type = value_t::array; - j.m_value = arr; - j.set_parents(); - j.assert_invariant(); - } - - template - static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) - { - j.m_value.destroy(j.m_type); - j.m_type = value_t::array; - j.m_value = std::move(arr); - j.set_parents(); - j.assert_invariant(); - } - - template < typename BasicJsonType, typename CompatibleArrayType, - enable_if_t < !std::is_same::value, - int > = 0 > - static void construct(BasicJsonType& j, const CompatibleArrayType& arr) - { - using std::begin; - using std::end; - - j.m_value.destroy(j.m_type); - j.m_type = value_t::array; - j.m_value.array = j.template create(begin(arr), end(arr)); - j.set_parents(); - j.assert_invariant(); - } - - template - static void construct(BasicJsonType& j, const std::vector& arr) - { - j.m_value.destroy(j.m_type); - j.m_type = value_t::array; - j.m_value = value_t::array; - j.m_value.array->reserve(arr.size()); - for (const bool x : arr) - { - j.m_value.array->push_back(x); - j.set_parent(j.m_value.array->back()); - } - j.assert_invariant(); - } - - template::value, int> = 0> - static void construct(BasicJsonType& j, const std::valarray& arr) - { - j.m_value.destroy(j.m_type); - j.m_type = value_t::array; - j.m_value = value_t::array; - j.m_value.array->resize(arr.size()); - if (arr.size() > 0) - { - std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); - } - j.set_parents(); - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) - { - j.m_value.destroy(j.m_type); - j.m_type = value_t::object; - j.m_value = obj; - j.set_parents(); - j.assert_invariant(); - } - - template - static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) - { - j.m_value.destroy(j.m_type); - j.m_type = value_t::object; - j.m_value = std::move(obj); - j.set_parents(); - j.assert_invariant(); - } - - template < typename BasicJsonType, typename CompatibleObjectType, - enable_if_t < !std::is_same::value, int > = 0 > - static void construct(BasicJsonType& j, const CompatibleObjectType& obj) - { - using std::begin; - using std::end; - - j.m_value.destroy(j.m_type); - j.m_type = value_t::object; - j.m_value.object = j.template create(begin(obj), end(obj)); - j.set_parents(); - j.assert_invariant(); - } -}; - -///////////// -// to_json // -///////////// - -template::value, int> = 0> -void to_json(BasicJsonType& j, T b) noexcept -{ - external_constructor::construct(j, b); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, const CompatibleString& s) -{ - external_constructor::construct(j, s); -} - -template -void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) -{ - external_constructor::construct(j, std::move(s)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, FloatType val) noexcept -{ - external_constructor::construct(j, static_cast(val)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept -{ - external_constructor::construct(j, static_cast(val)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept -{ - external_constructor::construct(j, static_cast(val)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, EnumType e) noexcept -{ - using underlying_type = typename std::underlying_type::type; - external_constructor::construct(j, static_cast(e)); -} - -template -void to_json(BasicJsonType& j, const std::vector& e) -{ - external_constructor::construct(j, e); -} - -template < typename BasicJsonType, typename CompatibleArrayType, - enable_if_t < is_compatible_array_type::value&& - !is_compatible_object_type::value&& - !is_compatible_string_type::value&& - !std::is_same::value&& - !is_basic_json::value, - int > = 0 > -void to_json(BasicJsonType& j, const CompatibleArrayType& arr) -{ - external_constructor::construct(j, arr); -} - -template -void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin) -{ - external_constructor::construct(j, bin); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, const std::valarray& arr) -{ - external_constructor::construct(j, std::move(arr)); -} - -template -void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) -{ - external_constructor::construct(j, std::move(arr)); -} - -template < typename BasicJsonType, typename CompatibleObjectType, - enable_if_t < is_compatible_object_type::value&& !is_basic_json::value, int > = 0 > -void to_json(BasicJsonType& j, const CompatibleObjectType& obj) -{ - external_constructor::construct(j, obj); -} - -template -void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) -{ - external_constructor::construct(j, std::move(obj)); -} - -template < - typename BasicJsonType, typename T, std::size_t N, - enable_if_t < !std::is_constructible::value, // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - int > = 0 > -void to_json(BasicJsonType& j, const T(&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) -{ - external_constructor::construct(j, arr); -} - -template < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible::value&& std::is_constructible::value, int > = 0 > -void to_json(BasicJsonType& j, const std::pair& p) -{ - j = { p.first, p.second }; -} - -// for https://github.com/nlohmann/json/pull/1134 -template>::value, int> = 0> -void to_json(BasicJsonType& j, const T& b) -{ - j = { {b.key(), b.value()} }; -} - -template -void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence /*unused*/) -{ - j = { std::get(t)... }; -} - -template::value, int > = 0> -void to_json(BasicJsonType& j, const T& t) -{ - to_json_tuple_impl(j, t, make_index_sequence::value> {}); -} - -#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM -template -void to_json(BasicJsonType& j, const std_fs::path& p) -{ - j = p.string(); -} -#endif - -struct to_json_fn -{ - template - auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward(val)))) - -> decltype(to_json(j, std::forward(val)), void()) - { - return to_json(j, std::forward(val)); - } -}; -} // namespace detail - -/// namespace to hold default `to_json` function -/// to see why this is required: -/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html -namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces) -{ -constexpr const auto& to_json = detail::static_const::value; // NOLINT(misc-definitions-in-headers) -} // namespace -} // namespace nlohmann - -// #include - -// #include - - -namespace nlohmann -{ - -/// @sa https://json.nlohmann.me/api/adl_serializer/ -template -struct adl_serializer -{ - /// @brief convert a JSON value to any value type - /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/ - template - static auto from_json(BasicJsonType && j, TargetType& val) noexcept( - noexcept(::nlohmann::from_json(std::forward(j), val))) - -> decltype(::nlohmann::from_json(std::forward(j), val), void()) - { - ::nlohmann::from_json(std::forward(j), val); - } - - /// @brief convert a JSON value to any value type - /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/ - template - static auto from_json(BasicJsonType && j) noexcept( - noexcept(::nlohmann::from_json(std::forward(j), detail::identity_tag {}))) - -> decltype(::nlohmann::from_json(std::forward(j), detail::identity_tag {})) - { - return ::nlohmann::from_json(std::forward(j), detail::identity_tag {}); - } - - /// @brief convert any value type to a JSON value - /// @sa https://json.nlohmann.me/api/adl_serializer/to_json/ - template - static auto to_json(BasicJsonType& j, TargetType && val) noexcept( - noexcept(::nlohmann::to_json(j, std::forward(val)))) - -> decltype(::nlohmann::to_json(j, std::forward(val)), void()) - { - ::nlohmann::to_json(j, std::forward(val)); - } -}; -} // namespace nlohmann - -// #include - - -#include // uint8_t, uint64_t -#include // tie -#include // move - -namespace nlohmann -{ - -/// @brief an internal type for a backed binary type -/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/ -template -class byte_container_with_subtype : public BinaryType -{ - public: - using container_type = BinaryType; - using subtype_type = std::uint64_t; - - /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ - byte_container_with_subtype() noexcept(noexcept(container_type())) - : container_type() - {} - - /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ - byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b))) - : container_type(b) - {} - - /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ - byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b)))) - : container_type(std::move(b)) - {} - - /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ - byte_container_with_subtype(const container_type& b, subtype_type subtype_) noexcept(noexcept(container_type(b))) - : container_type(b) - , m_subtype(subtype_) - , m_has_subtype(true) - {} - - /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ - byte_container_with_subtype(container_type&& b, subtype_type subtype_) noexcept(noexcept(container_type(std::move(b)))) - : container_type(std::move(b)) - , m_subtype(subtype_) - , m_has_subtype(true) - {} - - bool operator==(const byte_container_with_subtype& rhs) const - { - return std::tie(static_cast(*this), m_subtype, m_has_subtype) == - std::tie(static_cast(rhs), rhs.m_subtype, rhs.m_has_subtype); - } - - bool operator!=(const byte_container_with_subtype& rhs) const - { - return !(rhs == *this); - } - - /// @brief sets the binary subtype - /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/set_subtype/ - void set_subtype(subtype_type subtype_) noexcept - { - m_subtype = subtype_; - m_has_subtype = true; - } - - /// @brief return the binary subtype - /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/subtype/ - constexpr subtype_type subtype() const noexcept - { - return m_has_subtype ? m_subtype : static_cast(-1); - } - - /// @brief return whether the value has a subtype - /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/has_subtype/ - constexpr bool has_subtype() const noexcept - { - return m_has_subtype; - } - - /// @brief clears the binary subtype - /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/clear_subtype/ - void clear_subtype() noexcept - { - m_subtype = 0; - m_has_subtype = false; - } - - private: - subtype_type m_subtype = 0; - bool m_has_subtype = false; -}; - -} // namespace nlohmann - -// #include - -// #include - -// #include - -// #include - - -#include // uint8_t -#include // size_t -#include // hash - -// #include - -// #include - - -namespace nlohmann -{ -namespace detail -{ - -// boost::hash_combine -inline std::size_t combine(std::size_t seed, std::size_t h) noexcept -{ - seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U); - return seed; -} - -/*! -@brief hash a JSON value - -The hash function tries to rely on std::hash where possible. Furthermore, the -type of the JSON value is taken into account to have different hash values for -null, 0, 0U, and false, etc. - -@tparam BasicJsonType basic_json specialization -@param j JSON value to hash -@return hash value of j -*/ -template -std::size_t hash(const BasicJsonType& j) -{ - using string_t = typename BasicJsonType::string_t; - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - - const auto type = static_cast(j.type()); - switch (j.type()) - { - case BasicJsonType::value_t::null: - case BasicJsonType::value_t::discarded: - { - return combine(type, 0); - } - - case BasicJsonType::value_t::object: - { - auto seed = combine(type, j.size()); - for (const auto& element : j.items()) - { - const auto h = std::hash {}(element.key()); - seed = combine(seed, h); - seed = combine(seed, hash(element.value())); - } - return seed; - } - - case BasicJsonType::value_t::array: - { - auto seed = combine(type, j.size()); - for (const auto& element : j) - { - seed = combine(seed, hash(element)); - } - return seed; - } - - case BasicJsonType::value_t::string: - { - const auto h = std::hash {}(j.template get_ref()); - return combine(type, h); - } - - case BasicJsonType::value_t::boolean: - { - const auto h = std::hash {}(j.template get()); - return combine(type, h); - } - - case BasicJsonType::value_t::number_integer: - { - const auto h = std::hash {}(j.template get()); - return combine(type, h); - } - - case BasicJsonType::value_t::number_unsigned: - { - const auto h = std::hash {}(j.template get()); - return combine(type, h); - } - - case BasicJsonType::value_t::number_float: - { - const auto h = std::hash {}(j.template get()); - return combine(type, h); - } - - case BasicJsonType::value_t::binary: - { - auto seed = combine(type, j.get_binary().size()); - const auto h = std::hash {}(j.get_binary().has_subtype()); - seed = combine(seed, h); - seed = combine(seed, static_cast(j.get_binary().subtype())); - for (const auto byte : j.get_binary()) - { - seed = combine(seed, std::hash {}(byte)); - } - return seed; - } - - default: // LCOV_EXCL_LINE - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE - return 0; // LCOV_EXCL_LINE - } -} - -} // namespace detail -} // namespace nlohmann - -// #include - - -#include // generate_n -#include // array -#include // ldexp -#include // size_t -#include // uint8_t, uint16_t, uint32_t, uint64_t -#include // snprintf -#include // memcpy -#include // back_inserter -#include // numeric_limits -#include // char_traits, string -#include // make_pair, move -#include // vector - -// #include - -// #include - - -#include // array -#include // size_t -#include // strlen -#include // begin, end, iterator_traits, random_access_iterator_tag, distance, next -#include // shared_ptr, make_shared, addressof -#include // accumulate -#include // string, char_traits -#include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer -#include // pair, declval - -#ifndef JSON_NO_IO - #include // FILE * - #include // istream -#endif // JSON_NO_IO - -// #include - -// #include - - -namespace nlohmann -{ -namespace detail -{ -/// the supported input formats -enum class input_format_t { json, cbor, msgpack, ubjson, bson }; - -//////////////////// -// input adapters // -//////////////////// - -#ifndef JSON_NO_IO -/*! -Input adapter for stdio file access. This adapter read only 1 byte and do not use any - buffer. This adapter is a very low level adapter. -*/ -class file_input_adapter -{ - public: - using char_type = char; - - JSON_HEDLEY_NON_NULL(2) - explicit file_input_adapter(std::FILE* f) noexcept - : m_file(f) - {} - - // make class move-only - file_input_adapter(const file_input_adapter&) = delete; - file_input_adapter(file_input_adapter&&) noexcept = default; - file_input_adapter& operator=(const file_input_adapter&) = delete; - file_input_adapter& operator=(file_input_adapter&&) = delete; - ~file_input_adapter() = default; - - std::char_traits::int_type get_character() noexcept - { - return std::fgetc(m_file); - } - - private: - /// the file pointer to read from - std::FILE* m_file; -}; - - -/*! -Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at -beginning of input. Does not support changing the underlying std::streambuf -in mid-input. Maintains underlying std::istream and std::streambuf to support -subsequent use of standard std::istream operations to process any input -characters following those used in parsing the JSON input. Clears the -std::istream flags; any input errors (e.g., EOF) will be detected by the first -subsequent call for input from the std::istream. -*/ -class input_stream_adapter -{ - public: - using char_type = char; - - ~input_stream_adapter() - { - // clear stream flags; we use underlying streambuf I/O, do not - // maintain ifstream flags, except eof - if (is != nullptr) - { - is->clear(is->rdstate() & std::ios::eofbit); - } - } - - explicit input_stream_adapter(std::istream& i) - : is(&i), sb(i.rdbuf()) - {} - - // delete because of pointer members - input_stream_adapter(const input_stream_adapter&) = delete; - input_stream_adapter& operator=(input_stream_adapter&) = delete; - input_stream_adapter& operator=(input_stream_adapter&&) = delete; - - input_stream_adapter(input_stream_adapter&& rhs) noexcept - : is(rhs.is), sb(rhs.sb) - { - rhs.is = nullptr; - rhs.sb = nullptr; - } - - // std::istream/std::streambuf use std::char_traits::to_int_type, to - // ensure that std::char_traits::eof() and the character 0xFF do not - // end up as the same value, e.g. 0xFFFFFFFF. - std::char_traits::int_type get_character() - { - auto res = sb->sbumpc(); - // set eof manually, as we don't use the istream interface. - if (JSON_HEDLEY_UNLIKELY(res == std::char_traits::eof())) - { - is->clear(is->rdstate() | std::ios::eofbit); - } - return res; - } - - private: - /// the associated input stream - std::istream* is = nullptr; - std::streambuf* sb = nullptr; -}; -#endif // JSON_NO_IO - -// General-purpose iterator-based adapter. It might not be as fast as -// theoretically possible for some containers, but it is extremely versatile. -template -class iterator_input_adapter -{ - public: - using char_type = typename std::iterator_traits::value_type; - - iterator_input_adapter(IteratorType first, IteratorType last) - : current(std::move(first)), end(std::move(last)) - {} - - typename std::char_traits::int_type get_character() - { - if (JSON_HEDLEY_LIKELY(current != end)) - { - auto result = std::char_traits::to_int_type(*current); - std::advance(current, 1); - return result; - } - - return std::char_traits::eof(); - } - - private: - IteratorType current; - IteratorType end; - - template - friend struct wide_string_input_helper; - - bool empty() const - { - return current == end; - } -}; - - -template -struct wide_string_input_helper; - -template -struct wide_string_input_helper -{ - // UTF-32 - static void fill_buffer(BaseInputAdapter& input, - std::array::int_type, 4>& utf8_bytes, - size_t& utf8_bytes_index, - size_t& utf8_bytes_filled) - { - utf8_bytes_index = 0; - - if (JSON_HEDLEY_UNLIKELY(input.empty())) - { - utf8_bytes[0] = std::char_traits::eof(); - utf8_bytes_filled = 1; - } - else - { - // get the current character - const auto wc = input.get_character(); - - // UTF-32 to UTF-8 encoding - if (wc < 0x80) - { - utf8_bytes[0] = static_cast::int_type>(wc); - utf8_bytes_filled = 1; - } - else if (wc <= 0x7FF) - { - utf8_bytes[0] = static_cast::int_type>(0xC0u | ((static_cast(wc) >> 6u) & 0x1Fu)); - utf8_bytes[1] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); - utf8_bytes_filled = 2; - } - else if (wc <= 0xFFFF) - { - utf8_bytes[0] = static_cast::int_type>(0xE0u | ((static_cast(wc) >> 12u) & 0x0Fu)); - utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); - utf8_bytes[2] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); - utf8_bytes_filled = 3; - } - else if (wc <= 0x10FFFF) - { - utf8_bytes[0] = static_cast::int_type>(0xF0u | ((static_cast(wc) >> 18u) & 0x07u)); - utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 12u) & 0x3Fu)); - utf8_bytes[2] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); - utf8_bytes[3] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); - utf8_bytes_filled = 4; - } - else - { - // unknown character - utf8_bytes[0] = static_cast::int_type>(wc); - utf8_bytes_filled = 1; - } - } - } -}; - -template -struct wide_string_input_helper -{ - // UTF-16 - static void fill_buffer(BaseInputAdapter& input, - std::array::int_type, 4>& utf8_bytes, - size_t& utf8_bytes_index, - size_t& utf8_bytes_filled) - { - utf8_bytes_index = 0; - - if (JSON_HEDLEY_UNLIKELY(input.empty())) - { - utf8_bytes[0] = std::char_traits::eof(); - utf8_bytes_filled = 1; - } - else - { - // get the current character - const auto wc = input.get_character(); - - // UTF-16 to UTF-8 encoding - if (wc < 0x80) - { - utf8_bytes[0] = static_cast::int_type>(wc); - utf8_bytes_filled = 1; - } - else if (wc <= 0x7FF) - { - utf8_bytes[0] = static_cast::int_type>(0xC0u | ((static_cast(wc) >> 6u))); - utf8_bytes[1] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); - utf8_bytes_filled = 2; - } - else if (0xD800 > wc || wc >= 0xE000) - { - utf8_bytes[0] = static_cast::int_type>(0xE0u | ((static_cast(wc) >> 12u))); - utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); - utf8_bytes[2] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); - utf8_bytes_filled = 3; - } - else - { - if (JSON_HEDLEY_UNLIKELY(!input.empty())) - { - const auto wc2 = static_cast(input.get_character()); - const auto charcode = 0x10000u + (((static_cast(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu)); - utf8_bytes[0] = static_cast::int_type>(0xF0u | (charcode >> 18u)); - utf8_bytes[1] = static_cast::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu)); - utf8_bytes[2] = static_cast::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu)); - utf8_bytes[3] = static_cast::int_type>(0x80u | (charcode & 0x3Fu)); - utf8_bytes_filled = 4; - } - else - { - utf8_bytes[0] = static_cast::int_type>(wc); - utf8_bytes_filled = 1; - } - } - } - } -}; - -// Wraps another input apdater to convert wide character types into individual bytes. -template -class wide_string_input_adapter -{ - public: - using char_type = char; - - wide_string_input_adapter(BaseInputAdapter base) - : base_adapter(base) {} - - typename std::char_traits::int_type get_character() noexcept - { - // check if buffer needs to be filled - if (utf8_bytes_index == utf8_bytes_filled) - { - fill_buffer(); - - JSON_ASSERT(utf8_bytes_filled > 0); - JSON_ASSERT(utf8_bytes_index == 0); - } - - // use buffer - JSON_ASSERT(utf8_bytes_filled > 0); - JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled); - return utf8_bytes[utf8_bytes_index++]; - } - - private: - BaseInputAdapter base_adapter; - - template - void fill_buffer() - { - wide_string_input_helper::fill_buffer(base_adapter, utf8_bytes, utf8_bytes_index, utf8_bytes_filled); - } - - /// a buffer for UTF-8 bytes - std::array::int_type, 4> utf8_bytes = {{0, 0, 0, 0}}; - - /// index to the utf8_codes array for the next valid byte - std::size_t utf8_bytes_index = 0; - /// number of valid bytes in the utf8_codes array - std::size_t utf8_bytes_filled = 0; -}; - - -template -struct iterator_input_adapter_factory -{ - using iterator_type = IteratorType; - using char_type = typename std::iterator_traits::value_type; - using adapter_type = iterator_input_adapter; - - static adapter_type create(IteratorType first, IteratorType last) - { - return adapter_type(std::move(first), std::move(last)); - } -}; - -template -struct is_iterator_of_multibyte -{ - using value_type = typename std::iterator_traits::value_type; - enum - { - value = sizeof(value_type) > 1 - }; -}; - -template -struct iterator_input_adapter_factory::value>> -{ - using iterator_type = IteratorType; - using char_type = typename std::iterator_traits::value_type; - using base_adapter_type = iterator_input_adapter; - using adapter_type = wide_string_input_adapter; - - static adapter_type create(IteratorType first, IteratorType last) - { - return adapter_type(base_adapter_type(std::move(first), std::move(last))); - } -}; - -// General purpose iterator-based input -template -typename iterator_input_adapter_factory::adapter_type input_adapter(IteratorType first, IteratorType last) -{ - using factory_type = iterator_input_adapter_factory; - return factory_type::create(first, last); -} - -// Convenience shorthand from container to iterator -// Enables ADL on begin(container) and end(container) -// Encloses the using declarations in namespace for not to leak them to outside scope - -namespace container_input_adapter_factory_impl -{ - -using std::begin; -using std::end; - -template -struct container_input_adapter_factory {}; - -template -struct container_input_adapter_factory< ContainerType, - void_t()), end(std::declval()))>> - { - using adapter_type = decltype(input_adapter(begin(std::declval()), end(std::declval()))); - - static adapter_type create(const ContainerType& container) -{ - return input_adapter(begin(container), end(container)); -} - }; - -} // namespace container_input_adapter_factory_impl - -template -typename container_input_adapter_factory_impl::container_input_adapter_factory::adapter_type input_adapter(const ContainerType& container) -{ - return container_input_adapter_factory_impl::container_input_adapter_factory::create(container); -} - -#ifndef JSON_NO_IO -// Special cases with fast paths -inline file_input_adapter input_adapter(std::FILE* file) -{ - return file_input_adapter(file); -} - -inline input_stream_adapter input_adapter(std::istream& stream) -{ - return input_stream_adapter(stream); -} - -inline input_stream_adapter input_adapter(std::istream&& stream) -{ - return input_stream_adapter(stream); -} -#endif // JSON_NO_IO - -using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval(), std::declval())); - -// Null-delimited strings, and the like. -template < typename CharT, - typename std::enable_if < - std::is_pointer::value&& - !std::is_array::value&& - std::is_integral::type>::value&& - sizeof(typename std::remove_pointer::type) == 1, - int >::type = 0 > -contiguous_bytes_input_adapter input_adapter(CharT b) -{ - auto length = std::strlen(reinterpret_cast(b)); - const auto* ptr = reinterpret_cast(b); - return input_adapter(ptr, ptr + length); -} - -template -auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) -{ - return input_adapter(array, array + N); -} - -// This class only handles inputs of input_buffer_adapter type. -// It's required so that expressions like {ptr, len} can be implicitly cast -// to the correct adapter. -class span_input_adapter -{ - public: - template < typename CharT, - typename std::enable_if < - std::is_pointer::value&& - std::is_integral::type>::value&& - sizeof(typename std::remove_pointer::type) == 1, - int >::type = 0 > - span_input_adapter(CharT b, std::size_t l) - : ia(reinterpret_cast(b), reinterpret_cast(b) + l) {} - - template::iterator_category, std::random_access_iterator_tag>::value, - int>::type = 0> - span_input_adapter(IteratorType first, IteratorType last) - : ia(input_adapter(first, last)) {} - - contiguous_bytes_input_adapter&& get() - { - return std::move(ia); // NOLINT(hicpp-move-const-arg,performance-move-const-arg) - } - - private: - contiguous_bytes_input_adapter ia; -}; -} // namespace detail -} // namespace nlohmann - -// #include - - -#include -#include // string -#include // move -#include // vector - -// #include - -// #include - - -namespace nlohmann -{ - -/*! -@brief SAX interface - -This class describes the SAX interface used by @ref nlohmann::json::sax_parse. -Each function is called in different situations while the input is parsed. The -boolean return value informs the parser whether to continue processing the -input. -*/ -template -struct json_sax -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; - - /*! - @brief a null value was read - @return whether parsing should proceed - */ - virtual bool null() = 0; - - /*! - @brief a boolean value was read - @param[in] val boolean value - @return whether parsing should proceed - */ - virtual bool boolean(bool val) = 0; - - /*! - @brief an integer number was read - @param[in] val integer value - @return whether parsing should proceed - */ - virtual bool number_integer(number_integer_t val) = 0; - - /*! - @brief an unsigned integer number was read - @param[in] val unsigned integer value - @return whether parsing should proceed - */ - virtual bool number_unsigned(number_unsigned_t val) = 0; - - /*! - @brief a floating-point number was read - @param[in] val floating-point value - @param[in] s raw token value - @return whether parsing should proceed - */ - virtual bool number_float(number_float_t val, const string_t& s) = 0; - - /*! - @brief a string value was read - @param[in] val string value - @return whether parsing should proceed - @note It is safe to move the passed string value. - */ - virtual bool string(string_t& val) = 0; - - /*! - @brief a binary value was read - @param[in] val binary value - @return whether parsing should proceed - @note It is safe to move the passed binary value. - */ - virtual bool binary(binary_t& val) = 0; - - /*! - @brief the beginning of an object was read - @param[in] elements number of object elements or -1 if unknown - @return whether parsing should proceed - @note binary formats may report the number of elements - */ - virtual bool start_object(std::size_t elements) = 0; - - /*! - @brief an object key was read - @param[in] val object key - @return whether parsing should proceed - @note It is safe to move the passed string. - */ - virtual bool key(string_t& val) = 0; - - /*! - @brief the end of an object was read - @return whether parsing should proceed - */ - virtual bool end_object() = 0; - - /*! - @brief the beginning of an array was read - @param[in] elements number of array elements or -1 if unknown - @return whether parsing should proceed - @note binary formats may report the number of elements - */ - virtual bool start_array(std::size_t elements) = 0; - - /*! - @brief the end of an array was read - @return whether parsing should proceed - */ - virtual bool end_array() = 0; - - /*! - @brief a parse error occurred - @param[in] position the position in the input where the error occurs - @param[in] last_token the last read token - @param[in] ex an exception object describing the error - @return whether parsing should proceed (must return false) - */ - virtual bool parse_error(std::size_t position, - const std::string& last_token, - const detail::exception& ex) = 0; - - json_sax() = default; - json_sax(const json_sax&) = default; - json_sax(json_sax&&) noexcept = default; - json_sax& operator=(const json_sax&) = default; - json_sax& operator=(json_sax&&) noexcept = default; - virtual ~json_sax() = default; -}; - - -namespace detail -{ -/*! -@brief SAX implementation to create a JSON value from SAX events - -This class implements the @ref json_sax interface and processes the SAX events -to create a JSON value which makes it basically a DOM parser. The structure or -hierarchy of the JSON value is managed by the stack `ref_stack` which contains -a pointer to the respective array or object for each recursion depth. - -After successful parsing, the value that is passed by reference to the -constructor contains the parsed value. - -@tparam BasicJsonType the JSON type -*/ -template -class json_sax_dom_parser -{ - public: - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; - - /*! - @param[in,out] r reference to a JSON value that is manipulated while - parsing - @param[in] allow_exceptions_ whether parse errors yield exceptions - */ - explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true) - : root(r), allow_exceptions(allow_exceptions_) - {} - - // make class move-only - json_sax_dom_parser(const json_sax_dom_parser&) = delete; - json_sax_dom_parser(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete; - json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - ~json_sax_dom_parser() = default; - - bool null() - { - handle_value(nullptr); - return true; - } - - bool boolean(bool val) - { - handle_value(val); - return true; - } - - bool number_integer(number_integer_t val) - { - handle_value(val); - return true; - } - - bool number_unsigned(number_unsigned_t val) - { - handle_value(val); - return true; - } - - bool number_float(number_float_t val, const string_t& /*unused*/) - { - handle_value(val); - return true; - } - - bool string(string_t& val) - { - handle_value(val); - return true; - } - - bool binary(binary_t& val) - { - handle_value(std::move(val)); - return true; - } - - bool start_object(std::size_t len) - { - ref_stack.push_back(handle_value(BasicJsonType::value_t::object)); - - if (JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) - { - JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len), *ref_stack.back())); - } - - return true; - } - - bool key(string_t& val) - { - // add null at given key and store the reference for later - object_element = &(ref_stack.back()->m_value.object->operator[](val)); - return true; - } - - bool end_object() - { - ref_stack.back()->set_parents(); - ref_stack.pop_back(); - return true; - } - - bool start_array(std::size_t len) - { - ref_stack.push_back(handle_value(BasicJsonType::value_t::array)); - - if (JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) - { - JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len), *ref_stack.back())); - } - - return true; - } - - bool end_array() - { - ref_stack.back()->set_parents(); - ref_stack.pop_back(); - return true; - } - - template - bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, - const Exception& ex) - { - errored = true; - static_cast(ex); - if (allow_exceptions) - { - JSON_THROW(ex); - } - return false; - } - - constexpr bool is_errored() const - { - return errored; - } - - private: - /*! - @invariant If the ref stack is empty, then the passed value will be the new - root. - @invariant If the ref stack contains a value, then it is an array or an - object to which we can add elements - */ - template - JSON_HEDLEY_RETURNS_NON_NULL - BasicJsonType* handle_value(Value&& v) - { - if (ref_stack.empty()) - { - root = BasicJsonType(std::forward(v)); - return &root; - } - - JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); - - if (ref_stack.back()->is_array()) - { - ref_stack.back()->m_value.array->emplace_back(std::forward(v)); - return &(ref_stack.back()->m_value.array->back()); - } - - JSON_ASSERT(ref_stack.back()->is_object()); - JSON_ASSERT(object_element); - *object_element = BasicJsonType(std::forward(v)); - return object_element; - } - - /// the parsed JSON value - BasicJsonType& root; - /// stack to model hierarchy of values - std::vector ref_stack {}; - /// helper to hold the reference for the next object element - BasicJsonType* object_element = nullptr; - /// whether a syntax error occurred - bool errored = false; - /// whether to throw exceptions in case of errors - const bool allow_exceptions = true; -}; - -template -class json_sax_dom_callback_parser -{ - public: - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; - using parser_callback_t = typename BasicJsonType::parser_callback_t; - using parse_event_t = typename BasicJsonType::parse_event_t; - - json_sax_dom_callback_parser(BasicJsonType& r, - const parser_callback_t cb, - const bool allow_exceptions_ = true) - : root(r), callback(cb), allow_exceptions(allow_exceptions_) - { - keep_stack.push_back(true); - } - - // make class move-only - json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete; - json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete; - json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - ~json_sax_dom_callback_parser() = default; - - bool null() - { - handle_value(nullptr); - return true; - } - - bool boolean(bool val) - { - handle_value(val); - return true; - } - - bool number_integer(number_integer_t val) - { - handle_value(val); - return true; - } - - bool number_unsigned(number_unsigned_t val) - { - handle_value(val); - return true; - } - - bool number_float(number_float_t val, const string_t& /*unused*/) - { - handle_value(val); - return true; - } - - bool string(string_t& val) - { - handle_value(val); - return true; - } - - bool binary(binary_t& val) - { - handle_value(std::move(val)); - return true; - } - - bool start_object(std::size_t len) - { - // check callback for object start - const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::object_start, discarded); - keep_stack.push_back(keep); - - auto val = handle_value(BasicJsonType::value_t::object, true); - ref_stack.push_back(val.second); - - // check object limit - if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) - { - JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len), *ref_stack.back())); - } - - return true; - } - - bool key(string_t& val) - { - BasicJsonType k = BasicJsonType(val); - - // check callback for key - const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::key, k); - key_keep_stack.push_back(keep); - - // add discarded value at given key and store the reference for later - if (keep && ref_stack.back()) - { - object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded); - } - - return true; - } - - bool end_object() - { - if (ref_stack.back()) - { - if (!callback(static_cast(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back())) - { - // discard object - *ref_stack.back() = discarded; - } - else - { - ref_stack.back()->set_parents(); - } - } - - JSON_ASSERT(!ref_stack.empty()); - JSON_ASSERT(!keep_stack.empty()); - ref_stack.pop_back(); - keep_stack.pop_back(); - - if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured()) - { - // remove discarded value - for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it) - { - if (it->is_discarded()) - { - ref_stack.back()->erase(it); - break; - } - } - } - - return true; - } - - bool start_array(std::size_t len) - { - const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::array_start, discarded); - keep_stack.push_back(keep); - - auto val = handle_value(BasicJsonType::value_t::array, true); - ref_stack.push_back(val.second); - - // check array limit - if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) - { - JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len), *ref_stack.back())); - } - - return true; - } - - bool end_array() - { - bool keep = true; - - if (ref_stack.back()) - { - keep = callback(static_cast(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back()); - if (keep) - { - ref_stack.back()->set_parents(); - } - else - { - // discard array - *ref_stack.back() = discarded; - } - } - - JSON_ASSERT(!ref_stack.empty()); - JSON_ASSERT(!keep_stack.empty()); - ref_stack.pop_back(); - keep_stack.pop_back(); - - // remove discarded value - if (!keep && !ref_stack.empty() && ref_stack.back()->is_array()) - { - ref_stack.back()->m_value.array->pop_back(); - } - - return true; - } - - template - bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, - const Exception& ex) - { - errored = true; - static_cast(ex); - if (allow_exceptions) - { - JSON_THROW(ex); - } - return false; - } - - constexpr bool is_errored() const - { - return errored; - } - - private: - /*! - @param[in] v value to add to the JSON value we build during parsing - @param[in] skip_callback whether we should skip calling the callback - function; this is required after start_array() and - start_object() SAX events, because otherwise we would call the - callback function with an empty array or object, respectively. - - @invariant If the ref stack is empty, then the passed value will be the new - root. - @invariant If the ref stack contains a value, then it is an array or an - object to which we can add elements - - @return pair of boolean (whether value should be kept) and pointer (to the - passed value in the ref_stack hierarchy; nullptr if not kept) - */ - template - std::pair handle_value(Value&& v, const bool skip_callback = false) - { - JSON_ASSERT(!keep_stack.empty()); - - // do not handle this value if we know it would be added to a discarded - // container - if (!keep_stack.back()) - { - return {false, nullptr}; - } - - // create value - auto value = BasicJsonType(std::forward(v)); - - // check callback - const bool keep = skip_callback || callback(static_cast(ref_stack.size()), parse_event_t::value, value); - - // do not handle this value if we just learnt it shall be discarded - if (!keep) - { - return {false, nullptr}; - } - - if (ref_stack.empty()) - { - root = std::move(value); - return {true, &root}; - } - - // skip this value if we already decided to skip the parent - // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360) - if (!ref_stack.back()) - { - return {false, nullptr}; - } - - // we now only expect arrays and objects - JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); - - // array - if (ref_stack.back()->is_array()) - { - ref_stack.back()->m_value.array->emplace_back(std::move(value)); - return {true, &(ref_stack.back()->m_value.array->back())}; - } - - // object - JSON_ASSERT(ref_stack.back()->is_object()); - // check if we should store an element for the current key - JSON_ASSERT(!key_keep_stack.empty()); - const bool store_element = key_keep_stack.back(); - key_keep_stack.pop_back(); - - if (!store_element) - { - return {false, nullptr}; - } - - JSON_ASSERT(object_element); - *object_element = std::move(value); - return {true, object_element}; - } - - /// the parsed JSON value - BasicJsonType& root; - /// stack to model hierarchy of values - std::vector ref_stack {}; - /// stack to manage which values to keep - std::vector keep_stack {}; - /// stack to manage which object keys to keep - std::vector key_keep_stack {}; - /// helper to hold the reference for the next object element - BasicJsonType* object_element = nullptr; - /// whether a syntax error occurred - bool errored = false; - /// callback function - const parser_callback_t callback = nullptr; - /// whether to throw exceptions in case of errors - const bool allow_exceptions = true; - /// a discarded value for the callback - BasicJsonType discarded = BasicJsonType::value_t::discarded; -}; - -template -class json_sax_acceptor -{ - public: - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; - - bool null() - { - return true; - } - - bool boolean(bool /*unused*/) - { - return true; - } - - bool number_integer(number_integer_t /*unused*/) - { - return true; - } - - bool number_unsigned(number_unsigned_t /*unused*/) - { - return true; - } - - bool number_float(number_float_t /*unused*/, const string_t& /*unused*/) - { - return true; - } - - bool string(string_t& /*unused*/) - { - return true; - } - - bool binary(binary_t& /*unused*/) - { - return true; - } - - bool start_object(std::size_t /*unused*/ = static_cast(-1)) - { - return true; - } - - bool key(string_t& /*unused*/) - { - return true; - } - - bool end_object() - { - return true; - } - - bool start_array(std::size_t /*unused*/ = static_cast(-1)) - { - return true; - } - - bool end_array() - { - return true; - } - - bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/) - { - return false; - } -}; -} // namespace detail - -} // namespace nlohmann - -// #include - - -#include // array -#include // localeconv -#include // size_t -#include // snprintf -#include // strtof, strtod, strtold, strtoll, strtoull -#include // initializer_list -#include // char_traits, string -#include // move -#include // vector - -// #include - -// #include - -// #include - - -namespace nlohmann -{ -namespace detail -{ -/////////// -// lexer // -/////////// - -template -class lexer_base -{ - public: - /// token types for the parser - enum class token_type - { - uninitialized, ///< indicating the scanner is uninitialized - literal_true, ///< the `true` literal - literal_false, ///< the `false` literal - literal_null, ///< the `null` literal - value_string, ///< a string -- use get_string() for actual value - value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value - value_integer, ///< a signed integer -- use get_number_integer() for actual value - value_float, ///< an floating point number -- use get_number_float() for actual value - begin_array, ///< the character for array begin `[` - begin_object, ///< the character for object begin `{` - end_array, ///< the character for array end `]` - end_object, ///< the character for object end `}` - name_separator, ///< the name separator `:` - value_separator, ///< the value separator `,` - parse_error, ///< indicating a parse error - end_of_input, ///< indicating the end of the input buffer - literal_or_value ///< a literal or the begin of a value (only for diagnostics) - }; - - /// return name of values of type token_type (only used for errors) - JSON_HEDLEY_RETURNS_NON_NULL - JSON_HEDLEY_CONST - static const char* token_type_name(const token_type t) noexcept - { - switch (t) - { - case token_type::uninitialized: - return ""; - case token_type::literal_true: - return "true literal"; - case token_type::literal_false: - return "false literal"; - case token_type::literal_null: - return "null literal"; - case token_type::value_string: - return "string literal"; - case token_type::value_unsigned: - case token_type::value_integer: - case token_type::value_float: - return "number literal"; - case token_type::begin_array: - return "'['"; - case token_type::begin_object: - return "'{'"; - case token_type::end_array: - return "']'"; - case token_type::end_object: - return "'}'"; - case token_type::name_separator: - return "':'"; - case token_type::value_separator: - return "','"; - case token_type::parse_error: - return ""; - case token_type::end_of_input: - return "end of input"; - case token_type::literal_or_value: - return "'[', '{', or a literal"; - // LCOV_EXCL_START - default: // catch non-enum values - return "unknown token"; - // LCOV_EXCL_STOP - } - } -}; -/*! -@brief lexical analysis - -This class organizes the lexical analysis during JSON deserialization. -*/ -template -class lexer : public lexer_base -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using char_type = typename InputAdapterType::char_type; - using char_int_type = typename std::char_traits::int_type; - - public: - using token_type = typename lexer_base::token_type; - - explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false) noexcept - : ia(std::move(adapter)) - , ignore_comments(ignore_comments_) - , decimal_point_char(static_cast(get_decimal_point())) - {} - - // delete because of pointer members - lexer(const lexer&) = delete; - lexer(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - lexer& operator=(lexer&) = delete; - lexer& operator=(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - ~lexer() = default; - - private: - ///////////////////// - // locales - ///////////////////// - - /// return the locale-dependent decimal point - JSON_HEDLEY_PURE - static char get_decimal_point() noexcept - { - const auto* loc = localeconv(); - JSON_ASSERT(loc != nullptr); - return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); - } - - ///////////////////// - // scan functions - ///////////////////// - - /*! - @brief get codepoint from 4 hex characters following `\u` - - For input "\u c1 c2 c3 c4" the codepoint is: - (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 - = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) - - Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' - must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The - conversion is done by subtracting the offset (0x30, 0x37, and 0x57) - between the ASCII value of the character and the desired integer value. - - @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or - non-hex character) - */ - int get_codepoint() - { - // this function only makes sense after reading `\u` - JSON_ASSERT(current == 'u'); - int codepoint = 0; - - const auto factors = { 12u, 8u, 4u, 0u }; - for (const auto factor : factors) - { - get(); - - if (current >= '0' && current <= '9') - { - codepoint += static_cast((static_cast(current) - 0x30u) << factor); - } - else if (current >= 'A' && current <= 'F') - { - codepoint += static_cast((static_cast(current) - 0x37u) << factor); - } - else if (current >= 'a' && current <= 'f') - { - codepoint += static_cast((static_cast(current) - 0x57u) << factor); - } - else - { - return -1; - } - } - - JSON_ASSERT(0x0000 <= codepoint && codepoint <= 0xFFFF); - return codepoint; - } - - /*! - @brief check if the next byte(s) are inside a given range - - Adds the current byte and, for each passed range, reads a new byte and - checks if it is inside the range. If a violation was detected, set up an - error message and return false. Otherwise, return true. - - @param[in] ranges list of integers; interpreted as list of pairs of - inclusive lower and upper bound, respectively - - @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, - 1, 2, or 3 pairs. This precondition is enforced by an assertion. - - @return true if and only if no range violation was detected - */ - bool next_byte_in_range(std::initializer_list ranges) - { - JSON_ASSERT(ranges.size() == 2 || ranges.size() == 4 || ranges.size() == 6); - add(current); - - for (auto range = ranges.begin(); range != ranges.end(); ++range) - { - get(); - if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range))) - { - add(current); - } - else - { - error_message = "invalid string: ill-formed UTF-8 byte"; - return false; - } - } - - return true; - } - - /*! - @brief scan a string literal - - This function scans a string according to Sect. 7 of RFC 8259. While - scanning, bytes are escaped and copied into buffer token_buffer. Then the - function returns successfully, token_buffer is *not* null-terminated (as it - may contain \0 bytes), and token_buffer.size() is the number of bytes in the - string. - - @return token_type::value_string if string could be successfully scanned, - token_type::parse_error otherwise - - @note In case of errors, variable error_message contains a textual - description. - */ - token_type scan_string() - { - // reset token_buffer (ignore opening quote) - reset(); - - // we entered the function by reading an open quote - JSON_ASSERT(current == '\"'); - - while (true) - { - // get next character - switch (get()) - { - // end of file while parsing string - case std::char_traits::eof(): - { - error_message = "invalid string: missing closing quote"; - return token_type::parse_error; - } - - // closing quote - case '\"': - { - return token_type::value_string; - } - - // escapes - case '\\': - { - switch (get()) - { - // quotation mark - case '\"': - add('\"'); - break; - // reverse solidus - case '\\': - add('\\'); - break; - // solidus - case '/': - add('/'); - break; - // backspace - case 'b': - add('\b'); - break; - // form feed - case 'f': - add('\f'); - break; - // line feed - case 'n': - add('\n'); - break; - // carriage return - case 'r': - add('\r'); - break; - // tab - case 't': - add('\t'); - break; - - // unicode escapes - case 'u': - { - const int codepoint1 = get_codepoint(); - int codepoint = codepoint1; // start with codepoint1 - - if (JSON_HEDLEY_UNLIKELY(codepoint1 == -1)) - { - error_message = "invalid string: '\\u' must be followed by 4 hex digits"; - return token_type::parse_error; - } - - // check if code point is a high surrogate - if (0xD800 <= codepoint1 && codepoint1 <= 0xDBFF) - { - // expect next \uxxxx entry - if (JSON_HEDLEY_LIKELY(get() == '\\' && get() == 'u')) - { - const int codepoint2 = get_codepoint(); - - if (JSON_HEDLEY_UNLIKELY(codepoint2 == -1)) - { - error_message = "invalid string: '\\u' must be followed by 4 hex digits"; - return token_type::parse_error; - } - - // check if codepoint2 is a low surrogate - if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 && codepoint2 <= 0xDFFF)) - { - // overwrite codepoint - codepoint = static_cast( - // high surrogate occupies the most significant 22 bits - (static_cast(codepoint1) << 10u) - // low surrogate occupies the least significant 15 bits - + static_cast(codepoint2) - // there is still the 0xD800, 0xDC00 and 0x10000 noise - // in the result, so we have to subtract with: - // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 - - 0x35FDC00u); - } - else - { - error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF"; - return token_type::parse_error; - } - } - else - { - error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF"; - return token_type::parse_error; - } - } - else - { - if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 && codepoint1 <= 0xDFFF)) - { - error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; - return token_type::parse_error; - } - } - - // result of the above calculation yields a proper codepoint - JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF); - - // translate codepoint into bytes - if (codepoint < 0x80) - { - // 1-byte characters: 0xxxxxxx (ASCII) - add(static_cast(codepoint)); - } - else if (codepoint <= 0x7FF) - { - // 2-byte characters: 110xxxxx 10xxxxxx - add(static_cast(0xC0u | (static_cast(codepoint) >> 6u))); - add(static_cast(0x80u | (static_cast(codepoint) & 0x3Fu))); - } - else if (codepoint <= 0xFFFF) - { - // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx - add(static_cast(0xE0u | (static_cast(codepoint) >> 12u))); - add(static_cast(0x80u | ((static_cast(codepoint) >> 6u) & 0x3Fu))); - add(static_cast(0x80u | (static_cast(codepoint) & 0x3Fu))); - } - else - { - // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - add(static_cast(0xF0u | (static_cast(codepoint) >> 18u))); - add(static_cast(0x80u | ((static_cast(codepoint) >> 12u) & 0x3Fu))); - add(static_cast(0x80u | ((static_cast(codepoint) >> 6u) & 0x3Fu))); - add(static_cast(0x80u | (static_cast(codepoint) & 0x3Fu))); - } - - break; - } - - // other characters after escape - default: - error_message = "invalid string: forbidden character after backslash"; - return token_type::parse_error; - } - - break; - } - - // invalid control characters - case 0x00: - { - error_message = "invalid string: control character U+0000 (NUL) must be escaped to \\u0000"; - return token_type::parse_error; - } - - case 0x01: - { - error_message = "invalid string: control character U+0001 (SOH) must be escaped to \\u0001"; - return token_type::parse_error; - } - - case 0x02: - { - error_message = "invalid string: control character U+0002 (STX) must be escaped to \\u0002"; - return token_type::parse_error; - } - - case 0x03: - { - error_message = "invalid string: control character U+0003 (ETX) must be escaped to \\u0003"; - return token_type::parse_error; - } - - case 0x04: - { - error_message = "invalid string: control character U+0004 (EOT) must be escaped to \\u0004"; - return token_type::parse_error; - } - - case 0x05: - { - error_message = "invalid string: control character U+0005 (ENQ) must be escaped to \\u0005"; - return token_type::parse_error; - } - - case 0x06: - { - error_message = "invalid string: control character U+0006 (ACK) must be escaped to \\u0006"; - return token_type::parse_error; - } - - case 0x07: - { - error_message = "invalid string: control character U+0007 (BEL) must be escaped to \\u0007"; - return token_type::parse_error; - } - - case 0x08: - { - error_message = "invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b"; - return token_type::parse_error; - } - - case 0x09: - { - error_message = "invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t"; - return token_type::parse_error; - } - - case 0x0A: - { - error_message = "invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n"; - return token_type::parse_error; - } - - case 0x0B: - { - error_message = "invalid string: control character U+000B (VT) must be escaped to \\u000B"; - return token_type::parse_error; - } - - case 0x0C: - { - error_message = "invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f"; - return token_type::parse_error; - } - - case 0x0D: - { - error_message = "invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r"; - return token_type::parse_error; - } - - case 0x0E: - { - error_message = "invalid string: control character U+000E (SO) must be escaped to \\u000E"; - return token_type::parse_error; - } - - case 0x0F: - { - error_message = "invalid string: control character U+000F (SI) must be escaped to \\u000F"; - return token_type::parse_error; - } - - case 0x10: - { - error_message = "invalid string: control character U+0010 (DLE) must be escaped to \\u0010"; - return token_type::parse_error; - } - - case 0x11: - { - error_message = "invalid string: control character U+0011 (DC1) must be escaped to \\u0011"; - return token_type::parse_error; - } - - case 0x12: - { - error_message = "invalid string: control character U+0012 (DC2) must be escaped to \\u0012"; - return token_type::parse_error; - } - - case 0x13: - { - error_message = "invalid string: control character U+0013 (DC3) must be escaped to \\u0013"; - return token_type::parse_error; - } - - case 0x14: - { - error_message = "invalid string: control character U+0014 (DC4) must be escaped to \\u0014"; - return token_type::parse_error; - } - - case 0x15: - { - error_message = "invalid string: control character U+0015 (NAK) must be escaped to \\u0015"; - return token_type::parse_error; - } - - case 0x16: - { - error_message = "invalid string: control character U+0016 (SYN) must be escaped to \\u0016"; - return token_type::parse_error; - } - - case 0x17: - { - error_message = "invalid string: control character U+0017 (ETB) must be escaped to \\u0017"; - return token_type::parse_error; - } - - case 0x18: - { - error_message = "invalid string: control character U+0018 (CAN) must be escaped to \\u0018"; - return token_type::parse_error; - } - - case 0x19: - { - error_message = "invalid string: control character U+0019 (EM) must be escaped to \\u0019"; - return token_type::parse_error; - } - - case 0x1A: - { - error_message = "invalid string: control character U+001A (SUB) must be escaped to \\u001A"; - return token_type::parse_error; - } - - case 0x1B: - { - error_message = "invalid string: control character U+001B (ESC) must be escaped to \\u001B"; - return token_type::parse_error; - } - - case 0x1C: - { - error_message = "invalid string: control character U+001C (FS) must be escaped to \\u001C"; - return token_type::parse_error; - } - - case 0x1D: - { - error_message = "invalid string: control character U+001D (GS) must be escaped to \\u001D"; - return token_type::parse_error; - } - - case 0x1E: - { - error_message = "invalid string: control character U+001E (RS) must be escaped to \\u001E"; - return token_type::parse_error; - } - - case 0x1F: - { - error_message = "invalid string: control character U+001F (US) must be escaped to \\u001F"; - return token_type::parse_error; - } - - // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) - case 0x20: - case 0x21: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2A: - case 0x2B: - case 0x2C: - case 0x2D: - case 0x2E: - case 0x2F: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3D: - case 0x3E: - case 0x3F: - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4A: - case 0x4B: - case 0x4C: - case 0x4D: - case 0x4E: - case 0x4F: - case 0x50: - case 0x51: - case 0x52: - case 0x53: - case 0x54: - case 0x55: - case 0x56: - case 0x57: - case 0x58: - case 0x59: - case 0x5A: - case 0x5B: - case 0x5D: - case 0x5E: - case 0x5F: - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: - case 0x79: - case 0x7A: - case 0x7B: - case 0x7C: - case 0x7D: - case 0x7E: - case 0x7F: - { - add(current); - break; - } - - // U+0080..U+07FF: bytes C2..DF 80..BF - case 0xC2: - case 0xC3: - case 0xC4: - case 0xC5: - case 0xC6: - case 0xC7: - case 0xC8: - case 0xC9: - case 0xCA: - case 0xCB: - case 0xCC: - case 0xCD: - case 0xCE: - case 0xCF: - case 0xD0: - case 0xD1: - case 0xD2: - case 0xD3: - case 0xD4: - case 0xD5: - case 0xD6: - case 0xD7: - case 0xD8: - case 0xD9: - case 0xDA: - case 0xDB: - case 0xDC: - case 0xDD: - case 0xDE: - case 0xDF: - { - if (JSON_HEDLEY_UNLIKELY(!next_byte_in_range({0x80, 0xBF}))) - { - return token_type::parse_error; - } - break; - } - - // U+0800..U+0FFF: bytes E0 A0..BF 80..BF - case 0xE0: - { - if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF - // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF - case 0xE1: - case 0xE2: - case 0xE3: - case 0xE4: - case 0xE5: - case 0xE6: - case 0xE7: - case 0xE8: - case 0xE9: - case 0xEA: - case 0xEB: - case 0xEC: - case 0xEE: - case 0xEF: - { - if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+D000..U+D7FF: bytes ED 80..9F 80..BF - case 0xED: - { - if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF - case 0xF0: - { - if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF - case 0xF1: - case 0xF2: - case 0xF3: - { - if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF - case 0xF4: - { - if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // remaining bytes (80..C1 and F5..FF) are ill-formed - default: - { - error_message = "invalid string: ill-formed UTF-8 byte"; - return token_type::parse_error; - } - } - } - } - - /*! - * @brief scan a comment - * @return whether comment could be scanned successfully - */ - bool scan_comment() - { - switch (get()) - { - // single-line comments skip input until a newline or EOF is read - case '/': - { - while (true) - { - switch (get()) - { - case '\n': - case '\r': - case std::char_traits::eof(): - case '\0': - return true; - - default: - break; - } - } - } - - // multi-line comments skip input until */ is read - case '*': - { - while (true) - { - switch (get()) - { - case std::char_traits::eof(): - case '\0': - { - error_message = "invalid comment; missing closing '*/'"; - return false; - } - - case '*': - { - switch (get()) - { - case '/': - return true; - - default: - { - unget(); - continue; - } - } - } - - default: - continue; - } - } - } - - // unexpected character after reading '/' - default: - { - error_message = "invalid comment; expecting '/' or '*' after '/'"; - return false; - } - } - } - - JSON_HEDLEY_NON_NULL(2) - static void strtof(float& f, const char* str, char** endptr) noexcept - { - f = std::strtof(str, endptr); - } - - JSON_HEDLEY_NON_NULL(2) - static void strtof(double& f, const char* str, char** endptr) noexcept - { - f = std::strtod(str, endptr); - } - - JSON_HEDLEY_NON_NULL(2) - static void strtof(long double& f, const char* str, char** endptr) noexcept - { - f = std::strtold(str, endptr); - } - - /*! - @brief scan a number literal - - This function scans a string according to Sect. 6 of RFC 8259. - - The function is realized with a deterministic finite state machine derived - from the grammar described in RFC 8259. Starting in state "init", the - input is read and used to determined the next state. Only state "done" - accepts the number. State "error" is a trap state to model errors. In the - table below, "anything" means any character but the ones listed before. - - state | 0 | 1-9 | e E | + | - | . | anything - ---------|----------|----------|----------|---------|---------|----------|----------- - init | zero | any1 | [error] | [error] | minus | [error] | [error] - minus | zero | any1 | [error] | [error] | [error] | [error] | [error] - zero | done | done | exponent | done | done | decimal1 | done - any1 | any1 | any1 | exponent | done | done | decimal1 | done - decimal1 | decimal2 | decimal2 | [error] | [error] | [error] | [error] | [error] - decimal2 | decimal2 | decimal2 | exponent | done | done | done | done - exponent | any2 | any2 | [error] | sign | sign | [error] | [error] - sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] - any2 | any2 | any2 | done | done | done | done | done - - The state machine is realized with one label per state (prefixed with - "scan_number_") and `goto` statements between them. The state machine - contains cycles, but any cycle can be left when EOF is read. Therefore, - the function is guaranteed to terminate. - - During scanning, the read bytes are stored in token_buffer. This string is - then converted to a signed integer, an unsigned integer, or a - floating-point number. - - @return token_type::value_unsigned, token_type::value_integer, or - token_type::value_float if number could be successfully scanned, - token_type::parse_error otherwise - - @note The scanner is independent of the current locale. Internally, the - locale's decimal point is used instead of `.` to work with the - locale-dependent converters. - */ - token_type scan_number() // lgtm [cpp/use-of-goto] - { - // reset token_buffer to store the number's bytes - reset(); - - // the type of the parsed number; initially set to unsigned; will be - // changed if minus sign, decimal point or exponent is read - token_type number_type = token_type::value_unsigned; - - // state (init): we just found out we need to scan a number - switch (current) - { - case '-': - { - add(current); - goto scan_number_minus; - } - - case '0': - { - add(current); - goto scan_number_zero; - } - - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } - - // all other characters are rejected outside scan_number() - default: // LCOV_EXCL_LINE - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE - } - -scan_number_minus: - // state: we just parsed a leading minus sign - number_type = token_type::value_integer; - switch (get()) - { - case '0': - { - add(current); - goto scan_number_zero; - } - - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } - - default: - { - error_message = "invalid number; expected digit after '-'"; - return token_type::parse_error; - } - } - -scan_number_zero: - // state: we just parse a zero (maybe with a leading minus sign) - switch (get()) - { - case '.': - { - add(decimal_point_char); - goto scan_number_decimal1; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - goto scan_number_done; - } - -scan_number_any1: - // state: we just parsed a number 0-9 (maybe with a leading minus sign) - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } - - case '.': - { - add(decimal_point_char); - goto scan_number_decimal1; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - goto scan_number_done; - } - -scan_number_decimal1: - // state: we just parsed a decimal point - number_type = token_type::value_float; - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_decimal2; - } - - default: - { - error_message = "invalid number; expected digit after '.'"; - return token_type::parse_error; - } - } - -scan_number_decimal2: - // we just parsed at least one number after a decimal point - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_decimal2; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - goto scan_number_done; - } - -scan_number_exponent: - // we just parsed an exponent - number_type = token_type::value_float; - switch (get()) - { - case '+': - case '-': - { - add(current); - goto scan_number_sign; - } - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - { - error_message = - "invalid number; expected '+', '-', or digit after exponent"; - return token_type::parse_error; - } - } - -scan_number_sign: - // we just parsed an exponent sign - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - { - error_message = "invalid number; expected digit after exponent sign"; - return token_type::parse_error; - } - } - -scan_number_any2: - // we just parsed a number after the exponent or exponent sign - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - goto scan_number_done; - } - -scan_number_done: - // unget the character after the number (we only read it to know that - // we are done scanning a number) - unget(); - - char* endptr = nullptr; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) - errno = 0; - - // try to parse integers first and fall back to floats - if (number_type == token_type::value_unsigned) - { - const auto x = std::strtoull(token_buffer.data(), &endptr, 10); - - // we checked the number format before - JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); - - if (errno == 0) - { - value_unsigned = static_cast(x); - if (value_unsigned == x) - { - return token_type::value_unsigned; - } - } - } - else if (number_type == token_type::value_integer) - { - const auto x = std::strtoll(token_buffer.data(), &endptr, 10); - - // we checked the number format before - JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); - - if (errno == 0) - { - value_integer = static_cast(x); - if (value_integer == x) - { - return token_type::value_integer; - } - } - } - - // this code is reached if we parse a floating-point number or if an - // integer conversion above failed - strtof(value_float, token_buffer.data(), &endptr); - - // we checked the number format before - JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); - - return token_type::value_float; - } - - /*! - @param[in] literal_text the literal text to expect - @param[in] length the length of the passed literal text - @param[in] return_type the token type to return on success - */ - JSON_HEDLEY_NON_NULL(2) - token_type scan_literal(const char_type* literal_text, const std::size_t length, - token_type return_type) - { - JSON_ASSERT(std::char_traits::to_char_type(current) == literal_text[0]); - for (std::size_t i = 1; i < length; ++i) - { - if (JSON_HEDLEY_UNLIKELY(std::char_traits::to_char_type(get()) != literal_text[i])) - { - error_message = "invalid literal"; - return token_type::parse_error; - } - } - return return_type; - } - - ///////////////////// - // input management - ///////////////////// - - /// reset token_buffer; current character is beginning of token - void reset() noexcept - { - token_buffer.clear(); - token_string.clear(); - token_string.push_back(std::char_traits::to_char_type(current)); - } - - /* - @brief get next character from the input - - This function provides the interface to the used input adapter. It does - not throw in case the input reached EOF, but returns a - `std::char_traits::eof()` in that case. Stores the scanned characters - for use in error messages. - - @return character read from the input - */ - char_int_type get() - { - ++position.chars_read_total; - ++position.chars_read_current_line; - - if (next_unget) - { - // just reset the next_unget variable and work with current - next_unget = false; - } - else - { - current = ia.get_character(); - } - - if (JSON_HEDLEY_LIKELY(current != std::char_traits::eof())) - { - token_string.push_back(std::char_traits::to_char_type(current)); - } - - if (current == '\n') - { - ++position.lines_read; - position.chars_read_current_line = 0; - } - - return current; - } - - /*! - @brief unget current character (read it again on next get) - - We implement unget by setting variable next_unget to true. The input is not - changed - we just simulate ungetting by modifying chars_read_total, - chars_read_current_line, and token_string. The next call to get() will - behave as if the unget character is read again. - */ - void unget() - { - next_unget = true; - - --position.chars_read_total; - - // in case we "unget" a newline, we have to also decrement the lines_read - if (position.chars_read_current_line == 0) - { - if (position.lines_read > 0) - { - --position.lines_read; - } - } - else - { - --position.chars_read_current_line; - } - - if (JSON_HEDLEY_LIKELY(current != std::char_traits::eof())) - { - JSON_ASSERT(!token_string.empty()); - token_string.pop_back(); - } - } - - /// add a character to token_buffer - void add(char_int_type c) - { - token_buffer.push_back(static_cast(c)); - } - - public: - ///////////////////// - // value getters - ///////////////////// - - /// return integer value - constexpr number_integer_t get_number_integer() const noexcept - { - return value_integer; - } - - /// return unsigned integer value - constexpr number_unsigned_t get_number_unsigned() const noexcept - { - return value_unsigned; - } - - /// return floating-point value - constexpr number_float_t get_number_float() const noexcept - { - return value_float; - } - - /// return current string value (implicitly resets the token; useful only once) - string_t& get_string() - { - return token_buffer; - } - - ///////////////////// - // diagnostics - ///////////////////// - - /// return position of last read token - constexpr position_t get_position() const noexcept - { - return position; - } - - /// return the last read token (for errors only). Will never contain EOF - /// (an arbitrary value that is not a valid char value, often -1), because - /// 255 may legitimately occur. May contain NUL, which should be escaped. - std::string get_token_string() const - { - // escape control characters - std::string result; - for (const auto c : token_string) - { - if (static_cast(c) <= '\x1F') - { - // escape control characters - std::array cs{{}}; - static_cast((std::snprintf)(cs.data(), cs.size(), "", static_cast(c))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) - result += cs.data(); - } - else - { - // add character as is - result.push_back(static_cast(c)); - } - } - - return result; - } - - /// return syntax error message - JSON_HEDLEY_RETURNS_NON_NULL - constexpr const char* get_error_message() const noexcept - { - return error_message; - } - - ///////////////////// - // actual scanner - ///////////////////// - - /*! - @brief skip the UTF-8 byte order mark - @return true iff there is no BOM or the correct BOM has been skipped - */ - bool skip_bom() - { - if (get() == 0xEF) - { - // check if we completely parse the BOM - return get() == 0xBB && get() == 0xBF; - } - - // the first character is not the beginning of the BOM; unget it to - // process is later - unget(); - return true; - } - - void skip_whitespace() - { - do - { - get(); - } - while (current == ' ' || current == '\t' || current == '\n' || current == '\r'); - } - - token_type scan() - { - // initially, skip the BOM - if (position.chars_read_total == 0 && !skip_bom()) - { - error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given"; - return token_type::parse_error; - } - - // read next character and ignore whitespace - skip_whitespace(); - - // ignore comments - while (ignore_comments && current == '/') - { - if (!scan_comment()) - { - return token_type::parse_error; - } - - // skip following whitespace - skip_whitespace(); - } - - switch (current) - { - // structural characters - case '[': - return token_type::begin_array; - case ']': - return token_type::end_array; - case '{': - return token_type::begin_object; - case '}': - return token_type::end_object; - case ':': - return token_type::name_separator; - case ',': - return token_type::value_separator; - - // literals - case 't': - { - std::array true_literal = {{static_cast('t'), static_cast('r'), static_cast('u'), static_cast('e')}}; - return scan_literal(true_literal.data(), true_literal.size(), token_type::literal_true); - } - case 'f': - { - std::array false_literal = {{static_cast('f'), static_cast('a'), static_cast('l'), static_cast('s'), static_cast('e')}}; - return scan_literal(false_literal.data(), false_literal.size(), token_type::literal_false); - } - case 'n': - { - std::array null_literal = {{static_cast('n'), static_cast('u'), static_cast('l'), static_cast('l')}}; - return scan_literal(null_literal.data(), null_literal.size(), token_type::literal_null); - } - - // string - case '\"': - return scan_string(); - - // number - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return scan_number(); - - // end of input (the null byte is needed when parsing from - // string literals) - case '\0': - case std::char_traits::eof(): - return token_type::end_of_input; - - // error - default: - error_message = "invalid literal"; - return token_type::parse_error; - } - } - - private: - /// input adapter - InputAdapterType ia; - - /// whether comments should be ignored (true) or signaled as errors (false) - const bool ignore_comments = false; - - /// the current character - char_int_type current = std::char_traits::eof(); - - /// whether the next get() call should just return current - bool next_unget = false; - - /// the start position of the current token - position_t position {}; - - /// raw input token string (for error messages) - std::vector token_string {}; - - /// buffer for variable-length tokens (numbers, strings) - string_t token_buffer {}; - - /// a description of occurred lexer errors - const char* error_message = ""; - - // number values - number_integer_t value_integer = 0; - number_unsigned_t value_unsigned = 0; - number_float_t value_float = 0; - - /// the decimal point - const char_int_type decimal_point_char = '.'; -}; -} // namespace detail -} // namespace nlohmann - -// #include - -// #include - - -#include // size_t -#include // declval -#include // string - -// #include - -// #include - - -namespace nlohmann -{ -namespace detail -{ -template -using null_function_t = decltype(std::declval().null()); - -template -using boolean_function_t = - decltype(std::declval().boolean(std::declval())); - -template -using number_integer_function_t = - decltype(std::declval().number_integer(std::declval())); - -template -using number_unsigned_function_t = - decltype(std::declval().number_unsigned(std::declval())); - -template -using number_float_function_t = decltype(std::declval().number_float( - std::declval(), std::declval())); - -template -using string_function_t = - decltype(std::declval().string(std::declval())); - -template -using binary_function_t = - decltype(std::declval().binary(std::declval())); - -template -using start_object_function_t = - decltype(std::declval().start_object(std::declval())); - -template -using key_function_t = - decltype(std::declval().key(std::declval())); - -template -using end_object_function_t = decltype(std::declval().end_object()); - -template -using start_array_function_t = - decltype(std::declval().start_array(std::declval())); - -template -using end_array_function_t = decltype(std::declval().end_array()); - -template -using parse_error_function_t = decltype(std::declval().parse_error( - std::declval(), std::declval(), - std::declval())); - -template -struct is_sax -{ - private: - static_assert(is_basic_json::value, - "BasicJsonType must be of type basic_json<...>"); - - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; - using exception_t = typename BasicJsonType::exception; - - public: - static constexpr bool value = - is_detected_exact::value && - is_detected_exact::value && - is_detected_exact::value && - is_detected_exact::value && - is_detected_exact::value && - is_detected_exact::value && - is_detected_exact::value && - is_detected_exact::value && - is_detected_exact::value && - is_detected_exact::value && - is_detected_exact::value && - is_detected_exact::value && - is_detected_exact::value; -}; - -template -struct is_sax_static_asserts -{ - private: - static_assert(is_basic_json::value, - "BasicJsonType must be of type basic_json<...>"); - - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; - using exception_t = typename BasicJsonType::exception; - - public: - static_assert(is_detected_exact::value, - "Missing/invalid function: bool null()"); - static_assert(is_detected_exact::value, - "Missing/invalid function: bool boolean(bool)"); - static_assert(is_detected_exact::value, - "Missing/invalid function: bool boolean(bool)"); - static_assert( - is_detected_exact::value, - "Missing/invalid function: bool number_integer(number_integer_t)"); - static_assert( - is_detected_exact::value, - "Missing/invalid function: bool number_unsigned(number_unsigned_t)"); - static_assert(is_detected_exact::value, - "Missing/invalid function: bool number_float(number_float_t, const string_t&)"); - static_assert( - is_detected_exact::value, - "Missing/invalid function: bool string(string_t&)"); - static_assert( - is_detected_exact::value, - "Missing/invalid function: bool binary(binary_t&)"); - static_assert(is_detected_exact::value, - "Missing/invalid function: bool start_object(std::size_t)"); - static_assert(is_detected_exact::value, - "Missing/invalid function: bool key(string_t&)"); - static_assert(is_detected_exact::value, - "Missing/invalid function: bool end_object()"); - static_assert(is_detected_exact::value, - "Missing/invalid function: bool start_array(std::size_t)"); - static_assert(is_detected_exact::value, - "Missing/invalid function: bool end_array()"); - static_assert( - is_detected_exact::value, - "Missing/invalid function: bool parse_error(std::size_t, const " - "std::string&, const exception&)"); -}; -} // namespace detail -} // namespace nlohmann - -// #include - -// #include - - -namespace nlohmann -{ -namespace detail -{ - -/// how to treat CBOR tags -enum class cbor_tag_handler_t -{ - error, ///< throw a parse_error exception in case of a tag - ignore, ///< ignore tags - store ///< store tags as binary type -}; - -/*! -@brief determine system byte order - -@return true if and only if system's byte order is little endian - -@note from https://stackoverflow.com/a/1001328/266378 -*/ -static inline bool little_endianness(int num = 1) noexcept -{ - return *reinterpret_cast(&num) == 1; -} - - -/////////////////// -// binary reader // -/////////////////// - -/*! -@brief deserialization of CBOR, MessagePack, and UBJSON values -*/ -template> -class binary_reader -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; - using json_sax_t = SAX; - using char_type = typename InputAdapterType::char_type; - using char_int_type = typename std::char_traits::int_type; - - public: - /*! - @brief create a binary reader - - @param[in] adapter input adapter to read from - */ - explicit binary_reader(InputAdapterType&& adapter) noexcept : ia(std::move(adapter)) - { - (void)detail::is_sax_static_asserts {}; - } - - // make class move-only - binary_reader(const binary_reader&) = delete; - binary_reader(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - binary_reader& operator=(const binary_reader&) = delete; - binary_reader& operator=(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - ~binary_reader() = default; - - /*! - @param[in] format the binary format to parse - @param[in] sax_ a SAX event processor - @param[in] strict whether to expect the input to be consumed completed - @param[in] tag_handler how to treat CBOR tags - - @return whether parsing was successful - */ - JSON_HEDLEY_NON_NULL(3) - bool sax_parse(const input_format_t format, - json_sax_t* sax_, - const bool strict = true, - const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) - { - sax = sax_; - bool result = false; - - switch (format) - { - case input_format_t::bson: - result = parse_bson_internal(); - break; - - case input_format_t::cbor: - result = parse_cbor_internal(true, tag_handler); - break; - - case input_format_t::msgpack: - result = parse_msgpack_internal(); - break; - - case input_format_t::ubjson: - result = parse_ubjson_internal(); - break; - - case input_format_t::json: // LCOV_EXCL_LINE - default: // LCOV_EXCL_LINE - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE - } - - // strict mode: next byte must be EOF - if (result && strict) - { - if (format == input_format_t::ubjson) - { - get_ignore_noop(); - } - else - { - get(); - } - - if (JSON_HEDLEY_UNLIKELY(current != std::char_traits::eof())) - { - return sax->parse_error(chars_read, get_token_string(), - parse_error::create(110, chars_read, exception_message(format, "expected end of input; last byte: 0x" + get_token_string(), "value"), BasicJsonType())); - } - } - - return result; - } - - private: - ////////// - // BSON // - ////////// - - /*! - @brief Reads in a BSON-object and passes it to the SAX-parser. - @return whether a valid BSON-value was passed to the SAX parser - */ - bool parse_bson_internal() - { - std::int32_t document_size{}; - get_number(input_format_t::bson, document_size); - - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast(-1)))) - { - return false; - } - - if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/false))) - { - return false; - } - - return sax->end_object(); - } - - /*! - @brief Parses a C-style string from the BSON input. - @param[in,out] result A reference to the string variable where the read - string is to be stored. - @return `true` if the \x00-byte indicating the end of the string was - encountered before the EOF; false` indicates an unexpected EOF. - */ - bool get_bson_cstr(string_t& result) - { - auto out = std::back_inserter(result); - while (true) - { - get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "cstring"))) - { - return false; - } - if (current == 0x00) - { - return true; - } - *out++ = static_cast(current); - } - } - - /*! - @brief Parses a zero-terminated string of length @a len from the BSON - input. - @param[in] len The length (including the zero-byte at the end) of the - string to be read. - @param[in,out] result A reference to the string variable where the read - string is to be stored. - @tparam NumberType The type of the length @a len - @pre len >= 1 - @return `true` if the string was successfully parsed - */ - template - bool get_bson_string(const NumberType len, string_t& result) - { - if (JSON_HEDLEY_UNLIKELY(len < 1)) - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "string length must be at least 1, is " + std::to_string(len), "string"), BasicJsonType())); - } - - return get_string(input_format_t::bson, len - static_cast(1), result) && get() != std::char_traits::eof(); - } - - /*! - @brief Parses a byte array input of length @a len from the BSON input. - @param[in] len The length of the byte array to be read. - @param[in,out] result A reference to the binary variable where the read - array is to be stored. - @tparam NumberType The type of the length @a len - @pre len >= 0 - @return `true` if the byte array was successfully parsed - */ - template - bool get_bson_binary(const NumberType len, binary_t& result) - { - if (JSON_HEDLEY_UNLIKELY(len < 0)) - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "byte array length cannot be negative, is " + std::to_string(len), "binary"), BasicJsonType())); - } - - // All BSON binary values have a subtype - std::uint8_t subtype{}; - get_number(input_format_t::bson, subtype); - result.set_subtype(subtype); - - return get_binary(input_format_t::bson, len, result); - } - - /*! - @brief Read a BSON document element of the given @a element_type. - @param[in] element_type The BSON element type, c.f. http://bsonspec.org/spec.html - @param[in] element_type_parse_position The position in the input stream, - where the `element_type` was read. - @warning Not all BSON element types are supported yet. An unsupported - @a element_type will give rise to a parse_error.114: - Unsupported BSON record type 0x... - @return whether a valid BSON-object/array was passed to the SAX parser - */ - bool parse_bson_element_internal(const char_int_type element_type, - const std::size_t element_type_parse_position) - { - switch (element_type) - { - case 0x01: // double - { - double number{}; - return get_number(input_format_t::bson, number) && sax->number_float(static_cast(number), ""); - } - - case 0x02: // string - { - std::int32_t len{}; - string_t value; - return get_number(input_format_t::bson, len) && get_bson_string(len, value) && sax->string(value); - } - - case 0x03: // object - { - return parse_bson_internal(); - } - - case 0x04: // array - { - return parse_bson_array(); - } - - case 0x05: // binary - { - std::int32_t len{}; - binary_t value; - return get_number(input_format_t::bson, len) && get_bson_binary(len, value) && sax->binary(value); - } - - case 0x08: // boolean - { - return sax->boolean(get() != 0); - } - - case 0x0A: // null - { - return sax->null(); - } - - case 0x10: // int32 - { - std::int32_t value{}; - return get_number(input_format_t::bson, value) && sax->number_integer(value); - } - - case 0x12: // int64 - { - std::int64_t value{}; - return get_number(input_format_t::bson, value) && sax->number_integer(value); - } - - default: // anything else not supported (yet) - { - std::array cr{{}}; - static_cast((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(element_type))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) - return sax->parse_error(element_type_parse_position, std::string(cr.data()), parse_error::create(114, element_type_parse_position, "Unsupported BSON record type 0x" + std::string(cr.data()), BasicJsonType())); - } - } - } - - /*! - @brief Read a BSON element list (as specified in the BSON-spec) - - The same binary layout is used for objects and arrays, hence it must be - indicated with the argument @a is_array which one is expected - (true --> array, false --> object). - - @param[in] is_array Determines if the element list being read is to be - treated as an object (@a is_array == false), or as an - array (@a is_array == true). - @return whether a valid BSON-object/array was passed to the SAX parser - */ - bool parse_bson_element_list(const bool is_array) - { - string_t key; - - while (auto element_type = get()) - { - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "element list"))) - { - return false; - } - - const std::size_t element_type_parse_position = chars_read; - if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key))) - { - return false; - } - - if (!is_array && !sax->key(key)) - { - return false; - } - - if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_internal(element_type, element_type_parse_position))) - { - return false; - } - - // get_bson_cstr only appends - key.clear(); - } - - return true; - } - - /*! - @brief Reads an array from the BSON input and passes it to the SAX-parser. - @return whether a valid BSON-array was passed to the SAX parser - */ - bool parse_bson_array() - { - std::int32_t document_size{}; - get_number(input_format_t::bson, document_size); - - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast(-1)))) - { - return false; - } - - if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/true))) - { - return false; - } - - return sax->end_array(); - } - - ////////// - // CBOR // - ////////// - - /*! - @param[in] get_char whether a new character should be retrieved from the - input (true) or whether the last read character should - be considered instead (false) - @param[in] tag_handler how CBOR tags should be treated - - @return whether a valid CBOR value was passed to the SAX parser - */ - bool parse_cbor_internal(const bool get_char, - const cbor_tag_handler_t tag_handler) - { - switch (get_char ? get() : current) - { - // EOF - case std::char_traits::eof(): - return unexpect_eof(input_format_t::cbor, "value"); - - // Integer 0x00..0x17 (0..23) - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - case 0x0C: - case 0x0D: - case 0x0E: - case 0x0F: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - return sax->number_unsigned(static_cast(current)); - - case 0x18: // Unsigned integer (one-byte uint8_t follows) - { - std::uint8_t number{}; - return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); - } - - case 0x19: // Unsigned integer (two-byte uint16_t follows) - { - std::uint16_t number{}; - return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); - } - - case 0x1A: // Unsigned integer (four-byte uint32_t follows) - { - std::uint32_t number{}; - return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); - } - - case 0x1B: // Unsigned integer (eight-byte uint64_t follows) - { - std::uint64_t number{}; - return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); - } - - // Negative integer -1-0x00..-1-0x17 (-1..-24) - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2A: - case 0x2B: - case 0x2C: - case 0x2D: - case 0x2E: - case 0x2F: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - return sax->number_integer(static_cast(0x20 - 1 - current)); - - case 0x38: // Negative integer (one-byte uint8_t follows) - { - std::uint8_t number{}; - return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); - } - - case 0x39: // Negative integer -1-n (two-byte uint16_t follows) - { - std::uint16_t number{}; - return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); - } - - case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) - { - std::uint32_t number{}; - return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); - } - - case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) - { - std::uint64_t number{}; - return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - - static_cast(number)); - } - - // Binary data (0x00..0x17 bytes follow) - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4A: - case 0x4B: - case 0x4C: - case 0x4D: - case 0x4E: - case 0x4F: - case 0x50: - case 0x51: - case 0x52: - case 0x53: - case 0x54: - case 0x55: - case 0x56: - case 0x57: - case 0x58: // Binary data (one-byte uint8_t for n follows) - case 0x59: // Binary data (two-byte uint16_t for n follow) - case 0x5A: // Binary data (four-byte uint32_t for n follow) - case 0x5B: // Binary data (eight-byte uint64_t for n follow) - case 0x5F: // Binary data (indefinite length) - { - binary_t b; - return get_cbor_binary(b) && sax->binary(b); - } - - // UTF-8 string (0x00..0x17 bytes follow) - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: // UTF-8 string (one-byte uint8_t for n follows) - case 0x79: // UTF-8 string (two-byte uint16_t for n follow) - case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) - case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) - case 0x7F: // UTF-8 string (indefinite length) - { - string_t s; - return get_cbor_string(s) && sax->string(s); - } - - // array (0x00..0x17 data items follow) - case 0x80: - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x85: - case 0x86: - case 0x87: - case 0x88: - case 0x89: - case 0x8A: - case 0x8B: - case 0x8C: - case 0x8D: - case 0x8E: - case 0x8F: - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - return get_cbor_array(static_cast(static_cast(current) & 0x1Fu), tag_handler); - - case 0x98: // array (one-byte uint8_t for n follows) - { - std::uint8_t len{}; - return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); - } - - case 0x99: // array (two-byte uint16_t for n follow) - { - std::uint16_t len{}; - return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); - } - - case 0x9A: // array (four-byte uint32_t for n follow) - { - std::uint32_t len{}; - return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); - } - - case 0x9B: // array (eight-byte uint64_t for n follow) - { - std::uint64_t len{}; - return get_number(input_format_t::cbor, len) && get_cbor_array(detail::conditional_static_cast(len), tag_handler); - } - - case 0x9F: // array (indefinite length) - return get_cbor_array(static_cast(-1), tag_handler); - - // map (0x00..0x17 pairs of data items follow) - case 0xA0: - case 0xA1: - case 0xA2: - case 0xA3: - case 0xA4: - case 0xA5: - case 0xA6: - case 0xA7: - case 0xA8: - case 0xA9: - case 0xAA: - case 0xAB: - case 0xAC: - case 0xAD: - case 0xAE: - case 0xAF: - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - return get_cbor_object(static_cast(static_cast(current) & 0x1Fu), tag_handler); - - case 0xB8: // map (one-byte uint8_t for n follows) - { - std::uint8_t len{}; - return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); - } - - case 0xB9: // map (two-byte uint16_t for n follow) - { - std::uint16_t len{}; - return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); - } - - case 0xBA: // map (four-byte uint32_t for n follow) - { - std::uint32_t len{}; - return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); - } - - case 0xBB: // map (eight-byte uint64_t for n follow) - { - std::uint64_t len{}; - return get_number(input_format_t::cbor, len) && get_cbor_object(detail::conditional_static_cast(len), tag_handler); - } - - case 0xBF: // map (indefinite length) - return get_cbor_object(static_cast(-1), tag_handler); - - case 0xC6: // tagged item - case 0xC7: - case 0xC8: - case 0xC9: - case 0xCA: - case 0xCB: - case 0xCC: - case 0xCD: - case 0xCE: - case 0xCF: - case 0xD0: - case 0xD1: - case 0xD2: - case 0xD3: - case 0xD4: - case 0xD8: // tagged item (1 bytes follow) - case 0xD9: // tagged item (2 bytes follow) - case 0xDA: // tagged item (4 bytes follow) - case 0xDB: // tagged item (8 bytes follow) - { - switch (tag_handler) - { - case cbor_tag_handler_t::error: - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value"), BasicJsonType())); - } - - case cbor_tag_handler_t::ignore: - { - // ignore binary subtype - switch (current) - { - case 0xD8: - { - std::uint8_t subtype_to_ignore{}; - get_number(input_format_t::cbor, subtype_to_ignore); - break; - } - case 0xD9: - { - std::uint16_t subtype_to_ignore{}; - get_number(input_format_t::cbor, subtype_to_ignore); - break; - } - case 0xDA: - { - std::uint32_t subtype_to_ignore{}; - get_number(input_format_t::cbor, subtype_to_ignore); - break; - } - case 0xDB: - { - std::uint64_t subtype_to_ignore{}; - get_number(input_format_t::cbor, subtype_to_ignore); - break; - } - default: - break; - } - return parse_cbor_internal(true, tag_handler); - } - - case cbor_tag_handler_t::store: - { - binary_t b; - // use binary subtype and store in binary container - switch (current) - { - case 0xD8: - { - std::uint8_t subtype{}; - get_number(input_format_t::cbor, subtype); - b.set_subtype(detail::conditional_static_cast(subtype)); - break; - } - case 0xD9: - { - std::uint16_t subtype{}; - get_number(input_format_t::cbor, subtype); - b.set_subtype(detail::conditional_static_cast(subtype)); - break; - } - case 0xDA: - { - std::uint32_t subtype{}; - get_number(input_format_t::cbor, subtype); - b.set_subtype(detail::conditional_static_cast(subtype)); - break; - } - case 0xDB: - { - std::uint64_t subtype{}; - get_number(input_format_t::cbor, subtype); - b.set_subtype(detail::conditional_static_cast(subtype)); - break; - } - default: - return parse_cbor_internal(true, tag_handler); - } - get(); - return get_cbor_binary(b) && sax->binary(b); - } - - default: // LCOV_EXCL_LINE - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE - return false; // LCOV_EXCL_LINE - } - } - - case 0xF4: // false - return sax->boolean(false); - - case 0xF5: // true - return sax->boolean(true); - - case 0xF6: // null - return sax->null(); - - case 0xF9: // Half-Precision Float (two-byte IEEE 754) - { - const auto byte1_raw = get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number"))) - { - return false; - } - const auto byte2_raw = get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number"))) - { - return false; - } - - const auto byte1 = static_cast(byte1_raw); - const auto byte2 = static_cast(byte2_raw); - - // code from RFC 7049, Appendix D, Figure 3: - // As half-precision floating-point numbers were only added - // to IEEE 754 in 2008, today's programming platforms often - // still only have limited support for them. It is very - // easy to include at least decoding support for them even - // without such support. An example of a small decoder for - // half-precision floating-point numbers in the C language - // is shown in Fig. 3. - const auto half = static_cast((byte1 << 8u) + byte2); - const double val = [&half] - { - const int exp = (half >> 10u) & 0x1Fu; - const unsigned int mant = half & 0x3FFu; - JSON_ASSERT(0 <= exp&& exp <= 32); - JSON_ASSERT(mant <= 1024); - switch (exp) - { - case 0: - return std::ldexp(mant, -24); - case 31: - return (mant == 0) - ? std::numeric_limits::infinity() - : std::numeric_limits::quiet_NaN(); - default: - return std::ldexp(mant + 1024, exp - 25); - } - }(); - return sax->number_float((half & 0x8000u) != 0 - ? static_cast(-val) - : static_cast(val), ""); - } - - case 0xFA: // Single-Precision Float (four-byte IEEE 754) - { - float number{}; - return get_number(input_format_t::cbor, number) && sax->number_float(static_cast(number), ""); - } - - case 0xFB: // Double-Precision Float (eight-byte IEEE 754) - { - double number{}; - return get_number(input_format_t::cbor, number) && sax->number_float(static_cast(number), ""); - } - - default: // anything else (0xFF is handled inside the other types) - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value"), BasicJsonType())); - } - } - } - - /*! - @brief reads a CBOR string - - This function first reads starting bytes to determine the expected - string length and then copies this number of bytes into a string. - Additionally, CBOR's strings with indefinite lengths are supported. - - @param[out] result created string - - @return whether string creation completed - */ - bool get_cbor_string(string_t& result) - { - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "string"))) - { - return false; - } - - switch (current) - { - // UTF-8 string (0x00..0x17 bytes follow) - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - { - return get_string(input_format_t::cbor, static_cast(current) & 0x1Fu, result); - } - - case 0x78: // UTF-8 string (one-byte uint8_t for n follows) - { - std::uint8_t len{}; - return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); - } - - case 0x79: // UTF-8 string (two-byte uint16_t for n follow) - { - std::uint16_t len{}; - return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); - } - - case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) - { - std::uint32_t len{}; - return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); - } - - case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) - { - std::uint64_t len{}; - return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); - } - - case 0x7F: // UTF-8 string (indefinite length) - { - while (get() != 0xFF) - { - string_t chunk; - if (!get_cbor_string(chunk)) - { - return false; - } - result.append(chunk); - } - return true; - } - - default: - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x" + last_token, "string"), BasicJsonType())); - } - } - } - - /*! - @brief reads a CBOR byte array - - This function first reads starting bytes to determine the expected - byte array length and then copies this number of bytes into the byte array. - Additionally, CBOR's byte arrays with indefinite lengths are supported. - - @param[out] result created byte array - - @return whether byte array creation completed - */ - bool get_cbor_binary(binary_t& result) - { - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "binary"))) - { - return false; - } - - switch (current) - { - // Binary data (0x00..0x17 bytes follow) - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4A: - case 0x4B: - case 0x4C: - case 0x4D: - case 0x4E: - case 0x4F: - case 0x50: - case 0x51: - case 0x52: - case 0x53: - case 0x54: - case 0x55: - case 0x56: - case 0x57: - { - return get_binary(input_format_t::cbor, static_cast(current) & 0x1Fu, result); - } - - case 0x58: // Binary data (one-byte uint8_t for n follows) - { - std::uint8_t len{}; - return get_number(input_format_t::cbor, len) && - get_binary(input_format_t::cbor, len, result); - } - - case 0x59: // Binary data (two-byte uint16_t for n follow) - { - std::uint16_t len{}; - return get_number(input_format_t::cbor, len) && - get_binary(input_format_t::cbor, len, result); - } - - case 0x5A: // Binary data (four-byte uint32_t for n follow) - { - std::uint32_t len{}; - return get_number(input_format_t::cbor, len) && - get_binary(input_format_t::cbor, len, result); - } - - case 0x5B: // Binary data (eight-byte uint64_t for n follow) - { - std::uint64_t len{}; - return get_number(input_format_t::cbor, len) && - get_binary(input_format_t::cbor, len, result); - } - - case 0x5F: // Binary data (indefinite length) - { - while (get() != 0xFF) - { - binary_t chunk; - if (!get_cbor_binary(chunk)) - { - return false; - } - result.insert(result.end(), chunk.begin(), chunk.end()); - } - return true; - } - - default: - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x" + last_token, "binary"), BasicJsonType())); - } - } - } - - /*! - @param[in] len the length of the array or static_cast(-1) for an - array of indefinite size - @param[in] tag_handler how CBOR tags should be treated - @return whether array creation completed - */ - bool get_cbor_array(const std::size_t len, - const cbor_tag_handler_t tag_handler) - { - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len))) - { - return false; - } - - if (len != static_cast(-1)) - { - for (std::size_t i = 0; i < len; ++i) - { - if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) - { - return false; - } - } - } - else - { - while (get() != 0xFF) - { - if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(false, tag_handler))) - { - return false; - } - } - } - - return sax->end_array(); - } - - /*! - @param[in] len the length of the object or static_cast(-1) for an - object of indefinite size - @param[in] tag_handler how CBOR tags should be treated - @return whether object creation completed - */ - bool get_cbor_object(const std::size_t len, - const cbor_tag_handler_t tag_handler) - { - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len))) - { - return false; - } - - if (len != 0) - { - string_t key; - if (len != static_cast(-1)) - { - for (std::size_t i = 0; i < len; ++i) - { - get(); - if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) - { - return false; - } - - if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) - { - return false; - } - key.clear(); - } - } - else - { - while (get() != 0xFF) - { - if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) - { - return false; - } - - if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) - { - return false; - } - key.clear(); - } - } - } - - return sax->end_object(); - } - - ///////////// - // MsgPack // - ///////////// - - /*! - @return whether a valid MessagePack value was passed to the SAX parser - */ - bool parse_msgpack_internal() - { - switch (get()) - { - // EOF - case std::char_traits::eof(): - return unexpect_eof(input_format_t::msgpack, "value"); - - // positive fixint - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - case 0x0C: - case 0x0D: - case 0x0E: - case 0x0F: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1A: - case 0x1B: - case 0x1C: - case 0x1D: - case 0x1E: - case 0x1F: - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2A: - case 0x2B: - case 0x2C: - case 0x2D: - case 0x2E: - case 0x2F: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3D: - case 0x3E: - case 0x3F: - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4A: - case 0x4B: - case 0x4C: - case 0x4D: - case 0x4E: - case 0x4F: - case 0x50: - case 0x51: - case 0x52: - case 0x53: - case 0x54: - case 0x55: - case 0x56: - case 0x57: - case 0x58: - case 0x59: - case 0x5A: - case 0x5B: - case 0x5C: - case 0x5D: - case 0x5E: - case 0x5F: - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: - case 0x79: - case 0x7A: - case 0x7B: - case 0x7C: - case 0x7D: - case 0x7E: - case 0x7F: - return sax->number_unsigned(static_cast(current)); - - // fixmap - case 0x80: - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x85: - case 0x86: - case 0x87: - case 0x88: - case 0x89: - case 0x8A: - case 0x8B: - case 0x8C: - case 0x8D: - case 0x8E: - case 0x8F: - return get_msgpack_object(static_cast(static_cast(current) & 0x0Fu)); - - // fixarray - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - case 0x98: - case 0x99: - case 0x9A: - case 0x9B: - case 0x9C: - case 0x9D: - case 0x9E: - case 0x9F: - return get_msgpack_array(static_cast(static_cast(current) & 0x0Fu)); - - // fixstr - case 0xA0: - case 0xA1: - case 0xA2: - case 0xA3: - case 0xA4: - case 0xA5: - case 0xA6: - case 0xA7: - case 0xA8: - case 0xA9: - case 0xAA: - case 0xAB: - case 0xAC: - case 0xAD: - case 0xAE: - case 0xAF: - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - case 0xB8: - case 0xB9: - case 0xBA: - case 0xBB: - case 0xBC: - case 0xBD: - case 0xBE: - case 0xBF: - case 0xD9: // str 8 - case 0xDA: // str 16 - case 0xDB: // str 32 - { - string_t s; - return get_msgpack_string(s) && sax->string(s); - } - - case 0xC0: // nil - return sax->null(); - - case 0xC2: // false - return sax->boolean(false); - - case 0xC3: // true - return sax->boolean(true); - - case 0xC4: // bin 8 - case 0xC5: // bin 16 - case 0xC6: // bin 32 - case 0xC7: // ext 8 - case 0xC8: // ext 16 - case 0xC9: // ext 32 - case 0xD4: // fixext 1 - case 0xD5: // fixext 2 - case 0xD6: // fixext 4 - case 0xD7: // fixext 8 - case 0xD8: // fixext 16 - { - binary_t b; - return get_msgpack_binary(b) && sax->binary(b); - } - - case 0xCA: // float 32 - { - float number{}; - return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast(number), ""); - } - - case 0xCB: // float 64 - { - double number{}; - return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast(number), ""); - } - - case 0xCC: // uint 8 - { - std::uint8_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); - } - - case 0xCD: // uint 16 - { - std::uint16_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); - } - - case 0xCE: // uint 32 - { - std::uint32_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); - } - - case 0xCF: // uint 64 - { - std::uint64_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); - } - - case 0xD0: // int 8 - { - std::int8_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_integer(number); - } - - case 0xD1: // int 16 - { - std::int16_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_integer(number); - } - - case 0xD2: // int 32 - { - std::int32_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_integer(number); - } - - case 0xD3: // int 64 - { - std::int64_t number{}; - return get_number(input_format_t::msgpack, number) && sax->number_integer(number); - } - - case 0xDC: // array 16 - { - std::uint16_t len{}; - return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast(len)); - } - - case 0xDD: // array 32 - { - std::uint32_t len{}; - return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast(len)); - } - - case 0xDE: // map 16 - { - std::uint16_t len{}; - return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast(len)); - } - - case 0xDF: // map 32 - { - std::uint32_t len{}; - return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast(len)); - } - - // negative fixint - case 0xE0: - case 0xE1: - case 0xE2: - case 0xE3: - case 0xE4: - case 0xE5: - case 0xE6: - case 0xE7: - case 0xE8: - case 0xE9: - case 0xEA: - case 0xEB: - case 0xEC: - case 0xED: - case 0xEE: - case 0xEF: - case 0xF0: - case 0xF1: - case 0xF2: - case 0xF3: - case 0xF4: - case 0xF5: - case 0xF6: - case 0xF7: - case 0xF8: - case 0xF9: - case 0xFA: - case 0xFB: - case 0xFC: - case 0xFD: - case 0xFE: - case 0xFF: - return sax->number_integer(static_cast(current)); - - default: // anything else - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::msgpack, "invalid byte: 0x" + last_token, "value"), BasicJsonType())); - } - } - } - - /*! - @brief reads a MessagePack string - - This function first reads starting bytes to determine the expected - string length and then copies this number of bytes into a string. - - @param[out] result created string - - @return whether string creation completed - */ - bool get_msgpack_string(string_t& result) - { - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::msgpack, "string"))) - { - return false; - } - - switch (current) - { - // fixstr - case 0xA0: - case 0xA1: - case 0xA2: - case 0xA3: - case 0xA4: - case 0xA5: - case 0xA6: - case 0xA7: - case 0xA8: - case 0xA9: - case 0xAA: - case 0xAB: - case 0xAC: - case 0xAD: - case 0xAE: - case 0xAF: - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - case 0xB8: - case 0xB9: - case 0xBA: - case 0xBB: - case 0xBC: - case 0xBD: - case 0xBE: - case 0xBF: - { - return get_string(input_format_t::msgpack, static_cast(current) & 0x1Fu, result); - } - - case 0xD9: // str 8 - { - std::uint8_t len{}; - return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); - } - - case 0xDA: // str 16 - { - std::uint16_t len{}; - return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); - } - - case 0xDB: // str 32 - { - std::uint32_t len{}; - return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); - } - - default: - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::msgpack, "expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x" + last_token, "string"), BasicJsonType())); - } - } - } - - /*! - @brief reads a MessagePack byte array - - This function first reads starting bytes to determine the expected - byte array length and then copies this number of bytes into a byte array. - - @param[out] result created byte array - - @return whether byte array creation completed - */ - bool get_msgpack_binary(binary_t& result) - { - // helper function to set the subtype - auto assign_and_return_true = [&result](std::int8_t subtype) - { - result.set_subtype(static_cast(subtype)); - return true; - }; - - switch (current) - { - case 0xC4: // bin 8 - { - std::uint8_t len{}; - return get_number(input_format_t::msgpack, len) && - get_binary(input_format_t::msgpack, len, result); - } - - case 0xC5: // bin 16 - { - std::uint16_t len{}; - return get_number(input_format_t::msgpack, len) && - get_binary(input_format_t::msgpack, len, result); - } - - case 0xC6: // bin 32 - { - std::uint32_t len{}; - return get_number(input_format_t::msgpack, len) && - get_binary(input_format_t::msgpack, len, result); - } - - case 0xC7: // ext 8 - { - std::uint8_t len{}; - std::int8_t subtype{}; - return get_number(input_format_t::msgpack, len) && - get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, len, result) && - assign_and_return_true(subtype); - } - - case 0xC8: // ext 16 - { - std::uint16_t len{}; - std::int8_t subtype{}; - return get_number(input_format_t::msgpack, len) && - get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, len, result) && - assign_and_return_true(subtype); - } - - case 0xC9: // ext 32 - { - std::uint32_t len{}; - std::int8_t subtype{}; - return get_number(input_format_t::msgpack, len) && - get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, len, result) && - assign_and_return_true(subtype); - } - - case 0xD4: // fixext 1 - { - std::int8_t subtype{}; - return get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, 1, result) && - assign_and_return_true(subtype); - } - - case 0xD5: // fixext 2 - { - std::int8_t subtype{}; - return get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, 2, result) && - assign_and_return_true(subtype); - } - - case 0xD6: // fixext 4 - { - std::int8_t subtype{}; - return get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, 4, result) && - assign_and_return_true(subtype); - } - - case 0xD7: // fixext 8 - { - std::int8_t subtype{}; - return get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, 8, result) && - assign_and_return_true(subtype); - } - - case 0xD8: // fixext 16 - { - std::int8_t subtype{}; - return get_number(input_format_t::msgpack, subtype) && - get_binary(input_format_t::msgpack, 16, result) && - assign_and_return_true(subtype); - } - - default: // LCOV_EXCL_LINE - return false; // LCOV_EXCL_LINE - } - } - - /*! - @param[in] len the length of the array - @return whether array creation completed - */ - bool get_msgpack_array(const std::size_t len) - { - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len))) - { - return false; - } - - for (std::size_t i = 0; i < len; ++i) - { - if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal())) - { - return false; - } - } - - return sax->end_array(); - } - - /*! - @param[in] len the length of the object - @return whether object creation completed - */ - bool get_msgpack_object(const std::size_t len) - { - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len))) - { - return false; - } - - string_t key; - for (std::size_t i = 0; i < len; ++i) - { - get(); - if (JSON_HEDLEY_UNLIKELY(!get_msgpack_string(key) || !sax->key(key))) - { - return false; - } - - if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal())) - { - return false; - } - key.clear(); - } - - return sax->end_object(); - } - - //////////// - // UBJSON // - //////////// - - /*! - @param[in] get_char whether a new character should be retrieved from the - input (true, default) or whether the last read - character should be considered instead - - @return whether a valid UBJSON value was passed to the SAX parser - */ - bool parse_ubjson_internal(const bool get_char = true) - { - return get_ubjson_value(get_char ? get_ignore_noop() : current); - } - - /*! - @brief reads a UBJSON string - - This function is either called after reading the 'S' byte explicitly - indicating a string, or in case of an object key where the 'S' byte can be - left out. - - @param[out] result created string - @param[in] get_char whether a new character should be retrieved from the - input (true, default) or whether the last read - character should be considered instead - - @return whether string creation completed - */ - bool get_ubjson_string(string_t& result, const bool get_char = true) - { - if (get_char) - { - get(); // TODO(niels): may we ignore N here? - } - - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "value"))) - { - return false; - } - - switch (current) - { - case 'U': - { - std::uint8_t len{}; - return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); - } - - case 'i': - { - std::int8_t len{}; - return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); - } - - case 'I': - { - std::int16_t len{}; - return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); - } - - case 'l': - { - std::int32_t len{}; - return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); - } - - case 'L': - { - std::int64_t len{}; - return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); - } - - default: - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token, "string"), BasicJsonType())); - } - } - - /*! - @param[out] result determined size - @return whether size determination completed - */ - bool get_ubjson_size_value(std::size_t& result) - { - switch (get_ignore_noop()) - { - case 'U': - { - std::uint8_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) - { - return false; - } - result = static_cast(number); - return true; - } - - case 'i': - { - std::int8_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) - { - return false; - } - result = static_cast(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char - return true; - } - - case 'I': - { - std::int16_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) - { - return false; - } - result = static_cast(number); - return true; - } - - case 'l': - { - std::int32_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) - { - return false; - } - result = static_cast(number); - return true; - } - - case 'L': - { - std::int64_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) - { - return false; - } - result = static_cast(number); - return true; - } - - default: - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token, "size"), BasicJsonType())); - } - } - } - - /*! - @brief determine the type and size for a container - - In the optimized UBJSON format, a type and a size can be provided to allow - for a more compact representation. - - @param[out] result pair of the size and the type - - @return whether pair creation completed - */ - bool get_ubjson_size_type(std::pair& result) - { - result.first = string_t::npos; // size - result.second = 0; // type - - get_ignore_noop(); - - if (current == '$') - { - result.second = get(); // must not ignore 'N', because 'N' maybe the type - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "type"))) - { - return false; - } - - get_ignore_noop(); - if (JSON_HEDLEY_UNLIKELY(current != '#')) - { - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "value"))) - { - return false; - } - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "expected '#' after type information; last byte: 0x" + last_token, "size"), BasicJsonType())); - } - - return get_ubjson_size_value(result.first); - } - - if (current == '#') - { - return get_ubjson_size_value(result.first); - } - - return true; - } - - /*! - @param prefix the previously read or set type prefix - @return whether value creation completed - */ - bool get_ubjson_value(const char_int_type prefix) - { - switch (prefix) - { - case std::char_traits::eof(): // EOF - return unexpect_eof(input_format_t::ubjson, "value"); - - case 'T': // true - return sax->boolean(true); - case 'F': // false - return sax->boolean(false); - - case 'Z': // null - return sax->null(); - - case 'U': - { - std::uint8_t number{}; - return get_number(input_format_t::ubjson, number) && sax->number_unsigned(number); - } - - case 'i': - { - std::int8_t number{}; - return get_number(input_format_t::ubjson, number) && sax->number_integer(number); - } - - case 'I': - { - std::int16_t number{}; - return get_number(input_format_t::ubjson, number) && sax->number_integer(number); - } - - case 'l': - { - std::int32_t number{}; - return get_number(input_format_t::ubjson, number) && sax->number_integer(number); - } - - case 'L': - { - std::int64_t number{}; - return get_number(input_format_t::ubjson, number) && sax->number_integer(number); - } - - case 'd': - { - float number{}; - return get_number(input_format_t::ubjson, number) && sax->number_float(static_cast(number), ""); - } - - case 'D': - { - double number{}; - return get_number(input_format_t::ubjson, number) && sax->number_float(static_cast(number), ""); - } - - case 'H': - { - return get_ubjson_high_precision_number(); - } - - case 'C': // char - { - get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "char"))) - { - return false; - } - if (JSON_HEDLEY_UNLIKELY(current > 127)) - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + last_token, "char"), BasicJsonType())); - } - string_t s(1, static_cast(current)); - return sax->string(s); - } - - case 'S': // string - { - string_t s; - return get_ubjson_string(s) && sax->string(s); - } - - case '[': // array - return get_ubjson_array(); - - case '{': // object - return get_ubjson_object(); - - default: // anything else - { - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "invalid byte: 0x" + last_token, "value"), BasicJsonType())); - } - } - } - - /*! - @return whether array creation completed - */ - bool get_ubjson_array() - { - std::pair size_and_type; - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type))) - { - return false; - } - - if (size_and_type.first != string_t::npos) - { - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first))) - { - return false; - } - - if (size_and_type.second != 0) - { - if (size_and_type.second != 'N') - { - for (std::size_t i = 0; i < size_and_type.first; ++i) - { - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) - { - return false; - } - } - } - } - else - { - for (std::size_t i = 0; i < size_and_type.first; ++i) - { - if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) - { - return false; - } - } - } - } - else - { - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast(-1)))) - { - return false; - } - - while (current != ']') - { - if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal(false))) - { - return false; - } - get_ignore_noop(); - } - } - - return sax->end_array(); - } - - /*! - @return whether object creation completed - */ - bool get_ubjson_object() - { - std::pair size_and_type; - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type))) - { - return false; - } - - string_t key; - if (size_and_type.first != string_t::npos) - { - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(size_and_type.first))) - { - return false; - } - - if (size_and_type.second != 0) - { - for (std::size_t i = 0; i < size_and_type.first; ++i) - { - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key))) - { - return false; - } - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) - { - return false; - } - key.clear(); - } - } - else - { - for (std::size_t i = 0; i < size_and_type.first; ++i) - { - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key))) - { - return false; - } - if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) - { - return false; - } - key.clear(); - } - } - } - else - { - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast(-1)))) - { - return false; - } - - while (current != '}') - { - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key, false) || !sax->key(key))) - { - return false; - } - if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) - { - return false; - } - get_ignore_noop(); - key.clear(); - } - } - - return sax->end_object(); - } - - // Note, no reader for UBJSON binary types is implemented because they do - // not exist - - bool get_ubjson_high_precision_number() - { - // get size of following number string - std::size_t size{}; - auto res = get_ubjson_size_value(size); - if (JSON_HEDLEY_UNLIKELY(!res)) - { - return res; - } - - // get number string - std::vector number_vector; - for (std::size_t i = 0; i < size; ++i) - { - get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "number"))) - { - return false; - } - number_vector.push_back(static_cast(current)); - } - - // parse number string - using ia_type = decltype(detail::input_adapter(number_vector)); - auto number_lexer = detail::lexer(detail::input_adapter(number_vector), false); - const auto result_number = number_lexer.scan(); - const auto number_string = number_lexer.get_token_string(); - const auto result_remainder = number_lexer.scan(); - - using token_type = typename detail::lexer_base::token_type; - - if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input)) - { - return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, "invalid number text: " + number_lexer.get_token_string(), "high-precision number"), BasicJsonType())); - } - - switch (result_number) - { - case token_type::value_integer: - return sax->number_integer(number_lexer.get_number_integer()); - case token_type::value_unsigned: - return sax->number_unsigned(number_lexer.get_number_unsigned()); - case token_type::value_float: - return sax->number_float(number_lexer.get_number_float(), std::move(number_string)); - case token_type::uninitialized: - case token_type::literal_true: - case token_type::literal_false: - case token_type::literal_null: - case token_type::value_string: - case token_type::begin_array: - case token_type::begin_object: - case token_type::end_array: - case token_type::end_object: - case token_type::name_separator: - case token_type::value_separator: - case token_type::parse_error: - case token_type::end_of_input: - case token_type::literal_or_value: - default: - return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, "invalid number text: " + number_lexer.get_token_string(), "high-precision number"), BasicJsonType())); - } - } - - /////////////////////// - // Utility functions // - /////////////////////// - - /*! - @brief get next character from the input - - This function provides the interface to the used input adapter. It does - not throw in case the input reached EOF, but returns a -'ve valued - `std::char_traits::eof()` in that case. - - @return character read from the input - */ - char_int_type get() - { - ++chars_read; - return current = ia.get_character(); - } - - /*! - @return character read from the input after ignoring all 'N' entries - */ - char_int_type get_ignore_noop() - { - do - { - get(); - } - while (current == 'N'); - - return current; - } - - /* - @brief read a number from the input - - @tparam NumberType the type of the number - @param[in] format the current format (for diagnostics) - @param[out] result number of type @a NumberType - - @return whether conversion completed - - @note This function needs to respect the system's endianness, because - bytes in CBOR, MessagePack, and UBJSON are stored in network order - (big endian) and therefore need reordering on little endian systems. - */ - template - bool get_number(const input_format_t format, NumberType& result) - { - // step 1: read input into array with system's byte order - std::array vec{}; - for (std::size_t i = 0; i < sizeof(NumberType); ++i) - { - get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number"))) - { - return false; - } - - // reverse byte order prior to conversion if necessary - if (is_little_endian != InputIsLittleEndian) - { - vec[sizeof(NumberType) - i - 1] = static_cast(current); - } - else - { - vec[i] = static_cast(current); // LCOV_EXCL_LINE - } - } - - // step 2: convert array into number of type T and return - std::memcpy(&result, vec.data(), sizeof(NumberType)); - return true; - } - - /*! - @brief create a string by reading characters from the input - - @tparam NumberType the type of the number - @param[in] format the current format (for diagnostics) - @param[in] len number of characters to read - @param[out] result string created by reading @a len bytes - - @return whether string creation completed - - @note We can not reserve @a len bytes for the result, because @a len - may be too large. Usually, @ref unexpect_eof() detects the end of - the input before we run out of string memory. - */ - template - bool get_string(const input_format_t format, - const NumberType len, - string_t& result) - { - bool success = true; - for (NumberType i = 0; i < len; i++) - { - get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "string"))) - { - success = false; - break; - } - result.push_back(static_cast(current)); - } - return success; - } - - /*! - @brief create a byte array by reading bytes from the input - - @tparam NumberType the type of the number - @param[in] format the current format (for diagnostics) - @param[in] len number of bytes to read - @param[out] result byte array created by reading @a len bytes - - @return whether byte array creation completed - - @note We can not reserve @a len bytes for the result, because @a len - may be too large. Usually, @ref unexpect_eof() detects the end of - the input before we run out of memory. - */ - template - bool get_binary(const input_format_t format, - const NumberType len, - binary_t& result) - { - bool success = true; - for (NumberType i = 0; i < len; i++) - { - get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "binary"))) - { - success = false; - break; - } - result.push_back(static_cast(current)); - } - return success; - } - - /*! - @param[in] format the current format (for diagnostics) - @param[in] context further context information (for diagnostics) - @return whether the last read character is not EOF - */ - JSON_HEDLEY_NON_NULL(3) - bool unexpect_eof(const input_format_t format, const char* context) const - { - if (JSON_HEDLEY_UNLIKELY(current == std::char_traits::eof())) - { - return sax->parse_error(chars_read, "", - parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), BasicJsonType())); - } - return true; - } - - /*! - @return a string representation of the last read byte - */ - std::string get_token_string() const - { - std::array cr{{}}; - static_cast((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(current))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) - return std::string{cr.data()}; - } - - /*! - @param[in] format the current format - @param[in] detail a detailed error message - @param[in] context further context information - @return a message string to use in the parse_error exceptions - */ - std::string exception_message(const input_format_t format, - const std::string& detail, - const std::string& context) const - { - std::string error_msg = "syntax error while parsing "; - - switch (format) - { - case input_format_t::cbor: - error_msg += "CBOR"; - break; - - case input_format_t::msgpack: - error_msg += "MessagePack"; - break; - - case input_format_t::ubjson: - error_msg += "UBJSON"; - break; - - case input_format_t::bson: - error_msg += "BSON"; - break; - - case input_format_t::json: // LCOV_EXCL_LINE - default: // LCOV_EXCL_LINE - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE - } - - return error_msg + " " + context + ": " + detail; - } - - private: - /// input adapter - InputAdapterType ia; - - /// the current character - char_int_type current = std::char_traits::eof(); - - /// the number of characters read - std::size_t chars_read = 0; - - /// whether we can assume little endianness - const bool is_little_endian = little_endianness(); - - /// the SAX parser - json_sax_t* sax = nullptr; -}; -} // namespace detail -} // namespace nlohmann - -// #include - -// #include - -// #include - - -#include // isfinite -#include // uint8_t -#include // function -#include // string -#include // move -#include // vector - -// #include - -// #include - -// #include - -// #include - -// #include - -// #include - -// #include - - -namespace nlohmann -{ -namespace detail -{ -//////////// -// parser // -//////////// - -enum class parse_event_t : std::uint8_t -{ - /// the parser read `{` and started to process a JSON object - object_start, - /// the parser read `}` and finished processing a JSON object - object_end, - /// the parser read `[` and started to process a JSON array - array_start, - /// the parser read `]` and finished processing a JSON array - array_end, - /// the parser read a key of a value in an object - key, - /// the parser finished reading a JSON value - value -}; - -template -using parser_callback_t = - std::function; - -/*! -@brief syntax analysis - -This class implements a recursive descent parser. -*/ -template -class parser -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using lexer_t = lexer; - using token_type = typename lexer_t::token_type; - - public: - /// a parser reading from an input adapter - explicit parser(InputAdapterType&& adapter, - const parser_callback_t cb = nullptr, - const bool allow_exceptions_ = true, - const bool skip_comments = false) - : callback(cb) - , m_lexer(std::move(adapter), skip_comments) - , allow_exceptions(allow_exceptions_) - { - // read first token - get_token(); - } - - /*! - @brief public parser interface - - @param[in] strict whether to expect the last token to be EOF - @param[in,out] result parsed JSON value - - @throw parse_error.101 in case of an unexpected token - @throw parse_error.102 if to_unicode fails or surrogate error - @throw parse_error.103 if to_unicode fails - */ - void parse(const bool strict, BasicJsonType& result) - { - if (callback) - { - json_sax_dom_callback_parser sdp(result, callback, allow_exceptions); - sax_parse_internal(&sdp); - - // in strict mode, input must be completely read - if (strict && (get_token() != token_type::end_of_input)) - { - sdp.parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), - exception_message(token_type::end_of_input, "value"), BasicJsonType())); - } - - // in case of an error, return discarded value - if (sdp.is_errored()) - { - result = value_t::discarded; - return; - } - - // set top-level value to null if it was discarded by the callback - // function - if (result.is_discarded()) - { - result = nullptr; - } - } - else - { - json_sax_dom_parser sdp(result, allow_exceptions); - sax_parse_internal(&sdp); - - // in strict mode, input must be completely read - if (strict && (get_token() != token_type::end_of_input)) - { - sdp.parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), BasicJsonType())); - } - - // in case of an error, return discarded value - if (sdp.is_errored()) - { - result = value_t::discarded; - return; - } - } - - result.assert_invariant(); - } - - /*! - @brief public accept interface - - @param[in] strict whether to expect the last token to be EOF - @return whether the input is a proper JSON text - */ - bool accept(const bool strict = true) - { - json_sax_acceptor sax_acceptor; - return sax_parse(&sax_acceptor, strict); - } - - template - JSON_HEDLEY_NON_NULL(2) - bool sax_parse(SAX* sax, const bool strict = true) - { - (void)detail::is_sax_static_asserts {}; - const bool result = sax_parse_internal(sax); - - // strict mode: next byte must be EOF - if (result && strict && (get_token() != token_type::end_of_input)) - { - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), BasicJsonType())); - } - - return result; - } - - private: - template - JSON_HEDLEY_NON_NULL(2) - bool sax_parse_internal(SAX* sax) - { - // stack to remember the hierarchy of structured values we are parsing - // true = array; false = object - std::vector states; - // value to avoid a goto (see comment where set to true) - bool skip_to_state_evaluation = false; - - while (true) - { - if (!skip_to_state_evaluation) - { - // invariant: get_token() was called before each iteration - switch (last_token) - { - case token_type::begin_object: - { - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast(-1)))) - { - return false; - } - - // closing } -> we are done - if (get_token() == token_type::end_object) - { - if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) - { - return false; - } - break; - } - - // parse key - if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string)) - { - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), BasicJsonType())); - } - if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) - { - return false; - } - - // parse separator (:) - if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) - { - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), BasicJsonType())); - } - - // remember we are now inside an object - states.push_back(false); - - // parse values - get_token(); - continue; - } - - case token_type::begin_array: - { - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast(-1)))) - { - return false; - } - - // closing ] -> we are done - if (get_token() == token_type::end_array) - { - if (JSON_HEDLEY_UNLIKELY(!sax->end_array())) - { - return false; - } - break; - } - - // remember we are now inside an array - states.push_back(true); - - // parse values (no need to call get_token) - continue; - } - - case token_type::value_float: - { - const auto res = m_lexer.get_number_float(); - - if (JSON_HEDLEY_UNLIKELY(!std::isfinite(res))) - { - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'", BasicJsonType())); - } - - if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string()))) - { - return false; - } - - break; - } - - case token_type::literal_false: - { - if (JSON_HEDLEY_UNLIKELY(!sax->boolean(false))) - { - return false; - } - break; - } - - case token_type::literal_null: - { - if (JSON_HEDLEY_UNLIKELY(!sax->null())) - { - return false; - } - break; - } - - case token_type::literal_true: - { - if (JSON_HEDLEY_UNLIKELY(!sax->boolean(true))) - { - return false; - } - break; - } - - case token_type::value_integer: - { - if (JSON_HEDLEY_UNLIKELY(!sax->number_integer(m_lexer.get_number_integer()))) - { - return false; - } - break; - } - - case token_type::value_string: - { - if (JSON_HEDLEY_UNLIKELY(!sax->string(m_lexer.get_string()))) - { - return false; - } - break; - } - - case token_type::value_unsigned: - { - if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(m_lexer.get_number_unsigned()))) - { - return false; - } - break; - } - - case token_type::parse_error: - { - // using "uninitialized" to avoid "expected" message - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), BasicJsonType())); - } - - case token_type::uninitialized: - case token_type::end_array: - case token_type::end_object: - case token_type::name_separator: - case token_type::value_separator: - case token_type::end_of_input: - case token_type::literal_or_value: - default: // the last token was unexpected - { - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), BasicJsonType())); - } - } - } - else - { - skip_to_state_evaluation = false; - } - - // we reached this line after we successfully parsed a value - if (states.empty()) - { - // empty stack: we reached the end of the hierarchy: done - return true; - } - - if (states.back()) // array - { - // comma -> next value - if (get_token() == token_type::value_separator) - { - // parse a new value - get_token(); - continue; - } - - // closing ] - if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array)) - { - if (JSON_HEDLEY_UNLIKELY(!sax->end_array())) - { - return false; - } - - // We are done with this array. Before we can parse a - // new value, we need to evaluate the new state first. - // By setting skip_to_state_evaluation to false, we - // are effectively jumping to the beginning of this if. - JSON_ASSERT(!states.empty()); - states.pop_back(); - skip_to_state_evaluation = true; - continue; - } - - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array, "array"), BasicJsonType())); - } - - // states.back() is false -> object - - // comma -> next value - if (get_token() == token_type::value_separator) - { - // parse key - if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string)) - { - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), BasicJsonType())); - } - - if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) - { - return false; - } - - // parse separator (:) - if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) - { - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), BasicJsonType())); - } - - // parse values - get_token(); - continue; - } - - // closing } - if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object)) - { - if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) - { - return false; - } - - // We are done with this object. Before we can parse a - // new value, we need to evaluate the new state first. - // By setting skip_to_state_evaluation to false, we - // are effectively jumping to the beginning of this if. - JSON_ASSERT(!states.empty()); - states.pop_back(); - skip_to_state_evaluation = true; - continue; - } - - return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object, "object"), BasicJsonType())); - } - } - - /// get next token from lexer - token_type get_token() - { - return last_token = m_lexer.scan(); - } - - std::string exception_message(const token_type expected, const std::string& context) - { - std::string error_msg = "syntax error "; - - if (!context.empty()) - { - error_msg += "while parsing " + context + " "; - } - - error_msg += "- "; - - if (last_token == token_type::parse_error) - { - error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" + - m_lexer.get_token_string() + "'"; - } - else - { - error_msg += "unexpected " + std::string(lexer_t::token_type_name(last_token)); - } - - if (expected != token_type::uninitialized) - { - error_msg += "; expected " + std::string(lexer_t::token_type_name(expected)); - } - - return error_msg; - } - - private: - /// callback function - const parser_callback_t callback = nullptr; - /// the type of the last read token - token_type last_token = token_type::uninitialized; - /// the lexer - lexer_t m_lexer; - /// whether to throw exceptions in case of errors - const bool allow_exceptions = true; -}; - -} // namespace detail -} // namespace nlohmann - -// #include - - -// #include - - -#include // ptrdiff_t -#include // numeric_limits - -// #include - - -namespace nlohmann -{ -namespace detail -{ -/* -@brief an iterator for primitive JSON types - -This class models an iterator for primitive JSON types (boolean, number, -string). It's only purpose is to allow the iterator/const_iterator classes -to "iterate" over primitive values. Internally, the iterator is modeled by -a `difference_type` variable. Value begin_value (`0`) models the begin, -end_value (`1`) models past the end. -*/ -class primitive_iterator_t -{ - private: - using difference_type = std::ptrdiff_t; - static constexpr difference_type begin_value = 0; - static constexpr difference_type end_value = begin_value + 1; - - JSON_PRIVATE_UNLESS_TESTED: - /// iterator as signed integer type - difference_type m_it = (std::numeric_limits::min)(); - - public: - constexpr difference_type get_value() const noexcept - { - return m_it; - } - - /// set iterator to a defined beginning - void set_begin() noexcept - { - m_it = begin_value; - } - - /// set iterator to a defined past the end - void set_end() noexcept - { - m_it = end_value; - } - - /// return whether the iterator can be dereferenced - constexpr bool is_begin() const noexcept - { - return m_it == begin_value; - } - - /// return whether the iterator is at end - constexpr bool is_end() const noexcept - { - return m_it == end_value; - } - - friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it == rhs.m_it; - } - - friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it < rhs.m_it; - } - - primitive_iterator_t operator+(difference_type n) noexcept - { - auto result = *this; - result += n; - return result; - } - - friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it - rhs.m_it; - } - - primitive_iterator_t& operator++() noexcept - { - ++m_it; - return *this; - } - - primitive_iterator_t const operator++(int) noexcept // NOLINT(readability-const-return-type) - { - auto result = *this; - ++m_it; - return result; - } - - primitive_iterator_t& operator--() noexcept - { - --m_it; - return *this; - } - - primitive_iterator_t const operator--(int) noexcept // NOLINT(readability-const-return-type) - { - auto result = *this; - --m_it; - return result; - } - - primitive_iterator_t& operator+=(difference_type n) noexcept - { - m_it += n; - return *this; - } - - primitive_iterator_t& operator-=(difference_type n) noexcept - { - m_it -= n; - return *this; - } -}; -} // namespace detail -} // namespace nlohmann - - -namespace nlohmann -{ -namespace detail -{ -/*! -@brief an iterator value - -@note This structure could easily be a union, but MSVC currently does not allow -unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. -*/ -template struct internal_iterator -{ - /// iterator for JSON objects - typename BasicJsonType::object_t::iterator object_iterator {}; - /// iterator for JSON arrays - typename BasicJsonType::array_t::iterator array_iterator {}; - /// generic iterator for all other types - primitive_iterator_t primitive_iterator {}; -}; -} // namespace detail -} // namespace nlohmann - -// #include - - -#include // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next -#include // conditional, is_const, remove_const - -// #include - -// #include - -// #include - -// #include - -// #include - -// #include - -// #include - - -namespace nlohmann -{ -namespace detail -{ -// forward declare, to be able to friend it later on -template class iteration_proxy; -template class iteration_proxy_value; - -/*! -@brief a template for a bidirectional iterator for the @ref basic_json class -This class implements a both iterators (iterator and const_iterator) for the -@ref basic_json class. -@note An iterator is called *initialized* when a pointer to a JSON value has - been set (e.g., by a constructor or a copy assignment). If the iterator is - default-constructed, it is *uninitialized* and most methods are undefined. - **The library uses assertions to detect calls on uninitialized iterators.** -@requirement The class satisfies the following concept requirements: -- -[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator): - The iterator that can be moved can be moved in both directions (i.e. - incremented and decremented). -@since version 1.0.0, simplified in version 2.0.9, change to bidirectional - iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593) -*/ -template -class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) -{ - /// the iterator with BasicJsonType of different const-ness - using other_iter_impl = iter_impl::value, typename std::remove_const::type, const BasicJsonType>::type>; - /// allow basic_json to access private members - friend other_iter_impl; - friend BasicJsonType; - friend iteration_proxy; - friend iteration_proxy_value; - - using object_t = typename BasicJsonType::object_t; - using array_t = typename BasicJsonType::array_t; - // make sure BasicJsonType is basic_json or const basic_json - static_assert(is_basic_json::type>::value, - "iter_impl only accepts (const) basic_json"); - - public: - - /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17. - /// The C++ Standard has never required user-defined iterators to derive from std::iterator. - /// A user-defined iterator should provide publicly accessible typedefs named - /// iterator_category, value_type, difference_type, pointer, and reference. - /// Note that value_type is required to be non-const, even for constant iterators. - using iterator_category = std::bidirectional_iterator_tag; - - /// the type of the values when the iterator is dereferenced - using value_type = typename BasicJsonType::value_type; - /// a type to represent differences between iterators - using difference_type = typename BasicJsonType::difference_type; - /// defines a pointer to the type iterated over (value_type) - using pointer = typename std::conditional::value, - typename BasicJsonType::const_pointer, - typename BasicJsonType::pointer>::type; - /// defines a reference to the type iterated over (value_type) - using reference = - typename std::conditional::value, - typename BasicJsonType::const_reference, - typename BasicJsonType::reference>::type; - - iter_impl() = default; - ~iter_impl() = default; - iter_impl(iter_impl&&) noexcept = default; - iter_impl& operator=(iter_impl&&) noexcept = default; - - /*! - @brief constructor for a given JSON instance - @param[in] object pointer to a JSON object for this iterator - @pre object != nullptr - @post The iterator is initialized; i.e. `m_object != nullptr`. - */ - explicit iter_impl(pointer object) noexcept : m_object(object) - { - JSON_ASSERT(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - m_it.object_iterator = typename object_t::iterator(); - break; - } - - case value_t::array: - { - m_it.array_iterator = typename array_t::iterator(); - break; - } - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - m_it.primitive_iterator = primitive_iterator_t(); - break; - } - } - } - - /*! - @note The conventional copy constructor and copy assignment are implicitly - defined. Combined with the following converting constructor and - assignment, they support: (1) copy from iterator to iterator, (2) - copy from const iterator to const iterator, and (3) conversion from - iterator to const iterator. However conversion from const iterator - to iterator is not defined. - */ - - /*! - @brief const copy constructor - @param[in] other const iterator to copy from - @note This copy constructor had to be defined explicitly to circumvent a bug - occurring on msvc v19.0 compiler (VS 2015) debug build. For more - information refer to: https://github.com/nlohmann/json/issues/1608 - */ - iter_impl(const iter_impl& other) noexcept - : m_object(other.m_object), m_it(other.m_it) - {} - - /*! - @brief converting assignment - @param[in] other const iterator to copy from - @return const/non-const iterator - @note It is not checked whether @a other is initialized. - */ - iter_impl& operator=(const iter_impl& other) noexcept - { - if (&other != this) - { - m_object = other.m_object; - m_it = other.m_it; - } - return *this; - } - - /*! - @brief converting constructor - @param[in] other non-const iterator to copy from - @note It is not checked whether @a other is initialized. - */ - iter_impl(const iter_impl::type>& other) noexcept - : m_object(other.m_object), m_it(other.m_it) - {} - - /*! - @brief converting assignment - @param[in] other non-const iterator to copy from - @return const/non-const iterator - @note It is not checked whether @a other is initialized. - */ - iter_impl& operator=(const iter_impl::type>& other) noexcept // NOLINT(cert-oop54-cpp) - { - m_object = other.m_object; - m_it = other.m_it; - return *this; - } - - JSON_PRIVATE_UNLESS_TESTED: - /*! - @brief set the iterator to the first value - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - void set_begin() noexcept - { - JSON_ASSERT(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - m_it.object_iterator = m_object->m_value.object->begin(); - break; - } - - case value_t::array: - { - m_it.array_iterator = m_object->m_value.array->begin(); - break; - } - - case value_t::null: - { - // set to end so begin()==end() is true: null is empty - m_it.primitive_iterator.set_end(); - break; - } - - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - m_it.primitive_iterator.set_begin(); - break; - } - } - } - - /*! - @brief set the iterator past the last value - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - void set_end() noexcept - { - JSON_ASSERT(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - m_it.object_iterator = m_object->m_value.object->end(); - break; - } - - case value_t::array: - { - m_it.array_iterator = m_object->m_value.array->end(); - break; - } - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - m_it.primitive_iterator.set_end(); - break; - } - } - } - - public: - /*! - @brief return a reference to the value pointed to by the iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - reference operator*() const - { - JSON_ASSERT(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end()); - return m_it.object_iterator->second; - } - - case value_t::array: - { - JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end()); - return *m_it.array_iterator; - } - - case value_t::null: - JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object)); - - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) - { - return *m_object; - } - - JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object)); - } - } - } - - /*! - @brief dereference the iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - pointer operator->() const - { - JSON_ASSERT(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end()); - return &(m_it.object_iterator->second); - } - - case value_t::array: - { - JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end()); - return &*m_it.array_iterator; - } - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) - { - return m_object; - } - - JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object)); - } - } - } - - /*! - @brief post-increment (it++) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl const operator++(int) // NOLINT(readability-const-return-type) - { - auto result = *this; - ++(*this); - return result; - } - - /*! - @brief pre-increment (++it) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator++() - { - JSON_ASSERT(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - std::advance(m_it.object_iterator, 1); - break; - } - - case value_t::array: - { - std::advance(m_it.array_iterator, 1); - break; - } - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - ++m_it.primitive_iterator; - break; - } - } - - return *this; - } - - /*! - @brief post-decrement (it--) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl const operator--(int) // NOLINT(readability-const-return-type) - { - auto result = *this; - --(*this); - return result; - } - - /*! - @brief pre-decrement (--it) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator--() - { - JSON_ASSERT(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - { - std::advance(m_it.object_iterator, -1); - break; - } - - case value_t::array: - { - std::advance(m_it.array_iterator, -1); - break; - } - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - --m_it.primitive_iterator; - break; - } - } - - return *this; - } - - /*! - @brief comparison: equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - template < typename IterImpl, detail::enable_if_t < (std::is_same::value || std::is_same::value), std::nullptr_t > = nullptr > - bool operator==(const IterImpl& other) const - { - // if objects are not the same, the comparison is undefined - if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) - { - JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", *m_object)); - } - - JSON_ASSERT(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - return (m_it.object_iterator == other.m_it.object_iterator); - - case value_t::array: - return (m_it.array_iterator == other.m_it.array_iterator); - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - return (m_it.primitive_iterator == other.m_it.primitive_iterator); - } - } - - /*! - @brief comparison: not equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - template < typename IterImpl, detail::enable_if_t < (std::is_same::value || std::is_same::value), std::nullptr_t > = nullptr > - bool operator!=(const IterImpl& other) const - { - return !operator==(other); - } - - /*! - @brief comparison: smaller - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator<(const iter_impl& other) const - { - // if objects are not the same, the comparison is undefined - if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) - { - JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", *m_object)); - } - - JSON_ASSERT(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators", *m_object)); - - case value_t::array: - return (m_it.array_iterator < other.m_it.array_iterator); - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - return (m_it.primitive_iterator < other.m_it.primitive_iterator); - } - } - - /*! - @brief comparison: less than or equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator<=(const iter_impl& other) const - { - return !other.operator < (*this); - } - - /*! - @brief comparison: greater than - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator>(const iter_impl& other) const - { - return !operator<=(other); - } - - /*! - @brief comparison: greater than or equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator>=(const iter_impl& other) const - { - return !operator<(other); - } - - /*! - @brief add to iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator+=(difference_type i) - { - JSON_ASSERT(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", *m_object)); - - case value_t::array: - { - std::advance(m_it.array_iterator, i); - break; - } - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - m_it.primitive_iterator += i; - break; - } - } - - return *this; - } - - /*! - @brief subtract from iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator-=(difference_type i) - { - return operator+=(-i); - } - - /*! - @brief add to iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl operator+(difference_type i) const - { - auto result = *this; - result += i; - return result; - } - - /*! - @brief addition of distance and iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - friend iter_impl operator+(difference_type i, const iter_impl& it) - { - auto result = it; - result += i; - return result; - } - - /*! - @brief subtract from iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl operator-(difference_type i) const - { - auto result = *this; - result -= i; - return result; - } - - /*! - @brief return difference - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - difference_type operator-(const iter_impl& other) const - { - JSON_ASSERT(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", *m_object)); - - case value_t::array: - return m_it.array_iterator - other.m_it.array_iterator; - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - return m_it.primitive_iterator - other.m_it.primitive_iterator; - } - } - - /*! - @brief access to successor - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - reference operator[](difference_type n) const - { - JSON_ASSERT(m_object != nullptr); - - switch (m_object->m_type) - { - case value_t::object: - JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators", *m_object)); - - case value_t::array: - return *std::next(m_it.array_iterator, n); - - case value_t::null: - JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object)); - - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.get_value() == -n)) - { - return *m_object; - } - - JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object)); - } - } - } - - /*! - @brief return the key of an object iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - const typename object_t::key_type& key() const - { - JSON_ASSERT(m_object != nullptr); - - if (JSON_HEDLEY_LIKELY(m_object->is_object())) - { - return m_it.object_iterator->first; - } - - JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators", *m_object)); - } - - /*! - @brief return the value of an iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - reference value() const - { - return operator*(); - } - - JSON_PRIVATE_UNLESS_TESTED: - /// associated JSON instance - pointer m_object = nullptr; - /// the actual iterator of the associated instance - internal_iterator::type> m_it {}; -}; -} // namespace detail -} // namespace nlohmann - -// #include - -// #include - - -#include // ptrdiff_t -#include // reverse_iterator -#include // declval - -namespace nlohmann -{ -namespace detail -{ -////////////////////// -// reverse_iterator // -////////////////////// - -/*! -@brief a template for a reverse iterator class - -@tparam Base the base iterator type to reverse. Valid types are @ref -iterator (to create @ref reverse_iterator) and @ref const_iterator (to -create @ref const_reverse_iterator). - -@requirement The class satisfies the following concept requirements: -- -[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator): - The iterator that can be moved can be moved in both directions (i.e. - incremented and decremented). -- [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator): - It is possible to write to the pointed-to element (only if @a Base is - @ref iterator). - -@since version 1.0.0 -*/ -template -class json_reverse_iterator : public std::reverse_iterator -{ - public: - using difference_type = std::ptrdiff_t; - /// shortcut to the reverse iterator adapter - using base_iterator = std::reverse_iterator; - /// the reference type for the pointed-to element - using reference = typename Base::reference; - - /// create reverse iterator from iterator - explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept - : base_iterator(it) {} - - /// create reverse iterator from base class - explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} - - /// post-increment (it++) - json_reverse_iterator const operator++(int) // NOLINT(readability-const-return-type) - { - return static_cast(base_iterator::operator++(1)); - } - - /// pre-increment (++it) - json_reverse_iterator& operator++() - { - return static_cast(base_iterator::operator++()); - } - - /// post-decrement (it--) - json_reverse_iterator const operator--(int) // NOLINT(readability-const-return-type) - { - return static_cast(base_iterator::operator--(1)); - } - - /// pre-decrement (--it) - json_reverse_iterator& operator--() - { - return static_cast(base_iterator::operator--()); - } - - /// add to iterator - json_reverse_iterator& operator+=(difference_type i) - { - return static_cast(base_iterator::operator+=(i)); - } - - /// add to iterator - json_reverse_iterator operator+(difference_type i) const - { - return static_cast(base_iterator::operator+(i)); - } - - /// subtract from iterator - json_reverse_iterator operator-(difference_type i) const - { - return static_cast(base_iterator::operator-(i)); - } - - /// return difference - difference_type operator-(const json_reverse_iterator& other) const - { - return base_iterator(*this) - base_iterator(other); - } - - /// access to successor - reference operator[](difference_type n) const - { - return *(this->operator+(n)); - } - - /// return the key of an object iterator - auto key() const -> decltype(std::declval().key()) - { - auto it = --this->base(); - return it.key(); - } - - /// return the value of an iterator - reference value() const - { - auto it = --this->base(); - return it.operator * (); - } -}; -} // namespace detail -} // namespace nlohmann - -// #include - -// #include - - -#include // all_of -#include // isdigit -#include // max -#include // accumulate -#include // string -#include // move -#include // vector - -// #include - -// #include - -// #include - -// #include - - -namespace nlohmann -{ - -/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document -/// @sa https://json.nlohmann.me/api/json_pointer/ -template -class json_pointer -{ - // allow basic_json to access private members - NLOHMANN_BASIC_JSON_TPL_DECLARATION - friend class basic_json; - - public: - /// @brief create JSON pointer - /// @sa https://json.nlohmann.me/api/json_pointer/json_pointer/ - explicit json_pointer(const std::string& s = "") - : reference_tokens(split(s)) - {} - - /// @brief return a string representation of the JSON pointer - /// @sa https://json.nlohmann.me/api/json_pointer/to_string/ - std::string to_string() const - { - return std::accumulate(reference_tokens.begin(), reference_tokens.end(), - std::string{}, - [](const std::string & a, const std::string & b) - { - return a + "/" + detail::escape(b); - }); - } - - /// @brief return a string representation of the JSON pointer - /// @sa https://json.nlohmann.me/api/json_pointer/operator_string/ - operator std::string() const - { - return to_string(); - } - - /// @brief append another JSON pointer at the end of this JSON pointer - /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ - json_pointer& operator/=(const json_pointer& ptr) - { - reference_tokens.insert(reference_tokens.end(), - ptr.reference_tokens.begin(), - ptr.reference_tokens.end()); - return *this; - } - - /// @brief append an unescaped reference token at the end of this JSON pointer - /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ - json_pointer& operator/=(std::string token) - { - push_back(std::move(token)); - return *this; - } - - /// @brief append an array index at the end of this JSON pointer - /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/ - json_pointer& operator/=(std::size_t array_idx) - { - return *this /= std::to_string(array_idx); - } - - /// @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer - /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ - friend json_pointer operator/(const json_pointer& lhs, - const json_pointer& rhs) - { - return json_pointer(lhs) /= rhs; - } - - /// @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer - /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ - friend json_pointer operator/(const json_pointer& lhs, std::string token) // NOLINT(performance-unnecessary-value-param) - { - return json_pointer(lhs) /= std::move(token); - } - - /// @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer - /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ - friend json_pointer operator/(const json_pointer& lhs, std::size_t array_idx) - { - return json_pointer(lhs) /= array_idx; - } - - /// @brief returns the parent of this JSON pointer - /// @sa https://json.nlohmann.me/api/json_pointer/parent_pointer/ - json_pointer parent_pointer() const - { - if (empty()) - { - return *this; - } - - json_pointer res = *this; - res.pop_back(); - return res; - } - - /// @brief remove last reference token - /// @sa https://json.nlohmann.me/api/json_pointer/pop_back/ - void pop_back() - { - if (JSON_HEDLEY_UNLIKELY(empty())) - { - JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", BasicJsonType())); - } - - reference_tokens.pop_back(); - } - - /// @brief return last reference token - /// @sa https://json.nlohmann.me/api/json_pointer/back/ - const std::string& back() const - { - if (JSON_HEDLEY_UNLIKELY(empty())) - { - JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", BasicJsonType())); - } - - return reference_tokens.back(); - } - - /// @brief append an unescaped token at the end of the reference pointer - /// @sa https://json.nlohmann.me/api/json_pointer/push_back/ - void push_back(const std::string& token) - { - reference_tokens.push_back(token); - } - - /// @brief append an unescaped token at the end of the reference pointer - /// @sa https://json.nlohmann.me/api/json_pointer/push_back/ - void push_back(std::string&& token) - { - reference_tokens.push_back(std::move(token)); - } - - /// @brief return whether pointer points to the root document - /// @sa https://json.nlohmann.me/api/json_pointer/empty/ - bool empty() const noexcept - { - return reference_tokens.empty(); - } - - private: - /*! - @param[in] s reference token to be converted into an array index - - @return integer representation of @a s - - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index begins not with a digit - @throw out_of_range.404 if string @a s could not be converted to an integer - @throw out_of_range.410 if an array index exceeds size_type - */ - static typename BasicJsonType::size_type array_index(const std::string& s) - { - using size_type = typename BasicJsonType::size_type; - - // error condition (cf. RFC 6901, Sect. 4) - if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0')) - { - JSON_THROW(detail::parse_error::create(106, 0, "array index '" + s + "' must not begin with '0'", BasicJsonType())); - } - - // error condition (cf. RFC 6901, Sect. 4) - if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9'))) - { - JSON_THROW(detail::parse_error::create(109, 0, "array index '" + s + "' is not a number", BasicJsonType())); - } - - std::size_t processed_chars = 0; - unsigned long long res = 0; // NOLINT(runtime/int) - JSON_TRY - { - res = std::stoull(s, &processed_chars); - } - JSON_CATCH(std::out_of_range&) - { - JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'", BasicJsonType())); - } - - // check if the string was completely read - if (JSON_HEDLEY_UNLIKELY(processed_chars != s.size())) - { - JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'", BasicJsonType())); - } - - // only triggered on special platforms (like 32bit), see also - // https://github.com/nlohmann/json/pull/2203 - if (res >= static_cast((std::numeric_limits::max)())) // NOLINT(runtime/int) - { - JSON_THROW(detail::out_of_range::create(410, "array index " + s + " exceeds size_type", BasicJsonType())); // LCOV_EXCL_LINE - } - - return static_cast(res); - } - - JSON_PRIVATE_UNLESS_TESTED: - json_pointer top() const - { - if (JSON_HEDLEY_UNLIKELY(empty())) - { - JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", BasicJsonType())); - } - - json_pointer result = *this; - result.reference_tokens = {reference_tokens[0]}; - return result; - } - - private: - /*! - @brief create and return a reference to the pointed to value - - @complexity Linear in the number of reference tokens. - - @throw parse_error.109 if array index is not a number - @throw type_error.313 if value cannot be unflattened - */ - BasicJsonType& get_and_create(BasicJsonType& j) const - { - auto* result = &j; - - // in case no reference tokens exist, return a reference to the JSON value - // j which will be overwritten by a primitive value - for (const auto& reference_token : reference_tokens) - { - switch (result->type()) - { - case detail::value_t::null: - { - if (reference_token == "0") - { - // start a new array if reference token is 0 - result = &result->operator[](0); - } - else - { - // start a new object otherwise - result = &result->operator[](reference_token); - } - break; - } - - case detail::value_t::object: - { - // create an entry in the object - result = &result->operator[](reference_token); - break; - } - - case detail::value_t::array: - { - // create an entry in the array - result = &result->operator[](array_index(reference_token)); - break; - } - - /* - The following code is only reached if there exists a reference - token _and_ the current value is primitive. In this case, we have - an error situation, because primitive values may only occur as - single value; that is, with an empty list of reference tokens. - */ - case detail::value_t::string: - case detail::value_t::boolean: - case detail::value_t::number_integer: - case detail::value_t::number_unsigned: - case detail::value_t::number_float: - case detail::value_t::binary: - case detail::value_t::discarded: - default: - JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", j)); - } - } - - return *result; - } - - /*! - @brief return a reference to the pointed to value - - @note This version does not throw if a value is not present, but tries to - create nested values instead. For instance, calling this function - with pointer `"/this/that"` on a null value is equivalent to calling - `operator[]("this").operator[]("that")` on that value, effectively - changing the null value to an object. - - @param[in] ptr a JSON value - - @return reference to the JSON value pointed to by the JSON pointer - - @complexity Linear in the length of the JSON pointer. - - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.404 if the JSON pointer can not be resolved - */ - BasicJsonType& get_unchecked(BasicJsonType* ptr) const - { - for (const auto& reference_token : reference_tokens) - { - // convert null values to arrays or objects before continuing - if (ptr->is_null()) - { - // check if reference token is a number - const bool nums = - std::all_of(reference_token.begin(), reference_token.end(), - [](const unsigned char x) - { - return std::isdigit(x); - }); - - // change value to array for numbers or "-" or to object otherwise - *ptr = (nums || reference_token == "-") - ? detail::value_t::array - : detail::value_t::object; - } - - switch (ptr->type()) - { - case detail::value_t::object: - { - // use unchecked object access - ptr = &ptr->operator[](reference_token); - break; - } - - case detail::value_t::array: - { - if (reference_token == "-") - { - // explicitly treat "-" as index beyond the end - ptr = &ptr->operator[](ptr->m_value.array->size()); - } - else - { - // convert array index to number; unchecked access - ptr = &ptr->operator[](array_index(reference_token)); - } - break; - } - - case detail::value_t::null: - case detail::value_t::string: - case detail::value_t::boolean: - case detail::value_t::number_integer: - case detail::value_t::number_unsigned: - case detail::value_t::number_float: - case detail::value_t::binary: - case detail::value_t::discarded: - default: - JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'", *ptr)); - } - } - - return *ptr; - } - - /*! - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.402 if the array index '-' is used - @throw out_of_range.404 if the JSON pointer can not be resolved - */ - BasicJsonType& get_checked(BasicJsonType* ptr) const - { - for (const auto& reference_token : reference_tokens) - { - switch (ptr->type()) - { - case detail::value_t::object: - { - // note: at performs range check - ptr = &ptr->at(reference_token); - break; - } - - case detail::value_t::array: - { - if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) - { - // "-" always fails the range check - JSON_THROW(detail::out_of_range::create(402, - "array index '-' (" + std::to_string(ptr->m_value.array->size()) + - ") is out of range", *ptr)); - } - - // note: at performs range check - ptr = &ptr->at(array_index(reference_token)); - break; - } - - case detail::value_t::null: - case detail::value_t::string: - case detail::value_t::boolean: - case detail::value_t::number_integer: - case detail::value_t::number_unsigned: - case detail::value_t::number_float: - case detail::value_t::binary: - case detail::value_t::discarded: - default: - JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'", *ptr)); - } - } - - return *ptr; - } - - /*! - @brief return a const reference to the pointed to value - - @param[in] ptr a JSON value - - @return const reference to the JSON value pointed to by the JSON - pointer - - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.402 if the array index '-' is used - @throw out_of_range.404 if the JSON pointer can not be resolved - */ - const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const - { - for (const auto& reference_token : reference_tokens) - { - switch (ptr->type()) - { - case detail::value_t::object: - { - // use unchecked object access - ptr = &ptr->operator[](reference_token); - break; - } - - case detail::value_t::array: - { - if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) - { - // "-" cannot be used for const access - JSON_THROW(detail::out_of_range::create(402, "array index '-' (" + std::to_string(ptr->m_value.array->size()) + ") is out of range", *ptr)); - } - - // use unchecked array access - ptr = &ptr->operator[](array_index(reference_token)); - break; - } - - case detail::value_t::null: - case detail::value_t::string: - case detail::value_t::boolean: - case detail::value_t::number_integer: - case detail::value_t::number_unsigned: - case detail::value_t::number_float: - case detail::value_t::binary: - case detail::value_t::discarded: - default: - JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'", *ptr)); - } - } - - return *ptr; - } - - /*! - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.402 if the array index '-' is used - @throw out_of_range.404 if the JSON pointer can not be resolved - */ - const BasicJsonType& get_checked(const BasicJsonType* ptr) const - { - for (const auto& reference_token : reference_tokens) - { - switch (ptr->type()) - { - case detail::value_t::object: - { - // note: at performs range check - ptr = &ptr->at(reference_token); - break; - } - - case detail::value_t::array: - { - if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) - { - // "-" always fails the range check - JSON_THROW(detail::out_of_range::create(402, - "array index '-' (" + std::to_string(ptr->m_value.array->size()) + - ") is out of range", *ptr)); - } - - // note: at performs range check - ptr = &ptr->at(array_index(reference_token)); - break; - } - - case detail::value_t::null: - case detail::value_t::string: - case detail::value_t::boolean: - case detail::value_t::number_integer: - case detail::value_t::number_unsigned: - case detail::value_t::number_float: - case detail::value_t::binary: - case detail::value_t::discarded: - default: - JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'", *ptr)); - } - } - - return *ptr; - } - - /*! - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - */ - bool contains(const BasicJsonType* ptr) const - { - for (const auto& reference_token : reference_tokens) - { - switch (ptr->type()) - { - case detail::value_t::object: - { - if (!ptr->contains(reference_token)) - { - // we did not find the key in the object - return false; - } - - ptr = &ptr->operator[](reference_token); - break; - } - - case detail::value_t::array: - { - if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) - { - // "-" always fails the range check - return false; - } - if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9"))) - { - // invalid char - return false; - } - if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1)) - { - if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9'))) - { - // first char should be between '1' and '9' - return false; - } - for (std::size_t i = 1; i < reference_token.size(); i++) - { - if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9'))) - { - // other char should be between '0' and '9' - return false; - } - } - } - - const auto idx = array_index(reference_token); - if (idx >= ptr->size()) - { - // index out of range - return false; - } - - ptr = &ptr->operator[](idx); - break; - } - - case detail::value_t::null: - case detail::value_t::string: - case detail::value_t::boolean: - case detail::value_t::number_integer: - case detail::value_t::number_unsigned: - case detail::value_t::number_float: - case detail::value_t::binary: - case detail::value_t::discarded: - default: - { - // we do not expect primitive values if there is still a - // reference token to process - return false; - } - } - } - - // no reference token left means we found a primitive value - return true; - } - - /*! - @brief split the string input to reference tokens - - @note This function is only called by the json_pointer constructor. - All exceptions below are documented there. - - @throw parse_error.107 if the pointer is not empty or begins with '/' - @throw parse_error.108 if character '~' is not followed by '0' or '1' - */ - static std::vector split(const std::string& reference_string) - { - std::vector result; - - // special case: empty reference string -> no reference tokens - if (reference_string.empty()) - { - return result; - } - - // check if nonempty reference string begins with slash - if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/')) - { - JSON_THROW(detail::parse_error::create(107, 1, "JSON pointer must be empty or begin with '/' - was: '" + reference_string + "'", BasicJsonType())); - } - - // extract the reference tokens: - // - slash: position of the last read slash (or end of string) - // - start: position after the previous slash - for ( - // search for the first slash after the first character - std::size_t slash = reference_string.find_first_of('/', 1), - // set the beginning of the first reference token - start = 1; - // we can stop if start == 0 (if slash == std::string::npos) - start != 0; - // set the beginning of the next reference token - // (will eventually be 0 if slash == std::string::npos) - start = (slash == std::string::npos) ? 0 : slash + 1, - // find next slash - slash = reference_string.find_first_of('/', start)) - { - // use the text between the beginning of the reference token - // (start) and the last slash (slash). - auto reference_token = reference_string.substr(start, slash - start); - - // check reference tokens are properly escaped - for (std::size_t pos = reference_token.find_first_of('~'); - pos != std::string::npos; - pos = reference_token.find_first_of('~', pos + 1)) - { - JSON_ASSERT(reference_token[pos] == '~'); - - // ~ must be followed by 0 or 1 - if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 || - (reference_token[pos + 1] != '0' && - reference_token[pos + 1] != '1'))) - { - JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'", BasicJsonType())); - } - } - - // finally, store the reference token - detail::unescape(reference_token); - result.push_back(reference_token); - } - - return result; - } - - private: - /*! - @param[in] reference_string the reference string to the current value - @param[in] value the value to consider - @param[in,out] result the result object to insert values to - - @note Empty objects or arrays are flattened to `null`. - */ - static void flatten(const std::string& reference_string, - const BasicJsonType& value, - BasicJsonType& result) - { - switch (value.type()) - { - case detail::value_t::array: - { - if (value.m_value.array->empty()) - { - // flatten empty array as null - result[reference_string] = nullptr; - } - else - { - // iterate array and use index as reference string - for (std::size_t i = 0; i < value.m_value.array->size(); ++i) - { - flatten(reference_string + "/" + std::to_string(i), - value.m_value.array->operator[](i), result); - } - } - break; - } - - case detail::value_t::object: - { - if (value.m_value.object->empty()) - { - // flatten empty object as null - result[reference_string] = nullptr; - } - else - { - // iterate object and use keys as reference string - for (const auto& element : *value.m_value.object) - { - flatten(reference_string + "/" + detail::escape(element.first), element.second, result); - } - } - break; - } - - case detail::value_t::null: - case detail::value_t::string: - case detail::value_t::boolean: - case detail::value_t::number_integer: - case detail::value_t::number_unsigned: - case detail::value_t::number_float: - case detail::value_t::binary: - case detail::value_t::discarded: - default: - { - // add primitive value with its reference string - result[reference_string] = value; - break; - } - } - } - - /*! - @param[in] value flattened JSON - - @return unflattened JSON - - @throw parse_error.109 if array index is not a number - @throw type_error.314 if value is not an object - @throw type_error.315 if object values are not primitive - @throw type_error.313 if value cannot be unflattened - */ - static BasicJsonType - unflatten(const BasicJsonType& value) - { - if (JSON_HEDLEY_UNLIKELY(!value.is_object())) - { - JSON_THROW(detail::type_error::create(314, "only objects can be unflattened", value)); - } - - BasicJsonType result; - - // iterate the JSON object values - for (const auto& element : *value.m_value.object) - { - if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive())) - { - JSON_THROW(detail::type_error::create(315, "values in object must be primitive", element.second)); - } - - // assign value to reference pointed to by JSON pointer; Note that if - // the JSON pointer is "" (i.e., points to the whole value), function - // get_and_create returns a reference to result itself. An assignment - // will then create a primitive value. - json_pointer(element.first).get_and_create(result) = element.second; - } - - return result; - } - - /*! - @brief compares two JSON pointers for equality - - @param[in] lhs JSON pointer to compare - @param[in] rhs JSON pointer to compare - @return whether @a lhs is equal to @a rhs - - @complexity Linear in the length of the JSON pointer - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - */ - friend bool operator==(json_pointer const& lhs, - json_pointer const& rhs) noexcept - { - return lhs.reference_tokens == rhs.reference_tokens; - } - - /*! - @brief compares two JSON pointers for inequality - - @param[in] lhs JSON pointer to compare - @param[in] rhs JSON pointer to compare - @return whether @a lhs is not equal @a rhs - - @complexity Linear in the length of the JSON pointer - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - */ - friend bool operator!=(json_pointer const& lhs, - json_pointer const& rhs) noexcept - { - return !(lhs == rhs); - } - - /// the reference tokens - std::vector reference_tokens; -}; -} // namespace nlohmann - -// #include - - -#include -#include - -// #include - - -namespace nlohmann -{ -namespace detail -{ -template -class json_ref -{ - public: - using value_type = BasicJsonType; - - json_ref(value_type&& value) - : owned_value(std::move(value)) - {} - - json_ref(const value_type& value) - : value_ref(&value) - {} - - json_ref(std::initializer_list init) - : owned_value(init) - {} - - template < - class... Args, - enable_if_t::value, int> = 0 > - json_ref(Args && ... args) - : owned_value(std::forward(args)...) - {} - - // class should be movable only - json_ref(json_ref&&) noexcept = default; - json_ref(const json_ref&) = delete; - json_ref& operator=(const json_ref&) = delete; - json_ref& operator=(json_ref&&) = delete; - ~json_ref() = default; - - value_type moved_or_copied() const - { - if (value_ref == nullptr) - { - return std::move(owned_value); - } - return *value_ref; - } - - value_type const& operator*() const - { - return value_ref ? *value_ref : owned_value; - } - - value_type const* operator->() const - { - return &** this; - } - - private: - mutable value_type owned_value = nullptr; - value_type const* value_ref = nullptr; -}; -} // namespace detail -} // namespace nlohmann - -// #include - -// #include - -// #include - -// #include - -// #include - - -#include // reverse -#include // array -#include // isnan, isinf -#include // uint8_t, uint16_t, uint32_t, uint64_t -#include // memcpy -#include // numeric_limits -#include // string -#include // move - -// #include - -// #include - -// #include - - -#include // copy -#include // size_t -#include // back_inserter -#include // shared_ptr, make_shared -#include // basic_string -#include // vector - -#ifndef JSON_NO_IO - #include // streamsize - #include // basic_ostream -#endif // JSON_NO_IO - -// #include - - -namespace nlohmann -{ -namespace detail -{ -/// abstract output adapter interface -template struct output_adapter_protocol -{ - virtual void write_character(CharType c) = 0; - virtual void write_characters(const CharType* s, std::size_t length) = 0; - virtual ~output_adapter_protocol() = default; - - output_adapter_protocol() = default; - output_adapter_protocol(const output_adapter_protocol&) = default; - output_adapter_protocol(output_adapter_protocol&&) noexcept = default; - output_adapter_protocol& operator=(const output_adapter_protocol&) = default; - output_adapter_protocol& operator=(output_adapter_protocol&&) noexcept = default; -}; - -/// a type to simplify interfaces -template -using output_adapter_t = std::shared_ptr>; - -/// output adapter for byte vectors -template> -class output_vector_adapter : public output_adapter_protocol -{ - public: - explicit output_vector_adapter(std::vector& vec) noexcept - : v(vec) - {} - - void write_character(CharType c) override - { - v.push_back(c); - } - - JSON_HEDLEY_NON_NULL(2) - void write_characters(const CharType* s, std::size_t length) override - { - std::copy(s, s + length, std::back_inserter(v)); - } - - private: - std::vector& v; -}; - -#ifndef JSON_NO_IO -/// output adapter for output streams -template -class output_stream_adapter : public output_adapter_protocol -{ - public: - explicit output_stream_adapter(std::basic_ostream& s) noexcept - : stream(s) - {} - - void write_character(CharType c) override - { - stream.put(c); - } - - JSON_HEDLEY_NON_NULL(2) - void write_characters(const CharType* s, std::size_t length) override - { - stream.write(s, static_cast(length)); - } - - private: - std::basic_ostream& stream; -}; -#endif // JSON_NO_IO - -/// output adapter for basic_string -template> -class output_string_adapter : public output_adapter_protocol -{ - public: - explicit output_string_adapter(StringType& s) noexcept - : str(s) - {} - - void write_character(CharType c) override - { - str.push_back(c); - } - - JSON_HEDLEY_NON_NULL(2) - void write_characters(const CharType* s, std::size_t length) override - { - str.append(s, length); - } - - private: - StringType& str; -}; - -template> -class output_adapter -{ - public: - template> - output_adapter(std::vector& vec) - : oa(std::make_shared>(vec)) {} - -#ifndef JSON_NO_IO - output_adapter(std::basic_ostream& s) - : oa(std::make_shared>(s)) {} -#endif // JSON_NO_IO - - output_adapter(StringType& s) - : oa(std::make_shared>(s)) {} - - operator output_adapter_t() - { - return oa; - } - - private: - output_adapter_t oa = nullptr; -}; -} // namespace detail -} // namespace nlohmann - - -namespace nlohmann -{ -namespace detail -{ -/////////////////// -// binary writer // -/////////////////// - -/*! -@brief serialization to CBOR and MessagePack values -*/ -template -class binary_writer -{ - using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; - using number_float_t = typename BasicJsonType::number_float_t; - - public: - /*! - @brief create a binary writer - - @param[in] adapter output adapter to write to - */ - explicit binary_writer(output_adapter_t adapter) : oa(std::move(adapter)) - { - JSON_ASSERT(oa); - } - - /*! - @param[in] j JSON value to serialize - @pre j.type() == value_t::object - */ - void write_bson(const BasicJsonType& j) - { - switch (j.type()) - { - case value_t::object: - { - write_bson_object(*j.m_value.object); - break; - } - - case value_t::null: - case value_t::array: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - JSON_THROW(type_error::create(317, "to serialize to BSON, top-level type must be object, but is " + std::string(j.type_name()), j)); - } - } - } - - /*! - @param[in] j JSON value to serialize - */ - void write_cbor(const BasicJsonType& j) - { - switch (j.type()) - { - case value_t::null: - { - oa->write_character(to_char_type(0xF6)); - break; - } - - case value_t::boolean: - { - oa->write_character(j.m_value.boolean - ? to_char_type(0xF5) - : to_char_type(0xF4)); - break; - } - - case value_t::number_integer: - { - if (j.m_value.number_integer >= 0) - { - // CBOR does not differentiate between positive signed - // integers and unsigned integers. Therefore, we used the - // code from the value_t::number_unsigned case here. - if (j.m_value.number_integer <= 0x17) - { - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0x18)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0x19)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0x1A)); - write_number(static_cast(j.m_value.number_integer)); - } - else - { - oa->write_character(to_char_type(0x1B)); - write_number(static_cast(j.m_value.number_integer)); - } - } - else - { - // The conversions below encode the sign in the first - // byte, and the value is converted to a positive number. - const auto positive_number = -1 - j.m_value.number_integer; - if (j.m_value.number_integer >= -24) - { - write_number(static_cast(0x20 + positive_number)); - } - else if (positive_number <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0x38)); - write_number(static_cast(positive_number)); - } - else if (positive_number <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0x39)); - write_number(static_cast(positive_number)); - } - else if (positive_number <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0x3A)); - write_number(static_cast(positive_number)); - } - else - { - oa->write_character(to_char_type(0x3B)); - write_number(static_cast(positive_number)); - } - } - break; - } - - case value_t::number_unsigned: - { - if (j.m_value.number_unsigned <= 0x17) - { - write_number(static_cast(j.m_value.number_unsigned)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0x18)); - write_number(static_cast(j.m_value.number_unsigned)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0x19)); - write_number(static_cast(j.m_value.number_unsigned)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0x1A)); - write_number(static_cast(j.m_value.number_unsigned)); - } - else - { - oa->write_character(to_char_type(0x1B)); - write_number(static_cast(j.m_value.number_unsigned)); - } - break; - } - - case value_t::number_float: - { - if (std::isnan(j.m_value.number_float)) - { - // NaN is 0xf97e00 in CBOR - oa->write_character(to_char_type(0xF9)); - oa->write_character(to_char_type(0x7E)); - oa->write_character(to_char_type(0x00)); - } - else if (std::isinf(j.m_value.number_float)) - { - // Infinity is 0xf97c00, -Infinity is 0xf9fc00 - oa->write_character(to_char_type(0xf9)); - oa->write_character(j.m_value.number_float > 0 ? to_char_type(0x7C) : to_char_type(0xFC)); - oa->write_character(to_char_type(0x00)); - } - else - { - write_compact_float(j.m_value.number_float, detail::input_format_t::cbor); - } - break; - } - - case value_t::string: - { - // step 1: write control byte and the string length - const auto N = j.m_value.string->size(); - if (N <= 0x17) - { - write_number(static_cast(0x60 + N)); - } - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0x78)); - write_number(static_cast(N)); - } - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0x79)); - write_number(static_cast(N)); - } - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0x7A)); - write_number(static_cast(N)); - } - // LCOV_EXCL_START - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0x7B)); - write_number(static_cast(N)); - } - // LCOV_EXCL_STOP - - // step 2: write the string - oa->write_characters( - reinterpret_cast(j.m_value.string->c_str()), - j.m_value.string->size()); - break; - } - - case value_t::array: - { - // step 1: write control byte and the array size - const auto N = j.m_value.array->size(); - if (N <= 0x17) - { - write_number(static_cast(0x80 + N)); - } - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0x98)); - write_number(static_cast(N)); - } - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0x99)); - write_number(static_cast(N)); - } - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0x9A)); - write_number(static_cast(N)); - } - // LCOV_EXCL_START - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0x9B)); - write_number(static_cast(N)); - } - // LCOV_EXCL_STOP - - // step 2: write each element - for (const auto& el : *j.m_value.array) - { - write_cbor(el); - } - break; - } - - case value_t::binary: - { - if (j.m_value.binary->has_subtype()) - { - if (j.m_value.binary->subtype() <= (std::numeric_limits::max)()) - { - write_number(static_cast(0xd8)); - write_number(static_cast(j.m_value.binary->subtype())); - } - else if (j.m_value.binary->subtype() <= (std::numeric_limits::max)()) - { - write_number(static_cast(0xd9)); - write_number(static_cast(j.m_value.binary->subtype())); - } - else if (j.m_value.binary->subtype() <= (std::numeric_limits::max)()) - { - write_number(static_cast(0xda)); - write_number(static_cast(j.m_value.binary->subtype())); - } - else if (j.m_value.binary->subtype() <= (std::numeric_limits::max)()) - { - write_number(static_cast(0xdb)); - write_number(static_cast(j.m_value.binary->subtype())); - } - } - - // step 1: write control byte and the binary array size - const auto N = j.m_value.binary->size(); - if (N <= 0x17) - { - write_number(static_cast(0x40 + N)); - } - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0x58)); - write_number(static_cast(N)); - } - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0x59)); - write_number(static_cast(N)); - } - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0x5A)); - write_number(static_cast(N)); - } - // LCOV_EXCL_START - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0x5B)); - write_number(static_cast(N)); - } - // LCOV_EXCL_STOP - - // step 2: write each element - oa->write_characters( - reinterpret_cast(j.m_value.binary->data()), - N); - - break; - } - - case value_t::object: - { - // step 1: write control byte and the object size - const auto N = j.m_value.object->size(); - if (N <= 0x17) - { - write_number(static_cast(0xA0 + N)); - } - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0xB8)); - write_number(static_cast(N)); - } - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0xB9)); - write_number(static_cast(N)); - } - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0xBA)); - write_number(static_cast(N)); - } - // LCOV_EXCL_START - else if (N <= (std::numeric_limits::max)()) - { - oa->write_character(to_char_type(0xBB)); - write_number(static_cast(N)); - } - // LCOV_EXCL_STOP - - // step 2: write each element - for (const auto& el : *j.m_value.object) - { - write_cbor(el.first); - write_cbor(el.second); - } - break; - } - - case value_t::discarded: - default: - break; - } - } - - /*! - @param[in] j JSON value to serialize - */ - void write_msgpack(const BasicJsonType& j) - { - switch (j.type()) - { - case value_t::null: // nil - { - oa->write_character(to_char_type(0xC0)); - break; - } - - case value_t::boolean: // true and false - { - oa->write_character(j.m_value.boolean - ? to_char_type(0xC3) - : to_char_type(0xC2)); - break; - } - - case value_t::number_integer: - { - if (j.m_value.number_integer >= 0) - { - // MessagePack does not differentiate between positive - // signed integers and unsigned integers. Therefore, we used - // the code from the value_t::number_unsigned case here. - if (j.m_value.number_unsigned < 128) - { - // positive fixnum - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 8 - oa->write_character(to_char_type(0xCC)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 16 - oa->write_character(to_char_type(0xCD)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 32 - oa->write_character(to_char_type(0xCE)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 64 - oa->write_character(to_char_type(0xCF)); - write_number(static_cast(j.m_value.number_integer)); - } - } - else - { - if (j.m_value.number_integer >= -32) - { - // negative fixnum - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer >= (std::numeric_limits::min)() && - j.m_value.number_integer <= (std::numeric_limits::max)()) - { - // int 8 - oa->write_character(to_char_type(0xD0)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer >= (std::numeric_limits::min)() && - j.m_value.number_integer <= (std::numeric_limits::max)()) - { - // int 16 - oa->write_character(to_char_type(0xD1)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer >= (std::numeric_limits::min)() && - j.m_value.number_integer <= (std::numeric_limits::max)()) - { - // int 32 - oa->write_character(to_char_type(0xD2)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer >= (std::numeric_limits::min)() && - j.m_value.number_integer <= (std::numeric_limits::max)()) - { - // int 64 - oa->write_character(to_char_type(0xD3)); - write_number(static_cast(j.m_value.number_integer)); - } - } - break; - } - - case value_t::number_unsigned: - { - if (j.m_value.number_unsigned < 128) - { - // positive fixnum - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 8 - oa->write_character(to_char_type(0xCC)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 16 - oa->write_character(to_char_type(0xCD)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 32 - oa->write_character(to_char_type(0xCE)); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 64 - oa->write_character(to_char_type(0xCF)); - write_number(static_cast(j.m_value.number_integer)); - } - break; - } - - case value_t::number_float: - { - write_compact_float(j.m_value.number_float, detail::input_format_t::msgpack); - break; - } - - case value_t::string: - { - // step 1: write control byte and the string length - const auto N = j.m_value.string->size(); - if (N <= 31) - { - // fixstr - write_number(static_cast(0xA0 | N)); - } - else if (N <= (std::numeric_limits::max)()) - { - // str 8 - oa->write_character(to_char_type(0xD9)); - write_number(static_cast(N)); - } - else if (N <= (std::numeric_limits::max)()) - { - // str 16 - oa->write_character(to_char_type(0xDA)); - write_number(static_cast(N)); - } - else if (N <= (std::numeric_limits::max)()) - { - // str 32 - oa->write_character(to_char_type(0xDB)); - write_number(static_cast(N)); - } - - // step 2: write the string - oa->write_characters( - reinterpret_cast(j.m_value.string->c_str()), - j.m_value.string->size()); - break; - } - - case value_t::array: - { - // step 1: write control byte and the array size - const auto N = j.m_value.array->size(); - if (N <= 15) - { - // fixarray - write_number(static_cast(0x90 | N)); - } - else if (N <= (std::numeric_limits::max)()) - { - // array 16 - oa->write_character(to_char_type(0xDC)); - write_number(static_cast(N)); - } - else if (N <= (std::numeric_limits::max)()) - { - // array 32 - oa->write_character(to_char_type(0xDD)); - write_number(static_cast(N)); - } - - // step 2: write each element - for (const auto& el : *j.m_value.array) - { - write_msgpack(el); - } - break; - } - - case value_t::binary: - { - // step 0: determine if the binary type has a set subtype to - // determine whether or not to use the ext or fixext types - const bool use_ext = j.m_value.binary->has_subtype(); - - // step 1: write control byte and the byte string length - const auto N = j.m_value.binary->size(); - if (N <= (std::numeric_limits::max)()) - { - std::uint8_t output_type{}; - bool fixed = true; - if (use_ext) - { - switch (N) - { - case 1: - output_type = 0xD4; // fixext 1 - break; - case 2: - output_type = 0xD5; // fixext 2 - break; - case 4: - output_type = 0xD6; // fixext 4 - break; - case 8: - output_type = 0xD7; // fixext 8 - break; - case 16: - output_type = 0xD8; // fixext 16 - break; - default: - output_type = 0xC7; // ext 8 - fixed = false; - break; - } - - } - else - { - output_type = 0xC4; // bin 8 - fixed = false; - } - - oa->write_character(to_char_type(output_type)); - if (!fixed) - { - write_number(static_cast(N)); - } - } - else if (N <= (std::numeric_limits::max)()) - { - std::uint8_t output_type = use_ext - ? 0xC8 // ext 16 - : 0xC5; // bin 16 - - oa->write_character(to_char_type(output_type)); - write_number(static_cast(N)); - } - else if (N <= (std::numeric_limits::max)()) - { - std::uint8_t output_type = use_ext - ? 0xC9 // ext 32 - : 0xC6; // bin 32 - - oa->write_character(to_char_type(output_type)); - write_number(static_cast(N)); - } - - // step 1.5: if this is an ext type, write the subtype - if (use_ext) - { - write_number(static_cast(j.m_value.binary->subtype())); - } - - // step 2: write the byte string - oa->write_characters( - reinterpret_cast(j.m_value.binary->data()), - N); - - break; - } - - case value_t::object: - { - // step 1: write control byte and the object size - const auto N = j.m_value.object->size(); - if (N <= 15) - { - // fixmap - write_number(static_cast(0x80 | (N & 0xF))); - } - else if (N <= (std::numeric_limits::max)()) - { - // map 16 - oa->write_character(to_char_type(0xDE)); - write_number(static_cast(N)); - } - else if (N <= (std::numeric_limits::max)()) - { - // map 32 - oa->write_character(to_char_type(0xDF)); - write_number(static_cast(N)); - } - - // step 2: write each element - for (const auto& el : *j.m_value.object) - { - write_msgpack(el.first); - write_msgpack(el.second); - } - break; - } - - case value_t::discarded: - default: - break; - } - } - - /*! - @param[in] j JSON value to serialize - @param[in] use_count whether to use '#' prefixes (optimized format) - @param[in] use_type whether to use '$' prefixes (optimized format) - @param[in] add_prefix whether prefixes need to be used for this value - */ - void write_ubjson(const BasicJsonType& j, const bool use_count, - const bool use_type, const bool add_prefix = true) - { - switch (j.type()) - { - case value_t::null: - { - if (add_prefix) - { - oa->write_character(to_char_type('Z')); - } - break; - } - - case value_t::boolean: - { - if (add_prefix) - { - oa->write_character(j.m_value.boolean - ? to_char_type('T') - : to_char_type('F')); - } - break; - } - - case value_t::number_integer: - { - write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix); - break; - } - - case value_t::number_unsigned: - { - write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix); - break; - } - - case value_t::number_float: - { - write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix); - break; - } - - case value_t::string: - { - if (add_prefix) - { - oa->write_character(to_char_type('S')); - } - write_number_with_ubjson_prefix(j.m_value.string->size(), true); - oa->write_characters( - reinterpret_cast(j.m_value.string->c_str()), - j.m_value.string->size()); - break; - } - - case value_t::array: - { - if (add_prefix) - { - oa->write_character(to_char_type('[')); - } - - bool prefix_required = true; - if (use_type && !j.m_value.array->empty()) - { - JSON_ASSERT(use_count); - const CharType first_prefix = ubjson_prefix(j.front()); - const bool same_prefix = std::all_of(j.begin() + 1, j.end(), - [this, first_prefix](const BasicJsonType & v) - { - return ubjson_prefix(v) == first_prefix; - }); - - if (same_prefix) - { - prefix_required = false; - oa->write_character(to_char_type('$')); - oa->write_character(first_prefix); - } - } - - if (use_count) - { - oa->write_character(to_char_type('#')); - write_number_with_ubjson_prefix(j.m_value.array->size(), true); - } - - for (const auto& el : *j.m_value.array) - { - write_ubjson(el, use_count, use_type, prefix_required); - } - - if (!use_count) - { - oa->write_character(to_char_type(']')); - } - - break; - } - - case value_t::binary: - { - if (add_prefix) - { - oa->write_character(to_char_type('[')); - } - - if (use_type && !j.m_value.binary->empty()) - { - JSON_ASSERT(use_count); - oa->write_character(to_char_type('$')); - oa->write_character('U'); - } - - if (use_count) - { - oa->write_character(to_char_type('#')); - write_number_with_ubjson_prefix(j.m_value.binary->size(), true); - } - - if (use_type) - { - oa->write_characters( - reinterpret_cast(j.m_value.binary->data()), - j.m_value.binary->size()); - } - else - { - for (size_t i = 0; i < j.m_value.binary->size(); ++i) - { - oa->write_character(to_char_type('U')); - oa->write_character(j.m_value.binary->data()[i]); - } - } - - if (!use_count) - { - oa->write_character(to_char_type(']')); - } - - break; - } - - case value_t::object: - { - if (add_prefix) - { - oa->write_character(to_char_type('{')); - } - - bool prefix_required = true; - if (use_type && !j.m_value.object->empty()) - { - JSON_ASSERT(use_count); - const CharType first_prefix = ubjson_prefix(j.front()); - const bool same_prefix = std::all_of(j.begin(), j.end(), - [this, first_prefix](const BasicJsonType & v) - { - return ubjson_prefix(v) == first_prefix; - }); - - if (same_prefix) - { - prefix_required = false; - oa->write_character(to_char_type('$')); - oa->write_character(first_prefix); - } - } - - if (use_count) - { - oa->write_character(to_char_type('#')); - write_number_with_ubjson_prefix(j.m_value.object->size(), true); - } - - for (const auto& el : *j.m_value.object) - { - write_number_with_ubjson_prefix(el.first.size(), true); - oa->write_characters( - reinterpret_cast(el.first.c_str()), - el.first.size()); - write_ubjson(el.second, use_count, use_type, prefix_required); - } - - if (!use_count) - { - oa->write_character(to_char_type('}')); - } - - break; - } - - case value_t::discarded: - default: - break; - } - } - - private: - ////////// - // BSON // - ////////// - - /*! - @return The size of a BSON document entry header, including the id marker - and the entry name size (and its null-terminator). - */ - static std::size_t calc_bson_entry_header_size(const string_t& name, const BasicJsonType& j) - { - const auto it = name.find(static_cast(0)); - if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos)) - { - JSON_THROW(out_of_range::create(409, "BSON key cannot contain code point U+0000 (at byte " + std::to_string(it) + ")", j)); - static_cast(j); - } - - return /*id*/ 1ul + name.size() + /*zero-terminator*/1u; - } - - /*! - @brief Writes the given @a element_type and @a name to the output adapter - */ - void write_bson_entry_header(const string_t& name, - const std::uint8_t element_type) - { - oa->write_character(to_char_type(element_type)); // boolean - oa->write_characters( - reinterpret_cast(name.c_str()), - name.size() + 1u); - } - - /*! - @brief Writes a BSON element with key @a name and boolean value @a value - */ - void write_bson_boolean(const string_t& name, - const bool value) - { - write_bson_entry_header(name, 0x08); - oa->write_character(value ? to_char_type(0x01) : to_char_type(0x00)); - } - - /*! - @brief Writes a BSON element with key @a name and double value @a value - */ - void write_bson_double(const string_t& name, - const double value) - { - write_bson_entry_header(name, 0x01); - write_number(value); - } - - /*! - @return The size of the BSON-encoded string in @a value - */ - static std::size_t calc_bson_string_size(const string_t& value) - { - return sizeof(std::int32_t) + value.size() + 1ul; - } - - /*! - @brief Writes a BSON element with key @a name and string value @a value - */ - void write_bson_string(const string_t& name, - const string_t& value) - { - write_bson_entry_header(name, 0x02); - - write_number(static_cast(value.size() + 1ul)); - oa->write_characters( - reinterpret_cast(value.c_str()), - value.size() + 1); - } - - /*! - @brief Writes a BSON element with key @a name and null value - */ - void write_bson_null(const string_t& name) - { - write_bson_entry_header(name, 0x0A); - } - - /*! - @return The size of the BSON-encoded integer @a value - */ - static std::size_t calc_bson_integer_size(const std::int64_t value) - { - return (std::numeric_limits::min)() <= value && value <= (std::numeric_limits::max)() - ? sizeof(std::int32_t) - : sizeof(std::int64_t); - } - - /*! - @brief Writes a BSON element with key @a name and integer @a value - */ - void write_bson_integer(const string_t& name, - const std::int64_t value) - { - if ((std::numeric_limits::min)() <= value && value <= (std::numeric_limits::max)()) - { - write_bson_entry_header(name, 0x10); // int32 - write_number(static_cast(value)); - } - else - { - write_bson_entry_header(name, 0x12); // int64 - write_number(static_cast(value)); - } - } - - /*! - @return The size of the BSON-encoded unsigned integer in @a j - */ - static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept - { - return (value <= static_cast((std::numeric_limits::max)())) - ? sizeof(std::int32_t) - : sizeof(std::int64_t); - } - - /*! - @brief Writes a BSON element with key @a name and unsigned @a value - */ - void write_bson_unsigned(const string_t& name, - const BasicJsonType& j) - { - if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) - { - write_bson_entry_header(name, 0x10 /* int32 */); - write_number(static_cast(j.m_value.number_unsigned)); - } - else if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) - { - write_bson_entry_header(name, 0x12 /* int64 */); - write_number(static_cast(j.m_value.number_unsigned)); - } - else - { - JSON_THROW(out_of_range::create(407, "integer number " + std::to_string(j.m_value.number_unsigned) + " cannot be represented by BSON as it does not fit int64", j)); - } - } - - /*! - @brief Writes a BSON element with key @a name and object @a value - */ - void write_bson_object_entry(const string_t& name, - const typename BasicJsonType::object_t& value) - { - write_bson_entry_header(name, 0x03); // object - write_bson_object(value); - } - - /*! - @return The size of the BSON-encoded array @a value - */ - static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value) - { - std::size_t array_index = 0ul; - - const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), static_cast(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el) - { - return result + calc_bson_element_size(std::to_string(array_index++), el); - }); - - return sizeof(std::int32_t) + embedded_document_size + 1ul; - } - - /*! - @return The size of the BSON-encoded binary array @a value - */ - static std::size_t calc_bson_binary_size(const typename BasicJsonType::binary_t& value) - { - return sizeof(std::int32_t) + value.size() + 1ul; - } - - /*! - @brief Writes a BSON element with key @a name and array @a value - */ - void write_bson_array(const string_t& name, - const typename BasicJsonType::array_t& value) - { - write_bson_entry_header(name, 0x04); // array - write_number(static_cast(calc_bson_array_size(value))); - - std::size_t array_index = 0ul; - - for (const auto& el : value) - { - write_bson_element(std::to_string(array_index++), el); - } - - oa->write_character(to_char_type(0x00)); - } - - /*! - @brief Writes a BSON element with key @a name and binary value @a value - */ - void write_bson_binary(const string_t& name, - const binary_t& value) - { - write_bson_entry_header(name, 0x05); - - write_number(static_cast(value.size())); - write_number(value.has_subtype() ? static_cast(value.subtype()) : static_cast(0x00)); - - oa->write_characters(reinterpret_cast(value.data()), value.size()); - } - - /*! - @brief Calculates the size necessary to serialize the JSON value @a j with its @a name - @return The calculated size for the BSON document entry for @a j with the given @a name. - */ - static std::size_t calc_bson_element_size(const string_t& name, - const BasicJsonType& j) - { - const auto header_size = calc_bson_entry_header_size(name, j); - switch (j.type()) - { - case value_t::object: - return header_size + calc_bson_object_size(*j.m_value.object); - - case value_t::array: - return header_size + calc_bson_array_size(*j.m_value.array); - - case value_t::binary: - return header_size + calc_bson_binary_size(*j.m_value.binary); - - case value_t::boolean: - return header_size + 1ul; - - case value_t::number_float: - return header_size + 8ul; - - case value_t::number_integer: - return header_size + calc_bson_integer_size(j.m_value.number_integer); - - case value_t::number_unsigned: - return header_size + calc_bson_unsigned_size(j.m_value.number_unsigned); - - case value_t::string: - return header_size + calc_bson_string_size(*j.m_value.string); - - case value_t::null: - return header_size + 0ul; - - // LCOV_EXCL_START - case value_t::discarded: - default: - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) - return 0ul; - // LCOV_EXCL_STOP - } - } - - /*! - @brief Serializes the JSON value @a j to BSON and associates it with the - key @a name. - @param name The name to associate with the JSON entity @a j within the - current BSON document - */ - void write_bson_element(const string_t& name, - const BasicJsonType& j) - { - switch (j.type()) - { - case value_t::object: - return write_bson_object_entry(name, *j.m_value.object); - - case value_t::array: - return write_bson_array(name, *j.m_value.array); - - case value_t::binary: - return write_bson_binary(name, *j.m_value.binary); - - case value_t::boolean: - return write_bson_boolean(name, j.m_value.boolean); - - case value_t::number_float: - return write_bson_double(name, j.m_value.number_float); - - case value_t::number_integer: - return write_bson_integer(name, j.m_value.number_integer); - - case value_t::number_unsigned: - return write_bson_unsigned(name, j); - - case value_t::string: - return write_bson_string(name, *j.m_value.string); - - case value_t::null: - return write_bson_null(name); - - // LCOV_EXCL_START - case value_t::discarded: - default: - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) - return; - // LCOV_EXCL_STOP - } - } - - /*! - @brief Calculates the size of the BSON serialization of the given - JSON-object @a j. - @param[in] value JSON value to serialize - @pre value.type() == value_t::object - */ - static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value) - { - std::size_t document_size = std::accumulate(value.begin(), value.end(), static_cast(0), - [](size_t result, const typename BasicJsonType::object_t::value_type & el) - { - return result += calc_bson_element_size(el.first, el.second); - }); - - return sizeof(std::int32_t) + document_size + 1ul; - } - - /*! - @param[in] value JSON value to serialize - @pre value.type() == value_t::object - */ - void write_bson_object(const typename BasicJsonType::object_t& value) - { - write_number(static_cast(calc_bson_object_size(value))); - - for (const auto& el : value) - { - write_bson_element(el.first, el.second); - } - - oa->write_character(to_char_type(0x00)); - } - - ////////// - // CBOR // - ////////// - - static constexpr CharType get_cbor_float_prefix(float /*unused*/) - { - return to_char_type(0xFA); // Single-Precision Float - } - - static constexpr CharType get_cbor_float_prefix(double /*unused*/) - { - return to_char_type(0xFB); // Double-Precision Float - } - - ///////////// - // MsgPack // - ///////////// - - static constexpr CharType get_msgpack_float_prefix(float /*unused*/) - { - return to_char_type(0xCA); // float 32 - } - - static constexpr CharType get_msgpack_float_prefix(double /*unused*/) - { - return to_char_type(0xCB); // float 64 - } - - //////////// - // UBJSON // - //////////// - - // UBJSON: write number (floating point) - template::value, int>::type = 0> - void write_number_with_ubjson_prefix(const NumberType n, - const bool add_prefix) - { - if (add_prefix) - { - oa->write_character(get_ubjson_float_prefix(n)); - } - write_number(n); - } - - // UBJSON: write number (unsigned integer) - template::value, int>::type = 0> - void write_number_with_ubjson_prefix(const NumberType n, - const bool add_prefix) - { - if (n <= static_cast((std::numeric_limits::max)())) - { - if (add_prefix) - { - oa->write_character(to_char_type('i')); // int8 - } - write_number(static_cast(n)); - } - else if (n <= (std::numeric_limits::max)()) - { - if (add_prefix) - { - oa->write_character(to_char_type('U')); // uint8 - } - write_number(static_cast(n)); - } - else if (n <= static_cast((std::numeric_limits::max)())) - { - if (add_prefix) - { - oa->write_character(to_char_type('I')); // int16 - } - write_number(static_cast(n)); - } - else if (n <= static_cast((std::numeric_limits::max)())) - { - if (add_prefix) - { - oa->write_character(to_char_type('l')); // int32 - } - write_number(static_cast(n)); - } - else if (n <= static_cast((std::numeric_limits::max)())) - { - if (add_prefix) - { - oa->write_character(to_char_type('L')); // int64 - } - write_number(static_cast(n)); - } - else - { - if (add_prefix) - { - oa->write_character(to_char_type('H')); // high-precision number - } - - const auto number = BasicJsonType(n).dump(); - write_number_with_ubjson_prefix(number.size(), true); - for (std::size_t i = 0; i < number.size(); ++i) - { - oa->write_character(to_char_type(static_cast(number[i]))); - } - } - } - - // UBJSON: write number (signed integer) - template < typename NumberType, typename std::enable_if < - std::is_signed::value&& - !std::is_floating_point::value, int >::type = 0 > - void write_number_with_ubjson_prefix(const NumberType n, - const bool add_prefix) - { - if ((std::numeric_limits::min)() <= n && n <= (std::numeric_limits::max)()) - { - if (add_prefix) - { - oa->write_character(to_char_type('i')); // int8 - } - write_number(static_cast(n)); - } - else if (static_cast((std::numeric_limits::min)()) <= n && n <= static_cast((std::numeric_limits::max)())) - { - if (add_prefix) - { - oa->write_character(to_char_type('U')); // uint8 - } - write_number(static_cast(n)); - } - else if ((std::numeric_limits::min)() <= n && n <= (std::numeric_limits::max)()) - { - if (add_prefix) - { - oa->write_character(to_char_type('I')); // int16 - } - write_number(static_cast(n)); - } - else if ((std::numeric_limits::min)() <= n && n <= (std::numeric_limits::max)()) - { - if (add_prefix) - { - oa->write_character(to_char_type('l')); // int32 - } - write_number(static_cast(n)); - } - else if ((std::numeric_limits::min)() <= n && n <= (std::numeric_limits::max)()) - { - if (add_prefix) - { - oa->write_character(to_char_type('L')); // int64 - } - write_number(static_cast(n)); - } - // LCOV_EXCL_START - else - { - if (add_prefix) - { - oa->write_character(to_char_type('H')); // high-precision number - } - - const auto number = BasicJsonType(n).dump(); - write_number_with_ubjson_prefix(number.size(), true); - for (std::size_t i = 0; i < number.size(); ++i) - { - oa->write_character(to_char_type(static_cast(number[i]))); - } - } - // LCOV_EXCL_STOP - } - - /*! - @brief determine the type prefix of container values - */ - CharType ubjson_prefix(const BasicJsonType& j) const noexcept - { - switch (j.type()) - { - case value_t::null: - return 'Z'; - - case value_t::boolean: - return j.m_value.boolean ? 'T' : 'F'; - - case value_t::number_integer: - { - if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) - { - return 'i'; - } - if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) - { - return 'U'; - } - if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) - { - return 'I'; - } - if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) - { - return 'l'; - } - if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) - { - return 'L'; - } - // anything else is treated as high-precision number - return 'H'; // LCOV_EXCL_LINE - } - - case value_t::number_unsigned: - { - if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) - { - return 'i'; - } - if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) - { - return 'U'; - } - if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) - { - return 'I'; - } - if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) - { - return 'l'; - } - if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) - { - return 'L'; - } - // anything else is treated as high-precision number - return 'H'; // LCOV_EXCL_LINE - } - - case value_t::number_float: - return get_ubjson_float_prefix(j.m_value.number_float); - - case value_t::string: - return 'S'; - - case value_t::array: // fallthrough - case value_t::binary: - return '['; - - case value_t::object: - return '{'; - - case value_t::discarded: - default: // discarded values - return 'N'; - } - } - - static constexpr CharType get_ubjson_float_prefix(float /*unused*/) - { - return 'd'; // float 32 - } - - static constexpr CharType get_ubjson_float_prefix(double /*unused*/) - { - return 'D'; // float 64 - } - - /////////////////////// - // Utility functions // - /////////////////////// - - /* - @brief write a number to output input - @param[in] n number of type @a NumberType - @tparam NumberType the type of the number - @tparam OutputIsLittleEndian Set to true if output data is - required to be little endian - - @note This function needs to respect the system's endianness, because bytes - in CBOR, MessagePack, and UBJSON are stored in network order (big - endian) and therefore need reordering on little endian systems. - */ - template - void write_number(const NumberType n) - { - // step 1: write number to array of length NumberType - std::array vec{}; - std::memcpy(vec.data(), &n, sizeof(NumberType)); - - // step 2: write array to output (with possible reordering) - if (is_little_endian != OutputIsLittleEndian) - { - // reverse byte order prior to conversion if necessary - std::reverse(vec.begin(), vec.end()); - } - - oa->write_characters(vec.data(), sizeof(NumberType)); - } - - void write_compact_float(const number_float_t n, detail::input_format_t format) - { -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wfloat-equal" -#endif - if (static_cast(n) >= static_cast(std::numeric_limits::lowest()) && - static_cast(n) <= static_cast((std::numeric_limits::max)()) && - static_cast(static_cast(n)) == static_cast(n)) - { - oa->write_character(format == detail::input_format_t::cbor - ? get_cbor_float_prefix(static_cast(n)) - : get_msgpack_float_prefix(static_cast(n))); - write_number(static_cast(n)); - } - else - { - oa->write_character(format == detail::input_format_t::cbor - ? get_cbor_float_prefix(n) - : get_msgpack_float_prefix(n)); - write_number(n); - } -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif - } - - public: - // The following to_char_type functions are implement the conversion - // between uint8_t and CharType. In case CharType is not unsigned, - // such a conversion is required to allow values greater than 128. - // See for a discussion. - template < typename C = CharType, - enable_if_t < std::is_signed::value && std::is_signed::value > * = nullptr > - static constexpr CharType to_char_type(std::uint8_t x) noexcept - { - return *reinterpret_cast(&x); - } - - template < typename C = CharType, - enable_if_t < std::is_signed::value && std::is_unsigned::value > * = nullptr > - static CharType to_char_type(std::uint8_t x) noexcept - { - static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t"); - static_assert(std::is_trivial::value, "CharType must be trivial"); - CharType result; - std::memcpy(&result, &x, sizeof(x)); - return result; - } - - template::value>* = nullptr> - static constexpr CharType to_char_type(std::uint8_t x) noexcept - { - return x; - } - - template < typename InputCharType, typename C = CharType, - enable_if_t < - std::is_signed::value && - std::is_signed::value && - std::is_same::type>::value - > * = nullptr > - static constexpr CharType to_char_type(InputCharType x) noexcept - { - return x; - } - - private: - /// whether we can assume little endianness - const bool is_little_endian = little_endianness(); - - /// the output - output_adapter_t oa = nullptr; -}; -} // namespace detail -} // namespace nlohmann - -// #include - -// #include - - -#include // reverse, remove, fill, find, none_of -#include // array -#include // localeconv, lconv -#include // labs, isfinite, isnan, signbit -#include // size_t, ptrdiff_t -#include // uint8_t -#include // snprintf -#include // numeric_limits -#include // string, char_traits -#include // setfill, setw -#include // is_same -#include // move - -// #include - - -#include // array -#include // signbit, isfinite -#include // intN_t, uintN_t -#include // memcpy, memmove -#include // numeric_limits -#include // conditional - -// #include - - -namespace nlohmann -{ -namespace detail -{ - -/*! -@brief implements the Grisu2 algorithm for binary to decimal floating-point -conversion. - -This implementation is a slightly modified version of the reference -implementation which may be obtained from -http://florian.loitsch.com/publications (bench.tar.gz). - -The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch. - -For a detailed description of the algorithm see: - -[1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with - Integers", Proceedings of the ACM SIGPLAN 2010 Conference on Programming - Language Design and Implementation, PLDI 2010 -[2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately", - Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language - Design and Implementation, PLDI 1996 -*/ -namespace dtoa_impl -{ - -template -Target reinterpret_bits(const Source source) -{ - static_assert(sizeof(Target) == sizeof(Source), "size mismatch"); - - Target target; - std::memcpy(&target, &source, sizeof(Source)); - return target; -} - -struct diyfp // f * 2^e -{ - static constexpr int kPrecision = 64; // = q - - std::uint64_t f = 0; - int e = 0; - - constexpr diyfp(std::uint64_t f_, int e_) noexcept : f(f_), e(e_) {} - - /*! - @brief returns x - y - @pre x.e == y.e and x.f >= y.f - */ - static diyfp sub(const diyfp& x, const diyfp& y) noexcept - { - JSON_ASSERT(x.e == y.e); - JSON_ASSERT(x.f >= y.f); - - return {x.f - y.f, x.e}; - } - - /*! - @brief returns x * y - @note The result is rounded. (Only the upper q bits are returned.) - */ - static diyfp mul(const diyfp& x, const diyfp& y) noexcept - { - static_assert(kPrecision == 64, "internal error"); - - // Computes: - // f = round((x.f * y.f) / 2^q) - // e = x.e + y.e + q - - // Emulate the 64-bit * 64-bit multiplication: - // - // p = u * v - // = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi) - // = (u_lo v_lo ) + 2^32 ((u_lo v_hi ) + (u_hi v_lo )) + 2^64 (u_hi v_hi ) - // = (p0 ) + 2^32 ((p1 ) + (p2 )) + 2^64 (p3 ) - // = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3 ) - // = (p0_lo ) + 2^32 (p0_hi + p1_lo + p2_lo ) + 2^64 (p1_hi + p2_hi + p3) - // = (p0_lo ) + 2^32 (Q ) + 2^64 (H ) - // = (p0_lo ) + 2^32 (Q_lo + 2^32 Q_hi ) + 2^64 (H ) - // - // (Since Q might be larger than 2^32 - 1) - // - // = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H) - // - // (Q_hi + H does not overflow a 64-bit int) - // - // = p_lo + 2^64 p_hi - - const std::uint64_t u_lo = x.f & 0xFFFFFFFFu; - const std::uint64_t u_hi = x.f >> 32u; - const std::uint64_t v_lo = y.f & 0xFFFFFFFFu; - const std::uint64_t v_hi = y.f >> 32u; - - const std::uint64_t p0 = u_lo * v_lo; - const std::uint64_t p1 = u_lo * v_hi; - const std::uint64_t p2 = u_hi * v_lo; - const std::uint64_t p3 = u_hi * v_hi; - - const std::uint64_t p0_hi = p0 >> 32u; - const std::uint64_t p1_lo = p1 & 0xFFFFFFFFu; - const std::uint64_t p1_hi = p1 >> 32u; - const std::uint64_t p2_lo = p2 & 0xFFFFFFFFu; - const std::uint64_t p2_hi = p2 >> 32u; - - std::uint64_t Q = p0_hi + p1_lo + p2_lo; - - // The full product might now be computed as - // - // p_hi = p3 + p2_hi + p1_hi + (Q >> 32) - // p_lo = p0_lo + (Q << 32) - // - // But in this particular case here, the full p_lo is not required. - // Effectively we only need to add the highest bit in p_lo to p_hi (and - // Q_hi + 1 does not overflow). - - Q += std::uint64_t{1} << (64u - 32u - 1u); // round, ties up - - const std::uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32u); - - return {h, x.e + y.e + 64}; - } - - /*! - @brief normalize x such that the significand is >= 2^(q-1) - @pre x.f != 0 - */ - static diyfp normalize(diyfp x) noexcept - { - JSON_ASSERT(x.f != 0); - - while ((x.f >> 63u) == 0) - { - x.f <<= 1u; - x.e--; - } - - return x; - } - - /*! - @brief normalize x such that the result has the exponent E - @pre e >= x.e and the upper e - x.e bits of x.f must be zero. - */ - static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept - { - const int delta = x.e - target_exponent; - - JSON_ASSERT(delta >= 0); - JSON_ASSERT(((x.f << delta) >> delta) == x.f); - - return {x.f << delta, target_exponent}; - } -}; - -struct boundaries -{ - diyfp w; - diyfp minus; - diyfp plus; -}; - -/*! -Compute the (normalized) diyfp representing the input number 'value' and its -boundaries. - -@pre value must be finite and positive -*/ -template -boundaries compute_boundaries(FloatType value) -{ - JSON_ASSERT(std::isfinite(value)); - JSON_ASSERT(value > 0); - - // Convert the IEEE representation into a diyfp. - // - // If v is denormal: - // value = 0.F * 2^(1 - bias) = ( F) * 2^(1 - bias - (p-1)) - // If v is normalized: - // value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1)) - - static_assert(std::numeric_limits::is_iec559, - "internal error: dtoa_short requires an IEEE-754 floating-point implementation"); - - constexpr int kPrecision = std::numeric_limits::digits; // = p (includes the hidden bit) - constexpr int kBias = std::numeric_limits::max_exponent - 1 + (kPrecision - 1); - constexpr int kMinExp = 1 - kBias; - constexpr std::uint64_t kHiddenBit = std::uint64_t{1} << (kPrecision - 1); // = 2^(p-1) - - using bits_type = typename std::conditional::type; - - const auto bits = static_cast(reinterpret_bits(value)); - const std::uint64_t E = bits >> (kPrecision - 1); - const std::uint64_t F = bits & (kHiddenBit - 1); - - const bool is_denormal = E == 0; - const diyfp v = is_denormal - ? diyfp(F, kMinExp) - : diyfp(F + kHiddenBit, static_cast(E) - kBias); - - // Compute the boundaries m- and m+ of the floating-point value - // v = f * 2^e. - // - // Determine v- and v+, the floating-point predecessor and successor if v, - // respectively. - // - // v- = v - 2^e if f != 2^(p-1) or e == e_min (A) - // = v - 2^(e-1) if f == 2^(p-1) and e > e_min (B) - // - // v+ = v + 2^e - // - // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_ - // between m- and m+ round to v, regardless of how the input rounding - // algorithm breaks ties. - // - // ---+-------------+-------------+-------------+-------------+--- (A) - // v- m- v m+ v+ - // - // -----------------+------+------+-------------+-------------+--- (B) - // v- m- v m+ v+ - - const bool lower_boundary_is_closer = F == 0 && E > 1; - const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1); - const diyfp m_minus = lower_boundary_is_closer - ? diyfp(4 * v.f - 1, v.e - 2) // (B) - : diyfp(2 * v.f - 1, v.e - 1); // (A) - - // Determine the normalized w+ = m+. - const diyfp w_plus = diyfp::normalize(m_plus); - - // Determine w- = m- such that e_(w-) = e_(w+). - const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e); - - return {diyfp::normalize(v), w_minus, w_plus}; -} - -// Given normalized diyfp w, Grisu needs to find a (normalized) cached -// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies -// within a certain range [alpha, gamma] (Definition 3.2 from [1]) -// -// alpha <= e = e_c + e_w + q <= gamma -// -// or -// -// f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q -// <= f_c * f_w * 2^gamma -// -// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies -// -// 2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma -// -// or -// -// 2^(q - 2 + alpha) <= c * w < 2^(q + gamma) -// -// The choice of (alpha,gamma) determines the size of the table and the form of -// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well -// in practice: -// -// The idea is to cut the number c * w = f * 2^e into two parts, which can be -// processed independently: An integral part p1, and a fractional part p2: -// -// f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e -// = (f div 2^-e) + (f mod 2^-e) * 2^e -// = p1 + p2 * 2^e -// -// The conversion of p1 into decimal form requires a series of divisions and -// modulos by (a power of) 10. These operations are faster for 32-bit than for -// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be -// achieved by choosing -// -// -e >= 32 or e <= -32 := gamma -// -// In order to convert the fractional part -// -// p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ... -// -// into decimal form, the fraction is repeatedly multiplied by 10 and the digits -// d[-i] are extracted in order: -// -// (10 * p2) div 2^-e = d[-1] -// (10 * p2) mod 2^-e = d[-2] / 10^1 + ... -// -// The multiplication by 10 must not overflow. It is sufficient to choose -// -// 10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64. -// -// Since p2 = f mod 2^-e < 2^-e, -// -// -e <= 60 or e >= -60 := alpha - -constexpr int kAlpha = -60; -constexpr int kGamma = -32; - -struct cached_power // c = f * 2^e ~= 10^k -{ - std::uint64_t f; - int e; - int k; -}; - -/*! -For a normalized diyfp w = f * 2^e, this function returns a (normalized) cached -power-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c -satisfies (Definition 3.2 from [1]) - - alpha <= e_c + e + q <= gamma. -*/ -inline cached_power get_cached_power_for_binary_exponent(int e) -{ - // Now - // - // alpha <= e_c + e + q <= gamma (1) - // ==> f_c * 2^alpha <= c * 2^e * 2^q - // - // and since the c's are normalized, 2^(q-1) <= f_c, - // - // ==> 2^(q - 1 + alpha) <= c * 2^(e + q) - // ==> 2^(alpha - e - 1) <= c - // - // If c were an exact power of ten, i.e. c = 10^k, one may determine k as - // - // k = ceil( log_10( 2^(alpha - e - 1) ) ) - // = ceil( (alpha - e - 1) * log_10(2) ) - // - // From the paper: - // "In theory the result of the procedure could be wrong since c is rounded, - // and the computation itself is approximated [...]. In practice, however, - // this simple function is sufficient." - // - // For IEEE double precision floating-point numbers converted into - // normalized diyfp's w = f * 2^e, with q = 64, - // - // e >= -1022 (min IEEE exponent) - // -52 (p - 1) - // -52 (p - 1, possibly normalize denormal IEEE numbers) - // -11 (normalize the diyfp) - // = -1137 - // - // and - // - // e <= +1023 (max IEEE exponent) - // -52 (p - 1) - // -11 (normalize the diyfp) - // = 960 - // - // This binary exponent range [-1137,960] results in a decimal exponent - // range [-307,324]. One does not need to store a cached power for each - // k in this range. For each such k it suffices to find a cached power - // such that the exponent of the product lies in [alpha,gamma]. - // This implies that the difference of the decimal exponents of adjacent - // table entries must be less than or equal to - // - // floor( (gamma - alpha) * log_10(2) ) = 8. - // - // (A smaller distance gamma-alpha would require a larger table.) - - // NB: - // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34. - - constexpr int kCachedPowersMinDecExp = -300; - constexpr int kCachedPowersDecStep = 8; - - static constexpr std::array kCachedPowers = - { - { - { 0xAB70FE17C79AC6CA, -1060, -300 }, - { 0xFF77B1FCBEBCDC4F, -1034, -292 }, - { 0xBE5691EF416BD60C, -1007, -284 }, - { 0x8DD01FAD907FFC3C, -980, -276 }, - { 0xD3515C2831559A83, -954, -268 }, - { 0x9D71AC8FADA6C9B5, -927, -260 }, - { 0xEA9C227723EE8BCB, -901, -252 }, - { 0xAECC49914078536D, -874, -244 }, - { 0x823C12795DB6CE57, -847, -236 }, - { 0xC21094364DFB5637, -821, -228 }, - { 0x9096EA6F3848984F, -794, -220 }, - { 0xD77485CB25823AC7, -768, -212 }, - { 0xA086CFCD97BF97F4, -741, -204 }, - { 0xEF340A98172AACE5, -715, -196 }, - { 0xB23867FB2A35B28E, -688, -188 }, - { 0x84C8D4DFD2C63F3B, -661, -180 }, - { 0xC5DD44271AD3CDBA, -635, -172 }, - { 0x936B9FCEBB25C996, -608, -164 }, - { 0xDBAC6C247D62A584, -582, -156 }, - { 0xA3AB66580D5FDAF6, -555, -148 }, - { 0xF3E2F893DEC3F126, -529, -140 }, - { 0xB5B5ADA8AAFF80B8, -502, -132 }, - { 0x87625F056C7C4A8B, -475, -124 }, - { 0xC9BCFF6034C13053, -449, -116 }, - { 0x964E858C91BA2655, -422, -108 }, - { 0xDFF9772470297EBD, -396, -100 }, - { 0xA6DFBD9FB8E5B88F, -369, -92 }, - { 0xF8A95FCF88747D94, -343, -84 }, - { 0xB94470938FA89BCF, -316, -76 }, - { 0x8A08F0F8BF0F156B, -289, -68 }, - { 0xCDB02555653131B6, -263, -60 }, - { 0x993FE2C6D07B7FAC, -236, -52 }, - { 0xE45C10C42A2B3B06, -210, -44 }, - { 0xAA242499697392D3, -183, -36 }, - { 0xFD87B5F28300CA0E, -157, -28 }, - { 0xBCE5086492111AEB, -130, -20 }, - { 0x8CBCCC096F5088CC, -103, -12 }, - { 0xD1B71758E219652C, -77, -4 }, - { 0x9C40000000000000, -50, 4 }, - { 0xE8D4A51000000000, -24, 12 }, - { 0xAD78EBC5AC620000, 3, 20 }, - { 0x813F3978F8940984, 30, 28 }, - { 0xC097CE7BC90715B3, 56, 36 }, - { 0x8F7E32CE7BEA5C70, 83, 44 }, - { 0xD5D238A4ABE98068, 109, 52 }, - { 0x9F4F2726179A2245, 136, 60 }, - { 0xED63A231D4C4FB27, 162, 68 }, - { 0xB0DE65388CC8ADA8, 189, 76 }, - { 0x83C7088E1AAB65DB, 216, 84 }, - { 0xC45D1DF942711D9A, 242, 92 }, - { 0x924D692CA61BE758, 269, 100 }, - { 0xDA01EE641A708DEA, 295, 108 }, - { 0xA26DA3999AEF774A, 322, 116 }, - { 0xF209787BB47D6B85, 348, 124 }, - { 0xB454E4A179DD1877, 375, 132 }, - { 0x865B86925B9BC5C2, 402, 140 }, - { 0xC83553C5C8965D3D, 428, 148 }, - { 0x952AB45CFA97A0B3, 455, 156 }, - { 0xDE469FBD99A05FE3, 481, 164 }, - { 0xA59BC234DB398C25, 508, 172 }, - { 0xF6C69A72A3989F5C, 534, 180 }, - { 0xB7DCBF5354E9BECE, 561, 188 }, - { 0x88FCF317F22241E2, 588, 196 }, - { 0xCC20CE9BD35C78A5, 614, 204 }, - { 0x98165AF37B2153DF, 641, 212 }, - { 0xE2A0B5DC971F303A, 667, 220 }, - { 0xA8D9D1535CE3B396, 694, 228 }, - { 0xFB9B7CD9A4A7443C, 720, 236 }, - { 0xBB764C4CA7A44410, 747, 244 }, - { 0x8BAB8EEFB6409C1A, 774, 252 }, - { 0xD01FEF10A657842C, 800, 260 }, - { 0x9B10A4E5E9913129, 827, 268 }, - { 0xE7109BFBA19C0C9D, 853, 276 }, - { 0xAC2820D9623BF429, 880, 284 }, - { 0x80444B5E7AA7CF85, 907, 292 }, - { 0xBF21E44003ACDD2D, 933, 300 }, - { 0x8E679C2F5E44FF8F, 960, 308 }, - { 0xD433179D9C8CB841, 986, 316 }, - { 0x9E19DB92B4E31BA9, 1013, 324 }, - } - }; - - // This computation gives exactly the same results for k as - // k = ceil((kAlpha - e - 1) * 0.30102999566398114) - // for |e| <= 1500, but doesn't require floating-point operations. - // NB: log_10(2) ~= 78913 / 2^18 - JSON_ASSERT(e >= -1500); - JSON_ASSERT(e <= 1500); - const int f = kAlpha - e - 1; - const int k = (f * 78913) / (1 << 18) + static_cast(f > 0); - - const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; - JSON_ASSERT(index >= 0); - JSON_ASSERT(static_cast(index) < kCachedPowers.size()); - - const cached_power cached = kCachedPowers[static_cast(index)]; - JSON_ASSERT(kAlpha <= cached.e + e + 64); - JSON_ASSERT(kGamma >= cached.e + e + 64); - - return cached; -} - -/*! -For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k. -For n == 0, returns 1 and sets pow10 := 1. -*/ -inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10) -{ - // LCOV_EXCL_START - if (n >= 1000000000) - { - pow10 = 1000000000; - return 10; - } - // LCOV_EXCL_STOP - if (n >= 100000000) - { - pow10 = 100000000; - return 9; - } - if (n >= 10000000) - { - pow10 = 10000000; - return 8; - } - if (n >= 1000000) - { - pow10 = 1000000; - return 7; - } - if (n >= 100000) - { - pow10 = 100000; - return 6; - } - if (n >= 10000) - { - pow10 = 10000; - return 5; - } - if (n >= 1000) - { - pow10 = 1000; - return 4; - } - if (n >= 100) - { - pow10 = 100; - return 3; - } - if (n >= 10) - { - pow10 = 10; - return 2; - } - - pow10 = 1; - return 1; -} - -inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta, - std::uint64_t rest, std::uint64_t ten_k) -{ - JSON_ASSERT(len >= 1); - JSON_ASSERT(dist <= delta); - JSON_ASSERT(rest <= delta); - JSON_ASSERT(ten_k > 0); - - // <--------------------------- delta ----> - // <---- dist ---------> - // --------------[------------------+-------------------]-------------- - // M- w M+ - // - // ten_k - // <------> - // <---- rest ----> - // --------------[------------------+----+--------------]-------------- - // w V - // = buf * 10^k - // - // ten_k represents a unit-in-the-last-place in the decimal representation - // stored in buf. - // Decrement buf by ten_k while this takes buf closer to w. - - // The tests are written in this order to avoid overflow in unsigned - // integer arithmetic. - - while (rest < dist - && delta - rest >= ten_k - && (rest + ten_k < dist || dist - rest > rest + ten_k - dist)) - { - JSON_ASSERT(buf[len - 1] != '0'); - buf[len - 1]--; - rest += ten_k; - } -} - -/*! -Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+. -M- and M+ must be normalized and share the same exponent -60 <= e <= -32. -*/ -inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, - diyfp M_minus, diyfp w, diyfp M_plus) -{ - static_assert(kAlpha >= -60, "internal error"); - static_assert(kGamma <= -32, "internal error"); - - // Generates the digits (and the exponent) of a decimal floating-point - // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's - // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma. - // - // <--------------------------- delta ----> - // <---- dist ---------> - // --------------[------------------+-------------------]-------------- - // M- w M+ - // - // Grisu2 generates the digits of M+ from left to right and stops as soon as - // V is in [M-,M+]. - - JSON_ASSERT(M_plus.e >= kAlpha); - JSON_ASSERT(M_plus.e <= kGamma); - - std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e) - std::uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e) - - // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0): - // - // M+ = f * 2^e - // = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e - // = ((p1 ) * 2^-e + (p2 )) * 2^e - // = p1 + p2 * 2^e - - const diyfp one(std::uint64_t{1} << -M_plus.e, M_plus.e); - - auto p1 = static_cast(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.) - std::uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e - - // 1) - // - // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0] - - JSON_ASSERT(p1 > 0); - - std::uint32_t pow10{}; - const int k = find_largest_pow10(p1, pow10); - - // 10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1) - // - // p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1)) - // = (d[k-1] ) * 10^(k-1) + (p1 mod 10^(k-1)) - // - // M+ = p1 + p2 * 2^e - // = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1)) + p2 * 2^e - // = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e - // = d[k-1] * 10^(k-1) + ( rest) * 2^e - // - // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0) - // - // p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0] - // - // but stop as soon as - // - // rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e - - int n = k; - while (n > 0) - { - // Invariants: - // M+ = buffer * 10^n + (p1 + p2 * 2^e) (buffer = 0 for n = k) - // pow10 = 10^(n-1) <= p1 < 10^n - // - const std::uint32_t d = p1 / pow10; // d = p1 div 10^(n-1) - const std::uint32_t r = p1 % pow10; // r = p1 mod 10^(n-1) - // - // M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e - // = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e) - // - JSON_ASSERT(d <= 9); - buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d - // - // M+ = buffer * 10^(n-1) + (r + p2 * 2^e) - // - p1 = r; - n--; - // - // M+ = buffer * 10^n + (p1 + p2 * 2^e) - // pow10 = 10^n - // - - // Now check if enough digits have been generated. - // Compute - // - // p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e - // - // Note: - // Since rest and delta share the same exponent e, it suffices to - // compare the significands. - const std::uint64_t rest = (std::uint64_t{p1} << -one.e) + p2; - if (rest <= delta) - { - // V = buffer * 10^n, with M- <= V <= M+. - - decimal_exponent += n; - - // We may now just stop. But instead look if the buffer could be - // decremented to bring V closer to w. - // - // pow10 = 10^n is now 1 ulp in the decimal representation V. - // The rounding procedure works with diyfp's with an implicit - // exponent of e. - // - // 10^n = (10^n * 2^-e) * 2^e = ulp * 2^e - // - const std::uint64_t ten_n = std::uint64_t{pow10} << -one.e; - grisu2_round(buffer, length, dist, delta, rest, ten_n); - - return; - } - - pow10 /= 10; - // - // pow10 = 10^(n-1) <= p1 < 10^n - // Invariants restored. - } - - // 2) - // - // The digits of the integral part have been generated: - // - // M+ = d[k-1]...d[1]d[0] + p2 * 2^e - // = buffer + p2 * 2^e - // - // Now generate the digits of the fractional part p2 * 2^e. - // - // Note: - // No decimal point is generated: the exponent is adjusted instead. - // - // p2 actually represents the fraction - // - // p2 * 2^e - // = p2 / 2^-e - // = d[-1] / 10^1 + d[-2] / 10^2 + ... - // - // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...) - // - // p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m - // + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...) - // - // using - // - // 10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e) - // = ( d) * 2^-e + ( r) - // - // or - // 10^m * p2 * 2^e = d + r * 2^e - // - // i.e. - // - // M+ = buffer + p2 * 2^e - // = buffer + 10^-m * (d + r * 2^e) - // = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e - // - // and stop as soon as 10^-m * r * 2^e <= delta * 2^e - - JSON_ASSERT(p2 > delta); - - int m = 0; - for (;;) - { - // Invariant: - // M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e - // = buffer * 10^-m + 10^-m * (p2 ) * 2^e - // = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e - // = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e - // - JSON_ASSERT(p2 <= (std::numeric_limits::max)() / 10); - p2 *= 10; - const std::uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e - const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e - // - // M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e - // = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e)) - // = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e - // - JSON_ASSERT(d <= 9); - buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d - // - // M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e - // - p2 = r; - m++; - // - // M+ = buffer * 10^-m + 10^-m * p2 * 2^e - // Invariant restored. - - // Check if enough digits have been generated. - // - // 10^-m * p2 * 2^e <= delta * 2^e - // p2 * 2^e <= 10^m * delta * 2^e - // p2 <= 10^m * delta - delta *= 10; - dist *= 10; - if (p2 <= delta) - { - break; - } - } - - // V = buffer * 10^-m, with M- <= V <= M+. - - decimal_exponent -= m; - - // 1 ulp in the decimal representation is now 10^-m. - // Since delta and dist are now scaled by 10^m, we need to do the - // same with ulp in order to keep the units in sync. - // - // 10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e - // - const std::uint64_t ten_m = one.f; - grisu2_round(buffer, length, dist, delta, p2, ten_m); - - // By construction this algorithm generates the shortest possible decimal - // number (Loitsch, Theorem 6.2) which rounds back to w. - // For an input number of precision p, at least - // - // N = 1 + ceil(p * log_10(2)) - // - // decimal digits are sufficient to identify all binary floating-point - // numbers (Matula, "In-and-Out conversions"). - // This implies that the algorithm does not produce more than N decimal - // digits. - // - // N = 17 for p = 53 (IEEE double precision) - // N = 9 for p = 24 (IEEE single precision) -} - -/*! -v = buf * 10^decimal_exponent -len is the length of the buffer (number of decimal digits) -The buffer must be large enough, i.e. >= max_digits10. -*/ -JSON_HEDLEY_NON_NULL(1) -inline void grisu2(char* buf, int& len, int& decimal_exponent, - diyfp m_minus, diyfp v, diyfp m_plus) -{ - JSON_ASSERT(m_plus.e == m_minus.e); - JSON_ASSERT(m_plus.e == v.e); - - // --------(-----------------------+-----------------------)-------- (A) - // m- v m+ - // - // --------------------(-----------+-----------------------)-------- (B) - // m- v m+ - // - // First scale v (and m- and m+) such that the exponent is in the range - // [alpha, gamma]. - - const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e); - - const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k - - // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma] - const diyfp w = diyfp::mul(v, c_minus_k); - const diyfp w_minus = diyfp::mul(m_minus, c_minus_k); - const diyfp w_plus = diyfp::mul(m_plus, c_minus_k); - - // ----(---+---)---------------(---+---)---------------(---+---)---- - // w- w w+ - // = c*m- = c*v = c*m+ - // - // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and - // w+ are now off by a small amount. - // In fact: - // - // w - v * 10^k < 1 ulp - // - // To account for this inaccuracy, add resp. subtract 1 ulp. - // - // --------+---[---------------(---+---)---------------]---+-------- - // w- M- w M+ w+ - // - // Now any number in [M-, M+] (bounds included) will round to w when input, - // regardless of how the input rounding algorithm breaks ties. - // - // And digit_gen generates the shortest possible such number in [M-, M+]. - // Note that this does not mean that Grisu2 always generates the shortest - // possible number in the interval (m-, m+). - const diyfp M_minus(w_minus.f + 1, w_minus.e); - const diyfp M_plus (w_plus.f - 1, w_plus.e ); - - decimal_exponent = -cached.k; // = -(-k) = k - - grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus); -} - -/*! -v = buf * 10^decimal_exponent -len is the length of the buffer (number of decimal digits) -The buffer must be large enough, i.e. >= max_digits10. -*/ -template -JSON_HEDLEY_NON_NULL(1) -void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value) -{ - static_assert(diyfp::kPrecision >= std::numeric_limits::digits + 3, - "internal error: not enough precision"); - - JSON_ASSERT(std::isfinite(value)); - JSON_ASSERT(value > 0); - - // If the neighbors (and boundaries) of 'value' are always computed for double-precision - // numbers, all float's can be recovered using strtod (and strtof). However, the resulting - // decimal representations are not exactly "short". - // - // The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars) - // says "value is converted to a string as if by std::sprintf in the default ("C") locale" - // and since sprintf promotes floats to doubles, I think this is exactly what 'std::to_chars' - // does. - // On the other hand, the documentation for 'std::to_chars' requires that "parsing the - // representation using the corresponding std::from_chars function recovers value exactly". That - // indicates that single precision floating-point numbers should be recovered using - // 'std::strtof'. - // - // NB: If the neighbors are computed for single-precision numbers, there is a single float - // (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision - // value is off by 1 ulp. -#if 0 - const boundaries w = compute_boundaries(static_cast(value)); -#else - const boundaries w = compute_boundaries(value); -#endif - - grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus); -} - -/*! -@brief appends a decimal representation of e to buf -@return a pointer to the element following the exponent. -@pre -1000 < e < 1000 -*/ -JSON_HEDLEY_NON_NULL(1) -JSON_HEDLEY_RETURNS_NON_NULL -inline char* append_exponent(char* buf, int e) -{ - JSON_ASSERT(e > -1000); - JSON_ASSERT(e < 1000); - - if (e < 0) - { - e = -e; - *buf++ = '-'; - } - else - { - *buf++ = '+'; - } - - auto k = static_cast(e); - if (k < 10) - { - // Always print at least two digits in the exponent. - // This is for compatibility with printf("%g"). - *buf++ = '0'; - *buf++ = static_cast('0' + k); - } - else if (k < 100) - { - *buf++ = static_cast('0' + k / 10); - k %= 10; - *buf++ = static_cast('0' + k); - } - else - { - *buf++ = static_cast('0' + k / 100); - k %= 100; - *buf++ = static_cast('0' + k / 10); - k %= 10; - *buf++ = static_cast('0' + k); - } - - return buf; -} - -/*! -@brief prettify v = buf * 10^decimal_exponent - -If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point -notation. Otherwise it will be printed in exponential notation. - -@pre min_exp < 0 -@pre max_exp > 0 -*/ -JSON_HEDLEY_NON_NULL(1) -JSON_HEDLEY_RETURNS_NON_NULL -inline char* format_buffer(char* buf, int len, int decimal_exponent, - int min_exp, int max_exp) -{ - JSON_ASSERT(min_exp < 0); - JSON_ASSERT(max_exp > 0); - - const int k = len; - const int n = len + decimal_exponent; - - // v = buf * 10^(n-k) - // k is the length of the buffer (number of decimal digits) - // n is the position of the decimal point relative to the start of the buffer. - - if (k <= n && n <= max_exp) - { - // digits[000] - // len <= max_exp + 2 - - std::memset(buf + k, '0', static_cast(n) - static_cast(k)); - // Make it look like a floating-point number (#362, #378) - buf[n + 0] = '.'; - buf[n + 1] = '0'; - return buf + (static_cast(n) + 2); - } - - if (0 < n && n <= max_exp) - { - // dig.its - // len <= max_digits10 + 1 - - JSON_ASSERT(k > n); - - std::memmove(buf + (static_cast(n) + 1), buf + n, static_cast(k) - static_cast(n)); - buf[n] = '.'; - return buf + (static_cast(k) + 1U); - } - - if (min_exp < n && n <= 0) - { - // 0.[000]digits - // len <= 2 + (-min_exp - 1) + max_digits10 - - std::memmove(buf + (2 + static_cast(-n)), buf, static_cast(k)); - buf[0] = '0'; - buf[1] = '.'; - std::memset(buf + 2, '0', static_cast(-n)); - return buf + (2U + static_cast(-n) + static_cast(k)); - } - - if (k == 1) - { - // dE+123 - // len <= 1 + 5 - - buf += 1; - } - else - { - // d.igitsE+123 - // len <= max_digits10 + 1 + 5 - - std::memmove(buf + 2, buf + 1, static_cast(k) - 1); - buf[1] = '.'; - buf += 1 + static_cast(k); - } - - *buf++ = 'e'; - return append_exponent(buf, n - 1); -} - -} // namespace dtoa_impl - -/*! -@brief generates a decimal representation of the floating-point number value in [first, last). - -The format of the resulting decimal representation is similar to printf's %g -format. Returns an iterator pointing past-the-end of the decimal representation. - -@note The input number must be finite, i.e. NaN's and Inf's are not supported. -@note The buffer must be large enough. -@note The result is NOT null-terminated. -*/ -template -JSON_HEDLEY_NON_NULL(1, 2) -JSON_HEDLEY_RETURNS_NON_NULL -char* to_chars(char* first, const char* last, FloatType value) -{ - static_cast(last); // maybe unused - fix warning - JSON_ASSERT(std::isfinite(value)); - - // Use signbit(value) instead of (value < 0) since signbit works for -0. - if (std::signbit(value)) - { - value = -value; - *first++ = '-'; - } - -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wfloat-equal" -#endif - if (value == 0) // +-0 - { - *first++ = '0'; - // Make it look like a floating-point number (#362, #378) - *first++ = '.'; - *first++ = '0'; - return first; - } -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif - - JSON_ASSERT(last - first >= std::numeric_limits::max_digits10); - - // Compute v = buffer * 10^decimal_exponent. - // The decimal digits are stored in the buffer, which needs to be interpreted - // as an unsigned decimal integer. - // len is the length of the buffer, i.e. the number of decimal digits. - int len = 0; - int decimal_exponent = 0; - dtoa_impl::grisu2(first, len, decimal_exponent, value); - - JSON_ASSERT(len <= std::numeric_limits::max_digits10); - - // Format the buffer like printf("%.*g", prec, value) - constexpr int kMinExp = -4; - // Use digits10 here to increase compatibility with version 2. - constexpr int kMaxExp = std::numeric_limits::digits10; - - JSON_ASSERT(last - first >= kMaxExp + 2); - JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits::max_digits10); - JSON_ASSERT(last - first >= std::numeric_limits::max_digits10 + 6); - - return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp); -} - -} // namespace detail -} // namespace nlohmann - -// #include - -// #include - -// #include - -// #include - -// #include - -// #include - - -namespace nlohmann -{ -namespace detail -{ -/////////////////// -// serialization // -/////////////////// - -/// how to treat decoding errors -enum class error_handler_t -{ - strict, ///< throw a type_error exception in case of invalid UTF-8 - replace, ///< replace invalid UTF-8 sequences with U+FFFD - ignore ///< ignore invalid UTF-8 sequences -}; - -template -class serializer -{ - using string_t = typename BasicJsonType::string_t; - using number_float_t = typename BasicJsonType::number_float_t; - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using binary_char_t = typename BasicJsonType::binary_t::value_type; - static constexpr std::uint8_t UTF8_ACCEPT = 0; - static constexpr std::uint8_t UTF8_REJECT = 1; - - public: - /*! - @param[in] s output stream to serialize to - @param[in] ichar indentation character to use - @param[in] error_handler_ how to react on decoding errors - */ - serializer(output_adapter_t s, const char ichar, - error_handler_t error_handler_ = error_handler_t::strict) - : o(std::move(s)) - , loc(std::localeconv()) - , thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits::to_char_type(* (loc->thousands_sep))) - , decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits::to_char_type(* (loc->decimal_point))) - , indent_char(ichar) - , indent_string(512, indent_char) - , error_handler(error_handler_) - {} - - // delete because of pointer members - serializer(const serializer&) = delete; - serializer& operator=(const serializer&) = delete; - serializer(serializer&&) = delete; - serializer& operator=(serializer&&) = delete; - ~serializer() = default; - - /*! - @brief internal implementation of the serialization function - - This function is called by the public member function dump and organizes - the serialization internally. The indentation level is propagated as - additional parameter. In case of arrays and objects, the function is - called recursively. - - - strings and object keys are escaped using `escape_string()` - - integer numbers are converted implicitly via `operator<<` - - floating-point numbers are converted to a string using `"%g"` format - - binary values are serialized as objects containing the subtype and the - byte array - - @param[in] val value to serialize - @param[in] pretty_print whether the output shall be pretty-printed - @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters - in the output are escaped with `\uXXXX` sequences, and the result consists - of ASCII characters only. - @param[in] indent_step the indent level - @param[in] current_indent the current indent level (only used internally) - */ - void dump(const BasicJsonType& val, - const bool pretty_print, - const bool ensure_ascii, - const unsigned int indent_step, - const unsigned int current_indent = 0) - { - switch (val.m_type) - { - case value_t::object: - { - if (val.m_value.object->empty()) - { - o->write_characters("{}", 2); - return; - } - - if (pretty_print) - { - o->write_characters("{\n", 2); - - // variable to hold indentation for recursive calls - const auto new_indent = current_indent + indent_step; - if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) - { - indent_string.resize(indent_string.size() * 2, ' '); - } - - // first n-1 elements - auto i = val.m_value.object->cbegin(); - for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) - { - o->write_characters(indent_string.c_str(), new_indent); - o->write_character('\"'); - dump_escaped(i->first, ensure_ascii); - o->write_characters("\": ", 3); - dump(i->second, true, ensure_ascii, indent_step, new_indent); - o->write_characters(",\n", 2); - } - - // last element - JSON_ASSERT(i != val.m_value.object->cend()); - JSON_ASSERT(std::next(i) == val.m_value.object->cend()); - o->write_characters(indent_string.c_str(), new_indent); - o->write_character('\"'); - dump_escaped(i->first, ensure_ascii); - o->write_characters("\": ", 3); - dump(i->second, true, ensure_ascii, indent_step, new_indent); - - o->write_character('\n'); - o->write_characters(indent_string.c_str(), current_indent); - o->write_character('}'); - } - else - { - o->write_character('{'); - - // first n-1 elements - auto i = val.m_value.object->cbegin(); - for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) - { - o->write_character('\"'); - dump_escaped(i->first, ensure_ascii); - o->write_characters("\":", 2); - dump(i->second, false, ensure_ascii, indent_step, current_indent); - o->write_character(','); - } - - // last element - JSON_ASSERT(i != val.m_value.object->cend()); - JSON_ASSERT(std::next(i) == val.m_value.object->cend()); - o->write_character('\"'); - dump_escaped(i->first, ensure_ascii); - o->write_characters("\":", 2); - dump(i->second, false, ensure_ascii, indent_step, current_indent); - - o->write_character('}'); - } - - return; - } - - case value_t::array: - { - if (val.m_value.array->empty()) - { - o->write_characters("[]", 2); - return; - } - - if (pretty_print) - { - o->write_characters("[\n", 2); - - // variable to hold indentation for recursive calls - const auto new_indent = current_indent + indent_step; - if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) - { - indent_string.resize(indent_string.size() * 2, ' '); - } - - // first n-1 elements - for (auto i = val.m_value.array->cbegin(); - i != val.m_value.array->cend() - 1; ++i) - { - o->write_characters(indent_string.c_str(), new_indent); - dump(*i, true, ensure_ascii, indent_step, new_indent); - o->write_characters(",\n", 2); - } - - // last element - JSON_ASSERT(!val.m_value.array->empty()); - o->write_characters(indent_string.c_str(), new_indent); - dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); - - o->write_character('\n'); - o->write_characters(indent_string.c_str(), current_indent); - o->write_character(']'); - } - else - { - o->write_character('['); - - // first n-1 elements - for (auto i = val.m_value.array->cbegin(); - i != val.m_value.array->cend() - 1; ++i) - { - dump(*i, false, ensure_ascii, indent_step, current_indent); - o->write_character(','); - } - - // last element - JSON_ASSERT(!val.m_value.array->empty()); - dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); - - o->write_character(']'); - } - - return; - } - - case value_t::string: - { - o->write_character('\"'); - dump_escaped(*val.m_value.string, ensure_ascii); - o->write_character('\"'); - return; - } - - case value_t::binary: - { - if (pretty_print) - { - o->write_characters("{\n", 2); - - // variable to hold indentation for recursive calls - const auto new_indent = current_indent + indent_step; - if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) - { - indent_string.resize(indent_string.size() * 2, ' '); - } - - o->write_characters(indent_string.c_str(), new_indent); - - o->write_characters("\"bytes\": [", 10); - - if (!val.m_value.binary->empty()) - { - for (auto i = val.m_value.binary->cbegin(); - i != val.m_value.binary->cend() - 1; ++i) - { - dump_integer(*i); - o->write_characters(", ", 2); - } - dump_integer(val.m_value.binary->back()); - } - - o->write_characters("],\n", 3); - o->write_characters(indent_string.c_str(), new_indent); - - o->write_characters("\"subtype\": ", 11); - if (val.m_value.binary->has_subtype()) - { - dump_integer(val.m_value.binary->subtype()); - } - else - { - o->write_characters("null", 4); - } - o->write_character('\n'); - o->write_characters(indent_string.c_str(), current_indent); - o->write_character('}'); - } - else - { - o->write_characters("{\"bytes\":[", 10); - - if (!val.m_value.binary->empty()) - { - for (auto i = val.m_value.binary->cbegin(); - i != val.m_value.binary->cend() - 1; ++i) - { - dump_integer(*i); - o->write_character(','); - } - dump_integer(val.m_value.binary->back()); - } - - o->write_characters("],\"subtype\":", 12); - if (val.m_value.binary->has_subtype()) - { - dump_integer(val.m_value.binary->subtype()); - o->write_character('}'); - } - else - { - o->write_characters("null}", 5); - } - } - return; - } - - case value_t::boolean: - { - if (val.m_value.boolean) - { - o->write_characters("true", 4); - } - else - { - o->write_characters("false", 5); - } - return; - } - - case value_t::number_integer: - { - dump_integer(val.m_value.number_integer); - return; - } - - case value_t::number_unsigned: - { - dump_integer(val.m_value.number_unsigned); - return; - } - - case value_t::number_float: - { - dump_float(val.m_value.number_float); - return; - } - - case value_t::discarded: - { - o->write_characters("", 11); - return; - } - - case value_t::null: - { - o->write_characters("null", 4); - return; - } - - default: // LCOV_EXCL_LINE - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE - } - } - - JSON_PRIVATE_UNLESS_TESTED: - /*! - @brief dump escaped string - - Escape a string by replacing certain special characters by a sequence of an - escape character (backslash) and another character and other control - characters by a sequence of "\u" followed by a four-digit hex - representation. The escaped string is written to output stream @a o. - - @param[in] s the string to escape - @param[in] ensure_ascii whether to escape non-ASCII characters with - \uXXXX sequences - - @complexity Linear in the length of string @a s. - */ - void dump_escaped(const string_t& s, const bool ensure_ascii) - { - std::uint32_t codepoint{}; - std::uint8_t state = UTF8_ACCEPT; - std::size_t bytes = 0; // number of bytes written to string_buffer - - // number of bytes written at the point of the last valid byte - std::size_t bytes_after_last_accept = 0; - std::size_t undumped_chars = 0; - - for (std::size_t i = 0; i < s.size(); ++i) - { - const auto byte = static_cast(s[i]); - - switch (decode(state, codepoint, byte)) - { - case UTF8_ACCEPT: // decode found a new code point - { - switch (codepoint) - { - case 0x08: // backspace - { - string_buffer[bytes++] = '\\'; - string_buffer[bytes++] = 'b'; - break; - } - - case 0x09: // horizontal tab - { - string_buffer[bytes++] = '\\'; - string_buffer[bytes++] = 't'; - break; - } - - case 0x0A: // newline - { - string_buffer[bytes++] = '\\'; - string_buffer[bytes++] = 'n'; - break; - } - - case 0x0C: // formfeed - { - string_buffer[bytes++] = '\\'; - string_buffer[bytes++] = 'f'; - break; - } - - case 0x0D: // carriage return - { - string_buffer[bytes++] = '\\'; - string_buffer[bytes++] = 'r'; - break; - } - - case 0x22: // quotation mark - { - string_buffer[bytes++] = '\\'; - string_buffer[bytes++] = '\"'; - break; - } - - case 0x5C: // reverse solidus - { - string_buffer[bytes++] = '\\'; - string_buffer[bytes++] = '\\'; - break; - } - - default: - { - // escape control characters (0x00..0x1F) or, if - // ensure_ascii parameter is used, non-ASCII characters - if ((codepoint <= 0x1F) || (ensure_ascii && (codepoint >= 0x7F))) - { - if (codepoint <= 0xFFFF) - { - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) - static_cast((std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x", - static_cast(codepoint))); - bytes += 6; - } - else - { - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) - static_cast((std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x", - static_cast(0xD7C0u + (codepoint >> 10u)), - static_cast(0xDC00u + (codepoint & 0x3FFu)))); - bytes += 12; - } - } - else - { - // copy byte to buffer (all previous bytes - // been copied have in default case above) - string_buffer[bytes++] = s[i]; - } - break; - } - } - - // write buffer and reset index; there must be 13 bytes - // left, as this is the maximal number of bytes to be - // written ("\uxxxx\uxxxx\0") for one code point - if (string_buffer.size() - bytes < 13) - { - o->write_characters(string_buffer.data(), bytes); - bytes = 0; - } - - // remember the byte position of this accept - bytes_after_last_accept = bytes; - undumped_chars = 0; - break; - } - - case UTF8_REJECT: // decode found invalid UTF-8 byte - { - switch (error_handler) - { - case error_handler_t::strict: - { - JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + hex_bytes(byte | 0), BasicJsonType())); - } - - case error_handler_t::ignore: - case error_handler_t::replace: - { - // in case we saw this character the first time, we - // would like to read it again, because the byte - // may be OK for itself, but just not OK for the - // previous sequence - if (undumped_chars > 0) - { - --i; - } - - // reset length buffer to the last accepted index; - // thus removing/ignoring the invalid characters - bytes = bytes_after_last_accept; - - if (error_handler == error_handler_t::replace) - { - // add a replacement character - if (ensure_ascii) - { - string_buffer[bytes++] = '\\'; - string_buffer[bytes++] = 'u'; - string_buffer[bytes++] = 'f'; - string_buffer[bytes++] = 'f'; - string_buffer[bytes++] = 'f'; - string_buffer[bytes++] = 'd'; - } - else - { - string_buffer[bytes++] = detail::binary_writer::to_char_type('\xEF'); - string_buffer[bytes++] = detail::binary_writer::to_char_type('\xBF'); - string_buffer[bytes++] = detail::binary_writer::to_char_type('\xBD'); - } - - // write buffer and reset index; there must be 13 bytes - // left, as this is the maximal number of bytes to be - // written ("\uxxxx\uxxxx\0") for one code point - if (string_buffer.size() - bytes < 13) - { - o->write_characters(string_buffer.data(), bytes); - bytes = 0; - } - - bytes_after_last_accept = bytes; - } - - undumped_chars = 0; - - // continue processing the string - state = UTF8_ACCEPT; - break; - } - - default: // LCOV_EXCL_LINE - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE - } - break; - } - - default: // decode found yet incomplete multi-byte code point - { - if (!ensure_ascii) - { - // code point will not be escaped - copy byte to buffer - string_buffer[bytes++] = s[i]; - } - ++undumped_chars; - break; - } - } - } - - // we finished processing the string - if (JSON_HEDLEY_LIKELY(state == UTF8_ACCEPT)) - { - // write buffer - if (bytes > 0) - { - o->write_characters(string_buffer.data(), bytes); - } - } - else - { - // we finish reading, but do not accept: string was incomplete - switch (error_handler) - { - case error_handler_t::strict: - { - JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + hex_bytes(static_cast(s.back() | 0)), BasicJsonType())); - } - - case error_handler_t::ignore: - { - // write all accepted bytes - o->write_characters(string_buffer.data(), bytes_after_last_accept); - break; - } - - case error_handler_t::replace: - { - // write all accepted bytes - o->write_characters(string_buffer.data(), bytes_after_last_accept); - // add a replacement character - if (ensure_ascii) - { - o->write_characters("\\ufffd", 6); - } - else - { - o->write_characters("\xEF\xBF\xBD", 3); - } - break; - } - - default: // LCOV_EXCL_LINE - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE - } - } - } - - private: - /*! - @brief count digits - - Count the number of decimal (base 10) digits for an input unsigned integer. - - @param[in] x unsigned integer number to count its digits - @return number of decimal digits - */ - inline unsigned int count_digits(number_unsigned_t x) noexcept - { - unsigned int n_digits = 1; - for (;;) - { - if (x < 10) - { - return n_digits; - } - if (x < 100) - { - return n_digits + 1; - } - if (x < 1000) - { - return n_digits + 2; - } - if (x < 10000) - { - return n_digits + 3; - } - x = x / 10000u; - n_digits += 4; - } - } - - /*! - * @brief convert a byte to a uppercase hex representation - * @param[in] byte byte to represent - * @return representation ("00".."FF") - */ - static std::string hex_bytes(std::uint8_t byte) - { - std::string result = "FF"; - constexpr const char* nibble_to_hex = "0123456789ABCDEF"; - result[0] = nibble_to_hex[byte / 16]; - result[1] = nibble_to_hex[byte % 16]; - return result; - } - - // templates to avoid warnings about useless casts - template ::value, int> = 0> - bool is_negative_number(NumberType x) - { - return x < 0; - } - - template < typename NumberType, enable_if_t ::value, int > = 0 > - bool is_negative_number(NumberType /*unused*/) - { - return false; - } - - /*! - @brief dump an integer - - Dump a given integer to output stream @a o. Works internally with - @a number_buffer. - - @param[in] x integer number (signed or unsigned) to dump - @tparam NumberType either @a number_integer_t or @a number_unsigned_t - */ - template < typename NumberType, detail::enable_if_t < - std::is_integral::value || - std::is_same::value || - std::is_same::value || - std::is_same::value, - int > = 0 > - void dump_integer(NumberType x) - { - static constexpr std::array, 100> digits_to_99 - { - { - {{'0', '0'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, {{'0', '6'}}, {{'0', '7'}}, {{'0', '8'}}, {{'0', '9'}}, - {{'1', '0'}}, {{'1', '1'}}, {{'1', '2'}}, {{'1', '3'}}, {{'1', '4'}}, {{'1', '5'}}, {{'1', '6'}}, {{'1', '7'}}, {{'1', '8'}}, {{'1', '9'}}, - {{'2', '0'}}, {{'2', '1'}}, {{'2', '2'}}, {{'2', '3'}}, {{'2', '4'}}, {{'2', '5'}}, {{'2', '6'}}, {{'2', '7'}}, {{'2', '8'}}, {{'2', '9'}}, - {{'3', '0'}}, {{'3', '1'}}, {{'3', '2'}}, {{'3', '3'}}, {{'3', '4'}}, {{'3', '5'}}, {{'3', '6'}}, {{'3', '7'}}, {{'3', '8'}}, {{'3', '9'}}, - {{'4', '0'}}, {{'4', '1'}}, {{'4', '2'}}, {{'4', '3'}}, {{'4', '4'}}, {{'4', '5'}}, {{'4', '6'}}, {{'4', '7'}}, {{'4', '8'}}, {{'4', '9'}}, - {{'5', '0'}}, {{'5', '1'}}, {{'5', '2'}}, {{'5', '3'}}, {{'5', '4'}}, {{'5', '5'}}, {{'5', '6'}}, {{'5', '7'}}, {{'5', '8'}}, {{'5', '9'}}, - {{'6', '0'}}, {{'6', '1'}}, {{'6', '2'}}, {{'6', '3'}}, {{'6', '4'}}, {{'6', '5'}}, {{'6', '6'}}, {{'6', '7'}}, {{'6', '8'}}, {{'6', '9'}}, - {{'7', '0'}}, {{'7', '1'}}, {{'7', '2'}}, {{'7', '3'}}, {{'7', '4'}}, {{'7', '5'}}, {{'7', '6'}}, {{'7', '7'}}, {{'7', '8'}}, {{'7', '9'}}, - {{'8', '0'}}, {{'8', '1'}}, {{'8', '2'}}, {{'8', '3'}}, {{'8', '4'}}, {{'8', '5'}}, {{'8', '6'}}, {{'8', '7'}}, {{'8', '8'}}, {{'8', '9'}}, - {{'9', '0'}}, {{'9', '1'}}, {{'9', '2'}}, {{'9', '3'}}, {{'9', '4'}}, {{'9', '5'}}, {{'9', '6'}}, {{'9', '7'}}, {{'9', '8'}}, {{'9', '9'}}, - } - }; - - // special case for "0" - if (x == 0) - { - o->write_character('0'); - return; - } - - // use a pointer to fill the buffer - auto buffer_ptr = number_buffer.begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto,cppcoreguidelines-pro-type-vararg,hicpp-vararg) - - number_unsigned_t abs_value; - - unsigned int n_chars{}; - - if (is_negative_number(x)) - { - *buffer_ptr = '-'; - abs_value = remove_sign(static_cast(x)); - - // account one more byte for the minus sign - n_chars = 1 + count_digits(abs_value); - } - else - { - abs_value = static_cast(x); - n_chars = count_digits(abs_value); - } - - // spare 1 byte for '\0' - JSON_ASSERT(n_chars < number_buffer.size() - 1); - - // jump to the end to generate the string from backward, - // so we later avoid reversing the result - buffer_ptr += n_chars; - - // Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu - // See: https://www.youtube.com/watch?v=o4-CwDo2zpg - while (abs_value >= 100) - { - const auto digits_index = static_cast((abs_value % 100)); - abs_value /= 100; - *(--buffer_ptr) = digits_to_99[digits_index][1]; - *(--buffer_ptr) = digits_to_99[digits_index][0]; - } - - if (abs_value >= 10) - { - const auto digits_index = static_cast(abs_value); - *(--buffer_ptr) = digits_to_99[digits_index][1]; - *(--buffer_ptr) = digits_to_99[digits_index][0]; - } - else - { - *(--buffer_ptr) = static_cast('0' + abs_value); - } - - o->write_characters(number_buffer.data(), n_chars); - } - - /*! - @brief dump a floating-point number - - Dump a given floating-point number to output stream @a o. Works internally - with @a number_buffer. - - @param[in] x floating-point number to dump - */ - void dump_float(number_float_t x) - { - // NaN / inf - if (!std::isfinite(x)) - { - o->write_characters("null", 4); - return; - } - - // If number_float_t is an IEEE-754 single or double precision number, - // use the Grisu2 algorithm to produce short numbers which are - // guaranteed to round-trip, using strtof and strtod, resp. - // - // NB: The test below works if == . - static constexpr bool is_ieee_single_or_double - = (std::numeric_limits::is_iec559 && std::numeric_limits::digits == 24 && std::numeric_limits::max_exponent == 128) || - (std::numeric_limits::is_iec559 && std::numeric_limits::digits == 53 && std::numeric_limits::max_exponent == 1024); - - dump_float(x, std::integral_constant()); - } - - void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/) - { - auto* begin = number_buffer.data(); - auto* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x); - - o->write_characters(begin, static_cast(end - begin)); - } - - void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/) - { - // get number of digits for a float -> text -> float round-trip - static constexpr auto d = std::numeric_limits::max_digits10; - - // the actual conversion - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) - std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x); - - // negative value indicates an error - JSON_ASSERT(len > 0); - // check if buffer was large enough - JSON_ASSERT(static_cast(len) < number_buffer.size()); - - // erase thousands separator - if (thousands_sep != '\0') - { - // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::remove returns an iterator, see https://github.com/nlohmann/json/issues/3081 - const auto end = std::remove(number_buffer.begin(), number_buffer.begin() + len, thousands_sep); - std::fill(end, number_buffer.end(), '\0'); - JSON_ASSERT((end - number_buffer.begin()) <= len); - len = (end - number_buffer.begin()); - } - - // convert decimal point to '.' - if (decimal_point != '\0' && decimal_point != '.') - { - // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::find returns an iterator, see https://github.com/nlohmann/json/issues/3081 - const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point); - if (dec_pos != number_buffer.end()) - { - *dec_pos = '.'; - } - } - - o->write_characters(number_buffer.data(), static_cast(len)); - - // determine if we need to append ".0" - const bool value_is_int_like = - std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1, - [](char c) - { - return c == '.' || c == 'e'; - }); - - if (value_is_int_like) - { - o->write_characters(".0", 2); - } - } - - /*! - @brief check whether a string is UTF-8 encoded - - The function checks each byte of a string whether it is UTF-8 encoded. The - result of the check is stored in the @a state parameter. The function must - be called initially with state 0 (accept). State 1 means the string must - be rejected, because the current byte is not allowed. If the string is - completely processed, but the state is non-zero, the string ended - prematurely; that is, the last byte indicated more bytes should have - followed. - - @param[in,out] state the state of the decoding - @param[in,out] codep codepoint (valid only if resulting state is UTF8_ACCEPT) - @param[in] byte next byte to decode - @return new state - - @note The function has been edited: a std::array is used. - - @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann - @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ - */ - static std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep, const std::uint8_t byte) noexcept - { - static const std::array utf8d = - { - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF - 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF - 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF - 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF - 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 - 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 - 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 - 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8 - } - }; - - JSON_ASSERT(byte < utf8d.size()); - const std::uint8_t type = utf8d[byte]; - - codep = (state != UTF8_ACCEPT) - ? (byte & 0x3fu) | (codep << 6u) - : (0xFFu >> type) & (byte); - - std::size_t index = 256u + static_cast(state) * 16u + static_cast(type); - JSON_ASSERT(index < 400); - state = utf8d[index]; - return state; - } - - /* - * Overload to make the compiler happy while it is instantiating - * dump_integer for number_unsigned_t. - * Must never be called. - */ - number_unsigned_t remove_sign(number_unsigned_t x) - { - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE - return x; // LCOV_EXCL_LINE - } - - /* - * Helper function for dump_integer - * - * This function takes a negative signed integer and returns its absolute - * value as unsigned integer. The plus/minus shuffling is necessary as we can - * not directly remove the sign of an arbitrary signed integer as the - * absolute values of INT_MIN and INT_MAX are usually not the same. See - * #1708 for details. - */ - inline number_unsigned_t remove_sign(number_integer_t x) noexcept - { - JSON_ASSERT(x < 0 && x < (std::numeric_limits::max)()); // NOLINT(misc-redundant-expression) - return static_cast(-(x + 1)) + 1; - } - - private: - /// the output of the serializer - output_adapter_t o = nullptr; - - /// a (hopefully) large enough character buffer - std::array number_buffer{{}}; - - /// the locale - const std::lconv* loc = nullptr; - /// the locale's thousand separator character - const char thousands_sep = '\0'; - /// the locale's decimal point character - const char decimal_point = '\0'; - - /// string buffer - std::array string_buffer{{}}; - - /// the indentation character - const char indent_char; - /// the indentation string - string_t indent_string; - - /// error_handler how to react on decoding errors - const error_handler_t error_handler; -}; -} // namespace detail -} // namespace nlohmann - -// #include - -// #include - -// #include - - -#include // less -#include // initializer_list -#include // input_iterator_tag, iterator_traits -#include // allocator -#include // for out_of_range -#include // enable_if, is_convertible -#include // pair -#include // vector - -// #include - - -namespace nlohmann -{ - -/// ordered_map: a minimal map-like container that preserves insertion order -/// for use within nlohmann::basic_json -template , - class Allocator = std::allocator>> - struct ordered_map : std::vector, Allocator> -{ - using key_type = Key; - using mapped_type = T; - using Container = std::vector, Allocator>; - using iterator = typename Container::iterator; - using const_iterator = typename Container::const_iterator; - using size_type = typename Container::size_type; - using value_type = typename Container::value_type; - - // Explicit constructors instead of `using Container::Container` - // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4) - ordered_map(const Allocator& alloc = Allocator()) : Container{alloc} {} - template - ordered_map(It first, It last, const Allocator& alloc = Allocator()) - : Container{first, last, alloc} {} - ordered_map(std::initializer_list init, const Allocator& alloc = Allocator() ) - : Container{init, alloc} {} - - std::pair emplace(const key_type& key, T&& t) - { - for (auto it = this->begin(); it != this->end(); ++it) - { - if (it->first == key) - { - return {it, false}; - } - } - Container::emplace_back(key, t); - return {--this->end(), true}; - } - - T& operator[](const Key& key) - { - return emplace(key, T{}).first->second; - } - - const T& operator[](const Key& key) const - { - return at(key); - } - - T& at(const Key& key) - { - for (auto it = this->begin(); it != this->end(); ++it) - { - if (it->first == key) - { - return it->second; - } - } - - JSON_THROW(std::out_of_range("key not found")); - } - - const T& at(const Key& key) const - { - for (auto it = this->begin(); it != this->end(); ++it) - { - if (it->first == key) - { - return it->second; - } - } - - JSON_THROW(std::out_of_range("key not found")); - } - - size_type erase(const Key& key) - { - for (auto it = this->begin(); it != this->end(); ++it) - { - if (it->first == key) - { - // Since we cannot move const Keys, re-construct them in place - for (auto next = it; ++next != this->end(); ++it) - { - it->~value_type(); // Destroy but keep allocation - new (&*it) value_type{std::move(*next)}; - } - Container::pop_back(); - return 1; - } - } - return 0; - } - - iterator erase(iterator pos) - { - return erase(pos, std::next(pos)); - } - - iterator erase(iterator first, iterator last) - { - const auto elements_affected = std::distance(first, last); - const auto offset = std::distance(Container::begin(), first); - - // This is the start situation. We need to delete elements_affected - // elements (3 in this example: e, f, g), and need to return an - // iterator past the last deleted element (h in this example). - // Note that offset is the distance from the start of the vector - // to first. We will need this later. - - // [ a, b, c, d, e, f, g, h, i, j ] - // ^ ^ - // first last - - // Since we cannot move const Keys, we re-construct them in place. - // We start at first and re-construct (viz. copy) the elements from - // the back of the vector. Example for first iteration: - - // ,--------. - // v | destroy e and re-construct with h - // [ a, b, c, d, e, f, g, h, i, j ] - // ^ ^ - // it it + elements_affected - - for (auto it = first; std::next(it, elements_affected) != Container::end(); ++it) - { - it->~value_type(); // destroy but keep allocation - new (&*it) value_type{std::move(*std::next(it, elements_affected))}; // "move" next element to it - } - - // [ a, b, c, d, h, i, j, h, i, j ] - // ^ ^ - // first last - - // remove the unneeded elements at the end of the vector - Container::resize(this->size() - static_cast(elements_affected)); - - // [ a, b, c, d, h, i, j ] - // ^ ^ - // first last - - // first is now pointing past the last deleted element, but we cannot - // use this iterator, because it may have been invalidated by the - // resize call. Instead, we can return begin() + offset. - return Container::begin() + offset; - } - - size_type count(const Key& key) const - { - for (auto it = this->begin(); it != this->end(); ++it) - { - if (it->first == key) - { - return 1; - } - } - return 0; - } - - iterator find(const Key& key) - { - for (auto it = this->begin(); it != this->end(); ++it) - { - if (it->first == key) - { - return it; - } - } - return Container::end(); - } - - const_iterator find(const Key& key) const - { - for (auto it = this->begin(); it != this->end(); ++it) - { - if (it->first == key) - { - return it; - } - } - return Container::end(); - } - - std::pair insert( value_type&& value ) - { - return emplace(value.first, std::move(value.second)); - } - - std::pair insert( const value_type& value ) - { - for (auto it = this->begin(); it != this->end(); ++it) - { - if (it->first == value.first) - { - return {it, false}; - } - } - Container::push_back(value); - return {--this->end(), true}; - } - - template - using require_input_iter = typename std::enable_if::iterator_category, - std::input_iterator_tag>::value>::type; - - template> - void insert(InputIt first, InputIt last) - { - for (auto it = first; it != last; ++it) - { - insert(*it); - } - } -}; - -} // namespace nlohmann - - -#if defined(JSON_HAS_CPP_17) - #include -#endif - -/*! -@brief namespace for Niels Lohmann -@see https://github.com/nlohmann -@since version 1.0.0 -*/ -namespace nlohmann -{ - -/*! -@brief a class to store JSON values - -@internal -@invariant The member variables @a m_value and @a m_type have the following -relationship: -- If `m_type == value_t::object`, then `m_value.object != nullptr`. -- If `m_type == value_t::array`, then `m_value.array != nullptr`. -- If `m_type == value_t::string`, then `m_value.string != nullptr`. -The invariants are checked by member function assert_invariant(). - -@note ObjectType trick from https://stackoverflow.com/a/9860911 -@endinternal - -@since version 1.0.0 - -@nosubgrouping -*/ -NLOHMANN_BASIC_JSON_TPL_DECLARATION -class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) -{ - private: - template friend struct detail::external_constructor; - friend ::nlohmann::json_pointer; - - template - friend class ::nlohmann::detail::parser; - friend ::nlohmann::detail::serializer; - template - friend class ::nlohmann::detail::iter_impl; - template - friend class ::nlohmann::detail::binary_writer; - template - friend class ::nlohmann::detail::binary_reader; - template - friend class ::nlohmann::detail::json_sax_dom_parser; - template - friend class ::nlohmann::detail::json_sax_dom_callback_parser; - friend class ::nlohmann::detail::exception; - - /// workaround type for MSVC - using basic_json_t = NLOHMANN_BASIC_JSON_TPL; - - JSON_PRIVATE_UNLESS_TESTED: - // convenience aliases for types residing in namespace detail; - using lexer = ::nlohmann::detail::lexer_base; - - template - static ::nlohmann::detail::parser parser( - InputAdapterType adapter, - detail::parser_callback_tcb = nullptr, - const bool allow_exceptions = true, - const bool ignore_comments = false - ) - { - return ::nlohmann::detail::parser(std::move(adapter), - std::move(cb), allow_exceptions, ignore_comments); - } - - private: - using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t; - template - using internal_iterator = ::nlohmann::detail::internal_iterator; - template - using iter_impl = ::nlohmann::detail::iter_impl; - template - using iteration_proxy = ::nlohmann::detail::iteration_proxy; - template using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator; - - template - using output_adapter_t = ::nlohmann::detail::output_adapter_t; - - template - using binary_reader = ::nlohmann::detail::binary_reader; - template using binary_writer = ::nlohmann::detail::binary_writer; - - JSON_PRIVATE_UNLESS_TESTED: - using serializer = ::nlohmann::detail::serializer; - - public: - using value_t = detail::value_t; - /// JSON Pointer, see @ref nlohmann::json_pointer - using json_pointer = ::nlohmann::json_pointer; - template - using json_serializer = JSONSerializer; - /// how to treat decoding errors - using error_handler_t = detail::error_handler_t; - /// how to treat CBOR tags - using cbor_tag_handler_t = detail::cbor_tag_handler_t; - /// helper type for initializer lists of basic_json values - using initializer_list_t = std::initializer_list>; - - using input_format_t = detail::input_format_t; - /// SAX interface type, see @ref nlohmann::json_sax - using json_sax_t = json_sax; - - //////////////// - // exceptions // - //////////////// - - /// @name exceptions - /// Classes to implement user-defined exceptions. - /// @{ - - using exception = detail::exception; - using parse_error = detail::parse_error; - using invalid_iterator = detail::invalid_iterator; - using type_error = detail::type_error; - using out_of_range = detail::out_of_range; - using other_error = detail::other_error; - - /// @} - - - ///////////////////// - // container types // - ///////////////////// - - /// @name container types - /// The canonic container types to use @ref basic_json like any other STL - /// container. - /// @{ - - /// the type of elements in a basic_json container - using value_type = basic_json; - - /// the type of an element reference - using reference = value_type&; - /// the type of an element const reference - using const_reference = const value_type&; - - /// a type to represent differences between iterators - using difference_type = std::ptrdiff_t; - /// a type to represent container sizes - using size_type = std::size_t; - - /// the allocator type - using allocator_type = AllocatorType; - - /// the type of an element pointer - using pointer = typename std::allocator_traits::pointer; - /// the type of an element const pointer - using const_pointer = typename std::allocator_traits::const_pointer; - - /// an iterator for a basic_json container - using iterator = iter_impl; - /// a const iterator for a basic_json container - using const_iterator = iter_impl; - /// a reverse iterator for a basic_json container - using reverse_iterator = json_reverse_iterator; - /// a const reverse iterator for a basic_json container - using const_reverse_iterator = json_reverse_iterator; - - /// @} - - - /// @brief returns the allocator associated with the container - /// @sa https://json.nlohmann.me/api/basic_json/get_allocator/ - static allocator_type get_allocator() - { - return allocator_type(); - } - - /// @brief returns version information on the library - /// @sa https://json.nlohmann.me/api/basic_json/meta/ - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json meta() - { - basic_json result; - - result["copyright"] = "(C) 2013-2022 Niels Lohmann"; - result["name"] = "JSON for Modern C++"; - result["url"] = "https://github.com/nlohmann/json"; - result["version"]["string"] = - std::to_string(NLOHMANN_JSON_VERSION_MAJOR) + "." + - std::to_string(NLOHMANN_JSON_VERSION_MINOR) + "." + - std::to_string(NLOHMANN_JSON_VERSION_PATCH); - result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR; - result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR; - result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH; - -#ifdef _WIN32 - result["platform"] = "win32"; -#elif defined __linux__ - result["platform"] = "linux"; -#elif defined __APPLE__ - result["platform"] = "apple"; -#elif defined __unix__ - result["platform"] = "unix"; -#else - result["platform"] = "unknown"; -#endif - -#if defined(__ICC) || defined(__INTEL_COMPILER) - result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}}; -#elif defined(__clang__) - result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}}; -#elif defined(__GNUC__) || defined(__GNUG__) - result["compiler"] = {{"family", "gcc"}, {"version", std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}}; -#elif defined(__HP_cc) || defined(__HP_aCC) - result["compiler"] = "hp" -#elif defined(__IBMCPP__) - result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}}; -#elif defined(_MSC_VER) - result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}}; -#elif defined(__PGI) - result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}}; -#elif defined(__SUNPRO_CC) - result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}}; -#else - result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}}; -#endif - -#ifdef __cplusplus - result["compiler"]["c++"] = std::to_string(__cplusplus); -#else - result["compiler"]["c++"] = "unknown"; -#endif - return result; - } - - - /////////////////////////// - // JSON value data types // - /////////////////////////// - - /// @name JSON value data types - /// The data types to store a JSON value. These types are derived from - /// the template arguments passed to class @ref basic_json. - /// @{ - - /// @brief object key comparator type - /// @sa https://json.nlohmann.me/api/basic_json/object_comparator_t/ -#if defined(JSON_HAS_CPP_14) - // Use transparent comparator if possible, combined with perfect forwarding - // on find() and count() calls prevents unnecessary string construction. - using object_comparator_t = std::less<>; -#else - using object_comparator_t = std::less; -#endif - - /// @brief a type for an object - /// @sa https://json.nlohmann.me/api/basic_json/object_t/ - using object_t = ObjectType>>; - - /// @brief a type for an array - /// @sa https://json.nlohmann.me/api/basic_json/array_t/ - using array_t = ArrayType>; - - /// @brief a type for a string - /// @sa https://json.nlohmann.me/api/basic_json/string_t/ - using string_t = StringType; - - /// @brief a type for a boolean - /// @sa https://json.nlohmann.me/api/basic_json/boolean_t/ - using boolean_t = BooleanType; - - /// @brief a type for a number (integer) - /// @sa https://json.nlohmann.me/api/basic_json/number_integer_t/ - using number_integer_t = NumberIntegerType; - - /// @brief a type for a number (unsigned) - /// @sa https://json.nlohmann.me/api/basic_json/number_unsigned_t/ - using number_unsigned_t = NumberUnsignedType; - - /// @brief a type for a number (floating-point) - /// @sa https://json.nlohmann.me/api/basic_json/number_float_t/ - using number_float_t = NumberFloatType; - - /// @brief a type for a packed binary type - /// @sa https://json.nlohmann.me/api/basic_json/binary_t/ - using binary_t = nlohmann::byte_container_with_subtype; - - /// @} - - private: - - /// helper for exception-safe object creation - template - JSON_HEDLEY_RETURNS_NON_NULL - static T* create(Args&& ... args) - { - AllocatorType alloc; - using AllocatorTraits = std::allocator_traits>; - - auto deleter = [&](T * obj) - { - AllocatorTraits::deallocate(alloc, obj, 1); - }; - std::unique_ptr obj(AllocatorTraits::allocate(alloc, 1), deleter); - AllocatorTraits::construct(alloc, obj.get(), std::forward(args)...); - JSON_ASSERT(obj != nullptr); - return obj.release(); - } - - //////////////////////// - // JSON value storage // - //////////////////////// - - JSON_PRIVATE_UNLESS_TESTED: - /*! - @brief a JSON value - - The actual storage for a JSON value of the @ref basic_json class. This - union combines the different storage types for the JSON value types - defined in @ref value_t. - - JSON type | value_t type | used type - --------- | --------------- | ------------------------ - object | object | pointer to @ref object_t - array | array | pointer to @ref array_t - string | string | pointer to @ref string_t - boolean | boolean | @ref boolean_t - number | number_integer | @ref number_integer_t - number | number_unsigned | @ref number_unsigned_t - number | number_float | @ref number_float_t - binary | binary | pointer to @ref binary_t - null | null | *no value is stored* - - @note Variable-length types (objects, arrays, and strings) are stored as - pointers. The size of the union should not exceed 64 bits if the default - value types are used. - - @since version 1.0.0 - */ - union json_value - { - /// object (stored with pointer to save storage) - object_t* object; - /// array (stored with pointer to save storage) - array_t* array; - /// string (stored with pointer to save storage) - string_t* string; - /// binary (stored with pointer to save storage) - binary_t* binary; - /// boolean - boolean_t boolean; - /// number (integer) - number_integer_t number_integer; - /// number (unsigned integer) - number_unsigned_t number_unsigned; - /// number (floating-point) - number_float_t number_float; - - /// default constructor (for null values) - json_value() = default; - /// constructor for booleans - json_value(boolean_t v) noexcept : boolean(v) {} - /// constructor for numbers (integer) - json_value(number_integer_t v) noexcept : number_integer(v) {} - /// constructor for numbers (unsigned) - json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} - /// constructor for numbers (floating-point) - json_value(number_float_t v) noexcept : number_float(v) {} - /// constructor for empty values of a given type - json_value(value_t t) - { - switch (t) - { - case value_t::object: - { - object = create(); - break; - } - - case value_t::array: - { - array = create(); - break; - } - - case value_t::string: - { - string = create(""); - break; - } - - case value_t::binary: - { - binary = create(); - break; - } - - case value_t::boolean: - { - boolean = static_cast(false); - break; - } - - case value_t::number_integer: - { - number_integer = static_cast(0); - break; - } - - case value_t::number_unsigned: - { - number_unsigned = static_cast(0); - break; - } - - case value_t::number_float: - { - number_float = static_cast(0.0); - break; - } - - case value_t::null: - { - object = nullptr; // silence warning, see #821 - break; - } - - case value_t::discarded: - default: - { - object = nullptr; // silence warning, see #821 - if (JSON_HEDLEY_UNLIKELY(t == value_t::null)) - { - JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.10.5", basic_json())); // LCOV_EXCL_LINE - } - break; - } - } - } - - /// constructor for strings - json_value(const string_t& value) : string(create(value)) {} - - /// constructor for rvalue strings - json_value(string_t&& value) : string(create(std::move(value))) {} - - /// constructor for objects - json_value(const object_t& value) : object(create(value)) {} - - /// constructor for rvalue objects - json_value(object_t&& value) : object(create(std::move(value))) {} - - /// constructor for arrays - json_value(const array_t& value) : array(create(value)) {} - - /// constructor for rvalue arrays - json_value(array_t&& value) : array(create(std::move(value))) {} - - /// constructor for binary arrays - json_value(const typename binary_t::container_type& value) : binary(create(value)) {} - - /// constructor for rvalue binary arrays - json_value(typename binary_t::container_type&& value) : binary(create(std::move(value))) {} - - /// constructor for binary arrays (internal type) - json_value(const binary_t& value) : binary(create(value)) {} - - /// constructor for rvalue binary arrays (internal type) - json_value(binary_t&& value) : binary(create(std::move(value))) {} - - void destroy(value_t t) - { - if (t == value_t::array || t == value_t::object) - { - // flatten the current json_value to a heap-allocated stack - std::vector stack; - - // move the top-level items to stack - if (t == value_t::array) - { - stack.reserve(array->size()); - std::move(array->begin(), array->end(), std::back_inserter(stack)); - } - else - { - stack.reserve(object->size()); - for (auto&& it : *object) - { - stack.push_back(std::move(it.second)); - } - } - - while (!stack.empty()) - { - // move the last item to local variable to be processed - basic_json current_item(std::move(stack.back())); - stack.pop_back(); - - // if current_item is array/object, move - // its children to the stack to be processed later - if (current_item.is_array()) - { - std::move(current_item.m_value.array->begin(), current_item.m_value.array->end(), std::back_inserter(stack)); - - current_item.m_value.array->clear(); - } - else if (current_item.is_object()) - { - for (auto&& it : *current_item.m_value.object) - { - stack.push_back(std::move(it.second)); - } - - current_item.m_value.object->clear(); - } - - // it's now safe that current_item get destructed - // since it doesn't have any children - } - } - - switch (t) - { - case value_t::object: - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, object); - std::allocator_traits::deallocate(alloc, object, 1); - break; - } - - case value_t::array: - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, array); - std::allocator_traits::deallocate(alloc, array, 1); - break; - } - - case value_t::string: - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, string); - std::allocator_traits::deallocate(alloc, string, 1); - break; - } - - case value_t::binary: - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, binary); - std::allocator_traits::deallocate(alloc, binary, 1); - break; - } - - case value_t::null: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::discarded: - default: - { - break; - } - } - } - }; - - private: - /*! - @brief checks the class invariants - - This function asserts the class invariants. It needs to be called at the - end of every constructor to make sure that created objects respect the - invariant. Furthermore, it has to be called each time the type of a JSON - value is changed, because the invariant expresses a relationship between - @a m_type and @a m_value. - - Furthermore, the parent relation is checked for arrays and objects: If - @a check_parents true and the value is an array or object, then the - container's elements must have the current value as parent. - - @param[in] check_parents whether the parent relation should be checked. - The value is true by default and should only be set to false - during destruction of objects when the invariant does not - need to hold. - */ - void assert_invariant(bool check_parents = true) const noexcept - { - JSON_ASSERT(m_type != value_t::object || m_value.object != nullptr); - JSON_ASSERT(m_type != value_t::array || m_value.array != nullptr); - JSON_ASSERT(m_type != value_t::string || m_value.string != nullptr); - JSON_ASSERT(m_type != value_t::binary || m_value.binary != nullptr); - -#if JSON_DIAGNOSTICS - JSON_TRY - { - // cppcheck-suppress assertWithSideEffect - JSON_ASSERT(!check_parents || !is_structured() || std::all_of(begin(), end(), [this](const basic_json & j) - { - return j.m_parent == this; - })); - } - JSON_CATCH(...) {} // LCOV_EXCL_LINE -#endif - static_cast(check_parents); - } - - void set_parents() - { -#if JSON_DIAGNOSTICS - switch (m_type) - { - case value_t::array: - { - for (auto& element : *m_value.array) - { - element.m_parent = this; - } - break; - } - - case value_t::object: - { - for (auto& element : *m_value.object) - { - element.second.m_parent = this; - } - break; - } - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - break; - } -#endif - } - - iterator set_parents(iterator it, typename iterator::difference_type count_set_parents) - { -#if JSON_DIAGNOSTICS - for (typename iterator::difference_type i = 0; i < count_set_parents; ++i) - { - (it + i)->m_parent = this; - } -#else - static_cast(count_set_parents); -#endif - return it; - } - - reference set_parent(reference j, std::size_t old_capacity = static_cast(-1)) - { -#if JSON_DIAGNOSTICS - if (old_capacity != static_cast(-1)) - { - // see https://github.com/nlohmann/json/issues/2838 - JSON_ASSERT(type() == value_t::array); - if (JSON_HEDLEY_UNLIKELY(m_value.array->capacity() != old_capacity)) - { - // capacity has changed: update all parents - set_parents(); - return j; - } - } - - // ordered_json uses a vector internally, so pointers could have - // been invalidated; see https://github.com/nlohmann/json/issues/2962 -#ifdef JSON_HEDLEY_MSVC_VERSION -#pragma warning(push ) -#pragma warning(disable : 4127) // ignore warning to replace if with if constexpr -#endif - if (detail::is_ordered_map::value) - { - set_parents(); - return j; - } -#ifdef JSON_HEDLEY_MSVC_VERSION -#pragma warning( pop ) -#endif - - j.m_parent = this; -#else - static_cast(j); - static_cast(old_capacity); -#endif - return j; - } - - public: - ////////////////////////// - // JSON parser callback // - ////////////////////////// - - /// @brief parser event types - /// @sa https://json.nlohmann.me/api/basic_json/parse_event_t/ - using parse_event_t = detail::parse_event_t; - - /// @brief per-element parser callback type - /// @sa https://json.nlohmann.me/api/basic_json/parser_callback_t/ - using parser_callback_t = detail::parser_callback_t; - - ////////////////// - // constructors // - ////////////////// - - /// @name constructors and destructors - /// Constructors of class @ref basic_json, copy/move constructor, copy - /// assignment, static functions creating objects, and the destructor. - /// @{ - - /// @brief create an empty value with a given type - /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ - basic_json(const value_t v) - : m_type(v), m_value(v) - { - assert_invariant(); - } - - /// @brief create a null object - /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ - basic_json(std::nullptr_t = nullptr) noexcept - : basic_json(value_t::null) - { - assert_invariant(); - } - - /// @brief create a JSON value from compatible types - /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ - template < typename CompatibleType, - typename U = detail::uncvref_t, - detail::enable_if_t < - !detail::is_basic_json::value && detail::is_compatible_type::value, int > = 0 > - basic_json(CompatibleType && val) noexcept(noexcept( // NOLINT(bugprone-forwarding-reference-overload,bugprone-exception-escape) - JSONSerializer::to_json(std::declval(), - std::forward(val)))) - { - JSONSerializer::to_json(*this, std::forward(val)); - set_parents(); - assert_invariant(); - } - - /// @brief create a JSON value from an existing one - /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ - template < typename BasicJsonType, - detail::enable_if_t < - detail::is_basic_json::value&& !std::is_same::value, int > = 0 > - basic_json(const BasicJsonType& val) - { - using other_boolean_t = typename BasicJsonType::boolean_t; - using other_number_float_t = typename BasicJsonType::number_float_t; - using other_number_integer_t = typename BasicJsonType::number_integer_t; - using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using other_string_t = typename BasicJsonType::string_t; - using other_object_t = typename BasicJsonType::object_t; - using other_array_t = typename BasicJsonType::array_t; - using other_binary_t = typename BasicJsonType::binary_t; - - switch (val.type()) - { - case value_t::boolean: - JSONSerializer::to_json(*this, val.template get()); - break; - case value_t::number_float: - JSONSerializer::to_json(*this, val.template get()); - break; - case value_t::number_integer: - JSONSerializer::to_json(*this, val.template get()); - break; - case value_t::number_unsigned: - JSONSerializer::to_json(*this, val.template get()); - break; - case value_t::string: - JSONSerializer::to_json(*this, val.template get_ref()); - break; - case value_t::object: - JSONSerializer::to_json(*this, val.template get_ref()); - break; - case value_t::array: - JSONSerializer::to_json(*this, val.template get_ref()); - break; - case value_t::binary: - JSONSerializer::to_json(*this, val.template get_ref()); - break; - case value_t::null: - *this = nullptr; - break; - case value_t::discarded: - m_type = value_t::discarded; - break; - default: // LCOV_EXCL_LINE - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE - } - set_parents(); - assert_invariant(); - } - - /// @brief create a container (array or object) from an initializer list - /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ - basic_json(initializer_list_t init, - bool type_deduction = true, - value_t manual_type = value_t::array) - { - // check if each element is an array with two elements whose first - // element is a string - bool is_an_object = std::all_of(init.begin(), init.end(), - [](const detail::json_ref& element_ref) - { - return element_ref->is_array() && element_ref->size() == 2 && (*element_ref)[0].is_string(); - }); - - // adjust type if type deduction is not wanted - if (!type_deduction) - { - // if array is wanted, do not create an object though possible - if (manual_type == value_t::array) - { - is_an_object = false; - } - - // if object is wanted but impossible, throw an exception - if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object)) - { - JSON_THROW(type_error::create(301, "cannot create object from initializer list", basic_json())); - } - } - - if (is_an_object) - { - // the initializer list is a list of pairs -> create object - m_type = value_t::object; - m_value = value_t::object; - - for (auto& element_ref : init) - { - auto element = element_ref.moved_or_copied(); - m_value.object->emplace( - std::move(*((*element.m_value.array)[0].m_value.string)), - std::move((*element.m_value.array)[1])); - } - } - else - { - // the initializer list describes an array -> create array - m_type = value_t::array; - m_value.array = create(init.begin(), init.end()); - } - - set_parents(); - assert_invariant(); - } - - /// @brief explicitly create a binary array (without subtype) - /// @sa https://json.nlohmann.me/api/basic_json/binary/ - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary(const typename binary_t::container_type& init) - { - auto res = basic_json(); - res.m_type = value_t::binary; - res.m_value = init; - return res; - } - - /// @brief explicitly create a binary array (with subtype) - /// @sa https://json.nlohmann.me/api/basic_json/binary/ - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype) - { - auto res = basic_json(); - res.m_type = value_t::binary; - res.m_value = binary_t(init, subtype); - return res; - } - - /// @brief explicitly create a binary array - /// @sa https://json.nlohmann.me/api/basic_json/binary/ - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary(typename binary_t::container_type&& init) - { - auto res = basic_json(); - res.m_type = value_t::binary; - res.m_value = std::move(init); - return res; - } - - /// @brief explicitly create a binary array (with subtype) - /// @sa https://json.nlohmann.me/api/basic_json/binary/ - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype) - { - auto res = basic_json(); - res.m_type = value_t::binary; - res.m_value = binary_t(std::move(init), subtype); - return res; - } - - /// @brief explicitly create an array from an initializer list - /// @sa https://json.nlohmann.me/api/basic_json/array/ - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json array(initializer_list_t init = {}) - { - return basic_json(init, false, value_t::array); - } - - /// @brief explicitly create an object from an initializer list - /// @sa https://json.nlohmann.me/api/basic_json/object/ - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json object(initializer_list_t init = {}) - { - return basic_json(init, false, value_t::object); - } - - /// @brief construct an array with count copies of given value - /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ - basic_json(size_type cnt, const basic_json& val) - : m_type(value_t::array) - { - m_value.array = create(cnt, val); - set_parents(); - assert_invariant(); - } - - /// @brief construct a JSON container given an iterator range - /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ - template < class InputIT, typename std::enable_if < - std::is_same::value || - std::is_same::value, int >::type = 0 > - basic_json(InputIT first, InputIT last) - { - JSON_ASSERT(first.m_object != nullptr); - JSON_ASSERT(last.m_object != nullptr); - - // make sure iterator fits the current value - if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) - { - JSON_THROW(invalid_iterator::create(201, "iterators are not compatible", basic_json())); - } - - // copy type from first iterator - m_type = first.m_object->m_type; - - // check if iterator range is complete for primitive values - switch (m_type) - { - case value_t::boolean: - case value_t::number_float: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::string: - { - if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin() - || !last.m_it.primitive_iterator.is_end())) - { - JSON_THROW(invalid_iterator::create(204, "iterators out of range", *first.m_object)); - } - break; - } - - case value_t::null: - case value_t::object: - case value_t::array: - case value_t::binary: - case value_t::discarded: - default: - break; - } - - switch (m_type) - { - case value_t::number_integer: - { - m_value.number_integer = first.m_object->m_value.number_integer; - break; - } - - case value_t::number_unsigned: - { - m_value.number_unsigned = first.m_object->m_value.number_unsigned; - break; - } - - case value_t::number_float: - { - m_value.number_float = first.m_object->m_value.number_float; - break; - } - - case value_t::boolean: - { - m_value.boolean = first.m_object->m_value.boolean; - break; - } - - case value_t::string: - { - m_value = *first.m_object->m_value.string; - break; - } - - case value_t::object: - { - m_value.object = create(first.m_it.object_iterator, - last.m_it.object_iterator); - break; - } - - case value_t::array: - { - m_value.array = create(first.m_it.array_iterator, - last.m_it.array_iterator); - break; - } - - case value_t::binary: - { - m_value = *first.m_object->m_value.binary; - break; - } - - case value_t::null: - case value_t::discarded: - default: - JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " + std::string(first.m_object->type_name()), *first.m_object)); - } - - set_parents(); - assert_invariant(); - } - - - /////////////////////////////////////// - // other constructors and destructor // - /////////////////////////////////////// - - template, - std::is_same>::value, int> = 0 > - basic_json(const JsonRef& ref) : basic_json(ref.moved_or_copied()) {} - - /// @brief copy constructor - /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ - basic_json(const basic_json& other) - : m_type(other.m_type) - { - // check of passed value is valid - other.assert_invariant(); - - switch (m_type) - { - case value_t::object: - { - m_value = *other.m_value.object; - break; - } - - case value_t::array: - { - m_value = *other.m_value.array; - break; - } - - case value_t::string: - { - m_value = *other.m_value.string; - break; - } - - case value_t::boolean: - { - m_value = other.m_value.boolean; - break; - } - - case value_t::number_integer: - { - m_value = other.m_value.number_integer; - break; - } - - case value_t::number_unsigned: - { - m_value = other.m_value.number_unsigned; - break; - } - - case value_t::number_float: - { - m_value = other.m_value.number_float; - break; - } - - case value_t::binary: - { - m_value = *other.m_value.binary; - break; - } - - case value_t::null: - case value_t::discarded: - default: - break; - } - - set_parents(); - assert_invariant(); - } - - /// @brief move constructor - /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ - basic_json(basic_json&& other) noexcept - : m_type(std::move(other.m_type)), - m_value(std::move(other.m_value)) - { - // check that passed value is valid - other.assert_invariant(false); - - // invalidate payload - other.m_type = value_t::null; - other.m_value = {}; - - set_parents(); - assert_invariant(); - } - - /// @brief copy assignment - /// @sa https://json.nlohmann.me/api/basic_json/operator=/ - basic_json& operator=(basic_json other) noexcept ( - std::is_nothrow_move_constructible::value&& - std::is_nothrow_move_assignable::value&& - std::is_nothrow_move_constructible::value&& - std::is_nothrow_move_assignable::value - ) - { - // check that passed value is valid - other.assert_invariant(); - - using std::swap; - swap(m_type, other.m_type); - swap(m_value, other.m_value); - - set_parents(); - assert_invariant(); - return *this; - } - - /// @brief destructor - /// @sa https://json.nlohmann.me/api/basic_json/~basic_json/ - ~basic_json() noexcept - { - assert_invariant(false); - m_value.destroy(m_type); - } - - /// @} - - public: - /////////////////////// - // object inspection // - /////////////////////// - - /// @name object inspection - /// Functions to inspect the type of a JSON value. - /// @{ - - /// @brief serialization - /// @sa https://json.nlohmann.me/api/basic_json/dump/ - string_t dump(const int indent = -1, - const char indent_char = ' ', - const bool ensure_ascii = false, - const error_handler_t error_handler = error_handler_t::strict) const - { - string_t result; - serializer s(detail::output_adapter(result), indent_char, error_handler); - - if (indent >= 0) - { - s.dump(*this, true, ensure_ascii, static_cast(indent)); - } - else - { - s.dump(*this, false, ensure_ascii, 0); - } - - return result; - } - - /// @brief return the type of the JSON value (explicit) - /// @sa https://json.nlohmann.me/api/basic_json/type/ - constexpr value_t type() const noexcept - { - return m_type; - } - - /// @brief return whether type is primitive - /// @sa https://json.nlohmann.me/api/basic_json/is_primitive/ - constexpr bool is_primitive() const noexcept - { - return is_null() || is_string() || is_boolean() || is_number() || is_binary(); - } - - /// @brief return whether type is structured - /// @sa https://json.nlohmann.me/api/basic_json/is_structured/ - constexpr bool is_structured() const noexcept - { - return is_array() || is_object(); - } - - /// @brief return whether value is null - /// @sa https://json.nlohmann.me/api/basic_json/is_null/ - constexpr bool is_null() const noexcept - { - return m_type == value_t::null; - } - - /// @brief return whether value is a boolean - /// @sa https://json.nlohmann.me/api/basic_json/is_boolean/ - constexpr bool is_boolean() const noexcept - { - return m_type == value_t::boolean; - } - - /// @brief return whether value is a number - /// @sa https://json.nlohmann.me/api/basic_json/is_number/ - constexpr bool is_number() const noexcept - { - return is_number_integer() || is_number_float(); - } - - /// @brief return whether value is an integer number - /// @sa https://json.nlohmann.me/api/basic_json/is_number_integer/ - constexpr bool is_number_integer() const noexcept - { - return m_type == value_t::number_integer || m_type == value_t::number_unsigned; - } - - /// @brief return whether value is an unsigned integer number - /// @sa https://json.nlohmann.me/api/basic_json/is_number_unsigned/ - constexpr bool is_number_unsigned() const noexcept - { - return m_type == value_t::number_unsigned; - } - - /// @brief return whether value is a floating-point number - /// @sa https://json.nlohmann.me/api/basic_json/is_number_float/ - constexpr bool is_number_float() const noexcept - { - return m_type == value_t::number_float; - } - - /// @brief return whether value is an object - /// @sa https://json.nlohmann.me/api/basic_json/is_object/ - constexpr bool is_object() const noexcept - { - return m_type == value_t::object; - } - - /// @brief return whether value is an array - /// @sa https://json.nlohmann.me/api/basic_json/is_array/ - constexpr bool is_array() const noexcept - { - return m_type == value_t::array; - } - - /// @brief return whether value is a string - /// @sa https://json.nlohmann.me/api/basic_json/is_string/ - constexpr bool is_string() const noexcept - { - return m_type == value_t::string; - } - - /// @brief return whether value is a binary array - /// @sa https://json.nlohmann.me/api/basic_json/is_binary/ - constexpr bool is_binary() const noexcept - { - return m_type == value_t::binary; - } - - /// @brief return whether value is discarded - /// @sa https://json.nlohmann.me/api/basic_json/is_discarded/ - constexpr bool is_discarded() const noexcept - { - return m_type == value_t::discarded; - } - - /// @brief return the type of the JSON value (implicit) - /// @sa https://json.nlohmann.me/api/basic_json/operator_value_t/ - constexpr operator value_t() const noexcept - { - return m_type; - } - - /// @} - - private: - ////////////////// - // value access // - ////////////////// - - /// get a boolean (explicit) - boolean_t get_impl(boolean_t* /*unused*/) const - { - if (JSON_HEDLEY_LIKELY(is_boolean())) - { - return m_value.boolean; - } - - JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(type_name()), *this)); - } - - /// get a pointer to the value (object) - object_t* get_impl_ptr(object_t* /*unused*/) noexcept - { - return is_object() ? m_value.object : nullptr; - } - - /// get a pointer to the value (object) - constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept - { - return is_object() ? m_value.object : nullptr; - } - - /// get a pointer to the value (array) - array_t* get_impl_ptr(array_t* /*unused*/) noexcept - { - return is_array() ? m_value.array : nullptr; - } - - /// get a pointer to the value (array) - constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept - { - return is_array() ? m_value.array : nullptr; - } - - /// get a pointer to the value (string) - string_t* get_impl_ptr(string_t* /*unused*/) noexcept - { - return is_string() ? m_value.string : nullptr; - } - - /// get a pointer to the value (string) - constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept - { - return is_string() ? m_value.string : nullptr; - } - - /// get a pointer to the value (boolean) - boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept - { - return is_boolean() ? &m_value.boolean : nullptr; - } - - /// get a pointer to the value (boolean) - constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept - { - return is_boolean() ? &m_value.boolean : nullptr; - } - - /// get a pointer to the value (integer number) - number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept - { - return is_number_integer() ? &m_value.number_integer : nullptr; - } - - /// get a pointer to the value (integer number) - constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept - { - return is_number_integer() ? &m_value.number_integer : nullptr; - } - - /// get a pointer to the value (unsigned number) - number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept - { - return is_number_unsigned() ? &m_value.number_unsigned : nullptr; - } - - /// get a pointer to the value (unsigned number) - constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept - { - return is_number_unsigned() ? &m_value.number_unsigned : nullptr; - } - - /// get a pointer to the value (floating-point number) - number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept - { - return is_number_float() ? &m_value.number_float : nullptr; - } - - /// get a pointer to the value (floating-point number) - constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept - { - return is_number_float() ? &m_value.number_float : nullptr; - } - - /// get a pointer to the value (binary) - binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept - { - return is_binary() ? m_value.binary : nullptr; - } - - /// get a pointer to the value (binary) - constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept - { - return is_binary() ? m_value.binary : nullptr; - } - - /*! - @brief helper function to implement get_ref() - - This function helps to implement get_ref() without code duplication for - const and non-const overloads - - @tparam ThisType will be deduced as `basic_json` or `const basic_json` - - @throw type_error.303 if ReferenceType does not match underlying value - type of the current JSON - */ - template - static ReferenceType get_ref_impl(ThisType& obj) - { - // delegate the call to get_ptr<>() - auto* ptr = obj.template get_ptr::type>(); - - if (JSON_HEDLEY_LIKELY(ptr != nullptr)) - { - return *ptr; - } - - JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is " + std::string(obj.type_name()), obj)); - } - - public: - /// @name value access - /// Direct access to the stored value of a JSON value. - /// @{ - - /// @brief get a pointer value (implicit) - /// @sa https://json.nlohmann.me/api/basic_json/get_ptr/ - template::value, int>::type = 0> - auto get_ptr() noexcept -> decltype(std::declval().get_impl_ptr(std::declval())) - { - // delegate the call to get_impl_ptr<>() - return get_impl_ptr(static_cast(nullptr)); - } - - /// @brief get a pointer value (implicit) - /// @sa https://json.nlohmann.me/api/basic_json/get_ptr/ - template < typename PointerType, typename std::enable_if < - std::is_pointer::value&& - std::is_const::type>::value, int >::type = 0 > - constexpr auto get_ptr() const noexcept -> decltype(std::declval().get_impl_ptr(std::declval())) - { - // delegate the call to get_impl_ptr<>() const - return get_impl_ptr(static_cast(nullptr)); - } - - private: - /*! - @brief get a value (explicit) - - Explicit type conversion between the JSON value and a compatible value - which is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible) - and [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). - The value is converted by calling the @ref json_serializer - `from_json()` method. - - The function is equivalent to executing - @code {.cpp} - ValueType ret; - JSONSerializer::from_json(*this, ret); - return ret; - @endcode - - This overloads is chosen if: - - @a ValueType is not @ref basic_json, - - @ref json_serializer has a `from_json()` method of the form - `void from_json(const basic_json&, ValueType&)`, and - - @ref json_serializer does not have a `from_json()` method of - the form `ValueType from_json(const basic_json&)` - - @tparam ValueType the returned value type - - @return copy of the JSON value, converted to @a ValueType - - @throw what @ref json_serializer `from_json()` method throws - - @liveexample{The example below shows several conversions from JSON values - to other types. There a few things to note: (1) Floating-point numbers can - be converted to integers\, (2) A JSON array can be converted to a standard - `std::vector`\, (3) A JSON object can be converted to C++ - associative containers such as `std::unordered_map`.,get__ValueType_const} - - @since version 2.1.0 - */ - template < typename ValueType, - detail::enable_if_t < - detail::is_default_constructible::value&& - detail::has_from_json::value, - int > = 0 > - ValueType get_impl(detail::priority_tag<0> /*unused*/) const noexcept(noexcept( - JSONSerializer::from_json(std::declval(), std::declval()))) - { - auto ret = ValueType(); - JSONSerializer::from_json(*this, ret); - return ret; - } - - /*! - @brief get a value (explicit); special case - - Explicit type conversion between the JSON value and a compatible value - which is **not** [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible) - and **not** [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). - The value is converted by calling the @ref json_serializer - `from_json()` method. - - The function is equivalent to executing - @code {.cpp} - return JSONSerializer::from_json(*this); - @endcode - - This overloads is chosen if: - - @a ValueType is not @ref basic_json and - - @ref json_serializer has a `from_json()` method of the form - `ValueType from_json(const basic_json&)` - - @note If @ref json_serializer has both overloads of - `from_json()`, this one is chosen. - - @tparam ValueType the returned value type - - @return copy of the JSON value, converted to @a ValueType - - @throw what @ref json_serializer `from_json()` method throws - - @since version 2.1.0 - */ - template < typename ValueType, - detail::enable_if_t < - detail::has_non_default_from_json::value, - int > = 0 > - ValueType get_impl(detail::priority_tag<1> /*unused*/) const noexcept(noexcept( - JSONSerializer::from_json(std::declval()))) - { - return JSONSerializer::from_json(*this); - } - - /*! - @brief get special-case overload - - This overloads converts the current @ref basic_json in a different - @ref basic_json type - - @tparam BasicJsonType == @ref basic_json - - @return a copy of *this, converted into @a BasicJsonType - - @complexity Depending on the implementation of the called `from_json()` - method. - - @since version 3.2.0 - */ - template < typename BasicJsonType, - detail::enable_if_t < - detail::is_basic_json::value, - int > = 0 > - BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const - { - return *this; - } - - /*! - @brief get special-case overload - - This overloads avoids a lot of template boilerplate, it can be seen as the - identity method - - @tparam BasicJsonType == @ref basic_json - - @return a copy of *this - - @complexity Constant. - - @since version 2.1.0 - */ - template::value, - int> = 0> - basic_json get_impl(detail::priority_tag<3> /*unused*/) const - { - return *this; - } - - /*! - @brief get a pointer value (explicit) - @copydoc get() - */ - template::value, - int> = 0> - constexpr auto get_impl(detail::priority_tag<4> /*unused*/) const noexcept - -> decltype(std::declval().template get_ptr()) - { - // delegate the call to get_ptr - return get_ptr(); - } - - public: - /*! - @brief get a (pointer) value (explicit) - - Performs explicit type conversion between the JSON value and a compatible value if required. - - - If the requested type is a pointer to the internally stored JSON value that pointer is returned. - No copies are made. - - - If the requested type is the current @ref basic_json, or a different @ref basic_json convertible - from the current @ref basic_json. - - - Otherwise the value is converted by calling the @ref json_serializer `from_json()` - method. - - @tparam ValueTypeCV the provided value type - @tparam ValueType the returned value type - - @return copy of the JSON value, converted to @tparam ValueType if necessary - - @throw what @ref json_serializer `from_json()` method throws if conversion is required - - @since version 2.1.0 - */ - template < typename ValueTypeCV, typename ValueType = detail::uncvref_t> -#if defined(JSON_HAS_CPP_14) - constexpr -#endif - auto get() const noexcept( - noexcept(std::declval().template get_impl(detail::priority_tag<4> {}))) - -> decltype(std::declval().template get_impl(detail::priority_tag<4> {})) - { - // we cannot static_assert on ValueTypeCV being non-const, because - // there is support for get(), which is why we - // still need the uncvref - static_assert(!std::is_reference::value, - "get() cannot be used with reference types, you might want to use get_ref()"); - return get_impl(detail::priority_tag<4> {}); - } - - /*! - @brief get a pointer value (explicit) - - Explicit pointer access to the internally stored JSON value. No copies are - made. - - @warning The pointer becomes invalid if the underlying JSON object - changes. - - @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref - object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, - @ref number_unsigned_t, or @ref number_float_t. - - @return pointer to the internally stored JSON value if the requested - pointer type @a PointerType fits to the JSON value; `nullptr` otherwise - - @complexity Constant. - - @liveexample{The example below shows how pointers to internal values of a - JSON value can be requested. Note that no type conversions are made and a - `nullptr` is returned if the value and the requested pointer type does not - match.,get__PointerType} - - @sa see @ref get_ptr() for explicit pointer-member access - - @since version 1.0.0 - */ - template::value, int>::type = 0> - auto get() noexcept -> decltype(std::declval().template get_ptr()) - { - // delegate the call to get_ptr - return get_ptr(); - } - - /// @brief get a value (explicit) - /// @sa https://json.nlohmann.me/api/basic_json/get_to/ - template < typename ValueType, - detail::enable_if_t < - !detail::is_basic_json::value&& - detail::has_from_json::value, - int > = 0 > - ValueType & get_to(ValueType& v) const noexcept(noexcept( - JSONSerializer::from_json(std::declval(), v))) - { - JSONSerializer::from_json(*this, v); - return v; - } - - // specialization to allow calling get_to with a basic_json value - // see https://github.com/nlohmann/json/issues/2175 - template::value, - int> = 0> - ValueType & get_to(ValueType& v) const - { - v = *this; - return v; - } - - template < - typename T, std::size_t N, - typename Array = T (&)[N], // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - detail::enable_if_t < - detail::has_from_json::value, int > = 0 > - Array get_to(T (&v)[N]) const // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - noexcept(noexcept(JSONSerializer::from_json( - std::declval(), v))) - { - JSONSerializer::from_json(*this, v); - return v; - } - - /// @brief get a reference value (implicit) - /// @sa https://json.nlohmann.me/api/basic_json/get_ref/ - template::value, int>::type = 0> - ReferenceType get_ref() - { - // delegate call to get_ref_impl - return get_ref_impl(*this); - } - - /// @brief get a reference value (implicit) - /// @sa https://json.nlohmann.me/api/basic_json/get_ref/ - template < typename ReferenceType, typename std::enable_if < - std::is_reference::value&& - std::is_const::type>::value, int >::type = 0 > - ReferenceType get_ref() const - { - // delegate call to get_ref_impl - return get_ref_impl(*this); - } - - /*! - @brief get a value (implicit) - - Implicit type conversion between the JSON value and a compatible value. - The call is realized by calling @ref get() const. - - @tparam ValueType non-pointer type compatible to the JSON value, for - instance `int` for JSON integer numbers, `bool` for JSON booleans, or - `std::vector` types for JSON arrays. The character type of @ref string_t - as well as an initializer list of this type is excluded to avoid - ambiguities as these types implicitly convert to `std::string`. - - @return copy of the JSON value, converted to type @a ValueType - - @throw type_error.302 in case passed type @a ValueType is incompatible - to the JSON value type (e.g., the JSON value is of type boolean, but a - string is requested); see example below - - @complexity Linear in the size of the JSON value. - - @liveexample{The example below shows several conversions from JSON values - to other types. There a few things to note: (1) Floating-point numbers can - be converted to integers\, (2) A JSON array can be converted to a standard - `std::vector`\, (3) A JSON object can be converted to C++ - associative containers such as `std::unordered_map`.,operator__ValueType} - - @since version 1.0.0 - */ - template < typename ValueType, typename std::enable_if < - detail::conjunction < - detail::negation>, - detail::negation>>, - detail::negation>, - detail::negation>, - detail::negation>>, - -#if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914)) - detail::negation>, -#endif - detail::is_detected_lazy - >::value, int >::type = 0 > - JSON_EXPLICIT operator ValueType() const - { - // delegate the call to get<>() const - return get(); - } - - /// @brief get a binary value - /// @sa https://json.nlohmann.me/api/basic_json/get_binary/ - binary_t& get_binary() - { - if (!is_binary()) - { - JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name()), *this)); - } - - return *get_ptr(); - } - - /// @brief get a binary value - /// @sa https://json.nlohmann.me/api/basic_json/get_binary/ - const binary_t& get_binary() const - { - if (!is_binary()) - { - JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name()), *this)); - } - - return *get_ptr(); - } - - /// @} - - - //////////////////// - // element access // - //////////////////// - - /// @name element access - /// Access to the JSON value. - /// @{ - - /// @brief access specified array element with bounds checking - /// @sa https://json.nlohmann.me/api/basic_json/at/ - reference at(size_type idx) - { - // at only works for arrays - if (JSON_HEDLEY_LIKELY(is_array())) - { - JSON_TRY - { - return set_parent(m_value.array->at(idx)); - } - JSON_CATCH (std::out_of_range&) - { - // create better exception explanation - JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range", *this)); - } - } - else - { - JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()), *this)); - } - } - - /// @brief access specified array element with bounds checking - /// @sa https://json.nlohmann.me/api/basic_json/at/ - const_reference at(size_type idx) const - { - // at only works for arrays - if (JSON_HEDLEY_LIKELY(is_array())) - { - JSON_TRY - { - return m_value.array->at(idx); - } - JSON_CATCH (std::out_of_range&) - { - // create better exception explanation - JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range", *this)); - } - } - else - { - JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()), *this)); - } - } - - /// @brief access specified object element with bounds checking - /// @sa https://json.nlohmann.me/api/basic_json/at/ - reference at(const typename object_t::key_type& key) - { - // at only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - JSON_TRY - { - return set_parent(m_value.object->at(key)); - } - JSON_CATCH (std::out_of_range&) - { - // create better exception explanation - JSON_THROW(out_of_range::create(403, "key '" + key + "' not found", *this)); - } - } - else - { - JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()), *this)); - } - } - - /// @brief access specified object element with bounds checking - /// @sa https://json.nlohmann.me/api/basic_json/at/ - const_reference at(const typename object_t::key_type& key) const - { - // at only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - JSON_TRY - { - return m_value.object->at(key); - } - JSON_CATCH (std::out_of_range&) - { - // create better exception explanation - JSON_THROW(out_of_range::create(403, "key '" + key + "' not found", *this)); - } - } - else - { - JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()), *this)); - } - } - - /// @brief access specified array element - /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ - reference operator[](size_type idx) - { - // implicitly convert null value to an empty array - if (is_null()) - { - m_type = value_t::array; - m_value.array = create(); - assert_invariant(); - } - - // operator[] only works for arrays - if (JSON_HEDLEY_LIKELY(is_array())) - { - // fill up array with null values if given idx is outside range - if (idx >= m_value.array->size()) - { -#if JSON_DIAGNOSTICS - // remember array size & capacity before resizing - const auto old_size = m_value.array->size(); - const auto old_capacity = m_value.array->capacity(); -#endif - m_value.array->resize(idx + 1); - -#if JSON_DIAGNOSTICS - if (JSON_HEDLEY_UNLIKELY(m_value.array->capacity() != old_capacity)) - { - // capacity has changed: update all parents - set_parents(); - } - else - { - // set parent for values added above - set_parents(begin() + static_cast(old_size), static_cast(idx + 1 - old_size)); - } -#endif - assert_invariant(); - } - - return m_value.array->operator[](idx); - } - - JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name()), *this)); - } - - /// @brief access specified array element - /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ - const_reference operator[](size_type idx) const - { - // const operator[] only works for arrays - if (JSON_HEDLEY_LIKELY(is_array())) - { - return m_value.array->operator[](idx); - } - - JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name()), *this)); - } - - /// @brief access specified object element - /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ - reference operator[](const typename object_t::key_type& key) - { - // implicitly convert null value to an empty object - if (is_null()) - { - m_type = value_t::object; - m_value.object = create(); - assert_invariant(); - } - - // operator[] only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - return set_parent(m_value.object->operator[](key)); - } - - JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this)); - } - - /// @brief access specified object element - /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ - const_reference operator[](const typename object_t::key_type& key) const - { - // const operator[] only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - JSON_ASSERT(m_value.object->find(key) != m_value.object->end()); - return m_value.object->find(key)->second; - } - - JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this)); - } - - /// @brief access specified object element - /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ - template - JSON_HEDLEY_NON_NULL(2) - reference operator[](T* key) - { - // implicitly convert null to object - if (is_null()) - { - m_type = value_t::object; - m_value = value_t::object; - assert_invariant(); - } - - // at only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - return set_parent(m_value.object->operator[](key)); - } - - JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this)); - } - - /// @brief access specified object element - /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ - template - JSON_HEDLEY_NON_NULL(2) - const_reference operator[](T* key) const - { - // at only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - JSON_ASSERT(m_value.object->find(key) != m_value.object->end()); - return m_value.object->find(key)->second; - } - - JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this)); - } - - /// @brief access specified object element with default value - /// @sa https://json.nlohmann.me/api/basic_json/value/ - /// using std::is_convertible in a std::enable_if will fail when using explicit conversions - template < class ValueType, typename std::enable_if < - detail::is_getable::value - && !std::is_same::value, int >::type = 0 > - ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const - { - // at only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - // if key is found, return value and given default value otherwise - const auto it = find(key); - if (it != end()) - { - return it->template get(); - } - - return default_value; - } - - JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()), *this)); - } - - /// @brief access specified object element with default value - /// @sa https://json.nlohmann.me/api/basic_json/value/ - /// overload for a default value of type const char* - string_t value(const typename object_t::key_type& key, const char* default_value) const - { - return value(key, string_t(default_value)); - } - - /// @brief access specified object element via JSON Pointer with default value - /// @sa https://json.nlohmann.me/api/basic_json/value/ - template::value, int>::type = 0> - ValueType value(const json_pointer& ptr, const ValueType& default_value) const - { - // at only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - // if pointer resolves a value, return it or use default value - JSON_TRY - { - return ptr.get_checked(this).template get(); - } - JSON_INTERNAL_CATCH (out_of_range&) - { - return default_value; - } - } - - JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()), *this)); - } - - /// @brief access specified object element via JSON Pointer with default value - /// @sa https://json.nlohmann.me/api/basic_json/value/ - /// overload for a default value of type const char* - JSON_HEDLEY_NON_NULL(3) - string_t value(const json_pointer& ptr, const char* default_value) const - { - return value(ptr, string_t(default_value)); - } - - /// @brief access the first element - /// @sa https://json.nlohmann.me/api/basic_json/front/ - reference front() - { - return *begin(); - } - - /// @brief access the first element - /// @sa https://json.nlohmann.me/api/basic_json/front/ - const_reference front() const - { - return *cbegin(); - } - - /// @brief access the last element - /// @sa https://json.nlohmann.me/api/basic_json/back/ - reference back() - { - auto tmp = end(); - --tmp; - return *tmp; - } - - /// @brief access the last element - /// @sa https://json.nlohmann.me/api/basic_json/back/ - const_reference back() const - { - auto tmp = cend(); - --tmp; - return *tmp; - } - - /// @brief remove element given an iterator - /// @sa https://json.nlohmann.me/api/basic_json/erase/ - template < class IteratorType, typename std::enable_if < - std::is_same::value || - std::is_same::value, int >::type - = 0 > - IteratorType erase(IteratorType pos) - { - // make sure iterator fits the current value - if (JSON_HEDLEY_UNLIKELY(this != pos.m_object)) - { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", *this)); - } - - IteratorType result = end(); - - switch (m_type) - { - case value_t::boolean: - case value_t::number_float: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::string: - case value_t::binary: - { - if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin())) - { - JSON_THROW(invalid_iterator::create(205, "iterator out of range", *this)); - } - - if (is_string()) - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, m_value.string); - std::allocator_traits::deallocate(alloc, m_value.string, 1); - m_value.string = nullptr; - } - else if (is_binary()) - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, m_value.binary); - std::allocator_traits::deallocate(alloc, m_value.binary, 1); - m_value.binary = nullptr; - } - - m_type = value_t::null; - assert_invariant(); - break; - } - - case value_t::object: - { - result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); - break; - } - - case value_t::array: - { - result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); - break; - } - - case value_t::null: - case value_t::discarded: - default: - JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()), *this)); - } - - return result; - } - - /// @brief remove elements given an iterator range - /// @sa https://json.nlohmann.me/api/basic_json/erase/ - template < class IteratorType, typename std::enable_if < - std::is_same::value || - std::is_same::value, int >::type - = 0 > - IteratorType erase(IteratorType first, IteratorType last) - { - // make sure iterator fits the current value - if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object)) - { - JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value", *this)); - } - - IteratorType result = end(); - - switch (m_type) - { - case value_t::boolean: - case value_t::number_float: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::string: - case value_t::binary: - { - if (JSON_HEDLEY_LIKELY(!first.m_it.primitive_iterator.is_begin() - || !last.m_it.primitive_iterator.is_end())) - { - JSON_THROW(invalid_iterator::create(204, "iterators out of range", *this)); - } - - if (is_string()) - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, m_value.string); - std::allocator_traits::deallocate(alloc, m_value.string, 1); - m_value.string = nullptr; - } - else if (is_binary()) - { - AllocatorType alloc; - std::allocator_traits::destroy(alloc, m_value.binary); - std::allocator_traits::deallocate(alloc, m_value.binary, 1); - m_value.binary = nullptr; - } - - m_type = value_t::null; - assert_invariant(); - break; - } - - case value_t::object: - { - result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, - last.m_it.object_iterator); - break; - } - - case value_t::array: - { - result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, - last.m_it.array_iterator); - break; - } - - case value_t::null: - case value_t::discarded: - default: - JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()), *this)); - } - - return result; - } - - /// @brief remove element from a JSON object given a key - /// @sa https://json.nlohmann.me/api/basic_json/erase/ - size_type erase(const typename object_t::key_type& key) - { - // this erase only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - return m_value.object->erase(key); - } - - JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()), *this)); - } - - /// @brief remove element from a JSON array given an index - /// @sa https://json.nlohmann.me/api/basic_json/erase/ - void erase(const size_type idx) - { - // this erase only works for arrays - if (JSON_HEDLEY_LIKELY(is_array())) - { - if (JSON_HEDLEY_UNLIKELY(idx >= size())) - { - JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range", *this)); - } - - m_value.array->erase(m_value.array->begin() + static_cast(idx)); - } - else - { - JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()), *this)); - } - } - - /// @} - - - //////////// - // lookup // - //////////// - - /// @name lookup - /// @{ - - /// @brief find an element in a JSON object - /// @sa https://json.nlohmann.me/api/basic_json/find/ - template - iterator find(KeyT&& key) - { - auto result = end(); - - if (is_object()) - { - result.m_it.object_iterator = m_value.object->find(std::forward(key)); - } - - return result; - } - - /// @brief find an element in a JSON object - /// @sa https://json.nlohmann.me/api/basic_json/find/ - template - const_iterator find(KeyT&& key) const - { - auto result = cend(); - - if (is_object()) - { - result.m_it.object_iterator = m_value.object->find(std::forward(key)); - } - - return result; - } - - /// @brief returns the number of occurrences of a key in a JSON object - /// @sa https://json.nlohmann.me/api/basic_json/count/ - template - size_type count(KeyT&& key) const - { - // return 0 for all nonobject types - return is_object() ? m_value.object->count(std::forward(key)) : 0; - } - - /// @brief check the existence of an element in a JSON object - /// @sa https://json.nlohmann.me/api/basic_json/contains/ - template < typename KeyT, typename std::enable_if < - !std::is_same::type, json_pointer>::value, int >::type = 0 > - bool contains(KeyT && key) const - { - return is_object() && m_value.object->find(std::forward(key)) != m_value.object->end(); - } - - /// @brief check the existence of an element in a JSON object given a JSON pointer - /// @sa https://json.nlohmann.me/api/basic_json/contains/ - bool contains(const json_pointer& ptr) const - { - return ptr.contains(this); - } - - /// @} - - - /////////////// - // iterators // - /////////////// - - /// @name iterators - /// @{ - - /// @brief returns an iterator to the first element - /// @sa https://json.nlohmann.me/api/basic_json/begin/ - iterator begin() noexcept - { - iterator result(this); - result.set_begin(); - return result; - } - - /// @brief returns an iterator to the first element - /// @sa https://json.nlohmann.me/api/basic_json/begin/ - const_iterator begin() const noexcept - { - return cbegin(); - } - - /// @brief returns a const iterator to the first element - /// @sa https://json.nlohmann.me/api/basic_json/cbegin/ - const_iterator cbegin() const noexcept - { - const_iterator result(this); - result.set_begin(); - return result; - } - - /// @brief returns an iterator to one past the last element - /// @sa https://json.nlohmann.me/api/basic_json/end/ - iterator end() noexcept - { - iterator result(this); - result.set_end(); - return result; - } - - /// @brief returns an iterator to one past the last element - /// @sa https://json.nlohmann.me/api/basic_json/end/ - const_iterator end() const noexcept - { - return cend(); - } - - /// @brief returns an iterator to one past the last element - /// @sa https://json.nlohmann.me/api/basic_json/cend/ - const_iterator cend() const noexcept - { - const_iterator result(this); - result.set_end(); - return result; - } - - /// @brief returns an iterator to the reverse-beginning - /// @sa https://json.nlohmann.me/api/basic_json/rbegin/ - reverse_iterator rbegin() noexcept - { - return reverse_iterator(end()); - } - - /// @brief returns an iterator to the reverse-beginning - /// @sa https://json.nlohmann.me/api/basic_json/rbegin/ - const_reverse_iterator rbegin() const noexcept - { - return crbegin(); - } - - /// @brief returns an iterator to the reverse-end - /// @sa https://json.nlohmann.me/api/basic_json/rend/ - reverse_iterator rend() noexcept - { - return reverse_iterator(begin()); - } - - /// @brief returns an iterator to the reverse-end - /// @sa https://json.nlohmann.me/api/basic_json/rend/ - const_reverse_iterator rend() const noexcept - { - return crend(); - } - - /// @brief returns a const reverse iterator to the last element - /// @sa https://json.nlohmann.me/api/basic_json/crbegin/ - const_reverse_iterator crbegin() const noexcept - { - return const_reverse_iterator(cend()); - } - - /// @brief returns a const reverse iterator to one before the first - /// @sa https://json.nlohmann.me/api/basic_json/crend/ - const_reverse_iterator crend() const noexcept - { - return const_reverse_iterator(cbegin()); - } - - public: - /// @brief wrapper to access iterator member functions in range-based for - /// @sa https://json.nlohmann.me/api/basic_json/items/ - /// @deprecated This function is deprecated since 3.1.0 and will be removed in - /// version 4.0.0 of the library. Please use @ref items() instead; - /// that is, replace `json::iterator_wrapper(j)` with `j.items()`. - JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items()) - static iteration_proxy iterator_wrapper(reference ref) noexcept - { - return ref.items(); - } - - /// @brief wrapper to access iterator member functions in range-based for - /// @sa https://json.nlohmann.me/api/basic_json/items/ - /// @deprecated This function is deprecated since 3.1.0 and will be removed in - /// version 4.0.0 of the library. Please use @ref items() instead; - /// that is, replace `json::iterator_wrapper(j)` with `j.items()`. - JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items()) - static iteration_proxy iterator_wrapper(const_reference ref) noexcept - { - return ref.items(); - } - - /// @brief helper to access iterator member functions in range-based for - /// @sa https://json.nlohmann.me/api/basic_json/items/ - iteration_proxy items() noexcept - { - return iteration_proxy(*this); - } - - /// @brief helper to access iterator member functions in range-based for - /// @sa https://json.nlohmann.me/api/basic_json/items/ - iteration_proxy items() const noexcept - { - return iteration_proxy(*this); - } - - /// @} - - - ////////////// - // capacity // - ////////////// - - /// @name capacity - /// @{ - - /// @brief checks whether the container is empty. - /// @sa https://json.nlohmann.me/api/basic_json/empty/ - bool empty() const noexcept - { - switch (m_type) - { - case value_t::null: - { - // null values are empty - return true; - } - - case value_t::array: - { - // delegate call to array_t::empty() - return m_value.array->empty(); - } - - case value_t::object: - { - // delegate call to object_t::empty() - return m_value.object->empty(); - } - - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - // all other types are nonempty - return false; - } - } - } - - /// @brief returns the number of elements - /// @sa https://json.nlohmann.me/api/basic_json/size/ - size_type size() const noexcept - { - switch (m_type) - { - case value_t::null: - { - // null values are empty - return 0; - } - - case value_t::array: - { - // delegate call to array_t::size() - return m_value.array->size(); - } - - case value_t::object: - { - // delegate call to object_t::size() - return m_value.object->size(); - } - - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - // all other types have size 1 - return 1; - } - } - } - - /// @brief returns the maximum possible number of elements - /// @sa https://json.nlohmann.me/api/basic_json/max_size/ - size_type max_size() const noexcept - { - switch (m_type) - { - case value_t::array: - { - // delegate call to array_t::max_size() - return m_value.array->max_size(); - } - - case value_t::object: - { - // delegate call to object_t::max_size() - return m_value.object->max_size(); - } - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - // all other types have max_size() == size() - return size(); - } - } - } - - /// @} - - - /////////////// - // modifiers // - /////////////// - - /// @name modifiers - /// @{ - - /// @brief clears the contents - /// @sa https://json.nlohmann.me/api/basic_json/clear/ - void clear() noexcept - { - switch (m_type) - { - case value_t::number_integer: - { - m_value.number_integer = 0; - break; - } - - case value_t::number_unsigned: - { - m_value.number_unsigned = 0; - break; - } - - case value_t::number_float: - { - m_value.number_float = 0.0; - break; - } - - case value_t::boolean: - { - m_value.boolean = false; - break; - } - - case value_t::string: - { - m_value.string->clear(); - break; - } - - case value_t::binary: - { - m_value.binary->clear(); - break; - } - - case value_t::array: - { - m_value.array->clear(); - break; - } - - case value_t::object: - { - m_value.object->clear(); - break; - } - - case value_t::null: - case value_t::discarded: - default: - break; - } - } - - /// @brief add an object to an array - /// @sa https://json.nlohmann.me/api/basic_json/push_back/ - void push_back(basic_json&& val) - { - // push_back only works for null objects or arrays - if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) - { - JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()), *this)); - } - - // transform null object into an array - if (is_null()) - { - m_type = value_t::array; - m_value = value_t::array; - assert_invariant(); - } - - // add element to array (move semantics) - const auto old_capacity = m_value.array->capacity(); - m_value.array->push_back(std::move(val)); - set_parent(m_value.array->back(), old_capacity); - // if val is moved from, basic_json move constructor marks it null, so we do not call the destructor - } - - /// @brief add an object to an array - /// @sa https://json.nlohmann.me/api/basic_json/operator+=/ - reference operator+=(basic_json&& val) - { - push_back(std::move(val)); - return *this; - } - - /// @brief add an object to an array - /// @sa https://json.nlohmann.me/api/basic_json/push_back/ - void push_back(const basic_json& val) - { - // push_back only works for null objects or arrays - if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) - { - JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()), *this)); - } - - // transform null object into an array - if (is_null()) - { - m_type = value_t::array; - m_value = value_t::array; - assert_invariant(); - } - - // add element to array - const auto old_capacity = m_value.array->capacity(); - m_value.array->push_back(val); - set_parent(m_value.array->back(), old_capacity); - } - - /// @brief add an object to an array - /// @sa https://json.nlohmann.me/api/basic_json/operator+=/ - reference operator+=(const basic_json& val) - { - push_back(val); - return *this; - } - - /// @brief add an object to an object - /// @sa https://json.nlohmann.me/api/basic_json/push_back/ - void push_back(const typename object_t::value_type& val) - { - // push_back only works for null objects or objects - if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object()))) - { - JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()), *this)); - } - - // transform null object into an object - if (is_null()) - { - m_type = value_t::object; - m_value = value_t::object; - assert_invariant(); - } - - // add element to object - auto res = m_value.object->insert(val); - set_parent(res.first->second); - } - - /// @brief add an object to an object - /// @sa https://json.nlohmann.me/api/basic_json/operator+=/ - reference operator+=(const typename object_t::value_type& val) - { - push_back(val); - return *this; - } - - /// @brief add an object to an object - /// @sa https://json.nlohmann.me/api/basic_json/push_back/ - void push_back(initializer_list_t init) - { - if (is_object() && init.size() == 2 && (*init.begin())->is_string()) - { - basic_json&& key = init.begin()->moved_or_copied(); - push_back(typename object_t::value_type( - std::move(key.get_ref()), (init.begin() + 1)->moved_or_copied())); - } - else - { - push_back(basic_json(init)); - } - } - - /// @brief add an object to an object - /// @sa https://json.nlohmann.me/api/basic_json/operator+=/ - reference operator+=(initializer_list_t init) - { - push_back(init); - return *this; - } - - /// @brief add an object to an array - /// @sa https://json.nlohmann.me/api/basic_json/emplace_back/ - template - reference emplace_back(Args&& ... args) - { - // emplace_back only works for null objects or arrays - if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) - { - JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + std::string(type_name()), *this)); - } - - // transform null object into an array - if (is_null()) - { - m_type = value_t::array; - m_value = value_t::array; - assert_invariant(); - } - - // add element to array (perfect forwarding) - const auto old_capacity = m_value.array->capacity(); - m_value.array->emplace_back(std::forward(args)...); - return set_parent(m_value.array->back(), old_capacity); - } - - /// @brief add an object to an object if key does not exist - /// @sa https://json.nlohmann.me/api/basic_json/emplace/ - template - std::pair emplace(Args&& ... args) - { - // emplace only works for null objects or arrays - if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object()))) - { - JSON_THROW(type_error::create(311, "cannot use emplace() with " + std::string(type_name()), *this)); - } - - // transform null object into an object - if (is_null()) - { - m_type = value_t::object; - m_value = value_t::object; - assert_invariant(); - } - - // add element to array (perfect forwarding) - auto res = m_value.object->emplace(std::forward(args)...); - set_parent(res.first->second); - - // create result iterator and set iterator to the result of emplace - auto it = begin(); - it.m_it.object_iterator = res.first; - - // return pair of iterator and boolean - return {it, res.second}; - } - - /// Helper for insertion of an iterator - /// @note: This uses std::distance to support GCC 4.8, - /// see https://github.com/nlohmann/json/pull/1257 - template - iterator insert_iterator(const_iterator pos, Args&& ... args) - { - iterator result(this); - JSON_ASSERT(m_value.array != nullptr); - - auto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator); - m_value.array->insert(pos.m_it.array_iterator, std::forward(args)...); - result.m_it.array_iterator = m_value.array->begin() + insert_pos; - - // This could have been written as: - // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); - // but the return value of insert is missing in GCC 4.8, so it is written this way instead. - - set_parents(); - return result; - } - - /// @brief inserts element into array - /// @sa https://json.nlohmann.me/api/basic_json/insert/ - iterator insert(const_iterator pos, const basic_json& val) - { - // insert only works for arrays - if (JSON_HEDLEY_LIKELY(is_array())) - { - // check if iterator pos fits to this JSON value - if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) - { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", *this)); - } - - // insert to array and return iterator - return insert_iterator(pos, val); - } - - JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); - } - - /// @brief inserts element into array - /// @sa https://json.nlohmann.me/api/basic_json/insert/ - iterator insert(const_iterator pos, basic_json&& val) - { - return insert(pos, val); - } - - /// @brief inserts copies of element into array - /// @sa https://json.nlohmann.me/api/basic_json/insert/ - iterator insert(const_iterator pos, size_type cnt, const basic_json& val) - { - // insert only works for arrays - if (JSON_HEDLEY_LIKELY(is_array())) - { - // check if iterator pos fits to this JSON value - if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) - { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", *this)); - } - - // insert to array and return iterator - return insert_iterator(pos, cnt, val); - } - - JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); - } - - /// @brief inserts range of elements into array - /// @sa https://json.nlohmann.me/api/basic_json/insert/ - iterator insert(const_iterator pos, const_iterator first, const_iterator last) - { - // insert only works for arrays - if (JSON_HEDLEY_UNLIKELY(!is_array())) - { - JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); - } - - // check if iterator pos fits to this JSON value - if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) - { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", *this)); - } - - // check if range iterators belong to the same JSON object - if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) - { - JSON_THROW(invalid_iterator::create(210, "iterators do not fit", *this)); - } - - if (JSON_HEDLEY_UNLIKELY(first.m_object == this)) - { - JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container", *this)); - } - - // insert to array and return iterator - return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator); - } - - /// @brief inserts elements from initializer list into array - /// @sa https://json.nlohmann.me/api/basic_json/insert/ - iterator insert(const_iterator pos, initializer_list_t ilist) - { - // insert only works for arrays - if (JSON_HEDLEY_UNLIKELY(!is_array())) - { - JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); - } - - // check if iterator pos fits to this JSON value - if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) - { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", *this)); - } - - // insert to array and return iterator - return insert_iterator(pos, ilist.begin(), ilist.end()); - } - - /// @brief inserts range of elements into object - /// @sa https://json.nlohmann.me/api/basic_json/insert/ - void insert(const_iterator first, const_iterator last) - { - // insert only works for objects - if (JSON_HEDLEY_UNLIKELY(!is_object())) - { - JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); - } - - // check if range iterators belong to the same JSON object - if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) - { - JSON_THROW(invalid_iterator::create(210, "iterators do not fit", *this)); - } - - // passed iterators must belong to objects - if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object())) - { - JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects", *this)); - } - - m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator); - } - - /// @brief updates a JSON object from another object, overwriting existing keys - /// @sa https://json.nlohmann.me/api/basic_json/update/ - void update(const_reference j, bool merge_objects = false) - { - update(j.begin(), j.end(), merge_objects); - } - - /// @brief updates a JSON object from another object, overwriting existing keys - /// @sa https://json.nlohmann.me/api/basic_json/update/ - void update(const_iterator first, const_iterator last, bool merge_objects = false) - { - // implicitly convert null value to an empty object - if (is_null()) - { - m_type = value_t::object; - m_value.object = create(); - assert_invariant(); - } - - if (JSON_HEDLEY_UNLIKELY(!is_object())) - { - JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()), *this)); - } - - // check if range iterators belong to the same JSON object - if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) - { - JSON_THROW(invalid_iterator::create(210, "iterators do not fit", *this)); - } - - // passed iterators must belong to objects - if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object())) - { - JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(first.m_object->type_name()), *first.m_object)); - } - - for (auto it = first; it != last; ++it) - { - if (merge_objects && it.value().is_object()) - { - auto it2 = m_value.object->find(it.key()); - if (it2 != m_value.object->end()) - { - it2->second.update(it.value(), true); - continue; - } - } - m_value.object->operator[](it.key()) = it.value(); -#if JSON_DIAGNOSTICS - m_value.object->operator[](it.key()).m_parent = this; -#endif - } - } - - /// @brief exchanges the values - /// @sa https://json.nlohmann.me/api/basic_json/swap/ - void swap(reference other) noexcept ( - std::is_nothrow_move_constructible::value&& - std::is_nothrow_move_assignable::value&& - std::is_nothrow_move_constructible::value&& - std::is_nothrow_move_assignable::value - ) - { - std::swap(m_type, other.m_type); - std::swap(m_value, other.m_value); - - set_parents(); - other.set_parents(); - assert_invariant(); - } - - /// @brief exchanges the values - /// @sa https://json.nlohmann.me/api/basic_json/swap/ - friend void swap(reference left, reference right) noexcept ( - std::is_nothrow_move_constructible::value&& - std::is_nothrow_move_assignable::value&& - std::is_nothrow_move_constructible::value&& - std::is_nothrow_move_assignable::value - ) - { - left.swap(right); - } - - /// @brief exchanges the values - /// @sa https://json.nlohmann.me/api/basic_json/swap/ - void swap(array_t& other) // NOLINT(bugprone-exception-escape) - { - // swap only works for arrays - if (JSON_HEDLEY_LIKELY(is_array())) - { - std::swap(*(m_value.array), other); - } - else - { - JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()), *this)); - } - } - - /// @brief exchanges the values - /// @sa https://json.nlohmann.me/api/basic_json/swap/ - void swap(object_t& other) // NOLINT(bugprone-exception-escape) - { - // swap only works for objects - if (JSON_HEDLEY_LIKELY(is_object())) - { - std::swap(*(m_value.object), other); - } - else - { - JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()), *this)); - } - } - - /// @brief exchanges the values - /// @sa https://json.nlohmann.me/api/basic_json/swap/ - void swap(string_t& other) // NOLINT(bugprone-exception-escape) - { - // swap only works for strings - if (JSON_HEDLEY_LIKELY(is_string())) - { - std::swap(*(m_value.string), other); - } - else - { - JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()), *this)); - } - } - - /// @brief exchanges the values - /// @sa https://json.nlohmann.me/api/basic_json/swap/ - void swap(binary_t& other) // NOLINT(bugprone-exception-escape) - { - // swap only works for strings - if (JSON_HEDLEY_LIKELY(is_binary())) - { - std::swap(*(m_value.binary), other); - } - else - { - JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()), *this)); - } - } - - /// @brief exchanges the values - /// @sa https://json.nlohmann.me/api/basic_json/swap/ - void swap(typename binary_t::container_type& other) // NOLINT(bugprone-exception-escape) - { - // swap only works for strings - if (JSON_HEDLEY_LIKELY(is_binary())) - { - std::swap(*(m_value.binary), other); - } - else - { - JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()), *this)); - } - } - - /// @} - - public: - ////////////////////////////////////////// - // lexicographical comparison operators // - ////////////////////////////////////////// - - /// @name lexicographical comparison operators - /// @{ - - /// @brief comparison: equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ - friend bool operator==(const_reference lhs, const_reference rhs) noexcept - { -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wfloat-equal" -#endif - const auto lhs_type = lhs.type(); - const auto rhs_type = rhs.type(); - - if (lhs_type == rhs_type) - { - switch (lhs_type) - { - case value_t::array: - return *lhs.m_value.array == *rhs.m_value.array; - - case value_t::object: - return *lhs.m_value.object == *rhs.m_value.object; - - case value_t::null: - return true; - - case value_t::string: - return *lhs.m_value.string == *rhs.m_value.string; - - case value_t::boolean: - return lhs.m_value.boolean == rhs.m_value.boolean; - - case value_t::number_integer: - return lhs.m_value.number_integer == rhs.m_value.number_integer; - - case value_t::number_unsigned: - return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned; - - case value_t::number_float: - return lhs.m_value.number_float == rhs.m_value.number_float; - - case value_t::binary: - return *lhs.m_value.binary == *rhs.m_value.binary; - - case value_t::discarded: - default: - return false; - } - } - else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float) - { - return static_cast(lhs.m_value.number_integer) == rhs.m_value.number_float; - } - else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer) - { - return lhs.m_value.number_float == static_cast(rhs.m_value.number_integer); - } - else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float) - { - return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_float; - } - else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned) - { - return lhs.m_value.number_float == static_cast(rhs.m_value.number_unsigned); - } - else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer) - { - return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer; - } - else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned) - { - return lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned); - } - - return false; -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif - } - - /// @brief comparison: equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ - template::value, int>::type = 0> - friend bool operator==(const_reference lhs, ScalarType rhs) noexcept - { - return lhs == basic_json(rhs); - } - - /// @brief comparison: equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/ - template::value, int>::type = 0> - friend bool operator==(ScalarType lhs, const_reference rhs) noexcept - { - return basic_json(lhs) == rhs; - } - - /// @brief comparison: not equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ - friend bool operator!=(const_reference lhs, const_reference rhs) noexcept - { - return !(lhs == rhs); - } - - /// @brief comparison: not equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ - template::value, int>::type = 0> - friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept - { - return lhs != basic_json(rhs); - } - - /// @brief comparison: not equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/ - template::value, int>::type = 0> - friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept - { - return basic_json(lhs) != rhs; - } - - /// @brief comparison: less than - /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ - friend bool operator<(const_reference lhs, const_reference rhs) noexcept - { - const auto lhs_type = lhs.type(); - const auto rhs_type = rhs.type(); - - if (lhs_type == rhs_type) - { - switch (lhs_type) - { - case value_t::array: - // note parentheses are necessary, see - // https://github.com/nlohmann/json/issues/1530 - return (*lhs.m_value.array) < (*rhs.m_value.array); - - case value_t::object: - return (*lhs.m_value.object) < (*rhs.m_value.object); - - case value_t::null: - return false; - - case value_t::string: - return (*lhs.m_value.string) < (*rhs.m_value.string); - - case value_t::boolean: - return (lhs.m_value.boolean) < (rhs.m_value.boolean); - - case value_t::number_integer: - return (lhs.m_value.number_integer) < (rhs.m_value.number_integer); - - case value_t::number_unsigned: - return (lhs.m_value.number_unsigned) < (rhs.m_value.number_unsigned); - - case value_t::number_float: - return (lhs.m_value.number_float) < (rhs.m_value.number_float); - - case value_t::binary: - return (*lhs.m_value.binary) < (*rhs.m_value.binary); - - case value_t::discarded: - default: - return false; - } - } - else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float) - { - return static_cast(lhs.m_value.number_integer) < rhs.m_value.number_float; - } - else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer) - { - return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); - } - else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float) - { - return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_float; - } - else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned) - { - return lhs.m_value.number_float < static_cast(rhs.m_value.number_unsigned); - } - else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned) - { - return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); - } - else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer) - { - return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; - } - - // We only reach this line if we cannot compare values. In that case, - // we compare types. Note we have to call the operator explicitly, - // because MSVC has problems otherwise. - return operator<(lhs_type, rhs_type); - } - - /// @brief comparison: less than - /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ - template::value, int>::type = 0> - friend bool operator<(const_reference lhs, ScalarType rhs) noexcept - { - return lhs < basic_json(rhs); - } - - /// @brief comparison: less than - /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/ - template::value, int>::type = 0> - friend bool operator<(ScalarType lhs, const_reference rhs) noexcept - { - return basic_json(lhs) < rhs; - } - - /// @brief comparison: less than or equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ - friend bool operator<=(const_reference lhs, const_reference rhs) noexcept - { - return !(rhs < lhs); - } - - /// @brief comparison: less than or equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ - template::value, int>::type = 0> - friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept - { - return lhs <= basic_json(rhs); - } - - /// @brief comparison: less than or equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_le/ - template::value, int>::type = 0> - friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept - { - return basic_json(lhs) <= rhs; - } - - /// @brief comparison: greater than - /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ - friend bool operator>(const_reference lhs, const_reference rhs) noexcept - { - return !(lhs <= rhs); - } - - /// @brief comparison: greater than - /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ - template::value, int>::type = 0> - friend bool operator>(const_reference lhs, ScalarType rhs) noexcept - { - return lhs > basic_json(rhs); - } - - /// @brief comparison: greater than - /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/ - template::value, int>::type = 0> - friend bool operator>(ScalarType lhs, const_reference rhs) noexcept - { - return basic_json(lhs) > rhs; - } - - /// @brief comparison: greater than or equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ - friend bool operator>=(const_reference lhs, const_reference rhs) noexcept - { - return !(lhs < rhs); - } - - /// @brief comparison: greater than or equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ - template::value, int>::type = 0> - friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept - { - return lhs >= basic_json(rhs); - } - - /// @brief comparison: greater than or equal - /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/ - template::value, int>::type = 0> - friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept - { - return basic_json(lhs) >= rhs; - } - - /// @} - - /////////////////// - // serialization // - /////////////////// - - /// @name serialization - /// @{ -#ifndef JSON_NO_IO - /// @brief serialize to stream - /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/ - friend std::ostream& operator<<(std::ostream& o, const basic_json& j) - { - // read width member and use it as indentation parameter if nonzero - const bool pretty_print = o.width() > 0; - const auto indentation = pretty_print ? o.width() : 0; - - // reset width to 0 for subsequent calls to this stream - o.width(0); - - // do the actual serialization - serializer s(detail::output_adapter(o), o.fill()); - s.dump(j, pretty_print, false, static_cast(indentation)); - return o; - } - - /// @brief serialize to stream - /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/ - /// @deprecated This function is deprecated since 3.0.0 and will be removed in - /// version 4.0.0 of the library. Please use - /// operator<<(std::ostream&, const basic_json&) instead; that is, - /// replace calls like `j >> o;` with `o << j;`. - JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator<<(std::ostream&, const basic_json&)) - friend std::ostream& operator>>(const basic_json& j, std::ostream& o) - { - return o << j; - } -#endif // JSON_NO_IO - /// @} - - - ///////////////////// - // deserialization // - ///////////////////// - - /// @name deserialization - /// @{ - - /// @brief deserialize from a compatible input - /// @sa https://json.nlohmann.me/api/basic_json/parse/ - template - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json parse(InputType&& i, - const parser_callback_t cb = nullptr, - const bool allow_exceptions = true, - const bool ignore_comments = false) - { - basic_json result; - parser(detail::input_adapter(std::forward(i)), cb, allow_exceptions, ignore_comments).parse(true, result); - return result; - } - - /// @brief deserialize from a pair of character iterators - /// @sa https://json.nlohmann.me/api/basic_json/parse/ - template - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json parse(IteratorType first, - IteratorType last, - const parser_callback_t cb = nullptr, - const bool allow_exceptions = true, - const bool ignore_comments = false) - { - basic_json result; - parser(detail::input_adapter(std::move(first), std::move(last)), cb, allow_exceptions, ignore_comments).parse(true, result); - return result; - } - - JSON_HEDLEY_WARN_UNUSED_RESULT - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len)) - static basic_json parse(detail::span_input_adapter&& i, - const parser_callback_t cb = nullptr, - const bool allow_exceptions = true, - const bool ignore_comments = false) - { - basic_json result; - parser(i.get(), cb, allow_exceptions, ignore_comments).parse(true, result); - return result; - } - - /// @brief check if the input is valid JSON - /// @sa https://json.nlohmann.me/api/basic_json/accept/ - template - static bool accept(InputType&& i, - const bool ignore_comments = false) - { - return parser(detail::input_adapter(std::forward(i)), nullptr, false, ignore_comments).accept(true); - } - - /// @brief check if the input is valid JSON - /// @sa https://json.nlohmann.me/api/basic_json/accept/ - template - static bool accept(IteratorType first, IteratorType last, - const bool ignore_comments = false) - { - return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments).accept(true); - } - - JSON_HEDLEY_WARN_UNUSED_RESULT - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len)) - static bool accept(detail::span_input_adapter&& i, - const bool ignore_comments = false) - { - return parser(i.get(), nullptr, false, ignore_comments).accept(true); - } - - /// @brief generate SAX events - /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/ - template - JSON_HEDLEY_NON_NULL(2) - static bool sax_parse(InputType&& i, SAX* sax, - input_format_t format = input_format_t::json, - const bool strict = true, - const bool ignore_comments = false) - { - auto ia = detail::input_adapter(std::forward(i)); - return format == input_format_t::json - ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) - : detail::binary_reader(std::move(ia)).sax_parse(format, sax, strict); - } - - /// @brief generate SAX events - /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/ - template - JSON_HEDLEY_NON_NULL(3) - static bool sax_parse(IteratorType first, IteratorType last, SAX* sax, - input_format_t format = input_format_t::json, - const bool strict = true, - const bool ignore_comments = false) - { - auto ia = detail::input_adapter(std::move(first), std::move(last)); - return format == input_format_t::json - ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) - : detail::binary_reader(std::move(ia)).sax_parse(format, sax, strict); - } - - /// @brief generate SAX events - /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/ - /// @deprecated This function is deprecated since 3.8.0 and will be removed in - /// version 4.0.0 of the library. Please use - /// sax_parse(ptr, ptr + len) instead. - template - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...)) - JSON_HEDLEY_NON_NULL(2) - static bool sax_parse(detail::span_input_adapter&& i, SAX* sax, - input_format_t format = input_format_t::json, - const bool strict = true, - const bool ignore_comments = false) - { - auto ia = i.get(); - return format == input_format_t::json - // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) - // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - : detail::binary_reader(std::move(ia)).sax_parse(format, sax, strict); - } -#ifndef JSON_NO_IO - /// @brief deserialize from stream - /// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/ - /// @deprecated This stream operator is deprecated since 3.0.0 and will be removed in - /// version 4.0.0 of the library. Please use - /// operator>>(std::istream&, basic_json&) instead; that is, - /// replace calls like `j << i;` with `i >> j;`. - JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator>>(std::istream&, basic_json&)) - friend std::istream& operator<<(basic_json& j, std::istream& i) - { - return operator>>(i, j); - } - - /// @brief deserialize from stream - /// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/ - friend std::istream& operator>>(std::istream& i, basic_json& j) - { - parser(detail::input_adapter(i)).parse(false, j); - return i; - } -#endif // JSON_NO_IO - /// @} - - /////////////////////////// - // convenience functions // - /////////////////////////// - - /// @brief return the type as string - /// @sa https://json.nlohmann.me/api/basic_json/type_name/ - JSON_HEDLEY_RETURNS_NON_NULL - const char* type_name() const noexcept - { - switch (m_type) - { - case value_t::null: - return "null"; - case value_t::object: - return "object"; - case value_t::array: - return "array"; - case value_t::string: - return "string"; - case value_t::boolean: - return "boolean"; - case value_t::binary: - return "binary"; - case value_t::discarded: - return "discarded"; - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - default: - return "number"; - } - } - - - JSON_PRIVATE_UNLESS_TESTED: - ////////////////////// - // member variables // - ////////////////////// - - /// the type of the current element - value_t m_type = value_t::null; - - /// the value of the current element - json_value m_value = {}; - -#if JSON_DIAGNOSTICS - /// a pointer to a parent value (for debugging purposes) - basic_json* m_parent = nullptr; -#endif - - ////////////////////////////////////////// - // binary serialization/deserialization // - ////////////////////////////////////////// - - /// @name binary serialization/deserialization support - /// @{ - - public: - /// @brief create a CBOR serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/ - static std::vector to_cbor(const basic_json& j) - { - std::vector result; - to_cbor(j, result); - return result; - } - - /// @brief create a CBOR serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/ - static void to_cbor(const basic_json& j, detail::output_adapter o) - { - binary_writer(o).write_cbor(j); - } - - /// @brief create a CBOR serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/ - static void to_cbor(const basic_json& j, detail::output_adapter o) - { - binary_writer(o).write_cbor(j); - } - - /// @brief create a MessagePack serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/ - static std::vector to_msgpack(const basic_json& j) - { - std::vector result; - to_msgpack(j, result); - return result; - } - - /// @brief create a MessagePack serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/ - static void to_msgpack(const basic_json& j, detail::output_adapter o) - { - binary_writer(o).write_msgpack(j); - } - - /// @brief create a MessagePack serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/ - static void to_msgpack(const basic_json& j, detail::output_adapter o) - { - binary_writer(o).write_msgpack(j); - } - - /// @brief create a UBJSON serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/ - static std::vector to_ubjson(const basic_json& j, - const bool use_size = false, - const bool use_type = false) - { - std::vector result; - to_ubjson(j, result, use_size, use_type); - return result; - } - - /// @brief create a UBJSON serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/ - static void to_ubjson(const basic_json& j, detail::output_adapter o, - const bool use_size = false, const bool use_type = false) - { - binary_writer(o).write_ubjson(j, use_size, use_type); - } - - /// @brief create a UBJSON serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/ - static void to_ubjson(const basic_json& j, detail::output_adapter o, - const bool use_size = false, const bool use_type = false) - { - binary_writer(o).write_ubjson(j, use_size, use_type); - } - - /// @brief create a BSON serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_bson/ - static std::vector to_bson(const basic_json& j) - { - std::vector result; - to_bson(j, result); - return result; - } - - /// @brief create a BSON serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_bson/ - static void to_bson(const basic_json& j, detail::output_adapter o) - { - binary_writer(o).write_bson(j); - } - - /// @brief create a BSON serialization of a given JSON value - /// @sa https://json.nlohmann.me/api/basic_json/to_bson/ - static void to_bson(const basic_json& j, detail::output_adapter o) - { - binary_writer(o).write_bson(j); - } - - /// @brief create a JSON value from an input in CBOR format - /// @sa https://json.nlohmann.me/api/basic_json/from_cbor/ - template - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_cbor(InputType&& i, - const bool strict = true, - const bool allow_exceptions = true, - const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) - { - basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); - auto ia = detail::input_adapter(std::forward(i)); - const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); - return res ? result : basic_json(value_t::discarded); - } - - /// @brief create a JSON value from an input in CBOR format - /// @sa https://json.nlohmann.me/api/basic_json/from_cbor/ - template - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_cbor(IteratorType first, IteratorType last, - const bool strict = true, - const bool allow_exceptions = true, - const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) - { - basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); - auto ia = detail::input_adapter(std::move(first), std::move(last)); - const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); - return res ? result : basic_json(value_t::discarded); - } - - template - JSON_HEDLEY_WARN_UNUSED_RESULT - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) - static basic_json from_cbor(const T* ptr, std::size_t len, - const bool strict = true, - const bool allow_exceptions = true, - const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) - { - return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler); - } - - - JSON_HEDLEY_WARN_UNUSED_RESULT - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) - static basic_json from_cbor(detail::span_input_adapter&& i, - const bool strict = true, - const bool allow_exceptions = true, - const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) - { - basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); - auto ia = i.get(); - // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); - return res ? result : basic_json(value_t::discarded); - } - - /// @brief create a JSON value from an input in MessagePack format - /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/ - template - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_msgpack(InputType&& i, - const bool strict = true, - const bool allow_exceptions = true) - { - basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); - auto ia = detail::input_adapter(std::forward(i)); - const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict); - return res ? result : basic_json(value_t::discarded); - } - - /// @brief create a JSON value from an input in MessagePack format - /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/ - template - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_msgpack(IteratorType first, IteratorType last, - const bool strict = true, - const bool allow_exceptions = true) - { - basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); - auto ia = detail::input_adapter(std::move(first), std::move(last)); - const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict); - return res ? result : basic_json(value_t::discarded); - } - - template - JSON_HEDLEY_WARN_UNUSED_RESULT - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) - static basic_json from_msgpack(const T* ptr, std::size_t len, - const bool strict = true, - const bool allow_exceptions = true) - { - return from_msgpack(ptr, ptr + len, strict, allow_exceptions); - } - - JSON_HEDLEY_WARN_UNUSED_RESULT - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) - static basic_json from_msgpack(detail::span_input_adapter&& i, - const bool strict = true, - const bool allow_exceptions = true) - { - basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); - auto ia = i.get(); - // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict); - return res ? result : basic_json(value_t::discarded); - } - - /// @brief create a JSON value from an input in UBJSON format - /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/ - template - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_ubjson(InputType&& i, - const bool strict = true, - const bool allow_exceptions = true) - { - basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); - auto ia = detail::input_adapter(std::forward(i)); - const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict); - return res ? result : basic_json(value_t::discarded); - } - - /// @brief create a JSON value from an input in UBJSON format - /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/ - template - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_ubjson(IteratorType first, IteratorType last, - const bool strict = true, - const bool allow_exceptions = true) - { - basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); - auto ia = detail::input_adapter(std::move(first), std::move(last)); - const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict); - return res ? result : basic_json(value_t::discarded); - } - - template - JSON_HEDLEY_WARN_UNUSED_RESULT - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) - static basic_json from_ubjson(const T* ptr, std::size_t len, - const bool strict = true, - const bool allow_exceptions = true) - { - return from_ubjson(ptr, ptr + len, strict, allow_exceptions); - } - - JSON_HEDLEY_WARN_UNUSED_RESULT - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) - static basic_json from_ubjson(detail::span_input_adapter&& i, - const bool strict = true, - const bool allow_exceptions = true) - { - basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); - auto ia = i.get(); - // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict); - return res ? result : basic_json(value_t::discarded); - } - - /// @brief create a JSON value from an input in BSON format - /// @sa https://json.nlohmann.me/api/basic_json/from_bson/ - template - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_bson(InputType&& i, - const bool strict = true, - const bool allow_exceptions = true) - { - basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); - auto ia = detail::input_adapter(std::forward(i)); - const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict); - return res ? result : basic_json(value_t::discarded); - } - - /// @brief create a JSON value from an input in BSON format - /// @sa https://json.nlohmann.me/api/basic_json/from_bson/ - template - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_bson(IteratorType first, IteratorType last, - const bool strict = true, - const bool allow_exceptions = true) - { - basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); - auto ia = detail::input_adapter(std::move(first), std::move(last)); - const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict); - return res ? result : basic_json(value_t::discarded); - } - - template - JSON_HEDLEY_WARN_UNUSED_RESULT - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) - static basic_json from_bson(const T* ptr, std::size_t len, - const bool strict = true, - const bool allow_exceptions = true) - { - return from_bson(ptr, ptr + len, strict, allow_exceptions); - } - - JSON_HEDLEY_WARN_UNUSED_RESULT - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) - static basic_json from_bson(detail::span_input_adapter&& i, - const bool strict = true, - const bool allow_exceptions = true) - { - basic_json result; - detail::json_sax_dom_parser sdp(result, allow_exceptions); - auto ia = i.get(); - // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) - const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict); - return res ? result : basic_json(value_t::discarded); - } - /// @} - - ////////////////////////// - // JSON Pointer support // - ////////////////////////// - - /// @name JSON Pointer functions - /// @{ - - /// @brief access specified element via JSON Pointer - /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ - reference operator[](const json_pointer& ptr) - { - return ptr.get_unchecked(this); - } - - /// @brief access specified element via JSON Pointer - /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ - const_reference operator[](const json_pointer& ptr) const - { - return ptr.get_unchecked(this); - } - - /// @brief access specified element via JSON Pointer - /// @sa https://json.nlohmann.me/api/basic_json/at/ - reference at(const json_pointer& ptr) - { - return ptr.get_checked(this); - } - - /// @brief access specified element via JSON Pointer - /// @sa https://json.nlohmann.me/api/basic_json/at/ - const_reference at(const json_pointer& ptr) const - { - return ptr.get_checked(this); - } - - /// @brief return flattened JSON value - /// @sa https://json.nlohmann.me/api/basic_json/flatten/ - basic_json flatten() const - { - basic_json result(value_t::object); - json_pointer::flatten("", *this, result); - return result; - } - - /// @brief unflatten a previously flattened JSON value - /// @sa https://json.nlohmann.me/api/basic_json/unflatten/ - basic_json unflatten() const - { - return json_pointer::unflatten(*this); - } - - /// @} - - ////////////////////////// - // JSON Patch functions // - ////////////////////////// - - /// @name JSON Patch functions - /// @{ - - /// @brief applies a JSON patch - /// @sa https://json.nlohmann.me/api/basic_json/patch/ - basic_json patch(const basic_json& json_patch) const - { - // make a working copy to apply the patch to - basic_json result = *this; - - // the valid JSON Patch operations - enum class patch_operations {add, remove, replace, move, copy, test, invalid}; - - const auto get_op = [](const std::string & op) - { - if (op == "add") - { - return patch_operations::add; - } - if (op == "remove") - { - return patch_operations::remove; - } - if (op == "replace") - { - return patch_operations::replace; - } - if (op == "move") - { - return patch_operations::move; - } - if (op == "copy") - { - return patch_operations::copy; - } - if (op == "test") - { - return patch_operations::test; - } - - return patch_operations::invalid; - }; - - // wrapper for "add" operation; add value at ptr - const auto operation_add = [&result](json_pointer & ptr, basic_json val) - { - // adding to the root of the target document means replacing it - if (ptr.empty()) - { - result = val; - return; - } - - // make sure the top element of the pointer exists - json_pointer top_pointer = ptr.top(); - if (top_pointer != ptr) - { - result.at(top_pointer); - } - - // get reference to parent of JSON pointer ptr - const auto last_path = ptr.back(); - ptr.pop_back(); - basic_json& parent = result[ptr]; - - switch (parent.m_type) - { - case value_t::null: - case value_t::object: - { - // use operator[] to add value - parent[last_path] = val; - break; - } - - case value_t::array: - { - if (last_path == "-") - { - // special case: append to back - parent.push_back(val); - } - else - { - const auto idx = json_pointer::array_index(last_path); - if (JSON_HEDLEY_UNLIKELY(idx > parent.size())) - { - // avoid undefined behavior - JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range", parent)); - } - - // default case: insert add offset - parent.insert(parent.begin() + static_cast(idx), val); - } - break; - } - - // if there exists a parent it cannot be primitive - case value_t::string: // LCOV_EXCL_LINE - case value_t::boolean: // LCOV_EXCL_LINE - case value_t::number_integer: // LCOV_EXCL_LINE - case value_t::number_unsigned: // LCOV_EXCL_LINE - case value_t::number_float: // LCOV_EXCL_LINE - case value_t::binary: // LCOV_EXCL_LINE - case value_t::discarded: // LCOV_EXCL_LINE - default: // LCOV_EXCL_LINE - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE - } - }; - - // wrapper for "remove" operation; remove value at ptr - const auto operation_remove = [this, &result](json_pointer & ptr) - { - // get reference to parent of JSON pointer ptr - const auto last_path = ptr.back(); - ptr.pop_back(); - basic_json& parent = result.at(ptr); - - // remove child - if (parent.is_object()) - { - // perform range check - auto it = parent.find(last_path); - if (JSON_HEDLEY_LIKELY(it != parent.end())) - { - parent.erase(it); - } - else - { - JSON_THROW(out_of_range::create(403, "key '" + last_path + "' not found", *this)); - } - } - else if (parent.is_array()) - { - // note erase performs range check - parent.erase(json_pointer::array_index(last_path)); - } - }; - - // type check: top level value must be an array - if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array())) - { - JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", json_patch)); - } - - // iterate and apply the operations - for (const auto& val : json_patch) - { - // wrapper to get a value for an operation - const auto get_value = [&val](const std::string & op, - const std::string & member, - bool string_type) -> basic_json & - { - // find value - auto it = val.m_value.object->find(member); - - // context-sensitive error message - const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'"; - - // check if desired value is present - if (JSON_HEDLEY_UNLIKELY(it == val.m_value.object->end())) - { - // NOLINTNEXTLINE(performance-inefficient-string-concatenation) - JSON_THROW(parse_error::create(105, 0, error_msg + " must have member '" + member + "'", val)); - } - - // check if result is of type string - if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string())) - { - // NOLINTNEXTLINE(performance-inefficient-string-concatenation) - JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'", val)); - } - - // no error: return value - return it->second; - }; - - // type check: every element of the array must be an object - if (JSON_HEDLEY_UNLIKELY(!val.is_object())) - { - JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", val)); - } - - // collect mandatory members - const auto op = get_value("op", "op", true).template get(); - const auto path = get_value(op, "path", true).template get(); - json_pointer ptr(path); - - switch (get_op(op)) - { - case patch_operations::add: - { - operation_add(ptr, get_value("add", "value", false)); - break; - } - - case patch_operations::remove: - { - operation_remove(ptr); - break; - } - - case patch_operations::replace: - { - // the "path" location must exist - use at() - result.at(ptr) = get_value("replace", "value", false); - break; - } - - case patch_operations::move: - { - const auto from_path = get_value("move", "from", true).template get(); - json_pointer from_ptr(from_path); - - // the "from" location must exist - use at() - basic_json v = result.at(from_ptr); - - // The move operation is functionally identical to a - // "remove" operation on the "from" location, followed - // immediately by an "add" operation at the target - // location with the value that was just removed. - operation_remove(from_ptr); - operation_add(ptr, v); - break; - } - - case patch_operations::copy: - { - const auto from_path = get_value("copy", "from", true).template get(); - const json_pointer from_ptr(from_path); - - // the "from" location must exist - use at() - basic_json v = result.at(from_ptr); - - // The copy is functionally identical to an "add" - // operation at the target location using the value - // specified in the "from" member. - operation_add(ptr, v); - break; - } - - case patch_operations::test: - { - bool success = false; - JSON_TRY - { - // check if "value" matches the one at "path" - // the "path" location must exist - use at() - success = (result.at(ptr) == get_value("test", "value", false)); - } - JSON_INTERNAL_CATCH (out_of_range&) - { - // ignore out of range errors: success remains false - } - - // throw an exception if test fails - if (JSON_HEDLEY_UNLIKELY(!success)) - { - JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump(), val)); - } - - break; - } - - case patch_operations::invalid: - default: - { - // op must be "add", "remove", "replace", "move", "copy", or - // "test" - JSON_THROW(parse_error::create(105, 0, "operation value '" + op + "' is invalid", val)); - } - } - } - - return result; - } - - /// @brief creates a diff as a JSON patch - /// @sa https://json.nlohmann.me/api/basic_json/diff/ - JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json diff(const basic_json& source, const basic_json& target, - const std::string& path = "") - { - // the patch - basic_json result(value_t::array); - - // if the values are the same, return empty patch - if (source == target) - { - return result; - } - - if (source.type() != target.type()) - { - // different types: replace value - result.push_back( - { - {"op", "replace"}, {"path", path}, {"value", target} - }); - return result; - } - - switch (source.type()) - { - case value_t::array: - { - // first pass: traverse common elements - std::size_t i = 0; - while (i < source.size() && i < target.size()) - { - // recursive call to compare array values at index i - auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); - result.insert(result.end(), temp_diff.begin(), temp_diff.end()); - ++i; - } - - // We now reached the end of at least one array - // in a second pass, traverse the remaining elements - - // remove my remaining elements - const auto end_index = static_cast(result.size()); - while (i < source.size()) - { - // add operations in reverse order to avoid invalid - // indices - result.insert(result.begin() + end_index, object( - { - {"op", "remove"}, - {"path", path + "/" + std::to_string(i)} - })); - ++i; - } - - // add other remaining elements - while (i < target.size()) - { - result.push_back( - { - {"op", "add"}, - {"path", path + "/-"}, - {"value", target[i]} - }); - ++i; - } - - break; - } - - case value_t::object: - { - // first pass: traverse this object's elements - for (auto it = source.cbegin(); it != source.cend(); ++it) - { - // escape the key name to be used in a JSON patch - const auto path_key = path + "/" + detail::escape(it.key()); - - if (target.find(it.key()) != target.end()) - { - // recursive call to compare object values at key it - auto temp_diff = diff(it.value(), target[it.key()], path_key); - result.insert(result.end(), temp_diff.begin(), temp_diff.end()); - } - else - { - // found a key that is not in o -> remove it - result.push_back(object( - { - {"op", "remove"}, {"path", path_key} - })); - } - } - - // second pass: traverse other object's elements - for (auto it = target.cbegin(); it != target.cend(); ++it) - { - if (source.find(it.key()) == source.end()) - { - // found a key that is not in this -> add it - const auto path_key = path + "/" + detail::escape(it.key()); - result.push_back( - { - {"op", "add"}, {"path", path_key}, - {"value", it.value()} - }); - } - } - - break; - } - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - // both primitive type: replace value - result.push_back( - { - {"op", "replace"}, {"path", path}, {"value", target} - }); - break; - } - } - - return result; - } - - /// @} - - //////////////////////////////// - // JSON Merge Patch functions // - //////////////////////////////// - - /// @name JSON Merge Patch functions - /// @{ - - /// @brief applies a JSON Merge Patch - /// @sa https://json.nlohmann.me/api/basic_json/merge_patch/ - void merge_patch(const basic_json& apply_patch) - { - if (apply_patch.is_object()) - { - if (!is_object()) - { - *this = object(); - } - for (auto it = apply_patch.begin(); it != apply_patch.end(); ++it) - { - if (it.value().is_null()) - { - erase(it.key()); - } - else - { - operator[](it.key()).merge_patch(it.value()); - } - } - } - else - { - *this = apply_patch; - } - } - - /// @} -}; - -/// @brief user-defined to_string function for JSON values -/// @sa https://json.nlohmann.me/api/basic_json/to_string/ -NLOHMANN_BASIC_JSON_TPL_DECLARATION -std::string to_string(const NLOHMANN_BASIC_JSON_TPL& j) -{ - return j.dump(); -} - -} // namespace nlohmann - -/////////////////////// -// nonmember support // -/////////////////////// - -namespace std // NOLINT(cert-dcl58-cpp) -{ - -/// @brief hash value for JSON objects -/// @sa https://json.nlohmann.me/api/basic_json/std_hash/ -NLOHMANN_BASIC_JSON_TPL_DECLARATION -struct hash -{ - std::size_t operator()(const nlohmann::NLOHMANN_BASIC_JSON_TPL& j) const - { - return nlohmann::detail::hash(j); - } -}; - -// specialization for std::less -template<> -struct less< ::nlohmann::detail::value_t> // do not remove the space after '<', see https://github.com/nlohmann/json/pull/679 -{ - /*! - @brief compare two value_t enum values - @since version 3.0.0 - */ - bool operator()(nlohmann::detail::value_t lhs, - nlohmann::detail::value_t rhs) const noexcept - { - return nlohmann::detail::operator<(lhs, rhs); - } -}; - -// C++20 prohibit function specialization in the std namespace. -#ifndef JSON_HAS_CPP_20 - -/// @brief exchanges the values of two JSON objects -/// @sa https://json.nlohmann.me/api/basic_json/std_swap/ -NLOHMANN_BASIC_JSON_TPL_DECLARATION -inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC_JSON_TPL& j2) noexcept( // NOLINT(readability-inconsistent-declaration-parameter-name) - is_nothrow_move_constructible::value&& // NOLINT(misc-redundant-expression) - is_nothrow_move_assignable::value) -{ - j1.swap(j2); -} - -#endif - -} // namespace std - -/// @brief user-defined string literal for JSON values -/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json/ -JSON_HEDLEY_NON_NULL(1) -inline nlohmann::json operator "" _json(const char* s, std::size_t n) -{ - return nlohmann::json::parse(s, s + n); -} - -/// @brief user-defined string literal for JSON pointer -/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json_pointer/ -JSON_HEDLEY_NON_NULL(1) -inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n) -{ - return nlohmann::json::json_pointer(std::string(s, n)); -} - -// #include - - -// restore clang diagnostic settings -#if defined(__clang__) - #pragma clang diagnostic pop -#endif - -// clean up -#undef JSON_ASSERT -#undef JSON_INTERNAL_CATCH -#undef JSON_CATCH -#undef JSON_THROW -#undef JSON_TRY -#undef JSON_PRIVATE_UNLESS_TESTED -#undef JSON_HAS_CPP_11 -#undef JSON_HAS_CPP_14 -#undef JSON_HAS_CPP_17 -#undef JSON_HAS_CPP_20 -#undef JSON_HAS_FILESYSTEM -#undef JSON_HAS_EXPERIMENTAL_FILESYSTEM -#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION -#undef NLOHMANN_BASIC_JSON_TPL -#undef JSON_EXPLICIT -#undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL - -// #include - - -#undef JSON_HEDLEY_ALWAYS_INLINE -#undef JSON_HEDLEY_ARM_VERSION -#undef JSON_HEDLEY_ARM_VERSION_CHECK -#undef JSON_HEDLEY_ARRAY_PARAM -#undef JSON_HEDLEY_ASSUME -#undef JSON_HEDLEY_BEGIN_C_DECLS -#undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE -#undef JSON_HEDLEY_CLANG_HAS_BUILTIN -#undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE -#undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE -#undef JSON_HEDLEY_CLANG_HAS_EXTENSION -#undef JSON_HEDLEY_CLANG_HAS_FEATURE -#undef JSON_HEDLEY_CLANG_HAS_WARNING -#undef JSON_HEDLEY_COMPCERT_VERSION -#undef JSON_HEDLEY_COMPCERT_VERSION_CHECK -#undef JSON_HEDLEY_CONCAT -#undef JSON_HEDLEY_CONCAT3 -#undef JSON_HEDLEY_CONCAT3_EX -#undef JSON_HEDLEY_CONCAT_EX -#undef JSON_HEDLEY_CONST -#undef JSON_HEDLEY_CONSTEXPR -#undef JSON_HEDLEY_CONST_CAST -#undef JSON_HEDLEY_CPP_CAST -#undef JSON_HEDLEY_CRAY_VERSION -#undef JSON_HEDLEY_CRAY_VERSION_CHECK -#undef JSON_HEDLEY_C_DECL -#undef JSON_HEDLEY_DEPRECATED -#undef JSON_HEDLEY_DEPRECATED_FOR -#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL -#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ -#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED -#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES -#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS -#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION -#undef JSON_HEDLEY_DIAGNOSTIC_POP -#undef JSON_HEDLEY_DIAGNOSTIC_PUSH -#undef JSON_HEDLEY_DMC_VERSION -#undef JSON_HEDLEY_DMC_VERSION_CHECK -#undef JSON_HEDLEY_EMPTY_BASES -#undef JSON_HEDLEY_EMSCRIPTEN_VERSION -#undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK -#undef JSON_HEDLEY_END_C_DECLS -#undef JSON_HEDLEY_FLAGS -#undef JSON_HEDLEY_FLAGS_CAST -#undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE -#undef JSON_HEDLEY_GCC_HAS_BUILTIN -#undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE -#undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE -#undef JSON_HEDLEY_GCC_HAS_EXTENSION -#undef JSON_HEDLEY_GCC_HAS_FEATURE -#undef JSON_HEDLEY_GCC_HAS_WARNING -#undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK -#undef JSON_HEDLEY_GCC_VERSION -#undef JSON_HEDLEY_GCC_VERSION_CHECK -#undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE -#undef JSON_HEDLEY_GNUC_HAS_BUILTIN -#undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE -#undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE -#undef JSON_HEDLEY_GNUC_HAS_EXTENSION -#undef JSON_HEDLEY_GNUC_HAS_FEATURE -#undef JSON_HEDLEY_GNUC_HAS_WARNING -#undef JSON_HEDLEY_GNUC_VERSION -#undef JSON_HEDLEY_GNUC_VERSION_CHECK -#undef JSON_HEDLEY_HAS_ATTRIBUTE -#undef JSON_HEDLEY_HAS_BUILTIN -#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE -#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS -#undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE -#undef JSON_HEDLEY_HAS_EXTENSION -#undef JSON_HEDLEY_HAS_FEATURE -#undef JSON_HEDLEY_HAS_WARNING -#undef JSON_HEDLEY_IAR_VERSION -#undef JSON_HEDLEY_IAR_VERSION_CHECK -#undef JSON_HEDLEY_IBM_VERSION -#undef JSON_HEDLEY_IBM_VERSION_CHECK -#undef JSON_HEDLEY_IMPORT -#undef JSON_HEDLEY_INLINE -#undef JSON_HEDLEY_INTEL_CL_VERSION -#undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK -#undef JSON_HEDLEY_INTEL_VERSION -#undef JSON_HEDLEY_INTEL_VERSION_CHECK -#undef JSON_HEDLEY_IS_CONSTANT -#undef JSON_HEDLEY_IS_CONSTEXPR_ -#undef JSON_HEDLEY_LIKELY -#undef JSON_HEDLEY_MALLOC -#undef JSON_HEDLEY_MCST_LCC_VERSION -#undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK -#undef JSON_HEDLEY_MESSAGE -#undef JSON_HEDLEY_MSVC_VERSION -#undef JSON_HEDLEY_MSVC_VERSION_CHECK -#undef JSON_HEDLEY_NEVER_INLINE -#undef JSON_HEDLEY_NON_NULL -#undef JSON_HEDLEY_NO_ESCAPE -#undef JSON_HEDLEY_NO_RETURN -#undef JSON_HEDLEY_NO_THROW -#undef JSON_HEDLEY_NULL -#undef JSON_HEDLEY_PELLES_VERSION -#undef JSON_HEDLEY_PELLES_VERSION_CHECK -#undef JSON_HEDLEY_PGI_VERSION -#undef JSON_HEDLEY_PGI_VERSION_CHECK -#undef JSON_HEDLEY_PREDICT -#undef JSON_HEDLEY_PRINTF_FORMAT -#undef JSON_HEDLEY_PRIVATE -#undef JSON_HEDLEY_PUBLIC -#undef JSON_HEDLEY_PURE -#undef JSON_HEDLEY_REINTERPRET_CAST -#undef JSON_HEDLEY_REQUIRE -#undef JSON_HEDLEY_REQUIRE_CONSTEXPR -#undef JSON_HEDLEY_REQUIRE_MSG -#undef JSON_HEDLEY_RESTRICT -#undef JSON_HEDLEY_RETURNS_NON_NULL -#undef JSON_HEDLEY_SENTINEL -#undef JSON_HEDLEY_STATIC_ASSERT -#undef JSON_HEDLEY_STATIC_CAST -#undef JSON_HEDLEY_STRINGIFY -#undef JSON_HEDLEY_STRINGIFY_EX -#undef JSON_HEDLEY_SUNPRO_VERSION -#undef JSON_HEDLEY_SUNPRO_VERSION_CHECK -#undef JSON_HEDLEY_TINYC_VERSION -#undef JSON_HEDLEY_TINYC_VERSION_CHECK -#undef JSON_HEDLEY_TI_ARMCL_VERSION -#undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK -#undef JSON_HEDLEY_TI_CL2000_VERSION -#undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK -#undef JSON_HEDLEY_TI_CL430_VERSION -#undef JSON_HEDLEY_TI_CL430_VERSION_CHECK -#undef JSON_HEDLEY_TI_CL6X_VERSION -#undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK -#undef JSON_HEDLEY_TI_CL7X_VERSION -#undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK -#undef JSON_HEDLEY_TI_CLPRU_VERSION -#undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK -#undef JSON_HEDLEY_TI_VERSION -#undef JSON_HEDLEY_TI_VERSION_CHECK -#undef JSON_HEDLEY_UNAVAILABLE -#undef JSON_HEDLEY_UNLIKELY -#undef JSON_HEDLEY_UNPREDICTABLE -#undef JSON_HEDLEY_UNREACHABLE -#undef JSON_HEDLEY_UNREACHABLE_RETURN -#undef JSON_HEDLEY_VERSION -#undef JSON_HEDLEY_VERSION_DECODE_MAJOR -#undef JSON_HEDLEY_VERSION_DECODE_MINOR -#undef JSON_HEDLEY_VERSION_DECODE_REVISION -#undef JSON_HEDLEY_VERSION_ENCODE -#undef JSON_HEDLEY_WARNING -#undef JSON_HEDLEY_WARN_UNUSED_RESULT -#undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG -#undef JSON_HEDLEY_FALL_THROUGH - - - -#endif // INCLUDE_NLOHMANN_JSON_HPP_ diff --git a/src-libhv/docs/API.md b/src-libhv/docs/API.md deleted file mode 100644 index ac9cdebc4..000000000 --- a/src-libhv/docs/API.md +++ /dev/null @@ -1,506 +0,0 @@ -# libhv API Manual - -## base - -### hplatform.h -- OS: OS_WIN, OS_UNIX (OS_LINUX, OS_ANDROID, OS_DARWIN ...) -- ARCH: ARCH_X86, ARCH_X64, ARCH_ARM, ARCH_ARM64 -- COMPILER: COMPILER_MSVC, COMPILER_MINGW, COMPILER_GCC, COMPILER_CLANG -- BYTE_ORDER: BIG_ENDIAN, LITTLE_ENDIAN -- stdbool.h: bool, true, false -- stdint.h: int8_t, int16_t, int32_t, int64_t -- hv_sleep, hv_msleep, hv_usleep, hv_delay -- hv_mkdir -- stricmp, strcasecmp - -### hexport.h -- HV_EXPORT, HV_INLINE -- HV_SOURCE, HV_STATICLIB, HV_DYNAMICLIB -- HV_DEPRECATED -- HV_UNUSED -- EXTERN_C, BEGIN_EXTERN_C, END_EXTERN_C -- BEGIN_NAMESPACE, END_NAMESPACE, USING_NAMESPACE -- DEFAULT -- ENUM, STRUCT -- IN, OUT, INOUT -- OPTIONAL, REQUIRED, REPEATED - -### hdef.h -- ABS, NABS -- ARRAY_SIZE -- BITSET, BITCLR, BITGET -- CR, LF, CRLF -- FLOAT_EQUAL_ZERO -- INFINITE -- IS_ALPHA, IS_NUM, IS_ALPHANUM -- IS_CNTRL, IS_GRAPH -- IS_HEX -- IS_LOWER, IS_UPPER -- LOWER, UPPER -- LD, LU, LLD, LLU -- MAKEWORD, LOBYTE, HIBYTE -- MAKELONG, LOWORD, HIWORD -- MAKEINT64, LOINT, HIINT -- MAKE_FOURCC -- MAX, MIN, LIMIT -- MAX_PATH -- NULL, TRUE, FALSE -- SAFE_FREE, SAFE_DELETE, SAFE_DELETE_ARRAY, SAFE_RELEASE -- STRINGCAT -- STRINGIFY -- offsetof, offsetofend -- container_of -- prefetch -- printd, printe - -### hatomic.h -- hatomic_flag_t, hatomic_t -- hatomic_flag_test_and_set -- hatomic_flag_clear -- hatomic_add -- hatomic_sub -- hatomic_inc -- hatomic_dec - -### herr.h -- hv_strerror - -### htime.h -- IS_LEAP_YEAR -- datetime_t -- gettick_ms -- gettimeofday -- gettimeofday_ms -- gettimeofday_us -- gethrtime_us -- datetime_now -- datetime_mktime -- datetime_past -- datetime_future -- duration_fmt -- datetime_fmt -- gmtime_fmt -- days_of_month -- month_atoi -- month_itoa -- weekday_atoi -- weekday_itoa -- hv_compile_datetime -- cron_next_timeout - -### hmath.h -- floor2e -- ceil2e - -### hbase.h -- safe_malloc -- safe_calloc -- safe_realloc -- safe_zalloc -- safe_strncpy -- safe_strncat -- strlower -- strupper -- strreverse -- strstartswith -- strendswith -- strcontains -- strlcpy -- strlcat -- strrchr_dot -- strrchr_dir -- hv_basename -- hv_suffixname -- hv_mkdir_p -- hv_rmdir_p -- getboolean -- get_executable_path -- get_executable_dir -- get_executable_file -- get_run_dir - -### hversion.h -- hv_version -- hv_compile_version -- version_atoi -- version_itoa - -### hsysinfo.h -- get_ncpu -- get_meminfo - -### hproc.h -- hproc_spawn - -### hthread.h -- hv_getpid -- hv_gettid -- HTHREAD_RETTYPE -- HTHREAD_ROUTINE -- hthread_create -- hthread_join -- class HThread - -### hmutex.h -- hmutex_t -- hmutex_init -- hmutex_destroy -- hmutex_lock -- hmutex_unlock -- hspinlock_t -- hspinlock_init -- hspinlock_destroy -- hspinlock_lock -- hspinlock_unlock -- hrwlock_t -- hrwlock_init -- hrwlock_destroy -- hrwlock_rdlock -- hrwlock_rdunlock -- hrwlock_wrlock -- hrwlock_wrunlock -- htimed_mutex_t -- htimed_mutex_init -- htimed_mutex_destroy -- htimed_mutex_lock -- htimed_mutex_lock_for -- htimed_mutex_unlock -- hcondvar_t -- hcondvar_init -- hcondvar_destroy -- hcondvar_wait -- hcondvar_wait_for -- hcondvar_signal -- hcondvar_broadcast -- hsem_init -- hsem_destroy -- hsem_wait -- hsem_post -- hsem_timedwait -- honce_t -- HONCE_INIT -- honce -- class `hv::MutexLock` -- class `hv::SpinLock` -- class `hv::RWLock` -- class `hv::LockGuard` -- synchronized - -### hsocket.h -- INVALID_SOCKET -- closesocket -- blocking -- nonblocking -- Bind -- Listen -- Connect -- ConnectNonblock -- ConnectTimeout -- Resolver -- Socketpair -- socket_errno -- socket_strerror -- sockaddr_u -- sockaddr_ip -- sockaddr_port -- sockaddr_set_ip -- sockaddr_set_port -- sockaddr_set_ipport -- sockaddr_len -- sockaddr_str -- sockaddr_print -- SOCKADDR_LEN -- SOCKADDR_STR -- SOCKADDR_PRINT -- tcp_nodelay -- tcp_nopush -- tcp_keepalive -- udp_broadcast -- so_sndtimeo -- so_rcvtimeo - -### hlog.h -- default_logger -- file_logger -- stderr_logger -- stdout_logger -- logger_create -- logger_destroy -- logger_enable_color -- logger_enable_fsync -- logger_fsync -- logger_print -- logger_set_file -- logger_set_handler -- logger_set_level -- logger_set_max_bufsize -- logger_set_max_filesize -- logger_set_remain_days -- logger_get_cur_file -- hlogd, hlogi, hlogw, hloge, hlogf -- LOGD, LOGI, LOGW, LOGE, LOGF - -### hbuf.h -- hbuf_t -- offset_buf_t -- class HBuf -- class HVLBuf -- class HRingBuf - -### hstring.h -- asprintf -- trim -- trimL -- trimR -- trim_pairs -- split -- splitKV -- replace -- basename -- dirname -- filename -- suffixname -- hv::to_string -- hv::from_string - -### hfile.h -- class HFile - -### hdir.h -- listdir - -### hurl.h -- url_escape -- url_unescape - -### hscope.h -- defer -- template ScopeCleanup -- template ScopeFree -- template ScopeDelete -- template ScopeDeleteArray -- template ScopeRelease -- template ScopeLock - -### ifconfig.h -- ifconfig - -## utils -### md5.h -- MD5Init -- MD5Update -- MD5Final - -### base64.h -- base64_decode -- base64_encode - -### json.hpp - -### hmain.h -- main_ctx_init -- parse_opt -- parse_opt_long -- get_arg -- get_env -- setproctitle -- signal_init -- signal_handle -- signal_handler -- create_pidfile -- delete_pidfile -- getpid_form_pidfile -- master_workers_run - -### singleton.h -- DISABLE_COPY -- SINGLETON_DECL -- SINGLETON_IMPL - -## event - -### hloop.h -- hloop_create_tcp_client -- hloop_create_tcp_server -- hloop_create_udp_client -- hloop_create_udp_server -- hloop_create_ssl_client -- hloop_create_ssl_server -- hloop_new -- hloop_free -- hloop_run -- hloop_stop -- hloop_pause -- hloop_resume -- hloop_now -- hloop_now_ms -- hloop_now_hrtime -- hloop_update_time -- hloop_set_userdata -- hloop_userdata -- hloop_post_event -- hevent_loop -- hevent_type -- hevent_id -- hevent_priority -- hevent_userdata -- hevent_set_priority -- hevent_ser_userdata -- haccept -- hconnect -- hread -- hwrite -- hrecv -- hsend -- hrecvfrom -- hsendto -- hio_add -- hio_del -- hio_get -- hio_read -- hio_write -- hio_close -- hio_accept -- hio_connect -- hio_fd -- hio_type -- hio_error -- hio_localaddr -- hio_peeraddr -- hio_setcb_accept -- hio_setcb_connect -- hio_setcb_read -- hio_setcb_write -- hio_setcb_close -- hio_set_localaddr -- hio_set_peeraddr -- hio_set_readbuf -- hio_set_type -- hio_enable_ssl -- htimer_add -- htimer_add_period -- htimer_del -- htimer_reset -- hidle_add -- hidle_del - -### nlog.h -- network_logger -- nlog_listen - -### nmap.h -- nmap_discover -- segment_discover -- host_discover - -## evpp -- class Buffer -- class Channel -- class Event -- class EventLoop -- class EventLoopThread -- class EventLoopThreadPool -- class TcpClient -- class TcpServer -- class UdpClient -- class UdpServer - -## protocol - -### dns.h -- dns_name_decode -- dns_name_encode -- dns_pack -- dns_unpack -- dns_rr_pack -- dns_rr_unpack -- dns_query -- dns_free -- nslookup - -### ftp.h -- ftp_command_str -- ftp_connect -- ftp_login -- ftp_exec -- ftp_upload -- ftp_download -- ftp_download_with_cb -- ftp_quit -- ftp_status_str - -### smtp.h -- smtp_command_str -- smtp_status_str -- smtp_build_command -- sendmail - -### icmp.h -- ping - -## http -- class HttpMessage -- class HttpRequest -- class HttpResponse -- class HttpParser -- class HttpService - -### httpdef.h -- http_content_type_enum -- http_content_type_enum_by_suffix -- http_content_type_str -- http_content_type_str_by_suffix -- http_content_type_suffix -- http_errno_description -- http_errno_name -- http_method_enum -- http_method_str -- http_status_enum -- http_status_str - -### http_content.h -- parse_query_params -- parse_json -- parse_multipart -- dump_query_params -- dump_json -- dump_multipart - -### http_client.h -- http_client_new -- http_client_del -- http_client_send -- http_client_send_async -- http_client_strerror -- http_client_set_timeout -- http_client_set_header -- http_client_del_header -- http_client_get_header -- http_client_clear_headers - -### requests.h -- requests::request -- requests::get -- requests::post -- requests::put -- requests::patch -- requests::Delete -- requests::head -- requests::options -- requests::async - -### HttpServer.h -- http_server_run -- http_server_stop - -### WebSocketClient.h -- class WebSocketClient - -### WebSocketServer.h -- websocket_server_run -- websocket_server_stop - -## other -- class HThreadPool -- class HObjectPool -- class ThreadLocalStorage diff --git a/src-libhv/docs/PLAN.md b/src-libhv/docs/PLAN.md deleted file mode 100644 index 6d46328f6..000000000 --- a/src-libhv/docs/PLAN.md +++ /dev/null @@ -1,15 +0,0 @@ -## Done - -- event: select/poll/epoll/kqueue/port -- evpp: c++ EventLoop interface similar to muduo and evpp -- http client/server: include https http1/x http2 -- websocket client/server - -## Improving - -- IOCP: fix bug, add SSL/TLS support - -## Plan - -- mqtt client -- redis client diff --git a/src-libhv/echo-servers/asio_echo.cpp b/src-libhv/echo-servers/asio_echo.cpp deleted file mode 100644 index 8a435f515..000000000 --- a/src-libhv/echo-servers/asio_echo.cpp +++ /dev/null @@ -1,105 +0,0 @@ -// -// async_tcp_echo_server.cpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// 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) -// -#include -#include -#include -#include - -using boost::asio::ip::tcp; - -class session { -public: - session(boost::asio::io_service& io_service) : - socket_(io_service) { - } - - tcp::socket& socket() { - return socket_; - } - - void start() { - socket_.async_read_some(boost::asio::buffer(data_, max_length), - boost::bind(&session::handle_read, this, - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); - } - - void handle_read(const boost::system::error_code& error, - size_t bytes_transferred) { - if (!error) { - boost::asio::async_write(socket_, boost::asio::buffer(data_, - bytes_transferred), boost::bind(&session::handle_write, - this, boost::asio::placeholders::error)); - } else { - delete this; - } - } - - void handle_write(const boost::system::error_code& error) { - if (!error) { - socket_.async_read_some(boost::asio::buffer(data_, max_length), - boost::bind(&session::handle_read, this, - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); - } else { - delete this; - } - } - -private: - tcp::socket socket_; - enum { - max_length = 1024 - }; - char data_[max_length]; -}; - -class server { -public: - server(boost::asio::io_service& io_service, short port) : - io_service_(io_service), acceptor_(io_service, tcp::endpoint(tcp::v4(), - port)) { - session* new_session = new session(io_service_); - acceptor_.async_accept(new_session->socket(), boost::bind( - &server::handle_accept, this, new_session, - boost::asio::placeholders::error)); - } - - void handle_accept(session* new_session, - const boost::system::error_code& error) { - if (!error) { - new_session->start(); - new_session = new session(io_service_); - acceptor_.async_accept(new_session->socket(), boost::bind( - &server::handle_accept, this, new_session, - boost::asio::placeholders::error)); - } else { - delete new_session; - } - } - -private: - boost::asio::io_service& io_service_; - tcp::acceptor acceptor_; -}; - -int main(int argc, char** argv) { - if (argc < 2) { - printf("Usage: cmd port\n"); - return -10; - } - int port = atoi(argv[1]); - - boost::asio::io_service io_service; - server s(io_service, port); - io_service.run(); - - return 0; -} diff --git a/src-libhv/echo-servers/benchmark.sh b/src-libhv/echo-servers/benchmark.sh deleted file mode 100755 index af91ddc36..000000000 --- a/src-libhv/echo-servers/benchmark.sh +++ /dev/null @@ -1,86 +0,0 @@ -#!/bin/bash - -host=127.0.0.1 -port=2000 -client=2 -time=10 - -while getopts 'h:p:c:t:' opt -do - case $opt in - h) host=$OPTARG;; - p) port=$OPTARG;; - c) client=$OPTARG;; - t) time=$OPTARG;; - *) exit -1;; - esac -done - -SCRIPT_DIR=$(cd `dirname $0`; pwd) -cd ${SCRIPT_DIR}/.. - -killall_echo_servers() { - #sudo killall libevent_echo libev_echo libuv_echo libhv_echo asio_echo poco_echo muduo_echo - if [ $(ps aux | grep _echo | grep -v grep | wc -l) -gt 0 ]; then - ps aux | grep _echo | grep -v grep | awk '{print $2}' | xargs sudo kill -9 - fi -} - -export LD_LIBRARY_PATH=lib:$LD_LIBRARY_PATH - -killall_echo_servers - -sport=$port - -if [ -x bin/libevent_echo ]; then - let port++ - bin/libevent_echo $port & - echo "libevent running on port $port" -fi - -if [ -x bin/libev_echo ]; then - let port++ - bin/libev_echo $port & - echo "libev running on port $port" -fi - -if [ -x bin/libuv_echo ]; then - let port++ - bin/libuv_echo $port & - echo "libuv running on port $port" -fi - -if [ -x bin/libhv_echo ]; then - let port++ - bin/libhv_echo $port & - echo "libhv running on port $port" -fi - -if [ -x bin/asio_echo ]; then - let port++ - bin/asio_echo $port & - echo "asio running on port $port" -fi - -if [ -x bin/poco_echo ]; then - let port++ - bin/poco_echo $port & - echo "poco running on port $port" -fi - -if [ -x bin/muduo_echo ]; then - let port++ - bin/muduo_echo $port & - echo "muduo running on port $port" -fi - -sleep 1 - -for ((p=$sport+1; p<=$port; ++p)); do - echo -e "\n==============$p=====================================" - # bin/webbench -q -c $client -t $time $host:$p - bin/pingpong_client -H $host -p $p - sleep 1 -done - -killall_echo_servers diff --git a/src-libhv/echo-servers/build.sh b/src-libhv/echo-servers/build.sh deleted file mode 100755 index 513e20c52..000000000 --- a/src-libhv/echo-servers/build.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash - -SCRIPT_DIR=$(cd `dirname $0`; pwd) -ROOT_DIR=${SCRIPT_DIR}/.. - -# install libevent libev libuv asio poco -UNAME=$(uname -a) -case ${UNAME} in - *Ubuntu*|*Debian*) - sudo apt install libevent-dev libev-dev libuv1-dev libboost-dev libboost-system-dev libasio-dev libpoco-dev - ;; - *CentOS*) - sudo yum install libevent-devel libev-devel libuv-devel boost-devel asio-devel poco-devel - ;; - *Darwin*) - brew install libevent libev libuv boost asio poco - ;; - *) - echo 'please install libevent libev libuv boost asio poco' - ;; -esac - -# install muduo => https://github.com/chenshuo/muduo.git -if false; then -cd ${ROOT_DIR}/.. -git clone https://github.com/chenshuo/muduo.git -cd muduo -mkdir build && cd build -cmake .. && make && sudo make install -fi - -cd ${ROOT_DIR} -make libhv && sudo make install -make echo-servers -make webbench diff --git a/src-libhv/echo-servers/libev_echo.c b/src-libhv/echo-servers/libev_echo.c deleted file mode 100644 index cb1295cfd..000000000 --- a/src-libhv/echo-servers/libev_echo.c +++ /dev/null @@ -1,78 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include - -#include "ev.h" - -#define RECV_BUFSIZE 8192 -static char recvbuf[RECV_BUFSIZE]; - -void do_recv(struct ev_loop *loop, struct ev_io *io, int revents) { - int nread, nsend; - nread = recv(io->fd, recvbuf, RECV_BUFSIZE, 0); - if (nread <= 0) { - goto error; - } - nsend = send(io->fd, recvbuf, nread, 0); - if (nsend != nread) { - goto error; - } - return; - -error: - ev_io_stop(loop, io); - close(io->fd); - free(io); -} - -void do_accept(struct ev_loop *loop, struct ev_io *listenio, int revents) { - struct sockaddr_in peeraddr; - socklen_t addrlen = sizeof(peeraddr); - int connfd = accept(listenio->fd, (struct sockaddr*)&peeraddr, &addrlen); - if (connfd <= 0) { - return; - } - - struct ev_io* io = (struct ev_io*)malloc(sizeof(struct ev_io)); - ev_io_init(io, do_recv, connfd, EV_READ); - ev_io_start(loop, io); -} - -int main(int argc, char** argv) { - if (argc < 2) { - printf("Usage: cmd port\n"); - return -10; - } - int port = atoi(argv[1]); - - struct sockaddr_in addr; - int addrlen = sizeof(addr); - memset(&addr, 0, addrlen); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - int listenfd = socket(AF_INET, SOCK_STREAM, 0); - if (listenfd < 0) { - return -20; - } - if (bind(listenfd, (struct sockaddr*)&addr, addrlen) < 0) { - return -30; - } - if (listen(listenfd, SOMAXCONN) < 0) { - return -40; - } - - struct ev_loop* loop = ev_loop_new(0); - - struct ev_io listenio; - ev_io_init(&listenio, do_accept, listenfd, EV_READ); - ev_io_start(loop, &listenio); - - ev_run(loop, 0); - ev_loop_destroy(loop); - return 0; -} diff --git a/src-libhv/echo-servers/libevent_echo.c b/src-libhv/echo-servers/libevent_echo.c deleted file mode 100644 index 5c8e266d6..000000000 --- a/src-libhv/echo-servers/libevent_echo.c +++ /dev/null @@ -1,61 +0,0 @@ -#include -#include -#include - -#include "event2/event.h" -#include "event2/listener.h" -#include "event2/bufferevent.h" -#include "event2/buffer.h" - -//#define RECV_BUFSIZE 8192 - -void error_cb(struct bufferevent* bev, short event, void* userdata) { - bufferevent_free(bev); -} - -void read_cb(struct bufferevent* bev, void* userdata) { - //static char recvbuf[RECV_BUFSIZE]; - //int nread = bufferevent_read(bev, &recvbuf, RECV_BUFSIZE); - //bufferevent_write(bev, recvbuf, nread); - struct evbuffer* buf = evbuffer_new(); - int ret = bufferevent_read_buffer(bev, buf); - if (ret == 0) { - bufferevent_write_buffer(bev, buf); - } - evbuffer_free(buf); -} - -void on_accept(struct evconnlistener* listener, evutil_socket_t connfd, struct sockaddr* peeraddr, int addrlen, void* userdata) { - struct event_base* loop = evconnlistener_get_base(listener); - struct bufferevent* bev = bufferevent_socket_new(loop, connfd, BEV_OPT_CLOSE_ON_FREE); - bufferevent_setcb(bev, read_cb, NULL, error_cb, NULL); - bufferevent_enable(bev, EV_READ|EV_WRITE|EV_PERSIST); -} - -int main(int argc, char** argv) { - if (argc < 2) { - printf("Usage: cmd port\n"); - return -10; - } - int port = atoi(argv[1]); - - struct event_base* loop = event_base_new(); - - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - struct evconnlistener* listener = evconnlistener_new_bind( - loop, on_accept, NULL, - LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, - -1, (struct sockaddr*)&addr, sizeof(addr)); - if (listener == NULL) { - return -20; - } - - event_base_dispatch(loop); - - evconnlistener_free(listener); - event_base_free(loop); - return 0; -} diff --git a/src-libhv/echo-servers/libhv_echo.c b/src-libhv/echo-servers/libhv_echo.c deleted file mode 100644 index 8cfc153e8..000000000 --- a/src-libhv/echo-servers/libhv_echo.c +++ /dev/null @@ -1,31 +0,0 @@ -#include "hv/hloop.h" - -void on_close(hio_t* io) { -} - -void on_recv(hio_t* io, void* buf, int readbytes) { - hio_write(io, buf, readbytes); -} - -void on_accept(hio_t* io) { - hio_setcb_close(io, on_close); - hio_setcb_read(io, on_recv); - hio_read(io); -} - -int main(int argc, char** argv) { - if (argc < 2) { - printf("Usage: cmd port\n"); - return -10; - } - int port = atoi(argv[1]); - - hloop_t* loop = hloop_new(0); - hio_t* listenio = hloop_create_tcp_server(loop, "0.0.0.0", port, on_accept); - if (listenio == NULL) { - return -20; - } - hloop_run(loop); - hloop_free(&loop); - return 0; -} diff --git a/src-libhv/echo-servers/libuv_echo.c b/src-libhv/echo-servers/libuv_echo.c deleted file mode 100644 index abc7d1884..000000000 --- a/src-libhv/echo-servers/libuv_echo.c +++ /dev/null @@ -1,75 +0,0 @@ -#define _GNU_SOURCE 1 -#include -#include -#include - -#include "uv.h" - -typedef struct { - uv_write_t req; - uv_buf_t buf; -} uv_write_req_t; - -void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { - buf->base = (char*)malloc(suggested_size); - buf->len = suggested_size; -} - -void close_cb(uv_handle_t* handle) { - free(handle); -} - -void write_cb(uv_write_t* req, int status) { - uv_write_req_t* wr = (uv_write_req_t*)req; - free(wr->buf.base); - free(wr); -} - -void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { - if (nread <= 0) { - uv_close((uv_handle_t*)stream, close_cb); - return; - } - uv_write_req_t* wr = (uv_write_req_t*)malloc(sizeof(uv_write_req_t)); - wr->buf.base = buf->base; - wr->buf.len = nread; - uv_write(&wr->req, stream, &wr->buf, 1, write_cb); -} - -void do_accept(uv_stream_t* server, int status) { - uv_tcp_t* tcp_stream = (uv_tcp_t*)malloc(sizeof(uv_tcp_t)); - uv_tcp_init(server->loop, tcp_stream); - uv_accept(server, (uv_stream_t*)tcp_stream); - uv_read_start((uv_stream_t*)tcp_stream, alloc_cb, read_cb); -} - -int main(int argc, char** argv) { - if (argc < 2) { - printf("Usage: cmd port\n"); - return -10; - } - int port = atoi(argv[1]); - - uv_loop_t loop; - uv_loop_init(&loop); - - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - //addr.sin_family = AF_INET; - //addr.sin_port = htons(port); - uv_ip4_addr("0.0.0.0", port, &addr); - - uv_tcp_t tcp_server; - uv_tcp_init(&loop, &tcp_server); - int ret = uv_tcp_bind(&tcp_server, (struct sockaddr*)&addr, 0); - if (ret) { - return -20; - } - ret = uv_listen((uv_stream_t*)&tcp_server, SOMAXCONN, do_accept); - if (ret) { - return -30; - } - - uv_run(&loop, UV_RUN_DEFAULT); - return 0; -} diff --git a/src-libhv/echo-servers/muduo_echo.cpp b/src-libhv/echo-servers/muduo_echo.cpp deleted file mode 100644 index 60e440273..000000000 --- a/src-libhv/echo-servers/muduo_echo.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// @see muduo/examples/simple/echo -#include "muduo/base/Logging.h" -#include "muduo/net/EventLoop.h" -#include "muduo/net/InetAddress.h" -#include "muduo/net/TcpServer.h" - -using std::placeholders::_1; -using std::placeholders::_2; -using std::placeholders::_3; - -using muduo::Timestamp; - -using muduo::net::EventLoop; -using muduo::net::InetAddress; -using muduo::net::TcpServer; -using muduo::net::TcpConnectionPtr; -using muduo::net::Buffer; - -class EchoTcpServer { -public: - EchoTcpServer(EventLoop* loop, const InetAddress& addr) - : server_(loop, addr, "EchoTcpServer") - { - server_.setConnectionCallback(std::bind(&EchoTcpServer::onConnection, this, _1)); - server_.setMessageCallback(std::bind(&EchoTcpServer::onMessage, this, _1, _2, _3)); - } - - void start() { - server_.start(); - } - -private: - void onConnection(const TcpConnectionPtr& conn) { - } - - void onMessage(const TcpConnectionPtr& conn, - Buffer* buf, Timestamp time) { - muduo::string msg(buf->retrieveAllAsString()); - conn->send(msg); - } - - TcpServer server_; -}; - -int main(int argc, char** argv) { - if (argc < 2) { - printf("Usage: cmd port\n"); - return -10; - } - int port = atoi(argv[1]); - - muduo::g_logLevel = muduo::Logger::ERROR; - muduo::net::EventLoop loop; - - muduo::net::InetAddress addr(port); - EchoTcpServer server(&loop, addr); - server.start(); - - loop.loop(); - - return 0; -} diff --git a/src-libhv/echo-servers/pingpong_client.cpp b/src-libhv/echo-servers/pingpong_client.cpp deleted file mode 100644 index 8eb1a455f..000000000 --- a/src-libhv/echo-servers/pingpong_client.cpp +++ /dev/null @@ -1,120 +0,0 @@ -#include "hv/hmain.h" -#include "hv/hloop.h" -#include "hv/hsocket.h" - -#include "hv/EventLoopThreadPool.h" -using namespace hv; - -static const char options[] = "hH:p:t:c:s:b:"; - -static const char detail_options[] = R"( - -h Print help - -H default 127.0.0.1 - -p - -t default 4 - -c default 1000 - -s default 10 - -b send buffer size, default 1024 -)"; - -static const char* host = "127.0.0.1"; -static int port = 0; -static int threads = 4; -static int connections = 1000; -static int seconds = 10; -static int sendbytes = 1024; -static void* sendbuf = NULL; - -static std::atomic connected_num(0); -static std::atomic disconnected_num(0); -static std::atomic total_readcount(0); -static std::atomic total_readbytes(0); - -static void print_help() { - printf("Usage: %s [%s]\n", g_main_ctx.program_name, options); - printf("Options:\n%s\n", detail_options); -} - -static void print_result() { - printf("total readcount=%llu readbytes=%llu\n", - (unsigned long long)total_readcount, - (unsigned long long)total_readbytes); - printf("throughput = %llu MB/s\n", (total_readbytes) / ((unsigned long long)seconds * 1024 * 1024)); -} - -static void on_close(hio_t* io) { - if (++disconnected_num == connections) { - printf("all disconnected\n"); - } -} - -void on_recv(hio_t* io, void* buf, int readbytes) { - ++total_readcount; - total_readbytes += readbytes; - hio_write(io, buf, readbytes); -} - -static void on_connect(hio_t* io) { - if (++connected_num == connections) { - printf("all connected\n"); - } - - tcp_nodelay(hio_fd(io), 1); - hio_setcb_read(io, on_recv); - hio_setcb_close(io, on_close); - hio_read_start(io); - - hio_write(io, sendbuf, sendbytes); -} - -int main(int argc, char** argv) { - // parse cmdline - main_ctx_init(argc, argv); - int ret = parse_opt(argc, argv, options); - if (ret != 0) { - print_help(); - exit(ret); - } - const char* strHost = get_arg("H"); - const char* strPort = get_arg("p"); - const char* strThreads = get_arg("t"); - const char* strConnections = get_arg("c"); - const char* strSeconds = get_arg("s"); - const char* strBytes = get_arg("b"); - - if (strHost) host = strHost; - if (strPort) port = atoi(strPort); - if (strThreads) threads = atoi(strThreads); - if (strConnections) connections = atoi(strConnections); - if (strSeconds) seconds = atoi(strSeconds); - if (strBytes) sendbytes = atoi(strBytes); - - if (get_arg("h") || port == 0) { - print_help(); - exit(0); - } - sendbuf = malloc(sendbytes); - - printf("[%s:%d] %d threads %d connections run %ds\n", - host, port, - threads, connections, seconds); - - EventLoopThreadPool loop_threads(threads); - loop_threads.start(true); - for (int i = 0; i < connections; ++i) { - EventLoopPtr loop = loop_threads.nextLoop(); - loop->runInLoop(std::bind(hloop_create_tcp_client, loop->loop(), host, port, on_connect)); - } - - // stop after seconds - loop_threads.loop()->setTimeout(seconds * 1000, [&loop_threads](TimerID timerID){ - loop_threads.stop(false); - }); - - // wait loop_threads exit - loop_threads.join(); - - print_result(); - - return 0; -} diff --git a/src-libhv/echo-servers/poco_echo.cpp b/src-libhv/echo-servers/poco_echo.cpp deleted file mode 100644 index 715184d22..000000000 --- a/src-libhv/echo-servers/poco_echo.cpp +++ /dev/null @@ -1,225 +0,0 @@ -// -// EchoServer.cpp -// -// $Id: //poco/1.3/Net/samples/EchoServer/src/EchoServer.cpp#1 $ -// -// This sample demonstrates the SocketReactor and SocketAcceptor classes. -// -// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH. -// and Contributors. -// -// 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. -// - - -#include "Poco/Net/SocketReactor.h" -#include "Poco/Net/SocketAcceptor.h" -#include "Poco/Net/SocketNotification.h" -#include "Poco/Net/StreamSocket.h" -#include "Poco/Net/ServerSocket.h" -#include "Poco/NObserver.h" -#include "Poco/Exception.h" -#include "Poco/Thread.h" -#include "Poco/Util/ServerApplication.h" -#include "Poco/Util/Option.h" -#include "Poco/Util/OptionSet.h" -#include "Poco/Util/HelpFormatter.h" -#include - - -using Poco::Net::SocketReactor; -using Poco::Net::SocketAcceptor; -using Poco::Net::ReadableNotification; -using Poco::Net::ShutdownNotification; -using Poco::Net::ServerSocket; -using Poco::Net::StreamSocket; -using Poco::NObserver; -using Poco::AutoPtr; -using Poco::Thread; -using Poco::Util::ServerApplication; -using Poco::Util::Application; -using Poco::Util::Option; -using Poco::Util::OptionSet; -using Poco::Util::HelpFormatter; - - -class EchoServiceHandler -{ -public: - EchoServiceHandler(StreamSocket& socket, SocketReactor& reactor): - _socket(socket), - _reactor(reactor), - _pBuffer(new char[BUFFER_SIZE]) - { - // Application& app = Application::instance(); - // app.logger().information("Connection from " + socket.peerAddress().toString()); - - _reactor.addEventHandler(_socket, NObserver(*this, &EchoServiceHandler::onReadable)); - _reactor.addEventHandler(_socket, NObserver(*this, &EchoServiceHandler::onShutdown)); - } - - ~EchoServiceHandler() - { - // Application& app = Application::instance(); - // app.logger().information("Disconnecting " + _socket.peerAddress().toString()); - - _reactor.removeEventHandler(_socket, NObserver(*this, &EchoServiceHandler::onReadable)); - _reactor.removeEventHandler(_socket, NObserver(*this, &EchoServiceHandler::onShutdown)); - delete [] _pBuffer; - } - - void onReadable(const AutoPtr& pNf) - { - int n = _socket.receiveBytes(_pBuffer, BUFFER_SIZE); - if (n > 0) - _socket.sendBytes(_pBuffer, n); - else - delete this; - } - - void onShutdown(const AutoPtr& pNf) - { - delete this; - } - -private: - enum - { - BUFFER_SIZE = 1024 - }; - - StreamSocket _socket; - SocketReactor& _reactor; - char* _pBuffer; -}; - - -class EchoServer: public Poco::Util::ServerApplication - /// The main application class. - /// - /// This class handles command-line arguments and - /// configuration files. - /// Start the EchoServer executable with the help - /// option (/help on Windows, --help on Unix) for - /// the available command line options. - /// - /// To use the sample configuration file (EchoServer.properties), - /// copy the file to the directory where the EchoServer executable - /// resides. If you start the debug version of the EchoServer - /// (EchoServerd[.exe]), you must also create a copy of the configuration - /// file named EchoServerd.properties. In the configuration file, you - /// can specify the port on which the server is listening (default - /// 9977) and the format of the date/time string sent back to the client. - /// - /// To test the EchoServer you can use any telnet client (telnet localhost 9977). -{ -public: - EchoServer(): _helpRequested(false) - { - } - - ~EchoServer() - { - } - -protected: - void initialize(Application& self) - { - loadConfiguration(); // load default configuration files, if present - ServerApplication::initialize(self); - } - - void uninitialize() - { - ServerApplication::uninitialize(); - } - - void defineOptions(OptionSet& options) - { - ServerApplication::defineOptions(options); - - options.addOption( - Option("help", "h", "display help information on command line arguments") - .required(false) - .repeatable(false)); - } - - void handleOption(const std::string& name, const std::string& value) - { - ServerApplication::handleOption(name, value); - - if (name == "help") - _helpRequested = true; - } - - void displayHelp() - { - HelpFormatter helpFormatter(options()); - helpFormatter.setCommand(commandName()); - helpFormatter.setUsage("OPTIONS"); - helpFormatter.setHeader("An echo server implemented using the Reactor and Acceptor patterns."); - helpFormatter.format(std::cout); - } - - int main(const std::vector& args) - { - if (_helpRequested) - { - displayHelp(); - } - else - { - if (args.size() < 1) { - printf("Usage: cmd port\n"); - return -10; - } - int port = atoi(args[0].c_str()); - // set-up a server socket - ServerSocket svs(port); - // set-up a SocketReactor... - SocketReactor reactor; - // ... and a SocketAcceptor - SocketAcceptor acceptor(svs, reactor); - // run the reactor in its own thread so that we can wait for - // a termination request - Thread thread; - thread.start(reactor); - // wait for CTRL-C or kill - waitForTerminationRequest(); - // Stop the SocketReactor - reactor.stop(); - thread.join(); - } - return Application::EXIT_OK; - } - -private: - bool _helpRequested; -}; - - -int main(int argc, char** argv) -{ - EchoServer app; - return app.run(argc, argv); -} diff --git a/src-libhv/event/hevent.c b/src-libhv/event/hevent.c deleted file mode 100644 index 2c72e1502..000000000 --- a/src-libhv/event/hevent.c +++ /dev/null @@ -1,193 +0,0 @@ -#include "hevent.h" -#include "hsocket.h" -#include "hatomic.h" -#include "hlog.h" - -uint64_t hloop_next_event_id() { - static hatomic_t s_id = HATOMIC_VAR_INIT(0); - return ++s_id; -} - -uint32_t hio_next_id() { - static hatomic_t s_id = HATOMIC_VAR_INIT(0); - return ++s_id; -} - -uint32_t hio_id (hio_t* io) { - return io->id; -} - -int hio_fd(hio_t* io) { - return io->fd; -} - -hio_type_e hio_type(hio_t* io) { - return io->io_type; -} - -int hio_error(hio_t* io) { - return io->error; -} - -int hio_events(hio_t* io) { - return io->events; -} - -int hio_revents(hio_t* io) { - return io->revents; -} - -struct sockaddr* hio_localaddr(hio_t* io) { - return io->localaddr; -} - -struct sockaddr* hio_peeraddr(hio_t* io) { - return io->peeraddr; -} - -void hio_set_context(hio_t* io, void* ctx) { - io->ctx = ctx; -} - -void* hio_context(hio_t* io) { - return io->ctx; -} - -haccept_cb hio_getcb_accept(hio_t* io) { - return io->accept_cb; -} - -hconnect_cb hio_getcb_connect(hio_t* io) { - return io->connect_cb; -} - -hread_cb hio_getcb_read(hio_t* io) { - return io->read_cb; -} - -hwrite_cb hio_getcb_write(hio_t* io) { - return io->write_cb; -} - -hclose_cb hio_getcb_close(hio_t* io) { - return io->close_cb; -} - -void hio_setcb_accept (hio_t* io, haccept_cb accept_cb) { - io->accept_cb = accept_cb; -} - -void hio_setcb_connect (hio_t* io, hconnect_cb connect_cb) { - io->connect_cb = connect_cb; -} - -void hio_setcb_read (hio_t* io, hread_cb read_cb) { - io->read_cb = read_cb; -} - -void hio_setcb_write (hio_t* io, hwrite_cb write_cb) { - io->write_cb = write_cb; -} - -void hio_setcb_close (hio_t* io, hclose_cb close_cb) { - io->close_cb = close_cb; -} - -void hio_set_type(hio_t* io, hio_type_e type) { - io->io_type = type; -} - -void hio_set_localaddr(hio_t* io, struct sockaddr* addr, int addrlen) { - if (io->localaddr == NULL) { - HV_ALLOC(io->localaddr, sizeof(sockaddr_u)); - } - memcpy(io->localaddr, addr, addrlen); -} - -void hio_set_peeraddr (hio_t* io, struct sockaddr* addr, int addrlen) { - if (io->peeraddr == NULL) { - HV_ALLOC(io->peeraddr, sizeof(sockaddr_u)); - } - memcpy(io->peeraddr, addr, addrlen); -} - -int hio_enable_ssl(hio_t* io) { - io->io_type = HIO_TYPE_SSL; - return 0; -} - -void hio_set_readbuf(hio_t* io, void* buf, size_t len) { - if (buf == NULL || len == 0) { - hloop_t* loop = io->loop; - if (loop && (loop->readbuf.base == NULL || loop->readbuf.len == 0)) { - loop->readbuf.len = HLOOP_READ_BUFSIZE; - HV_ALLOC(loop->readbuf.base, loop->readbuf.len); - io->readbuf = loop->readbuf; - } - } - else { - io->readbuf.base = (char*)buf; - io->readbuf.len = len; - } -} - -void hio_set_connect_timeout(hio_t* io, int timeout_ms) { - io->connect_timeout = timeout_ms; -} - -void hio_set_close_timeout(hio_t* io, int timeout_ms) { - io->close_timeout = timeout_ms; -} - -static void __keepalive_timeout_cb(htimer_t* timer) { - hio_t* io = (hio_t*)timer->privdata; - if (io) { - char localaddrstr[SOCKADDR_STRLEN] = {0}; - char peeraddrstr[SOCKADDR_STRLEN] = {0}; - hlogw("keepalive timeout [%s] <=> [%s]", - SOCKADDR_STR(io->localaddr, localaddrstr), - SOCKADDR_STR(io->peeraddr, peeraddrstr)); - io->error = ETIMEDOUT; - hio_close(io); - } -} - -void hio_set_keepalive_timeout(hio_t* io, int timeout_ms) { - if (io->keepalive_timer) { - if (timeout_ms == 0) { - htimer_del(io->keepalive_timer); - io->keepalive_timer = NULL; - } else { - ((struct htimeout_s*)io->keepalive_timer)->timeout = timeout_ms; - htimer_reset(io->keepalive_timer); - } - } else { - io->keepalive_timer = htimer_add(io->loop, __keepalive_timeout_cb, timeout_ms, 1); - io->keepalive_timer->privdata = io; - } - io->keepalive_timeout = timeout_ms; -} - -static void __heartbeat_timer_cb(htimer_t* timer) { - hio_t* io = (hio_t*)timer->privdata; - if (io && io->heartbeat_fn) { - io->heartbeat_fn(io); - } -} - -void hio_set_heartbeat(hio_t* io, int interval_ms, hio_send_heartbeat_fn fn) { - if (io->heartbeat_timer) { - if (interval_ms == 0) { - htimer_del(io->heartbeat_timer); - io->heartbeat_timer = NULL; - } else { - ((struct htimeout_s*)io->heartbeat_timer)->timeout = interval_ms; - htimer_reset(io->heartbeat_timer); - } - } else { - io->heartbeat_timer = htimer_add(io->loop, __heartbeat_timer_cb, interval_ms, INFINITE); - io->heartbeat_timer->privdata = io; - } - io->heartbeat_interval = interval_ms; - io->heartbeat_fn = fn; -} diff --git a/src-libhv/event/hloop.h b/src-libhv/event/hloop.h deleted file mode 100644 index 7ddc7fb2c..000000000 --- a/src-libhv/event/hloop.h +++ /dev/null @@ -1,358 +0,0 @@ -#ifndef HV_LOOP_H_ -#define HV_LOOP_H_ - -#include "hexport.h" -#include "hplatform.h" -#include "hdef.h" - -typedef struct hloop_s hloop_t; -typedef struct hevent_s hevent_t; - -// NOTE: The following structures are subclasses of hevent_t, -// inheriting hevent_t data members and function members. -typedef struct hidle_s hidle_t; -typedef struct htimer_s htimer_t; -typedef struct htimeout_s htimeout_t; -typedef struct hperiod_s hperiod_t; -typedef struct hio_s hio_t; - -typedef void (*hevent_cb) (hevent_t* ev); -typedef void (*hidle_cb) (hidle_t* idle); -typedef void (*htimer_cb) (htimer_t* timer); -typedef void (*hio_cb) (hio_t* io); - -typedef void (*haccept_cb) (hio_t* io); -typedef void (*hconnect_cb) (hio_t* io); -typedef void (*hread_cb) (hio_t* io, void* buf, int readbytes); -typedef void (*hwrite_cb) (hio_t* io, const void* buf, int writebytes); -typedef void (*hclose_cb) (hio_t* io); - -typedef enum { - HLOOP_STATUS_STOP, - HLOOP_STATUS_RUNNING, - HLOOP_STATUS_PAUSE -} hloop_status_e; - -typedef enum { - HEVENT_TYPE_NONE = 0, - HEVENT_TYPE_IO = 0x00000001, - HEVENT_TYPE_TIMEOUT = 0x00000010, - HEVENT_TYPE_PERIOD = 0x00000020, - HEVENT_TYPE_TIMER = HEVENT_TYPE_TIMEOUT|HEVENT_TYPE_PERIOD, - HEVENT_TYPE_IDLE = 0x00000100, - HEVENT_TYPE_CUSTOM = 0x00000400, // 1024 -} hevent_type_e; - -#define HEVENT_LOWEST_PRIORITY (-5) -#define HEVENT_LOW_PRIORITY (-3) -#define HEVENT_NORMAL_PRIORITY 0 -#define HEVENT_HIGH_PRIORITY 3 -#define HEVENT_HIGHEST_PRIORITY 5 -#define HEVENT_PRIORITY_SIZE (HEVENT_HIGHEST_PRIORITY-HEVENT_LOWEST_PRIORITY+1) -#define HEVENT_PRIORITY_INDEX(priority) (priority-HEVENT_LOWEST_PRIORITY) - -#define HEVENT_FLAGS \ - unsigned destroy :1; \ - unsigned active :1; \ - unsigned pending :1; - -#define HEVENT_FIELDS \ - hloop_t* loop; \ - hevent_type_e event_type; \ - uint64_t event_id; \ - hevent_cb cb; \ - void* userdata; \ - void* privdata; \ - int priority; \ - struct hevent_s* pending_next; \ - HEVENT_FLAGS - -struct hevent_s { - HEVENT_FIELDS -}; - -#define hevent_set_priority(ev, prio) ((hevent_t*)(ev))->priority = prio -#define hevent_set_userdata(ev, udata) ((hevent_t*)(ev))->userdata = (void*)udata - -#define hevent_loop(ev) (((hevent_t*)(ev))->loop) -#define hevent_type(ev) (((hevent_t*)(ev))->event_type) -#define hevent_id(ev) (((hevent_t*)(ev))->event_id) -#define hevent_priority(ev) (((hevent_t*)(ev))->priority) -#define hevent_userdata(ev) (((hevent_t*)(ev))->userdata) - -typedef enum { - HIO_TYPE_UNKNOWN = 0, - HIO_TYPE_STDIN = 0x00000001, - HIO_TYPE_STDOUT = 0x00000002, - HIO_TYPE_STDERR = 0x00000004, - HIO_TYPE_STDIO = 0x0000000F, - - HIO_TYPE_FILE = 0x00000010, - - HIO_TYPE_IP = 0x00000100, - HIO_TYPE_UDP = 0x00001000, - HIO_TYPE_TCP = 0x00010000, - HIO_TYPE_SSL = 0x00020000, - HIO_TYPE_SOCKET = 0x00FFFF00, -} hio_type_e; - -#define HIO_DEFAULT_CONNECT_TIMEOUT 5000 // ms -#define HIO_DEFAULT_CLOSE_TIMEOUT 60000 // ms -#define HIO_DEFAULT_KEEPALIVE_TIMEOUT 75000 // ms -#define HIO_DEFAULT_HEARTBEAT_INTERVAL 10000 // ms - -BEGIN_EXTERN_C - -// loop -#define HLOOP_FLAG_RUN_ONCE 0x00000001 -#define HLOOP_FLAG_AUTO_FREE 0x00000002 -#define HLOOP_FLAG_QUIT_WHEN_NO_ACTIVE_EVENTS 0x00000004 -HV_EXPORT hloop_t* hloop_new(int flags DEFAULT(HLOOP_FLAG_AUTO_FREE)); - -// WARN: Forbid to call hloop_free if HLOOP_FLAG_AUTO_FREE set. -HV_EXPORT void hloop_free(hloop_t** pp); - -// NOTE: when no active events, loop will quit if HLOOP_FLAG_QUIT_WHEN_NO_ACTIVE_EVENTS set. -HV_EXPORT int hloop_run(hloop_t* loop); -// NOTE: hloop_stop called in loop-thread just set flag to quit in next loop, -// if called in other thread, it will wakeup loop-thread from blocking poll system call, -// then you should join loop thread to safely exit loop thread. -HV_EXPORT int hloop_stop(hloop_t* loop); -HV_EXPORT int hloop_pause(hloop_t* loop); -HV_EXPORT int hloop_resume(hloop_t* loop); -HV_EXPORT int hloop_wakeup(hloop_t* loop); -HV_EXPORT hloop_status_e hloop_status(hloop_t* loop); - -HV_EXPORT void hloop_update_time(hloop_t* loop); -HV_EXPORT uint64_t hloop_now(hloop_t* loop); // s -HV_EXPORT uint64_t hloop_now_ms(hloop_t* loop); // ms -HV_EXPORT uint64_t hloop_now_hrtime(hloop_t* loop); // us -#define hloop_now_us hloop_now_hrtime -// @return pid of hloop_run -HV_EXPORT long hloop_pid(hloop_t* loop); -// @return tid of hloop_run -HV_EXPORT long hloop_tid(hloop_t* loop); - -// userdata -HV_EXPORT void hloop_set_userdata(hloop_t* loop, void* userdata); -HV_EXPORT void* hloop_userdata(hloop_t* loop); - -// custom_event -/* - * hevent_t ev; - * memset(&ev, 0, sizeof(hevent_t)); - * ev.event_type = (hevent_type_e)(HEVENT_TYPE_CUSTOM + 1); - * ev.cb = custom_event_cb; - * ev.userdata = userdata; - * hloop_post_event(loop, &ev); - */ -// NOTE: hloop_post_event is thread-safe, used to post event from other thread to loop thread. -HV_EXPORT void hloop_post_event(hloop_t* loop, hevent_t* ev); - -// idle -HV_EXPORT hidle_t* hidle_add(hloop_t* loop, hidle_cb cb, uint32_t repeat DEFAULT(INFINITE)); -HV_EXPORT void hidle_del(hidle_t* idle); - -// timer -// @param timeout: unit(ms) -HV_EXPORT htimer_t* htimer_add(hloop_t* loop, htimer_cb cb, uint32_t timeout, uint32_t repeat DEFAULT(INFINITE)); -/* - * minute hour day week month cb - * 0~59 0~23 1~31 0~6 1~12 - * 30 -1 -1 -1 -1 cron.hourly - * 30 1 -1 -1 -1 cron.daily - * 30 1 15 -1 -1 cron.monthly - * 30 1 -1 5 -1 cron.weekly - * 30 1 1 -1 10 cron.yearly - */ -HV_EXPORT htimer_t* htimer_add_period(hloop_t* loop, htimer_cb cb, - int8_t minute DEFAULT(0), int8_t hour DEFAULT(-1), int8_t day DEFAULT(-1), - int8_t week DEFAULT(-1), int8_t month DEFAULT(-1), uint32_t repeat DEFAULT(INFINITE)); - -HV_EXPORT void htimer_del(htimer_t* timer); -HV_EXPORT void htimer_reset(htimer_t* timer); - -// io -//-----------------------low-level apis--------------------------------------- -#define HV_READ 0x0001 -#define HV_WRITE 0x0004 -#define HV_RDWR (HV_READ|HV_WRITE) -/* -const char* hio_engine() { -#ifdef EVENT_SELECT - return "select"; -#elif defined(EVENT_POLL) - return "poll"; -#elif defined(EVENT_EPOLL) - return "epoll"; -#elif defined(EVENT_KQUEUE) - return "kqueue"; -#elif defined(EVENT_IOCP) - return "iocp"; -#elif defined(EVENT_PORT) - return "evport"; -#else - return "noevent"; -#endif -} -*/ -HV_EXPORT const char* hio_engine(); - -HV_EXPORT hio_t* hio_get(hloop_t* loop, int fd); -HV_EXPORT int hio_add(hio_t* io, hio_cb cb, int events DEFAULT(HV_READ)); -HV_EXPORT int hio_del(hio_t* io, int events DEFAULT(HV_RDWR)); - -// hio_t fields -// NOTE: fd cannot be used as unique identifier, so we provide an id. -HV_EXPORT uint32_t hio_id (hio_t* io); -HV_EXPORT int hio_fd (hio_t* io); -HV_EXPORT int hio_error (hio_t* io); -HV_EXPORT int hio_events (hio_t* io); -HV_EXPORT int hio_revents (hio_t* io); -HV_EXPORT hio_type_e hio_type (hio_t* io); -HV_EXPORT struct sockaddr* hio_localaddr(hio_t* io); -HV_EXPORT struct sockaddr* hio_peeraddr (hio_t* io); -HV_EXPORT void hio_set_context(hio_t* io, void* ctx); -HV_EXPORT void* hio_context(hio_t* io); -HV_EXPORT bool hio_is_opened(hio_t* io); -HV_EXPORT bool hio_is_closed(hio_t* io); - -// set callbacks -HV_EXPORT void hio_setcb_accept (hio_t* io, haccept_cb accept_cb); -HV_EXPORT void hio_setcb_connect (hio_t* io, hconnect_cb connect_cb); -HV_EXPORT void hio_setcb_read (hio_t* io, hread_cb read_cb); -HV_EXPORT void hio_setcb_write (hio_t* io, hwrite_cb write_cb); -HV_EXPORT void hio_setcb_close (hio_t* io, hclose_cb close_cb); -// get callbacks -HV_EXPORT haccept_cb hio_getcb_accept(hio_t* io); -HV_EXPORT hconnect_cb hio_getcb_connect(hio_t* io); -HV_EXPORT hread_cb hio_getcb_read(hio_t* io); -HV_EXPORT hwrite_cb hio_getcb_write(hio_t* io); -HV_EXPORT hclose_cb hio_getcb_close(hio_t* io); - -// some useful settings -// Enable SSL/TLS is so easy :) -HV_EXPORT int hio_enable_ssl(hio_t* io); -// TODO: One loop per thread, one readbuf per loop. -// But you can pass in your own readbuf instead of the default readbuf to avoid memcopy. -HV_EXPORT void hio_set_readbuf(hio_t* io, void* buf, size_t len); -// connect timeout => hclose_cb -HV_EXPORT void hio_set_connect_timeout(hio_t* io, int timeout_ms DEFAULT(HIO_DEFAULT_CONNECT_TIMEOUT)); -// close timeout => hclose_cb -HV_EXPORT void hio_set_close_timeout(hio_t* io, int timeout_ms DEFAULT(HIO_DEFAULT_CLOSE_TIMEOUT)); -// keepalive timeout => hclose_cb -HV_EXPORT void hio_set_keepalive_timeout(hio_t* io, int timeout_ms DEFAULT(HIO_DEFAULT_KEEPALIVE_TIMEOUT)); -/* -void send_heartbeat(hio_t* io) { - static char buf[] = "PING\r\n"; - hio_write(io, buf, 6); -} -hio_set_heartbeat(io, 3000, send_heartbeat); -*/ -typedef void (*hio_send_heartbeat_fn)(hio_t* io); -// heartbeat interval => hio_send_heartbeat_fn -HV_EXPORT void hio_set_heartbeat(hio_t* io, int interval_ms, hio_send_heartbeat_fn fn); - -// Nonblocking, poll IO events in the loop to call corresponding callback. -// hio_add(io, HV_READ) => accept => haccept_cb -HV_EXPORT int hio_accept (hio_t* io); -// connect => hio_add(io, HV_WRITE) => hconnect_cb -HV_EXPORT int hio_connect(hio_t* io); -// hio_add(io, HV_READ) => read => hread_cb -HV_EXPORT int hio_read (hio_t* io); -#define hio_read_start(io) hio_read(io) -#define hio_read_stop(io) hio_del(io, HV_READ) -// NOTE: hio_write is thread-safe, locked by recursive_mutex, allow to be called by other threads. -// hio_try_write => hio_add(io, HV_WRITE) => write => hwrite_cb -HV_EXPORT int hio_write (hio_t* io, const void* buf, size_t len); -// NOTE: hio_close is thread-safe, hio_close_async will be called actually in other thread. -// hio_del(io, HV_RDWR) => close => hclose_cb -HV_EXPORT int hio_close (hio_t* io); -// NOTE: hloop_post_event(hio_close_event) -HV_EXPORT int hio_close_async(hio_t* io); - -//------------------high-level apis------------------------------------------- -// hio_get -> hio_set_readbuf -> hio_setcb_read -> hio_read -HV_EXPORT hio_t* hread (hloop_t* loop, int fd, void* buf, size_t len, hread_cb read_cb); -// hio_get -> hio_setcb_write -> hio_write -HV_EXPORT hio_t* hwrite (hloop_t* loop, int fd, const void* buf, size_t len, hwrite_cb write_cb DEFAULT(NULL)); -// hio_get -> hio_close -HV_EXPORT void hclose (hloop_t* loop, int fd); - -// tcp -// hio_get -> hio_setcb_accept -> hio_accept -HV_EXPORT hio_t* haccept (hloop_t* loop, int listenfd, haccept_cb accept_cb); -// hio_get -> hio_setcb_connect -> hio_connect -HV_EXPORT hio_t* hconnect (hloop_t* loop, int connfd, hconnect_cb connect_cb); -// hio_get -> hio_set_readbuf -> hio_setcb_read -> hio_read -HV_EXPORT hio_t* hrecv (hloop_t* loop, int connfd, void* buf, size_t len, hread_cb read_cb); -// hio_get -> hio_setcb_write -> hio_write -HV_EXPORT hio_t* hsend (hloop_t* loop, int connfd, const void* buf, size_t len, hwrite_cb write_cb DEFAULT(NULL)); - -// udp -HV_EXPORT void hio_set_type(hio_t* io, hio_type_e type); -HV_EXPORT void hio_set_localaddr(hio_t* io, struct sockaddr* addr, int addrlen); -HV_EXPORT void hio_set_peeraddr (hio_t* io, struct sockaddr* addr, int addrlen); -// NOTE: must call hio_set_peeraddr before hrecvfrom/hsendto -// hio_get -> hio_set_readbuf -> hio_setcb_read -> hio_read -HV_EXPORT hio_t* hrecvfrom (hloop_t* loop, int sockfd, void* buf, size_t len, hread_cb read_cb); -// hio_get -> hio_setcb_write -> hio_write -HV_EXPORT hio_t* hsendto (hloop_t* loop, int sockfd, const void* buf, size_t len, hwrite_cb write_cb DEFAULT(NULL)); - -//-----------------top-level apis--------------------------------------------- -// Resolver -> socket -> hio_get -HV_EXPORT hio_t* hio_create(hloop_t* loop, const char* host, int port, int type DEFAULT(SOCK_STREAM)); - -// @tcp_server: socket -> bind -> listen -> haccept -// @see examples/tcp_echo_server.c -HV_EXPORT hio_t* hloop_create_tcp_server (hloop_t* loop, const char* host, int port, haccept_cb accept_cb); -// @tcp_client: hio_create(loop, host, port, SOCK_STREAM) -> hconnect -// @see examples/nc.c -HV_EXPORT hio_t* hloop_create_tcp_client (hloop_t* loop, const char* host, int port, hconnect_cb connect_cb); - -// @ssl_server: hloop_create_tcp_server -> hio_enable_ssl -// @see examples/tcp_echo_server.c => #define TEST_SSL 1 -HV_EXPORT hio_t* hloop_create_ssl_server (hloop_t* loop, const char* host, int port, haccept_cb accept_cb); -// @ssl_client: hio_create(loop, host, port, SOCK_STREAM) -> hio_enable_ssl -> hconnect -// @see examples/nc.c => #define TEST_SSL 1 -HV_EXPORT hio_t* hloop_create_ssl_client (hloop_t* loop, const char* host, int port, hconnect_cb connect_cb); - -// @udp_server: socket -> bind -> hio_get -// @see examples/udp_echo_server.c -HV_EXPORT hio_t* hloop_create_udp_server (hloop_t* loop, const char* host, int port); -// @udp_client: hio_create(loop, host, port, SOCK_DGRAM) -// @see examples/nc.c -HV_EXPORT hio_t* hloop_create_udp_client (hloop_t* loop, const char* host, int port); - -//-----------------upstream--------------------------------------------- -// hio_read(io) -// hio_read(io->upstream_io) -HV_EXPORT void hio_read_upstream(hio_t* io); -// hio_write(io->upstream_io, buf, bytes) -HV_EXPORT void hio_write_upstream(hio_t* io, void* buf, int bytes); -// hio_close(io->upstream_io) -HV_EXPORT void hio_close_upstream(hio_t* io); - -// io1->upstream_io = io2; -// io2->upstream_io = io1; -// hio_setcb_read(io1, hio_write_upstream); -// hio_setcb_read(io2, hio_write_upstream); -HV_EXPORT void hio_setup_upstream(hio_t* io1, hio_t* io2); - -// @return io->upstream_io -HV_EXPORT hio_t* hio_get_upstream(hio_t* io); - -// @tcp_upstream: hio_create -> hio_setup_upstream -> hio_setcb_close(hio_close_upstream) -> hconnect -> on_connect -> hio_read_upstream -// @return upstream_io -// @see examples/tcp_proxy_server -HV_EXPORT hio_t* hio_setup_tcp_upstream(hio_t* io, const char* host, int port, int ssl DEFAULT(0)); -#define hio_setup_ssl_upstream(io, host, port) hio_setup_tcp_upstream(io, host, port, 1) - -// @udp_upstream: hio_create -> hio_setup_upstream -> hio_read_upstream -// @return upstream_io -// @see examples/udp_proxy_server -HV_EXPORT hio_t* hio_setup_udp_upstream(hio_t* io, const char* host, int port); - -END_EXTERN_C - -#endif // HV_LOOP_H_ diff --git a/src-libhv/evpp/Callback.h b/src-libhv/evpp/Callback.h deleted file mode 100644 index 140983182..000000000 --- a/src-libhv/evpp/Callback.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef HV_CALLBACK_HPP_ -#define HV_CALLBACK_HPP_ - -#include - -#include "Buffer.h" -#include "Channel.h" - -namespace hv { - -typedef std::function ConnectionCallback; -typedef std::function MessageCallback; -typedef std::function WriteCompleteCallback; - -} - -#endif // HV_CALLBACK_HPP_ diff --git a/src-libhv/evpp/TcpClient.h b/src-libhv/evpp/TcpClient.h deleted file mode 100644 index ecd3ca66d..000000000 --- a/src-libhv/evpp/TcpClient.h +++ /dev/null @@ -1,199 +0,0 @@ -#ifndef HV_TCP_CLIENT_HPP_ -#define HV_TCP_CLIENT_HPP_ - -#include "hsocket.h" -#include "hssl.h" -#include "hlog.h" - -#include "EventLoopThread.h" -#include "Callback.h" -#include "Channel.h" - -namespace hv { - -struct ReconnectInfo { - uint32_t min_delay; // ms - uint32_t max_delay; // ms - uint32_t cur_delay; // ms - /* - * @delay_policy - * 0: fixed - * min_delay=3s => 3,3,3... - * 1: linear - * min_delay=3s max_delay=10s => 3,6,9,10,10... - * other: exponential - * min_delay=3s max_delay=60s delay_policy=2 => 3,6,12,24,48,60,60... - */ - uint32_t delay_policy; - uint32_t max_retry_cnt; - uint32_t cur_retry_cnt; - - ReconnectInfo() { - min_delay = 1000; - max_delay = 60000; - cur_delay = 0; - // 1,2,4,8,16,32,60,60... - delay_policy = 2; - max_retry_cnt = INFINITE; - cur_retry_cnt = 0; - } -}; - -template -class TcpClientTmpl { -public: - typedef std::shared_ptr TSocketChannelPtr; - - TcpClientTmpl() { - tls = false; - connect_timeout = 5000; - enable_reconnect = false; - } - - virtual ~TcpClientTmpl() { - } - - const EventLoopPtr& loop() { - return loop_thread.loop(); - } - - //@retval >=0 connfd, <0 error - int createsocket(int port, const char* host = "127.0.0.1") { - memset(&peeraddr, 0, sizeof(peeraddr)); - int ret = sockaddr_set_ipport(&peeraddr, host, port); - if (ret != 0) { - return -1; - } - return createsocket(&peeraddr.sa); - } - - int createsocket(struct sockaddr* peeraddr) { - int connfd = socket(peeraddr->sa_family, SOCK_STREAM, 0); - // SOCKADDR_PRINT(peeraddr); - if (connfd < 0) { - perror("socket"); - return -2; - } - - hio_t* io = hio_get(loop_thread.hloop(), connfd); - assert(io != NULL); - hio_set_peeraddr(io, peeraddr, SOCKADDR_LEN(peeraddr)); - channel.reset(new TSocketChannel(io)); - return connfd; - } - - int startConnect() { - assert(channel != NULL); - if (tls) { - channel->enableSSL(); - } - if (connect_timeout) { - channel->setConnectTimeout(connect_timeout); - } - channel->onconnect = [this]() { - channel->startRead(); - if (onConnection) { - onConnection(channel); - } - }; - channel->onread = [this](Buffer* buf) { - if (onMessage) { - onMessage(channel, buf); - } - }; - channel->onwrite = [this](Buffer* buf) { - if (onWriteComplete) { - onWriteComplete(channel, buf); - } - }; - channel->onclose = [this]() { - if (onConnection) { - onConnection(channel); - } - // reconnect - if (enable_reconnect) { - startReconnect(); - } else { - channel = NULL; - // NOTE: channel should be destroyed, - // so in this lambda function, no code should be added below. - } - }; - return channel->startConnect(); - } - - int startReconnect() { - if (++reconnect_info.cur_retry_cnt > reconnect_info.max_retry_cnt) return 0; - if (reconnect_info.delay_policy == 0) { - // fixed - reconnect_info.cur_delay = reconnect_info.min_delay; - } else if (reconnect_info.delay_policy == 1) { - // linear - reconnect_info.cur_delay += reconnect_info.min_delay; - } else { - // exponential - reconnect_info.cur_delay *= reconnect_info.delay_policy; - } - reconnect_info.cur_delay = MAX(reconnect_info.cur_delay, reconnect_info.min_delay); - reconnect_info.cur_delay = MIN(reconnect_info.cur_delay, reconnect_info.max_delay); - loop_thread.loop()->setTimeout(reconnect_info.cur_delay, [this](TimerID timerID){ - hlogi("reconnect... cnt=%d, delay=%d", reconnect_info.cur_retry_cnt, reconnect_info.cur_delay); - // printf("reconnect... cnt=%d, delay=%d\n", reconnect_info.cur_retry_cnt, reconnect_info.cur_delay); - createsocket(&peeraddr.sa); - startConnect(); - }); - return 0; - } - - void start(bool wait_threads_started = true) { - loop_thread.start(wait_threads_started, std::bind(&TcpClientTmpl::startConnect, this)); - } - void stop(bool wait_threads_stopped = true) { - enable_reconnect = false; - loop_thread.stop(wait_threads_stopped); - } - - int withTLS(const char* cert_file = NULL, const char* key_file = NULL) { - tls = true; - if (cert_file) { - hssl_ctx_init_param_t param; - memset(¶m, 0, sizeof(param)); - param.crt_file = cert_file; - param.key_file = key_file; - param.endpoint = 1; - return hssl_ctx_init(¶m) == NULL ? -1 : 0; - } - return 0; - } - - void setConnectTimeout(int ms) { - connect_timeout = ms; - } - - void setReconnect(ReconnectInfo* info) { - enable_reconnect = true; - reconnect_info = *info; - } - -public: - TSocketChannelPtr channel; - - sockaddr_u peeraddr; - bool tls; - int connect_timeout; - bool enable_reconnect; - ReconnectInfo reconnect_info; - - // Callback - std::function onConnection; - std::function onMessage; - std::function onWriteComplete; -private: - EventLoopThread loop_thread; -}; - -typedef TcpClientTmpl TcpClient; - -} - -#endif // HV_TCP_CLIENT_HPP_ diff --git a/src-libhv/evpp/TcpServer.h b/src-libhv/evpp/TcpServer.h deleted file mode 100644 index ed6516bf3..000000000 --- a/src-libhv/evpp/TcpServer.h +++ /dev/null @@ -1,146 +0,0 @@ -#ifndef HV_TCP_SERVER_HPP_ -#define HV_TCP_SERVER_HPP_ - -#include "hsocket.h" -#include "hssl.h" -#include "hlog.h" - -#include "EventLoopThreadPool.h" -#include "Callback.h" -#include "Channel.h" - -namespace hv { - -class TcpServer { -public: - TcpServer() { - listenfd = -1; - tls = false; - max_connections = 0xFFFFFFFF; - } - - virtual ~TcpServer() { - } - - //@retval >=0 listenfd, <0 error - int createsocket(int port, const char* host = "0.0.0.0") { - listenfd = Listen(port, host); - return listenfd; - } - - void setMaxConnectionNum(uint32_t num) { - max_connections = num; - } - void setThreadNum(int num) { - loop_threads.setThreadNum(num); - } - void start(bool wait_threads_started = true) { - loop_threads.start(wait_threads_started, [this](const EventLoopPtr& loop){ - assert(listenfd >= 0); - hio_t* listenio = haccept(loop->loop(), listenfd, onAccept); - hevent_set_userdata(listenio, this); - if (tls) { - hio_enable_ssl(listenio); - } - }); - } - void stop(bool wait_threads_stopped = true) { - loop_threads.stop(wait_threads_stopped); - } - - EventLoopPtr loop(int idx = -1) { - return loop_threads.loop(idx); - } - hloop_t* hloop(int idx = -1) { - return loop_threads.hloop(idx); - } - - int withTLS(const char* cert_file, const char* key_file) { - tls = true; - if (cert_file) { - hssl_ctx_init_param_t param; - memset(¶m, 0, sizeof(param)); - param.crt_file = cert_file; - param.key_file = key_file; - param.endpoint = 0; - return hssl_ctx_init(¶m) == NULL ? -1 : 0; - } - return 0; - } - - // channel - const SocketChannelPtr& addChannel(hio_t* io) { - std::lock_guard locker(mutex_); - int fd = hio_fd(io); - channels[fd] = SocketChannelPtr(new SocketChannel(io)); - return channels[fd]; - } - - void removeChannel(const SocketChannelPtr& channel) { - std::lock_guard locker(mutex_); - int fd = channel->fd(); - channels.erase(fd); - } - - size_t connectionNum() { - std::lock_guard locker(mutex_); - return channels.size(); - } - -private: - static void onAccept(hio_t* connio) { - TcpServer* server = (TcpServer*)hevent_userdata(connio); - if (server->connectionNum() >= server->max_connections) { - hlogw("over max_connections"); - hio_close(connio); - return; - } - const SocketChannelPtr& channel = server->addChannel(connio); - channel->status = SocketChannel::CONNECTED; - - channel->onread = [server, &channel](Buffer* buf) { - if (server->onMessage) { - server->onMessage(channel, buf); - } - }; - channel->onwrite = [server, &channel](Buffer* buf) { - if (server->onWriteComplete) { - server->onWriteComplete(channel, buf); - } - }; - channel->onclose = [server, &channel]() { - channel->status = SocketChannel::CLOSED; - if (server->onConnection) { - server->onConnection(channel); - } - server->removeChannel(channel); - // NOTE: After removeChannel, channel may be destroyed, - // so in this lambda function, no code should be added below. - }; - - channel->startRead(); - if (server->onConnection) { - server->onConnection(channel); - } - } - -public: - int listenfd; - bool tls; - // Callback - ConnectionCallback onConnection; - MessageCallback onMessage; - WriteCompleteCallback onWriteComplete; - - uint32_t max_connections; - -private: - EventLoopThreadPool loop_threads; - // fd => SocketChannelPtr - std::map channels; // GUAREDE_BY(mutex_) - std::mutex mutex_; -}; - -} - -#endif // HV_TCP_SERVER_HPP_ diff --git a/src-libhv/evpp/TcpServer_test.cpp b/src-libhv/evpp/TcpServer_test.cpp deleted file mode 100644 index b596c49b6..000000000 --- a/src-libhv/evpp/TcpServer_test.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * TcpServer_test.cpp - * - * @build - * make libhv && sudo make install - * g++ -std=c++11 TcpServer_test.cpp -o TcpServer_test -I/usr/local/include/hv -lhv -lpthread - * - */ - -#include "TcpServer.h" - -using namespace hv; - -int main(int argc, char* argv[]) { - if (argc < 2) { - printf("Usage: %s port\n", argv[0]); - return -10; - } - int port = atoi(argv[1]); - - TcpServer srv; - int listenfd = srv.createsocket(port); - if (listenfd < 0) { - return -20; - } - printf("server listen on port %d, listenfd=%d ...\n", port, listenfd); - srv.onConnection = [](const SocketChannelPtr& channel) { - std::string peeraddr = channel->peeraddr(); - if (channel->isConnected()) { - printf("%s connected! connfd=%d\n", peeraddr.c_str(), channel->fd()); - } else { - printf("%s disconnected! connfd=%d\n", peeraddr.c_str(), channel->fd()); - } - }; - srv.onMessage = [](const SocketChannelPtr& channel, Buffer* buf) { - // echo - printf("< %.*s\n", (int)buf->size(), (char*)buf->data()); - channel->write(buf); - }; - srv.onWriteComplete = [](const SocketChannelPtr& channel, Buffer* buf) { - printf("> %.*s\n", (int)buf->size(), (char*)buf->data()); - }; - srv.setThreadNum(4); - srv.start(); - - while (1) hv_sleep(1); - return 0; -} diff --git a/src-libhv/evpp/UdpClient.h b/src-libhv/evpp/UdpClient.h deleted file mode 100644 index d0bcb70dc..000000000 --- a/src-libhv/evpp/UdpClient.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef HV_UDP_CLIENT_HPP_ -#define HV_UDP_CLIENT_HPP_ - -#include "hsocket.h" - -#include "EventLoopThread.h" -#include "Callback.h" -#include "Channel.h" - -namespace hv { - -class UdpClient { -public: - UdpClient() { - } - - virtual ~UdpClient() { - } - - const EventLoopPtr& loop() { - return loop_thread.loop(); - } - - //@retval >=0 sockfd, <0 error - int createsocket(int port, const char* host = "127.0.0.1") { - hio_t* io = hloop_create_udp_client(loop_thread.hloop(), host, port); - if (io == NULL) return -1; - channel.reset(new SocketChannel(io)); - return channel->fd(); - } - - void start(bool wait_threads_started = true) { - loop_thread.start(wait_threads_started, - [this]() { - assert(channel != NULL); - channel->onread = [this](Buffer* buf) { - if (onMessage) { - onMessage(channel, buf); - } - }; - channel->onwrite = [this](Buffer* buf) { - if (onWriteComplete) { - onWriteComplete(channel, buf); - } - }; - channel->startRead(); - return 0; - } - ); - } - void stop(bool wait_threads_stopped = true) { - loop_thread.stop(wait_threads_stopped); - } - - int sendto(Buffer* buf) { - if (channel == NULL) return 0; - return channel->write(buf); - } - - int sendto(const std::string& str) { - if (channel == NULL) return 0; - return channel->write(str); - } - -public: - SocketChannelPtr channel; - // Callback - MessageCallback onMessage; - WriteCompleteCallback onWriteComplete; -private: - EventLoopThread loop_thread; -}; - -} - -#endif // HV_UDP_CLIENT_HPP_ diff --git a/src-libhv/evpp/UdpServer.h b/src-libhv/evpp/UdpServer.h deleted file mode 100644 index 7cd744a47..000000000 --- a/src-libhv/evpp/UdpServer.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef HV_UDP_SERVER_HPP_ -#define HV_UDP_SERVER_HPP_ - -#include "hsocket.h" - -#include "EventLoopThreadPool.h" -#include "Callback.h" -#include "Channel.h" - -namespace hv { - -class UdpServer { -public: - UdpServer() { - } - - virtual ~UdpServer() { - } - - const EventLoopPtr& loop() { - return loop_thread.loop(); - } - - //@retval >=0 bindfd, <0 error - int createsocket(int port, const char* host = "0.0.0.0") { - hio_t* io = hloop_create_udp_server(loop_thread.hloop(), host, port); - if (io == NULL) return -1; - channel.reset(new SocketChannel(io)); - return channel->fd(); - } - - void start(bool wait_threads_started = true) { - loop_thread.start(wait_threads_started, - [this]() { - assert(channel != NULL); - channel->onread = [this](Buffer* buf) { - if (onMessage) { - onMessage(channel, buf); - } - }; - channel->onwrite = [this](Buffer* buf) { - if (onWriteComplete) { - onWriteComplete(channel, buf); - } - }; - channel->startRead(); - return 0; - } - ); - } - void stop(bool wait_threads_stopped = true) { - loop_thread.stop(wait_threads_stopped); - } - - int sendto(Buffer* buf, struct sockaddr* peeraddr = NULL) { - if (channel == NULL) return 0; - if (peeraddr) hio_set_peeraddr(channel->io(), peeraddr, SOCKADDR_LEN(peeraddr)); - return channel->write(buf); - } - - int sendto(const std::string& str, struct sockaddr* peeraddr = NULL) { - if (channel == NULL) return 0; - if (peeraddr) hio_set_peeraddr(channel->io(), peeraddr, SOCKADDR_LEN(peeraddr)); - return channel->write(str); - } - -public: - SocketChannelPtr channel; - // Callback - MessageCallback onMessage; - WriteCompleteCallback onWriteComplete; - -private: - EventLoopThread loop_thread; -}; - -} - -#endif // HV_UDP_SERVER_HPP_ diff --git a/src-libhv/http/HttpMessage.h b/src-libhv/http/HttpMessage.h deleted file mode 100644 index 8b18f8084..000000000 --- a/src-libhv/http/HttpMessage.h +++ /dev/null @@ -1,425 +0,0 @@ -#ifndef HV_HTTP_MESSAGE_H_ -#define HV_HTTP_MESSAGE_H_ - -/* - * @class HttpMessage - * HttpRequest extends HttpMessage - * HttpResponse extends HttpMessage - * - * @member - * request-line: GET / HTTP/1.1\r\n => method path - * response-line: 200 OK\r\n => status_code - * headers - * body - * - * content, content_length, content_type - * json, form, kv - * - * @function - * Content, ContentLength, ContentType - * Get, Set - * GetHeader, GetParam, GetString, GetBool, GetInt, GetFloat - * String, Data, File, Json - * - * @example - * see examples/httpd - * - */ - -#include -#include -#include -#include - -#include "hexport.h" -#include "hbase.h" -#include "hstring.h" -#include "hfile.h" - -#include "httpdef.h" -#include "http_content.h" - -struct HNetAddr { - std::string ip; - int port; - - std::string ipport() { - return asprintf("%s:%d", ip.c_str(), port); - } -}; - -// Cookie: sessionid=1; domain=.example.com; path=/; max-age=86400; secure; httponly -struct HV_EXPORT HttpCookie { - std::string name; - std::string value; - std::string domain; - std::string path; - int max_age; - bool secure; - bool httponly; - - HttpCookie() { - max_age = 86400; - secure = false; - httponly = false; - } - - bool parse(const std::string& str); - std::string dump() const; -}; - -typedef std::map http_headers; -typedef std::vector http_cookies; -typedef std::string http_body; - -class HV_EXPORT HttpMessage { -public: - static char s_date[32]; - int type; - unsigned short http_major; - unsigned short http_minor; - - http_headers headers; - http_cookies cookies; - http_body body; - - // structured content - void* content; // DATA_NO_COPY - int content_length; - http_content_type content_type; -#ifndef WITHOUT_HTTP_CONTENT - hv::Json json; // APPLICATION_JSON - MultiPart form; // MULTIPART_FORM_DATA - hv::KeyValue kv; // X_WWW_FORM_URLENCODED - - // T=[bool, int64_t, double] - template - T Get(const char* key, T defvalue = 0); - - std::string GetString(const char* key, const std::string& = ""); - bool GetBool(const char* key, bool defvalue = 0); - int64_t GetInt(const char* key, int64_t defvalue = 0); - double GetFloat(const char* key, double defvalue = 0); - - template - void Set(const char* key, const T& value) { - switch (content_type) { - case APPLICATION_JSON: - json[key] = value; - break; - case MULTIPART_FORM_DATA: - form[key] = FormData(value); - break; - case X_WWW_FORM_URLENCODED: - kv[key] = hv::to_string(value); - break; - default: - break; - } - } - - /* - * @usage https://github.com/nlohmann/json - * - * null: Json(nullptr); - * boolean: Json(true); - * number: Json(123); - * string: Json("hello"); - * object: Json(std::map); - * Json(hv::Json::object({ - {"k1", "v1"}, - {"k2", "v2"} - })); - * array: Json(std::vector); - Json(hv::Json::array( - {1, 2, 3} - )); - */ - template - int Json(const T& t) { - content_type = APPLICATION_JSON; - json = t; - return 200; - } - - void UploadFormFile(const char* name, const char* filepath) { - content_type = MULTIPART_FORM_DATA; - form[name] = FormData(NULL, filepath); - } - - int SaveFormFile(const char* name, const char* filepath) { - if (content_type != MULTIPART_FORM_DATA) { - return HTTP_STATUS_BAD_REQUEST; - } - const FormData& formdata = form[name]; - if (formdata.content.empty()) { - return HTTP_STATUS_BAD_REQUEST; - } - HFile file; - if (file.open(filepath, "wb") != 0) { - return HTTP_STATUS_INTERNAL_SERVER_ERROR; - } - file.write(formdata.content.data(), formdata.content.size()); - return 200; - } -#endif - - HttpMessage() { - type = HTTP_BOTH; - Init(); - } - - virtual ~HttpMessage() {} - - void Init() { - http_major = 1; - http_minor = 1; - content = NULL; - content_length = 0; - content_type = CONTENT_TYPE_NONE; - } - - virtual void Reset() { - Init(); - headers.clear(); - body.clear(); -#ifndef WITHOUT_HTTP_CONTENT - json.clear(); - form.clear(); - kv.clear(); -#endif - } - - // structured-content -> content_type <-> headers Content-Type - void FillContentType(); - // body.size -> content_length <-> headers Content-Length - void FillContentLength(); - - bool IsKeepAlive(); - - std::string GetHeader(const char* key, const std::string& defvalue = "") { - auto iter = headers.find(key); - if (iter != headers.end()) { - return iter->second; - } - return defvalue; - } - - // headers -> string - void DumpHeaders(std::string& str); - // structured content -> body - void DumpBody(); - void DumpBody(std::string& str); - // body -> structured content - // @retval 0:succeed - int ParseBody(); - - virtual std::string Dump(bool is_dump_headers, bool is_dump_body); - - void* Content() { - if (content == NULL && body.size() != 0) { - content = (void*)body.data(); - } - return content; - } - - int ContentLength() { - if (content_length == 0) { - FillContentLength(); - } - return content_length; - } - - http_content_type ContentType() { - if (content_type == CONTENT_TYPE_NONE) { - FillContentType(); - } - return content_type; - } - - int String(const std::string& str) { - content_type = TEXT_PLAIN; - body = str; - return 200; - } - - int Data(void* data, int len, bool nocopy = true) { - content_type = APPLICATION_OCTET_STREAM; - if (nocopy) { - content = data; - content_length = len; - } else { - content_length = body.size(); - body.resize(content_length + len); - memcpy((void*)(body.data() + content_length), data, len); - content_length += len; - } - return 200; - } - - int File(const char* filepath) { - HFile file; - if (file.open(filepath, "rb") != 0) { - return HTTP_STATUS_NOT_FOUND; - } - const char* suffix = hv_suffixname(filepath); - if (suffix) { - content_type = http_content_type_enum_by_suffix(suffix); - } - if (content_type == CONTENT_TYPE_NONE || content_type == CONTENT_TYPE_UNDEFINED) { - content_type = APPLICATION_OCTET_STREAM; - } - file.readall(body); - return 200; - } -}; - -#define DEFAULT_USER_AGENT "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" -class HV_EXPORT HttpRequest : public HttpMessage { -public: - http_method method; - // scheme:[//[user[:password]@]host[:port]][/path][?query][#fragment] - std::string url; - // structured url - std::string scheme; - std::string host; - int port; - std::string path; - QueryParams query_params; - // client_addr - HNetAddr client_addr; // for http server save client addr of request - int timeout; // for http client timeout - bool redirect; // for http_client redirect - - HttpRequest() : HttpMessage() { - type = HTTP_REQUEST; - Init(); - } - - void Init() { - headers["User-Agent"] = DEFAULT_USER_AGENT; - headers["Accept"] = "*/*"; - method = HTTP_GET; - scheme = "http"; - host = "127.0.0.1"; - port = DEFAULT_HTTP_PORT; - path = "/"; - timeout = 0; - redirect = true; - } - - virtual void Reset() { - HttpMessage::Reset(); - Init(); - url.clear(); - query_params.clear(); - } - - virtual std::string Dump(bool is_dump_headers = true, bool is_dump_body = false); - - // structed url -> url - void DumpUrl(); - // url -> structed url - void ParseUrl(); - - std::string Host() { - auto iter = headers.find("Host"); - if (iter != headers.end()) { - host = iter->second; - } - return host; - } - - std::string Path() { - const char* s = path.c_str(); - const char* e = s; - while (*e && *e != '?' && *e != '#') ++e; - return std::string(s, e); - } - - std::string GetParam(const char* key, const std::string& defvalue = "") { - auto iter = query_params.find(key); - if (iter != query_params.end()) { - return iter->second; - } - return defvalue; - } - - // Range: bytes=0-4095 - void SetRange(long from = 0, long to = -1) { - headers["Range"] = asprintf("bytes=%ld-%ld", from, to); - } - bool GetRange(long& from, long& to) { - auto iter = headers.find("Range"); - if (iter != headers.end()) { - sscanf(iter->second.c_str(), "bytes=%ld-%ld", &from, &to); - return true; - } - from = to = 0; - return false; - } - - // Cookie - void SetCookie(const HttpCookie& cookie) { - headers["Cookie"] = cookie.dump(); - } - bool GetCookie(HttpCookie& cookie) { - std::string str = GetHeader("Cookie"); - if (str.empty()) return false; - return cookie.parse(str); - } -}; - -class HV_EXPORT HttpResponse : public HttpMessage { -public: - http_status status_code; - const char* status_message() { - return http_status_str(status_code); - } - - HttpResponse() : HttpMessage() { - type = HTTP_RESPONSE; - Init(); - } - - void Init() { - status_code = HTTP_STATUS_OK; - } - - virtual void Reset() { - HttpMessage::Reset(); - Init(); - } - - virtual std::string Dump(bool is_dump_headers = true, bool is_dump_body = false); - - // Content-Range: bytes 0-4095/10240000 - void SetRange(long from, long to, long total) { - headers["Content-Range"] = asprintf("bytes %ld-%ld/%ld", from, to, total); - } - bool GetRange(long& from, long& to, long& total) { - auto iter = headers.find("Content-Range"); - if (iter != headers.end()) { - sscanf(iter->second.c_str(), "bytes %ld-%ld/%ld", &from, &to, &total); - return true; - } - from = to = total = 0; - return false; - } - - // Set-Cookie - void SetCookie(const HttpCookie& cookie) { - headers["Set-Cookie"] = cookie.dump(); - } - bool GetCookie(HttpCookie& cookie) { - std::string str = GetHeader("Set-Cookie"); - if (str.empty()) return false; - return cookie.parse(str); - } -}; - -typedef std::shared_ptr HttpRequestPtr; -typedef std::shared_ptr HttpResponsePtr; -typedef std::function HttpResponseCallback; - -#endif // HV_HTTP_MESSAGE_H_ diff --git a/src-libhv/http/client/http_client.h b/src-libhv/http/client/http_client.h deleted file mode 100644 index 619146f70..000000000 --- a/src-libhv/http/client/http_client.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef HV_HTTP_CLIENT_H_ -#define HV_HTTP_CLIENT_H_ - -#include "hexport.h" -#include "HttpMessage.h" - -/* -#include - -#include "http_client.h" - -int main(int argc, char* argv[]) { - HttpRequest req; - req.method = HTTP_GET; - req.url = "http://www.example.com"; - HttpResponse res; - int ret = http_client_send(&req, &res); - printf("%s\n", req.Dump(true,true).c_str()); - if (ret != 0) { - printf("* Failed:%s:%d\n", http_client_strerror(ret), ret); - } - else { - printf("%s\n", res.Dump(true,true).c_str()); - } - return ret; -} -*/ - -#define DEFAULT_HTTP_TIMEOUT 30 // s -typedef struct http_client_s http_client_t; - -HV_EXPORT http_client_t* http_client_new(const char* host = NULL, int port = DEFAULT_HTTP_PORT, int https = 0); -HV_EXPORT int http_client_del(http_client_t* cli); -HV_EXPORT const char* http_client_strerror(int errcode); - -HV_EXPORT int http_client_set_timeout(http_client_t* cli, int timeout); - -// common headers -HV_EXPORT int http_client_clear_headers(http_client_t* cli); -HV_EXPORT int http_client_set_header(http_client_t* cli, const char* key, const char* value); -HV_EXPORT int http_client_del_header(http_client_t* cli, const char* key); -HV_EXPORT const char* http_client_get_header(http_client_t* cli, const char* key); - -// sync -HV_EXPORT int http_client_send(http_client_t* cli, HttpRequest* req, HttpResponse* resp); - -// async -// Intern will start an EventLoopThread when http_client_send_async first called, -// http_client_del will destroy the thread. -HV_EXPORT int http_client_send_async(http_client_t* cli, HttpRequestPtr req, HttpResponseCallback resp_cb = NULL); - -// top-level api -// http_client_new -> http_client_send -> http_client_del -HV_EXPORT int http_client_send(HttpRequest* req, HttpResponse* resp); -// http_client_send_async(&default_async_client, ...) -HV_EXPORT int http_client_send_async(HttpRequestPtr req, HttpResponseCallback resp_cb = NULL); - -#endif // HV_HTTP_CLIENT_H_ diff --git a/src-libhv/http/client/requests.h b/src-libhv/http/client/requests.h deleted file mode 100644 index 8c8ff2b3e..000000000 --- a/src-libhv/http/client/requests.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef HV_REQUESTS_H_ -#define HV_REQUESTS_H_ - -/* - * Inspired by python requests - * - * @code - -#include "requests.h" - -int main() { - auto resp = requests::get("http://127.0.0.1:8080/ping"); - if (resp == NULL) { - printf("request failed!\n"); - } else { - printf("%d %s\r\n", resp->status_code, resp->status_message()); - printf("%s\n", resp->body.c_str()); - } - - resp = requests::post("http://127.0.0.1:8080/echo", "hello,world!"); - if (resp == NULL) { - printf("request failed!\n"); - } else { - printf("%d %s\r\n", resp->status_code, resp->status_message()); - printf("%s\n", resp->body.c_str()); - } - - return 0; -} - -**/ - -#include -#include "http_client.h" - -namespace requests { - -typedef HttpRequestPtr Request; -typedef HttpResponsePtr Response; -typedef HttpResponseCallback ResponseCallback; - -static http_headers DefaultHeaders; -static http_body NoBody; - -HV_INLINE Response request(Request req) { - Response resp(new HttpResponse); - int ret = http_client_send(req.get(), resp.get()); - return ret ? NULL : resp; -} - -HV_INLINE Response request(http_method method, const char* url, const http_body& body = NoBody, const http_headers& headers = DefaultHeaders) { - Request req(new HttpRequest); - req->method = method; - req->url = url; - if (&body != &NoBody) { - req->body = body; - } - if (&headers != &DefaultHeaders) { - req->headers = headers; - } - return request(req); -} - -HV_INLINE Response head(const char* url, const http_headers& headers = DefaultHeaders) { - return request(HTTP_HEAD, url, NoBody, headers); -} - -HV_INLINE Response get(const char* url, const http_headers& headers = DefaultHeaders) { - return request(HTTP_GET, url, NoBody, headers); -} - -HV_INLINE Response post(const char* url, const http_body& body = NoBody, const http_headers& headers = DefaultHeaders) { - return request(HTTP_POST, url, body, headers); -} - -HV_INLINE Response put(const char* url, const http_body& body = NoBody, const http_headers& headers = DefaultHeaders) { - return request(HTTP_PUT, url, body, headers); -} - -HV_INLINE Response patch(const char* url, const http_body& body = NoBody, const http_headers& headers = DefaultHeaders) { - return request(HTTP_PATCH, url, body, headers); -} - -// delete is c++ keyword, we have to replace delete with Delete. -HV_INLINE Response Delete(const char* url, const http_body& body = NoBody, const http_headers& headers = DefaultHeaders) { - return request(HTTP_DELETE, url, body, headers); -} - -HV_INLINE int async(Request req, ResponseCallback resp_cb) { - return http_client_send_async(req, resp_cb); -} - -} - -#endif // HV_REQUESTS_H_ diff --git a/src-libhv/http/server/HttpHandler.cpp b/src-libhv/http/server/HttpHandler.cpp deleted file mode 100644 index e94540542..000000000 --- a/src-libhv/http/server/HttpHandler.cpp +++ /dev/null @@ -1,340 +0,0 @@ -#include "HttpHandler.h" - -#include "hbase.h" -#include "herr.h" -#include "hlog.h" -#include "http_page.h" - -int HttpHandler::HandleHttpRequest() { - // preprocessor -> processor -> postprocessor - int status_code = HTTP_STATUS_OK; - HttpRequest* pReq = req.get(); - HttpResponse* pResp = resp.get(); - - pReq->scheme = ssl ? "https" : "http"; - pReq->client_addr.ip = ip; - pReq->client_addr.port = port; - pReq->Host(); - pReq->ParseUrl(); - // pReq->ParseBody(); - -preprocessor: - state = HANDLE_BEGIN; - if (service->preprocessor) { - status_code = service->preprocessor(pReq, pResp); - if (status_code != 0) { - goto postprocessor; - } - } - -processor: - if (service->processor) { - status_code = customHttpHandler(service->processor); - } else { - status_code = defaultRequestHandler(); - } - -postprocessor: - if (status_code >= 100 && status_code < 600) { - pResp->status_code = (http_status)status_code; - } - if (pResp->status_code >= 400 && pResp->body.size() == 0 && pReq->method != HTTP_HEAD) { - if (service->errorHandler) { - customHttpHandler(service->errorHandler); - } else { - defaultErrorHandler(); - } - } - if (fc) { - pResp->content = fc->filebuf.base; - pResp->content_length = fc->filebuf.len; - pResp->headers["Content-Type"] = fc->content_type; - pResp->headers["Last-Modified"] = fc->last_modified; - pResp->headers["Etag"] = fc->etag; - } - if (service->postprocessor) { - service->postprocessor(pReq, pResp); - } - - if (status_code == 0) { - state = HANDLE_CONTINUE; - } else { - state = HANDLE_END; - parser->SubmitResponse(resp.get()); - } - return status_code; -} - -int HttpHandler::customHttpHandler(http_handler& fn) { - HttpContextPtr ctx(new HttpContext); - ctx->service = service; - ctx->request = req; - ctx->response = resp; - ctx->writer = writer; - return fn(ctx); -} - -int HttpHandler::defaultRequestHandler() { - int status_code = HTTP_STATUS_OK; - http_sync_handler sync_handler = NULL; - http_async_handler async_handler = NULL; - http_handler ctx_handler = NULL; - - if (service->api_handlers.size() != 0) { - service->GetApi(req.get(), &sync_handler, &async_handler, &ctx_handler); - } - - if (sync_handler) { - // sync api handler - status_code = sync_handler(req.get(), resp.get()); - if (status_code != 0) { - return status_code; - } - } - else if (async_handler) { - // async api handler - async_handler(req, writer); - status_code = 0; - } - else if (ctx_handler) { - // HttpContext handler - status_code = customHttpHandler(ctx_handler); - if (status_code != 0) { - return status_code; - } - } - else if (req->method == HTTP_GET || req->method == HTTP_HEAD) { - // static handler - if (service->staticHandler) { - customHttpHandler(service->staticHandler); - } - else if (service->document_root.size() != 0) { - status_code = defaultStaticHandler(); - } - else { - status_code = HTTP_STATUS_NOT_FOUND; - } - } - else { - // Not Implemented - status_code = HTTP_STATUS_NOT_IMPLEMENTED; - } - - return status_code; -} - -int HttpHandler::defaultStaticHandler() { - // file service - int status_code = HTTP_STATUS_OK; - std::string path = req->Path(); - const char* req_path = path.c_str(); - // path safe check - if (req_path[0] != '/' || strstr(req_path, "/../")) { - return HTTP_STATUS_BAD_REQUEST; - } - std::string filepath = service->document_root + path; - if (req_path[1] == '\0') { - filepath += service->home_page; - } - bool is_dir = filepath.c_str()[filepath.size()-1] == '/'; - bool is_index_of = false; - if (service->index_of.size() != 0 && strstartswith(req_path, service->index_of.c_str())) { - is_index_of = true; - } - if (!is_dir || is_index_of) { - FileCache::OpenParam param; - param.need_read = req->method == HTTP_HEAD ? false : true; - param.path = req_path; - fc = files->Open(filepath.c_str(), ¶m); - if (fc == NULL) { - status_code = HTTP_STATUS_NOT_FOUND; - if (param.error == ERR_OVER_LIMIT) { - if (service->largeFileHandler) { - status_code = customHttpHandler(service->largeFileHandler); - } - } - } - } else { - status_code = HTTP_STATUS_NOT_FOUND; - } - - if (fc) { - // Not Modified - auto iter = req->headers.find("if-not-match"); - if (iter != req->headers.end() && - strcmp(iter->second.c_str(), fc->etag) == 0) { - status_code = HTTP_STATUS_NOT_MODIFIED; - fc = NULL; - } - else { - iter = req->headers.find("if-modified-since"); - if (iter != req->headers.end() && - strcmp(iter->second.c_str(), fc->last_modified) == 0) { - status_code = HTTP_STATUS_NOT_MODIFIED; - fc = NULL; - } - } - } - return status_code; -} - -int HttpHandler::defaultErrorHandler() { - // error page - if (service->error_page.size() != 0) { - std::string filepath = service->document_root; - filepath += '/'; - filepath += service->error_page; - FileCache::OpenParam param; - fc = files->Open(filepath.c_str(), ¶m); - } - // status page - if (fc == NULL && resp->body.size() == 0) { - resp->content_type = TEXT_HTML; - make_http_status_page(resp->status_code, resp->body); - } - return 0; -} - -int HttpHandler::FeedRecvData(const char* data, size_t len) { - int nfeed = 0; - if (protocol == HttpHandler::WEBSOCKET) { - nfeed = ws->parser->FeedRecvData(data, len); - if (nfeed != len) { - hloge("[%s:%d] websocket parse error!", ip, port); - } - } else { - if (state != WANT_RECV) { - Reset(); - } - nfeed = parser->FeedRecvData(data, len); - if (nfeed != len) { - hloge("[%s:%d] http parse error: %s", ip, port, parser->StrError(parser->GetError())); - } - } - return nfeed; -} - -int HttpHandler::GetSendData(char** data, size_t* len) { - if (state == HANDLE_CONTINUE) { - return 0; - } - - HttpRequest* pReq = req.get(); - HttpResponse* pResp = resp.get(); - - if (protocol == HTTP_V1) { - switch(state) { - case WANT_RECV: - if (parser->IsComplete()) state = WANT_SEND; - else return 0; - case HANDLE_END: - state = WANT_SEND; - case WANT_SEND: - state = SEND_HEADER; - case SEND_HEADER: - { - int content_length = 0; - const char* content = NULL; - // HEAD - if (pReq->method == HTTP_HEAD) { - if (fc) { - pResp->headers["Accept-Ranges"] = "bytes"; - pResp->headers["Content-Length"] = hv::to_string(fc->st.st_size); - } else { - pResp->headers["Content-Type"] = "text/html"; - pResp->headers["Content-Length"] = "0"; - } - state = SEND_DONE; - goto return_nobody; - } - // File service - if (fc) { - long from, to, total; - int nread; - // Range: - if (pReq->GetRange(from, to)) { - HFile file; - if (file.open(fc->filepath.c_str(), "rb") != 0) { - pResp->status_code = HTTP_STATUS_NOT_FOUND; - state = SEND_DONE; - goto return_nobody; - } - total = file.size(); - if (to == 0 || to >= total) to = total - 1; - pResp->content_length = to - from + 1; - nread = file.readrange(body, from, to); - if (nread != pResp->content_length) { - pResp->status_code = HTTP_STATUS_INTERNAL_SERVER_ERROR; - state = SEND_DONE; - goto return_nobody; - } - pResp->SetRange(from, to, total); - state = SEND_BODY; - goto return_header; - } - // FileCache - // NOTE: no copy filebuf, more efficient - header = pResp->Dump(true, false); - fc->prepend_header(header.c_str(), header.size()); - *data = fc->httpbuf.base; - *len = fc->httpbuf.len; - state = SEND_DONE; - return *len; - } - // API service - content_length = pResp->ContentLength(); - content = (const char*)pResp->Content(); - if (content) { - if (content_length > (1 << 20)) { - state = SEND_BODY; - goto return_header; - } else { - // NOTE: header+body in one package if <= 1M - header = pResp->Dump(true, false); - header.append(content, content_length); - state = SEND_DONE; - goto return_header; - } - } else { - state = SEND_DONE; - goto return_header; - } -return_nobody: - pResp->content_length = 0; -return_header: - if (header.empty()) header = pResp->Dump(true, false); - *data = (char*)header.c_str(); - *len = header.size(); - return *len; - } - case SEND_BODY: - { - if (body.empty()) { - *data = (char*)pResp->Content(); - *len = pResp->ContentLength(); - } else { - *data = (char*)body.c_str(); - *len = body.size(); - } - state = SEND_DONE; - return *len; - } - case SEND_DONE: - { - // NOTE: remove file cache if > 16M - if (fc && fc->filebuf.len > (1 << 24)) { - files->Close(fc); - } - fc = NULL; - header.clear(); - body.clear(); - return 0; - } - default: - return 0; - } - } else if (protocol == HTTP_V2) { - return parser->GetSendData(data, len); - } - return 0; -} diff --git a/src-libhv/http/server/HttpHandler.h b/src-libhv/http/server/HttpHandler.h deleted file mode 100644 index 4e5a91dae..000000000 --- a/src-libhv/http/server/HttpHandler.h +++ /dev/null @@ -1,162 +0,0 @@ -#ifndef HV_HTTP_HANDLER_H_ -#define HV_HTTP_HANDLER_H_ - -#include "HttpService.h" -#include "HttpParser.h" -#include "FileCache.h" - -#include "WebSocketServer.h" -#include "WebSocketParser.h" - -class WebSocketHandler { -public: - WebSocketChannelPtr channel; - WebSocketParserPtr parser; - uint64_t last_send_ping_time; - uint64_t last_recv_pong_time; - - WebSocketHandler() { - parser.reset(new WebSocketParser); - // channel.reset(new WebSocketChannel); - last_send_ping_time = 0; - last_recv_pong_time = 0; - } - - void onopen() { - channel->status = hv::SocketChannel::CONNECTED; - } - - void onclose() { - channel->status = hv::SocketChannel::DISCONNECTED; - } -}; -typedef std::shared_ptr WebSocketHandlerPtr; - -class HttpHandler { -public: - enum ProtocolType { - UNKNOWN, - HTTP_V1, - HTTP_V2, - WEBSOCKET, - } protocol; - enum State { - WANT_RECV, - HANDLE_BEGIN, - HANDLE_CONTINUE, - HANDLE_END, - WANT_SEND, - SEND_HEADER, - SEND_BODY, - SEND_DONE, - } state; - - // peeraddr - bool ssl; - char ip[64]; - int port; - - // for http - HttpService *service; - FileCache *files; - - HttpRequestPtr req; - HttpResponsePtr resp; - HttpResponseWriterPtr writer; - HttpParserPtr parser; - - // for GetSendData - file_cache_ptr fc; - std::string header; - std::string body; - - // for websocket - WebSocketHandlerPtr ws; - WebSocketService* ws_service; - - HttpHandler() { - protocol = UNKNOWN; - state = WANT_RECV; - ssl = false; - service = NULL; - files = NULL; - ws_service = NULL; - } - - bool Init(int http_version = 1) { - parser.reset(HttpParser::New(HTTP_SERVER, (enum http_version)http_version)); - if (parser == NULL) { - return false; - } - protocol = http_version == 1 ? HTTP_V1 : HTTP_V2; - req.reset(new HttpRequest); - resp.reset(new HttpResponse); - if (http_version == 2) { - req->http_major = 2; - req->http_minor = 0; - resp->http_major = 2; - resp->http_minor = 0; - } - parser->InitRequest(req.get()); - return true; - } - - bool SwitchHTTP2() { - parser.reset(HttpParser::New(HTTP_SERVER, ::HTTP_V2)); - if (parser == NULL) { - return false; - } - protocol = HTTP_V2; - req->http_major = 2; - req->http_minor = 0; - resp->http_major = 2; - resp->http_minor = 0; - parser->InitRequest(req.get()); - return true; - } - - void Reset() { - state = WANT_RECV; - req->Reset(); - resp->Reset(); - parser->InitRequest(req.get()); - } - - int FeedRecvData(const char* data, size_t len); - // @workflow: preprocessor -> api -> web -> postprocessor - // @result: HttpRequest -> HttpResponse/file_cache_t - int HandleHttpRequest(); - int GetSendData(char** data, size_t* len); - - // websocket - WebSocketHandler* SwitchWebSocket() { - ws.reset(new WebSocketHandler); - protocol = WEBSOCKET; - return ws.get(); - } - void WebSocketOnOpen() { - ws->onopen(); - if (ws_service && ws_service->onopen) { - ws_service->onopen(ws->channel, req->url); - } - } - void WebSocketOnClose() { - ws->onclose(); - if (ws_service && ws_service->onclose) { - ws_service->onclose(ws->channel); - } - } - void WebSocketOnMessage(const std::string& msg) { - if (ws_service && ws_service->onmessage) { - ws_service->onmessage(ws->channel, msg); - } - } - -private: - int defaultRequestHandler(); - int defaultStaticHandler(); - int defaultErrorHandler(); - int customHttpHandler(http_handler& fn); -}; - -#endif // HV_HTTP_HANDLER_H_ diff --git a/src-libhv/http/server/HttpResponseWriter.h b/src-libhv/http/server/HttpResponseWriter.h deleted file mode 100644 index b8c02a42e..000000000 --- a/src-libhv/http/server/HttpResponseWriter.h +++ /dev/null @@ -1,126 +0,0 @@ -#ifndef HV_HTTP_RESPONSE_WRITER_H_ -#define HV_HTTP_RESPONSE_WRITER_H_ - -#include "Channel.h" -#include "HttpMessage.h" - -namespace hv { - -class HttpResponseWriter : public SocketChannel { -public: - HttpResponsePtr response; - enum State { - SEND_BEGIN, - SEND_HEADER, - SEND_BODY, - SEND_END, - } state; - HttpResponseWriter(hio_t* io, const HttpResponsePtr& resp) - : SocketChannel(io) - , response(resp) - , state(SEND_BEGIN) - {} - ~HttpResponseWriter() {} - - // Begin -> End - // Begin -> WriteResponse -> End - // Begin -> WriteStatus -> WriteHeader -> WriteBody -> End - // Begin -> WriteHeader -> EndHeaders -> WriteBody -> WriteBody -> ... -> End - - int Begin() { - state = SEND_BEGIN; - return 0; - } - - int WriteStatus(http_status status_codes) { - response->status_code = status_codes; - return 0; - } - - int WriteHeader(const char* key, const char* value) { - response->headers[key] = value; - return 0; - } - - template - int WriteHeader(const char* key, T num) { - response->headers[key] = hv::to_string(num); - return 0; - } - - int EndHeaders(const char* key = NULL, const char* value = NULL) { - if (state != SEND_BEGIN) return -1; - if (key && value) { - response->headers[key] = value; - } - std::string headers = response->Dump(true, false); - state = SEND_HEADER; - return write(headers); - } - - int WriteBody(const char* buf, int len = -1) { - if (len == -1) len = strlen(buf); - if (state == SEND_BEGIN) { - response->body.append(buf, len); - return len; - } else { - state = SEND_BODY; - return write(buf, len); - } - } - - int WriteBody(const std::string& str) { - return WriteBody(str.c_str(), str.size()); - } - - int WriteResponse(HttpResponse* resp) { - if (resp == NULL) { - response->status_code = HTTP_STATUS_INTERNAL_SERVER_ERROR; - return 0; - } - bool is_dump_headers = state == SEND_BEGIN ? true : false; - std::string msg = resp->Dump(is_dump_headers, true); - state = SEND_BODY; - return write(msg); - } - - int End(const char* buf = NULL, int len = -1) { - if (state == SEND_END) return 0; - if (!isConnected()) { - state = SEND_END; - return -1; - } - - int ret = 0; - if (buf) { - ret = WriteBody(buf, len); - } - bool is_dump_headers = true; - bool is_dump_body = true; - if (state == SEND_HEADER) { - is_dump_headers = false; - } else if (state == SEND_BODY) { - is_dump_headers = false; - is_dump_body = false; - } - if (is_dump_body) { - std::string msg = response->Dump(is_dump_headers, is_dump_body); - ret = write(msg); - } - state = SEND_END; - if (!response->IsKeepAlive()) { - close(); - } - return ret; - } - - int End(const std::string& str) { - return End(str.c_str(), str.size()); - } -}; - -} - -typedef std::shared_ptr HttpResponseWriterPtr; - -#endif // HV_HTTP_RESPONSE_WRITER_H_ diff --git a/src-libhv/http/server/HttpServer.h b/src-libhv/http/server/HttpServer.h deleted file mode 100644 index 445b41fc6..000000000 --- a/src-libhv/http/server/HttpServer.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef HV_HTTP_SERVER_H_ -#define HV_HTTP_SERVER_H_ - -#include "hexport.h" -#include "HttpService.h" - -struct WebSocketService; -typedef struct http_server_s { - char host[64]; - int port; // http_port - int https_port; - int http_version; - int worker_processes; - int worker_threads; - HttpService* service; - WebSocketService* ws; - void* userdata; -//private: - int listenfd[2]; // 0: http, 1: https - void* privdata; - -#ifdef __cplusplus - http_server_s() { - strcpy(host, "0.0.0.0"); - // port = DEFAULT_HTTP_PORT; - // https_port = DEFAULT_HTTPS_PORT; - // port = 8080; - // https_port = 8443; - port = https_port = 0; - http_version = 1; - worker_processes = 0; - worker_threads = 0; - service = NULL; - ws = NULL; - listenfd[0] = listenfd[1] = -1; - userdata = NULL; - privdata = NULL; - } -#endif -} http_server_t; - -/* -#include "HttpServer.h" - -int main() { - HttpService service; - service.base_url = "/api/v1"; - service.GET("/ping", [](HttpRequest* req, HttpResponse* resp) { - resp->body = "pong"; - return 200; - }); - - http_server_t server; - server.port = 8080; - server.worker_processes = 4; - server.service = &service; - http_server_run(&server); - return 0; -} -*/ -HV_EXPORT int http_server_run(http_server_t* server, int wait = 1); - -// NOTE: stop all loops and join all threads -HV_EXPORT int http_server_stop(http_server_t* server); - -#endif // HV_HTTP_SERVER_H_ diff --git a/src-libhv/http/server/HttpService.h b/src-libhv/http/server/HttpService.h deleted file mode 100644 index ce1c8852f..000000000 --- a/src-libhv/http/server/HttpService.h +++ /dev/null @@ -1,228 +0,0 @@ -#ifndef HV_HTTP_SERVICE_H_ -#define HV_HTTP_SERVICE_H_ - -#include -#include -#include -#include -#include - -#include "hexport.h" -#include "HttpMessage.h" -#include "HttpResponseWriter.h" - -#define DEFAULT_BASE_URL "/api/v1" -#define DEFAULT_DOCUMENT_ROOT "/var/www/html" -#define DEFAULT_HOME_PAGE "index.html" -#define DEFAULT_ERROR_PAGE "error.html" -#define DEFAULT_INDEXOF_DIR "/downloads/" - -/* - * @param[in] req: parsed structured http request - * @param[out] resp: structured http response - * @return 0: handle continue - * http_status_code: handle done - */ -typedef std::function http_sync_handler; -typedef std::function http_async_handler; - -struct HttpService; -struct HV_EXPORT HttpContext { - HttpService* service; - HttpRequestPtr request; - HttpResponsePtr response; - HttpResponseWriterPtr writer; -}; -typedef std::shared_ptr HttpContextPtr; -typedef std::function http_handler; - -struct http_method_handler { - http_method method; - http_sync_handler sync_handler; - http_async_handler async_handler; - http_handler handler; - http_method_handler(http_method m = HTTP_POST, - http_sync_handler s = NULL, - http_async_handler a = NULL, - http_handler h = NULL) - { - method = m; - sync_handler = std::move(s); - async_handler = std::move(a); - handler = std::move(h); - } -}; -// method => http_method_handler -typedef std::list http_method_handlers; -// path => http_method_handlers -typedef std::map> http_api_handlers; - -struct HV_EXPORT HttpService { - // preprocessor -> processor -> postprocessor - http_sync_handler preprocessor; - // processor: api_handlers -> staticHandler -> errorHandler - http_handler processor; - http_sync_handler postprocessor; - - // api service (that is http.APIServer) - std::string base_url; - http_api_handlers api_handlers; - - // file service (that is http.FileServer) - http_handler staticHandler; - http_handler largeFileHandler; - std::string document_root; - std::string home_page; - std::string error_page; - // indexof service (that is http.DirectoryServer) - std::string index_of; - - http_handler errorHandler; - - HttpService() { - preprocessor = NULL; - processor = NULL; - postprocessor = NULL; - - // base_url = DEFAULT_BASE_URL; - - staticHandler = NULL; - largeFileHandler = NULL; - - document_root = DEFAULT_DOCUMENT_ROOT; - home_page = DEFAULT_HOME_PAGE; - // error_page = DEFAULT_ERROR_PAGE; - // index_of = DEFAULT_INDEXOF_DIR; - - errorHandler = NULL; - } - - void AddApi(const char* path, http_method method, - http_sync_handler sync_handler = NULL, - http_async_handler async_handler = NULL, - http_handler handler = NULL); - // @retval 0 OK, else HTTP_STATUS_NOT_FOUND, HTTP_STATUS_METHOD_NOT_ALLOWED - int GetApi(const char* url, http_method method, - http_sync_handler* sync_handler = NULL, - http_async_handler* async_handler = NULL, - http_handler* handler = NULL); - // RESTful API /:field/ => req->query_params["field"] - int GetApi(HttpRequest* req, - http_sync_handler* sync_handler = NULL, - http_async_handler* async_handler = NULL, - http_handler* handler = NULL); - - StringList Paths() { - StringList paths; - for (auto& pair : api_handlers) { - paths.emplace_back(pair.first); - } - return paths; - } - - // github.com/gin-gonic/gin - void Handle(const char* httpMethod, const char* relativePath, http_sync_handler handlerFunc) { - AddApi(relativePath, http_method_enum(httpMethod), handlerFunc, NULL, NULL); - } - void Handle(const char* httpMethod, const char* relativePath, http_async_handler handlerFunc) { - AddApi(relativePath, http_method_enum(httpMethod), NULL, handlerFunc, NULL); - } - void Handle(const char* httpMethod, const char* relativePath, http_handler handlerFunc) { - AddApi(relativePath, http_method_enum(httpMethod), NULL, NULL, handlerFunc); - } - - // HEAD - void HEAD(const char* relativePath, http_sync_handler handlerFunc) { - Handle("HEAD", relativePath, handlerFunc); - } - void HEAD(const char* relativePath, http_async_handler handlerFunc) { - Handle("HEAD", relativePath, handlerFunc); - } - void HEAD(const char* relativePath, http_handler handlerFunc) { - Handle("HEAD", relativePath, handlerFunc); - } - - // GET - void GET(const char* relativePath, http_sync_handler handlerFunc) { - Handle("GET", relativePath, handlerFunc); - } - void GET(const char* relativePath, http_async_handler handlerFunc) { - Handle("GET", relativePath, handlerFunc); - } - void GET(const char* relativePath, http_handler handlerFunc) { - Handle("GET", relativePath, handlerFunc); - } - - // POST - void POST(const char* relativePath, http_sync_handler handlerFunc) { - Handle("POST", relativePath, handlerFunc); - } - void POST(const char* relativePath, http_async_handler handlerFunc) { - Handle("POST", relativePath, handlerFunc); - } - void POST(const char* relativePath, http_handler handlerFunc) { - Handle("POST", relativePath, handlerFunc); - } - - // PUT - void PUT(const char* relativePath, http_sync_handler handlerFunc) { - Handle("PUT", relativePath, handlerFunc); - } - void PUT(const char* relativePath, http_async_handler handlerFunc) { - Handle("PUT", relativePath, handlerFunc); - } - void PUT(const char* relativePath, http_handler handlerFunc) { - Handle("PUT", relativePath, handlerFunc); - } - - // DELETE - // NOTE: Windows #define DELETE as a macro, we have to replace DELETE with Delete. - void Delete(const char* relativePath, http_sync_handler handlerFunc) { - Handle("DELETE", relativePath, handlerFunc); - } - void Delete(const char* relativePath, http_async_handler handlerFunc) { - Handle("DELETE", relativePath, handlerFunc); - } - void Delete(const char* relativePath, http_handler handlerFunc) { - Handle("DELETE", relativePath, handlerFunc); - } - - // PATCH - void PATCH(const char* relativePath, http_sync_handler handlerFunc) { - Handle("PATCH", relativePath, handlerFunc); - } - void PATCH(const char* relativePath, http_async_handler handlerFunc) { - Handle("PATCH", relativePath, handlerFunc); - } - void PATCH(const char* relativePath, http_handler handlerFunc) { - Handle("PATCH", relativePath, handlerFunc); - } - - // Any - void Any(const char* relativePath, http_sync_handler handlerFunc) { - Handle("HEAD", relativePath, handlerFunc); - Handle("GET", relativePath, handlerFunc); - Handle("POST", relativePath, handlerFunc); - Handle("PUT", relativePath, handlerFunc); - Handle("DELETE", relativePath, handlerFunc); - Handle("PATCH", relativePath, handlerFunc); - } - void Any(const char* relativePath, http_async_handler handlerFunc) { - Handle("HEAD", relativePath, handlerFunc); - Handle("GET", relativePath, handlerFunc); - Handle("POST", relativePath, handlerFunc); - Handle("PUT", relativePath, handlerFunc); - Handle("DELETE", relativePath, handlerFunc); - Handle("PATCH", relativePath, handlerFunc); - } - void Any(const char* relativePath, http_handler handlerFunc) { - Handle("HEAD", relativePath, handlerFunc); - Handle("GET", relativePath, handlerFunc); - Handle("POST", relativePath, handlerFunc); - Handle("PUT", relativePath, handlerFunc); - Handle("DELETE", relativePath, handlerFunc); - Handle("PATCH", relativePath, handlerFunc); - } -}; - -#endif // HV_HTTP_SERVICE_H_ diff --git a/src-libhv/http/server/WebSocketServer.h b/src-libhv/http/server/WebSocketServer.h deleted file mode 100644 index 7406f200a..000000000 --- a/src-libhv/http/server/WebSocketServer.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef HV_WEBSOCKET_SERVER_H_ -#define HV_WEBSOCKET_SERVER_H_ - -/* - * @demo examples/websocket_server_test.cpp - */ - -#include "HttpServer.h" -#include "WebSocketChannel.h" - -struct WebSocketService { - std::function onopen; - std::function onmessage; - std::function onclose; - int ping_interval; - - WebSocketService() { - ping_interval = 10000; // ms - } -}; -#define WebSocketServerCallbacks WebSocketService // deprecated - -#define websocket_server_t http_server_t -#define websocket_server_run http_server_run -#define websocket_server_stop http_server_stop - -#endif // HV_WEBSOCKET_SERVER_H_ diff --git a/src-libhv/misc/grpc_server.h b/src-libhv/misc/grpc_server.h deleted file mode 100644 index 049d00bbe..000000000 --- a/src-libhv/misc/grpc_server.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef GRPC_SERVER_H -#define GRPC_SERVER_H - -#include "grpcpp/grpcpp.h" -using grpc::ServerBuilder; -using grpc::Server; -using grpc::Service; -using grpc::ServerCompletionQueue; - -// GRPC_DEFAULT_MAX_RECV_MESSAGE_LENGTH = 4M -// GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH = 4M -#define GRPC_MAX_RECV_MESSAGE_LENGTH 1<<24 // 16M -#define GRPC_MAX_SEND_MESSAGE_LENGTH 1<<24 // 16M - -class GrpcServer { -public: - GrpcServer(int port) : _port(port) { - char srvaddr[128] = {0}; - snprintf(srvaddr, sizeof(srvaddr), "%s:%d", "0.0.0.0", _port); - build_.AddListeningPort(srvaddr, grpc::InsecureServerCredentials()); - build_.AddChannelArgument(GRPC_ARG_KEEPALIVE_TIME_MS, 30000); - build_.AddChannelArgument(GRPC_ARG_KEEPALIVE_TIMEOUT_MS, 5000); - build_.AddChannelArgument(GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS, 1); - build_.SetMaxReceiveMessageSize(GRPC_MAX_RECV_MESSAGE_LENGTH); - build_.SetMaxSendMessageSize(GRPC_MAX_SEND_MESSAGE_LENGTH); - } - - void RegisterService(Service* service) { - build_.RegisterService(service); - } - - void Run(bool wait=true) { - server_ = build_.BuildAndStart(); - if (wait) { - server_->Wait(); - } - } - -public: - int _port; - ServerBuilder build_; - std::unique_ptr server_; -}; - -#endif // GRPC_SERVER_H diff --git a/src-libhv/misc/win32_getopt.h b/src-libhv/misc/win32_getopt.h deleted file mode 100644 index 697ad9fcc..000000000 --- a/src-libhv/misc/win32_getopt.h +++ /dev/null @@ -1,653 +0,0 @@ -#ifndef __GETOPT_H__ -/** - * DISCLAIMER - * This file is part of the mingw-w64 runtime package. - * - * The mingw-w64 runtime package and its code is distributed in the hope that it - * will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR - * IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to - * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - /* - * Copyright (c) 2002 Todd C. Miller - * - * 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. - * - * Sponsored in part by the Defense Advanced Research Projects - * Agency (DARPA) and Air Force Research Laboratory, Air Force - * Materiel Command, USAF, under agreement number F39502-99-1-0512. - */ -/*- - * Copyright (c) 2000 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Dieter Baron and Thomas Klausner. - * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. - */ - -#pragma warning(disable:4996); - -#define __GETOPT_H__ - -/* All the headers include this file. */ -#include -#include -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */ - -#ifdef REPLACE_GETOPT -int opterr = 1; /* if error message should be printed */ -int optind = 1; /* index into parent argv vector */ -int optopt = '?'; /* character checked for validity */ -#undef optreset /* see getopt.h */ -#define optreset __mingw_optreset -int optreset; /* reset getopt */ -char *optarg; /* argument associated with option */ -#endif - -//extern int optind; /* index of first non-option in argv */ -//extern int optopt; /* single option character, as parsed */ -//extern int opterr; /* flag to enable built-in diagnostics... */ -// /* (user may set to zero, to suppress) */ -// -//extern char *optarg; /* pointer to argument of current option */ - -#define PRINT_ERROR ((opterr) && (*options != ':')) - -#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ -#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ -#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ - -/* return values */ -#define BADCH (int)'?' -#define BADARG ((*options == ':') ? (int)':' : (int)'?') -#define INORDER (int)1 - -#ifndef __CYGWIN__ -#define __progname __argv[0] -#else -extern char __declspec(dllimport) *__progname; -#endif - -#ifdef __CYGWIN__ -static char EMSG[] = ""; -#else -#define EMSG (char*)"" -#endif - -static int getopt_internal(int, char * const *, const char *, - const struct option *, int *, int); -static int parse_long_options(char * const *, const char *, - const struct option *, int *, int); -static int gcd(int, int); -static void permute_args(int, int, int, char * const *); - -static char *place = EMSG; /* option letter processing */ - -/* XXX: set optreset to 1 rather than these two */ -static int nonopt_start = -1; /* first non option argument (for permute) */ -static int nonopt_end = -1; /* first option after non options (for permute) */ - -/* Error messages */ -static const char recargchar[] = "option requires an argument -- %c"; -static const char recargstring[] = "option requires an argument -- %s"; -static const char ambig[] = "ambiguous option -- %.*s"; -static const char noarg[] = "option doesn't take an argument -- %.*s"; -static const char illoptchar[] = "unknown option -- %c"; -static const char illoptstring[] = "unknown option -- %s"; - -static void -_vwarnx(const char *fmt,va_list ap) -{ - (void)fprintf(stderr,"%s: ",__progname); - if (fmt != NULL) - (void)vfprintf(stderr,fmt,ap); - (void)fprintf(stderr,"\n"); -} - -static void -warnx(const char *fmt,...) -{ - va_list ap; - va_start(ap,fmt); - _vwarnx(fmt,ap); - va_end(ap); -} - -/* - * Compute the greatest common divisor of a and b. - */ -static int -gcd(int a, int b) -{ - int c; - - c = a % b; - while (c != 0) { - a = b; - b = c; - c = a % b; - } - - return (b); -} - -/* - * Exchange the block from nonopt_start to nonopt_end with the block - * from nonopt_end to opt_end (keeping the same order of arguments - * in each block). - */ -static void -permute_args(int panonopt_start, int panonopt_end, int opt_end, - char * const *nargv) -{ - int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; - char *swap; - - /* - * compute lengths of blocks and number and size of cycles - */ - nnonopts = panonopt_end - panonopt_start; - nopts = opt_end - panonopt_end; - ncycle = gcd(nnonopts, nopts); - cyclelen = (opt_end - panonopt_start) / ncycle; - - for (i = 0; i < ncycle; i++) { - cstart = panonopt_end+i; - pos = cstart; - for (j = 0; j < cyclelen; j++) { - if (pos >= panonopt_end) - pos -= nnonopts; - else - pos += nopts; - swap = nargv[pos]; - /* LINTED const cast */ - ((char **) nargv)[pos] = nargv[cstart]; - /* LINTED const cast */ - ((char **)nargv)[cstart] = swap; - } - } -} - -#ifdef REPLACE_GETOPT -/* - * getopt -- - * Parse argc/argv argument vector. - * - * [eventually this will replace the BSD getopt] - */ -int -getopt(int nargc, char * const *nargv, const char *options) -{ - - /* - * We don't pass FLAG_PERMUTE to getopt_internal() since - * the BSD getopt(3) (unlike GNU) has never done this. - * - * Furthermore, since many privileged programs call getopt() - * before dropping privileges it makes sense to keep things - * as simple (and bug-free) as possible. - */ - return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); -} -#endif /* REPLACE_GETOPT */ - -//extern int getopt(int nargc, char * const *nargv, const char *options); - -#ifdef _BSD_SOURCE -/* - * BSD adds the non-standard `optreset' feature, for reinitialisation - * of `getopt' parsing. We support this feature, for applications which - * proclaim their BSD heritage, before including this header; however, - * to maintain portability, developers are advised to avoid it. - */ -# define optreset __mingw_optreset -extern int optreset; -#endif -#ifdef __cplusplus -} -#endif -/* - * POSIX requires the `getopt' API to be specified in `unistd.h'; - * thus, `unistd.h' includes this header. However, we do not want - * to expose the `getopt_long' or `getopt_long_only' APIs, when - * included in this manner. Thus, close the standard __GETOPT_H__ - * declarations block, and open an additional __GETOPT_LONG_H__ - * specific block, only when *not* __UNISTD_H_SOURCED__, in which - * to declare the extended API. - */ -#endif /* !defined(__GETOPT_H__) */ - -#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) -#define __GETOPT_LONG_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -struct option /* specification for a long form option... */ -{ - const char *name; /* option name, without leading hyphens */ - int has_arg; /* does it take an argument? */ - int *flag; /* where to save its status, or NULL */ - int val; /* its associated status value */ -}; - -enum /* permitted values for its `has_arg' field... */ -{ - no_argument = 0, /* option never takes an argument */ - required_argument, /* option always requires an argument */ - optional_argument /* option may take an argument */ -}; - -/* - * parse_long_options -- - * Parse long options in argc/argv argument vector. - * Returns -1 if short_too is set and the option does not match long_options. - */ -static int -parse_long_options(char * const *nargv, const char *options, - const struct option *long_options, int *idx, int short_too) -{ - char *current_argv, *has_equal; - size_t current_argv_len; - int i, ambiguous, match; - -#define IDENTICAL_INTERPRETATION(_x, _y) \ - (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \ - long_options[(_x)].flag == long_options[(_y)].flag && \ - long_options[(_x)].val == long_options[(_y)].val) - - current_argv = place; - match = -1; - ambiguous = 0; - - optind++; - - if ((has_equal = strchr(current_argv, '=')) != NULL) { - /* argument found (--option=arg) */ - current_argv_len = has_equal - current_argv; - has_equal++; - } else - current_argv_len = strlen(current_argv); - - for (i = 0; long_options[i].name; i++) { - /* find matching long option */ - if (strncmp(current_argv, long_options[i].name, - current_argv_len)) - continue; - - if (strlen(long_options[i].name) == current_argv_len) { - /* exact match */ - match = i; - ambiguous = 0; - break; - } - /* - * If this is a known short option, don't allow - * a partial match of a single character. - */ - if (short_too && current_argv_len == 1) - continue; - - if (match == -1) /* partial match */ - match = i; - else if (!IDENTICAL_INTERPRETATION(i, match)) - ambiguous = 1; - } - if (ambiguous) { - /* ambiguous abbreviation */ - if (PRINT_ERROR) - warnx(ambig, (int)current_argv_len, - current_argv); - optopt = 0; - return (BADCH); - } - if (match != -1) { /* option found */ - if (long_options[match].has_arg == no_argument - && has_equal) { - if (PRINT_ERROR) - warnx(noarg, (int)current_argv_len, - current_argv); - /* - * XXX: GNU sets optopt to val regardless of flag - */ - if (long_options[match].flag == NULL) - optopt = long_options[match].val; - else - optopt = 0; - return (BADARG); - } - if (long_options[match].has_arg == required_argument || - long_options[match].has_arg == optional_argument) { - if (has_equal) - optarg = has_equal; - else if (long_options[match].has_arg == - required_argument) { - /* - * optional argument doesn't use next nargv - */ - optarg = nargv[optind++]; - } - } - if ((long_options[match].has_arg == required_argument) - && (optarg == NULL)) { - /* - * Missing argument; leading ':' indicates no error - * should be generated. - */ - if (PRINT_ERROR) - warnx(recargstring, - current_argv); - /* - * XXX: GNU sets optopt to val regardless of flag - */ - if (long_options[match].flag == NULL) - optopt = long_options[match].val; - else - optopt = 0; - --optind; - return (BADARG); - } - } else { /* unknown option */ - if (short_too) { - --optind; - return (-1); - } - if (PRINT_ERROR) - warnx(illoptstring, current_argv); - optopt = 0; - return (BADCH); - } - if (idx) - *idx = match; - if (long_options[match].flag) { - *long_options[match].flag = long_options[match].val; - return (0); - } else - return (long_options[match].val); -#undef IDENTICAL_INTERPRETATION -} - -/* - * getopt_internal -- - * Parse argc/argv argument vector. Called by user level routines. - */ -static int -getopt_internal(int nargc, char * const *nargv, const char *options, - const struct option *long_options, int *idx, int flags) -{ - char *oli; /* option letter list index */ - int optchar, short_too; - static int posixly_correct = -1; - - if (options == NULL) - return (-1); - - /* - * XXX Some GNU programs (like cvs) set optind to 0 instead of - * XXX using optreset. Work around this braindamage. - */ - if (optind == 0) - optind = optreset = 1; - - /* - * Disable GNU extensions if POSIXLY_CORRECT is set or options - * string begins with a '+'. - * - * CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or - * optreset != 0 for GNU compatibility. - */ - if (posixly_correct == -1 || optreset != 0) - posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); - if (*options == '-') - flags |= FLAG_ALLARGS; - else if (posixly_correct || *options == '+') - flags &= ~FLAG_PERMUTE; - if (*options == '+' || *options == '-') - options++; - - optarg = NULL; - if (optreset) - nonopt_start = nonopt_end = -1; -start: - if (optreset || !*place) { /* update scanning pointer */ - optreset = 0; - if (optind >= nargc) { /* end of argument vector */ - place = EMSG; - if (nonopt_end != -1) { - /* do permutation, if we have to */ - permute_args(nonopt_start, nonopt_end, - optind, nargv); - optind -= nonopt_end - nonopt_start; - } - else if (nonopt_start != -1) { - /* - * If we skipped non-options, set optind - * to the first of them. - */ - optind = nonopt_start; - } - nonopt_start = nonopt_end = -1; - return (-1); - } - if (*(place = nargv[optind]) != '-' || - (place[1] == '\0' && strchr(options, '-') == NULL)) { - place = EMSG; /* found non-option */ - if (flags & FLAG_ALLARGS) { - /* - * GNU extension: - * return non-option as argument to option 1 - */ - optarg = nargv[optind++]; - return (INORDER); - } - if (!(flags & FLAG_PERMUTE)) { - /* - * If no permutation wanted, stop parsing - * at first non-option. - */ - return (-1); - } - /* do permutation */ - if (nonopt_start == -1) - nonopt_start = optind; - else if (nonopt_end != -1) { - permute_args(nonopt_start, nonopt_end, - optind, nargv); - nonopt_start = optind - - (nonopt_end - nonopt_start); - nonopt_end = -1; - } - optind++; - /* process next argument */ - goto start; - } - if (nonopt_start != -1 && nonopt_end == -1) - nonopt_end = optind; - - /* - * If we have "-" do nothing, if "--" we are done. - */ - if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { - optind++; - place = EMSG; - /* - * We found an option (--), so if we skipped - * non-options, we have to permute. - */ - if (nonopt_end != -1) { - permute_args(nonopt_start, nonopt_end, - optind, nargv); - optind -= nonopt_end - nonopt_start; - } - nonopt_start = nonopt_end = -1; - return (-1); - } - } - - /* - * Check long options if: - * 1) we were passed some - * 2) the arg is not just "-" - * 3) either the arg starts with -- we are getopt_long_only() - */ - if (long_options != NULL && place != nargv[optind] && - (*place == '-' || (flags & FLAG_LONGONLY))) { - short_too = 0; - if (*place == '-') - place++; /* --foo long option */ - else if (*place != ':' && strchr(options, *place) != NULL) - short_too = 1; /* could be short option too */ - - optchar = parse_long_options(nargv, options, long_options, - idx, short_too); - if (optchar != -1) { - place = EMSG; - return (optchar); - } - } - - if ((optchar = (int)*place++) == (int)':' || - (optchar == (int)'-' && *place != '\0') || - (oli = (char*)strchr(options, optchar)) == NULL) { - /* - * If the user specified "-" and '-' isn't listed in - * options, return -1 (non-option) as per POSIX. - * Otherwise, it is an unknown option character (or ':'). - */ - if (optchar == (int)'-' && *place == '\0') - return (-1); - if (!*place) - ++optind; - if (PRINT_ERROR) - warnx(illoptchar, optchar); - optopt = optchar; - return (BADCH); - } - if (long_options != NULL && optchar == 'W' && oli[1] == ';') { - /* -W long-option */ - if (*place) /* no space */ - /* NOTHING */; - else if (++optind >= nargc) { /* no arg */ - place = EMSG; - if (PRINT_ERROR) - warnx(recargchar, optchar); - optopt = optchar; - return (BADARG); - } else /* white space */ - place = nargv[optind]; - optchar = parse_long_options(nargv, options, long_options, - idx, 0); - place = EMSG; - return (optchar); - } - if (*++oli != ':') { /* doesn't take argument */ - if (!*place) - ++optind; - } else { /* takes (optional) argument */ - optarg = NULL; - if (*place) /* no white space */ - optarg = place; - else if (oli[1] != ':') { /* arg not optional */ - if (++optind >= nargc) { /* no arg */ - place = EMSG; - if (PRINT_ERROR) - warnx(recargchar, optchar); - optopt = optchar; - return (BADARG); - } else - optarg = nargv[optind]; - } - place = EMSG; - ++optind; - } - /* dump back option letter */ - return (optchar); -} - -/* - * getopt_long -- - * Parse argc/argv argument vector. - */ -int -getopt_long(int nargc, char * const *nargv, const char *options, - const struct option *long_options, int *idx) -{ - - return (getopt_internal(nargc, nargv, options, long_options, idx, - FLAG_PERMUTE)); -} - -/* - * getopt_long_only -- - * Parse argc/argv argument vector. - */ -int -getopt_long_only(int nargc, char * const *nargv, const char *options, - const struct option *long_options, int *idx) -{ - - return (getopt_internal(nargc, nargv, options, long_options, idx, - FLAG_PERMUTE|FLAG_LONGONLY)); -} - -//extern int getopt_long(int nargc, char * const *nargv, const char *options, -// const struct option *long_options, int *idx); -//extern int getopt_long_only(int nargc, char * const *nargv, const char *options, -// const struct option *long_options, int *idx); -/* - * Previous MinGW implementation had... - */ -#ifndef HAVE_DECL_GETOPT -/* - * ...for the long form API only; keep this for compatibility. - */ -# define HAVE_DECL_GETOPT 1 -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */ \ No newline at end of file diff --git a/src-libhv/util/base64.h b/src-libhv/util/base64.h deleted file mode 100644 index 92f1243d3..000000000 --- a/src-libhv/util/base64.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef HV_BASE64_H_ -#define HV_BASE64_H_ - -#include "hexport.h" - -enum {BASE64_OK = 0, BASE64_INVALID}; - -#define BASE64_ENCODE_OUT_SIZE(s) (((s) + 2) / 3 * 4) -#define BASE64_DECODE_OUT_SIZE(s) (((s)) / 4 * 3) - -BEGIN_EXTERN_C - -HV_EXPORT int base64_encode(const unsigned char *in, unsigned int inlen, char *out); -HV_EXPORT int base64_decode(const char *in, unsigned int inlen, unsigned char *out); - -END_EXTERN_C - -#endif // HV_BASE64_H_ diff --git a/src.wsjcpp/CMakeLists.txt b/src.wsjcpp/CMakeLists.txt index 29795364b..a2ffd08e6 100644 --- a/src.wsjcpp/CMakeLists.txt +++ b/src.wsjcpp/CMakeLists.txt @@ -1,14 +1,14 @@ -# Automaticly generated by wsjcpp@v0.2.2 +# Automaticly generated by wsjcpp@v0.2.5 cmake_minimum_required(VERSION 3.0) -add_definitions(-DWSJCPP_APP_VERSION="v0.2.51") +add_definitions(-DWSJCPP_APP_VERSION="v0.2.53") add_definitions(-DWSJCPP_APP_NAME="fhq-server") if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set(MACOSX TRUE) endif() -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) set (WSJCPP_LIBRARIES "") set (WSJCPP_INCLUDE_DIRS "") @@ -18,87 +18,87 @@ find_package(Threads REQUIRED) list (APPEND WSJCPP_LIBRARIES ${CMAKE_THREAD_LIBS_INIT}) # wsjcpp-levenshtein:v0.0.1 -list (APPEND WSJCPP_INCLUDE_DIRS "./src.wsjcpp/wsjcpp_levenshtein/") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_levenshtein/wsjcpp_levenshtein.cpp") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_levenshtein/wsjcpp_levenshtein.h") +list (APPEND WSJCPP_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_levenshtein/") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_levenshtein/wsjcpp_levenshtein.cpp") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_levenshtein/wsjcpp_levenshtein.h") # wsjcpp-hashes:v0.1.4 -list (APPEND WSJCPP_INCLUDE_DIRS "./src.wsjcpp/wsjcpp_hashes/") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_hashes/md5.cpp") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_hashes/md5.h") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_hashes/smallsha1.h") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_hashes/smallsha1.cpp") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_hashes/wsjcpp_hashes.cpp") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_hashes/wsjcpp_hashes.h") - -# wsjcpp-core:v0.2.2 -list (APPEND WSJCPP_INCLUDE_DIRS "./src.wsjcpp/wsjcpp_core/") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_core/wsjcpp_core.cpp") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_core/wsjcpp_core.h") +list (APPEND WSJCPP_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_hashes/") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_hashes/md5.cpp") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_hashes/md5.h") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_hashes/smallsha1.h") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_hashes/smallsha1.cpp") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_hashes/wsjcpp_hashes.cpp") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_hashes/wsjcpp_hashes.h") + +# wsjcpp-core:v0.2.3 +list (APPEND WSJCPP_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_core/") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_core/wsjcpp_core.cpp") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_core/wsjcpp_core.h") # nlohmann/json:v3.10.5 -list (APPEND WSJCPP_INCLUDE_DIRS "./src.wsjcpp/nlohmann_json/") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/nlohmann_json/json.hpp") +list (APPEND WSJCPP_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/./src.wsjcpp/nlohmann_json/") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/nlohmann_json/json.hpp") -# wsjcpp-validators:v0.1.2 -list (APPEND WSJCPP_INCLUDE_DIRS "./src.wsjcpp/wsjcpp_validators/") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_validators/wsjcpp_validators.h") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_validators/wsjcpp_validators.cpp") +# wsjcpp-validators:v0.1.3 +list (APPEND WSJCPP_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_validators/") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_validators/wsjcpp_validators.h") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_validators/wsjcpp_validators.cpp") # wsjcpp-print-tree:v0.1.0 -list (APPEND WSJCPP_INCLUDE_DIRS "./src.wsjcpp/wsjcpp_print_tree/") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_print_tree/wsjcpp_print_tree.h") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_print_tree/wsjcpp_print_tree.cpp") +list (APPEND WSJCPP_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_print_tree/") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_print_tree/wsjcpp_print_tree.h") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_print_tree/wsjcpp_print_tree.cpp") # wsjcpp-geoip:v0.1.0 -list (APPEND WSJCPP_INCLUDE_DIRS "./src.wsjcpp/wsjcpp_geoip/") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_geoip/wsjcpp_geoip.cpp") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_geoip/wsjcpp_geoip.h") +list (APPEND WSJCPP_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_geoip/") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_geoip/wsjcpp_geoip.cpp") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_geoip/wsjcpp_geoip.h") # wsjcpp-light-web-server:v0.1.1 -list (APPEND WSJCPP_INCLUDE_DIRS "./src.wsjcpp/wsjcpp_light_web_server/") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_light_web_server/wsjcpp_light_web_http_request.h") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_light_web_server/wsjcpp_light_web_http_request.cpp") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_light_web_server/wsjcpp_light_web_http_response.h") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_light_web_server/wsjcpp_light_web_http_response.cpp") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_light_web_server/wsjcpp_light_web_deque_http_requests.h") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_light_web_server/wsjcpp_light_web_deque_http_requests.cpp") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_light_web_server/wsjcpp_light_web_http_handler_rewrite_folder.h") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_light_web_server/wsjcpp_light_web_http_handler_rewrite_folder.cpp") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_light_web_server/wsjcpp_light_web_http_handler_web_folder.h") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_light_web_server/wsjcpp_light_web_http_handler_web_folder.cpp") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_light_web_server/wsjcpp_light_web_server.h") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_light_web_server/wsjcpp_light_web_server.cpp") +list (APPEND WSJCPP_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_light_web_server/") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_light_web_server/wsjcpp_light_web_http_request.h") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_light_web_server/wsjcpp_light_web_http_request.cpp") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_light_web_server/wsjcpp_light_web_http_response.h") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_light_web_server/wsjcpp_light_web_http_response.cpp") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_light_web_server/wsjcpp_light_web_deque_http_requests.h") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_light_web_server/wsjcpp_light_web_deque_http_requests.cpp") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_light_web_server/wsjcpp_light_web_http_handler_rewrite_folder.h") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_light_web_server/wsjcpp_light_web_http_handler_rewrite_folder.cpp") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_light_web_server/wsjcpp_light_web_http_handler_web_folder.h") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_light_web_server/wsjcpp_light_web_http_handler_web_folder.cpp") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_light_web_server/wsjcpp_light_web_server.h") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_light_web_server/wsjcpp_light_web_server.cpp") # wsjcpp-employees:v0.1.1 -list (APPEND WSJCPP_INCLUDE_DIRS "./src.wsjcpp/wsjcpp_employees/") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_employees/wsjcpp_employees.h") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_employees/wsjcpp_employees.cpp") +list (APPEND WSJCPP_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_employees/") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_employees/wsjcpp_employees.h") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_employees/wsjcpp_employees.cpp") # wsjcpp-diff-text:v0.1.0 -list (APPEND WSJCPP_INCLUDE_DIRS "./src.wsjcpp/wsjcpp_diff_text/") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_diff_text/wsjcpp_diff_text.cpp") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_diff_text/wsjcpp_diff_text.h") +list (APPEND WSJCPP_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_diff_text/") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_diff_text/wsjcpp_diff_text.cpp") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_diff_text/wsjcpp_diff_text.h") # wsjcpp-storages:v0.1.3 -list (APPEND WSJCPP_INCLUDE_DIRS "./src.wsjcpp/wsjcpp_storages/") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_storages/wsjcpp_storages.cpp") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_storages/wsjcpp_storages.h") +list (APPEND WSJCPP_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_storages/") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_storages/wsjcpp_storages.cpp") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_storages/wsjcpp_storages.h") # wsjcpp-arguments:v0.2.1 -list (APPEND WSJCPP_INCLUDE_DIRS "./src.wsjcpp/wsjcpp_arguments/") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_arguments/wsjcpp_arguments.cpp") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_arguments/wsjcpp_arguments.h") +list (APPEND WSJCPP_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_arguments/") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_arguments/wsjcpp_arguments.cpp") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_arguments/wsjcpp_arguments.h") -# wsjcpp-yaml:v0.1.7 -list (APPEND WSJCPP_INCLUDE_DIRS "./src.wsjcpp/wsjcpp_yaml/") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_yaml/wsjcpp_yaml.cpp") -list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_yaml/wsjcpp_yaml.h") +# wsjcpp-yaml:v0.1.8 +list (APPEND WSJCPP_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_yaml/") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_yaml/wsjcpp_yaml.cpp") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/./src.wsjcpp/wsjcpp_yaml/wsjcpp_yaml.h") # resources.wsjcpp -list (APPEND WSJCPP_INCLUDE_DIRS "./src-resources.wsjcpp/") -list (APPEND WSJCPP_SOURCES "./src-resources.wsjcpp/__src_resources_user_default_icon_png_path340587.h") -list (APPEND WSJCPP_SOURCES "./src-resources.wsjcpp/__src_resources_user_default_icon_png_path340587.cpp") +list (APPEND WSJCPP_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/src-resources.wsjcpp/") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/src-resources.wsjcpp/__src_resources_user_default_icon_png_path340587.h") +list (APPEND WSJCPP_SOURCES "${CMAKE_SOURCE_DIR}/src-resources.wsjcpp/__src_resources_user_default_icon_png_path340587.cpp") # required-libraries list (APPEND WSJCPP_LIBRARIES "-lpthread") diff --git a/src.wsjcpp/wsjcpp_core/wsjcpp.hold.yml b/src.wsjcpp/wsjcpp_core/wsjcpp.hold.yml index 7ef821249..d77226607 100644 --- a/src.wsjcpp/wsjcpp_core/wsjcpp.hold.yml +++ b/src.wsjcpp/wsjcpp_core/wsjcpp.hold.yml @@ -3,7 +3,7 @@ cmake_cxx_standard: 17 cmake_minimum_required: 3.0 name: wsjcpp-core -version: v0.2.2 +version: v0.2.3 description: Basic Utils for wsjcpp issues: https://github.com/wsjcpp/wsjcpp-core/issues repositories: @@ -21,11 +21,11 @@ distribution: - source-file: src/wsjcpp_core.cpp target-file: wsjcpp_core.cpp type: "source-code" - sha1: "15a0d9e4fcd6e34f9c4ccdc9dd6c855814abc020" + sha1: "9153a6eff17ea98ac510d96de7060dd25053bdb3" - source-file: src/wsjcpp_core.h target-file: wsjcpp_core.h type: "source-code" # todo must be header-file - sha1: "a885e73c96bc564158cb97525525c1b7e5b455a6" + sha1: "c2056e306e9cda6b90b764e83709b3c4e0199b8d" - source-file: "src/wsjcpp_unit_tests.cpp" target-file: "wsjcpp_unit_tests.cpp" type: "unit-tests" @@ -95,4 +95,9 @@ unit-tests: description: "" - name: "ExtractFilepath" description: "" + - name: "StartsWith" + description: "" + + - name: "EndsWith" + description: "" diff --git a/src.wsjcpp/wsjcpp_core/wsjcpp_core.cpp b/src.wsjcpp/wsjcpp_core/wsjcpp_core.cpp index f96f933f9..d57530e0a 100644 --- a/src.wsjcpp/wsjcpp_core/wsjcpp_core.cpp +++ b/src.wsjcpp/wsjcpp_core/wsjcpp_core.cpp @@ -501,7 +501,7 @@ std::vector WsjcppCore::getListOfDirs(const std::string &sDirname) for (auto& entry : std::filesystem::directory_iterator(sDirname)) { if (entry.is_directory()) { std::string sPath = entry.path(); - sPath = sPath.substr(sDirname.length()+1); + sPath.erase(0, sDirname.size() + 1); vDirs.push_back(sPath); } } @@ -519,6 +519,7 @@ std::vector WsjcppCore::getListOfFiles(const std::string &sDirname) for (auto& entry: std::filesystem::directory_iterator(sDirname)) { if (!entry.is_directory()) { std::string sPath = entry.path(); + sPath.erase(0, sDirname.size() + 1); vFiles.push_back(sPath); } } @@ -837,8 +838,6 @@ std::string WsjcppCore::extractURLProtocol(const std::string& sValue) { return sRet; } -// --------------------------------------------------------------------- - bool WsjcppCore::getEnv(const std::string& sName, std::string& sValue) { if (const char* env_p = std::getenv(sName.c_str())) { sValue = std::string(env_p); @@ -847,16 +846,14 @@ bool WsjcppCore::getEnv(const std::string& sName, std::string& sValue) { return false; } -// --------------------------------------------------------------------- - std::string WsjcppCore::encodeUriComponent(const std::string& sValue) { std::stringstream ssRet; for (int i = 0; i < sValue.length(); i++) { char c = sValue[i]; if ( c == '-' || c == '_' || c == '.' || c == '!' - || c == '~' || c == '*' || c == '\'' - || c == '(' || c == ')' || (c >= '0' && c <= '9') + || c == '~' || c == '*' || c == '\'' + || c == '(' || c == ')' || (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ) { ssRet << c; @@ -867,8 +864,6 @@ std::string WsjcppCore::encodeUriComponent(const std::string& sValue) { return ssRet.str(); } -// --------------------------------------------------------------------- - std::string WsjcppCore::decodeUriComponent(const std::string& sValue) { std::string sRet = ""; std::string sHex = ""; @@ -892,8 +887,6 @@ std::string WsjcppCore::decodeUriComponent(const std::string& sValue) { return sRet; } -// --------------------------------------------------------------------- - std::string WsjcppCore::getHumanSizeBytes(long nBytes) { if (nBytes == 0) { return "0B"; @@ -904,7 +897,7 @@ std::string WsjcppCore::getHumanSizeBytes(long nBytes) { for (int i = 0; i < 6; i++) { if (n0 >= 1 && n0 < 1000) { return std::to_string(n0) + arrPrefix[i]; - } + } n0 = nBytes / 1000; n1 = nBytes - n0 * 1000; n0 += n1 >= 500 ? 1 : 0; @@ -917,8 +910,6 @@ std::string WsjcppCore::getHumanSizeBytes(long nBytes) { return std::to_string(nBytes) + "PB"; } -// --------------------------------------------------------------------- - bool WsjcppCore::recoursiveCopyFiles(const std::string& sSourceDir, const std::string& sTargetDir) { if (!WsjcppCore::dirExists(sSourceDir)) { WsjcppLog::err("recoursiveCopyFiles", "Source Dir '" + sSourceDir + "' did not exists"); @@ -959,8 +950,6 @@ bool WsjcppCore::recoursiveCopyFiles(const std::string& sSourceDir, const std::s return true; } -// --------------------------------------------------------------------- - bool WsjcppCore::recoursiveRemoveDir(const std::string& sDir) { if (!WsjcppCore::dirExists(sDir)) { WsjcppLog::err("recoursiveCopyFiles", "Dir '" + sDir + "' did not exists"); @@ -989,8 +978,6 @@ bool WsjcppCore::recoursiveRemoveDir(const std::string& sDir) { return true; } -// --------------------------------------------------------------------- - bool WsjcppCore::setFilePermissions(const std::string& sFilePath, const WsjcppFilePermissions &filePermissions, std::string& sError) { mode_t m = 0x0; @@ -1017,8 +1004,6 @@ bool WsjcppCore::setFilePermissions(const std::string& sFilePath, const WsjcppFi return true; } -// --------------------------------------------------------------------- - bool WsjcppCore::getFilePermissions(const std::string& sFilePath, WsjcppFilePermissions &filePermissions, std::string& sError) { if (!WsjcppCore::fileExists(sFilePath)) { sError = "File '" + sFilePath + "' - not found"; @@ -1040,7 +1025,7 @@ bool WsjcppCore::getFilePermissions(const std::string& sFilePath, WsjcppFilePerm filePermissions.setOwnerWriteFlag(m & S_IWUSR); filePermissions.setOwnerExecuteFlag(m & S_IXUSR); - + // group filePermissions.setGroupReadFlag(m & S_IRGRP); filePermissions.setGroupWriteFlag(m & S_IWGRP); @@ -1054,8 +1039,6 @@ bool WsjcppCore::getFilePermissions(const std::string& sFilePath, WsjcppFilePerm return true; } -// --------------------------------------------------------------------- - std::string WsjcppCore::doPadLeft(const std::string& sIn, char cWhat, size_t nLength) { std::string sRet; size_t nPadLen = nLength - sIn.length(); @@ -1065,8 +1048,6 @@ std::string WsjcppCore::doPadLeft(const std::string& sIn, char cWhat, size_t nLe return sRet + sIn; } -// --------------------------------------------------------------------- - std::string WsjcppCore::doPadRight(const std::string& sIn, char cWhat, size_t nLength) { std::string sRet; size_t nPadLen = nLength - sIn.length(); @@ -1076,11 +1057,22 @@ std::string WsjcppCore::doPadRight(const std::string& sIn, char cWhat, size_t nL return sIn + sRet; } +bool WsjcppCore::startsWith(const std::string& sLine, const std::string& sStart) { + return sLine.rfind(sStart, 0) == 0; +} + +bool WsjcppCore::endsWith(const std::string& sLine, const std::string& sEnd) { + // https://www.techiedelight.com/check-if-a-string-ends-with-another-string-in-cpp/ + if (sLine.length() < sEnd.length()) { + return false; + } + return std::equal(sEnd.rbegin(), sEnd.rend(), sLine.rbegin()); +} + // --------------------------------------------------------------------- // WsjcppLog WsjcppLogGlobalConf::WsjcppLogGlobalConf() { - // logDir = "./"; logPrefixFile = ""; logFile = ""; @@ -1089,8 +1081,6 @@ WsjcppLogGlobalConf::WsjcppLogGlobalConf() { logRotationPeriodInSeconds = 51000; } -// --------------------------------------------------------------------- - void WsjcppLogGlobalConf::doLogRotateUpdateFilename(bool bForce) { long t = WsjcppCore::getCurrentTimeInSeconds(); long nEverySeconds = logRotationPeriodInSeconds; // rotate log if started now or if time left more then 1 day @@ -1104,44 +1094,32 @@ void WsjcppLogGlobalConf::doLogRotateUpdateFilename(bool bForce) { WsjcppLogGlobalConf WsjcppLog::g_WSJCPP_LOG_GLOBAL_CONF; -// --------------------------------------------------------------------- - void WsjcppLog::info(const std::string & sTag, const std::string &sMessage) { WsjcppColorModifier def(WsjcppColorCode::FG_DEFAULT); WsjcppLog::add(def, "INFO", sTag, sMessage); } -// --------------------------------------------------------------------- - void WsjcppLog::err(const std::string & sTag, const std::string &sMessage) { WsjcppColorModifier red(WsjcppColorCode::FG_RED); WsjcppLog::add(red, "ERR", sTag, sMessage); } -// --------------------------------------------------------------------- - void WsjcppLog::throw_err(const std::string &sTag, const std::string &sMessage) { WsjcppColorModifier red(WsjcppColorCode::FG_RED); WsjcppLog::add(red, "ERR", sTag, sMessage); throw std::runtime_error(sMessage); } -// --------------------------------------------------------------------- - void WsjcppLog::warn(const std::string & sTag, const std::string &sMessage) { WsjcppColorModifier yellow(WsjcppColorCode::FG_YELLOW); WsjcppLog::add(yellow, "WARN",sTag, sMessage); } -// --------------------------------------------------------------------- - void WsjcppLog::ok(const std::string &sTag, const std::string &sMessage) { WsjcppColorModifier green(WsjcppColorCode::FG_GREEN); WsjcppLog::add(green, "OK", sTag, sMessage); } -// --------------------------------------------------------------------- - std::vector WsjcppLog::getLastLogMessages() { std::lock_guard lock(WsjcppLog::g_WSJCPP_LOG_GLOBAL_CONF.logMutex); std::vector vRet; @@ -1151,8 +1129,6 @@ std::vector WsjcppLog::getLastLogMessages() { return vRet; } -// --------------------------------------------------------------------- - void WsjcppLog::setLogDirectory(const std::string &sDirectoryPath) { WsjcppLog::g_WSJCPP_LOG_GLOBAL_CONF.logDir = sDirectoryPath; if (!WsjcppCore::dirExists(sDirectoryPath)) { @@ -1163,27 +1139,19 @@ void WsjcppLog::setLogDirectory(const std::string &sDirectoryPath) { WsjcppLog::g_WSJCPP_LOG_GLOBAL_CONF.doLogRotateUpdateFilename(true); } -// --------------------------------------------------------------------- - void WsjcppLog::setPrefixLogFile(const std::string &sPrefixLogFile) { WsjcppLog::g_WSJCPP_LOG_GLOBAL_CONF.logPrefixFile = sPrefixLogFile; WsjcppLog::g_WSJCPP_LOG_GLOBAL_CONF.doLogRotateUpdateFilename(true); } -// --------------------------------------------------------------------- - void WsjcppLog::setEnableLogFile(bool bEnable) { WsjcppLog::g_WSJCPP_LOG_GLOBAL_CONF.enableLogFile = bEnable; } -// --------------------------------------------------------------------- - void WsjcppLog::setRotationPeriodInSec(long nRotationPeriodInSec) { WsjcppLog::g_WSJCPP_LOG_GLOBAL_CONF.logRotationPeriodInSeconds = nRotationPeriodInSec; } -// --------------------------------------------------------------------- - void WsjcppLog::add(WsjcppColorModifier &clr, const std::string &sType, const std::string &sTag, const std::string &sMessage) { WsjcppLog::g_WSJCPP_LOG_GLOBAL_CONF.doLogRotateUpdateFilename(); @@ -1201,7 +1169,7 @@ void WsjcppLog::add(WsjcppColorModifier &clr, const std::string &sType, const st WsjcppLog::g_WSJCPP_LOG_GLOBAL_CONF.logLastMessages.pop_back(); } - // log file + // log file if (WsjcppLog::g_WSJCPP_LOG_GLOBAL_CONF.enableLogFile) { std::ofstream logFile(WsjcppLog::g_WSJCPP_LOG_GLOBAL_CONF.logFile, std::ios::app); if (!logFile) { @@ -1210,7 +1178,7 @@ void WsjcppLog::add(WsjcppColorModifier &clr, const std::string &sType, const st } logFile << sLogMessage << std::endl; - logFile.close(); + logFile.close(); } } @@ -1269,7 +1237,6 @@ const std::vector &WsjcppResourcesManager::list() { return *g_pWsjcppResourceFiles; } -// --------------------------------------------------------------------- /* bool WsjcppResourcesManager::make(const std::string &sWorkspace) { diff --git a/src.wsjcpp/wsjcpp_core/wsjcpp_core.h b/src.wsjcpp/wsjcpp_core/wsjcpp_core.h index 66c85a326..c5a1883a2 100644 --- a/src.wsjcpp/wsjcpp_core/wsjcpp_core.h +++ b/src.wsjcpp/wsjcpp_core/wsjcpp_core.h @@ -132,6 +132,9 @@ class WsjcppCore { static std::string doPadLeft(const std::string& sIn, char cWhat, size_t nLength); static std::string doPadRight(const std::string& sIn, char cWhat, size_t nLength); + static bool startsWith(const std::string& sLine, const std::string& sStart); + static bool endsWith(const std::string& sLine, const std::string& sEnd); + }; diff --git a/src.wsjcpp/wsjcpp_validators/wsjcpp.hold.yml b/src.wsjcpp/wsjcpp_validators/wsjcpp.hold.yml index c1e46e1ce..8f4a6c49e 100644 --- a/src.wsjcpp/wsjcpp_validators/wsjcpp.hold.yml +++ b/src.wsjcpp/wsjcpp_validators/wsjcpp.hold.yml @@ -1,9 +1,9 @@ wsjcpp_version: v0.0.1 cmake_minimum_required: 3.0 -cmake_cxx_standard: 11 +cmake_cxx_standard: 17 name: wsjcpp-validators -version: v0.1.2 +version: v0.1.3 description: Classes for data validation issues: https://github.com/wsjcpp/wsjcpp-validators/issues @@ -17,32 +17,21 @@ required-libraries: repositories: - type: main url: "https://github.com/wsjcpp/wsjcpp-validators" + authors: - name: Evgenii Sopov email: mrseakg@gmail.com -dependencies: - - name: "wsjcpp-core" - version: "v0.1.7" - url: "https://github.com/wsjcpp/wsjcpp-core:master" - origin: "https://github.com/" - installation-dir: "./src.wsjcpp/wsjcpp_core" - - name: "nlohmann/json" - version: "v3.9.1" - url: "https://github.com/nlohmann/json:develop" - origin: "https://github.com/" - installation-dir: "./src.wsjcpp/nlohmann_json" - distribution: - source-file: "src/wsjcpp_validators.h" target-file: "wsjcpp_validators.h" type: "source-code" - sha1: "78e7f62c964f5e36f3940e03a4c8f673feaea289" + sha1: "957928f53bee20c19889892fd11f048ea3e2878e" - source-file: "src/wsjcpp_validators.cpp" target-file: "wsjcpp_validators.cpp" type: "source-code" - sha1: "9f4bd5c96b74aae164e785549d72d3a3e37ca8e8" + sha1: "9a17d195d33a6e2b5311dc0695f2e1314eadf4d6" unit-tests: cases: - name: "ValidatorEmail" @@ -79,3 +68,12 @@ unit-tests: description: "Test validator" - name: "ValidatorIntegerMaxValue" description: "Test validator" + +dependencies: + - name: "wsjcpp-core" + version: "v0.2.3" + url: "https://github.com/wsjcpp/wsjcpp-core:master" + origin: "https://github.com/" + installation-dir: "./src.wsjcpp/wsjcpp_core" + installation-datetime: "Mon, 14 Jul 2025 16:38:16 GMT" + diff --git a/src.wsjcpp/wsjcpp_validators/wsjcpp_validators.cpp b/src.wsjcpp/wsjcpp_validators/wsjcpp_validators.cpp index 6ccdc343e..60fa6b3f8 100644 --- a/src.wsjcpp/wsjcpp_validators/wsjcpp_validators.cpp +++ b/src.wsjcpp/wsjcpp_validators/wsjcpp_validators.cpp @@ -1,799 +1,783 @@ +/* +MIT License + +Copyright (c) 2020-2025 wsjcpp + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + #include "wsjcpp_validators.h" #include #include -bool WsjcppValidators::isValidDate(const std::string &sValue, std::string &sError) { - int nSize = sValue.size(); - if (nSize != 10) { - sError = "Invalid size format expected length 10"; - return false; - } - - for (int i = 0; i < 10; i++) { - char c = sValue[i]; - if (i == 4 || i == 7) { - if (c != '-') { - sError = "Expected '-' in " + std::to_string(i) + " position, but got '"; - sError += c; - sError += "'"; - return false; - } - continue; - } - if (c < '0' || c > '9') { - sError = "Unexpected char '"; - sError += c; - sError += "' in " + std::to_string(i) + " position"; - return false; - } - - } - // 2020-01-01 - std::string sYear = sValue.substr(0,4); - int nYear = std::atoi(sYear.c_str()); - - std::string sMonth = sValue.substr(5,2); - int nMonth = std::atoi(sMonth.c_str()); - if (nMonth < 1 || nMonth > 12) { - sError = "Invalid value nunber of month '" + std::to_string(nMonth) + "' expected 01..12"; - return false; - } - - int nMaxDay = 0; - if (nMonth == 1 || nMonth == 3 || nMonth == 5 || nMonth == 7 || nMonth == 8 || nMonth == 10 || nMonth == 12) { - nMaxDay = 31; - } else if (nMonth == 4 || nMonth == 6 || nMonth == 9 || nMonth == 11) { - nMaxDay = 30; - } else if (nMonth == 2 && nYear % 4 == 0) { - nMaxDay = 29; - } else if (nMonth == 2 && nYear % 4 != 0) { - nMaxDay = 28; - } - - std::string sDay = sValue.substr(8,2); - int nDay = std::atoi(sDay.c_str()); - if (nDay < 1 || nDay > nMaxDay) { - sError = "Invalid value number of day '" + std::to_string(nDay) + "' expected 01.." + std::to_string(nMaxDay); +bool WsjcppValidators::isValidDate(const std::string &sValue, + std::string &sError) { + int nSize = sValue.size(); + if (nSize != 10) { + sError = "Invalid size format expected length 10"; + return false; + } + + for (int i = 0; i < 10; i++) { + char c = sValue[i]; + if (i == 4 || i == 7) { + if (c != '-') { + sError = + "Expected '-' in " + std::to_string(i) + " position, but got '"; + sError += c; + sError += "'"; return false; - } - return true; + } + continue; + } + if (c < '0' || c > '9') { + sError = "Unexpected char '"; + sError += c; + sError += "' in " + std::to_string(i) + " position"; + return false; + } + } + // 2020-01-01 + std::string sYear = sValue.substr(0, 4); + int nYear = std::atoi(sYear.c_str()); + + std::string sMonth = sValue.substr(5, 2); + int nMonth = std::atoi(sMonth.c_str()); + if (nMonth < 1 || nMonth > 12) { + sError = "Invalid value nunber of month '" + std::to_string(nMonth) + + "' expected 01..12"; + return false; + } + + int nMaxDay = 0; + if (nMonth == 1 || nMonth == 3 || nMonth == 5 || nMonth == 7 || nMonth == 8 || + nMonth == 10 || nMonth == 12) { + nMaxDay = 31; + } else if (nMonth == 4 || nMonth == 6 || nMonth == 9 || nMonth == 11) { + nMaxDay = 30; + } else if (nMonth == 2 && nYear % 4 == 0) { + nMaxDay = 29; + } else if (nMonth == 2 && nYear % 4 != 0) { + nMaxDay = 28; + } + + std::string sDay = sValue.substr(8, 2); + int nDay = std::atoi(sDay.c_str()); + if (nDay < 1 || nDay > nMaxDay) { + sError = "Invalid value number of day '" + std::to_string(nDay) + + "' expected 01.." + std::to_string(nMaxDay); + return false; + } + return true; } -// ---------------------------------------------------------------------- - -bool WsjcppValidators::isValidTimeH24(const std::string &sValue, std::string &sError) { - int nSize = sValue.size(); - if (nSize != 8) { - sError = "Invalid size format expected length 8"; - return false; - } - - for (int i = 0; i < 8; i++) { - char c = sValue[i]; - if (i == 2 || i == 5) { - if (c != ':') { - sError = "Expected ':' in " + std::to_string(i) + " position, but got '"; - sError += c; - sError += "'"; - return false; - } - continue; - } - if (c < '0' || c > '9') { - sError = "Unexpected char '"; - sError += c; - sError += "' in " + std::to_string(i) + " position"; - return false; - } - - } - - std::string sHours = sValue.substr(0,2); - int nHours = std::atoi(sHours.c_str()); - if (nHours > 23) { - sError = "Invalid value of hours '" + std::to_string(nHours) + "' expected 00..23"; - return false; - } - std::string sMinutes = sValue.substr(3,2); - int nMinutes = std::atoi(sMinutes.c_str()); - if (nMinutes > 59) { - sError = "Invalid value of minutes '" + std::to_string(nMinutes) + "' expected 00..59"; - return false; - } - - std::string sSeconds = sValue.substr(6,2); - int nSeconds = std::atoi(sSeconds.c_str()); - if (nSeconds > 59) { - sError = "Invalid value of seconds '" + std::to_string(nSeconds) + "' expected 00..59"; +bool WsjcppValidators::isValidTimeH24(const std::string &sValue, + std::string &sError) { + int nSize = sValue.size(); + if (nSize != 8) { + sError = "Invalid size format expected length 8"; + return false; + } + + for (int i = 0; i < 8; i++) { + char c = sValue[i]; + if (i == 2 || i == 5) { + if (c != ':') { + sError = + "Expected ':' in " + std::to_string(i) + " position, but got '"; + sError += c; + sError += "'"; return false; - } - return true; -} - -// ---------------------------------------------------------------------- - -bool WsjcppValidators::isValidDomainName(const std::string &sValue, std::string &sError) { - std::vector vSubDomains; - std::string sTmpDomain = ""; - int nAddressLen = sValue.size(); - char cPrev = 0; - for (int i = 0; i < nAddressLen; i++) { - char c = sValue[i]; - if (i == 0 && c == '.') { - sError = "Domain Name '" + sValue + "' could not be start on '.'"; - return false; - } - if (c == '.') { - if (sTmpDomain != "") { - vSubDomains.push_back(sTmpDomain); - sTmpDomain = ""; - continue; - } else { - sError = "Domain Name '" + sValue + "' could not contains '..'"; - return false; - } - } - if ( - (c >= 'A' && c <= 'Z') - || (c >= 'a' && c <= 'z') - || (c >= '0' && c <= '9') - || c == '-' - ) { - sTmpDomain += c; - if (cPrev == '-' && c == cPrev) { - sError = "Domain Name '" + sValue + "' could not two times in a row '"; - sError += c; - sError += c; - sError += "'"; - return false; - } - cPrev = c; - } else { - sError = "Domain Name '" + sValue + "' contains unexpected '"; - sError += c; - sError += "'"; - return false; - } - - } + } + continue; + } + if (c < '0' || c > '9') { + sError = "Unexpected char '"; + sError += c; + sError += "' in " + std::to_string(i) + " position"; + return false; + } + } + + std::string sHours = sValue.substr(0, 2); + int nHours = std::atoi(sHours.c_str()); + if (nHours > 23) { + sError = "Invalid value of hours '" + std::to_string(nHours) + + "' expected 00..23"; + return false; + } + std::string sMinutes = sValue.substr(3, 2); + int nMinutes = std::atoi(sMinutes.c_str()); + if (nMinutes > 59) { + sError = "Invalid value of minutes '" + std::to_string(nMinutes) + + "' expected 00..59"; + return false; + } - if (sTmpDomain != "") { + std::string sSeconds = sValue.substr(6, 2); + int nSeconds = std::atoi(sSeconds.c_str()); + if (nSeconds > 59) { + sError = "Invalid value of seconds '" + std::to_string(nSeconds) + + "' expected 00..59"; + return false; + } + return true; +} + +bool WsjcppValidators::isValidDomainName(const std::string &sValue, + std::string &sError) { + std::vector vSubDomains; + std::string sTmpDomain = ""; + int nAddressLen = sValue.size(); + char cPrev = 0; + for (int i = 0; i < nAddressLen; i++) { + char c = sValue[i]; + if (i == 0 && c == '.') { + sError = "Domain Name '" + sValue + "' could not be start on '.'"; + return false; + } + if (c == '.') { + if (sTmpDomain != "") { vSubDomains.push_back(sTmpDomain); sTmpDomain = ""; - } else { - sError = "Domain Name '" + sValue + "' could not contains '.' on end"; + continue; + } else { + sError = "Domain Name '" + sValue + "' could not contains '..'"; return false; - } - - if (vSubDomains.size() < 2) { - sError = "Domain Name '" + sValue + "' must contains least one dot"; - return false; - } - std::string sRootDomain = vSubDomains[vSubDomains.size()-1]; - if (sRootDomain.size() < 2) { - sError = "Domain Name '" + sValue + "' has wrong root domain '" + sRootDomain + "' length must be more then 1"; + } + } + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || c == '-') { + sTmpDomain += c; + if (cPrev == '-' && c == cPrev) { + sError = "Domain Name '" + sValue + "' could not two times in a row '"; + sError += c; + sError += c; + sError += "'"; return false; - } - for (int i = 0; i < sRootDomain.size(); i++) { - char c = sRootDomain[i]; - if ( - (c < 'A' || c > 'Z') - && (c < 'a' || c > 'z') - ) { - sError = "Domain Name '" + sValue + "' has wrong root domain '" + sRootDomain + "' must have only chars"; - return false; - } - } - - for (int i = 0; i < vSubDomains.size(); i++) { - std::string sDomain = vSubDomains[i]; - char c = sDomain[0]; - if ( - (c < 'A' || c > 'Z') - && (c < 'a' || c > 'z') - && (c < '0' || c > '9') - ) { - sError = "Subdomain '" + sDomain + "' could not start on '"; - sError += c; - sError += "'"; - return false; - } - c = sDomain[sDomain.size()-1]; - if ( - (c < 'A' || c > 'Z') - && (c < 'a' || c > 'z') - && (c < '0' || c > '9') - ) { - sError = "Subdomain '" + sDomain + "' could not end on '"; - sError += c; - sError += "'"; - return false; - } - } - return true; -} - -// ---------------------------------------------------------------------- + } + cPrev = c; + } else { + sError = "Domain Name '" + sValue + "' contains unexpected '"; + sError += c; + sError += "'"; + return false; + } + } + + if (sTmpDomain != "") { + vSubDomains.push_back(sTmpDomain); + sTmpDomain = ""; + } else { + sError = "Domain Name '" + sValue + "' could not contains '.' on end"; + return false; + } -bool WsjcppValidators::isValidPort(const std::string &sValue, std::string &sError) { - int nPort = std::atoi(sValue.c_str()); - return WsjcppValidators::isValidPort(nPort, sError); + if (vSubDomains.size() < 2) { + sError = "Domain Name '" + sValue + "' must contains least one dot"; + return false; + } + std::string sRootDomain = vSubDomains[vSubDomains.size() - 1]; + if (sRootDomain.size() < 2) { + sError = "Domain Name '" + sValue + "' has wrong root domain '" + + sRootDomain + "' length must be more then 1"; + return false; + } + for (int i = 0; i < sRootDomain.size(); i++) { + char c = sRootDomain[i]; + if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z')) { + sError = "Domain Name '" + sValue + "' has wrong root domain '" + + sRootDomain + "' must have only chars"; + return false; + } + } + + for (int i = 0; i < vSubDomains.size(); i++) { + std::string sDomain = vSubDomains[i]; + char c = sDomain[0]; + if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && (c < '0' || c > '9')) { + sError = "Subdomain '" + sDomain + "' could not start on '"; + sError += c; + sError += "'"; + return false; + } + c = sDomain[sDomain.size() - 1]; + if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && (c < '0' || c > '9')) { + sError = "Subdomain '" + sDomain + "' could not end on '"; + sError += c; + sError += "'"; + return false; + } + } + return true; +} + +bool WsjcppValidators::isValidPort(const std::string &sValue, + std::string &sError) { + int nPort = std::atoi(sValue.c_str()); + return WsjcppValidators::isValidPort(nPort, sError); } -// ---------------------------------------------------------------------- - bool WsjcppValidators::isValidPort(int nValue, std::string &sError) { - if (nValue < 1 || nValue > 65535) { - sError = "Port '" + std::to_string(nValue) + "' must be more then 0 and less then 65536"; - return false; - } - return true; + if (nValue < 1 || nValue > 65535) { + sError = "Port '" + std::to_string(nValue) + + "' must be more then 0 and less then 65536"; + return false; + } + return true; } -// ---------------------------------------------------------------------- - -bool WsjcppValidators::isValidURLProtocol(const std::string &sValue, std::string &sError) { - if ( - sValue != "http" - && sValue != "https" - && sValue != "ws" - && sValue != "wss" - && sValue != "ftp" - && sValue != "ssl" - ) { - sError = "Unexpected protocol '" + sValue + "'"; - return false; - } - return true; +bool WsjcppValidators::isValidURLProtocol(const std::string &sValue, + std::string &sError) { + if (sValue != "http" && sValue != "https" && sValue != "ws" && + sValue != "wss" && sValue != "ftp" && sValue != "ssl") { + sError = "Unexpected protocol '" + sValue + "'"; + return false; + } + return true; } -// ---------------------------------------------------------------------- - -bool WsjcppValidators::isValidBase64(const std::string &sValue, std::string &sError) { - int nSize = sValue.size(); - if (nSize % 4 != 0) { - sError = "Value size must be a multiple of 4"; - return false; +bool WsjcppValidators::isValidBase64(const std::string &sValue, + std::string &sError) { + int nSize = sValue.size(); + if (nSize % 4 != 0) { + sError = "Value size must be a multiple of 4"; + return false; + } + bool bLastChar = false; + for (int i = 0; i < nSize; i++) { + char c = sValue[i]; + if (!bLastChar && c == '=') { + bLastChar = true; + continue; + } + if (bLastChar && c == '=') { + continue; + } + + if (bLastChar && c != '=') { + sError = "Unexpected char '"; + sError += c; + sError += "' after '=' in " + std::to_string(i) + " position"; + return false; + } + + if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && (c < '0' || c > '9') && + c != '+' && c != '/') { + sError = "Unexpected char '"; + sError += c; + sError += "' in " + std::to_string(i) + " position"; + return false; + } + } + return true; +} + +bool WsjcppValidators::isValidIPv4(const std::string &sValue, + std::string &sError) { + int n = 0; + std::string s[4] = {"", "", "", ""}; + for (int i = 0; i < sValue.length(); i++) { + char c = sValue[i]; + if (n > 3) { + sError = "Groups number must be less than 5 (like '0.0.0.0')"; + return false; + } + if (c >= '0' && c <= '9') { + s[n] += c; + } else if (c == '.') { + n++; + } else { + sError = "Unexpected character '"; + sError += c; + sError += "'"; + return false; } - bool bLastChar = false; - for (int i = 0; i < nSize; i++) { - char c = sValue[i]; - if (!bLastChar && c == '=') { - bLastChar = true; - continue; - } - if (bLastChar && c == '=') { - continue; - } - - if (bLastChar && c != '=') { - sError = "Unexpected char '"; - sError += c; - sError += "' after '=' in " + std::to_string(i) + " position"; - return false; - } - - if ( - (c < 'A' || c > 'Z') - && (c < 'a' || c > 'z') - && (c < '0' || c > '9') - && c != '+' - && c != '/' - ) { - sError = "Unexpected char '"; - sError += c; - sError += "' in " + std::to_string(i) + " position"; - return false; - } + } + for (int i = 0; i < 4; i++) { + if (s[i].length() > 3) { + sError = + "Value '" + s[i] + "' could not contains more than 3 digits in a row"; + return false; } - return true; -} - -// ---------------------------------------------------------------------- - -bool WsjcppValidators::isValidIPv4(const std::string &sValue, std::string &sError) { - int n = 0; - std::string s[4] = {"", "", "", ""}; - for (int i = 0; i < sValue.length(); i++) { - char c = sValue[i]; - if (n > 3) { - sError = "Groups number must be less than 5 (like '0.0.0.0')"; - return false; - } - if (c >= '0' && c <= '9') { - s[n] += c; - } else if (c == '.') { - n++; - } else { - sError = "Unexpected character '"; - sError += c; - sError += "'"; - return false; - } + int p = std::stoi(s[i]); + if (p > 255 || p < 0) { + sError = "Value '" + std::to_string(p) + "' must be 0..255"; + return false; } - for (int i = 0; i < 4; i++) { - if (s[i].length() > 3) { - sError = "Value '" + s[i] + "' could not contains more than 3 digits in a row"; - return false; - } - int p = std::stoi(s[i]); - if (p > 255 || p < 0) { - sError = "Value '" + std::to_string(p) + "' must be 0..255"; - return false; - } - } - return true; + } + return true; } -// ---------------------------------------------------------------------- - -bool WsjcppValidators::isValidIPv6(const std::string &sValue, std::string &sError) { - // TODO redesign without arpa - unsigned char buf[sizeof(struct in6_addr)]; - bool isValid = inet_pton(AF_INET6, sValue.c_str(), buf); - if (!isValid) { - sError = "Format of ipv6 invalid"; - } - return isValid; +bool WsjcppValidators::isValidIPv6(const std::string &sValue, + std::string &sError) { + // TODO redesign without arpa + unsigned char buf[sizeof(struct in6_addr)]; + bool isValid = inet_pton(AF_INET6, sValue.c_str(), buf); + if (!isValid) { + sError = "Format of ipv6 invalid"; + } + return isValid; } // ---------------------------------------------------------------------- // WsjcppValidatorStringBase -WsjcppValidatorStringBase::WsjcppValidatorStringBase(const std::string &sTypeName) { - TAG = "WsjcppValidatorStringBase"; - m_sTypeName = sTypeName; +WsjcppValidatorStringBase::WsjcppValidatorStringBase( + const std::string &sTypeName) { + TAG = "WsjcppValidatorStringBase"; + m_sTypeName = sTypeName; } -// ---------------------------------------------------------------------- - WsjcppValidatorType WsjcppValidatorStringBase::getBaseType() { - return WsjcppValidatorType::WSJCPP_VALIDATOR_STRING; + return WsjcppValidatorType::WSJCPP_VALIDATOR_STRING; } -// ---------------------------------------------------------------------- - -std::string WsjcppValidatorStringBase::getTypeName() { - return m_sTypeName; -} +std::string WsjcppValidatorStringBase::getTypeName() { return m_sTypeName; } // ---------------------------------------------------------------------- // WsjcppValidatorStringRegexpBase -WsjcppValidatorStringRegexpBase::WsjcppValidatorStringRegexpBase(const std::string &typeName, const std::string &sValidator) -: WsjcppValidatorStringBase(typeName) { - TAG = "ValidatorStringRegexpBase"; - m_sValidator = sValidator; - m_rxValidator = std::regex(sValidator); +WsjcppValidatorStringRegexpBase::WsjcppValidatorStringRegexpBase( + const std::string &typeName, const std::string &sValidator) + : WsjcppValidatorStringBase(typeName) { + TAG = "ValidatorStringRegexpBase"; + m_sValidator = sValidator; + m_rxValidator = std::regex(sValidator); } -// ---------------------------------------------------------------------- - -bool WsjcppValidatorStringRegexpBase::isValid(const std::string &sValue, std::string &sError) { - if (!std::regex_match(sValue, m_rxValidator)) { - sError = getTypeName() + " - Value must match regular expression " + m_sValidator; - return false; - } - return true; +bool WsjcppValidatorStringRegexpBase::isValid(const std::string &sValue, + std::string &sError) { + if (!std::regex_match(sValue, m_rxValidator)) { + sError = getTypeName() + " - Value must match regular expression " + + m_sValidator; + return false; + } + return true; } // ---------------------------------------------------------------------- // WsjcppValidatorStringListBase -WsjcppValidatorStringListBase::WsjcppValidatorStringListBase(const std::string &sTypeName, const std::vector &vListValues) -: WsjcppValidatorStringBase(sTypeName) { - m_vListValues = vListValues; +WsjcppValidatorStringListBase::WsjcppValidatorStringListBase( + const std::string &sTypeName, const std::vector &vListValues) + : WsjcppValidatorStringBase(sTypeName) { + m_vListValues = vListValues; } -// ---------------------------------------------------------------------- - -bool WsjcppValidatorStringListBase::isValid(const std::string &sValue, std::string &sError) { - if (std::find(m_vListValues.begin(), m_vListValues.end(), sValue) != m_vListValues.end()) { - return true; - } - sError = getTypeName() + " expected one of ["; - for (int i = 0; i < m_vListValues.size(); i++) { - sError += "'" + m_vListValues[i] + "'"; - if (i < m_vListValues.size() - 1) { - sError += ", "; - } +bool WsjcppValidatorStringListBase::isValid(const std::string &sValue, + std::string &sError) { + if (std::find(m_vListValues.begin(), m_vListValues.end(), sValue) != + m_vListValues.end()) { + return true; + } + sError = getTypeName() + " expected one of ["; + for (int i = 0; i < m_vListValues.size(); i++) { + sError += "'" + m_vListValues[i] + "'"; + if (i < m_vListValues.size() - 1) { + sError += ", "; } - sError += "]"; - return false; + } + sError += "]"; + return false; } // ---------------------------------------------------------------------- // WsjcppValidatorEmail WsjcppValidatorEmail::WsjcppValidatorEmail() -: WsjcppValidatorStringRegexpBase( - "email", - "^[0-9a-zA-Z]{1}[0-9a-zA-Z-._]*[0-9a-zA-Z]{1}@[0-9a-zA-Z]{1}[-.0-9a-zA-Z]*[0-9a-zA-Z]{1}\\.[a-zA-Z]{2,6}$" -) { - TAG = "WsjcppValidatorEmail"; + : WsjcppValidatorStringRegexpBase( + "email", "^[0-9a-zA-Z]{1}[0-9a-zA-Z-._]*[0-9a-zA-Z]{1}@[0-9a-zA-Z]{1}" + "[-.0-9a-zA-Z]*[0-9a-zA-Z]{1}\\.[a-zA-Z]{2,6}$") { + TAG = "WsjcppValidatorEmail"; } // ---------------------------------------------------------------------- // WsjcppValidatorUUID WsjcppValidatorUUID::WsjcppValidatorUUID() -: WsjcppValidatorStringRegexpBase( - "uuid", - "^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$" -) { - TAG = "WsjcppValidatorUUID"; + : WsjcppValidatorStringRegexpBase("uuid", + "^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-" + "f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$") { + TAG = "WsjcppValidatorUUID"; } // ---------------------------------------------------------------------- // WsjcppValidatorStringLenght -WsjcppValidatorStringLength::WsjcppValidatorStringLength(int nMinLength, int nMaxLength) -: WsjcppValidatorStringBase("string_length") { - TAG = "WsjcppValidatorStringLenght"; - m_nMinLength = nMinLength; - m_nMaxLength = nMaxLength; +WsjcppValidatorStringLength::WsjcppValidatorStringLength(int nMinLength, + int nMaxLength) + : WsjcppValidatorStringBase("string_length") { + TAG = "WsjcppValidatorStringLenght"; + m_nMinLength = nMinLength; + m_nMaxLength = nMaxLength; } -// ---------------------------------------------------------------------- - -bool WsjcppValidatorStringLength::isValid(const std::string &sValue, std::string &sError) { - if (sValue.length() < m_nMinLength) { - sError = "Value must have more than " + std::to_string(m_nMinLength) + " simbols"; - return false; - } +bool WsjcppValidatorStringLength::isValid(const std::string &sValue, + std::string &sError) { + if (sValue.length() < m_nMinLength) { + sError = "Value must have more than " + std::to_string(m_nMinLength) + + " simbols"; + return false; + } - if (sValue.length() > m_nMaxLength) { - sError = "Value must have less than " + std::to_string(m_nMaxLength) + " simbols"; - return false; - } - return true; + if (sValue.length() > m_nMaxLength) { + sError = "Value must have less than " + std::to_string(m_nMaxLength) + + " simbols"; + return false; + } + return true; } // ---------------------------------------------------------------------- // WsjcppValidatorJWT WsjcppValidatorJWT::WsjcppValidatorJWT() -: WsjcppValidatorStringRegexpBase( - "jwt", - "^[A-Za-z0-9-_=]+\\.[A-Za-z0-9-_=]+\\.?[A-Za-z0-9-_.+/=]*$" -) { - TAG = "WsjcppValidatorJWT"; + : WsjcppValidatorStringRegexpBase( + "jwt", "^[A-Za-z0-9-_=]+\\.[A-Za-z0-9-_=]+\\.?[A-Za-z0-9-_.+/=]*$") { + TAG = "WsjcppValidatorJWT"; } // ---------------------------------------------------------------------- // WsjcppValidatorDate -WsjcppValidatorDate::WsjcppValidatorDate() -: WsjcppValidatorStringBase("date") { - TAG = "WsjcppValidatorDate"; +WsjcppValidatorDate::WsjcppValidatorDate() : WsjcppValidatorStringBase("date") { + TAG = "WsjcppValidatorDate"; } // ---------------------------------------------------------------------- -bool WsjcppValidatorDate::isValid(const std::string &sValue, std::string &sError) { - return WsjcppValidators::isValidDate(sValue, sError); +bool WsjcppValidatorDate::isValid(const std::string &sValue, + std::string &sError) { + return WsjcppValidators::isValidDate(sValue, sError); } // ---------------------------------------------------------------------- // WsjcppValidatorTimeH24 WsjcppValidatorTimeH24::WsjcppValidatorTimeH24() -: WsjcppValidatorStringBase("time_h24") { - TAG = "WsjcppValidatorTime"; + : WsjcppValidatorStringBase("time_h24") { + TAG = "WsjcppValidatorTime"; } -// ---------------------------------------------------------------------- - -bool WsjcppValidatorTimeH24::isValid(const std::string &sValue, std::string &sError) { - return WsjcppValidators::isValidTimeH24(sValue, sError); +bool WsjcppValidatorTimeH24::isValid(const std::string &sValue, + std::string &sError) { + return WsjcppValidators::isValidTimeH24(sValue, sError); } // ---------------------------------------------------------------------- // WsjcppValidatorDateTime WsjcppValidatorDateTime::WsjcppValidatorDateTime() -: WsjcppValidatorStringBase("datetime") { - TAG = "WsjcppValidatorDateTime"; + : WsjcppValidatorStringBase("datetime") { + TAG = "WsjcppValidatorDateTime"; } -// ---------------------------------------------------------------------- - -bool WsjcppValidatorDateTime::isValid(const std::string &sValue, std::string &sError) { - int nSize = sValue.size(); - // '2020-01-01T00:00:00' - if (nSize != 19) { - sError = "Invalid size format expected length 19"; - return false; - } - std::string sDate = sValue.substr(0,10); - if (!WsjcppValidators::isValidDate(sDate, sError)) { - return false; - } - if (sValue[10] != 'T') { - sError = "Expected 'T' in 10 position, but got '"; - sError += sValue[10]; - sError += "'"; - return false; - } - std::string sTime = sValue.substr(11,8); - if (!WsjcppValidators::isValidTimeH24(sTime, sError)) { - return false; - } - return true; +bool WsjcppValidatorDateTime::isValid(const std::string &sValue, + std::string &sError) { + int nSize = sValue.size(); + // '2020-01-01T00:00:00' + if (nSize != 19) { + sError = "Invalid size format expected length 19"; + return false; + } + std::string sDate = sValue.substr(0, 10); + if (!WsjcppValidators::isValidDate(sDate, sError)) { + return false; + } + if (sValue[10] != 'T') { + sError = "Expected 'T' in 10 position, but got '"; + sError += sValue[10]; + sError += "'"; + return false; + } + std::string sTime = sValue.substr(11, 8); + if (!WsjcppValidators::isValidTimeH24(sTime, sError)) { + return false; + } + return true; } // ---------------------------------------------------------------------- // WsjcppValidatorURL -WsjcppValidatorURL::WsjcppValidatorURL() -: WsjcppValidatorStringBase("url") { - TAG = "WsjcppValidatorURL"; - m_rxLikeIPv4Format = std::regex("^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$"); +WsjcppValidatorURL::WsjcppValidatorURL() : WsjcppValidatorStringBase("url") { + TAG = "WsjcppValidatorURL"; + m_rxLikeIPv4Format = + std::regex("^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$"); } -// ---------------------------------------------------------------------- +bool WsjcppValidatorURL::isValid(const std::string &sValue, + std::string &sError) { + if (sValue.size() == 0) { + sError = "Value is empty"; + return false; + } + if (sValue.find(".") == std::string::npos) { + sError = "Must contain at least one dot"; + return false; + } + std::string sProtocol = WsjcppCore::extractURLProtocol(sValue); + if (!WsjcppValidators::isValidURLProtocol(sProtocol, sError)) { + return false; + } + + int nStartPos = sProtocol.length() + 3; + std::string sAuthorityAddressPath = ""; + for (int i = nStartPos; i < sValue.size(); i++) { + char c = sValue[i]; + if (c == '?') { + break; + } + sAuthorityAddressPath += c; + } + std::string sQuery = + sValue.substr(sProtocol.length() + 3 + sAuthorityAddressPath.size()); + std::string sAddressAndPath = sAuthorityAddressPath; + + int nPosAuthority = sAuthorityAddressPath.find("@"); + std::string sAuthority = ""; + if (nPosAuthority != std::string::npos) { + sAuthority = sAuthorityAddressPath.substr(0, nPosAuthority); + sAddressAndPath = sAuthorityAddressPath.substr(nPosAuthority + 1); + } + if (sAuthority != "") { + // sError = "TODO check username and password sAuthority= [" + sAuthority + + // "]"; + // -.~_!$&'()*+,;=:%40:80%2f:::::: + // WsjcppLog::warn(TAG, sError); + // return false; + } + std::string sAddress = sAddressAndPath; + std::string sPath = ""; + int nPosAddress = sAddressAndPath.find("/"); + if (nPosAddress != std::string::npos) { + sAddress = sAddressAndPath.substr(0, nPosAddress); + sPath = sAddressAndPath.substr(nPosAddress); + } + + if (sAddress.size() == 0) { + sError = "Address could not be empty"; + return false; + } -bool WsjcppValidatorURL::isValid(const std::string &sValue, std::string &sError) { - if (sValue.size() == 0) { - sError = "Value is empty"; - return false; - } - if (sValue.find(".") == std::string::npos) { - sError = "Must contain at least one dot"; - return false; - } - std::string sProtocol = WsjcppCore::extractURLProtocol(sValue); - if (!WsjcppValidators::isValidURLProtocol(sProtocol, sError)) { - return false; - } + int nPosPort = sAddress.find(":"); + std::string sPort = ""; + if (sAddress.find(":") != std::string::npos) { + sPort = sAddress.substr(nPosPort + 1); + sAddress = sAddress.substr(0, nPosPort); + } - int nStartPos = sProtocol.length() + 3; - std::string sAuthorityAddressPath = ""; - for (int i = nStartPos; i < sValue.size(); i++) { - char c = sValue[i]; - if (c == '?') { - break; - } - sAuthorityAddressPath += c; + if (sPort != "") { + if (!WsjcppValidators::isValidPort(sPort, sError)) { + return false; } - std::string sQuery = sValue.substr(sProtocol.length() + 3 + sAuthorityAddressPath.size()); - std::string sAddressAndPath = sAuthorityAddressPath; - - int nPosAuthority = sAuthorityAddressPath.find("@"); - std::string sAuthority = ""; - if (nPosAuthority != std::string::npos) { - sAuthority = sAuthorityAddressPath.substr(0,nPosAuthority); - sAddressAndPath = sAuthorityAddressPath.substr(nPosAuthority + 1); + } + + if (std::regex_match(sAddress, m_rxLikeIPv4Format)) { + if (!WsjcppValidators::isValidIPv4(sAddress, sError)) { + return false; } - if (sAuthority != "") { - // sError = "TODO check username and password sAuthority= [" + sAuthority + "]"; - // -.~_!$&'()*+,;=:%40:80%2f:::::: - // WsjcppLog::warn(TAG, sError); - // return false; + if (sPort != "") { + int nPort = std::atoi(sPort.c_str()); + if (nPort < 1 || nPort > 65535) { + sError = "Port '" + std::to_string(nPort) + + "' must be more then 0 and less then 65536"; + return false; + } } - std::string sAddress = sAddressAndPath; - std::string sPath = ""; - int nPosAddress = sAddressAndPath.find("/"); - if (nPosAddress != std::string::npos) { - sAddress = sAddressAndPath.substr(0, nPosAddress); - sPath = sAddressAndPath.substr(nPosAddress); + } else { + if (!WsjcppValidators::isValidDomainName(sAddress, sError)) { + return false; } + } - if (sAddress.size() == 0) { - sError = "Address could not be empty"; - return false; - } + if ((sPath == "" || sPath == "/") && sQuery == "") { + return true; + } - int nPosPort = sAddress.find(":"); - std::string sPort = ""; - if (sAddress.find(":") != std::string::npos) { - sPort = sAddress.substr(nPosPort + 1); - sAddress = sAddress.substr(0, nPosPort); - } - - if (sPort != "") { - if (!WsjcppValidators::isValidPort(sPort, sError)) { - return false; - } + if (sPath != "") { + for (int i = 0; i < sPath.length(); i++) { + char c = sPath[i]; + if (c == ' ') { + sError = "Path could not contains whitespace ' '"; + return false; + } } + } - if (std::regex_match(sAddress, m_rxLikeIPv4Format)) { - if (!WsjcppValidators::isValidIPv4(sAddress, sError)) { - return false; - } - if (sPort != "") { - int nPort = std::atoi(sPort.c_str()); - if (nPort < 1 || nPort > 65535) { - sError = "Port '" + std::to_string(nPort) + "' must be more then 0 and less then 65536"; - return false; - } - } - } else { - if (!WsjcppValidators::isValidDomainName(sAddress, sError)) { - return false; - } + if (sQuery != "") { + for (int i = 0; i < sQuery.length(); i++) { + char c = sQuery[i]; + if (c == ' ') { + sError = "Query could not contains whitespace ' ' (must be encoded)"; + return false; + } } + } - if ((sPath == "" || sPath == "/") && sQuery == "") { - return true; - } + // sError = "sAddressAndPath=[" + sAddressAndPath + "], , sAddress=[" + + // sAddress + "]"; + return true; +} - if (sPath != "") { - for (int i = 0; i < sPath.length(); i++) { - char c = sPath[i]; - if (c == ' ') { - sError = "Path could not contains whitespace ' '"; - return false; - } - } - } +// ---------------------------------------------------------------------- +// WsjcppValidatorDomainName - if (sQuery != "") { - for (int i = 0; i < sQuery.length(); i++) { - char c = sQuery[i]; - if (c == ' ') { - sError = "Query could not contains whitespace ' ' (must be encoded)"; - return false; - } - } - } +WsjcppValidatorDomainName::WsjcppValidatorDomainName() : WsjcppValidatorStringBase("domain_name") { + TAG = "WsjcppValidatorDomainName"; +} - // sError = "sAddressAndPath=[" + sAddressAndPath + "], , sAddress=[" + sAddress + "]"; - return true; +bool WsjcppValidatorDomainName::isValid(const std::string &sValue, std::string &sError) { + return WsjcppValidators::isValidDomainName(sValue, sError); } // ---------------------------------------------------------------------- // WsjcppValidatorBase64 -WsjcppValidatorBase64::WsjcppValidatorBase64() -: WsjcppValidatorStringBase("base64") { - TAG = "WsjcppValidatorBase64"; +WsjcppValidatorBase64::WsjcppValidatorBase64() + : WsjcppValidatorStringBase("base64") { + TAG = "WsjcppValidatorBase64"; } // ---------------------------------------------------------------------- -bool WsjcppValidatorBase64::isValid(const std::string &sValue, std::string &sError) { - return WsjcppValidators::isValidBase64(sValue, sError); +bool WsjcppValidatorBase64::isValid(const std::string &sValue, + std::string &sError) { + return WsjcppValidators::isValidBase64(sValue, sError); } // ---------------------------------------------------------------------- // WsjcppValidatorNumber -WsjcppValidatorNumber::WsjcppValidatorNumber() -: WsjcppValidatorStringBase("number") { - TAG = "WsjcppValidatorNumber"; +WsjcppValidatorNumber::WsjcppValidatorNumber() + : WsjcppValidatorStringBase("number") { + TAG = "WsjcppValidatorNumber"; } // ---------------------------------------------------------------------- -bool WsjcppValidatorNumber::isValid(const std::string &sValue, std::string &sError) { - int nSize = sValue.size(); - bool bHasOneAndMoreNumbers = false; - for (int i = 0; i < nSize; i++) { - char c = sValue[i]; - if (c == '-' && i == 0) { - continue; - } - if (c < '0' || c > '9') { - sError = "Unexpected char '"; - sError += c; - sError += "' in " + std::to_string(i) + " position"; - return false; - } - bHasOneAndMoreNumbers = true; +bool WsjcppValidatorNumber::isValid(const std::string &sValue, + std::string &sError) { + int nSize = sValue.size(); + bool bHasOneAndMoreNumbers = false; + for (int i = 0; i < nSize; i++) { + char c = sValue[i]; + if (c == '-' && i == 0) { + continue; } - return bHasOneAndMoreNumbers; + if (c < '0' || c > '9') { + sError = "Unexpected char '"; + sError += c; + sError += "' in " + std::to_string(i) + " position"; + return false; + } + bHasOneAndMoreNumbers = true; + } + return bHasOneAndMoreNumbers; } // ---------------------------------------------------------------------- // WsjcppValidatorHex -WsjcppValidatorHex::WsjcppValidatorHex() -: WsjcppValidatorStringBase("hex") { - TAG = "WsjcppValidatorHex"; +WsjcppValidatorHex::WsjcppValidatorHex() : WsjcppValidatorStringBase("hex") { + TAG = "WsjcppValidatorHex"; } // ---------------------------------------------------------------------- -bool WsjcppValidatorHex::isValid(const std::string &sValue, std::string &sError) { - int nSize = sValue.size(); - if (nSize == 0) { - sError = "Empty string"; - return false; +bool WsjcppValidatorHex::isValid(const std::string &sValue, + std::string &sError) { + int nSize = sValue.size(); + if (nSize == 0) { + sError = "Empty string"; + return false; + } + for (int i = 0; i < nSize; i++) { + char c = sValue[i]; + if (c == '-' && i == 0) { + continue; } - for (int i = 0; i < nSize; i++) { - char c = sValue[i]; - if (c == '-' && i == 0) { - continue; - } - if ((c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F')) { - sError = "Unexpected char '"; - sError += c; - sError += "' in " + std::to_string(i) + " position"; - return false; - } + if ((c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F')) { + sError = "Unexpected char '"; + sError += c; + sError += "' in " + std::to_string(i) + " position"; + return false; } - return true; + } + return true; } - // ---------------------------------------------------------------------- // WsjcppValidatorIntegerBase -WsjcppValidatorIntegerBase::WsjcppValidatorIntegerBase(const std::string &sTypeName) { - TAG = "WsjcppValidatorIntegerBase"; - m_sTypeName = sTypeName; +WsjcppValidatorIntegerBase::WsjcppValidatorIntegerBase( + const std::string &sTypeName) { + TAG = "WsjcppValidatorIntegerBase"; + m_sTypeName = sTypeName; } // ---------------------------------------------------------------------- WsjcppValidatorType WsjcppValidatorIntegerBase::getBaseType() { - return WsjcppValidatorType::WSJCPP_VALIDATOR_INTEGER; + return WsjcppValidatorType::WSJCPP_VALIDATOR_INTEGER; } // ---------------------------------------------------------------------- -std::string WsjcppValidatorIntegerBase::getTypeName() { - return m_sTypeName; -} +std::string WsjcppValidatorIntegerBase::getTypeName() { return m_sTypeName; } // ---------------------------------------------------------------------- // WsjcppValidatorIntegerMinValue -WsjcppValidatorIntegerMinValue::WsjcppValidatorIntegerMinValue(int nMinValue) -: WsjcppValidatorIntegerBase("integer_min_value") { - TAG = "WsjcppValidatorIntegerMinValue"; - m_nMinValue = nMinValue; +WsjcppValidatorIntegerMinValue::WsjcppValidatorIntegerMinValue(int nMinValue) + : WsjcppValidatorIntegerBase("integer_min_value") { + TAG = "WsjcppValidatorIntegerMinValue"; + m_nMinValue = nMinValue; } // ---------------------------------------------------------------------- bool WsjcppValidatorIntegerMinValue::isValid(int nValue, std::string &sError) { - if (nValue < m_nMinValue) { - sError = "Value must be more or equal then " + std::to_string(m_nMinValue); - return false; - } - return true; + if (nValue < m_nMinValue) { + sError = "Value must be more or equal then " + std::to_string(m_nMinValue); + return false; + } + return true; } // ---------------------------------------------------------------------- // WsjcppValidatorIntegerMaxValue -WsjcppValidatorIntegerMaxValue::WsjcppValidatorIntegerMaxValue(int nMaxValue) -: WsjcppValidatorIntegerBase("integer_max_value") { - TAG = "WsjcppValidatorIntegerMaxValue"; - m_nMaxValue = nMaxValue; +WsjcppValidatorIntegerMaxValue::WsjcppValidatorIntegerMaxValue(int nMaxValue) + : WsjcppValidatorIntegerBase("integer_max_value") { + TAG = "WsjcppValidatorIntegerMaxValue"; + m_nMaxValue = nMaxValue; } // ---------------------------------------------------------------------- bool WsjcppValidatorIntegerMaxValue::isValid(int nValue, std::string &sError) { - if (nValue > m_nMaxValue) { - sError = "Value must be less or equal then " + std::to_string(m_nMaxValue); - return false; - } - return true; -} - -// ---------------------------------------------------------------------- -// WsjcppValidatorJsonBase - -WsjcppValidatorJsonBase::WsjcppValidatorJsonBase(const std::string &sTypeName) { - TAG = "WsjcppValidatorJsonBase"; - m_sTypeName = sTypeName; -} - -// ---------------------------------------------------------------------- - -WsjcppValidatorType WsjcppValidatorJsonBase::getBaseType() { - return WsjcppValidatorType::WSJCPP_VALIDATOR_JSON; -} - -// ---------------------------------------------------------------------- - -std::string WsjcppValidatorJsonBase::getTypeName() { - return m_sTypeName; + if (nValue > m_nMaxValue) { + sError = "Value must be less or equal then " + std::to_string(m_nMaxValue); + return false; + } + return true; } - -// ---------------------------------------------------------------------- diff --git a/src.wsjcpp/wsjcpp_validators/wsjcpp_validators.h b/src.wsjcpp/wsjcpp_validators/wsjcpp_validators.h index e3c896bae..6b7fb07a8 100644 --- a/src.wsjcpp/wsjcpp_validators/wsjcpp_validators.h +++ b/src.wsjcpp/wsjcpp_validators/wsjcpp_validators.h @@ -1,30 +1,51 @@ -#ifndef WSJCPP_VALIDATOR_H -#define WSJCPP_VALIDATOR_H +/* +MIT License + +Copyright (c) 2020-2025 wsjcpp + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#pragma once +#include #include #include -#include -#include enum WsjcppValidatorType { - WSJCPP_VALIDATOR_STRING, - WSJCPP_VALIDATOR_INTEGER, - WSJCPP_VALIDATOR_JSON + WSJCPP_VALIDATOR_STRING, + WSJCPP_VALIDATOR_INTEGER, + WSJCPP_VALIDATOR_JSON }; -// ---------------------------------------------------------------------- - class WsjcppValidators { - public: - static bool isValidDate(const std::string &sValue, std::string &sError); - static bool isValidTimeH24(const std::string &sValue, std::string &sError); - static bool isValidURLProtocol(const std::string &sValue, std::string &sError); - static bool isValidDomainName(const std::string &sValue, std::string &sError); - static bool isValidPort(const std::string &sValue, std::string &sError); - static bool isValidPort(int nValue, std::string &sError); - static bool isValidBase64(const std::string &sValue, std::string &sError); - static bool isValidIPv4(const std::string &sValue, std::string &sError); - static bool isValidIPv6(const std::string &sValue, std::string &sError); +public: + static bool isValidDate(const std::string &sValue, std::string &sError); + static bool isValidTimeH24(const std::string &sValue, std::string &sError); + static bool isValidURLProtocol(const std::string &sValue, + std::string &sError); + static bool isValidDomainName(const std::string &sValue, std::string &sError); + static bool isValidPort(const std::string &sValue, std::string &sError); + static bool isValidPort(int nValue, std::string &sError); + static bool isValidBase64(const std::string &sValue, std::string &sError); + static bool isValidIPv4(const std::string &sValue, std::string &sError); + static bool isValidIPv6(const std::string &sValue, std::string &sError); }; /* @@ -32,213 +53,178 @@ class WsjcppValidators { class WsjcppValidatorBase { public: - WsjcppValidatorBase(const std::string &sTypeName, WsjcppValidatorType nValidatorType); - virtual WsjcppValidatorType getBaseType(); - virtual std::string getTypeName(); - virtual bool isValid(const std::string &sValue, std::string &sError) = 0; - protected: - std::string TAG; - private: - std::string m_sTypeName; + WsjcppValidatorBase(const std::string &sTypeName, WsjcppValidatorType +nValidatorType); virtual WsjcppValidatorType getBaseType(); virtual std::string +getTypeName(); virtual bool isValid(const std::string &sValue, std::string +&sError) = 0; protected: std::string TAG; private: std::string m_sTypeName; }; */ -// ---------------------------------------------------------------------- - class WsjcppValidatorStringBase { - public: - WsjcppValidatorStringBase(const std::string &typeName); - virtual WsjcppValidatorType getBaseType(); - virtual std::string getTypeName(); - virtual bool isValid(const std::string &sValue, std::string &sError) = 0; - protected: - std::string TAG; - private: - std::string m_sTypeName; -}; +public: + WsjcppValidatorStringBase(const std::string &typeName); + virtual WsjcppValidatorType getBaseType(); + virtual std::string getTypeName(); + virtual bool isValid(const std::string &sValue, std::string &sError) = 0; -// ---------------------------------------------------------------------- +protected: + std::string TAG; -class WsjcppValidatorStringRegexpBase : public WsjcppValidatorStringBase { - public: - WsjcppValidatorStringRegexpBase(const std::string &typeName, const std::string &sValidator); - virtual bool isValid(const std::string &sValue, std::string &sError) override; - private: - std::string m_sValidator; - std::regex m_rxValidator; +private: + std::string m_sTypeName; }; -// ---------------------------------------------------------------------- +class WsjcppValidatorStringRegexpBase : public WsjcppValidatorStringBase { +public: + WsjcppValidatorStringRegexpBase(const std::string &typeName, + const std::string &sValidator); + virtual bool isValid(const std::string &sValue, std::string &sError) override; -class WsjcppValidatorStringListBase : public WsjcppValidatorStringBase { - public: - WsjcppValidatorStringListBase(const std::string &typeName, const std::vector &vListValues); - virtual bool isValid(const std::string &sValue, std::string &sError) override; - private: - std::vector m_vListValues; +private: + std::string m_sValidator; + std::regex m_rxValidator; }; -// ---------------------------------------------------------------------- +class WsjcppValidatorStringListBase : public WsjcppValidatorStringBase { +public: + WsjcppValidatorStringListBase(const std::string &typeName, + const std::vector &vListValues); + virtual bool isValid(const std::string &sValue, std::string &sError) override; -class WsjcppValidatorEmail : public WsjcppValidatorStringRegexpBase { - public: - WsjcppValidatorEmail(); +private: + std::vector m_vListValues; }; -// ---------------------------------------------------------------------- +class WsjcppValidatorEmail : public WsjcppValidatorStringRegexpBase { +public: + WsjcppValidatorEmail(); +}; class WsjcppValidatorUUID : public WsjcppValidatorStringRegexpBase { - public: - WsjcppValidatorUUID(); +public: + WsjcppValidatorUUID(); }; -// ---------------------------------------------------------------------- - class WsjcppValidatorStringLength : public WsjcppValidatorStringBase { - public: - WsjcppValidatorStringLength(int nMinLength, int nMaxLength); - virtual bool isValid(const std::string &sValue, std::string &sError); +public: + WsjcppValidatorStringLength(int nMinLength, int nMaxLength); + virtual bool isValid(const std::string &sValue, std::string &sError); - private: - std::string TAG; - int m_nMinLength; - int m_nMaxLength; +private: + std::string TAG; + int m_nMinLength; + int m_nMaxLength; }; -// ---------------------------------------------------------------------- - class WsjcppValidatorJWT : public WsjcppValidatorStringRegexpBase { - public: - WsjcppValidatorJWT(); +public: + WsjcppValidatorJWT(); }; -// ---------------------------------------------------------------------- - class WsjcppValidatorDate : public WsjcppValidatorStringBase { - public: - WsjcppValidatorDate(); - virtual bool isValid(const std::string &sValue, std::string &sError); - private: - std::string TAG; -}; +public: + WsjcppValidatorDate(); + virtual bool isValid(const std::string &sValue, std::string &sError); -// ---------------------------------------------------------------------- +private: + std::string TAG; +}; class WsjcppValidatorTimeH24 : public WsjcppValidatorStringBase { - public: - WsjcppValidatorTimeH24(); - virtual bool isValid(const std::string &sValue, std::string &sError); - private: - std::string TAG; -}; +public: + WsjcppValidatorTimeH24(); + virtual bool isValid(const std::string &sValue, std::string &sError); -// ---------------------------------------------------------------------- +private: + std::string TAG; +}; class WsjcppValidatorDateTime : public WsjcppValidatorStringBase { - public: - WsjcppValidatorDateTime(); - virtual bool isValid(const std::string &sValue, std::string &sError); - private: - std::string TAG; -}; +public: + WsjcppValidatorDateTime(); + virtual bool isValid(const std::string &sValue, std::string &sError); -// ---------------------------------------------------------------------- +private: + std::string TAG; +}; class WsjcppValidatorURL : public WsjcppValidatorStringBase { - public: - WsjcppValidatorURL(); - virtual bool isValid(const std::string &sValue, std::string &sError); +public: + WsjcppValidatorURL(); + virtual bool isValid(const std::string &sValue, std::string &sError); - private: - std::string TAG; - std::regex m_rxLikeIPv4Format; +private: + std::string TAG; + std::regex m_rxLikeIPv4Format; }; -// ---------------------------------------------------------------------- +class WsjcppValidatorDomainName : public WsjcppValidatorStringBase { +public: + WsjcppValidatorDomainName(); + virtual bool isValid(const std::string &sValue, std::string &sError); + +private: + std::string TAG; +}; class WsjcppValidatorBase64 : public WsjcppValidatorStringBase { - public: - WsjcppValidatorBase64(); - virtual bool isValid(const std::string &sValue, std::string &sError); +public: + WsjcppValidatorBase64(); + virtual bool isValid(const std::string &sValue, std::string &sError); - private: - std::string TAG; +private: + std::string TAG; }; -// ---------------------------------------------------------------------- - class WsjcppValidatorNumber : public WsjcppValidatorStringBase { - public: - WsjcppValidatorNumber(); - virtual bool isValid(const std::string &sValue, std::string &sError); +public: + WsjcppValidatorNumber(); + virtual bool isValid(const std::string &sValue, std::string &sError); - private: - std::string TAG; +private: + std::string TAG; }; -// ---------------------------------------------------------------------- - class WsjcppValidatorHex : public WsjcppValidatorStringBase { - public: - WsjcppValidatorHex(); - virtual bool isValid(const std::string &sValue, std::string &sError); +public: + WsjcppValidatorHex(); + virtual bool isValid(const std::string &sValue, std::string &sError); - private: - std::string TAG; +private: + std::string TAG; }; -// ---------------------------------------------------------------------- - class WsjcppValidatorIntegerBase { - public: - WsjcppValidatorIntegerBase(const std::string &typeName); - virtual WsjcppValidatorType getBaseType(); - virtual std::string getTypeName(); - virtual bool isValid(int nValue, std::string &sError) = 0; - protected: - std::string TAG; - private: - std::string m_sTypeName; -}; +public: + WsjcppValidatorIntegerBase(const std::string &typeName); + virtual WsjcppValidatorType getBaseType(); + virtual std::string getTypeName(); + virtual bool isValid(int nValue, std::string &sError) = 0; -// ---------------------------------------------------------------------- +protected: + std::string TAG; -class WsjcppValidatorIntegerMinValue : public WsjcppValidatorIntegerBase { - public: - WsjcppValidatorIntegerMinValue(int nMinValue); - virtual bool isValid(int nValue, std::string &sError) override; - - private: - std::string TAG; - int m_nMinValue; +private: + std::string m_sTypeName; }; -// ---------------------------------------------------------------------- - -class WsjcppValidatorIntegerMaxValue : public WsjcppValidatorIntegerBase { - public: - WsjcppValidatorIntegerMaxValue(int nMaxValue); - virtual bool isValid(int nValue, std::string &sError) override; +class WsjcppValidatorIntegerMinValue : public WsjcppValidatorIntegerBase { +public: + WsjcppValidatorIntegerMinValue(int nMinValue); + virtual bool isValid(int nValue, std::string &sError) override; - private: - std::string TAG; - int m_nMaxValue; +private: + std::string TAG; + int m_nMinValue; }; -// ---------------------------------------------------------------------- - -class WsjcppValidatorJsonBase { - public: - WsjcppValidatorJsonBase(const std::string &typeName); - virtual WsjcppValidatorType getBaseType(); - virtual std::string getTypeName(); - virtual bool isValid(const nlohmann::json &nValue, std::string &sError) = 0; +class WsjcppValidatorIntegerMaxValue : public WsjcppValidatorIntegerBase { +public: + WsjcppValidatorIntegerMaxValue(int nMaxValue); + virtual bool isValid(int nValue, std::string &sError) override; - protected: - std::string TAG; - private: - std::string m_sTypeName; +private: + std::string TAG; + int m_nMaxValue; }; - -#endif // WSJCPP_VALIDATOR_H diff --git a/src.wsjcpp/wsjcpp_yaml/wsjcpp.hold.yml b/src.wsjcpp/wsjcpp_yaml/wsjcpp.hold.yml index bf1e86a78..61f72616f 100644 --- a/src.wsjcpp/wsjcpp_yaml/wsjcpp.hold.yml +++ b/src.wsjcpp/wsjcpp_yaml/wsjcpp.hold.yml @@ -1,8 +1,8 @@ wsjcpp_version: v0.0.1 cmake_minimum_required: 3.0 -cmake_cxx_standard: 11 +cmake_cxx_standard: 17 name: wsjcpp-yaml -version: v0.1.7 +version: v0.1.8 description: Read/Write yaml files issues: https://github.com/wsjcpp/wsjcpp-yaml/issues @@ -32,12 +32,12 @@ distribution: - source-file: src/wsjcpp_yaml.cpp target-file: wsjcpp_yaml.cpp type: "source-code" - sha1: "698fe214ee0e953e348b6e1f6a7e3e233d5b5ad3" + sha1: "75c07f509d386864ec5466fe9fb5ecccc879b526" - source-file: src/wsjcpp_yaml.h target-file: wsjcpp_yaml.h type: "source-code" - sha1: "893e63e20c01f32607e8862f308ecce4a98b25be" + sha1: "b32fb8314ca9975c81c9b27bcede8925a1728c61" unit-tests: cases: - name: LineParser @@ -50,8 +50,6 @@ unit-tests: description: Test Hierarchical Map - name: YamlParserQuotes description: YamlParserQuotes - - name: YamlParserComments - description: YamlParserComments - name: YamlParserAll description: YamlParserAll - name: YamlParserArrayIncludedMap diff --git a/src.wsjcpp/wsjcpp_yaml/wsjcpp_yaml.cpp b/src.wsjcpp/wsjcpp_yaml/wsjcpp_yaml.cpp index 1331cc753..bb87695a8 100644 --- a/src.wsjcpp/wsjcpp_yaml/wsjcpp_yaml.cpp +++ b/src.wsjcpp/wsjcpp_yaml/wsjcpp_yaml.cpp @@ -1,3 +1,28 @@ +/* +MIT License + +Copyright (c) 2019-2025 wsjcpp + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Official Source Code: https://github.com/wsjcpp/wsjcpp-yaml +*/ #include "wsjcpp_yaml.h" // #include @@ -6,6 +31,84 @@ #include #include #include +#if defined(__CODEGEARC__) && !defined(_WIN64) +#include +#endif + +// --------------------------------------------------------------------- + +std::string WSJCPP_INT_TO_STR(int number) { + #if defined(__CODEGEARC__) && !defined(_WIN64) + // TODO + char buffer[] = { + 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0 + }; + #if __CODEGEARC__ == 0x0770 + // 12.2 + _itoa(number, buffer, 10); + #else + itoa(number, buffer, 10); + #endif + return std::string(buffer); + #else + return std::to_string(number); + #endif +} + +std::string WSJCPP_FLOAT_TO_STR(float number) { + std::string ret; + #if defined(__CODEGEARC__) && !defined(_WIN64) + // TODO + char buffer[] = { + 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0 + }; + #if __CODEGEARC__ == 0x0770 + // 12.2 + _itoa(number, buffer, 10); + #else + itoa(number, buffer, 10); + #endif + ret = std::string(buffer); + #else + ret = std::to_string(number); + #endif + ret.erase(std::find_if(ret.rbegin(), ret.rend(), [](unsigned char ch) { + return ch != '0'; + }).base(), ret.end()); + return ret; +} + +std::string WSJCPP_DOUBLE_TO_STR(double number) { + std::string ret; + #if defined(__CODEGEARC__) && !defined(_WIN64) + // TODO + char buffer[] = { + 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0 + }; + #if __CODEGEARC__ == 0x0770 + // 12.2 + _itoa(number, buffer, 10); + #else + itoa(number, buffer, 10); + #endif + ret = std::string(buffer); + #else + ret = std::to_string(number); + #endif + ret.erase(std::find_if(ret.rbegin(), ret.rend(), [](unsigned char ch) { + return ch != '0'; + }).base(), ret.end()); + return ret; +} // --------------------------------------------------------------------- // WsjcppYamlPlaceInFile @@ -47,14 +150,21 @@ void WsjcppYamlPlaceInFile::setLine(const std::string &sLine) { } std::string WsjcppYamlPlaceInFile::getForLogFormat() { - return "(" + m_sFilename + ":" + std::to_string(m_nNumberOfLine + 1) + "): " + m_sLine; + return "(" + m_sFilename + ":" + WSJCPP_INT_TO_STR(m_nNumberOfLine + 1) + "): " + m_sLine; } // --------------------------------------------------------------------- // WsjcppYamlNode + +#if defined(__CODEGEARC__) && !defined(_WIN64) +#define WSJCPP_NULL NULL +#else +#define WSJCPP_NULL nullptr +#endif + WsjcppYamlNode::WsjcppYamlNode( - WsjcppYamlNode *pParent, + WsjcppYamlNode *pParent, IWsjcppYamlLog *pLog, const WsjcppYamlPlaceInFile &placeInFile, WsjcppYamlNodeType nItemType @@ -68,21 +178,21 @@ WsjcppYamlNode::WsjcppYamlNode( m_nValueQuotes = WSJCPP_YAML_QUOTES_NONE; m_nNameQuotes = WSJCPP_YAML_QUOTES_NONE; // TODO get child indent - if (m_pParent != nullptr && m_pParent->getParent() != nullptr) { + if (m_pParent != WSJCPP_NULL && m_pParent->getParent() != WSJCPP_NULL) { m_nNodeDiffIndent = 2; m_sNodeDiffIndent = " "; } else { m_nNodeDiffIndent = 0; m_sNodeDiffIndent = ""; } - + TAG = "WsjcppYamlNode"; } // --------------------------------------------------------------------- WsjcppYamlNode::~WsjcppYamlNode() { - for (int i = 0; i < m_vObjects.size(); i++) { + for (unsigned int i = 0; i < m_vObjects.size(); i++) { delete m_vObjects[i]; } m_vObjects.clear(); @@ -203,7 +313,7 @@ bool WsjcppYamlNode::hasElement(const std::string &sName) { if (m_nItemType != WSJCPP_YAML_NODE_MAP) { throw std::runtime_error(TAG + ": hasElement('" + sName + "'): Element must be map"); } - for (int i = 0; i < m_vObjects.size(); i++) { + for (unsigned int i = 0; i < m_vObjects.size(); i++) { if (m_vObjects[i]->getName() == sName) { return true; } @@ -217,31 +327,31 @@ WsjcppYamlNode *WsjcppYamlNode::getElement(const std::string &sName) { if (m_nItemType != WSJCPP_YAML_NODE_MAP) { throw std::runtime_error(TAG + ": getElement: Element must be map"); } - - for (int i = 0; i < m_vObjects.size(); i++) { + + for (unsigned int i = 0; i < m_vObjects.size(); i++) { std::string sObjectName = m_vObjects[i]->getName(); if (m_vObjects[i]->getName() == sName) { return m_vObjects[i]; } } - throw_error(TAG + "Element '" + sName + "' not found for " + this->getForLogFormat()); - return nullptr; + throw_error(TAG + "Element '" + sName + "' not found for " + this->getForLogFormat()); + return WSJCPP_NULL; } // --------------------------------------------------------------------- bool WsjcppYamlNode::setElement(const std::string &sName, WsjcppYamlNode *pItem) { if (m_nItemType == WSJCPP_YAML_NODE_UNDEFINED) { - m_nItemType = WSJCPP_YAML_NODE_MAP; // change item type to map on first element + m_nItemType = WSJCPP_YAML_NODE_MAP; // change item type to map on first element } if (m_nItemType != WSJCPP_YAML_NODE_MAP) { throw std::runtime_error(TAG + ": setElement, Element must be 'map' for " + pItem->getPlaceInFile().getForLogFormat()); } - + if (this->hasElement(sName)) { // TODO remove previous element throw std::runtime_error(TAG + ": setElement: Current map '" + this->getName() + "' " - "(" + m_placeInFile.getFilename() + ":" + std::to_string(m_placeInFile.getNumberOfLine()) + ") " + "(" + m_placeInFile.getFilename() + ":" + WSJCPP_INT_TO_STR(m_placeInFile.getNumberOfLine()) + ") " "already has element with this name: '" + sName + "'"); } m_vObjects.push_back(pItem); // TODO create clone @@ -273,7 +383,7 @@ std::vector WsjcppYamlNode::getKeys() { throw std::runtime_error(TAG + ": getKeys: Element must be map"); } std::vector vKeys; - for (int i = 0; i < m_vObjects.size(); i++) { + for (unsigned int i = 0; i < m_vObjects.size(); i++) { WsjcppYamlNode *pItem = m_vObjects[i]; if (pItem->isValue() || pItem->isMap() || pItem->isArray() || pItem->isUndefined()) { std::string sName = pItem->getName(); @@ -370,7 +480,7 @@ int WsjcppYamlNode::getLength() { throw std::runtime_error(TAG + ": getLength, Element must be array for " + this->getForLogFormat()); } int nCount = 0; - for (int i = 0; i < m_vObjects.size(); i++) { + for (unsigned int i = 0; i < m_vObjects.size(); i++) { if (!m_vObjects[i]->isEmpty()) { nCount++; } @@ -385,8 +495,8 @@ WsjcppYamlNode *WsjcppYamlNode::getElement(int i) { throw std::runtime_error(TAG + ": getElement, Element must be array"); } int nCounter = -1; - WsjcppYamlNode *pItem = nullptr; - for (int n = 0; n < m_vObjects.size(); n++) { + WsjcppYamlNode *pItem = WSJCPP_NULL; + for (unsigned int n = 0; n < m_vObjects.size(); n++) { if (!m_vObjects[n]->isEmpty()) { nCounter++; if (nCounter == i) { @@ -395,8 +505,8 @@ WsjcppYamlNode *WsjcppYamlNode::getElement(int i) { } } } - if (pItem == nullptr) { - throw std::runtime_error(TAG + ": getElement(" + std::to_string(i) + "), Out of range in array for '" + this->getPlaceInFile().getLine() + "'"); + if (pItem == WSJCPP_NULL) { + throw std::runtime_error(TAG + ": getElement(" + WSJCPP_INT_TO_STR(i) + "), Out of range in array for '" + this->getPlaceInFile().getLine() + "'"); } return pItem; } @@ -413,7 +523,7 @@ bool WsjcppYamlNode::appendElement(WsjcppYamlNode *pNode) { "tring add node \n" " name='" + pNode->getName() + "'\n" " type=" + pNode->getNodeTypeAsString() + "\n" - " line=" + std::to_string(pNode->getNumberOfLine()) + ")\n" + " line=" + WSJCPP_INT_TO_STR(pNode->getNumberOfLine()) + ")\n" " To element (must be array) \n" + this->getForLogFormat()); } m_vObjects.push_back(pNode); // TODO clone object @@ -439,8 +549,8 @@ bool WsjcppYamlNode::removeElement(int i) { throw std::runtime_error(TAG + ": appendElement, Element must be array for " + this->getForLogFormat()); } int nCounter = -1; - WsjcppYamlNode *pItem = nullptr; - for (int n = 0; n < m_vObjects.size(); n++) { + WsjcppYamlNode *pItem = WSJCPP_NULL; + for (unsigned int n = 0; n < m_vObjects.size(); n++) { if (!m_vObjects[n]->isEmpty()) { nCounter++; if (nCounter == i) { @@ -449,8 +559,8 @@ bool WsjcppYamlNode::removeElement(int i) { } } } - if (pItem == nullptr) { - throw std::runtime_error(TAG + ": getElement(" + std::to_string(i) + "), Out of range in array for '" + this->getPlaceInFile().getLine() + "'"); + if (pItem == WSJCPP_NULL) { + throw std::runtime_error(TAG + ": getElement(" + WSJCPP_INT_TO_STR(i) + "), Out of range in array for '" + this->getPlaceInFile().getLine() + "'"); } std::vector::iterator it; for (it = m_vObjects.begin(); it != m_vObjects.end(); ++it) { @@ -528,7 +638,7 @@ std::string WsjcppYamlNode::toString(std::string sIndent) { sRet += "# " + m_sComment; } } else if (this->isUndefined()) { - for (int i = 0; i < m_vObjects.size(); i++) { + for (unsigned int i = 0; i < m_vObjects.size(); i++) { if (m_vObjects[i]->isEmpty()) { sRet += "\n"; } else { @@ -543,7 +653,7 @@ std::string WsjcppYamlNode::toString(std::string sIndent) { } return sRet; } else if (this->isArray()) { - for (int i = 0; i < m_vObjects.size(); i++) { + for (unsigned int i = 0; i < m_vObjects.size(); i++) { WsjcppYamlNode *pNode = m_vObjects[i]; if (pNode->isEmpty()) { // std::string sVal = pNode->toString(sIndent + pNode->getStringNodeLastIndent()); @@ -564,7 +674,7 @@ std::string WsjcppYamlNode::toString(std::string sIndent) { } else if (this->isMap()) { if (m_vObjects.size() > 0) { // sRet += "-s-" + std::to_string(m_vObjects.size()) + "--"; - for (int i = 0; i < m_vObjects.size(); i++) { + for (unsigned int i = 0; i < m_vObjects.size(); i++) { WsjcppYamlNode *pNode = m_vObjects[i]; if (pNode->isEmpty() ) { std::string s = pNode->toString(sIndent); @@ -621,8 +731,8 @@ std::string WsjcppYamlNode::toString(std::string sIndent) { m_pLog->warn(TAG, "????"); sRet = ""; // undefined element must be empty } - - if (m_pParent == nullptr) { + + if (m_pParent == WSJCPP_NULL) { removeLastCharNewLine(sRet); } return sRet; @@ -670,7 +780,7 @@ void WsjcppYamlNode::setNodeIndents(const std::vector & vNodeIndents) { m_sNodeDiffIndent += " "; } m_nNodeIndent = 0; - for (int i = 0; i < vNodeIndents.size(); i++) { + for (unsigned int i = 0; i < vNodeIndents.size(); i++) { m_nNodeIndent += vNodeIndents[i]; } } @@ -716,7 +826,15 @@ bool WsjcppYamlNode::hasObjects() { // WsjcppYamlParsebleLine WsjcppYamlParsebleLine::WsjcppYamlParsebleLine(int nLine) { - TAG = "WsjcppYamlParsebleLine(line:" + std::to_string(nLine) + ")"; + initInstance(nLine); +} + +WsjcppYamlParsebleLine::WsjcppYamlParsebleLine() { + initInstance(-1); +} + +void WsjcppYamlParsebleLine::initInstance(int nLine) { + TAG = "WsjcppYamlParsebleLine(line:" + WSJCPP_INT_TO_STR(nLine) + ")"; m_nLineNumber = nLine; m_sPrefix = ""; m_bArrayItem = false; @@ -729,15 +847,6 @@ WsjcppYamlParsebleLine::WsjcppYamlParsebleLine(int nLine) { m_bEmptyLine = false; } -// --------------------------------------------------------------------- - -WsjcppYamlParsebleLine::WsjcppYamlParsebleLine() -: WsjcppYamlParsebleLine(-1) { - -} - -// --------------------------------------------------------------------- - int WsjcppYamlParsebleLine::getLineNumber() { return m_nLineNumber; } @@ -845,7 +954,7 @@ bool WsjcppYamlParsebleLine::parseLine(const std::string &sLine, std::string &sE } WsjcppYamlParserLineStates state = WSJCPP_YAML_PARSER_LINE_STATE_NO; - for (int i = 0; i < sLine.length(); i++) { + for (unsigned int i = 0; i < sLine.length(); i++) { char c = sLine[i]; if ((c == ' ' || c == '\t') && state == WSJCPP_YAML_PARSER_LINE_STATE_NO) { m_sPrefix += c; @@ -931,7 +1040,7 @@ bool WsjcppYamlParsebleLine::parseLine(const std::string &sLine, std::string &sE m_sValue += c; } }*/ - + m_sTagName = WsjcppYaml::trim(m_sTagName); if (m_sTagName.length() > 0 && m_sTagName[0] == '"') { m_nNameQuotes = WSJCPP_YAML_QUOTES_DOUBLE; @@ -1054,69 +1163,58 @@ std::string WsjcppYamlParsebleLine::removeStringSingleQuotes(const std::string & // WsjcppYamlCursor WsjcppYamlCursor::WsjcppYamlCursor(WsjcppYamlNode *pCurrentNode) { - m_pCurrentNode = pCurrentNode; - TAG = "WsjcppYamlCursor"; + initInstance(pCurrentNode); } -// --------------------------------------------------------------------- - -WsjcppYamlCursor::WsjcppYamlCursor() -: WsjcppYamlCursor(nullptr) { - // nothing +WsjcppYamlCursor::WsjcppYamlCursor() { + initInstance(WSJCPP_NULL); } -// --------------------------------------------------------------------- - WsjcppYamlCursor::~WsjcppYamlCursor() { // do nothing } -// --------------------------------------------------------------------- +void WsjcppYamlCursor::initInstance(WsjcppYamlNode *pCurrentNode) { + m_pCurrentNode = pCurrentNode; + TAG = "WsjcppYamlCursor"; +} bool WsjcppYamlCursor::isNull() const { - return m_pCurrentNode == nullptr; + return m_pCurrentNode == WSJCPP_NULL; } -// --------------------------------------------------------------------- - bool WsjcppYamlCursor::isUndefined() const { - return m_pCurrentNode != nullptr && m_pCurrentNode->isUndefined(); + return m_pCurrentNode != WSJCPP_NULL && m_pCurrentNode->isUndefined(); } -// --------------------------------------------------------------------- - bool WsjcppYamlCursor::isValue() const { - return m_pCurrentNode != nullptr && m_pCurrentNode->isValue(); + return m_pCurrentNode != WSJCPP_NULL && m_pCurrentNode->isValue(); } -// --------------------------------------------------------------------- - bool WsjcppYamlCursor::isArray() const { - return m_pCurrentNode != nullptr && m_pCurrentNode->isArray(); + return m_pCurrentNode != WSJCPP_NULL && m_pCurrentNode->isArray(); } -// --------------------------------------------------------------------- - size_t WsjcppYamlCursor::size() const { - return m_pCurrentNode != nullptr && m_pCurrentNode->isArray() ? m_pCurrentNode->getLength() : -1; + return m_pCurrentNode != WSJCPP_NULL && m_pCurrentNode->isArray() ? m_pCurrentNode->getLength() : -1; } // --------------------------------------------------------------------- bool WsjcppYamlCursor::isMap() const { - return m_pCurrentNode != nullptr && m_pCurrentNode->isMap(); + return m_pCurrentNode != WSJCPP_NULL && m_pCurrentNode->isMap(); } // --------------------------------------------------------------------- std::vector WsjcppYamlCursor::keys() const { - return m_pCurrentNode != nullptr && m_pCurrentNode->isMap() ? m_pCurrentNode->getKeys() : std::vector(); + return m_pCurrentNode != WSJCPP_NULL && m_pCurrentNode->isMap() ? m_pCurrentNode->getKeys() : std::vector(); } // --------------------------------------------------------------------- bool WsjcppYamlCursor::hasKey(const std::string &sKey) const { - return m_pCurrentNode != nullptr && m_pCurrentNode->isMap() && m_pCurrentNode->hasElement(sKey); + return m_pCurrentNode != WSJCPP_NULL && m_pCurrentNode->isMap() && m_pCurrentNode->hasElement(sKey); } // --------------------------------------------------------------------- @@ -1124,21 +1222,21 @@ bool WsjcppYamlCursor::hasKey(const std::string &sKey) const { // WsjcppYamlCursor &WsjcppYamlCursor::set(const std::string &sName, const std::string &sValue) { // return *this; // } -// +// // // --------------------------------------------------------------------- -// +// // WsjcppYamlCursor &WsjcppYamlCursor::set(const std::string &sName, int nValue) { // return *this; // } -// +// // // --------------------------------------------------------------------- -// +// // WsjcppYamlCursor &WsjcppYamlCursor::set(const std::string &sName, bool bValue) { // return *this; // } -// +// // // --------------------------------------------------------------------- -// +// // WsjcppYamlCursor &WsjcppYamlCursor::remove(const std::string &sKey) { // return *this; // } @@ -1146,13 +1244,13 @@ bool WsjcppYamlCursor::hasKey(const std::string &sKey) const { // --------------------------------------------------------------------- std::string WsjcppYamlCursor::comment() { - return m_pCurrentNode != nullptr ? m_pCurrentNode->getComment() : ""; + return m_pCurrentNode != WSJCPP_NULL ? m_pCurrentNode->getComment() : std::string(""); } // --------------------------------------------------------------------- WsjcppYamlCursor &WsjcppYamlCursor::comment(const std::string& sComment) { - if (m_pCurrentNode != nullptr) { + if (m_pCurrentNode != WSJCPP_NULL) { m_pCurrentNode->setComment(sComment); } return *this; @@ -1161,11 +1259,11 @@ WsjcppYamlCursor &WsjcppYamlCursor::comment(const std::string& sComment) { // --------------------------------------------------------------------- std::string WsjcppYamlCursor::valStr() const { - return m_pCurrentNode != nullptr ? m_pCurrentNode->getValue() : ""; + return m_pCurrentNode != WSJCPP_NULL ? m_pCurrentNode->getValue() : std::string(""); } WsjcppYamlCursor &WsjcppYamlCursor::val(const std::string &sValue) { - if (m_pCurrentNode != nullptr) { + if (m_pCurrentNode != WSJCPP_NULL) { m_pCurrentNode->setValue(sValue); // TODO reserch need or not add quotes } return *this; @@ -1177,11 +1275,11 @@ WsjcppYamlCursor &WsjcppYamlCursor::val(const char *sValue) { } int WsjcppYamlCursor::valInt() const { - if (m_pCurrentNode != nullptr) { + if (m_pCurrentNode != WSJCPP_NULL) { std::string sValue = m_pCurrentNode->getValue(); sValue = WsjcppYaml::toLower(sValue); - int nValue = std::strtol(sValue.c_str(), nullptr, 10); - if (std::to_string(nValue) != sValue) { + int nValue = std::strtol(sValue.c_str(), WSJCPP_NULL, 10); + if (WSJCPP_INT_TO_STR(nValue) != sValue) { throw std::runtime_error(TAG + ": valInt, Element must be int but have a string" + m_pCurrentNode->getForLogFormat()); } return nValue; @@ -1189,15 +1287,57 @@ int WsjcppYamlCursor::valInt() const { return 0; } +float WsjcppYamlCursor::valFloat() const { + if (m_pCurrentNode != WSJCPP_NULL) { + std::string sValue = m_pCurrentNode->getValue(); + float nValue = std::stof(sValue); + std::string sExpectedValue = WSJCPP_FLOAT_TO_STR(nValue); + if (sExpectedValue != sValue) { + std::string error_msg = TAG + ": valInt, Element must be float but have a string" + m_pCurrentNode->getForLogFormat() + "', but expected value is '" + sExpectedValue + "'"; + throw std::runtime_error(error_msg); + } + return nValue; + } + return 0.0f; +} + +WsjcppYamlCursor &WsjcppYamlCursor::val(float nValue) { + if (m_pCurrentNode != WSJCPP_NULL) { + m_pCurrentNode->setValue(WSJCPP_FLOAT_TO_STR(nValue)); + } + return *this; +} + +double WsjcppYamlCursor::valDouble() const { + if (m_pCurrentNode != WSJCPP_NULL) { + std::string sValue = m_pCurrentNode->getValue(); + double nValue = std::stod(sValue); + std::string sExpectedValue = WSJCPP_DOUBLE_TO_STR(nValue); + if (sExpectedValue != sValue) { + std::string error_msg = TAG + ": valInt, Element must be float but have a string '" + m_pCurrentNode->getForLogFormat() + "', but expected value is '" + sExpectedValue + "'"; + throw std::runtime_error(error_msg); + } + return nValue; + } + return 0.0f; +} + +WsjcppYamlCursor &WsjcppYamlCursor::val(double nValue) { + if (m_pCurrentNode != WSJCPP_NULL) { + m_pCurrentNode->setValue(WSJCPP_DOUBLE_TO_STR(nValue)); + } + return *this; +} + WsjcppYamlCursor &WsjcppYamlCursor::val(int nValue) { - if (m_pCurrentNode != nullptr) { - m_pCurrentNode->setValue(std::to_string(nValue)); + if (m_pCurrentNode != WSJCPP_NULL) { + m_pCurrentNode->setValue(WSJCPP_INT_TO_STR(nValue)); } return *this; } bool WsjcppYamlCursor::valBool() const { - if (m_pCurrentNode != nullptr) { + if (m_pCurrentNode != WSJCPP_NULL) { std::string sValue = m_pCurrentNode->getValue(); sValue = WsjcppYaml::toLower(sValue); if (sValue == "yes" || sValue == "true") { @@ -1213,7 +1353,7 @@ bool WsjcppYamlCursor::valBool() const { } WsjcppYamlCursor &WsjcppYamlCursor::val(bool bValue) { - if (m_pCurrentNode != nullptr) { + if (m_pCurrentNode != WSJCPP_NULL) { m_pCurrentNode->setValue((bValue ? "yes" : "no")); } return *this; @@ -1224,14 +1364,14 @@ WsjcppYamlNode *WsjcppYamlCursor::node() { } WsjcppYamlCursor WsjcppYamlCursor::operator[](int idx) const { - if (m_pCurrentNode != nullptr && m_pCurrentNode->isArray() && idx < m_pCurrentNode->getLength() && idx >= 0) { + if (m_pCurrentNode != WSJCPP_NULL && m_pCurrentNode->isArray() && idx < m_pCurrentNode->getLength() && idx >= 0) { return WsjcppYamlCursor(m_pCurrentNode->getElement(idx)); } return WsjcppYamlCursor(); } WsjcppYamlCursor WsjcppYamlCursor::operator[](const std::string &sName) const { - if (m_pCurrentNode != nullptr && m_pCurrentNode->isMap() && m_pCurrentNode->hasElement(sName)) { + if (m_pCurrentNode != WSJCPP_NULL && m_pCurrentNode->isMap() && m_pCurrentNode->hasElement(sName)) { return WsjcppYamlCursor(m_pCurrentNode->getElement(sName)); } return WsjcppYamlCursor(); @@ -1239,7 +1379,7 @@ WsjcppYamlCursor WsjcppYamlCursor::operator[](const std::string &sName) const { WsjcppYamlCursor WsjcppYamlCursor::operator[](const char *pName) const { std::string sName(pName); - if (m_pCurrentNode != nullptr && m_pCurrentNode->isMap() && m_pCurrentNode->hasElement(sName)) { + if (m_pCurrentNode != WSJCPP_NULL && m_pCurrentNode->isMap() && m_pCurrentNode->hasElement(sName)) { return WsjcppYamlCursor(m_pCurrentNode->getElement(sName)); } return WsjcppYamlCursor(); @@ -1265,9 +1405,9 @@ WsjcppYamlCursor& WsjcppYamlCursor::operator=(const bool &bVal) { // WsjcppYaml WsjcppYaml::WsjcppYaml() { - m_pRoot = new WsjcppYamlNode(nullptr, this, WsjcppYamlPlaceInFile(), WSJCPP_YAML_NODE_MAP); + m_pRoot = new WsjcppYamlNode(WSJCPP_NULL, this, WsjcppYamlPlaceInFile(), WSJCPP_YAML_NODE_MAP); TAG = "WsjcppYaml"; - m_pLog = nullptr; + m_pLog = WSJCPP_NULL; } WsjcppYaml::~WsjcppYaml() { @@ -1280,7 +1420,7 @@ void WsjcppYaml::setLogger(IWsjcppYamlLog *pLog) { void WsjcppYaml::clear() { delete m_pRoot; - m_pRoot = nullptr; + m_pRoot = WSJCPP_NULL; } bool WsjcppYaml::loadFromFile(const std::string &sFileName, std::string &sError) { @@ -1298,7 +1438,7 @@ bool WsjcppYaml::saveToFile(const std::string &sFileName, std::string &sError) { std::string sBuffer = m_pRoot->toString() + "\n"; // last empty line must be always if (!WsjcppYaml::writeFile(sFileName, sBuffer)) { sError = "Could not save to file"; - return false; + return false; } return true; } @@ -1342,14 +1482,14 @@ WsjcppYamlCursor WsjcppYaml::operator[](const std::string &sName) const { } bool WsjcppYaml::readTextFile(const std::string &sFilename, std::string &sOutputContent, std::string &sError) { - std::ifstream f(sFilename); - if (!f) { + std::ifstream file_(sFilename.c_str()); + if (!file_) { sError = "FAILED could not open file to read " + sFilename; return false; } sOutputContent = std::string( - (std::istreambuf_iterator(f)), + (std::istreambuf_iterator(file_)), std::istreambuf_iterator() ); @@ -1357,15 +1497,15 @@ bool WsjcppYaml::readTextFile(const std::string &sFilename, std::string &sOutput } bool WsjcppYaml::writeFile(const std::string &sFilename, const std::string &sContent) { - + // std::ofstream f(sFilename, std::ifstream::in); - std::ofstream f(sFilename, std::ios::out); - if (!f) { + std::ofstream file_(sFilename.c_str(), std::ios::out); + if (!file_) { std::cerr << "WsjcppYaml::writeFile" << "Could not create file to write '" << sFilename << "'" << std::endl; return false; } - f << sContent << std::endl; - f.close(); + file_ << sContent << std::endl; + file_.close(); return true; } @@ -1448,8 +1588,8 @@ std::vector WsjcppYaml::splitToLines(const std::string &sBuffer) { bool WsjcppYaml::parse(const std::string &sFileName, const std::string &sBuffer, std::string &sError) { this->clear(); - if (m_pRoot == nullptr) { - m_pRoot = new WsjcppYamlNode(nullptr, this, WsjcppYamlPlaceInFile(), WSJCPP_YAML_NODE_MAP); + if (m_pRoot == WSJCPP_NULL) { + m_pRoot = new WsjcppYamlNode(WSJCPP_NULL, this, WsjcppYamlPlaceInFile(), WSJCPP_YAML_NODE_MAP); } std::vector vLines = this->splitToLines(sBuffer); @@ -1460,15 +1600,15 @@ bool WsjcppYaml::parse(const std::string &sFileName, const std::string &sBuffer, m_nParseCurrentIndent = 0; m_pRoot->setPlaceInFile(m_parsePlaceInFile); - for (int nLine = 0; nLine < vLines.size(); nLine++) { + for (unsigned int nLine = 0; nLine < vLines.size(); nLine++) { m_parsePlaceInFile.setLine(vLines[nLine]); m_parsePlaceInFile.setNumberOfLine(nLine); m_parseLine = WsjcppYamlParsebleLine(nLine); if (!m_parseLine.parseLine(m_parsePlaceInFile.getLine(), sError)) { return false; } - - bool isEmptyName = m_parseLine.isEmptyName(); + + // bool isEmptyName = m_parseLine.isEmptyName(); bool isEmptyValue = m_parseLine.isEmptyValue(); bool isArrayItem = m_parseLine.isArrayItem(); int nLineIndent = m_parseLine.getIndent(); @@ -1480,7 +1620,7 @@ bool WsjcppYaml::parse(const std::string &sFileName, const std::string &sBuffer, } if (m_parseLine.isEmptyLine()) { - if (m_pParseCurrentParentNode != nullptr) { + if (m_pParseCurrentParentNode != WSJCPP_NULL) { // WsjcppLog::warn(TAG, "here empty line and parent exists " + m_parsePlaceInFile.getForLogFormat()); if (m_pParseCurrentParentNode->isArray() || m_pParseCurrentParentNode->isMap() || m_pParseCurrentParentNode->isUndefined()) { // WsjcppLog::warn(TAG, "array, map or undefined"); @@ -1492,7 +1632,7 @@ bool WsjcppYaml::parse(const std::string &sFileName, const std::string &sBuffer, ); pNode->setNodeIndents(m_vStackDiffNodeIndents); m_pParseCurrentParentNode->appendElement(pNode); - } else if (m_pParseCurrentParentNode->getParent() != nullptr && (m_pParseCurrentParentNode->getParent()->isArray() || m_pParseCurrentParentNode->getParent()->isMap())) { + } else if (m_pParseCurrentParentNode->getParent() != WSJCPP_NULL && (m_pParseCurrentParentNode->getParent()->isArray() || m_pParseCurrentParentNode->getParent()->isMap())) { // WsjcppLog::warn(TAG, "parent exists and parent map or array"); WsjcppYamlNode *pNode = new WsjcppYamlNode( m_pParseCurrentParentNode->getParent(), @@ -1519,15 +1659,15 @@ bool WsjcppYaml::parse(const std::string &sFileName, const std::string &sBuffer, m_vStackDiffNodeIndents.clear(); m_vStackDiffNodeIndents.push_back(0); } - + // switch to parent while (nDiffIndent < 0 && m_nParseCurrentIndent != m_parseLine.getIndent()) { - if (m_pParseCurrentParentNode == nullptr) { - sError = "Current node is nullptr, line: " + std::to_string(nLine); + if (m_pParseCurrentParentNode == WSJCPP_NULL) { + sError = "Current node is null, line: " + WSJCPP_INT_TO_STR(nLine); return false; } - if (m_pParseCurrentParentNode->getParent() == nullptr) { - sError = "Parent of current node is nullptr, line: " + std::to_string(nLine); + if (m_pParseCurrentParentNode->getParent() == WSJCPP_NULL) { + sError = "Parent of current node is null, line: " + WSJCPP_INT_TO_STR(nLine); return false; } m_nParseCurrentIndent = m_nParseCurrentIndent - m_vStackDiffNodeIndents.back(); @@ -1535,9 +1675,9 @@ bool WsjcppYaml::parse(const std::string &sFileName, const std::string &sBuffer, m_pParseCurrentParentNode = m_pParseCurrentParentNode->getParent(); if (m_nParseCurrentIndent < m_parseLine.getIndent()) { sError = "Wrong indent, expected " - "'" + std::to_string(m_parseLine.getIndent()) + "'," - " but got '" + - " in line: (" + sFileName + ":" + std::to_string(nLine) + ")"; + "'" + WSJCPP_INT_TO_STR(m_parseLine.getIndent()) + "'," + " but got '" + + " in line: (" + sFileName + ":" + WSJCPP_INT_TO_STR(nLine) + ")"; return false; } @@ -1589,14 +1729,14 @@ void WsjcppYaml::process_hasName_emptyValue_arrayItem() { void WsjcppYaml::process_hasName_emptyValue_noArrayItem() { // std::cout << "process_hasName_emptyValue_noArrayItem" << std::endl; if (m_parseLine.getIndent() == m_pParseCurrentParentNode->getNodeIndent()) { - if (m_pParseCurrentParentNode->getParent() != nullptr) { + if (m_pParseCurrentParentNode->getParent() != WSJCPP_NULL) { m_pParseCurrentParentNode = m_pParseCurrentParentNode->getParent(); } } WsjcppYamlNode *pNode = new WsjcppYamlNode( m_pParseCurrentParentNode, this, - m_parsePlaceInFile, + m_parsePlaceInFile, WSJCPP_YAML_NODE_UNDEFINED ); if (m_parseLine.getValueQuotes() != WSJCPP_YAML_QUOTES_NONE) { @@ -1642,16 +1782,16 @@ void WsjcppYaml::process_hasName_hasValue_arrayItem() { WsjcppYamlNode *pNode = new WsjcppYamlNode( m_pParseCurrentParentNode, this, - m_parsePlaceInFile, + m_parsePlaceInFile, WSJCPP_YAML_NODE_VALUE ); pNode->setComment(m_parseLine.getComment()); pNode->setValue(m_parseLine.getValue(), m_parseLine.getValueQuotes()); pNode->setName(m_parseLine.getName(), m_parseLine.getNameQuotes()); pMapItem->setElement(m_parseLine.getName(), pNode); - + // next indents must be for map - m_vStackDiffNodeIndents.push_back(2); + m_vStackDiffNodeIndents.push_back(2); m_nParseCurrentIndent += 2; } @@ -1662,7 +1802,7 @@ void WsjcppYaml::process_hasName_hasValue_noArrayItem() { WsjcppYamlNode *pNode = new WsjcppYamlNode( m_pParseCurrentParentNode, this, - m_parsePlaceInFile, + m_parsePlaceInFile, WSJCPP_YAML_NODE_VALUE ); // std::cout << "m_parseLine.getName(): " << m_parseLine.getName() << std::endl; @@ -1713,7 +1853,7 @@ void WsjcppYaml::process_emptyName_emptyValue_arrayItem() { WsjcppYamlNode *pNode = new WsjcppYamlNode( m_pParseCurrentParentNode, this, - m_parsePlaceInFile, + m_parsePlaceInFile, WSJCPP_YAML_NODE_VALUE ); pNode->setComment(m_parseLine.getComment()); @@ -1741,9 +1881,9 @@ void WsjcppYaml::logUnknownParseLine() { this->warn(TAG, "\n" " error:\n" " desc: \"unknown_line\"\n" - " line_number: " + std::to_string(m_pParseCurrentParentNode->getPlaceInFile().getNumberOfLine()) + "\n" + " line_number: " + WSJCPP_INT_TO_STR(m_pParseCurrentParentNode->getPlaceInFile().getNumberOfLine()) + "\n" " line: \"" + m_parsePlaceInFile.getLine() + "\"\n" - " indent: " + std::to_string(m_nParseCurrentIndent) + "\n" + " indent: " + WSJCPP_INT_TO_STR(m_nParseCurrentIndent) + "\n" " filename: \"" + m_pParseCurrentParentNode->getPlaceInFile().getFilename() + "\"" ); -} \ No newline at end of file +} diff --git a/src.wsjcpp/wsjcpp_yaml/wsjcpp_yaml.h b/src.wsjcpp/wsjcpp_yaml/wsjcpp_yaml.h index 93ba1de63..e1e05a680 100644 --- a/src.wsjcpp/wsjcpp_yaml/wsjcpp_yaml.h +++ b/src.wsjcpp/wsjcpp_yaml/wsjcpp_yaml.h @@ -1,3 +1,29 @@ +/* +MIT License + +Copyright (c) 2019-2025 wsjcpp + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Official Source Code: https://github.com/wsjcpp/wsjcpp-yaml +*/ + #ifndef WSJCPP_YAML_H #define WSJCPP_YAML_H @@ -61,9 +87,9 @@ class IWsjcppYamlLog { // --------------------------------------------------------------------- /*! - \brief Class for keep data of yaml node + \brief Class for keep data of yaml node - Basic class for yaml tree + Basic class for yaml tree */ class WsjcppYamlNode { @@ -125,12 +151,12 @@ class WsjcppYamlNode { bool removeElement(int i); bool isValue(); - + std::string getValue(); // contains only strings void setValue(const std::string &sValue, WsjcppYamlQuotes nQuotes = WSJCPP_YAML_QUOTES_NONE); WsjcppYamlQuotes getValueQuotes(); - + std::string getSerializedName(); std::string toString(std::string sIndent = ""); std::string getNodeTypeAsString(); @@ -189,7 +215,8 @@ class WsjcppYamlParsebleLine { bool parseLine(const std::string &sLine, std::string &sError); private: - + void initInstance(int nLine); + std::string TAG; int m_nLineNumber; @@ -218,13 +245,13 @@ class WsjcppYamlCursor { // null or undefined bool isNull() const; - + // isUndefined bool isUndefined() const; // value bool isValue() const; - + // array bool isArray() const; size_t size() const; @@ -242,19 +269,23 @@ class WsjcppYamlCursor { // WsjcppYamlCursor &set(const std::string &sName, bool bValue); // WsjcppYamlCursor &remove(const std::string &sKey); - // comment + // comment std::string comment(); WsjcppYamlCursor &comment(const std::string& sComment); - + // val std::string valStr() const; WsjcppYamlCursor &val(const std::string &sValue); WsjcppYamlCursor &val(const char *sValue); int valInt() const; WsjcppYamlCursor &val(int nValue); + float valFloat() const; + WsjcppYamlCursor &val(float nValue); + double valDouble() const; + WsjcppYamlCursor &val(double nValue); bool valBool() const; WsjcppYamlCursor &val(bool bValue); - + // node WsjcppYamlNode *node(); @@ -274,6 +305,8 @@ class WsjcppYamlCursor { WsjcppYamlCursor& operator=(const bool &bVal); private: + void initInstance(WsjcppYamlNode *pCurrentNode); + std::string TAG; WsjcppYamlNode *m_pCurrentNode; }; @@ -303,10 +336,17 @@ class WsjcppYaml : public IWsjcppYamlLog { static std::string toLower(const std::string &str); // IWsjcppYamlLog + #if defined(__CODEGEARC__) && !defined(_WIN64) + virtual void err(const std::string &TAG, const std::string &sMessage); + virtual void throw_err(const std::string &TAG, const std::string &sMessage); + virtual void warn(const std::string &TAG, const std::string &sMessage); + virtual void info(const std::string &TAG, const std::string &sMessage); + #else virtual void err(const std::string &TAG, const std::string &sMessage) override; virtual void throw_err(const std::string &TAG, const std::string &sMessage) override; virtual void warn(const std::string &TAG, const std::string &sMessage) override; virtual void info(const std::string &TAG, const std::string &sMessage) override; + #endif private: std::string TAG; diff --git a/src/3rdParty/quazip-0.7.3/CMakeLists.txt b/src/3rdParty/quazip-0.7.3/CMakeLists.txt deleted file mode 100644 index 3d2fb5501..000000000 --- a/src/3rdParty/quazip-0.7.3/CMakeLists.txt +++ /dev/null @@ -1,63 +0,0 @@ -project(QuaZip) -cmake_minimum_required(VERSION 2.6) - -# CMP0042: Explicitly acknowledge MACOSX_RPATH -# (introduced in CMake 2.8.12, enabled by default in CMake 3.0, -# and producing a warning when unset since 3.7.1) -cmake_policy(SET CMP0042 NEW) - -option(BUILD_WITH_QT4 "Build QuaZip with Qt4 no matter if Qt5 was found" OFF) - -if( NOT BUILD_WITH_QT4 ) - # try Qt5 first, and prefer that if found - find_package(Qt5Core QUIET) -endif() - -if(Qt5Core_FOUND) - set(CMAKE_CXX_STANDARD 11) - set(QTCORE_LIBRARIES ${Qt5Core_LIBRARIES}) - set(QUAZIP_LIB_VERSION_SUFFIX 5) - # if there is no QT_ROOT, try to deduce it from Qt QtCore include - if("${QT_ROOT}" STREQUAL "") - set(QT_ROOT ${QT_QTCORE_INCLUDE_DIR}/../..) - endif() - include_directories(${Qt5Core_INCLUDE_DIRS}) - - macro(qt_wrap_cpp) - qt5_wrap_cpp(${ARGN}) - endmacro() -else() - set(qt_min_version "4.5.0") - find_package(Qt4 REQUIRED) - set(QT_USE_QTGUI false) - include(${QT_USE_FILE}) - include_directories(${QT_INCLUDES}) - set(QTCORE_LIBRARIES ${QT_QTCORE_LIBRARY}) - - macro(qt_wrap_cpp) - qt4_wrap_cpp(${ARGN}) - endmacro() -endif() - -# Use system zlib on unix and Qt ZLIB on Windows -if(UNIX OR MINGW) - find_package(ZLIB REQUIRED) -else(UNIX OR MINGW) - set(ZLIB_INCLUDE_DIRS "${QT_ROOT}/src/3rdparty/zlib" CACHE STRING "Path to ZLIB headers of Qt") - set(ZLIB_LIBRARIES "") - if(NOT EXISTS "${ZLIB_INCLUDE_DIRS}/zlib.h") - message("Please specify a valid zlib include dir") - endif(NOT EXISTS "${ZLIB_INCLUDE_DIRS}/zlib.h") -endif(UNIX OR MINGW) - -# All build libraries are moved to this directory -set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}) - -set(LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)") -set(LIB_DESTINATION "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE STRING "Library directory name" FORCE) -set(QUAZIP_LIB_TARGET_NAME quazip${QUAZIP_LIB_VERSION_SUFFIX} CACHE - INTERNAL "Target name of libquazip" FORCE) - -add_subdirectory(quazip) - -install(FILES FindQuaZip.cmake RENAME FindQuaZip${QUAZIP_LIB_VERSION_SUFFIX}.cmake DESTINATION ${CMAKE_ROOT}/Modules) diff --git a/src/3rdParty/quazip-0.7.3/COPYING b/src/3rdParty/quazip-0.7.3/COPYING deleted file mode 100644 index e5e2603e6..000000000 --- a/src/3rdParty/quazip-0.7.3/COPYING +++ /dev/null @@ -1,474 +0,0 @@ -The QuaZIP library is licensed under the GNU Lesser General Public -License V2.1 plus a static linking exception. - -STATIC LINKING EXCEPTION - -The copyright holders give you permission to link this library with -independent modules to produce an executable, regardless of the license -terms of these independent modules, and to copy and distribute the -resulting executable under terms of your choice, provided that you also -meet, for each linked independent module, the terms and conditions of -the license of that module. An independent module is a module which is -not derived from or based on this library. If you modify this library, -you must extend this exception to your version of the library. - -The text of the GNU Lesser General Public License V2.1 follows. - - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS diff --git a/src/3rdParty/quazip-0.7.3/Doxyfile b/src/3rdParty/quazip-0.7.3/Doxyfile deleted file mode 100644 index 321af4860..000000000 --- a/src/3rdParty/quazip-0.7.3/Doxyfile +++ /dev/null @@ -1,1722 +0,0 @@ -# Doxyfile 1.7.4 - -# 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 = QuaZIP - -# 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 = quazip-0-7-3 - -# Using the PROJECT_BRIEF tag one can provide an optional one line description -# for a project that appears at the top of each page and should give viewer -# a quick idea about the purpose of the project. Keep the description short. - -PROJECT_BRIEF = - -# With the PROJECT_LOGO tag one can specify an logo or icon that is -# included in the documentation. The maximum height of the logo should not -# exceed 55 pixels and the maximum width should not exceed 200 pixels. -# Doxygen will copy the logo to the output directory. - -PROJECT_LOGO = - -# 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 = doc - -# 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-Cyrillic, 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 if your file system -# 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 = 8 - -# 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 = NO - -# 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 makes 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 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 - -# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and -# unions are shown inside the group in which they are included (e.g. using -# @ingroup) instead of on a separate page (for HTML and Man pages) or -# section (for LaTeX and RTF). - -INLINE_GROUPED_CLASSES = NO - -# 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 = NO - -# 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 penalty. -# 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 roughly 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 = NO - -# 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 namespaces 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 - -# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to -# do proper type resolution of all parameters of a function it will reject a -# match between the prototype and the implementation of a member function even -# if there is only one candidate or it is obvious which candidate to choose -# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen -# will still accept a match between prototype and implementation in such cases. - -STRICT_PROTO_MATCHING = 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 macro 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 macros 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 = YES - -# 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 - -# The WARN_NO_PARAMDOC option can be enabled 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 = quazip - -# 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++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh -# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py -# *.f90 *.f *.for *.vhd *.vhdl - -FILE_PATTERNS = *.cpp \ - *.h \ - *.dox - -# 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 = YES - -# 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 = quazip/unzip.h \ - quazip/zip.h \ - quazip/ioapi.h \ - quazip/crypt.h \ - qztest/ - -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix file system 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 = */.moc/* */release/* */debug/* */moc_*.cpp - -# 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 or if -# non of the patterns match the file name, INPUT_FILTER is applied. - -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 - -# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file -# pattern. A pattern will override the setting for FILTER_PATTERN (if any) -# and it is also possible to disable source filtering for a specific pattern -# using *.ext= (so without naming a filter). This option only has effect when -# FILTER_SOURCE_FILES is enabled. - -FILTER_SOURCE_PATTERNS = - -#--------------------------------------------------------------------------- -# 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 = YES - -# 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 = YES - -# 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 = NO - -# 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. Note that when using a custom header you are responsible -# for the proper inclusion of any scripts and style sheets that doxygen -# needs, which is dependent on the configuration options used. -# It is adviced to generate a default header using "doxygen -w html -# header.html footer.html stylesheet.css YourConfigFile" and then modify -# that header. Note that the header is subject to change so you typically -# have to redo this when upgrading to a newer version of doxygen or when changing the value of configuration settings such as GENERATE_TREEVIEW! - -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_EXTRA_FILES tag can be used to specify one or more extra images or -# other source files which should be copied to the HTML output directory. Note -# that these files will be copied to the base HTML output directory. Use the -# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these -# files. In the HTML_STYLESHEET file, use the file name only. Also note that -# the files will be copied as-is; there are no commands or markers available. - -HTML_EXTRA_FILES = - -# 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 - -# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values -# (range [0,1..20]) that doxygen will group on one line in the generated HTML -# documentation. Note that a value of 0 will completely suppress the enum -# values from appearing in the overview section. - -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 - -# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax -# (see http://www.mathjax.org) which uses client side Javascript for the -# rendering instead of using prerendered bitmaps. Use this if you do not -# have LaTeX installed or if you want to formulas look prettier in the HTML -# output. When enabled you also need to install MathJax separately and -# configure the path to it using the MATHJAX_RELPATH option. - -USE_MATHJAX = NO - -# When MathJax is enabled you need to specify the location relative to the -# HTML output directory using the MATHJAX_RELPATH option. The destination -# directory should contain the MathJax.js script. For instance, if the mathjax -# directory is located at the same level as the HTML output directory, then -# MATHJAX_RELPATH should be ../mathjax. The default value points to the -# mathjax.org site, so you can quickly see the result without installing -# MathJax, but it is strongly recommended to install a local copy of MathJax -# before deployment. - -MATHJAX_RELPATH = http://www.mathjax.org/mathjax - -# 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 = NO - -# 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 disadvantages are 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 = YES - -# 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, 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 = - -# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for -# the generated latex document. The footer should contain everything after -# the last chapter. If it is left blank doxygen will generate a -# standard footer. Notice: only use this tag if you know what you are doing! - -LATEX_FOOTER = - -# 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 = NO - -# 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 = NO - -# 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 = NO - -# 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 -# pointed to by INCLUDE_PATH will be searched when 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 = - -# 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 that -# overrules the definition found in the source code. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all references to function-like macros -# that are alone on a line, have an all uppercase name, and do not end with a -# semicolon, because these 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 = qtcore.tags=http://doc.qt.io/qt-5/ - -# 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 also works with HAVE_DOT disabled, but 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 = YES - -# 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 Helvetica to the output -# directory and reference it in all dot files that doxygen generates. -# When you want a differently looking font you can specify the font name -# using DOT_FONTNAME. You 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 = Helvetica - -# 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 generate a 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 svg, 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 MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the -# \mscfile command). - -MSCFILE_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 = NO - -# 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/src/3rdParty/quazip-0.7.3/FindQuaZip.cmake b/src/3rdParty/quazip-0.7.3/FindQuaZip.cmake deleted file mode 100644 index 23f4918db..000000000 --- a/src/3rdParty/quazip-0.7.3/FindQuaZip.cmake +++ /dev/null @@ -1,43 +0,0 @@ -# QUAZIP_FOUND - QuaZip library was found -# QUAZIP_INCLUDE_DIR - Path to QuaZip include dir -# QUAZIP_INCLUDE_DIRS - Path to QuaZip and zlib include dir (combined from QUAZIP_INCLUDE_DIR + ZLIB_INCLUDE_DIR) -# QUAZIP_LIBRARIES - List of QuaZip libraries -# QUAZIP_ZLIB_INCLUDE_DIR - The include dir of zlib headers - - -IF (QUAZIP_INCLUDE_DIRS AND QUAZIP_LIBRARIES) - # in cache already - SET(QUAZIP_FOUND TRUE) -ELSE (QUAZIP_INCLUDE_DIRS AND QUAZIP_LIBRARIES) - IF (Qt5Core_FOUND) - set(QUAZIP_LIB_VERSION_SUFFIX 5) - ENDIF() - IF (WIN32) - FIND_PATH(QUAZIP_LIBRARY_DIR - WIN32_DEBUG_POSTFIX d - NAMES libquazip${QUAZIP_LIB_VERSION_SUFFIX}.dll - HINTS "C:/Programme/" "C:/Program Files" - PATH_SUFFIXES QuaZip/lib - ) - FIND_LIBRARY(QUAZIP_LIBRARIES NAMES libquazip${QUAZIP_LIB_VERSION_SUFFIX}.dll HINTS ${QUAZIP_LIBRARY_DIR}) - FIND_PATH(QUAZIP_INCLUDE_DIR NAMES quazip.h HINTS ${QUAZIP_LIBRARY_DIR}/../ PATH_SUFFIXES include/quazip) - FIND_PATH(QUAZIP_ZLIB_INCLUDE_DIR NAMES zlib.h) - ELSE(WIN32) - FIND_PACKAGE(PkgConfig) -# pkg_check_modules(PC_QCA2 QUIET qca2) - pkg_check_modules(PC_QUAZIP quazip) - FIND_LIBRARY(QUAZIP_LIBRARIES - WIN32_DEBUG_POSTFIX d - NAMES quazip${QUAZIP_LIB_VERSION_SUFFIX} - HINTS /usr/lib /usr/lib64 - ) - FIND_PATH(QUAZIP_INCLUDE_DIR quazip.h - HINTS /usr/include /usr/local/include - PATH_SUFFIXES quazip${QUAZIP_LIB_VERSION_SUFFIX} - ) - FIND_PATH(QUAZIP_ZLIB_INCLUDE_DIR zlib.h HINTS /usr/include /usr/local/include) - ENDIF (WIN32) - INCLUDE(FindPackageHandleStandardArgs) - SET(QUAZIP_INCLUDE_DIRS ${QUAZIP_INCLUDE_DIR} ${QUAZIP_ZLIB_INCLUDE_DIR}) - find_package_handle_standard_args(QUAZIP DEFAULT_MSG QUAZIP_LIBRARIES QUAZIP_INCLUDE_DIR QUAZIP_ZLIB_INCLUDE_DIR QUAZIP_INCLUDE_DIRS) -ENDIF (QUAZIP_INCLUDE_DIRS AND QUAZIP_LIBRARIES) diff --git a/src/3rdParty/quazip-0.7.3/NEWS.txt b/src/3rdParty/quazip-0.7.3/NEWS.txt deleted file mode 100644 index 3d0be940d..000000000 --- a/src/3rdParty/quazip-0.7.3/NEWS.txt +++ /dev/null @@ -1,163 +0,0 @@ -QuaZIP changes - -* 2017-02-05 0.7.3 - * Symlink handling - * Static linking exception for LGPL - * Minor bug fixes - -* 2016-03-29 0.7.2 - * New JlCompress methods (QIODevice*-based API by Lukasz Kwiecinski) - * Implemented QuaZioDevice::atEnd() and bytesAvailable()--these might - break ABI, but pretty unlikely. - -* 2015-01-07 0.7.1 - * Fixed licensing issues (bug #45). - * Added the convenience method QuaZipFileInfo::isEncrypted(). - -* 2014-07-24 0.7 - * It is now possible to write ZIP files to sequential devices - like sockets (only in mdCreate mode, so no self-extract, sorry). - * A few zip64 fixes. - * Several bug fixes and portability improvements. - -* 2014-02-09 0.6.2 - * QuaZipNewInfo / QuaZipFileInfo64 now provide API to access/set - NTFS time stamps - useful even on non-NTFS systems if you - need more precise dates and times than default ones. - * QuaZipNewInfo may now be initialized from QuaZipFileInfo64. - * No more crashes when using QSaveFile as QIODevice for ZIP. - * The new QuaZip::setAutoClose() method allows to leave the - QIODevice open when you close the QuaZip instance. - * qztest now depends on quazip, no longer breaking the build. - -* 2014-01-26 0.6.1 - * Improved zip64 support. - * A LOT more tests thanks to g++ --coverage / lcov. - * JlCompress extraction methods now create files with default - permissions if they are zero in the original archive. - * Some QuaZipDir fixes (thanks to the new tests). - -* 2014-01-22 0.6 - * Minizip updated to 1.1 (with all the necessary modifications - re-done), and that means that... - * the long-awaited zip64 support is now available! - * A few rather minor fixes. - -* 2014-01-19 0.5.2 - * Some minor bug fixes. - * API to access file permissions subfield of the external - attributes. - * MS VS 2012 Express support. - * API to set the default codec used to encode/decode file names - (mainly for use by various wrappers such as JlCompress, when - you don't have direct access to the underlying QuaZip instance). - -* 2013-03-02 0.5.1 - * Lots of QuaZipDir fixes, thanks to all bug reporters. - * Full Qt Creator support. - * MS VS 2010 Express support. - * Qt5 support (didn't need any source code changes anyway). - * Lots of minor bug fixes. - -* 2012-09-07 0.5 - * Added run_moc.bat files for building under Windows in case Qt - integration is not available (e. g. VS 2008 Express). - * Added the QuaZipDir class to simplify ZIP navigation in terms - of directories. - * Added the QuaGzipFile class for working with GZIP archives. It - was added as a bonus since it has nothing to do with the main - purpose of the library. It probably won't get any major - improvements, although minor bug fixes are possible. - * Added the QuaZIODevice class for working with zlib - compression. It has nothing to do with the ZIP format, and - therefore the same notice as for the QuaGzipFile applies. - * The global comment is no longer erased when adding files to - an archive. - * Many bug fixes. - -* 2012-01-14 0.4.4 - * Fixed isSequential() test that was causing open() failures on - Unix. - * Fixed sub-directory compressing in JlCompress. - * Added MS VS 2008 solution, compatible with the binary Qt - distribution (tested on MS VS 2008 Express, had to run MOC - manually due to the lack of plugin in Express). - * Fixed extracting directories in JlCompress. - * Fixed JlCompress.h includes in the test suite, which used - lowercase names thus breaking on case-sensitive systems. - * Implemented missing QuaZipFile::getZip() that was only - declared. - * Fixed reopening closed files. - * Fixed possible memory leak in case of open error. - -* 2011-09-09 0.4.3 - * New test suite using QTestLib. - * Fixed bytesAvailable(), pos() and atEnd(). - * Added ZIP v1.0 support and disabling data descriptor for - compatibility with some older software. - * Fixed DLL export/import issues for some symbols. - * Added QUAZIP_STATIC macro for compiling as a static library or - directly including the source. - * Added getFileNameList() and getFileInfoList() convenience - functions. - * Added some buffering to JlCompress to improve performance. - -* 2011-08-10 0.4.2 - * Cmake patch (thanks to Bernhard Rosenkraenzer). - * Symbian patch (thanks to Hamish Willee). - * Documented the multiple files limitation of QuaZipFile. - * Fixed relative paths handling in JlCompress. - * Fixed linking to MinGW zlib. - -* 2011-05-26 0.4.1 - * License statement updated to avoid confusion. GPL license - removed for the very same reason. - * Parts of original package are now clearly marked as modified, - just as their license requires. - -* 2011-05-23 0.4 - * QuaZip and QuaZipFile classes now use the Pimpl idiom. This - means that future releases will probably be binary compatible - with this one, but it also means that this one is binary - incompatible with the old ones. - * IO API has been rewritten using QIODevice instead of standard - C library. Among other things it means that QuaZip now supports - files up to 4 GB in size instead of 2 GB. - * Added QuaZip methods allowing access to ZIP files represented - by any seekable QIODevice implementation (QBuffer is a good - example). - -* 2010-07-23 0.3 - * Fixed getComment() for global comments. - * Added some useful classes for calculating checksums (thanks to - Adam Walczak). - * Added some utility classes for working with whole directories - (thanks to Roberto Pompermaier). It would be nice if someone - documents these in English, though. - * Probably fixed some problems with passwords (thanks to Vasiliy - Sorokin). I didn't test it, though. - -* 2008-09-17 0.2.3 - * Fixed license notices in sources. - -* SVN - * Fixed a small bug in QuaZipFile::atEnd(). - -* 2007-01-16 0.2.2 - * Added LGPL as alternative license. - * Added FAQ documentation page. - -* 2006-03-21 0.2.1 - * Fixed setCommentCodec() bug. - * Fixed bug that set month 1-12 instead of 0-11, as specified in - zip.h. - * Added workaround for Qt's bug that caused wrong timestamps. - * Few documentation fixes and cosmetic changes. - -* 2005-07-08 0.2 - * Write support. - * Extended QuaZipFile API, including size(), *pos() functions. - * Support for comments encoding/decoding. - -* 2005-07-01 0.1 - * Initial version. diff --git a/src/3rdParty/quazip-0.7.3/README.txt b/src/3rdParty/quazip-0.7.3/README.txt deleted file mode 100644 index 2d8da5375..000000000 --- a/src/3rdParty/quazip-0.7.3/README.txt +++ /dev/null @@ -1,70 +0,0 @@ -QuaZIP is the C++ wrapper for Gilles Vollant's ZIP/UNZIP package -(AKA minizip) using Trolltech's Qt library. - -It uses existing ZIP/UNZIP package C code and therefore depends on -the zlib library. - -Also, it depends on Qt 4. - -To compile it on UNIX dialect: - -$ cd quazip -$ qmake -$ make - -You must make sure that: -* You have Qt 4 properly and fully installed (including tools and - headers, not just library) -* "qmake" command runs Qt 4's qmake, not some other version (you'll have - to type full path to qmake otherwise). - -To install compiled shared library, just type: - -$ make install - -By default, it installs in /usr/local, but you may change it using - -$ qmake PREFIX=/wherever/you/want/to/install - -You do not have to compile and install QuaZIP to use it. You can just -(and sometimes it may be the best way) add QuaZIP's source files to your -project and use them. - -See doc/html or, if you do not have a browser, quazip/*.h and -quazip/doc/* files for the more detailed documentation. - -For Windows, it's essentially the same, but you may have to adjust -settings for different environments. - -If linking statically (either a static lib or just using the source code -directly in your project), then QUAZIP_STATIC should be defined. This is -done automatically when you build QuaZIP as a static library. However, -when _using_ a static lib (or source code, for that matter) you must -also define QUAZIP_STATIC in your project (that uses QuaZIP) to tell -quazip_global.h that you use a static version because otherwise the -compiler wouldn't know that and will mark QuaZIP symbols as dllimported. -Linking problems among the lines of “undefined reference” are usually -caused by this. - -Copyright notice: - -Copyright (C) 2005-2012 Sergey A. Tachenov - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 2 of the License, or (at -your option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this program; if not, write to the Free Software Foundation, -Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant, see -quazip/(un)zip.h files for details, basically it's zlib license. diff --git a/src/3rdParty/quazip-0.7.3/includes.pri b/src/3rdParty/quazip-0.7.3/includes.pri deleted file mode 100644 index 8362f9758..000000000 --- a/src/3rdParty/quazip-0.7.3/includes.pri +++ /dev/null @@ -1,10 +0,0 @@ -OBJECTS_DIR = .obj -MOC_DIR = .moc - -unix { - isEmpty(PREFIX): PREFIX=/usr/local -} - -win32 { - isEmpty(PREFIX): warning("PREFIX unspecified, make install won't work") -} diff --git a/src/3rdParty/quazip-0.7.3/quazip.pri b/src/3rdParty/quazip-0.7.3/quazip.pri deleted file mode 100644 index 07cd9c043..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip.pri +++ /dev/null @@ -1,3 +0,0 @@ -INCLUDEPATH+=$$PWD -DEPENDPATH+=$$PWD/quazip -include($$PWD/quazip/quazip.pri) diff --git a/src/3rdParty/quazip-0.7.3/quazip.pro b/src/3rdParty/quazip-0.7.3/quazip.pro deleted file mode 100644 index 86d458754..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip.pro +++ /dev/null @@ -1,3 +0,0 @@ -TEMPLATE=subdirs -SUBDIRS=quazip qztest -qztest.depends = quazip diff --git a/src/3rdParty/quazip-0.7.3/quazip.sln b/src/3rdParty/quazip-0.7.3/quazip.sln deleted file mode 100644 index 2fe98ff63..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip.sln +++ /dev/null @@ -1,37 +0,0 @@ - -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}") = "quazip", "quazip\quazip.vcxproj", "{E4AC5F56-B711-4F0E-BC83-CDE8B6CD53AD}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qztest", "qztest\qztest.vcxproj", "{7632B767-D089-4F15-8B1E-C4B3F9EBF592}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E4AC5F56-B711-4F0E-BC83-CDE8B6CD53AD}.Debug|Win32.ActiveCfg = Debug|Win32 - {E4AC5F56-B711-4F0E-BC83-CDE8B6CD53AD}.Debug|Win32.Build.0 = Debug|Win32 - {E4AC5F56-B711-4F0E-BC83-CDE8B6CD53AD}.Debug|x64.ActiveCfg = Debug|x64 - {E4AC5F56-B711-4F0E-BC83-CDE8B6CD53AD}.Debug|x64.Build.0 = Debug|x64 - {E4AC5F56-B711-4F0E-BC83-CDE8B6CD53AD}.Release|Win32.ActiveCfg = Release|Win32 - {E4AC5F56-B711-4F0E-BC83-CDE8B6CD53AD}.Release|Win32.Build.0 = Release|Win32 - {E4AC5F56-B711-4F0E-BC83-CDE8B6CD53AD}.Release|x64.ActiveCfg = Release|x64 - {E4AC5F56-B711-4F0E-BC83-CDE8B6CD53AD}.Release|x64.Build.0 = Release|x64 - {7632B767-D089-4F15-8B1E-C4B3F9EBF592}.Debug|Win32.ActiveCfg = Debug|Win32 - {7632B767-D089-4F15-8B1E-C4B3F9EBF592}.Debug|Win32.Build.0 = Debug|Win32 - {7632B767-D089-4F15-8B1E-C4B3F9EBF592}.Debug|x64.ActiveCfg = Debug|Win32 - {7632B767-D089-4F15-8B1E-C4B3F9EBF592}.Release|Win32.ActiveCfg = Release|Win32 - {7632B767-D089-4F15-8B1E-C4B3F9EBF592}.Release|Win32.Build.0 = Release|Win32 - {7632B767-D089-4F15-8B1E-C4B3F9EBF592}.Release|x64.ActiveCfg = Release|x64 - {7632B767-D089-4F15-8B1E-C4B3F9EBF592}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/src/3rdParty/quazip-0.7.3/quazip/CMakeLists.txt b/src/3rdParty/quazip-0.7.3/quazip/CMakeLists.txt deleted file mode 100644 index b6b8ab6e2..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -# set all include directories for in and out of source builds -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR} - ${ZLIB_INCLUDE_DIRS} -) - -file(GLOB SRCS "*.c" "*.cpp") -file(GLOB PUBLIC_HEADERS "*.h") - -# Must be added to enable export macro -ADD_DEFINITIONS(-DQUAZIP_BUILD) - -qt_wrap_cpp(MOC_SRCS ${PUBLIC_HEADERS}) -set(SRCS ${SRCS} ${MOC_SRCS}) - -add_library(${QUAZIP_LIB_TARGET_NAME} SHARED ${SRCS}) -add_library(quazip_static STATIC ${SRCS}) - -# Windows uses .lib extension for both static and shared library -# *nix systems use different extensions for SHARED and STATIC library and by convention both libraries have the same name -if (NOT WIN32) - set_target_properties(quazip_static PROPERTIES OUTPUT_NAME quazip${QUAZIP_LIB_VERSION_SUFFIX}) -endif () - -set_target_properties(${QUAZIP_LIB_TARGET_NAME} quazip_static PROPERTIES VERSION 1.0.0 SOVERSION 1 DEBUG_POSTFIX d) -# Link against ZLIB_LIBRARIES if needed (on Windows this variable is empty) -target_link_libraries(${QUAZIP_LIB_TARGET_NAME} quazip_static ${QT_QTMAIN_LIBRARY} ${QTCORE_LIBRARIES} ${ZLIB_LIBRARIES}) - -install(FILES ${PUBLIC_HEADERS} DESTINATION include/quazip${QUAZIP_LIB_VERSION_SUFFIX}) -install(TARGETS ${QUAZIP_LIB_TARGET_NAME} quazip_static LIBRARY DESTINATION ${LIB_DESTINATION} ARCHIVE DESTINATION ${LIB_DESTINATION} RUNTIME DESTINATION ${LIB_DESTINATION}) diff --git a/src/3rdParty/quazip-0.7.3/quazip/JlCompress.cpp b/src/3rdParty/quazip-0.7.3/quazip/JlCompress.cpp deleted file mode 100644 index a62af808e..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/JlCompress.cpp +++ /dev/null @@ -1,443 +0,0 @@ -/* -Copyright (C) 2010 Roberto Pompermaier -Copyright (C) 2005-2014 Sergey A. Tachenov - -This file is part of QuaZIP. - -QuaZIP is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 of the License, or -(at your option) any later version. - -QuaZIP is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with QuaZIP. If not, see . - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant and contributors, -see quazip/(un)zip.h files for details. Basically it's the zlib license. -*/ - -#include "JlCompress.h" -#include - -static bool copyData(QIODevice &inFile, QIODevice &outFile) -{ - while (!inFile.atEnd()) { - char buf[4096]; - qint64 readLen = inFile.read(buf, 4096); - if (readLen <= 0) - return false; - if (outFile.write(buf, readLen) != readLen) - return false; - } - return true; -} - -bool JlCompress::compressFile(QuaZip* zip, QString fileName, QString fileDest) { - // zip: oggetto dove aggiungere il file - // fileName: nome del file reale - // fileDest: nome del file all'interno del file compresso - - // Controllo l'apertura dello zip - if (!zip) return false; - if (zip->getMode()!=QuaZip::mdCreate && - zip->getMode()!=QuaZip::mdAppend && - zip->getMode()!=QuaZip::mdAdd) return false; - - // Apro il file originale - QFile inFile; - inFile.setFileName(fileName); - if(!inFile.open(QIODevice::ReadOnly)) return false; - - // Apro il file risulato - QuaZipFile outFile(zip); - if(!outFile.open(QIODevice::WriteOnly, QuaZipNewInfo(fileDest, inFile.fileName()))) return false; - - // Copio i dati - if (!copyData(inFile, outFile) || outFile.getZipError()!=UNZ_OK) { - return false; - } - - // Chiudo i file - outFile.close(); - if (outFile.getZipError()!=UNZ_OK) return false; - inFile.close(); - - return true; -} - -bool JlCompress::compressSubDir(QuaZip* zip, QString dir, QString origDir, bool recursive, QDir::Filters filters) { - // zip: oggetto dove aggiungere il file - // dir: cartella reale corrente - // origDir: cartella reale originale - // (path(dir)-path(origDir)) = path interno all'oggetto zip - - // Controllo l'apertura dello zip - if (!zip) return false; - if (zip->getMode()!=QuaZip::mdCreate && - zip->getMode()!=QuaZip::mdAppend && - zip->getMode()!=QuaZip::mdAdd) return false; - - // Controllo la cartella - QDir directory(dir); - if (!directory.exists()) return false; - - QDir origDirectory(origDir); - if (dir != origDir) { - QuaZipFile dirZipFile(zip); - if (!dirZipFile.open(QIODevice::WriteOnly, - QuaZipNewInfo(origDirectory.relativeFilePath(dir) + "/", dir), 0, 0, 0)) { - return false; - } - dirZipFile.close(); - } - - - // Se comprimo anche le sotto cartelle - if (recursive) { - // Per ogni sotto cartella - QFileInfoList files = directory.entryInfoList(QDir::AllDirs|QDir::NoDotAndDotDot|filters); - Q_FOREACH (QFileInfo file, files) { - // Comprimo la sotto cartella - if(!compressSubDir(zip,file.absoluteFilePath(),origDir,recursive,filters)) return false; - } - } - - // Per ogni file nella cartella - QFileInfoList files = directory.entryInfoList(QDir::Files|filters); - Q_FOREACH (QFileInfo file, files) { - // Se non e un file o e il file compresso che sto creando - if(!file.isFile()||file.absoluteFilePath()==zip->getZipName()) continue; - - // Creo il nome relativo da usare all'interno del file compresso - QString filename = origDirectory.relativeFilePath(file.absoluteFilePath()); - - // Comprimo il file - if (!compressFile(zip,file.absoluteFilePath(),filename)) return false; - } - - return true; -} - -bool JlCompress::extractFile(QuaZip* zip, QString fileName, QString fileDest) { - // zip: oggetto dove aggiungere il file - // filename: nome del file reale - // fileincompress: nome del file all'interno del file compresso - - // Controllo l'apertura dello zip - if (!zip) return false; - if (zip->getMode()!=QuaZip::mdUnzip) return false; - - // Apro il file compresso - if (!fileName.isEmpty()) - zip->setCurrentFile(fileName); - QuaZipFile inFile(zip); - if(!inFile.open(QIODevice::ReadOnly) || inFile.getZipError()!=UNZ_OK) return false; - - // Controllo esistenza cartella file risultato - QDir curDir; - if (fileDest.endsWith('/')) { - if (!curDir.mkpath(fileDest)) { - return false; - } - } else { - if (!curDir.mkpath(QFileInfo(fileDest).absolutePath())) { - return false; - } - } - - QuaZipFileInfo64 info; - if (!zip->getCurrentFileInfo(&info)) - return false; - - QFile::Permissions srcPerm = info.getPermissions(); - if (fileDest.endsWith('/') && QFileInfo(fileDest).isDir()) { - if (srcPerm != 0) { - QFile(fileDest).setPermissions(srcPerm); - } - return true; - } - - // Apro il file risultato - QFile outFile; - outFile.setFileName(fileDest); - if(!outFile.open(QIODevice::WriteOnly)) return false; - - // Copio i dati - if (!copyData(inFile, outFile) || inFile.getZipError()!=UNZ_OK) { - outFile.close(); - removeFile(QStringList(fileDest)); - return false; - } - outFile.close(); - - // Chiudo i file - inFile.close(); - if (inFile.getZipError()!=UNZ_OK) { - removeFile(QStringList(fileDest)); - return false; - } - - if (srcPerm != 0) { - outFile.setPermissions(srcPerm); - } - return true; -} - -bool JlCompress::removeFile(QStringList listFile) { - bool ret = true; - // Per ogni file - for (int i=0; iopen(QuaZip::mdUnzip)) { - delete zip; - return QStringList(); - } - - // Estraggo i nomi dei file - QStringList lst; - QuaZipFileInfo64 info; - for(bool more=zip->goToFirstFile(); more; more=zip->goToNextFile()) { - if(!zip->getCurrentFileInfo(&info)) { - delete zip; - return QStringList(); - } - lst << info.name; - //info.name.toLocal8Bit().constData() - } - - // Chiudo il file zip - zip->close(); - if(zip->getZipError()!=0) { - delete zip; - return QStringList(); - } - delete zip; - return lst; -} - -QStringList JlCompress::extractDir(QIODevice *ioDevice, QString dir) -{ - QuaZip zip(ioDevice); - return extractDir(zip, dir); -} - -QStringList JlCompress::getFileList(QIODevice *ioDevice) -{ - QuaZip *zip = new QuaZip(ioDevice); - return getFileList(zip); -} - -QString JlCompress::extractFile(QIODevice *ioDevice, QString fileName, QString fileDest) -{ - QuaZip zip(ioDevice); - return extractFile(zip, fileName, fileDest); -} - -QStringList JlCompress::extractFiles(QIODevice *ioDevice, QStringList files, QString dir) -{ - QuaZip zip(ioDevice); - return extractFiles(zip, files, dir); -} diff --git a/src/3rdParty/quazip-0.7.3/quazip/JlCompress.h b/src/3rdParty/quazip-0.7.3/quazip/JlCompress.h deleted file mode 100644 index 49c50865b..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/JlCompress.h +++ /dev/null @@ -1,197 +0,0 @@ -#ifndef JLCOMPRESSFOLDER_H_ -#define JLCOMPRESSFOLDER_H_ - -/* -Copyright (C) 2010 Roberto Pompermaier -Copyright (C) 2005-2016 Sergey A. Tachenov - -This file is part of QuaZIP. - -QuaZIP is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 of the License, or -(at your option) any later version. - -QuaZIP is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with QuaZIP. If not, see . - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant and contributors, -see quazip/(un)zip.h files for details. Basically it's the zlib license. -*/ - -#include "quazip.h" -#include "quazipfile.h" -#include "quazipfileinfo.h" -#include -#include -#include -#include - -/// Utility class for typical operations. -/** - This class contains a number of useful static functions to perform - simple operations, such as mass ZIP packing or extraction. - */ -class QUAZIP_EXPORT JlCompress { -private: - static QStringList extractDir(QuaZip &zip, const QString &dir); - static QStringList getFileList(QuaZip *zip); - static QString extractFile(QuaZip &zip, QString fileName, QString fileDest); - static QStringList extractFiles(QuaZip &zip, const QStringList &files, const QString &dir); - /// Compress a single file. - /** - \param zip Opened zip to compress the file to. - \param fileName The full path to the source file. - \param fileDest The full name of the file inside the archive. - \return true if success, false otherwise. - */ - static bool compressFile(QuaZip* zip, QString fileName, QString fileDest); - /// Compress a subdirectory. - /** - \param parentZip Opened zip containing the parent directory. - \param dir The full path to the directory to pack. - \param parentDir The full path to the directory corresponding to - the root of the ZIP. - \param recursive Whether to pack sub-directories as well or only - files. - \return true if success, false otherwise. - */ - static bool compressSubDir(QuaZip* parentZip, QString dir, QString parentDir, bool recursive, - QDir::Filters filters); - /// Extract a single file. - /** - \param zip The opened zip archive to extract from. - \param fileName The full name of the file to extract. - \param fileDest The full path to the destination file. - \return true if success, false otherwise. - */ - static bool extractFile(QuaZip* zip, QString fileName, QString fileDest); - /// Remove some files. - /** - \param listFile The list of files to remove. - \return true if success, false otherwise. - */ - static bool removeFile(QStringList listFile); - -public: - /// Compress a single file. - /** - \param fileCompressed The name of the archive. - \param file The file to compress. - \return true if success, false otherwise. - */ - static bool compressFile(QString fileCompressed, QString file); - /// Compress a list of files. - /** - \param fileCompressed The name of the archive. - \param files The file list to compress. - \return true if success, false otherwise. - */ - static bool compressFiles(QString fileCompressed, QStringList files); - /// Compress a whole directory. - /** - Does not compress hidden files. See compressDir(QString, QString, bool, QDir::Filters). - - \param fileCompressed The name of the archive. - \param dir The directory to compress. - \param recursive Whether to pack the subdirectories as well, or - just regular files. - \return true if success, false otherwise. - */ - static bool compressDir(QString fileCompressed, QString dir = QString(), bool recursive = true); - /** - * @brief Compress a whole directory. - * - * Unless filters are specified explicitly, packs - * only regular non-hidden files (and subdirs, if @c recursive is true). - * If filters are specified, they are OR-combined with - * %QDir::AllDirs|%QDir::NoDotAndDotDot when searching for dirs - * and with QDir::Files when searching for files. - * - * @param fileCompressed path to the resulting archive - * @param dir path to the directory being compressed - * @param recursive if true, then the subdirectories are packed as well - * @param filters what to pack, filters are applied both when searching - * for subdirs (if packing recursively) and when looking for files to pack - * @return true on success, false otherwise - */ - static bool compressDir(QString fileCompressed, QString dir, - bool recursive, QDir::Filters filters); - -public: - /// Extract a single file. - /** - \param fileCompressed The name of the archive. - \param fileName The file to extract. - \param fileDest The destination file, assumed to be identical to - \a file if left empty. - \return The list of the full paths of the files extracted, empty on failure. - */ - static QString extractFile(QString fileCompressed, QString fileName, QString fileDest = QString()); - /// Extract a list of files. - /** - \param fileCompressed The name of the archive. - \param files The file list to extract. - \param dir The directory to put the files to, the current - directory if left empty. - \return The list of the full paths of the files extracted, empty on failure. - */ - static QStringList extractFiles(QString fileCompressed, QStringList files, QString dir = QString()); - /// Extract a whole archive. - /** - \param fileCompressed The name of the archive. - \param dir The directory to extract to, the current directory if - left empty. - \return The list of the full paths of the files extracted, empty on failure. - */ - static QStringList extractDir(QString fileCompressed, QString dir = QString()); - /// Get the file list. - /** - \return The list of the files in the archive, or, more precisely, the - list of the entries, including both files and directories if they - are present separately. - */ - static QStringList getFileList(QString fileCompressed); - /// Extract a single file. - /** - \param ioDevice pointer to device with compressed data. - \param fileName The file to extract. - \param fileDest The destination file, assumed to be identical to - \a file if left empty. - \return The list of the full paths of the files extracted, empty on failure. - */ - static QString extractFile(QIODevice *ioDevice, QString fileName, QString fileDest = QString()); - /// Extract a list of files. - /** - \param ioDevice pointer to device with compressed data. - \param files The file list to extract. - \param dir The directory to put the files to, the current - directory if left empty. - \return The list of the full paths of the files extracted, empty on failure. - */ - static QStringList extractFiles(QIODevice *ioDevice, QStringList files, QString dir = QString()); - /// Extract a whole archive. - /** - \param ioDevice pointer to device with compressed data. - \param dir The directory to extract to, the current directory if - left empty. - \return The list of the full paths of the files extracted, empty on failure. - */ - static QStringList extractDir(QIODevice *ioDevice, QString dir = QString()); - /// Get the file list. - /** - \return The list of the files in the archive, or, more precisely, the - list of the entries, including both files and directories if they - are present separately. - */ - static QStringList getFileList(QIODevice *ioDevice); -}; - -#endif /* JLCOMPRESSFOLDER_H_ */ diff --git a/src/3rdParty/quazip-0.7.3/quazip/debian/libquazip0.symbols b/src/3rdParty/quazip-0.7.3/quazip/debian/libquazip0.symbols deleted file mode 100644 index ed3c09b6f..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/debian/libquazip0.symbols +++ /dev/null @@ -1,163 +0,0 @@ -libquazip.so.0 libquazip0 #MINVER# - _Z24qiodevice_open_file_funcPvS_i@Base 0.4.4 - _Z24qiodevice_read_file_funcPvS_S_m@Base 0.4.4 - _Z24qiodevice_seek_file_funcPvS_mi@Base 0.4.4 - _Z24qiodevice_tell_file_funcPvS_@Base 0.4.4 - _Z25qiodevice_close_file_funcPvS_@Base 0.4.4 - _Z25qiodevice_error_file_funcPvS_@Base 0.4.4 - _Z25qiodevice_write_file_funcPvS_PKvm@Base 0.4.4 - _ZN10JlCompress10extractDirE7QStringS0_@Base 0.4.4 - _ZN10JlCompress11compressDirE7QStringS0_b@Base 0.4.4 - _ZN10JlCompress11extractFileE7QStringS0_S0_@Base 0.4.4 - _ZN10JlCompress11getFileListE7QString@Base 0.4.4 - _ZN10JlCompress12compressFileE7QStringS0_@Base 0.4.4 - _ZN10JlCompress12extractFilesE7QString11QStringListS0_@Base 0.4.4 - _ZN10JlCompress13compressFilesE7QString11QStringList@Base 0.4.4 - _ZN10QuaAdler325resetEv@Base 0.4.4 - _ZN10QuaAdler325valueEv@Base 0.4.4 - _ZN10QuaAdler326updateERK10QByteArray@Base 0.4.4 - _ZN10QuaAdler329calculateERK10QByteArray@Base 0.4.4 - _ZN10QuaAdler32C1Ev@Base 0.4.4 - _ZN10QuaAdler32C2Ev@Base 0.4.4 - _ZN10QuaZipFile10setZipNameERK7QString@Base 0.4.4 - _ZN10QuaZipFile11getFileInfoEP14QuaZipFileInfo@Base 0.4.4 - _ZN10QuaZipFile11setFileNameERK7QStringN6QuaZip15CaseSensitivityE@Base 0.4.4 - _ZN10QuaZipFile4openE6QFlagsIN9QIODevice12OpenModeFlagEE@Base 0.4.4 - _ZN10QuaZipFile4openE6QFlagsIN9QIODevice12OpenModeFlagEEPiS4_bPKc@Base 0.4.4 - _ZN10QuaZipFile4openE6QFlagsIN9QIODevice12OpenModeFlagEERK13QuaZipNewInfoPKcjiibiii@Base 0.4.4 - _ZN10QuaZipFile5closeEv@Base 0.4.4 - _ZN10QuaZipFile6setZipEP6QuaZip@Base 0.4.4 - _ZN10QuaZipFile8readDataEPcx@Base 0.4.4 - _ZN10QuaZipFile9writeDataEPKcx@Base 0.4.4 - _ZN10QuaZipFileC1EP6QuaZipP7QObject@Base 0.4.4 - _ZN10QuaZipFileC1EP7QObject@Base 0.4.4 - _ZN10QuaZipFileC1ERK7QStringP7QObject@Base 0.4.4 - _ZN10QuaZipFileC1ERK7QStringS2_N6QuaZip15CaseSensitivityEP7QObject@Base 0.4.4 - _ZN10QuaZipFileC1Ev@Base 0.4.4 - _ZN10QuaZipFileC2EP6QuaZipP7QObject@Base 0.4.4 - _ZN10QuaZipFileC2EP7QObject@Base 0.4.4 - _ZN10QuaZipFileC2ERK7QStringP7QObject@Base 0.4.4 - _ZN10QuaZipFileC2ERK7QStringS2_N6QuaZip15CaseSensitivityEP7QObject@Base 0.4.4 - _ZN10QuaZipFileC2Ev@Base 0.4.4 - _ZN10QuaZipFileD0Ev@Base 0.4.4 - _ZN10QuaZipFileD1Ev@Base 0.4.4 - _ZN10QuaZipFileD2Ev@Base 0.4.4 - _ZN13QuaZipNewInfo15setFileDateTimeERK7QString@Base 0.4.4 - _ZN13QuaZipNewInfoC1ERK7QString@Base 0.4.4 - _ZN13QuaZipNewInfoC1ERK7QStringS2_@Base 0.4.4 - _ZN13QuaZipNewInfoC2ERK7QString@Base 0.4.4 - _ZN13QuaZipNewInfoC2ERK7QStringS2_@Base 0.4.4 - _ZN13QuaZipNewInfoD1Ev@Base 0.4.4 - _ZN13QuaZipNewInfoD2Ev@Base 0.4.4 - _ZN14QuaZipFileInfoD1Ev@Base 0.4.4 - _ZN14QuaZipFileInfoD2Ev@Base 0.4.4 - _ZN6QuaZip10getUnzFileEv@Base 0.4.4 - _ZN6QuaZip10getZipFileEv@Base 0.4.4 - _ZN6QuaZip10setCommentERK7QString@Base 0.4.4 - _ZN6QuaZip10setZipNameERK7QString@Base 0.4.4 - _ZN6QuaZip11setIoDeviceEP9QIODevice@Base 0.4.4 - _ZN6QuaZip12goToNextFileEv@Base 0.4.4 - _ZN6QuaZip13goToFirstFileEv@Base 0.4.4 - _ZN6QuaZip14setCurrentFileERK7QStringNS_15CaseSensitivityE@Base 0.4.4 - _ZN6QuaZip15setCommentCodecEP10QTextCodec@Base 0.4.4 - _ZN6QuaZip15setCommentCodecEPKc@Base 0.4.4 - _ZN6QuaZip16setFileNameCodecEP10QTextCodec@Base 0.4.4 - _ZN6QuaZip16setFileNameCodecEPKc@Base 0.4.4 - _ZN6QuaZip31setDataDescriptorWritingEnabledEb@Base 0.4.4 - _ZN6QuaZip4openENS_4ModeEP19zlib_filefunc_def_s@Base 0.4.4 - _ZN6QuaZip5closeEv@Base 0.4.4 - _ZN6QuaZipC1EP9QIODevice@Base 0.4.4 - _ZN6QuaZipC1ERK7QString@Base 0.4.4 - _ZN6QuaZipC1Ev@Base 0.4.4 - _ZN6QuaZipC2EP9QIODevice@Base 0.4.4 - _ZN6QuaZipC2ERK7QString@Base 0.4.4 - _ZN6QuaZipC2Ev@Base 0.4.4 - _ZN6QuaZipD1Ev@Base 0.4.4 - _ZN6QuaZipD2Ev@Base 0.4.4 - _ZN7QStringD1Ev@Base 0.4.4 - _ZN7QStringD2Ev@Base 0.4.4 - _ZN8QuaCrc325resetEv@Base 0.4.4 - _ZN8QuaCrc325valueEv@Base 0.4.4 - _ZN8QuaCrc326updateERK10QByteArray@Base 0.4.4 - _ZN8QuaCrc329calculateERK10QByteArray@Base 0.4.4 - _ZN8QuaCrc32C1Ev@Base 0.4.4 - _ZN8QuaCrc32C2Ev@Base 0.4.4 - _ZNK10QuaZipFile10getZipNameEv@Base 0.4.4 - _ZNK10QuaZipFile10metaObjectEv@Base 0.4.4 - _ZNK10QuaZipFile11getFileNameEv@Base 0.4.4 - _ZNK10QuaZipFile11getZipErrorEv@Base 0.4.4 - _ZNK10QuaZipFile12isSequentialEv@Base 0.4.4 - _ZNK10QuaZipFile14bytesAvailableEv@Base 0.4.4 - _ZNK10QuaZipFile17getActualFileNameEv@Base 0.4.4 - _ZNK10QuaZipFile18getCaseSensitivityEv@Base 0.4.4 - _ZNK10QuaZipFile3posEv@Base 0.4.4 - _ZNK10QuaZipFile4sizeEv@Base 0.4.4 - _ZNK10QuaZipFile5atEndEv@Base 0.4.4 - _ZNK10QuaZipFile5csizeEv@Base 0.4.4 - _ZNK10QuaZipFile5isRawEv@Base 0.4.4 - _ZNK10QuaZipFile5usizeEv@Base 0.4.4 - _ZNK10QuaZipFile6getZipEv@Base 0.4.4 - _ZNK6QuaZip10getCommentEv@Base 0.4.4 - _ZNK6QuaZip10getZipNameEv@Base 0.4.4 - _ZNK6QuaZip11getIoDeviceEv@Base 0.4.4 - _ZNK6QuaZip11getZipErrorEv@Base 0.4.4 - _ZNK6QuaZip14hasCurrentFileEv@Base 0.4.4 - _ZNK6QuaZip15getCommentCodecEv@Base 0.4.4 - _ZNK6QuaZip15getEntriesCountEv@Base 0.4.4 - _ZNK6QuaZip15getFileInfoListEv@Base 0.4.4 - _ZNK6QuaZip15getFileNameListEv@Base 0.4.4 - _ZNK6QuaZip16getFileNameCodecEv@Base 0.4.4 - _ZNK6QuaZip18getCurrentFileInfoEP14QuaZipFileInfo@Base 0.4.4 - _ZNK6QuaZip18getCurrentFileNameEv@Base 0.4.4 - _ZNK6QuaZip30isDataDescriptorWritingEnabledEv@Base 0.4.4 - _ZNK6QuaZip6isOpenEv@Base 0.4.4 - _ZNK6QuaZip7getModeEv@Base 0.4.4 - _ZTI10QuaAdler32@Base 0.4.4 - _ZTI10QuaZipFile@Base 0.4.4 - _ZTI13QuaChecksum32@Base 0.4.4 - _ZTI8QuaCrc32@Base 0.4.4 - _ZTS10QuaAdler32@Base 0.4.4 - _ZTS10QuaZipFile@Base 0.4.4 - _ZTS13QuaChecksum32@Base 0.4.4 - _ZTS8QuaCrc32@Base 0.4.4 - _ZTV10QuaAdler32@Base 0.4.4 - _ZTV10QuaZipFile@Base 0.4.4 - _ZTV13QuaChecksum32@Base 0.4.4 - _ZTV8QuaCrc32@Base 0.4.4 - fill_qiodevice_filefunc@Base 0.4.4 - unzClose@Base 0.4.4 - unzCloseCurrentFile@Base 0.4.4 - unzGetCurrentFileInfo@Base 0.4.4 - unzGetFilePos@Base 0.4.4 - unzGetGlobalComment@Base 0.4.4 - unzGetGlobalInfo@Base 0.4.4 - unzGetLocalExtrafield@Base 0.4.4 - unzGetOffset@Base 0.4.4 - unzGoToFilePos@Base 0.4.4 - unzGoToFirstFile@Base 0.4.4 - unzGoToNextFile@Base 0.4.4 - unzLocateFile@Base 0.4.4 - unzOpen2@Base 0.4.4 - unzOpen@Base 0.4.4 - unzOpenCurrentFile2@Base 0.4.4 - unzOpenCurrentFile3@Base 0.4.4 - unzOpenCurrentFile@Base 0.4.4 - unzOpenCurrentFilePassword@Base 0.4.4 - unzReadCurrentFile@Base 0.4.4 - unzSetOffset@Base 0.4.4 - unzStringFileNameCompare@Base 0.4.4 - unz_copyright@Base 0.4.4 - unzeof@Base 0.4.4 - unztell@Base 0.4.4 - zipClearFlags@Base 0.4.4 - zipClose@Base 0.4.4 - zipCloseFileInZip@Base 0.4.4 - zipCloseFileInZipRaw@Base 0.4.4 - zipOpen2@Base 0.4.4 - zipOpen@Base 0.4.4 - zipOpenNewFileInZip2@Base 0.4.4 - zipOpenNewFileInZip3@Base 0.4.4 - zipOpenNewFileInZip@Base 0.4.4 - zipSetFlags@Base 0.4.4 - zipWriteInFileInZip@Base 0.4.4 - zip_copyright@Base 0.4.4 diff --git a/src/3rdParty/quazip-0.7.3/quazip/doc/faq.dox b/src/3rdParty/quazip-0.7.3/quazip/doc/faq.dox deleted file mode 100644 index 68fc52b85..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/doc/faq.dox +++ /dev/null @@ -1,45 +0,0 @@ -/** - * \page faq QuaZip FAQ - * - * - * - * \anchor faq-non-QIODevice Q. Is there any way to use QuaZipFile in Qt - * where you are supposed to use normal (non-zipped) file, but not - * through QIODevice API? - * - * A. Usually not. For example, if you are passing file name to some - * database driver (like SQLite), Qt usually just passes this name down - * to the 3rd-party library, which is usually does not know anything - * about QIODevice and therefore there is no way to pass QuaZipFile as - * normal file. However, if we are talking about some place where you - * pass file name, and then indirectly use QFile to open it, then it is - * a good idea to make overloaded method, which accepts a QIODevice - * pointer. Then you would be able to pass QuaZipFile as well as many - * other nice things such as QBuffer or QProcess. - * - * \anchor faq-zip64 Q. Can QuaZIP handle files larger than 4GB? What - * about zip64 standard? - * - * A. Starting with version 0.6, QuaZIP uses Minizip 1.1 with zip64 - * support which should handle large files perfectly. The zip64 support - * in Minizip looks like it's not 100% conforming to the standard, but - * 3rd party tools seem to have no problem with the resulting archives. - * - * \anchor faq-seekable Q. Can QuaZIP write archives to a sequential QIODevice like QTcpSocket? - * - * A. Not yet. It is not supported by vanilla Minizip (the back-end - * QuaZIP uses), although theoretically possible according to the ZIP - * standard. It would require some Minizip modifications that would - * allow it to detect non-seekable I/O and produce necessary output - * structures. QuaZIP already writes data descriptor which is necessary - * for non-seekable I/O. The only thing that is apparently left is to - * make Minizip fill local headers with correct values and forget about - * seeking after closing the file. - **/ diff --git a/src/3rdParty/quazip-0.7.3/quazip/doc/index.dox b/src/3rdParty/quazip-0.7.3/quazip/doc/index.dox deleted file mode 100644 index ae45c5cd9..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/doc/index.dox +++ /dev/null @@ -1,177 +0,0 @@ -/** - * \mainpage QuaZIP - Qt/C++ wrapper for ZIP/UNZIP package - * -\htmlonly -Powered by SourceForge.net -\endhtmlonly - * \section overview Overview - * - * QuaZIP is a simple C++ wrapper over Gilles Vollant's ZIP/UNZIP - * package that can be used to access ZIP archives. It uses the Qt toolkit. - * - * If you do not know what Qt is, you have two options: - * - Just forget about QuaZIP. - * - Learn more about Qt by downloading it and/or reading the excellent official Qt documentation - * - * The choice is yours, but if you are really interested in - * cross-platform (Windows/Linux/BSD/UNIX/Mac/Others) software - * development, I would definitely recommend you the latter ^_^ - * - * QuaZIP allows you to access files inside ZIP archives using QIODevice - * API, and - yes! - that means that you can also use QTextStream, - * QDataStream or whatever you would like to use on your zipped files. - * - * QuaZIP provides complete abstraction of the ZIP/UNZIP API, for both - * reading from and writing to ZIP archives. - * - * \section download Download QuaZIP - * - * Downloads are available from QuaZIP project's page - * at SourceForge.net. - * - * \section platforms Platforms supported - * - * QuaZIP has been currently tested on the following platforms: - * - linux-g++ (Ubuntu 11.10, Qt 4.7.4) - * - freebsd-g++ (Qt 4.0.0 - * - hpux-acc (HP-UX 11.11) - * - hpux-g++ (HP-UX 11.11) - * - win32-g++ (MinGW) - * - win32-msvc2010 (MS VS 2010 Express, Qt 4.8.4) - * - win32-msvc2010 (Qt Creator, Qt 5.0.1) - * - win32-msvc2012 (Qt Creator, Qt 5.2.0) - * - some Symbian version, reportedly - * - * No testing has been officially done on other systems. Of course, patches to - * make it work on any platform that it currently does not work on are - * always welcome! - * - * \section whats-new What is new in this version of QuaZIP? - * - * See the NEWS.txt file supplied with the distribution. - * - * \section Requirements - * - * Just zlib and Qt 4/5. Well, Qt 4 - * depends on zlib anyway, but you will need zlib headers to compile - * QuaZIP. With Qt5 sometimes you need the zlib library as well (on - * Windows, for example). - * - * \section building Building, testing and installing - * - * \note Instructions given in this section assume that you are - * using some UNIX dialect, but the build process should be very similar - * on win32-g++ platform too. On other platforms it's essentially the - * same process, maybe with some qmake adjustments not specific to - * QuaZIP itself. - * - * To build the library, run: -\verbatim -$ cd /wherever/quazip/source/is/quazip-x.y.z/quazip -$ qmake [PREFIX=where-to-install] -$ make -\endverbatim - * - * Make sure that you have Qt 4/5 installed with all required headers and - * utilities (that is, including the 'dev' or 'devel' package on Linux) - * and that you run qmake utility of the Qt 4, not some other version - * you may have already installed (you may need to type full path to - * qmake like /usr/local/qt4/bin/qmake). - * - * To reconfigure (with another PREFIX, for example), just run qmake - * with appropriate arguments again. - * - * If you need to specify additional include path or libraries, use - * qmake features (see qmake reference in the Qt documentation). For - * example: - * -\verbatim -$ qmake LIBS+=-L/usr/local/zlib/lib INCLUDEPATH+=/usr/local/zlib/include -\endverbatim - * (note abscence of "-I" before the include path and the presence of "-L" - * before the lib path) - * - * Also note that you may or may not need to define ZLIB_WINAPI (qmake - * DEFINES+=ZLIB_WINAPI) when linking to zlib on Windows, depending on - * how zlib was built (generally, if using zlibwapi.dll, this define is - * needed). - * - * To install compiled library: -\verbatim -$ make install -\endverbatim - * - * By default, QuaZIP compiles as a DLL/SO, but you have other - * options: - * - Just copy appropriate source files to your project and use them, - * but you need to define QUAZIP_STATIC before including any QuaZIP - * headers (best done as a compiler option). This will save you from - * possible side effects of importing/exporting QuaZIP symbols. - * - Compile it as a static library using CONFIG += staticlib qmake - * option. QUAZIP_STATIC is defined automatically by qmake in this case. - * - * Binary compatibility is guaranteed between minor releases starting - * with version 0.5, thanks to the Pimpl idiom. That is, the next binary - * incompatible version will be 1.x. - * - * \section test Testing - * - * To check if QuaZIP's basic features work OK on your platform, you may - * wish to compile the test suite provided in test directory: -\verbatim -$ cd /wherever/quazip/source/is/quazip-x.y.z/qztest -$ qmake -$ make -$ ./qztest -\endverbatim - * - * Note that the test suite looks for the quazip library in the "quazip" - * folder of the project ("../quazip"), but you may wish to use LIBS - * for some systems (Windows often puts the library in the separate - * "debug" or "release" directory). If you wish to use the quazip - * version that's already installed, provide the appropriate path. - * - * On some systems you may need to set PATH, LD_LIBRARY_PATH or - * SHLIB_PATH to get "qztest" to actually run. - * - * If everything went fine, the test suite should report a lot of PASS - * messages. If something goes wrong, it will provide details and a - * warning that some tests failed. - * - * \section using Using - * - * See \ref usage "usage page". - * - * \section contacts Authors and contacts - * - * This wrapper has been written by Sergey A. Tachenov, AKA Alqualos. - * This is my first open source project, so it may suck, but I did not - * find anything like that, so I just had no other choice but to write - * it. - * - * If you have anything to say to me about QuaZIP library, feel free to - * do so (read the \ref faq first, though). I can not promise, - * though, that I fix all the bugs you report in, add any features you - * want, or respond to your critics, or respond to your feedback at all. - * I may be busy, I may be tired of working on QuaZIP, I may be even - * dead already (you never know...). - * - * To report bugs or to post ideas about what should be done, use - * SourceForge.net's trackers. - * If you want to send me a private message, use my e-mail address - * stachenov@gmail.com. - * - * Do not use e-mail to report bugs, please. Reporting bugs and problems - * with the SourceForge.net's bug report system has that advantage that - * it is visible to public, and I can always search for open tickets - * that were created long ago. It is highly unlikely that I will search - * my mail for that kind of stuff, so if a bug reported by mail isn't - * fixed immediately, it will likely be forgotten forever. - * - * Copyright (C) 2005-2014 Sergey A. Tachenov and contributors - **/ diff --git a/src/3rdParty/quazip-0.7.3/quazip/doc/usage.dox b/src/3rdParty/quazip-0.7.3/quazip/doc/usage.dox deleted file mode 100644 index 108f6cbc1..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/doc/usage.dox +++ /dev/null @@ -1,77 +0,0 @@ -/** \page usage Usage - * - * This page provides general information on QuaZIP usage. See classes - * QuaZip and QuaZipFile for the detailed documentation on what can - * QuaZIP do and what it can not. Also, reading comments in the zip.h and - * unzip.h files (taken from the original ZIP/UNZIP package) is always a - * good idea too. After all, QuaZIP is just a wrapper with a few - * convenience extensions and reimplementations. - * - * QuaZip is a class representing ZIP archive, QuaZipFile represents a - * file inside archive and subclasses QIODevice as well. One limitation - * is that there can be only one instance of QuaZipFile per QuaZip - * instance, which kind of makes it confusing why there are two classes - * instead of one. This is actually no more than an API design mistake. - * - * \section terminology Terminology - * - * "QuaZIP" means whole this library, while "QuaZip" (note the - * lower case) is just one class in it. - * - * "ZIP/UNZIP API" or "minizip" means the original API of the Gilles - * Vollant's ZIP/UNZIP package. It was slightly modified to better - * integrate with Qt. These modifications are not source or binary - * compatible with the official minizip release, which means you can't - * just drop the newer minizip version into QuaZIP sources and make it - * work. - * - * "ZIP", "ZIP archive" or "ZIP file" means any ZIP archive. Typically - * this is a plain file with ".zip" (or ".ZIP") file name suffix, but it - * can also be any seekable QIODevice (say, QBuffer, but not - * QTcpSocket). - * - * "A file inside archive", "a file inside ZIP" or something like that - * means file either being read or written from/to some ZIP archive. - * - * \section error-handling Error handling - * - * Almost any call to ZIP/UNZIP API return some error code. Most of the - * original API's error checking could be done in this wrapper as well, - * but it would cause unnecessary code bloating without any benefit. So, - * QuaZIP only checks for situations that ZIP/UNZIP API can not check - * for. For example, ZIP/UNZIP API has no "ZIP open mode" concept - * because read and write modes are completely separated. On the other - * hand, to avoid creating classes like "QuaZipReader", "QuaZipWriter" - * or something like that, QuaZIP introduces "ZIP open mode" concept - * instead, thus making it possible to use one class (QuaZip) for both - * reading and writing. But this leads to additional open mode checks - * which are not done in ZIP/UNZIP package. - * - * Therefore, error checking is two-level (QuaZIP's level and ZIP/UNZIP - * API level), which sometimes can be confusing, so here are some - * advices on how the error checking should be properly done: - * - * - Both QuaZip and QuaZipFile have getZipError() function, which return - * error code of the last ZIP/UNZIP API call. Most function calls - * reset error code to UNZ_OK on success and set error code on - * failure. Some functions do not reset error code. Most of them are - * \c const and do not access ZIP archive in any way. Some, on the - * other hand, \em do access ZIP archive, but do not reset or set - * error code. For example, QuaZipFile::pos() function. Such functions - * are explicitly marked in the documentation. - * - Most functions have their own way to report errors, by returning a - * null string, negative value or \c false. If such a function returns - * error value, call getZipError() to get more information about - * error. See "zip.h" and "unzip.h" of the ZIP/UNZIP package for error - * codes. - * - If the function returns error-stating value (like \c false), but - * getZipError() returns UNZ_OK, it means that you did something - * obviously wrong. For example, tried to write in the archive open - * for reading or not open at all. You better just not do that! - * Most functions also issue a warning using qWarning() function in - * such cases. See documentation for a specific function for details - * on when it should not be called. - * - * I know that this is somewhat messy, but I could not find a better way - * to do all the error handling. - **/ diff --git a/src/3rdParty/quazip-0.7.3/quazip/ioapi.h b/src/3rdParty/quazip-0.7.3/quazip/ioapi.h deleted file mode 100644 index bbb94c8c7..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/ioapi.h +++ /dev/null @@ -1,207 +0,0 @@ -/* 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 ) - - Modified by Sergey A. Tachenov to allow QIODevice API usage. - - 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)) - - // 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 _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 - - -#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 - -#ifndef OF -#define OF _Z_OF -#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, voidpf file, 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 uLong (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); -typedef int (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 int (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); -typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, voidpf file, 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; - close_file_func zfakeclose_file; // for no-auto-close flag -} zlib_filefunc64_def; - -void fill_qiodevice64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); -void fill_qiodevice_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 ZFAKECLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zfakeclose_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,voidpf file,int mode)); -int 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/src/3rdParty/quazip-0.7.3/quazip/qioapi.cpp b/src/3rdParty/quazip-0.7.3/quazip/qioapi.cpp deleted file mode 100644 index 641883b02..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/qioapi.cpp +++ /dev/null @@ -1,363 +0,0 @@ -/* ioapi.c -- IO base function header for compress/uncompress .zip - files using zlib + zip or unzip API - - Version 1.01e, February 12th, 2005 - - Copyright (C) 1998-2005 Gilles Vollant - - Modified by Sergey A. Tachenov to integrate with Qt. -*/ - -#include -#include -#include - -#include "zlib.h" -#include "ioapi.h" -#include "quazip_global.h" -#include -#if (QT_VERSION >= 0x050100) -#define QUAZIP_QSAVEFILE_BUG_WORKAROUND -#endif -#ifdef QUAZIP_QSAVEFILE_BUG_WORKAROUND -#include -#endif - -/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ - -#ifndef SEEK_CUR -#define SEEK_CUR 1 -#endif - -#ifndef SEEK_END -#define SEEK_END 2 -#endif - -#ifndef SEEK_SET -#define SEEK_SET 0 -#endif - -voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,voidpf file,int mode) -{ - if (pfilefunc->zfile_func64.zopen64_file != NULL) - return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,file,mode); - else - { - return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,file,mode); - } -} - -int 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) == ((uLong)-1)) - return (ZPOS64_T)-1; - else - return tell_uLong; - } -} - -/// @cond internal -struct QIODevice_descriptor { - // Position only used for writing to sequential devices. - qint64 pos; - inline QIODevice_descriptor(): - pos(0) - {} -}; -/// @endcond - -voidpf ZCALLBACK qiodevice_open_file_func ( - voidpf opaque, - voidpf file, - int mode) -{ - QIODevice_descriptor *d = reinterpret_cast(opaque); - QIODevice *iodevice = reinterpret_cast(file); - QIODevice::OpenMode desiredMode; - if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) - desiredMode = QIODevice::ReadOnly; - else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) - desiredMode = QIODevice::ReadWrite; - else if (mode & ZLIB_FILEFUNC_MODE_CREATE) - desiredMode = QIODevice::WriteOnly; - if (iodevice->isOpen()) { - if ((iodevice->openMode() & desiredMode) == desiredMode) { - if (desiredMode != QIODevice::WriteOnly - && iodevice->isSequential()) { - // We can use sequential devices only for writing. - delete d; - return NULL; - } else { - if ((desiredMode & QIODevice::WriteOnly) != 0) { - // open for writing, need to seek existing device - if (!iodevice->isSequential()) { - iodevice->seek(0); - } else { - d->pos = iodevice->pos(); - } - } - } - return iodevice; - } else { - delete d; - return NULL; - } - } - iodevice->open(desiredMode); - if (iodevice->isOpen()) { - if (desiredMode != QIODevice::WriteOnly && iodevice->isSequential()) { - // We can use sequential devices only for writing. - iodevice->close(); - delete d; - return NULL; - } else { - return iodevice; - } - } else { - delete d; - return NULL; - } -} - - -uLong ZCALLBACK qiodevice_read_file_func ( - voidpf opaque, - voidpf stream, - void* buf, - uLong size) -{ - QIODevice_descriptor *d = reinterpret_cast(opaque); - QIODevice *iodevice = reinterpret_cast(stream); - qint64 ret64 = iodevice->read((char*)buf,size); - uLong ret; - ret = (uLong) ret64; - if (ret64 != -1) { - d->pos += ret64; - } - return ret; -} - - -uLong ZCALLBACK qiodevice_write_file_func ( - voidpf opaque, - voidpf stream, - const void* buf, - uLong size) -{ - QIODevice_descriptor *d = reinterpret_cast(opaque); - QIODevice *iodevice = reinterpret_cast(stream); - uLong ret; - qint64 ret64 = iodevice->write((char*)buf,size); - if (ret64 != -1) { - d->pos += ret64; - } - ret = (uLong) ret64; - return ret; -} - -uLong ZCALLBACK qiodevice_tell_file_func ( - voidpf opaque, - voidpf stream) -{ - QIODevice_descriptor *d = reinterpret_cast(opaque); - QIODevice *iodevice = reinterpret_cast(stream); - uLong ret; - qint64 ret64; - if (iodevice->isSequential()) { - ret64 = d->pos; - } else { - ret64 = iodevice->pos(); - } - ret = static_cast(ret64); - return ret; -} - -ZPOS64_T ZCALLBACK qiodevice64_tell_file_func ( - voidpf opaque, - voidpf stream) -{ - QIODevice_descriptor *d = reinterpret_cast(opaque); - QIODevice *iodevice = reinterpret_cast(stream); - qint64 ret; - if (iodevice->isSequential()) { - ret = d->pos; - } else { - ret = iodevice->pos(); - } - return static_cast(ret); -} - -int ZCALLBACK qiodevice_seek_file_func ( - voidpf /*opaque UNUSED*/, - voidpf stream, - uLong offset, - int origin) -{ - QIODevice *iodevice = reinterpret_cast(stream); - if (iodevice->isSequential()) { - if (origin == ZLIB_FILEFUNC_SEEK_END - && offset == 0) { - // sequential devices are always at end (needed in mdAppend) - return 0; - } else { - qWarning("qiodevice_seek_file_func() called for sequential device"); - return -1; - } - } - uLong qiodevice_seek_result=0; - int ret; - switch (origin) - { - case ZLIB_FILEFUNC_SEEK_CUR : - qiodevice_seek_result = ((QIODevice*)stream)->pos() + offset; - break; - case ZLIB_FILEFUNC_SEEK_END : - qiodevice_seek_result = ((QIODevice*)stream)->size() - offset; - break; - case ZLIB_FILEFUNC_SEEK_SET : - qiodevice_seek_result = offset; - break; - default: - return -1; - } - ret = !iodevice->seek(qiodevice_seek_result); - return ret; -} - -int ZCALLBACK qiodevice64_seek_file_func ( - voidpf /*opaque UNUSED*/, - voidpf stream, - ZPOS64_T offset, - int origin) -{ - QIODevice *iodevice = reinterpret_cast(stream); - if (iodevice->isSequential()) { - if (origin == ZLIB_FILEFUNC_SEEK_END - && offset == 0) { - // sequential devices are always at end (needed in mdAppend) - return 0; - } else { - qWarning("qiodevice_seek_file_func() called for sequential device"); - return -1; - } - } - qint64 qiodevice_seek_result=0; - int ret; - switch (origin) - { - case ZLIB_FILEFUNC_SEEK_CUR : - qiodevice_seek_result = ((QIODevice*)stream)->pos() + offset; - break; - case ZLIB_FILEFUNC_SEEK_END : - qiodevice_seek_result = ((QIODevice*)stream)->size() - offset; - break; - case ZLIB_FILEFUNC_SEEK_SET : - qiodevice_seek_result = offset; - break; - default: - return -1; - } - ret = !iodevice->seek(qiodevice_seek_result); - return ret; -} - -int ZCALLBACK qiodevice_close_file_func ( - voidpf opaque, - voidpf stream) -{ - QIODevice_descriptor *d = reinterpret_cast(opaque); - delete d; - QIODevice *device = reinterpret_cast(stream); -#ifdef QUAZIP_QSAVEFILE_BUG_WORKAROUND - // QSaveFile terribly breaks the is-a idiom: - // it IS a QIODevice, but it is NOT compatible with it: close() is private - QSaveFile *file = qobject_cast(device); - if (file != NULL) { - // We have to call the ugly commit() instead: - return file->commit() ? 0 : -1; - } -#endif - device->close(); - return 0; -} - -int ZCALLBACK qiodevice_fakeclose_file_func ( - voidpf opaque, - voidpf /*stream*/) -{ - QIODevice_descriptor *d = reinterpret_cast(opaque); - delete d; - return 0; -} - -int ZCALLBACK qiodevice_error_file_func ( - voidpf /*opaque UNUSED*/, - voidpf /*stream UNUSED*/) -{ - // can't check for error due to the QIODevice API limitation - return 0; -} - -void fill_qiodevice_filefunc ( - zlib_filefunc_def* pzlib_filefunc_def) -{ - pzlib_filefunc_def->zopen_file = qiodevice_open_file_func; - pzlib_filefunc_def->zread_file = qiodevice_read_file_func; - pzlib_filefunc_def->zwrite_file = qiodevice_write_file_func; - pzlib_filefunc_def->ztell_file = qiodevice_tell_file_func; - pzlib_filefunc_def->zseek_file = qiodevice_seek_file_func; - pzlib_filefunc_def->zclose_file = qiodevice_close_file_func; - pzlib_filefunc_def->zerror_file = qiodevice_error_file_func; - pzlib_filefunc_def->opaque = new QIODevice_descriptor; -} - -void fill_qiodevice64_filefunc ( - zlib_filefunc64_def* pzlib_filefunc_def) -{ - // Open functions are the same for Qt. - pzlib_filefunc_def->zopen64_file = qiodevice_open_file_func; - pzlib_filefunc_def->zread_file = qiodevice_read_file_func; - pzlib_filefunc_def->zwrite_file = qiodevice_write_file_func; - pzlib_filefunc_def->ztell64_file = qiodevice64_tell_file_func; - pzlib_filefunc_def->zseek64_file = qiodevice64_seek_file_func; - pzlib_filefunc_def->zclose_file = qiodevice_close_file_func; - pzlib_filefunc_def->zerror_file = qiodevice_error_file_func; - pzlib_filefunc_def->opaque = new QIODevice_descriptor; - pzlib_filefunc_def->zfakeclose_file = qiodevice_fakeclose_file_func; -} - -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->zfile_func64.zfakeclose_file = NULL; - p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; - p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; -} diff --git a/src/3rdParty/quazip-0.7.3/quazip/quaadler32.cpp b/src/3rdParty/quazip-0.7.3/quazip/quaadler32.cpp deleted file mode 100644 index 161db1196..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quaadler32.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* -Copyright (C) 2010 Adam Walczak -Copyright (C) 2005-2014 Sergey A. Tachenov - -This file is part of QuaZIP. - -QuaZIP is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 of the License, or -(at your option) any later version. - -QuaZIP is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with QuaZIP. If not, see . - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant and contributors, -see quazip/(un)zip.h files for details. Basically it's the zlib license. -*/ - -#include "quaadler32.h" - -#include "zlib.h" - -QuaAdler32::QuaAdler32() -{ - reset(); -} - -quint32 QuaAdler32::calculate(const QByteArray &data) -{ - return adler32( adler32(0L, Z_NULL, 0), (const Bytef*)data.data(), data.size() ); -} - -void QuaAdler32::reset() -{ - checksum = adler32(0L, Z_NULL, 0); -} - -void QuaAdler32::update(const QByteArray &buf) -{ - checksum = adler32( checksum, (const Bytef*)buf.data(), buf.size() ); -} - -quint32 QuaAdler32::value() -{ - return checksum; -} diff --git a/src/3rdParty/quazip-0.7.3/quazip/quaadler32.h b/src/3rdParty/quazip-0.7.3/quazip/quaadler32.h deleted file mode 100644 index e8847f402..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quaadler32.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef QUAADLER32_H -#define QUAADLER32_H - -/* -Copyright (C) 2010 Adam Walczak -Copyright (C) 2005-2014 Sergey A. Tachenov - -This file is part of QuaZIP. - -QuaZIP is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 of the License, or -(at your option) any later version. - -QuaZIP is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with QuaZIP. If not, see . - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant and contributors, -see quazip/(un)zip.h files for details. Basically it's the zlib license. -*/ - -#include - -#include "quachecksum32.h" - -/// Adler32 checksum -/** \class QuaAdler32 quaadler32.h - * This class wrappers the adler32 function with the QuaChecksum32 interface. - * See QuaChecksum32 for more info. - */ -class QUAZIP_EXPORT QuaAdler32 : public QuaChecksum32 -{ - -public: - QuaAdler32(); - - quint32 calculate(const QByteArray &data); - - void reset(); - void update(const QByteArray &buf); - quint32 value(); - -private: - quint32 checksum; -}; - -#endif //QUAADLER32_H diff --git a/src/3rdParty/quazip-0.7.3/quazip/quachecksum32.h b/src/3rdParty/quazip-0.7.3/quazip/quachecksum32.h deleted file mode 100644 index 40ff451f9..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quachecksum32.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef QUACHECKSUM32_H -#define QUACHECKSUM32_H - -/* -Copyright (C) 2005-2014 Sergey A. Tachenov - -This file is part of QuaZIP. - -QuaZIP is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 of the License, or -(at your option) any later version. - -QuaZIP is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with QuaZIP. If not, see . - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant and contributors, -see quazip/(un)zip.h files for details. Basically it's the zlib license. -*/ - -#include -#include "quazip_global.h" - -/// Checksum interface. -/** \class QuaChecksum32 quachecksum32.h - * This is an interface for 32 bit checksums. - * Classes implementing this interface can calcunate a certin - * checksum in a single step: - * \code - * QChecksum32 *crc32 = new QuaCrc32(); - * rasoult = crc32->calculate(data); - * \endcode - * or by streaming the data: - * \code - * QChecksum32 *crc32 = new QuaCrc32(); - * while(!fileA.atEnd()) - * crc32->update(fileA.read(bufSize)); - * resoultA = crc32->value(); - * crc32->reset(); - * while(!fileB.atEnd()) - * crc32->update(fileB.read(bufSize)); - * resoultB = crc32->value(); - * \endcode - */ -class QUAZIP_EXPORT QuaChecksum32 -{ - -public: - ///Calculates the checksum for data. - /** \a data source data - * \return data checksum - * - * This function has no efect on the value returned by value(). - */ - virtual quint32 calculate(const QByteArray &data) = 0; - - ///Resets the calculation on a checksun for a stream. - virtual void reset() = 0; - - ///Updates the calculated checksum for the stream - /** \a buf next portion of data from the stream - */ - virtual void update(const QByteArray &buf) = 0; - - ///Value of the checksum calculated for the stream passed throw update(). - /** \return checksum - */ - virtual quint32 value() = 0; -}; - -#endif //QUACHECKSUM32_H diff --git a/src/3rdParty/quazip-0.7.3/quazip/quacrc32.cpp b/src/3rdParty/quazip-0.7.3/quazip/quacrc32.cpp deleted file mode 100644 index 2de51173e..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quacrc32.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* -Copyright (C) 2005-2014 Sergey A. Tachenov - -This file is part of QuaZIP. - -QuaZIP is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 of the License, or -(at your option) any later version. - -QuaZIP is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with QuaZIP. If not, see . - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant and contributors, -see quazip/(un)zip.h files for details. Basically it's the zlib license. -*/ - -#include "quacrc32.h" - -#include "zlib.h" - -QuaCrc32::QuaCrc32() -{ - reset(); -} - -quint32 QuaCrc32::calculate(const QByteArray &data) -{ - return crc32( crc32(0L, Z_NULL, 0), (const Bytef*)data.data(), data.size() ); -} - -void QuaCrc32::reset() -{ - checksum = crc32(0L, Z_NULL, 0); -} - -void QuaCrc32::update(const QByteArray &buf) -{ - checksum = crc32( checksum, (const Bytef*)buf.data(), buf.size() ); -} - -quint32 QuaCrc32::value() -{ - return checksum; -} diff --git a/src/3rdParty/quazip-0.7.3/quazip/quacrc32.h b/src/3rdParty/quazip-0.7.3/quazip/quacrc32.h deleted file mode 100644 index af7703b2d..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quacrc32.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef QUACRC32_H -#define QUACRC32_H - -/* -Copyright (C) 2005-2014 Sergey A. Tachenov - -This file is part of QuaZIP. - -QuaZIP is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 of the License, or -(at your option) any later version. - -QuaZIP is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with QuaZIP. If not, see . - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant and contributors, -see quazip/(un)zip.h files for details. Basically it's the zlib license. -*/ - -#include "quachecksum32.h" - -///CRC32 checksum -/** \class QuaCrc32 quacrc32.h -* This class wrappers the crc32 function with the QuaChecksum32 interface. -* See QuaChecksum32 for more info. -*/ -class QUAZIP_EXPORT QuaCrc32 : public QuaChecksum32 { - -public: - QuaCrc32(); - - quint32 calculate(const QByteArray &data); - - void reset(); - void update(const QByteArray &buf); - quint32 value(); - -private: - quint32 checksum; -}; - -#endif //QUACRC32_H diff --git a/src/3rdParty/quazip-0.7.3/quazip/quagzipfile.cpp b/src/3rdParty/quazip-0.7.3/quazip/quagzipfile.cpp deleted file mode 100644 index efc54c177..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quagzipfile.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/* -Copyright (C) 2005-2014 Sergey A. Tachenov - -This file is part of QuaZIP. - -QuaZIP is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 of the License, or -(at your option) any later version. - -QuaZIP is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with QuaZIP. If not, see . - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant and contributors, -see quazip/(un)zip.h files for details. Basically it's the zlib license. -*/ - -#include - -#include "quagzipfile.h" - -/// \cond internal -class QuaGzipFilePrivate { - friend class QuaGzipFile; - QString fileName; - gzFile gzd; - inline QuaGzipFilePrivate(): gzd(NULL) {} - inline QuaGzipFilePrivate(const QString &fileName): - fileName(fileName), gzd(NULL) {} - template bool open(FileId id, - QIODevice::OpenMode mode, QString &error); - gzFile open(int fd, const char *modeString); - gzFile open(const QString &name, const char *modeString); -}; - -gzFile QuaGzipFilePrivate::open(const QString &name, const char *modeString) -{ - return gzopen(QFile::encodeName(name).constData(), modeString); -} - -gzFile QuaGzipFilePrivate::open(int fd, const char *modeString) -{ - return gzdopen(fd, modeString); -} - -template -bool QuaGzipFilePrivate::open(FileId id, QIODevice::OpenMode mode, - QString &error) -{ - char modeString[2]; - modeString[0] = modeString[1] = '\0'; - if ((mode & QIODevice::Append) != 0) { - error = QuaGzipFile::trUtf8("QIODevice::Append is not " - "supported for GZIP"); - return false; - } - if ((mode & QIODevice::ReadOnly) != 0 - && (mode & QIODevice::WriteOnly) != 0) { - error = QuaGzipFile::trUtf8("Opening gzip for both reading" - " and writing is not supported"); - return false; - } else if ((mode & QIODevice::ReadOnly) != 0) { - modeString[0] = 'r'; - } else if ((mode & QIODevice::WriteOnly) != 0) { - modeString[0] = 'w'; - } else { - error = QuaGzipFile::trUtf8("You can open a gzip either for reading" - " or for writing. Which is it?"); - return false; - } - gzd = open(id, modeString); - if (gzd == NULL) { - error = QuaGzipFile::trUtf8("Could not gzopen() file"); - return false; - } - return true; -} -/// \endcond - -QuaGzipFile::QuaGzipFile(): -d(new QuaGzipFilePrivate()) -{ -} - -QuaGzipFile::QuaGzipFile(QObject *parent): -QIODevice(parent), -d(new QuaGzipFilePrivate()) -{ -} - -QuaGzipFile::QuaGzipFile(const QString &fileName, QObject *parent): - QIODevice(parent), -d(new QuaGzipFilePrivate(fileName)) -{ -} - -QuaGzipFile::~QuaGzipFile() -{ - if (isOpen()) { - close(); - } - delete d; -} - -void QuaGzipFile::setFileName(const QString& fileName) -{ - d->fileName = fileName; -} - -QString QuaGzipFile::getFileName() const -{ - return d->fileName; -} - -bool QuaGzipFile::isSequential() const -{ - return true; -} - -bool QuaGzipFile::open(QIODevice::OpenMode mode) -{ - QString error; - if (!d->open(d->fileName, mode, error)) { - setErrorString(error); - return false; - } - return QIODevice::open(mode); -} - -bool QuaGzipFile::open(int fd, QIODevice::OpenMode mode) -{ - QString error; - if (!d->open(fd, mode, error)) { - setErrorString(error); - return false; - } - return QIODevice::open(mode); -} - -bool QuaGzipFile::flush() -{ - return gzflush(d->gzd, Z_SYNC_FLUSH) == Z_OK; -} - -void QuaGzipFile::close() -{ - QIODevice::close(); - gzclose(d->gzd); -} - -qint64 QuaGzipFile::readData(char *data, qint64 maxSize) -{ - return gzread(d->gzd, (voidp)data, (unsigned)maxSize); -} - -qint64 QuaGzipFile::writeData(const char *data, qint64 maxSize) -{ - if (maxSize == 0) - return 0; - int written = gzwrite(d->gzd, (voidp)data, (unsigned)maxSize); - if (written == 0) - return -1; - else - return written; -} diff --git a/src/3rdParty/quazip-0.7.3/quazip/quagzipfile.h b/src/3rdParty/quazip-0.7.3/quazip/quagzipfile.h deleted file mode 100644 index e2f9d9738..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quagzipfile.h +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef QUAZIP_QUAGZIPFILE_H -#define QUAZIP_QUAGZIPFILE_H - -/* -Copyright (C) 2005-2014 Sergey A. Tachenov - -This file is part of QuaZIP. - -QuaZIP is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 of the License, or -(at your option) any later version. - -QuaZIP is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with QuaZIP. If not, see . - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant and contributors, -see quazip/(un)zip.h files for details. Basically it's the zlib license. -*/ - -#include -#include "quazip_global.h" - -#include - -class QuaGzipFilePrivate; - -/// GZIP file -/** - This class is a wrapper around GZIP file access functions in zlib. Unlike QuaZip classes, it doesn't allow reading from a GZIP file opened as QIODevice, for example, if your GZIP file is in QBuffer. It only provides QIODevice access to a GZIP file contents, but the GZIP file itself must be identified by its name on disk or by descriptor id. - */ -class QUAZIP_EXPORT QuaGzipFile: public QIODevice { - Q_OBJECT -public: - /// Empty constructor. - /** - Must call setFileName() before trying to open. - */ - QuaGzipFile(); - /// Empty constructor with a parent. - /** - Must call setFileName() before trying to open. - \param parent The parent object, as per QObject logic. - */ - QuaGzipFile(QObject *parent); - /// Constructor. - /** - \param fileName The name of the GZIP file. - \param parent The parent object, as per QObject logic. - */ - QuaGzipFile(const QString &fileName, QObject *parent = NULL); - /// Destructor. - virtual ~QuaGzipFile(); - /// Sets the name of the GZIP file to be opened. - void setFileName(const QString& fileName); - /// Returns the name of the GZIP file. - QString getFileName() const; - /// Returns true. - /** - Strictly speaking, zlib supports seeking for GZIP files, but it is - poorly implemented, because there is no way to implement it - properly. For reading, seeking backwards is very slow, and for - writing, it is downright impossible. Therefore, QuaGzipFile does not - support seeking at all. - */ - virtual bool isSequential() const; - /// Opens the file. - /** - \param mode Can be either QIODevice::Write or QIODevice::Read. - ReadWrite and Append aren't supported. - */ - virtual bool open(QIODevice::OpenMode mode); - /// Opens the file. - /** - \overload - \param fd The file descriptor to read/write the GZIP file from/to. - \param mode Can be either QIODevice::Write or QIODevice::Read. - ReadWrite and Append aren't supported. - */ - virtual bool open(int fd, QIODevice::OpenMode mode); - /// Flushes data to file. - /** - The data is written using Z_SYNC_FLUSH mode. Doesn't make any sense - when reading. - */ - virtual bool flush(); - /// Closes the file. - virtual void close(); -protected: - /// Implementation of QIODevice::readData(). - virtual qint64 readData(char *data, qint64 maxSize); - /// Implementation of QIODevice::writeData(). - virtual qint64 writeData(const char *data, qint64 maxSize); -private: - // not implemented by design to disable copy - QuaGzipFile(const QuaGzipFile &that); - QuaGzipFile& operator=(const QuaGzipFile &that); - QuaGzipFilePrivate *d; -}; - -#endif // QUAZIP_QUAGZIPFILE_H diff --git a/src/3rdParty/quazip-0.7.3/quazip/quaziodevice.cpp b/src/3rdParty/quazip-0.7.3/quazip/quaziodevice.cpp deleted file mode 100644 index 04f34bfe4..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quaziodevice.cpp +++ /dev/null @@ -1,339 +0,0 @@ -/* -Copyright (C) 2005-2014 Sergey A. Tachenov - -This file is part of QuaZIP. - -QuaZIP is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 of the License, or -(at your option) any later version. - -QuaZIP is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with QuaZIP. If not, see . - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant and contributors, -see quazip/(un)zip.h files for details. Basically it's the zlib license. -*/ - -#include "quaziodevice.h" - -#define QUAZIO_INBUFSIZE 4096 -#define QUAZIO_OUTBUFSIZE 4096 - -/// \cond internal -class QuaZIODevicePrivate { - friend class QuaZIODevice; - QuaZIODevicePrivate(QIODevice *io); - ~QuaZIODevicePrivate(); - QIODevice *io; - z_stream zins; - z_stream zouts; - char *inBuf; - int inBufPos; - int inBufSize; - char *outBuf; - int outBufPos; - int outBufSize; - bool zBufError; - bool atEnd; - int doFlush(QString &error); -}; - -QuaZIODevicePrivate::QuaZIODevicePrivate(QIODevice *io): - io(io), - inBuf(NULL), - inBufPos(0), - inBufSize(0), - outBuf(NULL), - outBufPos(0), - outBufSize(0), - zBufError(false), - atEnd(false) -{ - zins.zalloc = (alloc_func) NULL; - zins.zfree = (free_func) NULL; - zins.opaque = NULL; - zouts.zalloc = (alloc_func) NULL; - zouts.zfree = (free_func) NULL; - zouts.opaque = NULL; - inBuf = new char[QUAZIO_INBUFSIZE]; - outBuf = new char[QUAZIO_OUTBUFSIZE]; -#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT - debug.setFileName("debug.out"); - debug.open(QIODevice::WriteOnly); -#endif -#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT - indebug.setFileName("debug.in"); - indebug.open(QIODevice::WriteOnly); -#endif -} - -QuaZIODevicePrivate::~QuaZIODevicePrivate() -{ -#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT - debug.close(); -#endif -#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT - indebug.close(); -#endif - if (inBuf != NULL) - delete[] inBuf; - if (outBuf != NULL) - delete[] outBuf; -} - -int QuaZIODevicePrivate::doFlush(QString &error) -{ - int flushed = 0; - while (outBufPos < outBufSize) { - int more = io->write(outBuf + outBufPos, outBufSize - outBufPos); - if (more == -1) { - error = io->errorString(); - return -1; - } - if (more == 0) - break; - outBufPos += more; - flushed += more; - } - if (outBufPos == outBufSize) { - outBufPos = outBufSize = 0; - } - return flushed; -} - -/// \endcond - -// #define QUAZIP_ZIODEVICE_DEBUG_OUTPUT -// #define QUAZIP_ZIODEVICE_DEBUG_INPUT -#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT -#include -static QFile debug; -#endif -#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT -#include -static QFile indebug; -#endif - -QuaZIODevice::QuaZIODevice(QIODevice *io, QObject *parent): - QIODevice(parent), - d(new QuaZIODevicePrivate(io)) -{ - connect(io, SIGNAL(readyRead()), SIGNAL(readyRead())); -} - -QuaZIODevice::~QuaZIODevice() -{ - if (isOpen()) - close(); - delete d; -} - -QIODevice *QuaZIODevice::getIoDevice() const -{ - return d->io; -} - -bool QuaZIODevice::open(QIODevice::OpenMode mode) -{ - if ((mode & QIODevice::Append) != 0) { - setErrorString(trUtf8("QIODevice::Append is not supported for" - " QuaZIODevice")); - return false; - } - if ((mode & QIODevice::ReadWrite) == QIODevice::ReadWrite) { - setErrorString(trUtf8("QIODevice::ReadWrite is not supported for" - " QuaZIODevice")); - return false; - } - if ((mode & QIODevice::ReadOnly) != 0) { - if (inflateInit(&d->zins) != Z_OK) { - setErrorString(d->zins.msg); - return false; - } - } - if ((mode & QIODevice::WriteOnly) != 0) { - if (deflateInit(&d->zouts, Z_DEFAULT_COMPRESSION) != Z_OK) { - setErrorString(d->zouts.msg); - return false; - } - } - return QIODevice::open(mode); -} - -void QuaZIODevice::close() -{ - if ((openMode() & QIODevice::ReadOnly) != 0) { - if (inflateEnd(&d->zins) != Z_OK) { - setErrorString(d->zins.msg); - } - } - if ((openMode() & QIODevice::WriteOnly) != 0) { - flush(); - if (deflateEnd(&d->zouts) != Z_OK) { - setErrorString(d->zouts.msg); - } - } - QIODevice::close(); -} - -qint64 QuaZIODevice::readData(char *data, qint64 maxSize) -{ - int read = 0; - while (read < maxSize) { - if (d->inBufPos == d->inBufSize) { - d->inBufPos = 0; - d->inBufSize = d->io->read(d->inBuf, QUAZIO_INBUFSIZE); - if (d->inBufSize == -1) { - d->inBufSize = 0; - setErrorString(d->io->errorString()); - return -1; - } - if (d->inBufSize == 0) - break; - } - while (read < maxSize && d->inBufPos < d->inBufSize) { - d->zins.next_in = (Bytef *) (d->inBuf + d->inBufPos); - d->zins.avail_in = d->inBufSize - d->inBufPos; - d->zins.next_out = (Bytef *) (data + read); - d->zins.avail_out = (uInt) (maxSize - read); // hope it's less than 2GB - int more = 0; - switch (inflate(&d->zins, Z_SYNC_FLUSH)) { - case Z_OK: - read = (char *) d->zins.next_out - data; - d->inBufPos = (char *) d->zins.next_in - d->inBuf; - break; - case Z_STREAM_END: - read = (char *) d->zins.next_out - data; - d->inBufPos = (char *) d->zins.next_in - d->inBuf; - d->atEnd = true; - return read; - case Z_BUF_ERROR: // this should never happen, but just in case - if (!d->zBufError) { - qWarning("Z_BUF_ERROR detected with %d/%d in/out, weird", - d->zins.avail_in, d->zins.avail_out); - d->zBufError = true; - } - memmove(d->inBuf, d->inBuf + d->inBufPos, d->inBufSize - d->inBufPos); - d->inBufSize -= d->inBufPos; - d->inBufPos = 0; - more = d->io->read(d->inBuf + d->inBufSize, QUAZIO_INBUFSIZE - d->inBufSize); - if (more == -1) { - setErrorString(d->io->errorString()); - return -1; - } - if (more == 0) - return read; - d->inBufSize += more; - break; - default: - setErrorString(QString::fromLocal8Bit(d->zins.msg)); - return -1; - } - } - } -#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT - indebug.write(data, read); -#endif - return read; -} - -qint64 QuaZIODevice::writeData(const char *data, qint64 maxSize) -{ - int written = 0; - QString error; - if (d->doFlush(error) == -1) { - setErrorString(error); - return -1; - } - while (written < maxSize) { - // there is some data waiting in the output buffer - if (d->outBufPos < d->outBufSize) - return written; - d->zouts.next_in = (Bytef *) (data + written); - d->zouts.avail_in = (uInt) (maxSize - written); // hope it's less than 2GB - d->zouts.next_out = (Bytef *) d->outBuf; - d->zouts.avail_out = QUAZIO_OUTBUFSIZE; - switch (deflate(&d->zouts, Z_NO_FLUSH)) { - case Z_OK: - written = (char *) d->zouts.next_in - data; - d->outBufSize = (char *) d->zouts.next_out - d->outBuf; - break; - default: - setErrorString(QString::fromLocal8Bit(d->zouts.msg)); - return -1; - } - if (d->doFlush(error) == -1) { - setErrorString(error); - return -1; - } - } -#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT - debug.write(data, written); -#endif - return written; -} - -bool QuaZIODevice::flush() -{ - QString error; - if (d->doFlush(error) < 0) { - setErrorString(error); - return false; - } - // can't flush buffer, some data is still waiting - if (d->outBufPos < d->outBufSize) - return true; - Bytef c = 0; - d->zouts.next_in = &c; // fake input buffer - d->zouts.avail_in = 0; // of zero size - do { - d->zouts.next_out = (Bytef *) d->outBuf; - d->zouts.avail_out = QUAZIO_OUTBUFSIZE; - switch (deflate(&d->zouts, Z_SYNC_FLUSH)) { - case Z_OK: - d->outBufSize = (char *) d->zouts.next_out - d->outBuf; - if (d->doFlush(error) < 0) { - setErrorString(error); - return false; - } - if (d->outBufPos < d->outBufSize) - return true; - break; - case Z_BUF_ERROR: // nothing to write? - return true; - default: - setErrorString(QString::fromLocal8Bit(d->zouts.msg)); - return false; - } - } while (d->zouts.avail_out == 0); - return true; -} - -bool QuaZIODevice::isSequential() const -{ - return true; -} - -bool QuaZIODevice::atEnd() const -{ - // Here we MUST check QIODevice::bytesAvailable() because WE - // might have reached the end, but QIODevice didn't-- - // it could have simply pre-buffered all remaining data. - return (openMode() == NotOpen) || (QIODevice::bytesAvailable() == 0 && d->atEnd); -} - -qint64 QuaZIODevice::bytesAvailable() const -{ - // If we haven't recevied Z_STREAM_END, it means that - // we have at least one more input byte available. - // Plus whatever QIODevice has buffered. - return (d->atEnd ? 0 : 1) + QIODevice::bytesAvailable(); -} diff --git a/src/3rdParty/quazip-0.7.3/quazip/quaziodevice.h b/src/3rdParty/quazip-0.7.3/quazip/quaziodevice.h deleted file mode 100644 index 63499c32a..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quaziodevice.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef QUAZIP_QUAZIODEVICE_H -#define QUAZIP_QUAZIODEVICE_H - -/* -Copyright (C) 2005-2014 Sergey A. Tachenov - -This file is part of QuaZIP. - -QuaZIP is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 of the License, or -(at your option) any later version. - -QuaZIP is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with QuaZIP. If not, see . - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant and contributors, -see quazip/(un)zip.h files for details. Basically it's the zlib license. -*/ - -#include -#include "quazip_global.h" - -#include - -class QuaZIODevicePrivate; - -/// A class to compress/decompress QIODevice. -/** - This class can be used to compress any data written to QIODevice or - decompress it back. Compressing data sent over a QTcpSocket is a good - example. - */ -class QUAZIP_EXPORT QuaZIODevice: public QIODevice { - Q_OBJECT -public: - /// Constructor. - /** - \param io The QIODevice to read/write. - \param parent The parent object, as per QObject logic. - */ - QuaZIODevice(QIODevice *io, QObject *parent = NULL); - /// Destructor. - ~QuaZIODevice(); - /// Flushes data waiting to be written. - /** - Unfortunately, as QIODevice doesn't support flush() by itself, the - only thing this method does is write the compressed data into the - device using Z_SYNC_FLUSH mode. If you need the compressed data to - actually be flushed from the buffer of the underlying QIODevice, you - need to call its flush() method as well, providing it supports it - (like QTcpSocket does). Example: - \code - QuaZIODevice dev(&sock); - dev.open(QIODevice::Write); - dev.write(yourDataGoesHere); - dev.flush(); - sock->flush(); // this actually sends data to network - \endcode - - This may change in the future versions of QuaZIP by implementing an - ugly hack: trying to cast the QIODevice using qobject_cast to known - flush()-supporting subclasses, and calling flush if the resulting - pointer is not zero. - */ - virtual bool flush(); - /// Opens the device. - /** - \param mode Neither QIODevice::ReadWrite nor QIODevice::Append are - not supported. - */ - virtual bool open(QIODevice::OpenMode mode); - /// Closes this device, but not the underlying one. - /** - The underlying QIODevice is not closed in case you want to write - something else to it. - */ - virtual void close(); - /// Returns the underlying device. - QIODevice *getIoDevice() const; - /// Returns true. - virtual bool isSequential() const; - /// Returns true iff the end of the compressed stream is reached. - virtual bool atEnd() const; - /// Returns the number of the bytes buffered. - virtual qint64 bytesAvailable() const; -protected: - /// Implementation of QIODevice::readData(). - virtual qint64 readData(char *data, qint64 maxSize); - /// Implementation of QIODevice::writeData(). - virtual qint64 writeData(const char *data, qint64 maxSize); -private: - QuaZIODevicePrivate *d; -}; -#endif // QUAZIP_QUAZIODEVICE_H diff --git a/src/3rdParty/quazip-0.7.3/quazip/quazip.cpp b/src/3rdParty/quazip-0.7.3/quazip/quazip.cpp deleted file mode 100644 index a5bc44eef..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quazip.cpp +++ /dev/null @@ -1,795 +0,0 @@ -/* -Copyright (C) 2005-2014 Sergey A. Tachenov - -This file is part of QuaZIP. - -QuaZIP is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 of the License, or -(at your option) any later version. - -QuaZIP is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with QuaZIP. If not, see . - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant, see -quazip/(un)zip.h files for details, basically it's zlib license. - **/ - -#include -#include -#include - -#include "quazip.h" - -/// All the internal stuff for the QuaZip class. -/** - \internal - - This class keeps all the private stuff for the QuaZip class so it can - be changed without breaking binary compatibility, according to the - Pimpl idiom. - */ -class QuaZipPrivate { - friend class QuaZip; - private: - Q_DISABLE_COPY(QuaZipPrivate) - /// The pointer to the corresponding QuaZip instance. - QuaZip *q; - /// The codec for file names. - QTextCodec *fileNameCodec; - /// The codec for comments. - QTextCodec *commentCodec; - /// The archive file name. - QString zipName; - /// The device to access the archive. - QIODevice *ioDevice; - /// The global comment. - QString comment; - /// The open mode. - QuaZip::Mode mode; - union { - /// The internal handle for UNZIP modes. - unzFile unzFile_f; - /// The internal handle for ZIP modes. - zipFile zipFile_f; - }; - /// Whether a current file is set. - bool hasCurrentFile_f; - /// The last error. - int zipError; - /// Whether \ref QuaZip::setDataDescriptorWritingEnabled() "the data descriptor writing mode" is enabled. - bool dataDescriptorWritingEnabled; - /// The zip64 mode. - bool zip64; - /// The auto-close flag. - bool autoClose; - inline QTextCodec *getDefaultFileNameCodec() - { - if (defaultFileNameCodec == NULL) { - return QTextCodec::codecForLocale(); - } else { - return defaultFileNameCodec; - } - } - /// The constructor for the corresponding QuaZip constructor. - inline QuaZipPrivate(QuaZip *q): - q(q), - fileNameCodec(getDefaultFileNameCodec()), - commentCodec(QTextCodec::codecForLocale()), - ioDevice(NULL), - mode(QuaZip::mdNotOpen), - hasCurrentFile_f(false), - zipError(UNZ_OK), - dataDescriptorWritingEnabled(true), - zip64(false), - autoClose(true) - { - unzFile_f = NULL; - zipFile_f = NULL; - lastMappedDirectoryEntry.num_of_file = 0; - lastMappedDirectoryEntry.pos_in_zip_directory = 0; - } - /// The constructor for the corresponding QuaZip constructor. - inline QuaZipPrivate(QuaZip *q, const QString &zipName): - q(q), - fileNameCodec(getDefaultFileNameCodec()), - commentCodec(QTextCodec::codecForLocale()), - zipName(zipName), - ioDevice(NULL), - mode(QuaZip::mdNotOpen), - hasCurrentFile_f(false), - zipError(UNZ_OK), - dataDescriptorWritingEnabled(true), - zip64(false), - autoClose(true) - { - unzFile_f = NULL; - zipFile_f = NULL; - lastMappedDirectoryEntry.num_of_file = 0; - lastMappedDirectoryEntry.pos_in_zip_directory = 0; - } - /// The constructor for the corresponding QuaZip constructor. - inline QuaZipPrivate(QuaZip *q, QIODevice *ioDevice): - q(q), - fileNameCodec(getDefaultFileNameCodec()), - commentCodec(QTextCodec::codecForLocale()), - ioDevice(ioDevice), - mode(QuaZip::mdNotOpen), - hasCurrentFile_f(false), - zipError(UNZ_OK), - dataDescriptorWritingEnabled(true), - zip64(false), - autoClose(true) - { - unzFile_f = NULL; - zipFile_f = NULL; - lastMappedDirectoryEntry.num_of_file = 0; - lastMappedDirectoryEntry.pos_in_zip_directory = 0; - } - /// Returns either a list of file names or a list of QuaZipFileInfo. - template - bool getFileInfoList(QList *result) const; - - /// Stores map of filenames and file locations for unzipping - inline void clearDirectoryMap(); - inline void addCurrentFileToDirectoryMap(const QString &fileName); - bool goToFirstUnmappedFile(); - QHash directoryCaseSensitive; - QHash directoryCaseInsensitive; - unz64_file_pos lastMappedDirectoryEntry; - static QTextCodec *defaultFileNameCodec; -}; - -QTextCodec *QuaZipPrivate::defaultFileNameCodec = NULL; - -void QuaZipPrivate::clearDirectoryMap() -{ - directoryCaseInsensitive.clear(); - directoryCaseSensitive.clear(); - lastMappedDirectoryEntry.num_of_file = 0; - lastMappedDirectoryEntry.pos_in_zip_directory = 0; -} - -void QuaZipPrivate::addCurrentFileToDirectoryMap(const QString &fileName) -{ - if (!hasCurrentFile_f || fileName.isEmpty()) { - return; - } - // Adds current file to filename map as fileName - unz64_file_pos fileDirectoryPos; - unzGetFilePos64(unzFile_f, &fileDirectoryPos); - directoryCaseSensitive.insert(fileName, fileDirectoryPos); - // Only add lowercase to directory map if not already there - // ensures only map the first one seen - QString lower = fileName.toLower(); - if (!directoryCaseInsensitive.contains(lower)) - directoryCaseInsensitive.insert(lower, fileDirectoryPos); - // Mark last one - if (fileDirectoryPos.pos_in_zip_directory > lastMappedDirectoryEntry.pos_in_zip_directory) - lastMappedDirectoryEntry = fileDirectoryPos; -} - -bool QuaZipPrivate::goToFirstUnmappedFile() -{ - zipError = UNZ_OK; - if (mode != QuaZip::mdUnzip) { - qWarning("QuaZipPrivate::goToNextUnmappedFile(): ZIP is not open in mdUnzip mode"); - return false; - } - // If not mapped anything, go to beginning - if (lastMappedDirectoryEntry.pos_in_zip_directory == 0) { - unzGoToFirstFile(unzFile_f); - } else { - // Goto the last one mapped, plus one - unzGoToFilePos64(unzFile_f, &lastMappedDirectoryEntry); - unzGoToNextFile(unzFile_f); - } - hasCurrentFile_f=zipError==UNZ_OK; - if(zipError==UNZ_END_OF_LIST_OF_FILE) - zipError=UNZ_OK; - return hasCurrentFile_f; -} - -QuaZip::QuaZip(): - p(new QuaZipPrivate(this)) -{ -} - -QuaZip::QuaZip(const QString& zipName): - p(new QuaZipPrivate(this, zipName)) -{ -} - -QuaZip::QuaZip(QIODevice *ioDevice): - p(new QuaZipPrivate(this, ioDevice)) -{ -} - -QuaZip::~QuaZip() -{ - if(isOpen()) - close(); - delete p; -} - -bool QuaZip::open(Mode mode, zlib_filefunc_def* ioApi) -{ - p->zipError=UNZ_OK; - if(isOpen()) { - qWarning("QuaZip::open(): ZIP already opened"); - return false; - } - QIODevice *ioDevice = p->ioDevice; - if (ioDevice == NULL) { - if (p->zipName.isEmpty()) { - qWarning("QuaZip::open(): set either ZIP file name or IO device first"); - return false; - } else { - ioDevice = new QFile(p->zipName); - } - } - unsigned flags = 0; - switch(mode) { - case mdUnzip: - if (ioApi == NULL) { - if (p->autoClose) - flags |= UNZ_AUTO_CLOSE; - p->unzFile_f=unzOpenInternal(ioDevice, NULL, 1, flags); - } else { - // QuaZIP pre-zip64 compatibility mode - p->unzFile_f=unzOpen2(ioDevice, ioApi); - if (p->unzFile_f != NULL) { - if (p->autoClose) { - unzSetFlags(p->unzFile_f, UNZ_AUTO_CLOSE); - } else { - unzClearFlags(p->unzFile_f, UNZ_AUTO_CLOSE); - } - } - } - if(p->unzFile_f!=NULL) { - if (ioDevice->isSequential()) { - unzClose(p->unzFile_f); - if (!p->zipName.isEmpty()) - delete ioDevice; - qWarning("QuaZip::open(): " - "only mdCreate can be used with " - "sequential devices"); - return false; - } - p->mode=mode; - p->ioDevice = ioDevice; - return true; - } else { - p->zipError=UNZ_OPENERROR; - if (!p->zipName.isEmpty()) - delete ioDevice; - return false; - } - case mdCreate: - case mdAppend: - case mdAdd: - if (ioApi == NULL) { - if (p->autoClose) - flags |= ZIP_AUTO_CLOSE; - if (p->dataDescriptorWritingEnabled) - flags |= ZIP_WRITE_DATA_DESCRIPTOR; - p->zipFile_f=zipOpen3(ioDevice, - mode==mdCreate?APPEND_STATUS_CREATE: - mode==mdAppend?APPEND_STATUS_CREATEAFTER: - APPEND_STATUS_ADDINZIP, - NULL, NULL, flags); - } else { - // QuaZIP pre-zip64 compatibility mode - p->zipFile_f=zipOpen2(ioDevice, - mode==mdCreate?APPEND_STATUS_CREATE: - mode==mdAppend?APPEND_STATUS_CREATEAFTER: - APPEND_STATUS_ADDINZIP, - NULL, - ioApi); - if (p->zipFile_f != NULL) { - zipSetFlags(p->zipFile_f, flags); - } - } - if(p->zipFile_f!=NULL) { - if (ioDevice->isSequential()) { - if (mode != mdCreate) { - zipClose(p->zipFile_f, NULL); - qWarning("QuaZip::open(): " - "only mdCreate can be used with " - "sequential devices"); - if (!p->zipName.isEmpty()) - delete ioDevice; - return false; - } - zipSetFlags(p->zipFile_f, ZIP_SEQUENTIAL); - } - p->mode=mode; - p->ioDevice = ioDevice; - return true; - } else { - p->zipError=UNZ_OPENERROR; - if (!p->zipName.isEmpty()) - delete ioDevice; - return false; - } - default: - qWarning("QuaZip::open(): unknown mode: %d", (int)mode); - if (!p->zipName.isEmpty()) - delete ioDevice; - return false; - break; - } -} - -void QuaZip::close() -{ - p->zipError=UNZ_OK; - switch(p->mode) { - case mdNotOpen: - qWarning("QuaZip::close(): ZIP is not open"); - return; - case mdUnzip: - p->zipError=unzClose(p->unzFile_f); - break; - case mdCreate: - case mdAppend: - case mdAdd: - p->zipError=zipClose(p->zipFile_f, - p->comment.isNull() ? NULL - : p->commentCodec->fromUnicode(p->comment).constData()); - break; - default: - qWarning("QuaZip::close(): unknown mode: %d", (int)p->mode); - return; - } - // opened by name, need to delete the internal IO device - if (!p->zipName.isEmpty()) { - delete p->ioDevice; - p->ioDevice = NULL; - } - p->clearDirectoryMap(); - if(p->zipError==UNZ_OK) - p->mode=mdNotOpen; -} - -void QuaZip::setZipName(const QString& zipName) -{ - if(isOpen()) { - qWarning("QuaZip::setZipName(): ZIP is already open!"); - return; - } - p->zipName=zipName; - p->ioDevice = NULL; -} - -void QuaZip::setIoDevice(QIODevice *ioDevice) -{ - if(isOpen()) { - qWarning("QuaZip::setIoDevice(): ZIP is already open!"); - return; - } - p->ioDevice = ioDevice; - p->zipName = QString(); -} - -int QuaZip::getEntriesCount()const -{ - QuaZip *fakeThis=(QuaZip*)this; // non-const - fakeThis->p->zipError=UNZ_OK; - if(p->mode!=mdUnzip) { - qWarning("QuaZip::getEntriesCount(): ZIP is not open in mdUnzip mode"); - return -1; - } - unz_global_info64 globalInfo; - if((fakeThis->p->zipError=unzGetGlobalInfo64(p->unzFile_f, &globalInfo))!=UNZ_OK) - return p->zipError; - return (int)globalInfo.number_entry; -} - -QString QuaZip::getComment()const -{ - QuaZip *fakeThis=(QuaZip*)this; // non-const - fakeThis->p->zipError=UNZ_OK; - if(p->mode!=mdUnzip) { - qWarning("QuaZip::getComment(): ZIP is not open in mdUnzip mode"); - return QString(); - } - unz_global_info64 globalInfo; - QByteArray comment; - if((fakeThis->p->zipError=unzGetGlobalInfo64(p->unzFile_f, &globalInfo))!=UNZ_OK) - return QString(); - comment.resize(globalInfo.size_comment); - if((fakeThis->p->zipError=unzGetGlobalComment(p->unzFile_f, comment.data(), comment.size())) < 0) - return QString(); - fakeThis->p->zipError = UNZ_OK; - return p->commentCodec->toUnicode(comment); -} - -bool QuaZip::setCurrentFile(const QString& fileName, CaseSensitivity cs) -{ - p->zipError=UNZ_OK; - if(p->mode!=mdUnzip) { - qWarning("QuaZip::setCurrentFile(): ZIP is not open in mdUnzip mode"); - return false; - } - if(fileName.isEmpty()) { - p->hasCurrentFile_f=false; - return true; - } - // Unicode-aware reimplementation of the unzLocateFile function - if(p->unzFile_f==NULL) { - p->zipError=UNZ_PARAMERROR; - return false; - } - if(fileName.length()>MAX_FILE_NAME_LENGTH) { - p->zipError=UNZ_PARAMERROR; - return false; - } - // Find the file by name - bool sens = convertCaseSensitivity(cs) == Qt::CaseSensitive; - QString lower, current; - if(!sens) lower=fileName.toLower(); - p->hasCurrentFile_f=false; - - // Check the appropriate Map - unz64_file_pos fileDirPos; - fileDirPos.pos_in_zip_directory = 0; - if (sens) { - if (p->directoryCaseSensitive.contains(fileName)) - fileDirPos = p->directoryCaseSensitive.value(fileName); - } else { - if (p->directoryCaseInsensitive.contains(lower)) - fileDirPos = p->directoryCaseInsensitive.value(lower); - } - - if (fileDirPos.pos_in_zip_directory != 0) { - p->zipError = unzGoToFilePos64(p->unzFile_f, &fileDirPos); - p->hasCurrentFile_f = p->zipError == UNZ_OK; - } - - if (p->hasCurrentFile_f) - return p->hasCurrentFile_f; - - // Not mapped yet, start from where we have got to so far - for(bool more=p->goToFirstUnmappedFile(); more; more=goToNextFile()) { - current=getCurrentFileName(); - if(current.isEmpty()) return false; - if(sens) { - if(current==fileName) break; - } else { - if(current.toLower()==lower) break; - } - } - return p->hasCurrentFile_f; -} - -bool QuaZip::goToFirstFile() -{ - p->zipError=UNZ_OK; - if(p->mode!=mdUnzip) { - qWarning("QuaZip::goToFirstFile(): ZIP is not open in mdUnzip mode"); - return false; - } - p->zipError=unzGoToFirstFile(p->unzFile_f); - p->hasCurrentFile_f=p->zipError==UNZ_OK; - return p->hasCurrentFile_f; -} - -bool QuaZip::goToNextFile() -{ - p->zipError=UNZ_OK; - if(p->mode!=mdUnzip) { - qWarning("QuaZip::goToFirstFile(): ZIP is not open in mdUnzip mode"); - return false; - } - p->zipError=unzGoToNextFile(p->unzFile_f); - p->hasCurrentFile_f=p->zipError==UNZ_OK; - if(p->zipError==UNZ_END_OF_LIST_OF_FILE) - p->zipError=UNZ_OK; - return p->hasCurrentFile_f; -} - -bool QuaZip::getCurrentFileInfo(QuaZipFileInfo *info)const -{ - QuaZipFileInfo64 info64; - if (info == NULL) { // Very unlikely because of the overloads - return false; - } - if (getCurrentFileInfo(&info64)) { - info64.toQuaZipFileInfo(*info); - return true; - } else { - return false; - } -} - -bool QuaZip::getCurrentFileInfo(QuaZipFileInfo64 *info)const -{ - QuaZip *fakeThis=(QuaZip*)this; // non-const - fakeThis->p->zipError=UNZ_OK; - if(p->mode!=mdUnzip) { - qWarning("QuaZip::getCurrentFileInfo(): ZIP is not open in mdUnzip mode"); - return false; - } - unz_file_info64 info_z; - QByteArray fileName; - QByteArray extra; - QByteArray comment; - if(info==NULL) return false; - if(!isOpen()||!hasCurrentFile()) return false; - if((fakeThis->p->zipError=unzGetCurrentFileInfo64(p->unzFile_f, &info_z, NULL, 0, NULL, 0, NULL, 0))!=UNZ_OK) - return false; - fileName.resize(info_z.size_filename); - extra.resize(info_z.size_file_extra); - comment.resize(info_z.size_file_comment); - if((fakeThis->p->zipError=unzGetCurrentFileInfo64(p->unzFile_f, NULL, - fileName.data(), fileName.size(), - extra.data(), extra.size(), - comment.data(), comment.size()))!=UNZ_OK) - return false; - info->versionCreated=info_z.version; - info->versionNeeded=info_z.version_needed; - info->flags=info_z.flag; - info->method=info_z.compression_method; - info->crc=info_z.crc; - info->compressedSize=info_z.compressed_size; - info->uncompressedSize=info_z.uncompressed_size; - info->diskNumberStart=info_z.disk_num_start; - info->internalAttr=info_z.internal_fa; - info->externalAttr=info_z.external_fa; - info->name=p->fileNameCodec->toUnicode(fileName); - info->comment=p->commentCodec->toUnicode(comment); - info->extra=extra; - info->dateTime=QDateTime( - QDate(info_z.tmu_date.tm_year, info_z.tmu_date.tm_mon+1, info_z.tmu_date.tm_mday), - QTime(info_z.tmu_date.tm_hour, info_z.tmu_date.tm_min, info_z.tmu_date.tm_sec)); - // Add to directory map - p->addCurrentFileToDirectoryMap(info->name); - return true; -} - -QString QuaZip::getCurrentFileName()const -{ - QuaZip *fakeThis=(QuaZip*)this; // non-const - fakeThis->p->zipError=UNZ_OK; - if(p->mode!=mdUnzip) { - qWarning("QuaZip::getCurrentFileName(): ZIP is not open in mdUnzip mode"); - return QString(); - } - if(!isOpen()||!hasCurrentFile()) return QString(); - QByteArray fileName(MAX_FILE_NAME_LENGTH, 0); - if((fakeThis->p->zipError=unzGetCurrentFileInfo64(p->unzFile_f, NULL, fileName.data(), fileName.size(), - NULL, 0, NULL, 0))!=UNZ_OK) - return QString(); - QString result = p->fileNameCodec->toUnicode(fileName.constData()); - if (result.isEmpty()) - return result; - // Add to directory map - p->addCurrentFileToDirectoryMap(result); - return result; -} - -void QuaZip::setFileNameCodec(QTextCodec *fileNameCodec) -{ - p->fileNameCodec=fileNameCodec; -} - -void QuaZip::setFileNameCodec(const char *fileNameCodecName) -{ - p->fileNameCodec=QTextCodec::codecForName(fileNameCodecName); -} - -QTextCodec *QuaZip::getFileNameCodec()const -{ - return p->fileNameCodec; -} - -void QuaZip::setCommentCodec(QTextCodec *commentCodec) -{ - p->commentCodec=commentCodec; -} - -void QuaZip::setCommentCodec(const char *commentCodecName) -{ - p->commentCodec=QTextCodec::codecForName(commentCodecName); -} - -QTextCodec *QuaZip::getCommentCodec()const -{ - return p->commentCodec; -} - -QString QuaZip::getZipName() const -{ - return p->zipName; -} - -QIODevice *QuaZip::getIoDevice() const -{ - if (!p->zipName.isEmpty()) // opened by name, using an internal QIODevice - return NULL; - return p->ioDevice; -} - -QuaZip::Mode QuaZip::getMode()const -{ - return p->mode; -} - -bool QuaZip::isOpen()const -{ - return p->mode!=mdNotOpen; -} - -int QuaZip::getZipError() const -{ - return p->zipError; -} - -void QuaZip::setComment(const QString& comment) -{ - p->comment=comment; -} - -bool QuaZip::hasCurrentFile()const -{ - return p->hasCurrentFile_f; -} - -unzFile QuaZip::getUnzFile() -{ - return p->unzFile_f; -} - -zipFile QuaZip::getZipFile() -{ - return p->zipFile_f; -} - -void QuaZip::setDataDescriptorWritingEnabled(bool enabled) -{ - p->dataDescriptorWritingEnabled = enabled; -} - -bool QuaZip::isDataDescriptorWritingEnabled() const -{ - return p->dataDescriptorWritingEnabled; -} - -template -TFileInfo QuaZip_getFileInfo(QuaZip *zip, bool *ok); - -template<> -QuaZipFileInfo QuaZip_getFileInfo(QuaZip *zip, bool *ok) -{ - QuaZipFileInfo info; - *ok = zip->getCurrentFileInfo(&info); - return info; -} - -template<> -QuaZipFileInfo64 QuaZip_getFileInfo(QuaZip *zip, bool *ok) -{ - QuaZipFileInfo64 info; - *ok = zip->getCurrentFileInfo(&info); - return info; -} - -template<> -QString QuaZip_getFileInfo(QuaZip *zip, bool *ok) -{ - QString name = zip->getCurrentFileName(); - *ok = !name.isEmpty(); - return name; -} - -template -bool QuaZipPrivate::getFileInfoList(QList *result) const -{ - QuaZipPrivate *fakeThis=const_cast(this); - fakeThis->zipError=UNZ_OK; - if (mode!=QuaZip::mdUnzip) { - qWarning("QuaZip::getFileNameList/getFileInfoList(): " - "ZIP is not open in mdUnzip mode"); - return false; - } - QString currentFile; - if (q->hasCurrentFile()) { - currentFile = q->getCurrentFileName(); - } - if (q->goToFirstFile()) { - do { - bool ok; - result->append(QuaZip_getFileInfo(q, &ok)); - if (!ok) - return false; - } while (q->goToNextFile()); - } - if (zipError != UNZ_OK) - return false; - if (currentFile.isEmpty()) { - if (!q->goToFirstFile()) - return false; - } else { - if (!q->setCurrentFile(currentFile)) - return false; - } - return true; -} - -QStringList QuaZip::getFileNameList() const -{ - QStringList list; - if (p->getFileInfoList(&list)) - return list; - else - return QStringList(); -} - -QList QuaZip::getFileInfoList() const -{ - QList list; - if (p->getFileInfoList(&list)) - return list; - else - return QList(); -} - -QList QuaZip::getFileInfoList64() const -{ - QList list; - if (p->getFileInfoList(&list)) - return list; - else - return QList(); -} - -Qt::CaseSensitivity QuaZip::convertCaseSensitivity(QuaZip::CaseSensitivity cs) -{ - if (cs == csDefault) { -#ifdef Q_OS_WIN - return Qt::CaseInsensitive; -#else - return Qt::CaseSensitive; -#endif - } else { - return cs == csSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive; - } -} - -void QuaZip::setDefaultFileNameCodec(QTextCodec *codec) -{ - QuaZipPrivate::defaultFileNameCodec = codec; -} - -void QuaZip::setDefaultFileNameCodec(const char *codecName) -{ - setDefaultFileNameCodec(QTextCodec::codecForName(codecName)); -} - -void QuaZip::setZip64Enabled(bool zip64) -{ - p->zip64 = zip64; -} - -bool QuaZip::isZip64Enabled() const -{ - return p->zip64; -} - -bool QuaZip::isAutoClose() const -{ - return p->autoClose; -} - -void QuaZip::setAutoClose(bool autoClose) const -{ - p->autoClose = autoClose; -} diff --git a/src/3rdParty/quazip-0.7.3/quazip/quazip.h b/src/3rdParty/quazip-0.7.3/quazip/quazip.h deleted file mode 100644 index ae2c8f494..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quazip.h +++ /dev/null @@ -1,571 +0,0 @@ -#ifndef QUA_ZIP_H -#define QUA_ZIP_H - -/* -Copyright (C) 2005-2014 Sergey A. Tachenov - -This file is part of QuaZIP. - -QuaZIP is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 of the License, or -(at your option) any later version. - -QuaZIP is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with QuaZIP. If not, see . - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant, see -quazip/(un)zip.h files for details, basically it's zlib license. - **/ - -#include -#include -#include - -#include "zip.h" -#include "unzip.h" - -#include "quazip_global.h" -#include "quazipfileinfo.h" - -// just in case it will be defined in the later versions of the ZIP/UNZIP -#ifndef UNZ_OPENERROR -// define additional error code -#define UNZ_OPENERROR -1000 -#endif - -class QuaZipPrivate; - -/// ZIP archive. -/** \class QuaZip quazip.h - * This class implements basic interface to the ZIP archive. It can be - * used to read table contents of the ZIP archive and retreiving - * information about the files inside it. - * - * You can also use this class to open files inside archive by passing - * pointer to the instance of this class to the constructor of the - * QuaZipFile class. But see QuaZipFile::QuaZipFile(QuaZip*, QObject*) - * for the possible pitfalls. - * - * This class is indended to provide interface to the ZIP subpackage of - * the ZIP/UNZIP package as well as to the UNZIP subpackage. But - * currently it supports only UNZIP. - * - * The use of this class is simple - just create instance using - * constructor, then set ZIP archive file name using setFile() function - * (if you did not passed the name to the constructor), then open() and - * then use different functions to work with it! Well, if you are - * paranoid, you may also wish to call close before destructing the - * instance, to check for errors on close. - * - * You may also use getUnzFile() and getZipFile() functions to get the - * ZIP archive handle and use it with ZIP/UNZIP package API directly. - * - * This class supports localized file names inside ZIP archive, but you - * have to set up proper codec with setCodec() function. By default, - * locale codec will be used, which is probably ok for UNIX systems, but - * will almost certainly fail with ZIP archives created in Windows. This - * is because Windows ZIP programs have strange habit of using DOS - * encoding for file names in ZIP archives. For example, ZIP archive - * with cyrillic names created in Windows will have file names in \c - * IBM866 encoding instead of \c WINDOWS-1251. I think that calling one - * function is not much trouble, but for true platform independency it - * would be nice to have some mechanism for file name encoding auto - * detection using locale information. Does anyone know a good way to do - * it? - **/ -class QUAZIP_EXPORT QuaZip { - friend class QuaZipPrivate; - public: - /// Useful constants. - enum Constants { - MAX_FILE_NAME_LENGTH=256 /**< Maximum file name length. Taken from - \c UNZ_MAXFILENAMEINZIP constant in - unzip.c. */ - }; - /// Open mode of the ZIP file. - enum Mode { - mdNotOpen, ///< ZIP file is not open. This is the initial mode. - mdUnzip, ///< ZIP file is open for reading files inside it. - mdCreate, ///< ZIP file was created with open() call. - mdAppend, /**< ZIP file was opened in append mode. This refers to - * \c APPEND_STATUS_CREATEAFTER mode in ZIP/UNZIP package - * and means that zip is appended to some existing file - * what is useful when that file contains - * self-extractor code. This is obviously \em not what - * you whant to use to add files to the existing ZIP - * archive. - **/ - mdAdd ///< ZIP file was opened for adding files in the archive. - }; - /// Case sensitivity for the file names. - /** This is what you specify when accessing files in the archive. - * Works perfectly fine with any characters thanks to Qt's great - * unicode support. This is different from ZIP/UNZIP API, where - * only US-ASCII characters was supported. - **/ - enum CaseSensitivity { - csDefault=0, ///< Default for platform. Case sensitive for UNIX, not for Windows. - csSensitive=1, ///< Case sensitive. - csInsensitive=2 ///< Case insensitive. - }; - /// Returns the actual case sensitivity for the specified QuaZIP one. - /** - \param cs The value to convert. - \returns If CaseSensitivity::csDefault, then returns the default - file name case sensitivity for the platform. Otherwise, just - returns the appropriate value from the Qt::CaseSensitivity enum. - */ - static Qt::CaseSensitivity convertCaseSensitivity( - CaseSensitivity cs); - private: - QuaZipPrivate *p; - // not (and will not be) implemented - QuaZip(const QuaZip& that); - // not (and will not be) implemented - QuaZip& operator=(const QuaZip& that); - public: - /// Constructs QuaZip object. - /** Call setName() before opening constructed object. */ - QuaZip(); - /// Constructs QuaZip object associated with ZIP file \a zipName. - QuaZip(const QString& zipName); - /// Constructs QuaZip object associated with ZIP file represented by \a ioDevice. - /** The IO device must be seekable, otherwise an error will occur when opening. */ - QuaZip(QIODevice *ioDevice); - /// Destroys QuaZip object. - /** Calls close() if necessary. */ - ~QuaZip(); - /// Opens ZIP file. - /** - * Argument \a mode specifies open mode of the ZIP archive. See Mode - * for details. Note that there is zipOpen2() function in the - * ZIP/UNZIP API which accepts \a globalcomment argument, but it - * does not use it anywhere, so this open() function does not have this - * argument. See setComment() if you need to set global comment. - * - * If the ZIP file is accessed via explicitly set QIODevice, then - * this device is opened in the necessary mode. If the device was - * already opened by some other means, then QuaZIP checks if the - * open mode is compatible to the mode needed for the requested operation. - * If necessary, seeking is performed to position the device properly. - * - * \return \c true if successful, \c false otherwise. - * - * \note ZIP/UNZIP API open calls do not return error code - they - * just return \c NULL indicating an error. But to make things - * easier, quazip.h header defines additional error code \c - * UNZ_ERROROPEN and getZipError() will return it if the open call - * of the ZIP/UNZIP API returns \c NULL. - * - * Argument \a ioApi specifies IO function set for ZIP/UNZIP - * package to use. See unzip.h, zip.h and ioapi.h for details. Note - * that IO API for QuaZip is different from the original package. - * The file path argument was changed to be of type \c voidpf, and - * QuaZip passes a QIODevice pointer there. This QIODevice is either - * set explicitly via setIoDevice() or the QuaZip(QIODevice*) - * constructor, or it is created internally when opening the archive - * by its file name. The default API (qioapi.cpp) just delegates - * everything to the QIODevice API. Not only this allows to use a - * QIODevice instead of file name, but also has a nice side effect - * of raising the file size limit from 2G to 4G (in non-zip64 archives). - * - * \note If the zip64 support is needed, the ioApi argument \em must be NULL - * because due to the backwards compatibility issues it can be used to - * provide a 32-bit API only. - * - * \note If the \ref QuaZip::setAutoClose() "no-auto-close" feature is used, - * then the \a ioApi argument \em should be NULL because the old API - * doesn't support the 'fake close' operation, causing slight memory leaks - * and other possible troubles (like closing the output device in case - * when an error occurs during opening). - * - * In short: just forget about the \a ioApi argument and you'll be - * fine. - **/ - bool open(Mode mode, zlib_filefunc_def *ioApi =NULL); - /// Closes ZIP file. - /** Call getZipError() to determine if the close was successful. - * - * If the file was opened by name, then the underlying QIODevice is closed - * and deleted. - * - * If the underlying QIODevice was set explicitly using setIoDevice() or - * the appropriate constructor, then it is closed if the auto-close flag - * is set (which it is by default). Call setAutoClose() to clear the - * auto-close flag if this behavior is undesirable. - * - * Since Qt 5.1, the QSaveFile was introduced. It breaks the QIODevice API - * by making close() private and crashing the application if it is called - * from the base class where it is public. It is an excellent example - * of poor design that illustrates why you should never ever break - * an is-a relationship between the base class and a subclass. QuaZIP - * works around this bug by checking if the QIODevice is an instance - * of QSaveFile, using qobject_cast<>, and if it is, calls - * QSaveFile::commit() instead of close(). It is a really ugly hack, - * but at least it makes your programs work instead of crashing. Note that - * if the auto-close flag is cleared, then this is a non-issue, and - * commit() isn't called. - */ - void close(); - /// Sets the codec used to encode/decode file names inside archive. - /** This is necessary to access files in the ZIP archive created - * under Windows with non-latin characters in file names. For - * example, file names with cyrillic letters will be in \c IBM866 - * encoding. - **/ - void setFileNameCodec(QTextCodec *fileNameCodec); - /// Sets the codec used to encode/decode file names inside archive. - /** \overload - * Equivalent to calling setFileNameCodec(QTextCodec::codecForName(codecName)); - **/ - void setFileNameCodec(const char *fileNameCodecName); - /// Returns the codec used to encode/decode comments inside archive. - QTextCodec* getFileNameCodec() const; - /// Sets the codec used to encode/decode comments inside archive. - /** This codec defaults to locale codec, which is probably ok. - **/ - void setCommentCodec(QTextCodec *commentCodec); - /// Sets the codec used to encode/decode comments inside archive. - /** \overload - * Equivalent to calling setCommentCodec(QTextCodec::codecForName(codecName)); - **/ - void setCommentCodec(const char *commentCodecName); - /// Returns the codec used to encode/decode comments inside archive. - QTextCodec* getCommentCodec() const; - /// Returns the name of the ZIP file. - /** Returns null string if no ZIP file name has been set, for - * example when the QuaZip instance is set up to use a QIODevice - * instead. - * \sa setZipName(), setIoDevice(), getIoDevice() - **/ - QString getZipName() const; - /// Sets the name of the ZIP file. - /** Does nothing if the ZIP file is open. - * - * Does not reset error code returned by getZipError(). - * \sa setIoDevice(), getIoDevice(), getZipName() - **/ - void setZipName(const QString& zipName); - /// Returns the device representing this ZIP file. - /** Returns null string if no device has been set explicitly, for - * example when opening a ZIP file by name. - * \sa setIoDevice(), getZipName(), setZipName() - **/ - QIODevice *getIoDevice() const; - /// Sets the device representing the ZIP file. - /** Does nothing if the ZIP file is open. - * - * Does not reset error code returned by getZipError(). - * \sa getIoDevice(), getZipName(), setZipName() - **/ - void setIoDevice(QIODevice *ioDevice); - /// Returns the mode in which ZIP file was opened. - Mode getMode() const; - /// Returns \c true if ZIP file is open, \c false otherwise. - bool isOpen() const; - /// Returns the error code of the last operation. - /** Returns \c UNZ_OK if the last operation was successful. - * - * Error code resets to \c UNZ_OK every time you call any function - * that accesses something inside ZIP archive, even if it is \c - * const (like getEntriesCount()). open() and close() calls reset - * error code too. See documentation for the specific functions for - * details on error detection. - **/ - int getZipError() const; - /// Returns number of the entries in the ZIP central directory. - /** Returns negative error code in the case of error. The same error - * code will be returned by subsequent getZipError() call. - **/ - int getEntriesCount() const; - /// Returns global comment in the ZIP file. - QString getComment() const; - /// Sets the global comment in the ZIP file. - /** The comment will be written to the archive on close operation. - * QuaZip makes a distinction between a null QByteArray() comment - * and an empty "" comment in the QuaZip::mdAdd mode. - * A null comment is the default and it means "don't change - * the comment". An empty comment removes the original comment. - * - * \sa open() - **/ - void setComment(const QString& comment); - /// Sets the current file to the first file in the archive. - /** Returns \c true on success, \c false otherwise. Call - * getZipError() to get the error code. - **/ - bool goToFirstFile(); - /// Sets the current file to the next file in the archive. - /** Returns \c true on success, \c false otherwise. Call - * getZipError() to determine if there was an error. - * - * Should be used only in QuaZip::mdUnzip mode. - * - * \note If the end of file was reached, getZipError() will return - * \c UNZ_OK instead of \c UNZ_END_OF_LIST_OF_FILE. This is to make - * things like this easier: - * \code - * for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) { - * // do something - * } - * if(zip.getZipError()==UNZ_OK) { - * // ok, there was no error - * } - * \endcode - **/ - bool goToNextFile(); - /// Sets current file by its name. - /** Returns \c true if successful, \c false otherwise. Argument \a - * cs specifies case sensitivity of the file name. Call - * getZipError() in the case of a failure to get error code. - * - * This is not a wrapper to unzLocateFile() function. That is - * because I had to implement locale-specific case-insensitive - * comparison. - * - * Here are the differences from the original implementation: - * - * - If the file was not found, error code is \c UNZ_OK, not \c - * UNZ_END_OF_LIST_OF_FILE (see also goToNextFile()). - * - If this function fails, it unsets the current file rather than - * resetting it back to what it was before the call. - * - * If \a fileName is null string then this function unsets the - * current file and return \c true. Note that you should close the - * file first if it is open! See - * QuaZipFile::QuaZipFile(QuaZip*,QObject*) for the details. - * - * Should be used only in QuaZip::mdUnzip mode. - * - * \sa setFileNameCodec(), CaseSensitivity - **/ - bool setCurrentFile(const QString& fileName, CaseSensitivity cs =csDefault); - /// Returns \c true if the current file has been set. - bool hasCurrentFile() const; - /// Retrieves information about the current file. - /** Fills the structure pointed by \a info. Returns \c true on - * success, \c false otherwise. In the latter case structure pointed - * by \a info remains untouched. If there was an error, - * getZipError() returns error code. - * - * Should be used only in QuaZip::mdUnzip mode. - * - * Does nothing and returns \c false in any of the following cases. - * - ZIP is not open; - * - ZIP does not have current file. - * - * In both cases getZipError() returns \c UNZ_OK since there - * is no ZIP/UNZIP API call. - * - * This overload doesn't support zip64, but will work OK on zip64 archives - * except that if one of the sizes (compressed or uncompressed) is greater - * than 0xFFFFFFFFu, it will be set to exactly 0xFFFFFFFFu. - * - * \sa getCurrentFileInfo(QuaZipFileInfo64* info)const - * \sa QuaZipFileInfo64::toQuaZipFileInfo(QuaZipFileInfo&)const - **/ - bool getCurrentFileInfo(QuaZipFileInfo* info)const; - /// Retrieves information about the current file. - /** \overload - * - * This function supports zip64. If the archive doesn't use zip64, it is - * completely equivalent to getCurrentFileInfo(QuaZipFileInfo* info) - * except for the argument type. - * - * \sa - **/ - bool getCurrentFileInfo(QuaZipFileInfo64* info)const; - /// Returns the current file name. - /** Equivalent to calling getCurrentFileInfo() and then getting \c - * name field of the QuaZipFileInfo structure, but faster and more - * convenient. - * - * Should be used only in QuaZip::mdUnzip mode. - **/ - QString getCurrentFileName()const; - /// Returns \c unzFile handle. - /** You can use this handle to directly call UNZIP part of the - * ZIP/UNZIP package functions (see unzip.h). - * - * \warning When using the handle returned by this function, please - * keep in mind that QuaZip class is unable to detect any changes - * you make in the ZIP file state (e. g. changing current file, or - * closing the handle). So please do not do anything with this - * handle that is possible to do with the functions of this class. - * Or at least return the handle in the original state before - * calling some another function of this class (including implicit - * destructor calls and calls from the QuaZipFile objects that refer - * to this QuaZip instance!). So if you have changed the current - * file in the ZIP archive - then change it back or you may - * experience some strange behavior or even crashes. - **/ - unzFile getUnzFile(); - /// Returns \c zipFile handle. - /** You can use this handle to directly call ZIP part of the - * ZIP/UNZIP package functions (see zip.h). Warnings about the - * getUnzFile() function also apply to this function. - **/ - zipFile getZipFile(); - /// Changes the data descriptor writing mode. - /** - According to the ZIP format specification, a file inside archive - may have a data descriptor immediately following the file - data. This is reflected by a special flag in the local file header - and in the central directory. By default, QuaZIP sets this flag - and writes the data descriptor unless both method and level were - set to 0, in which case it operates in 1.0-compatible mode and - never writes data descriptors. - - By setting this flag to false, it is possible to disable data - descriptor writing, thus increasing compatibility with archive - readers that don't understand this feature of the ZIP file format. - - Setting this flag affects all the QuaZipFile instances that are - opened after this flag is set. - - The data descriptor writing mode is enabled by default. - - Note that if the ZIP archive is written into a QIODevice for which - QIODevice::isSequential() returns \c true, then the data descriptor - is mandatory and will be written even if this flag is set to false. - - \param enabled If \c true, enable local descriptor writing, - disable it otherwise. - - \sa QuaZipFile::isDataDescriptorWritingEnabled() - */ - void setDataDescriptorWritingEnabled(bool enabled); - /// Returns the data descriptor default writing mode. - /** - \sa setDataDescriptorWritingEnabled() - */ - bool isDataDescriptorWritingEnabled() const; - /// Returns a list of files inside the archive. - /** - \return A list of file names or an empty list if there - was an error or if the archive is empty (call getZipError() to - figure out which). - \sa getFileInfoList() - */ - QStringList getFileNameList() const; - /// Returns information list about all files inside the archive. - /** - \return A list of QuaZipFileInfo objects or an empty list if there - was an error or if the archive is empty (call getZipError() to - figure out which). - - This function doesn't support zip64, but will still work with zip64 - archives, converting results using QuaZipFileInfo64::toQuaZipFileInfo(). - If all file sizes are below 4 GB, it will work just fine. - - \sa getFileNameList() - \sa getFileInfoList64() - */ - QList getFileInfoList() const; - /// Returns information list about all files inside the archive. - /** - \overload - - This function supports zip64. - - \sa getFileNameList() - \sa getFileInfoList() - */ - QList getFileInfoList64() const; - /// Enables the zip64 mode. - /** - * @param zip64 If \c true, the zip64 mode is enabled, disabled otherwise. - * - * Once this is enabled, all new files (until the mode is disabled again) - * will be created in the zip64 mode, thus enabling the ability to write - * files larger than 4 GB. By default, the zip64 mode is off due to - * compatibility reasons. - * - * Note that this does not affect the ability to read zip64 archives in any - * way. - * - * \sa isZip64Enabled() - */ - void setZip64Enabled(bool zip64); - /// Returns whether the zip64 mode is enabled. - /** - * @return \c true if and only if the zip64 mode is enabled. - * - * \sa setZip64Enabled() - */ - bool isZip64Enabled() const; - /// Returns the auto-close flag. - /** - @sa setAutoClose() - */ - bool isAutoClose() const; - /// Sets or unsets the auto-close flag. - /** - By default, QuaZIP opens the underlying QIODevice when open() is called, - and closes it when close() is called. In some cases, when the device - is set explicitly using setIoDevice(), it may be desirable to - leave the device open. If the auto-close flag is unset using this method, - then the device isn't closed automatically if it was set explicitly. - - If it is needed to clear this flag, it is recommended to do so before - opening the archive because otherwise QuaZIP may close the device - during the open() call if an error is encountered after the device - is opened. - - If the device was not set explicitly, but rather the setZipName() or - the appropriate constructor was used to set the ZIP file name instead, - then the auto-close flag has no effect, and the internal device - is closed nevertheless because there is no other way to close it. - - @sa isAutoClose() - @sa setIoDevice() - */ - void setAutoClose(bool autoClose) const; - /// Sets the default file name codec to use. - /** - * The default codec is used by the constructors, so calling this function - * won't affect the QuaZip instances already created at that moment. - * - * The codec specified here can be overriden by calling setFileNameCodec(). - * If neither function is called, QTextCodec::codecForLocale() will be used - * to decode or encode file names. Use this function with caution if - * the application uses other libraries that depend on QuaZIP. Those - * libraries can either call this function by themselves, thus overriding - * your setting or can rely on the default encoding, thus failing - * mysteriously if you change it. For these reasons, it isn't recommended - * to use this function if you are developing a library, not an application. - * Instead, ask your library users to call it in case they need specific - * encoding. - * - * In most cases, using setFileNameCodec() instead is the right choice. - * However, if you depend on third-party code that uses QuaZIP, then the - * reasons stated above can actually become a reason to use this function - * in case the third-party code in question fails because it doesn't - * understand the encoding you need and doesn't provide a way to specify it. - * This applies to the JlCompress class as well, as it was contributed and - * doesn't support explicit encoding parameters. - * - * In short: use setFileNameCodec() when you can, resort to - * setDefaultFileNameCodec() when you don't have access to the QuaZip - * instance. - * - * @param codec The codec to use by default. If NULL, resets to default. - */ - static void setDefaultFileNameCodec(QTextCodec *codec); - /** - * @overload - * Equivalent to calling - * setDefltFileNameCodec(QTextCodec::codecForName(codecName)). - */ - static void setDefaultFileNameCodec(const char *codecName); -}; - -#endif diff --git a/src/3rdParty/quazip-0.7.3/quazip/quazip.pri b/src/3rdParty/quazip-0.7.3/quazip/quazip.pri deleted file mode 100644 index 1a9db99b7..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quazip.pri +++ /dev/null @@ -1,33 +0,0 @@ -INCLUDEPATH += $$PWD -DEPENDPATH += $$PWD -HEADERS += \ - $$PWD/crypt.h \ - $$PWD/ioapi.h \ - $$PWD/JlCompress.h \ - $$PWD/quaadler32.h \ - $$PWD/quachecksum32.h \ - $$PWD/quacrc32.h \ - $$PWD/quagzipfile.h \ - $$PWD/quaziodevice.h \ - $$PWD/quazipdir.h \ - $$PWD/quazipfile.h \ - $$PWD/quazipfileinfo.h \ - $$PWD/quazip_global.h \ - $$PWD/quazip.h \ - $$PWD/quazipnewinfo.h \ - $$PWD/unzip.h \ - $$PWD/zip.h - -SOURCES += $$PWD/qioapi.cpp \ - $$PWD/JlCompress.cpp \ - $$PWD/quaadler32.cpp \ - $$PWD/quacrc32.cpp \ - $$PWD/quagzipfile.cpp \ - $$PWD/quaziodevice.cpp \ - $$PWD/quazip.cpp \ - $$PWD/quazipdir.cpp \ - $$PWD/quazipfile.cpp \ - $$PWD/quazipfileinfo.cpp \ - $$PWD/quazipnewinfo.cpp \ - $$PWD/unzip.c \ - $$PWD/zip.c diff --git a/src/3rdParty/quazip-0.7.3/quazip/quazip.pro b/src/3rdParty/quazip-0.7.3/quazip/quazip.pro deleted file mode 100644 index 3e10f3690..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quazip.pro +++ /dev/null @@ -1,87 +0,0 @@ -TEMPLATE = lib -CONFIG += qt warn_on -QT -= gui - -# The ABI version. - -!win32:VERSION = 1.0.0 - -# 1.0.0 is the first stable ABI. -# The next binary incompatible change will be 2.0.0 and so on. -# The existing QuaZIP policy on changing ABI requires to bump the -# major version of QuaZIP itself as well. Note that there may be -# other reasons for chaging the major version of QuaZIP, so -# in case where there is a QuaZIP major version bump but no ABI change, -# the VERSION variable will stay the same. - -# For example: - -# QuaZIP 1.0 is released after some 0.x, keeping binary compatibility. -# VERSION stays 1.0.0. -# Then some binary incompatible change is introduced. QuaZIP goes up to -# 2.0, VERSION to 2.0.0. -# And so on. - - -# This one handles dllimport/dllexport directives. -DEFINES += QUAZIP_BUILD - -# You'll need to define this one manually if using a build system other -# than qmake or using QuaZIP sources directly in your project. -CONFIG(staticlib): DEFINES += QUAZIP_STATIC - -# Input -include(quazip.pri) - - -CONFIG(debug, debug|release) { - mac: TARGET = $$join(TARGET,,,_debug) - win32: TARGET = $$join(TARGET,,,d) -} - -unix:!symbian { - headers.path=$$PREFIX/include/quazip - headers.files=$$HEADERS - target.path=$$PREFIX/lib/$${LIB_ARCH} - INSTALLS += headers target - - OBJECTS_DIR=.obj - MOC_DIR=.moc - -} - -win32 { - headers.path=$$PREFIX/include/quazip - headers.files=$$HEADERS - target.path=$$PREFIX/lib - INSTALLS += headers target - # workaround for qdatetime.h macro bug - DEFINES += NOMINMAX -} - - -symbian { - - # Note, on Symbian you may run into troubles with LGPL. - # The point is, if your application uses some version of QuaZip, - # and a newer binary compatible version of QuaZip is released, then - # the users of your application must be able to relink it with the - # new QuaZip version. For example, to take advantage of some QuaZip - # bug fixes. - - # This is probably best achieved by building QuaZip as a static - # library and providing linkable object files of your application, - # so users can relink it. - - CONFIG += staticlib - CONFIG += debug_and_release - - LIBS += -lezip - - #Export headers to SDK Epoc32/include directory - exportheaders.sources = $$HEADERS - exportheaders.path = quazip - for(header, exportheaders.sources) { - BLD_INF_RULES.prj_exports += "$$header $$exportheaders.path/$$basename(header)" - } -} diff --git a/src/3rdParty/quazip-0.7.3/quazip/quazip.sln b/src/3rdParty/quazip-0.7.3/quazip/quazip.sln deleted file mode 100644 index 549f3a453..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quazip.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual C++ Express 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "quazip", "quazip.vcproj", "{E4AC5F56-B711-4F0E-BC83-CDE8B6CD53AD}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E4AC5F56-B711-4F0E-BC83-CDE8B6CD53AD}.Debug|Win32.ActiveCfg = Debug|Win32 - {E4AC5F56-B711-4F0E-BC83-CDE8B6CD53AD}.Debug|Win32.Build.0 = Debug|Win32 - {E4AC5F56-B711-4F0E-BC83-CDE8B6CD53AD}.Release|Win32.ActiveCfg = Release|Win32 - {E4AC5F56-B711-4F0E-BC83-CDE8B6CD53AD}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/src/3rdParty/quazip-0.7.3/quazip/quazip.vcproj b/src/3rdParty/quazip-0.7.3/quazip/quazip.vcproj deleted file mode 100644 index 803400756..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quazip.vcproj +++ /dev/null @@ -1,314 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/3rdParty/quazip-0.7.3/quazip/quazip.vcxproj b/src/3rdParty/quazip-0.7.3/quazip/quazip.vcxproj deleted file mode 100644 index 8f331e675..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quazip.vcxproj +++ /dev/null @@ -1,183 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {E4AC5F56-B711-4F0E-BC83-CDE8B6CD53AD} - Win32Proj - - - - DynamicLibrary - v120 - - - DynamicLibrary - v120 - - - DynamicLibrary - v120 - - - DynamicLibrary - v120 - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - Debug\ - Debug\ - true - true - Release\ - Release\ - true - true - - - - Disabled - WIN32;_DEBUG;_WINDOWS;QUAZIP_BUILD;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - EditAndContinue - - - QtCored4.lib;%(AdditionalDependencies) - true - Windows - MachineX86 - - - - - Disabled - WIN32;_DEBUG;_WINDOWS;QUAZIP_BUILD;%(PreprocessorDefinitions) - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - ProgramDatabase - - - QtCored4.lib;%(AdditionalDependencies) - true - Windows - - - - - WIN32;NDEBUG;_WINDOWS;QUAZIP_BUILD;%(PreprocessorDefinitions) - MultiThreadedDLL - - - Level3 - ProgramDatabase - - - Qt5Core.lib;%(AdditionalDependencies) - true - Windows - true - true - MachineX86 - - - - - WIN32;NDEBUG;_WINDOWS;QUAZIP_BUILD;%(PreprocessorDefinitions) - MultiThreadedDLL - - - Level3 - ProgramDatabase - - - Qt5Core.lib;zlibwapi.lib;%(AdditionalDependencies) - true - Windows - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/3rdParty/quazip-0.7.3/quazip/quazip.vcxproj.filters b/src/3rdParty/quazip-0.7.3/quazip/quazip.vcxproj.filters deleted file mode 100644 index 68677d576..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quazip.vcxproj.filters +++ /dev/null @@ -1,117 +0,0 @@ - - - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header 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/src/3rdParty/quazip-0.7.3/quazip/quazip_global.h b/src/3rdParty/quazip-0.7.3/quazip/quazip_global.h deleted file mode 100644 index 7e3798afc..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quazip_global.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef QUAZIP_GLOBAL_H -#define QUAZIP_GLOBAL_H - -/* -Copyright (C) 2005-2014 Sergey A. Tachenov - -This file is part of QuaZIP. - -QuaZIP is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 of the License, or -(at your option) any later version. - -QuaZIP is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with QuaZIP. If not, see . - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant and contributors, -see quazip/(un)zip.h files for details. Basically it's the zlib license. -*/ - -#include - -/** - This is automatically defined when building a static library, but when - including QuaZip sources directly into a project, QUAZIP_STATIC should - be defined explicitly to avoid possible troubles with unnecessary - importing/exporting. - */ -#ifdef QUAZIP_STATIC -#define QUAZIP_EXPORT -#else -/** - * When building a DLL with MSVC, QUAZIP_BUILD must be defined. - * qglobal.h takes care of defining Q_DECL_* correctly for msvc/gcc. - */ -#if defined(QUAZIP_BUILD) - #define QUAZIP_EXPORT Q_DECL_EXPORT -#else - #define QUAZIP_EXPORT Q_DECL_IMPORT -#endif -#endif // QUAZIP_STATIC - -#ifdef __GNUC__ -#define UNUSED __attribute__((__unused__)) -#else -#define UNUSED -#endif - -#define QUAZIP_EXTRA_NTFS_MAGIC 0x000Au -#define QUAZIP_EXTRA_NTFS_TIME_MAGIC 0x0001u - -#endif // QUAZIP_GLOBAL_H diff --git a/src/3rdParty/quazip-0.7.3/quazip/quazipdir.cpp b/src/3rdParty/quazip-0.7.3/quazip/quazipdir.cpp deleted file mode 100644 index 5ae08a023..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quazipdir.cpp +++ /dev/null @@ -1,567 +0,0 @@ -/* -Copyright (C) 2005-2014 Sergey A. Tachenov - -This file is part of QuaZIP. - -QuaZIP is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 of the License, or -(at your option) any later version. - -QuaZIP is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with QuaZIP. If not, see . - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant and contributors, -see quazip/(un)zip.h files for details. Basically it's the zlib license. -*/ - -#include "quazipdir.h" - -#include -#include - -/// \cond internal -class QuaZipDirPrivate: public QSharedData { - friend class QuaZipDir; -private: - QuaZipDirPrivate(QuaZip *zip, const QString &dir = QString()): - zip(zip), dir(dir), caseSensitivity(QuaZip::csDefault), - filter(QDir::NoFilter), sorting(QDir::NoSort) {} - QuaZip *zip; - QString dir; - QuaZip::CaseSensitivity caseSensitivity; - QDir::Filters filter; - QStringList nameFilters; - QDir::SortFlags sorting; - template - bool entryInfoList(QStringList nameFilters, QDir::Filters filter, - QDir::SortFlags sort, TFileInfoList &result) const; - inline QString simplePath() const {return QDir::cleanPath(dir);} -}; -/// \endcond - -QuaZipDir::QuaZipDir(const QuaZipDir &that): - d(that.d) -{ -} - -QuaZipDir::QuaZipDir(QuaZip *zip, const QString &dir): - d(new QuaZipDirPrivate(zip, dir)) -{ - if (d->dir.startsWith('/')) - d->dir = d->dir.mid(1); -} - -QuaZipDir::~QuaZipDir() -{ -} - -bool QuaZipDir::operator==(const QuaZipDir &that) -{ - return d->zip == that.d->zip && d->dir == that.d->dir; -} - -QuaZipDir& QuaZipDir::operator=(const QuaZipDir &that) -{ - this->d = that.d; - return *this; -} - -QString QuaZipDir::operator[](int pos) const -{ - return entryList().at(pos); -} - -QuaZip::CaseSensitivity QuaZipDir::caseSensitivity() const -{ - return d->caseSensitivity; -} - -bool QuaZipDir::cd(const QString &directoryName) -{ - if (directoryName == "/") { - d->dir = ""; - return true; - } - QString dirName = directoryName; - if (dirName.endsWith('/')) - dirName.chop(1); - if (dirName.contains('/')) { - QuaZipDir dir(*this); - if (dirName.startsWith('/')) { -#ifdef QUAZIP_QUAZIPDIR_DEBUG - qDebug("QuaZipDir::cd(%s): going to /", - dirName.toUtf8().constData()); -#endif - if (!dir.cd("/")) - return false; - } - QStringList path = dirName.split('/', QString::SkipEmptyParts); - for (QStringList::const_iterator i = path.constBegin(); - i != path.end(); - ++i) { - const QString &step = *i; -#ifdef QUAZIP_QUAZIPDIR_DEBUG - qDebug("QuaZipDir::cd(%s): going to %s", - dirName.toUtf8().constData(), - step.toUtf8().constData()); -#endif - if (!dir.cd(step)) - return false; - } - d->dir = dir.path(); - return true; - } else { // no '/' - if (dirName == ".") { - return true; - } else if (dirName == "..") { - if (isRoot()) { - return false; - } else { - int slashPos = d->dir.lastIndexOf('/'); - if (slashPos == -1) { - d->dir = ""; - } else { - d->dir = d->dir.left(slashPos); - } - return true; - } - } else { // a simple subdirectory - if (exists(dirName)) { - if (isRoot()) - d->dir = dirName; - else - d->dir += "/" + dirName; - return true; - } else { - return false; - } - } - } -} - -bool QuaZipDir::cdUp() -{ - return cd(".."); -} - -uint QuaZipDir::count() const -{ - return entryList().count(); -} - -QString QuaZipDir::dirName() const -{ - return QDir(d->dir).dirName(); -} - -QuaZipFileInfo64 QuaZipDir_getFileInfo(QuaZip *zip, bool *ok, - const QString &relativeName, - bool isReal) -{ - QuaZipFileInfo64 info; - if (isReal) { - *ok = zip->getCurrentFileInfo(&info); - } else { - *ok = true; - info.compressedSize = 0; - info.crc = 0; - info.diskNumberStart = 0; - info.externalAttr = 0; - info.flags = 0; - info.internalAttr = 0; - info.method = 0; - info.uncompressedSize = 0; - info.versionCreated = info.versionNeeded = 0; - } - info.name = relativeName; - return info; -} - -static void QuaZipDir_convertInfoList(const QList &from, - QList &to) -{ - to = from; -} - -static void QuaZipDir_convertInfoList(const QList &from, - QStringList &to) -{ - to.clear(); - for (QList::const_iterator i = from.constBegin(); - i != from.constEnd(); - ++i) { - to.append(i->name); - } -} - -static void QuaZipDir_convertInfoList(const QList &from, - QList &to) -{ - to.clear(); - for (QList::const_iterator i = from.constBegin(); - i != from.constEnd(); - ++i) { - QuaZipFileInfo info32; - i->toQuaZipFileInfo(info32); - to.append(info32); - } -} - -/// \cond internal -/** - An utility class to restore the current file. - */ -class QuaZipDirRestoreCurrent { -public: - inline QuaZipDirRestoreCurrent(QuaZip *zip): - zip(zip), currentFile(zip->getCurrentFileName()) {} - inline ~QuaZipDirRestoreCurrent() - { - zip->setCurrentFile(currentFile); - } -private: - QuaZip *zip; - QString currentFile; -}; -/// \endcond - -/// \cond internal -class QuaZipDirComparator -{ - private: - QDir::SortFlags sort; - static QString getExtension(const QString &name); - int compareStrings(const QString &string1, const QString &string2); - public: - inline QuaZipDirComparator(QDir::SortFlags sort): sort(sort) {} - bool operator()(const QuaZipFileInfo64 &info1, const QuaZipFileInfo64 &info2); -}; - -QString QuaZipDirComparator::getExtension(const QString &name) -{ - if (name.endsWith('.') || name.indexOf('.', 1) == -1) { - return ""; - } else { - return name.mid(name.lastIndexOf('.') + 1); - } - -} - -int QuaZipDirComparator::compareStrings(const QString &string1, - const QString &string2) -{ - if (sort & QDir::LocaleAware) { - if (sort & QDir::IgnoreCase) { - return string1.toLower().localeAwareCompare(string2.toLower()); - } else { - return string1.localeAwareCompare(string2); - } - } else { - return string1.compare(string2, (sort & QDir::IgnoreCase) - ? Qt::CaseInsensitive : Qt::CaseSensitive); - } -} - -bool QuaZipDirComparator::operator()(const QuaZipFileInfo64 &info1, - const QuaZipFileInfo64 &info2) -{ - QDir::SortFlags order = sort - & (QDir::Name | QDir::Time | QDir::Size | QDir::Type); - if ((sort & QDir::DirsFirst) == QDir::DirsFirst - || (sort & QDir::DirsLast) == QDir::DirsLast) { - if (info1.name.endsWith('/') && !info2.name.endsWith('/')) - return (sort & QDir::DirsFirst) == QDir::DirsFirst; - else if (!info1.name.endsWith('/') && info2.name.endsWith('/')) - return (sort & QDir::DirsLast) == QDir::DirsLast; - } - bool result; - int extDiff; - switch (order) { - case QDir::Name: - result = compareStrings(info1.name, info2.name) < 0; - break; - case QDir::Type: - extDiff = compareStrings(getExtension(info1.name), - getExtension(info2.name)); - if (extDiff == 0) { - result = compareStrings(info1.name, info2.name) < 0; - } else { - result = extDiff < 0; - } - break; - case QDir::Size: - if (info1.uncompressedSize == info2.uncompressedSize) { - result = compareStrings(info1.name, info2.name) < 0; - } else { - result = info1.uncompressedSize < info2.uncompressedSize; - } - break; - case QDir::Time: - if (info1.dateTime == info2.dateTime) { - result = compareStrings(info1.name, info2.name) < 0; - } else { - result = info1.dateTime < info2.dateTime; - } - break; - default: - qWarning("QuaZipDirComparator(): Invalid sort mode 0x%2X", - static_cast(sort)); - return false; - } - return (sort & QDir::Reversed) ? !result : result; -} - -template -bool QuaZipDirPrivate::entryInfoList(QStringList nameFilters, - QDir::Filters filter, QDir::SortFlags sort, TFileInfoList &result) const -{ - QString basePath = simplePath(); - if (!basePath.isEmpty()) - basePath += "/"; - int baseLength = basePath.length(); - result.clear(); - QuaZipDirRestoreCurrent saveCurrent(zip); - if (!zip->goToFirstFile()) { - return zip->getZipError() == UNZ_OK; - } - QDir::Filters fltr = filter; - if (fltr == QDir::NoFilter) - fltr = this->filter; - if (fltr == QDir::NoFilter) - fltr = QDir::AllEntries; - QStringList nmfltr = nameFilters; - if (nmfltr.isEmpty()) - nmfltr = this->nameFilters; - QSet dirsFound; - QList list; - do { - QString name = zip->getCurrentFileName(); - if (!name.startsWith(basePath)) - continue; - QString relativeName = name.mid(baseLength); - if (relativeName.isEmpty()) - continue; - bool isDir = false; - bool isReal = true; - if (relativeName.contains('/')) { - int indexOfSlash = relativeName.indexOf('/'); - // something like "subdir/" - isReal = indexOfSlash == relativeName.length() - 1; - relativeName = relativeName.left(indexOfSlash + 1); - if (dirsFound.contains(relativeName)) - continue; - isDir = true; - } - dirsFound.insert(relativeName); - if ((fltr & QDir::Dirs) == 0 && isDir) - continue; - if ((fltr & QDir::Files) == 0 && !isDir) - continue; - if (!nmfltr.isEmpty() && !QDir::match(nmfltr, relativeName)) - continue; - bool ok; - QuaZipFileInfo64 info = QuaZipDir_getFileInfo(zip, &ok, relativeName, - isReal); - if (!ok) { - return false; - } - list.append(info); - } while (zip->goToNextFile()); - QDir::SortFlags srt = sort; - if (srt == QDir::NoSort) - srt = sorting; -#ifdef QUAZIP_QUAZIPDIR_DEBUG - qDebug("QuaZipDirPrivate::entryInfoList(): before sort:"); - foreach (QuaZipFileInfo64 info, list) { - qDebug("%s\t%s", info.name.toUtf8().constData(), - info.dateTime.toString(Qt::ISODate).toUtf8().constData()); - } -#endif - if (srt != QDir::NoSort && (srt & QDir::Unsorted) != QDir::Unsorted) { - if (QuaZip::convertCaseSensitivity(caseSensitivity) - == Qt::CaseInsensitive) - srt |= QDir::IgnoreCase; - QuaZipDirComparator lessThan(srt); - qSort(list.begin(), list.end(), lessThan); - } - QuaZipDir_convertInfoList(list, result); - return true; -} - -/// \endcond - -QList QuaZipDir::entryInfoList(const QStringList &nameFilters, - QDir::Filters filters, QDir::SortFlags sort) const -{ - QList result; - if (d->entryInfoList(nameFilters, filters, sort, result)) - return result; - else - return QList(); -} - -QList QuaZipDir::entryInfoList(QDir::Filters filters, - QDir::SortFlags sort) const -{ - return entryInfoList(QStringList(), filters, sort); -} - -QList QuaZipDir::entryInfoList64(const QStringList &nameFilters, - QDir::Filters filters, QDir::SortFlags sort) const -{ - QList result; - if (d->entryInfoList(nameFilters, filters, sort, result)) - return result; - else - return QList(); -} - -QList QuaZipDir::entryInfoList64(QDir::Filters filters, - QDir::SortFlags sort) const -{ - return entryInfoList64(QStringList(), filters, sort); -} - -QStringList QuaZipDir::entryList(const QStringList &nameFilters, - QDir::Filters filters, QDir::SortFlags sort) const -{ - QStringList result; - if (d->entryInfoList(nameFilters, filters, sort, result)) - return result; - else - return QStringList(); -} - -QStringList QuaZipDir::entryList(QDir::Filters filters, - QDir::SortFlags sort) const -{ - return entryList(QStringList(), filters, sort); -} - -bool QuaZipDir::exists(const QString &filePath) const -{ - if (filePath == "/" || filePath.isEmpty()) - return true; - QString fileName = filePath; - if (fileName.endsWith('/')) - fileName.chop(1); - if (fileName.contains('/')) { - QFileInfo fileInfo(fileName); -#ifdef QUAZIP_QUAZIPDIR_DEBUG - qDebug("QuaZipDir::exists(): fileName=%s, fileInfo.fileName()=%s, " - "fileInfo.path()=%s", fileName.toUtf8().constData(), - fileInfo.fileName().toUtf8().constData(), - fileInfo.path().toUtf8().constData()); -#endif - QuaZipDir dir(*this); - return dir.cd(fileInfo.path()) && dir.exists(fileInfo.fileName()); - } else { - if (fileName == "..") { - return !isRoot(); - } else if (fileName == ".") { - return true; - } else { - QStringList entries = entryList(QDir::AllEntries, QDir::NoSort); -#ifdef QUAZIP_QUAZIPDIR_DEBUG - qDebug("QuaZipDir::exists(): looking for %s", - fileName.toUtf8().constData()); - for (QStringList::const_iterator i = entries.constBegin(); - i != entries.constEnd(); - ++i) { - qDebug("QuaZipDir::exists(): entry: %s", - i->toUtf8().constData()); - } -#endif - Qt::CaseSensitivity cs = QuaZip::convertCaseSensitivity( - d->caseSensitivity); - if (filePath.endsWith('/')) { - return entries.contains(filePath, cs); - } else { - return entries.contains(fileName, cs) - || entries.contains(fileName + "/", cs); - } - } - } -} - -bool QuaZipDir::exists() const -{ - return QuaZipDir(d->zip).exists(d->dir); -} - -QString QuaZipDir::filePath(const QString &fileName) const -{ - return QDir(d->dir).filePath(fileName); -} - -QDir::Filters QuaZipDir::filter() -{ - return d->filter; -} - -bool QuaZipDir::isRoot() const -{ - return d->simplePath().isEmpty(); -} - -QStringList QuaZipDir::nameFilters() const -{ - return d->nameFilters; -} - -QString QuaZipDir::path() const -{ - return d->dir; -} - -QString QuaZipDir::relativeFilePath(const QString &fileName) const -{ - return QDir("/" + d->dir).relativeFilePath(fileName); -} - -void QuaZipDir::setCaseSensitivity(QuaZip::CaseSensitivity caseSensitivity) -{ - d->caseSensitivity = caseSensitivity; -} - -void QuaZipDir::setFilter(QDir::Filters filters) -{ - d->filter = filters; -} - -void QuaZipDir::setNameFilters(const QStringList &nameFilters) -{ - d->nameFilters = nameFilters; -} - -void QuaZipDir::setPath(const QString &path) -{ - QString newDir = path; - if (newDir == "/") { - d->dir = ""; - } else { - if (newDir.endsWith('/')) - newDir.chop(1); - if (newDir.startsWith('/')) - newDir = newDir.mid(1); - d->dir = newDir; - } -} - -void QuaZipDir::setSorting(QDir::SortFlags sort) -{ - d->sorting = sort; -} - -QDir::SortFlags QuaZipDir::sorting() const -{ - return d->sorting; -} diff --git a/src/3rdParty/quazip-0.7.3/quazip/quazipdir.h b/src/3rdParty/quazip-0.7.3/quazip/quazipdir.h deleted file mode 100644 index 4626b1718..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quazipdir.h +++ /dev/null @@ -1,223 +0,0 @@ -#ifndef QUAZIP_QUAZIPDIR_H -#define QUAZIP_QUAZIPDIR_H - -/* -Copyright (C) 2005-2014 Sergey A. Tachenov - -This file is part of QuaZIP. - -QuaZIP is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 of the License, or -(at your option) any later version. - -QuaZIP is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with QuaZIP. If not, see . - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant and contributors, -see quazip/(un)zip.h files for details. Basically it's the zlib license. -*/ - -class QuaZipDirPrivate; - -#include "quazip.h" -#include "quazipfileinfo.h" -#include -#include -#include - -/// Provides ZIP archive navigation. -/** -* This class is modelled after QDir, and is designed to provide similar -* features for ZIP archives. -* -* The only significant difference from QDir is that the root path is not -* '/', but an empty string since that's how the file paths are stored in -* the archive. However, QuaZipDir understands the paths starting with -* '/'. It is important in a few places: -* -* - In the cd() function. -* - In the constructor. -* - In the exists() function. -* - In the relativePath() function. -* -* Note that since ZIP uses '/' on all platforms, the '\' separator is -* not supported. -*/ -class QUAZIP_EXPORT QuaZipDir { -private: - QSharedDataPointer d; -public: - /// The copy constructor. - QuaZipDir(const QuaZipDir &that); - /// Constructs a QuaZipDir instance pointing to the specified directory. - /** - If \a dir is not specified, points to the root of the archive. - The same happens if the \a dir is "/". - */ - QuaZipDir(QuaZip *zip, const QString &dir = QString()); - /// Destructor. - ~QuaZipDir(); - /// The assignment operator. - bool operator==(const QuaZipDir &that); - /// operator!= - /** - \return \c true if either this and \a that use different QuaZip - instances or if they point to different directories. - */ - inline bool operator!=(const QuaZipDir &that) {return !operator==(that);} - /// operator== - /** - \return \c true if both this and \a that use the same QuaZip - instance and point to the same directory. - */ - QuaZipDir& operator=(const QuaZipDir &that); - /// Returns the name of the entry at the specified position. - QString operator[](int pos) const; - /// Returns the current case sensitivity mode. - QuaZip::CaseSensitivity caseSensitivity() const; - /// Changes the 'current' directory. - /** - * If the path starts with '/', it is interpreted as an absolute - * path from the root of the archive. Otherwise, it is interpreted - * as a path relative to the current directory as was set by the - * previous cd() or the constructor. - * - * Note that the subsequent path() call will not return a path - * starting with '/' in all cases. - */ - bool cd(const QString &dirName); - /// Goes up. - bool cdUp(); - /// Returns the number of entries in the directory. - uint count() const; - /// Returns the current directory name. - /** - The name doesn't include the path. - */ - QString dirName() const; - /// Returns the list of the entries in the directory. - /** - \param nameFilters The list of file patterns to list, uses the same - syntax as QDir. - \param filters The entry type filters, only Files and Dirs are - accepted. - \param sort Sorting mode. - */ - QList entryInfoList(const QStringList &nameFilters, - QDir::Filters filters = QDir::NoFilter, - QDir::SortFlags sort = QDir::NoSort) const; - /// Returns the list of the entries in the directory. - /** - \overload - - The same as entryInfoList(QStringList(), filters, sort). - */ - QList entryInfoList(QDir::Filters filters = QDir::NoFilter, - QDir::SortFlags sort = QDir::NoSort) const; - /// Returns the list of the entries in the directory with zip64 support. - /** - \param nameFilters The list of file patterns to list, uses the same - syntax as QDir. - \param filters The entry type filters, only Files and Dirs are - accepted. - \param sort Sorting mode. - */ - QList entryInfoList64(const QStringList &nameFilters, - QDir::Filters filters = QDir::NoFilter, - QDir::SortFlags sort = QDir::NoSort) const; - /// Returns the list of the entries in the directory with zip64 support. - /** - \overload - - The same as entryInfoList64(QStringList(), filters, sort). - */ - QList entryInfoList64(QDir::Filters filters = QDir::NoFilter, - QDir::SortFlags sort = QDir::NoSort) const; - /// Returns the list of the entry names in the directory. - /** - The same as entryInfoList(nameFilters, filters, sort), but only - returns entry names. - */ - QStringList entryList(const QStringList &nameFilters, - QDir::Filters filters = QDir::NoFilter, - QDir::SortFlags sort = QDir::NoSort) const; - /// Returns the list of the entry names in the directory. - /** - \overload - - The same as entryList(QStringList(), filters, sort). - */ - QStringList entryList(QDir::Filters filters = QDir::NoFilter, - QDir::SortFlags sort = QDir::NoSort) const; - /// Returns \c true if the entry with the specified name exists. - /** - The ".." is considered to exist if the current directory - is not root. The "." and "/" are considered to - always exist. Paths starting with "/" are relative to - the archive root, other paths are relative to the current dir. - */ - bool exists(const QString &fileName) const; - /// Return \c true if the directory pointed by this QuaZipDir exists. - bool exists() const; - /// Returns the full path to the specified file. - /** - Doesn't check if the file actually exists. - */ - QString filePath(const QString &fileName) const; - /// Returns the default filter. - QDir::Filters filter(); - /// Returns if the QuaZipDir points to the root of the archive. - /** - Not that the root path is the empty string, not '/'. - */ - bool isRoot() const; - /// Return the default name filter. - QStringList nameFilters() const; - /// Returns the path to the current dir. - /** - The path never starts with '/', and the root path is an empty - string. - */ - QString path() const; - /// Returns the path to the specified file relative to the current dir. - /** - * This function is mostly useless, provided only for the sake of - * completeness. - * - * @param fileName The path to the file, should start with "/" - * if relative to the archive root. - * @return Path relative to the current dir. - */ - QString relativeFilePath(const QString &fileName) const; - /// Sets the default case sensitivity mode. - void setCaseSensitivity(QuaZip::CaseSensitivity caseSensitivity); - /// Sets the default filter. - void setFilter(QDir::Filters filters); - /// Sets the default name filter. - void setNameFilters(const QStringList &nameFilters); - /// Goes to the specified path. - /** - The difference from cd() is that this function never checks if the - path actually exists and doesn't use relative paths, so it's - possible to go to the root directory with setPath(""). - - Note that this function still chops the trailing and/or leading - '/' and treats a single '/' as the root path (path() will still - return an empty string). - */ - void setPath(const QString &path); - /// Sets the default sorting mode. - void setSorting(QDir::SortFlags sort); - /// Returns the default sorting mode. - QDir::SortFlags sorting() const; -}; - -#endif // QUAZIP_QUAZIPDIR_H diff --git a/src/3rdParty/quazip-0.7.3/quazip/quazipfile.cpp b/src/3rdParty/quazip-0.7.3/quazip/quazipfile.cpp deleted file mode 100644 index 3ce895a05..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quazipfile.cpp +++ /dev/null @@ -1,531 +0,0 @@ -/* -Copyright (C) 2005-2014 Sergey A. Tachenov - -This file is part of QuaZIP. - -QuaZIP is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 of the License, or -(at your option) any later version. - -QuaZIP is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with QuaZIP. If not, see . - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant, see -quazip/(un)zip.h files for details, basically it's zlib license. - **/ - -#include "quazipfile.h" - -using namespace std; - -/// The implementation class for QuaZip. -/** -\internal - -This class contains all the private stuff for the QuaZipFile class, thus -allowing to preserve binary compatibility between releases, the -technique known as the Pimpl (private implementation) idiom. -*/ -class QuaZipFilePrivate { - friend class QuaZipFile; - private: - Q_DISABLE_COPY(QuaZipFilePrivate) - /// The pointer to the associated QuaZipFile instance. - QuaZipFile *q; - /// The QuaZip object to work with. - QuaZip *zip; - /// The file name. - QString fileName; - /// Case sensitivity mode. - QuaZip::CaseSensitivity caseSensitivity; - /// Whether this file is opened in the raw mode. - bool raw; - /// Write position to keep track of. - /** - QIODevice::pos() is broken for non-seekable devices, so we need - our own position. - */ - qint64 writePos; - /// Uncompressed size to write along with a raw file. - quint64 uncompressedSize; - /// CRC to write along with a raw file. - quint32 crc; - /// Whether \ref zip points to an internal QuaZip instance. - /** - This is true if the archive was opened by name, rather than by - supplying an existing QuaZip instance. - */ - bool internal; - /// The last error. - int zipError; - /// Resets \ref zipError. - inline void resetZipError() const {setZipError(UNZ_OK);} - /// Sets the zip error. - /** - This function is marked as const although it changes one field. - This allows to call it from const functions that don't change - anything by themselves. - */ - void setZipError(int zipError) const; - /// The constructor for the corresponding QuaZipFile constructor. - inline QuaZipFilePrivate(QuaZipFile *q): - q(q), - zip(NULL), - caseSensitivity(QuaZip::csDefault), - raw(false), - writePos(0), - uncompressedSize(0), - crc(0), - internal(true), - zipError(UNZ_OK) {} - /// The constructor for the corresponding QuaZipFile constructor. - inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName): - q(q), - caseSensitivity(QuaZip::csDefault), - raw(false), - writePos(0), - uncompressedSize(0), - crc(0), - internal(true), - zipError(UNZ_OK) - { - zip=new QuaZip(zipName); - } - /// The constructor for the corresponding QuaZipFile constructor. - inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName, const QString &fileName, - QuaZip::CaseSensitivity cs): - q(q), - raw(false), - writePos(0), - uncompressedSize(0), - crc(0), - internal(true), - zipError(UNZ_OK) - { - zip=new QuaZip(zipName); - this->fileName=fileName; - if (this->fileName.startsWith('/')) - this->fileName = this->fileName.mid(1); - this->caseSensitivity=cs; - } - /// The constructor for the QuaZipFile constructor accepting a file name. - inline QuaZipFilePrivate(QuaZipFile *q, QuaZip *zip): - q(q), - zip(zip), - raw(false), - writePos(0), - uncompressedSize(0), - crc(0), - internal(false), - zipError(UNZ_OK) {} - /// The destructor. - inline ~QuaZipFilePrivate() - { - if (internal) - delete zip; - } -}; - -QuaZipFile::QuaZipFile(): - p(new QuaZipFilePrivate(this)) -{ -} - -QuaZipFile::QuaZipFile(QObject *parent): - QIODevice(parent), - p(new QuaZipFilePrivate(this)) -{ -} - -QuaZipFile::QuaZipFile(const QString& zipName, QObject *parent): - QIODevice(parent), - p(new QuaZipFilePrivate(this, zipName)) -{ -} - -QuaZipFile::QuaZipFile(const QString& zipName, const QString& fileName, - QuaZip::CaseSensitivity cs, QObject *parent): - QIODevice(parent), - p(new QuaZipFilePrivate(this, zipName, fileName, cs)) -{ -} - -QuaZipFile::QuaZipFile(QuaZip *zip, QObject *parent): - QIODevice(parent), - p(new QuaZipFilePrivate(this, zip)) -{ -} - -QuaZipFile::~QuaZipFile() -{ - if (isOpen()) - close(); - delete p; -} - -QString QuaZipFile::getZipName() const -{ - return p->zip==NULL ? QString() : p->zip->getZipName(); -} - -QuaZip *QuaZipFile::getZip() const -{ - return p->internal ? NULL : p->zip; -} - -QString QuaZipFile::getActualFileName()const -{ - p->setZipError(UNZ_OK); - if (p->zip == NULL || (openMode() & WriteOnly)) - return QString(); - QString name=p->zip->getCurrentFileName(); - if(name.isNull()) - p->setZipError(p->zip->getZipError()); - return name; -} - -void QuaZipFile::setZipName(const QString& zipName) -{ - if(isOpen()) { - qWarning("QuaZipFile::setZipName(): file is already open - can not set ZIP name"); - return; - } - if(p->zip!=NULL && p->internal) - delete p->zip; - p->zip=new QuaZip(zipName); - p->internal=true; -} - -void QuaZipFile::setZip(QuaZip *zip) -{ - if(isOpen()) { - qWarning("QuaZipFile::setZip(): file is already open - can not set ZIP"); - return; - } - if(p->zip!=NULL && p->internal) - delete p->zip; - p->zip=zip; - p->fileName=QString(); - p->internal=false; -} - -void QuaZipFile::setFileName(const QString& fileName, QuaZip::CaseSensitivity cs) -{ - if(p->zip==NULL) { - qWarning("QuaZipFile::setFileName(): call setZipName() first"); - return; - } - if(!p->internal) { - qWarning("QuaZipFile::setFileName(): should not be used when not using internal QuaZip"); - return; - } - if(isOpen()) { - qWarning("QuaZipFile::setFileName(): can not set file name for already opened file"); - return; - } - p->fileName=fileName; - if (p->fileName.startsWith('/')) - p->fileName = p->fileName.mid(1); - p->caseSensitivity=cs; -} - -void QuaZipFilePrivate::setZipError(int zipError) const -{ - QuaZipFilePrivate *fakeThis = const_cast(this); // non-const - fakeThis->zipError=zipError; - if(zipError==UNZ_OK) - q->setErrorString(QString()); - else - q->setErrorString(QuaZipFile::tr("ZIP/UNZIP API error %1").arg(zipError)); -} - -bool QuaZipFile::open(OpenMode mode) -{ - return open(mode, NULL); -} - -bool QuaZipFile::open(OpenMode mode, int *method, int *level, bool raw, const char *password) -{ - p->resetZipError(); - if(isOpen()) { - qWarning("QuaZipFile::open(): already opened"); - return false; - } - if(mode&Unbuffered) { - qWarning("QuaZipFile::open(): Unbuffered mode is not supported"); - return false; - } - if((mode&ReadOnly)&&!(mode&WriteOnly)) { - if(p->internal) { - if(!p->zip->open(QuaZip::mdUnzip)) { - p->setZipError(p->zip->getZipError()); - return false; - } - if(!p->zip->setCurrentFile(p->fileName, p->caseSensitivity)) { - p->setZipError(p->zip->getZipError()); - p->zip->close(); - return false; - } - } else { - if(p->zip==NULL) { - qWarning("QuaZipFile::open(): zip is NULL"); - return false; - } - if(p->zip->getMode()!=QuaZip::mdUnzip) { - qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d", - (int)mode, (int)p->zip->getMode()); - return false; - } - if(!p->zip->hasCurrentFile()) { - qWarning("QuaZipFile::open(): zip does not have current file"); - return false; - } - } - p->setZipError(unzOpenCurrentFile3(p->zip->getUnzFile(), method, level, (int)raw, password)); - if(p->zipError==UNZ_OK) { - setOpenMode(mode); - p->raw=raw; - return true; - } else - return false; - } - qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode); - return false; -} - -bool QuaZipFile::open(OpenMode mode, const QuaZipNewInfo& info, - const char *password, quint32 crc, - int method, int level, bool raw, - int windowBits, int memLevel, int strategy) -{ - zip_fileinfo info_z; - p->resetZipError(); - if(isOpen()) { - qWarning("QuaZipFile::open(): already opened"); - return false; - } - if((mode&WriteOnly)&&!(mode&ReadOnly)) { - if(p->internal) { - qWarning("QuaZipFile::open(): write mode is incompatible with internal QuaZip approach"); - return false; - } - if(p->zip==NULL) { - qWarning("QuaZipFile::open(): zip is NULL"); - return false; - } - if(p->zip->getMode()!=QuaZip::mdCreate&&p->zip->getMode()!=QuaZip::mdAppend&&p->zip->getMode()!=QuaZip::mdAdd) { - qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d", - (int)mode, (int)p->zip->getMode()); - return false; - } - info_z.tmz_date.tm_year=info.dateTime.date().year(); - info_z.tmz_date.tm_mon=info.dateTime.date().month() - 1; - info_z.tmz_date.tm_mday=info.dateTime.date().day(); - info_z.tmz_date.tm_hour=info.dateTime.time().hour(); - info_z.tmz_date.tm_min=info.dateTime.time().minute(); - info_z.tmz_date.tm_sec=info.dateTime.time().second(); - info_z.dosDate = 0; - info_z.internal_fa=(uLong)info.internalAttr; - info_z.external_fa=(uLong)info.externalAttr; - if (p->zip->isDataDescriptorWritingEnabled()) - zipSetFlags(p->zip->getZipFile(), ZIP_WRITE_DATA_DESCRIPTOR); - else - zipClearFlags(p->zip->getZipFile(), ZIP_WRITE_DATA_DESCRIPTOR); - p->setZipError(zipOpenNewFileInZip3_64(p->zip->getZipFile(), - p->zip->getFileNameCodec()->fromUnicode(info.name).constData(), &info_z, - info.extraLocal.constData(), info.extraLocal.length(), - info.extraGlobal.constData(), info.extraGlobal.length(), - p->zip->getCommentCodec()->fromUnicode(info.comment).constData(), - method, level, (int)raw, - windowBits, memLevel, strategy, - password, (uLong)crc, p->zip->isZip64Enabled())); - if(p->zipError==UNZ_OK) { - p->writePos=0; - setOpenMode(mode); - p->raw=raw; - if(raw) { - p->crc=crc; - p->uncompressedSize=info.uncompressedSize; - } - return true; - } else - return false; - } - qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode); - return false; -} - -bool QuaZipFile::isSequential()const -{ - return true; -} - -qint64 QuaZipFile::pos()const -{ - if(p->zip==NULL) { - qWarning("QuaZipFile::pos(): call setZipName() or setZip() first"); - return -1; - } - if(!isOpen()) { - qWarning("QuaZipFile::pos(): file is not open"); - return -1; - } - if(openMode()&ReadOnly) - // QIODevice::pos() is broken for sequential devices, - // but thankfully bytesAvailable() returns the number of - // bytes buffered, so we know how far ahead we are. - return unztell64(p->zip->getUnzFile()) - QIODevice::bytesAvailable(); - else - return p->writePos; -} - -bool QuaZipFile::atEnd()const -{ - if(p->zip==NULL) { - qWarning("QuaZipFile::atEnd(): call setZipName() or setZip() first"); - return false; - } - if(!isOpen()) { - qWarning("QuaZipFile::atEnd(): file is not open"); - return false; - } - if(openMode()&ReadOnly) - // the same problem as with pos() - return QIODevice::bytesAvailable() == 0 - && unzeof(p->zip->getUnzFile())==1; - else - return true; -} - -qint64 QuaZipFile::size()const -{ - if(!isOpen()) { - qWarning("QuaZipFile::atEnd(): file is not open"); - return -1; - } - if(openMode()&ReadOnly) - return p->raw?csize():usize(); - else - return p->writePos; -} - -qint64 QuaZipFile::csize()const -{ - unz_file_info64 info_z; - p->setZipError(UNZ_OK); - if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1; - p->setZipError(unzGetCurrentFileInfo64(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0)); - if(p->zipError!=UNZ_OK) - return -1; - return info_z.compressed_size; -} - -qint64 QuaZipFile::usize()const -{ - unz_file_info64 info_z; - p->setZipError(UNZ_OK); - if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1; - p->setZipError(unzGetCurrentFileInfo64(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0)); - if(p->zipError!=UNZ_OK) - return -1; - return info_z.uncompressed_size; -} - -bool QuaZipFile::getFileInfo(QuaZipFileInfo *info) -{ - QuaZipFileInfo64 info64; - if (getFileInfo(&info64)) { - info64.toQuaZipFileInfo(*info); - return true; - } else { - return false; - } -} - -bool QuaZipFile::getFileInfo(QuaZipFileInfo64 *info) -{ - if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return false; - p->zip->getCurrentFileInfo(info); - p->setZipError(p->zip->getZipError()); - return p->zipError==UNZ_OK; -} - -void QuaZipFile::close() -{ - p->resetZipError(); - if(p->zip==NULL||!p->zip->isOpen()) return; - if(!isOpen()) { - qWarning("QuaZipFile::close(): file isn't open"); - return; - } - if(openMode()&ReadOnly) - p->setZipError(unzCloseCurrentFile(p->zip->getUnzFile())); - else if(openMode()&WriteOnly) - if(isRaw()) p->setZipError(zipCloseFileInZipRaw64(p->zip->getZipFile(), p->uncompressedSize, p->crc)); - else p->setZipError(zipCloseFileInZip(p->zip->getZipFile())); - else { - qWarning("Wrong open mode: %d", (int)openMode()); - return; - } - if(p->zipError==UNZ_OK) setOpenMode(QIODevice::NotOpen); - else return; - if(p->internal) { - p->zip->close(); - p->setZipError(p->zip->getZipError()); - } -} - -qint64 QuaZipFile::readData(char *data, qint64 maxSize) -{ - p->setZipError(UNZ_OK); - qint64 bytesRead=unzReadCurrentFile(p->zip->getUnzFile(), data, (unsigned)maxSize); - if (bytesRead < 0) { - p->setZipError((int) bytesRead); - return -1; - } - return bytesRead; -} - -qint64 QuaZipFile::writeData(const char* data, qint64 maxSize) -{ - p->setZipError(ZIP_OK); - p->setZipError(zipWriteInFileInZip(p->zip->getZipFile(), data, (uint)maxSize)); - if(p->zipError!=ZIP_OK) return -1; - else { - p->writePos+=maxSize; - return maxSize; - } -} - -QString QuaZipFile::getFileName() const -{ - return p->fileName; -} - -QuaZip::CaseSensitivity QuaZipFile::getCaseSensitivity() const -{ - return p->caseSensitivity; -} - -bool QuaZipFile::isRaw() const -{ - return p->raw; -} - -int QuaZipFile::getZipError() const -{ - return p->zipError; -} - -qint64 QuaZipFile::bytesAvailable() const -{ - return size() - pos(); -} diff --git a/src/3rdParty/quazip-0.7.3/quazip/quazipfile.h b/src/3rdParty/quazip-0.7.3/quazip/quazipfile.h deleted file mode 100644 index e27b7a4a6..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quazipfile.h +++ /dev/null @@ -1,456 +0,0 @@ -#ifndef QUA_ZIPFILE_H -#define QUA_ZIPFILE_H - -/* -Copyright (C) 2005-2014 Sergey A. Tachenov - -This file is part of QuaZIP. - -QuaZIP is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 of the License, or -(at your option) any later version. - -QuaZIP is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with QuaZIP. If not, see . - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant, see -quazip/(un)zip.h files for details, basically it's zlib license. - **/ - -#include - -#include "quazip_global.h" -#include "quazip.h" -#include "quazipnewinfo.h" - -class QuaZipFilePrivate; - -/// A file inside ZIP archive. -/** \class QuaZipFile quazipfile.h - * This is the most interesting class. Not only it provides C++ - * interface to the ZIP/UNZIP package, but also integrates it with Qt by - * subclassing QIODevice. This makes possible to access files inside ZIP - * archive using QTextStream or QDataStream, for example. Actually, this - * is the main purpose of the whole QuaZIP library. - * - * You can either use existing QuaZip instance to create instance of - * this class or pass ZIP archive file name to this class, in which case - * it will create internal QuaZip object. See constructors' descriptions - * for details. Writing is only possible with the existing instance. - * - * Note that due to the underlying library's limitation it is not - * possible to use multiple QuaZipFile instances to open several files - * in the same archive at the same time. If you need to write to - * multiple files in parallel, then you should write to temporary files - * first, then pack them all at once when you have finished writing. If - * you need to read multiple files inside the same archive in parallel, - * you should extract them all into a temporary directory first. - * - * \section quazipfile-sequential Sequential or random-access? - * - * At the first thought, QuaZipFile has fixed size, the start and the - * end and should be therefore considered random-access device. But - * there is one major obstacle to making it random-access: ZIP/UNZIP API - * does not support seek() operation and the only way to implement it is - * through reopening the file and re-reading to the required position, - * but this is prohibitively slow. - * - * Therefore, QuaZipFile is considered to be a sequential device. This - * has advantage of availability of the ungetChar() operation (QIODevice - * does not implement it properly for non-sequential devices unless they - * support seek()). Disadvantage is a somewhat strange behaviour of the - * size() and pos() functions. This should be kept in mind while using - * this class. - * - **/ -class QUAZIP_EXPORT QuaZipFile: public QIODevice { - friend class QuaZipFilePrivate; - Q_OBJECT - private: - QuaZipFilePrivate *p; - // these are not supported nor implemented - QuaZipFile(const QuaZipFile& that); - QuaZipFile& operator=(const QuaZipFile& that); - protected: - /// Implementation of the QIODevice::readData(). - qint64 readData(char *data, qint64 maxSize); - /// Implementation of the QIODevice::writeData(). - qint64 writeData(const char *data, qint64 maxSize); - public: - /// Constructs a QuaZipFile instance. - /** You should use setZipName() and setFileName() or setZip() before - * trying to call open() on the constructed object. - **/ - QuaZipFile(); - /// Constructs a QuaZipFile instance. - /** \a parent argument specifies this object's parent object. - * - * You should use setZipName() and setFileName() or setZip() before - * trying to call open() on the constructed object. - **/ - QuaZipFile(QObject *parent); - /// Constructs a QuaZipFile instance. - /** \a parent argument specifies this object's parent object and \a - * zipName specifies ZIP archive file name. - * - * You should use setFileName() before trying to call open() on the - * constructed object. - * - * QuaZipFile constructed by this constructor can be used for read - * only access. Use QuaZipFile(QuaZip*,QObject*) for writing. - **/ - QuaZipFile(const QString& zipName, QObject *parent =NULL); - /// Constructs a QuaZipFile instance. - /** \a parent argument specifies this object's parent object, \a - * zipName specifies ZIP archive file name and \a fileName and \a cs - * specify a name of the file to open inside archive. - * - * QuaZipFile constructed by this constructor can be used for read - * only access. Use QuaZipFile(QuaZip*,QObject*) for writing. - * - * \sa QuaZip::setCurrentFile() - **/ - QuaZipFile(const QString& zipName, const QString& fileName, - QuaZip::CaseSensitivity cs =QuaZip::csDefault, QObject *parent =NULL); - /// Constructs a QuaZipFile instance. - /** \a parent argument specifies this object's parent object. - * - * \a zip is the pointer to the existing QuaZip object. This - * QuaZipFile object then can be used to read current file in the - * \a zip or to write to the file inside it. - * - * \warning Using this constructor for reading current file can be - * tricky. Let's take the following example: - * \code - * QuaZip zip("archive.zip"); - * zip.open(QuaZip::mdUnzip); - * zip.setCurrentFile("file-in-archive"); - * QuaZipFile file(&zip); - * file.open(QIODevice::ReadOnly); - * // ok, now we can read from the file - * file.read(somewhere, some); - * zip.setCurrentFile("another-file-in-archive"); // oops... - * QuaZipFile anotherFile(&zip); - * anotherFile.open(QIODevice::ReadOnly); - * anotherFile.read(somewhere, some); // this is still ok... - * file.read(somewhere, some); // and this is NOT - * \endcode - * So, what exactly happens here? When we change current file in the - * \c zip archive, \c file that references it becomes invalid - * (actually, as far as I understand ZIP/UNZIP sources, it becomes - * closed, but QuaZipFile has no means to detect it). - * - * Summary: do not close \c zip object or change its current file as - * long as QuaZipFile is open. Even better - use another constructors - * which create internal QuaZip instances, one per object, and - * therefore do not cause unnecessary trouble. This constructor may - * be useful, though, if you already have a QuaZip instance and do - * not want to access several files at once. Good example: - * \code - * QuaZip zip("archive.zip"); - * zip.open(QuaZip::mdUnzip); - * // first, we need some information about archive itself - * QByteArray comment=zip.getComment(); - * // and now we are going to access files inside it - * QuaZipFile file(&zip); - * for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) { - * file.open(QIODevice::ReadOnly); - * // do something cool with file here - * file.close(); // do not forget to close! - * } - * zip.close(); - * \endcode - **/ - QuaZipFile(QuaZip *zip, QObject *parent =NULL); - /// Destroys a QuaZipFile instance. - /** Closes file if open, destructs internal QuaZip object (if it - * exists and \em is internal, of course). - **/ - virtual ~QuaZipFile(); - /// Returns the ZIP archive file name. - /** If this object was created by passing QuaZip pointer to the - * constructor, this function will return that QuaZip's file name - * (or null string if that object does not have file name yet). - * - * Otherwise, returns associated ZIP archive file name or null - * string if there are no name set yet. - * - * \sa setZipName() getFileName() - **/ - QString getZipName()const; - /// Returns a pointer to the associated QuaZip object. - /** Returns \c NULL if there is no associated QuaZip or it is - * internal (so you will not mess with it). - **/ - QuaZip* getZip()const; - /// Returns file name. - /** This function returns file name you passed to this object either - * by using - * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*) - * or by calling setFileName(). Real name of the file may differ in - * case if you used case-insensitivity. - * - * Returns null string if there is no file name set yet. This is the - * case when this QuaZipFile operates on the existing QuaZip object - * (constructor QuaZipFile(QuaZip*,QObject*) or setZip() was used). - * - * \sa getActualFileName - **/ - QString getFileName() const; - /// Returns case sensitivity of the file name. - /** This function returns case sensitivity argument you passed to - * this object either by using - * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*) - * or by calling setFileName(). - * - * Returns unpredictable value if getFileName() returns null string - * (this is the case when you did not used setFileName() or - * constructor above). - * - * \sa getFileName - **/ - QuaZip::CaseSensitivity getCaseSensitivity() const; - /// Returns the actual file name in the archive. - /** This is \em not a ZIP archive file name, but a name of file inside - * archive. It is not necessary the same name that you have passed - * to the - * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*), - * setFileName() or QuaZip::setCurrentFile() - this is the real file - * name inside archive, so it may differ in case if the file name - * search was case-insensitive. - * - * Equivalent to calling getCurrentFileName() on the associated - * QuaZip object. Returns null string if there is no associated - * QuaZip object or if it does not have a current file yet. And this - * is the case if you called setFileName() but did not open the - * file yet. So this is perfectly fine: - * \code - * QuaZipFile file("somezip.zip"); - * file.setFileName("somefile"); - * QString name=file.getName(); // name=="somefile" - * QString actual=file.getActualFileName(); // actual is null string - * file.open(QIODevice::ReadOnly); - * QString actual=file.getActualFileName(); // actual can be "SoMeFiLe" on Windows - * \endcode - * - * \sa getZipName(), getFileName(), QuaZip::CaseSensitivity - **/ - QString getActualFileName()const; - /// Sets the ZIP archive file name. - /** Automatically creates internal QuaZip object and destroys - * previously created internal QuaZip object, if any. - * - * Will do nothing if this file is already open. You must close() it - * first. - **/ - void setZipName(const QString& zipName); - /// Returns \c true if the file was opened in raw mode. - /** If the file is not open, the returned value is undefined. - * - * \sa open(OpenMode,int*,int*,bool,const char*) - **/ - bool isRaw() const; - /// Binds to the existing QuaZip instance. - /** This function destroys internal QuaZip object, if any, and makes - * this QuaZipFile to use current file in the \a zip object for any - * further operations. See QuaZipFile(QuaZip*,QObject*) for the - * possible pitfalls. - * - * Will do nothing if the file is currently open. You must close() - * it first. - **/ - void setZip(QuaZip *zip); - /// Sets the file name. - /** Will do nothing if at least one of the following conditions is - * met: - * - ZIP name has not been set yet (getZipName() returns null - * string). - * - This QuaZipFile is associated with external QuaZip. In this - * case you should call that QuaZip's setCurrentFile() function - * instead! - * - File is already open so setting the name is meaningless. - * - * \sa QuaZip::setCurrentFile - **/ - void setFileName(const QString& fileName, QuaZip::CaseSensitivity cs =QuaZip::csDefault); - /// Opens a file for reading. - /** Returns \c true on success, \c false otherwise. - * Call getZipError() to get error code. - * - * \note Since ZIP/UNZIP API provides buffered reading only, - * QuaZipFile does not support unbuffered reading. So do not pass - * QIODevice::Unbuffered flag in \a mode, or open will fail. - **/ - virtual bool open(OpenMode mode); - /// Opens a file for reading. - /** \overload - * Argument \a password specifies a password to decrypt the file. If - * it is NULL then this function behaves just like open(OpenMode). - **/ - inline bool open(OpenMode mode, const char *password) - {return open(mode, NULL, NULL, false, password);} - /// Opens a file for reading. - /** \overload - * Argument \a password specifies a password to decrypt the file. - * - * An integers pointed by \a method and \a level will receive codes - * of the compression method and level used. See unzip.h. - * - * If raw is \c true then no decompression is performed. - * - * \a method should not be \c NULL. \a level can be \c NULL if you - * don't want to know the compression level. - **/ - bool open(OpenMode mode, int *method, int *level, bool raw, const char *password =NULL); - /// Opens a file for writing. - /** \a info argument specifies information about file. It should at - * least specify a correct file name. Also, it is a good idea to - * specify correct timestamp (by default, current time will be - * used). See QuaZipNewInfo. - * - * The \a password argument specifies the password for crypting. Pass NULL - * if you don't need any crypting. The \a crc argument was supposed - * to be used for crypting too, but then it turned out that it's - * false information, so you need to set it to 0 unless you want to - * use the raw mode (see below). - * - * Arguments \a method and \a level specify compression method and - * level. The only method supported is Z_DEFLATED, but you may also - * specify 0 for no compression. If all of the files in the archive - * use both method 0 and either level 0 is explicitly specified or - * data descriptor writing is disabled with - * QuaZip::setDataDescriptorWritingEnabled(), then the - * resulting archive is supposed to be compatible with the 1.0 ZIP - * format version, should you need that. Except for this, \a level - * has no other effects with method 0. - * - * If \a raw is \c true, no compression is performed. In this case, - * \a crc and uncompressedSize field of the \a info are required. - * - * Arguments \a windowBits, \a memLevel, \a strategy provide zlib - * algorithms tuning. See deflateInit2() in zlib. - **/ - bool open(OpenMode mode, const QuaZipNewInfo& info, - const char *password =NULL, quint32 crc =0, - int method =Z_DEFLATED, int level =Z_DEFAULT_COMPRESSION, bool raw =false, - int windowBits =-MAX_WBITS, int memLevel =DEF_MEM_LEVEL, int strategy =Z_DEFAULT_STRATEGY); - /// Returns \c true, but \ref quazipfile-sequential "beware"! - virtual bool isSequential()const; - /// Returns current position in the file. - /** Implementation of the QIODevice::pos(). When reading, this - * function is a wrapper to the ZIP/UNZIP unztell(), therefore it is - * unable to keep track of the ungetChar() calls (which is - * non-virtual and therefore is dangerous to reimplement). So if you - * are using ungetChar() feature of the QIODevice, this function - * reports incorrect value until you get back characters which you - * ungot. - * - * When writing, pos() returns number of bytes already written - * (uncompressed unless you use raw mode). - * - * \note Although - * \ref quazipfile-sequential "QuaZipFile is a sequential device" - * and therefore pos() should always return zero, it does not, - * because it would be misguiding. Keep this in mind. - * - * This function returns -1 if the file or archive is not open. - * - * Error code returned by getZipError() is not affected by this - * function call. - **/ - virtual qint64 pos()const; - /// Returns \c true if the end of file was reached. - /** This function returns \c false in the case of error. This means - * that you called this function on either not open file, or a file - * in the not open archive or even on a QuaZipFile instance that - * does not even have QuaZip instance associated. Do not do that - * because there is no means to determine whether \c false is - * returned because of error or because end of file was reached. - * Well, on the other side you may interpret \c false return value - * as "there is no file open to check for end of file and there is - * no end of file therefore". - * - * When writing, this function always returns \c true (because you - * are always writing to the end of file). - * - * Error code returned by getZipError() is not affected by this - * function call. - **/ - virtual bool atEnd()const; - /// Returns file size. - /** This function returns csize() if the file is open for reading in - * raw mode, usize() if it is open for reading in normal mode and - * pos() if it is open for writing. - * - * Returns -1 on error, call getZipError() to get error code. - * - * \note This function returns file size despite that - * \ref quazipfile-sequential "QuaZipFile is considered to be sequential device", - * for which size() should return bytesAvailable() instead. But its - * name would be very misguiding otherwise, so just keep in mind - * this inconsistence. - **/ - virtual qint64 size()const; - /// Returns compressed file size. - /** Equivalent to calling getFileInfo() and then getting - * compressedSize field, but more convenient and faster. - * - * File must be open for reading before calling this function. - * - * Returns -1 on error, call getZipError() to get error code. - **/ - qint64 csize()const; - /// Returns uncompressed file size. - /** Equivalent to calling getFileInfo() and then getting - * uncompressedSize field, but more convenient and faster. See - * getFileInfo() for a warning. - * - * File must be open for reading before calling this function. - * - * Returns -1 on error, call getZipError() to get error code. - **/ - qint64 usize()const; - /// Gets information about current file. - /** This function does the same thing as calling - * QuaZip::getCurrentFileInfo() on the associated QuaZip object, - * but you can not call getCurrentFileInfo() if the associated - * QuaZip is internal (because you do not have access to it), while - * you still can call this function in that case. - * - * File must be open for reading before calling this function. - * - * \return \c false in the case of an error. - * - * This function doesn't support zip64, but will still work fine on zip64 - * archives if file sizes are below 4 GB, otherwise the values will be set - * as if converted using QuaZipFileInfo64::toQuaZipFileInfo(). - * - * \sa getFileInfo(QuaZipFileInfo64*) - **/ - bool getFileInfo(QuaZipFileInfo *info); - /// Gets information about current file with zip64 support. - /** - * @overload - * - * \sa getFileInfo(QuaZipFileInfo*) - */ - bool getFileInfo(QuaZipFileInfo64 *info); - /// Closes the file. - /** Call getZipError() to determine if the close was successful. - **/ - virtual void close(); - /// Returns the error code returned by the last ZIP/UNZIP API call. - int getZipError() const; - /// Returns the number of bytes available for reading. - virtual qint64 bytesAvailable() const; -}; - -#endif diff --git a/src/3rdParty/quazip-0.7.3/quazip/quazipfileinfo.cpp b/src/3rdParty/quazip-0.7.3/quazip/quazipfileinfo.cpp deleted file mode 100644 index f11c91017..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quazipfileinfo.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/* -Copyright (C) 2005-2014 Sergey A. Tachenov - -This file is part of QuaZIP. - -QuaZIP is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 of the License, or -(at your option) any later version. - -QuaZIP is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with QuaZIP. If not, see . - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant and contributors, -see quazip/(un)zip.h files for details. Basically it's the zlib license. -*/ - -#include "quazipfileinfo.h" - -static QFile::Permissions permissionsFromExternalAttr(quint32 externalAttr) { - quint32 uPerm = (externalAttr & 0xFFFF0000u) >> 16; - QFile::Permissions perm = 0; - if ((uPerm & 0400) != 0) - perm |= QFile::ReadOwner; - if ((uPerm & 0200) != 0) - perm |= QFile::WriteOwner; - if ((uPerm & 0100) != 0) - perm |= QFile::ExeOwner; - if ((uPerm & 0040) != 0) - perm |= QFile::ReadGroup; - if ((uPerm & 0020) != 0) - perm |= QFile::WriteGroup; - if ((uPerm & 0010) != 0) - perm |= QFile::ExeGroup; - if ((uPerm & 0004) != 0) - perm |= QFile::ReadOther; - if ((uPerm & 0002) != 0) - perm |= QFile::WriteOther; - if ((uPerm & 0001) != 0) - perm |= QFile::ExeOther; - return perm; - -} - -QFile::Permissions QuaZipFileInfo::getPermissions() const -{ - return permissionsFromExternalAttr(externalAttr); -} - -QFile::Permissions QuaZipFileInfo64::getPermissions() const -{ - return permissionsFromExternalAttr(externalAttr); -} - -bool QuaZipFileInfo64::toQuaZipFileInfo(QuaZipFileInfo &info) const -{ - bool noOverflow = true; - info.name = name; - info.versionCreated = versionCreated; - info.versionNeeded = versionNeeded; - info.flags = flags; - info.method = method; - info.dateTime = dateTime; - info.crc = crc; - if (compressedSize > 0xFFFFFFFFu) { - info.compressedSize = 0xFFFFFFFFu; - noOverflow = false; - } else { - info.compressedSize = compressedSize; - } - if (uncompressedSize > 0xFFFFFFFFu) { - info.uncompressedSize = 0xFFFFFFFFu; - noOverflow = false; - } else { - info.uncompressedSize = uncompressedSize; - } - info.diskNumberStart = diskNumberStart; - info.internalAttr = internalAttr; - info.externalAttr = externalAttr; - info.comment = comment; - info.extra = extra; - return noOverflow; -} - -static QDateTime getNTFSTime(const QByteArray &extra, int position, - int *fineTicks) -{ - QDateTime dateTime; - for (int i = 0; i <= extra.size() - 4; ) { - unsigned type = static_cast(static_cast( - extra.at(i))) - | (static_cast(static_cast( - extra.at(i + 1))) << 8); - i += 2; - unsigned length = static_cast(static_cast( - extra.at(i))) - | (static_cast(static_cast( - extra.at(i + 1))) << 8); - i += 2; - if (type == QUAZIP_EXTRA_NTFS_MAGIC && length >= 32) { - i += 4; // reserved - while (i <= extra.size() - 4) { - unsigned tag = static_cast( - static_cast(extra.at(i))) - | (static_cast( - static_cast(extra.at(i + 1))) - << 8); - i += 2; - int tagsize = static_cast( - static_cast(extra.at(i))) - | (static_cast( - static_cast(extra.at(i + 1))) - << 8); - i += 2; - if (tag == QUAZIP_EXTRA_NTFS_TIME_MAGIC - && tagsize >= position + 8) { - i += position; - quint64 mtime = static_cast( - static_cast(extra.at(i))) - | (static_cast(static_cast( - extra.at(i + 1))) << 8) - | (static_cast(static_cast( - extra.at(i + 2))) << 16) - | (static_cast(static_cast( - extra.at(i + 3))) << 24) - | (static_cast(static_cast( - extra.at(i + 4))) << 32) - | (static_cast(static_cast( - extra.at(i + 5))) << 40) - | (static_cast(static_cast( - extra.at(i + 6))) << 48) - | (static_cast(static_cast( - extra.at(i + 7))) << 56); - // the NTFS time is measured from 1601 for whatever reason - QDateTime base(QDate(1601, 1, 1), QTime(0, 0), Qt::UTC); - dateTime = base.addMSecs(mtime / 10000); - if (fineTicks != NULL) { - *fineTicks = static_cast(mtime % 10000); - } - i += tagsize - position; - } else { - i += tagsize; - } - - } - } else { - i += length; - } - } - if (fineTicks != NULL && dateTime.isNull()) { - *fineTicks = 0; - } - return dateTime; -} - -QDateTime QuaZipFileInfo64::getNTFSmTime(int *fineTicks) const -{ - return getNTFSTime(extra, 0, fineTicks); -} - -QDateTime QuaZipFileInfo64::getNTFSaTime(int *fineTicks) const -{ - return getNTFSTime(extra, 8, fineTicks); -} - -QDateTime QuaZipFileInfo64::getNTFScTime(int *fineTicks) const -{ - return getNTFSTime(extra, 16, fineTicks); -} diff --git a/src/3rdParty/quazip-0.7.3/quazip/quazipfileinfo.h b/src/3rdParty/quazip-0.7.3/quazip/quazipfileinfo.h deleted file mode 100644 index 4e142a4eb..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quazipfileinfo.h +++ /dev/null @@ -1,178 +0,0 @@ -#ifndef QUA_ZIPFILEINFO_H -#define QUA_ZIPFILEINFO_H - -/* -Copyright (C) 2005-2014 Sergey A. Tachenov - -This file is part of QuaZIP. - -QuaZIP is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 of the License, or -(at your option) any later version. - -QuaZIP is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with QuaZIP. If not, see . - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant and contributors, -see quazip/(un)zip.h files for details. Basically it's the zlib license. -*/ - -#include -#include -#include - -#include "quazip_global.h" - -/// Information about a file inside archive. -/** - * \deprecated Use QuaZipFileInfo64 instead. Not only it supports large files, - * but also more convenience methods as well. - * - * Call QuaZip::getCurrentFileInfo() or QuaZipFile::getFileInfo() to - * fill this structure. */ -struct QUAZIP_EXPORT QuaZipFileInfo { - /// File name. - QString name; - /// Version created by. - quint16 versionCreated; - /// Version needed to extract. - quint16 versionNeeded; - /// General purpose flags. - quint16 flags; - /// Compression method. - quint16 method; - /// Last modification date and time. - QDateTime dateTime; - /// CRC. - quint32 crc; - /// Compressed file size. - quint32 compressedSize; - /// Uncompressed file size. - quint32 uncompressedSize; - /// Disk number start. - quint16 diskNumberStart; - /// Internal file attributes. - quint16 internalAttr; - /// External file attributes. - quint32 externalAttr; - /// Comment. - QString comment; - /// Extra field. - QByteArray extra; - /// Get the file permissions. - /** - Returns the high 16 bits of external attributes converted to - QFile::Permissions. - */ - QFile::Permissions getPermissions() const; -}; - -/// Information about a file inside archive (with zip64 support). -/** Call QuaZip::getCurrentFileInfo() or QuaZipFile::getFileInfo() to - * fill this structure. */ -struct QUAZIP_EXPORT QuaZipFileInfo64 { - /// File name. - QString name; - /// Version created by. - quint16 versionCreated; - /// Version needed to extract. - quint16 versionNeeded; - /// General purpose flags. - quint16 flags; - /// Compression method. - quint16 method; - /// Last modification date and time. - /** - * This is the time stored in the standard ZIP header. This format only allows - * to store time with 2-second precision, so the seconds will always be even - * and the milliseconds will always be zero. If you need more precise - * date and time, you can try to call the getNTFSmTime() function or - * its siblings, provided that the archive itself contains these NTFS times. - */ - QDateTime dateTime; - /// CRC. - quint32 crc; - /// Compressed file size. - quint64 compressedSize; - /// Uncompressed file size. - quint64 uncompressedSize; - /// Disk number start. - quint16 diskNumberStart; - /// Internal file attributes. - quint16 internalAttr; - /// External file attributes. - quint32 externalAttr; - /// Comment. - QString comment; - /// Extra field. - QByteArray extra; - /// Get the file permissions. - /** - Returns the high 16 bits of external attributes converted to - QFile::Permissions. - */ - QFile::Permissions getPermissions() const; - /// Converts to QuaZipFileInfo - /** - If any of the fields are greater than 0xFFFFFFFFu, they are set to - 0xFFFFFFFFu exactly, not just truncated. This function should be mainly used - for compatibility with the old code expecting QuaZipFileInfo, in the cases - when it's impossible or otherwise unadvisable (due to ABI compatibility - reasons, for example) to modify that old code to use QuaZipFileInfo64. - - \return \c true if all fields converted correctly, \c false if an overflow - occured. - */ - bool toQuaZipFileInfo(QuaZipFileInfo &info) const; - /// Returns the NTFS modification time - /** - * The getNTFS*Time() functions only work if there is an NTFS extra field - * present. Otherwise, they all return invalid null timestamps. - * @param fineTicks If not NULL, the fractional part of milliseconds returned - * there, measured in 100-nanosecond ticks. Will be set to - * zero if there is no NTFS extra field. - * @sa dateTime - * @sa getNTFSaTime() - * @sa getNTFScTime() - * @return The NTFS modification time, UTC - */ - QDateTime getNTFSmTime(int *fineTicks = NULL) const; - /// Returns the NTFS access time - /** - * The getNTFS*Time() functions only work if there is an NTFS extra field - * present. Otherwise, they all return invalid null timestamps. - * @param fineTicks If not NULL, the fractional part of milliseconds returned - * there, measured in 100-nanosecond ticks. Will be set to - * zero if there is no NTFS extra field. - * @sa dateTime - * @sa getNTFSmTime() - * @sa getNTFScTime() - * @return The NTFS access time, UTC - */ - QDateTime getNTFSaTime(int *fineTicks = NULL) const; - /// Returns the NTFS creation time - /** - * The getNTFS*Time() functions only work if there is an NTFS extra field - * present. Otherwise, they all return invalid null timestamps. - * @param fineTicks If not NULL, the fractional part of milliseconds returned - * there, measured in 100-nanosecond ticks. Will be set to - * zero if there is no NTFS extra field. - * @sa dateTime - * @sa getNTFSmTime() - * @sa getNTFSaTime() - * @return The NTFS creation time, UTC - */ - QDateTime getNTFScTime(int *fineTicks = NULL) const; - /// Checks whether the file is encrypted. - bool isEncrypted() const {return (flags & 1) != 0;} -}; - -#endif diff --git a/src/3rdParty/quazip-0.7.3/quazip/quazipnewinfo.cpp b/src/3rdParty/quazip-0.7.3/quazip/quazipnewinfo.cpp deleted file mode 100644 index 8015d9239..000000000 --- a/src/3rdParty/quazip-0.7.3/quazip/quazipnewinfo.cpp +++ /dev/null @@ -1,286 +0,0 @@ -/* -Copyright (C) 2005-2014 Sergey A. Tachenov - -This file is part of QuaZIP. - -QuaZIP is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 2.1 of the License, or -(at your option) any later version. - -QuaZIP is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with QuaZIP. If not, see . - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant and contributors, -see quazip/(un)zip.h files for details. Basically it's the zlib license. -*/ - -#include - -#include "quazipnewinfo.h" - -#include - -static void QuaZipNewInfo_setPermissions(QuaZipNewInfo *info, - QFile::Permissions perm, bool isDir, bool isSymLink = false) -{ - quint32 uPerm = isDir ? 0040000 : 0100000; - - if ( isSymLink ) { -#ifdef Q_OS_WIN - uPerm = 0200000; -#else - uPerm = 0120000; -#endif - } - - if ((perm & QFile::ReadOwner) != 0) - uPerm |= 0400; - if ((perm & QFile::WriteOwner) != 0) - uPerm |= 0200; - if ((perm & QFile::ExeOwner) != 0) - uPerm |= 0100; - if ((perm & QFile::ReadGroup) != 0) - uPerm |= 0040; - if ((perm & QFile::WriteGroup) != 0) - uPerm |= 0020; - if ((perm & QFile::ExeGroup) != 0) - uPerm |= 0010; - if ((perm & QFile::ReadOther) != 0) - uPerm |= 0004; - if ((perm & QFile::WriteOther) != 0) - uPerm |= 0002; - if ((perm & QFile::ExeOther) != 0) - uPerm |= 0001; - info->externalAttr = (info->externalAttr & ~0xFFFF0000u) | (uPerm << 16); -} - -template -void QuaZipNewInfo_init(QuaZipNewInfo &self, const FileInfo &existing) -{ - self.name = existing.name; - self.dateTime = existing.dateTime; - self.internalAttr = existing.internalAttr; - self.externalAttr = existing.externalAttr; - self.comment = existing.comment; - self.extraLocal = existing.extra; - self.extraGlobal = existing.extra; - self.uncompressedSize = existing.uncompressedSize; -} - -QuaZipNewInfo::QuaZipNewInfo(const QuaZipFileInfo &existing) -{ - QuaZipNewInfo_init(*this, existing); -} - -QuaZipNewInfo::QuaZipNewInfo(const QuaZipFileInfo64 &existing) -{ - QuaZipNewInfo_init(*this, existing); -} - -QuaZipNewInfo::QuaZipNewInfo(const QString& name): - name(name), dateTime(QDateTime::currentDateTime()), internalAttr(0), externalAttr(0), - uncompressedSize(0) -{ -} - -QuaZipNewInfo::QuaZipNewInfo(const QString& name, const QString& file): - name(name), internalAttr(0), externalAttr(0), uncompressedSize(0) -{ - QFileInfo info(file); - QDateTime lm = info.lastModified(); - if (!info.exists()) { - dateTime = QDateTime::currentDateTime(); - } else { - dateTime = lm; - QuaZipNewInfo_setPermissions(this, info.permissions(), info.isDir(), info.isSymLink()); - } -} - -void QuaZipNewInfo::setFileDateTime(const QString& file) -{ - QFileInfo info(file); - QDateTime lm = info.lastModified(); - if (info.exists()) - dateTime = lm; -} - -void QuaZipNewInfo::setFilePermissions(const QString &file) -{ - QFileInfo info = QFileInfo(file); - QFile::Permissions perm = info.permissions(); - QuaZipNewInfo_setPermissions(this, perm, info.isDir(), info.isSymLink()); -} - -void QuaZipNewInfo::setPermissions(QFile::Permissions permissions) -{ - QuaZipNewInfo_setPermissions(this, permissions, name.endsWith('/')); -} - -void QuaZipNewInfo::setFileNTFSTimes(const QString &fileName) -{ - QFileInfo fi(fileName); - if (!fi.exists()) { - qWarning("QuaZipNewInfo::setFileNTFSTimes(): '%s' doesn't exist", - fileName.toUtf8().constData()); - return; - } - setFileNTFSmTime(fi.lastModified()); - setFileNTFSaTime(fi.lastRead()); - setFileNTFScTime(fi.created()); -} - -static void setNTFSTime(QByteArray &extra, const QDateTime &time, int position, - int fineTicks) { - int ntfsPos = -1, timesPos = -1; - unsigned ntfsLength = 0, ntfsTimesLength = 0; - for (int i = 0; i <= extra.size() - 4; ) { - unsigned type = static_cast(static_cast( - extra.at(i))) - | (static_cast(static_cast( - extra.at(i + 1))) << 8); - i += 2; - unsigned length = static_cast(static_cast( - extra.at(i))) - | (static_cast(static_cast( - extra.at(i + 1))) << 8); - i += 2; - if (type == QUAZIP_EXTRA_NTFS_MAGIC) { - ntfsPos = i - 4; // the beginning of the NTFS record - ntfsLength = length; - if (length <= 4) { - break; // no times in the NTFS record - } - i += 4; // reserved - while (i <= extra.size() - 4) { - unsigned tag = static_cast( - static_cast(extra.at(i))) - | (static_cast( - static_cast(extra.at(i + 1))) - << 8); - i += 2; - unsigned tagsize = static_cast( - static_cast(extra.at(i))) - | (static_cast( - static_cast(extra.at(i + 1))) - << 8); - i += 2; - if (tag == QUAZIP_EXTRA_NTFS_TIME_MAGIC) { - timesPos = i - 4; // the beginning of the NTFS times tag - ntfsTimesLength = tagsize; - break; - } else { - i += tagsize; - } - } - break; // I ain't going to search for yet another NTFS record! - } else { - i += length; - } - } - if (ntfsPos == -1) { - // No NTFS record, need to create one. - ntfsPos = extra.size(); - ntfsLength = 32; - extra.resize(extra.size() + 4 + ntfsLength); - // the NTFS record header - extra[ntfsPos] = static_cast(QUAZIP_EXTRA_NTFS_MAGIC); - extra[ntfsPos + 1] = static_cast(QUAZIP_EXTRA_NTFS_MAGIC >> 8); - extra[ntfsPos + 2] = 32; // the 2-byte size in LittleEndian - extra[ntfsPos + 3] = 0; - // zero the record - memset(extra.data() + ntfsPos + 4, 0, 32); - timesPos = ntfsPos + 8; - // now set the tag data - extra[timesPos] = static_cast(QUAZIP_EXTRA_NTFS_TIME_MAGIC); - extra[timesPos + 1] = static_cast(QUAZIP_EXTRA_NTFS_TIME_MAGIC - >> 8); - // the size: - extra[timesPos + 2] = 24; - extra[timesPos + 3] = 0; - ntfsTimesLength = 24; - } - if (timesPos == -1) { - // No time tag in the NTFS record, need to add one. - timesPos = ntfsPos + 4 + ntfsLength; - extra.resize(extra.size() + 28); - // Now we need to move the rest of the field - // (possibly zero bytes, but memmove() is OK with that). - // 0 ......... ntfsPos .. ntfsPos + 4 ... timesPos - //
- memmove(extra.data() + timesPos + 28, extra.data() + timesPos, - extra.size() - 28 - timesPos); - ntfsLength += 28; - // now set the tag data - extra[timesPos] = static_cast(QUAZIP_EXTRA_NTFS_TIME_MAGIC); - extra[timesPos + 1] = static_cast(QUAZIP_EXTRA_NTFS_TIME_MAGIC - >> 8); - // the size: - extra[timesPos + 2] = 24; - extra[timesPos + 3] = 0; - // zero the record - memset(extra.data() + timesPos + 4, 0, 24); - ntfsTimesLength = 24; - } - if (ntfsTimesLength < 24) { - // Broken times field. OK, this is really unlikely, but just in case... - size_t timesEnd = timesPos + 4 + ntfsTimesLength; - extra.resize(extra.size() + (24 - ntfsTimesLength)); - // Move it! - // 0 ......... timesPos .... timesPos + 4 .. timesEnd - //