warcraftxl without submodukle
This commit is contained in:
@@ -1,7 +1,3 @@
|
|||||||
[submodule "vendor/warcraftxl"]
|
|
||||||
path = vendor/warcraftxl
|
|
||||||
url = https://github.com/WarcraftXL/wxl-core.git
|
|
||||||
branch = main
|
|
||||||
[submodule "vendor/modules/wxl-modern-assets"]
|
[submodule "vendor/modules/wxl-modern-assets"]
|
||||||
path = vendor/modules/wxl-modern-assets
|
path = vendor/modules/wxl-modern-assets
|
||||||
url = https://github.com/WarcraftXL/wxl-modern-assets.git
|
url = https://github.com/WarcraftXL/wxl-modern-assets.git
|
||||||
|
|||||||
Vendored
-1
Submodule vendor/warcraftxl deleted from ee9d8a92a3
@@ -0,0 +1,69 @@
|
|||||||
|
# Prerequisites
|
||||||
|
*.d
|
||||||
|
|
||||||
|
# Compiled Object files
|
||||||
|
*.slo
|
||||||
|
*.lo
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Linker files
|
||||||
|
*.ilk
|
||||||
|
|
||||||
|
# Debugger Files
|
||||||
|
*.pdb
|
||||||
|
|
||||||
|
# Compiled Dynamic libraries
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
*.dll
|
||||||
|
*.so.*
|
||||||
|
|
||||||
|
|
||||||
|
# Fortran module files
|
||||||
|
*.mod
|
||||||
|
*.smod
|
||||||
|
|
||||||
|
# Compiled Static libraries
|
||||||
|
*.lai
|
||||||
|
*.la
|
||||||
|
*.a
|
||||||
|
*.lib
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
|
||||||
|
# Build directories
|
||||||
|
build/
|
||||||
|
Build/
|
||||||
|
build-*/
|
||||||
|
|
||||||
|
# CMake generated files
|
||||||
|
CMakeFiles/
|
||||||
|
CMakeCache.txt
|
||||||
|
cmake_install.cmake
|
||||||
|
Makefile
|
||||||
|
install_manifest.txt
|
||||||
|
compile_commands.json
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
*.tmp
|
||||||
|
*.log
|
||||||
|
*.bak
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
# vcpkg
|
||||||
|
vcpkg_installed/
|
||||||
|
|
||||||
|
# debug information files
|
||||||
|
*.dwo
|
||||||
|
|
||||||
|
# test output & cache
|
||||||
|
Testing/
|
||||||
|
.cache/
|
||||||
Vendored
+205
@@ -0,0 +1,205 @@
|
|||||||
|
# WarcraftXL. Two artifact families share this tree and cannot share one toolchain platform, so the file
|
||||||
|
# is platform-aware: configure -A Win32 for the injected DLL + patcher + proxy (32-bit), and -A x64 with
|
||||||
|
# -DWXL_BUILD_HOST=ON for the asset host (64-bit). build.ps1 drives both.
|
||||||
|
# Copyright (C) 2026 WarcraftXL. GPLv3 (see source headers).
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
project(WarcraftXL LANGUAGES CXX)
|
||||||
|
|
||||||
|
# Static CRT everywhere: the DLLs load inside the player's Wow.exe and the host runs standalone on
|
||||||
|
# machines that have no reason to carry the toolset's brand-new VC++ redistributable. A dynamic CRT
|
||||||
|
# turns a missing/stale redist into a loader failure at process start (0xc0000142) with no log at all.
|
||||||
|
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||||
|
|
||||||
|
# The 64-bit asset host (WarcraftXLHost.exe) is opt-in: OFF by default so a contributor who only wants the
|
||||||
|
# DLL needs no x64 toolchain and pays no build/deploy cost. build.ps1 -Host flips it on in an x64 configure.
|
||||||
|
option(WXL_BUILD_HOST "Build WarcraftXLHost.exe (64-bit asset host)" OFF)
|
||||||
|
|
||||||
|
# wxl-modern-assets per-format toggles: exclude an entire format pipeline (source down-convert, both its
|
||||||
|
# DLL and host halves) at configure time, without touching source. common/ and textures/dds stay in
|
||||||
|
# unconditionally (shared infrastructure, not format-specific). ADT gets WXL_MODERN_ADT here once it
|
||||||
|
# migrates into wxl-modern-assets.
|
||||||
|
option(WXL_MODERN_M2 "Build wxl-modern-assets M2 support" ON)
|
||||||
|
option(WXL_MODERN_M3 "Build wxl-modern-assets M3 support" ON)
|
||||||
|
option(WXL_MODERN_WMO "Build wxl-modern-assets WMO support" ON)
|
||||||
|
option(WXL_MODERN_BLP "Build wxl-modern-assets BLP/texture support" ON)
|
||||||
|
|
||||||
|
set(WXL_MODERN_ASSETS_EXCLUDE_REGEX "")
|
||||||
|
if(NOT WXL_MODERN_M2)
|
||||||
|
string(APPEND WXL_MODERN_ASSETS_EXCLUDE_REGEX "|/wxl-modern-assets/(shared|host|src)/models/m2/")
|
||||||
|
endif()
|
||||||
|
if(NOT WXL_MODERN_M3)
|
||||||
|
string(APPEND WXL_MODERN_ASSETS_EXCLUDE_REGEX "|/wxl-modern-assets/(shared|host|src)/models/m3/")
|
||||||
|
endif()
|
||||||
|
if(NOT WXL_MODERN_WMO)
|
||||||
|
string(APPEND WXL_MODERN_ASSETS_EXCLUDE_REGEX "|/wxl-modern-assets/(shared|host|src)/models/wmo/")
|
||||||
|
endif()
|
||||||
|
if(NOT WXL_MODERN_BLP)
|
||||||
|
string(APPEND WXL_MODERN_ASSETS_EXCLUDE_REGEX "|/wxl-modern-assets/(shared|host|src)/textures/blp/")
|
||||||
|
endif()
|
||||||
|
string(REGEX REPLACE "^\\|" "" WXL_MODERN_ASSETS_EXCLUDE_REGEX "${WXL_MODERN_ASSETS_EXCLUDE_REGEX}")
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # feeds the IDE the real C++20 flags
|
||||||
|
|
||||||
|
set(WXL_DEFS WIN32_LEAN_AND_MEAN NOMINMAX _CRT_SECURE_NO_WARNINGS)
|
||||||
|
|
||||||
|
# Client directory to deploy the built artifacts into. Passed by build.ps1 (-DCLIENT_PATH=...) and cached.
|
||||||
|
set(CLIENT_PATH "" CACHE PATH "Client folder the built artifacts are copied into after each build")
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 32-bit family (injected into the client): WarcraftXL.dll + wxl-patcher.exe + d3d9.dll
|
||||||
|
# =============================================================================
|
||||||
|
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||||
|
# --- Automatic, recursive source discovery (no hand-written paths) -----------------------------
|
||||||
|
# CONFIGURE_DEPENDS re-globs at build time, so dropping a file (or a whole script) needs no edit here.
|
||||||
|
# The DLL excludes the patcher/host/gpu trees; the host (64-bit) takes its own slice in the EQUAL 8 block.
|
||||||
|
file(GLOB_RECURSE WXL_CORE_SRC CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
|
||||||
|
list(FILTER WXL_CORE_SRC EXCLUDE REGEX "/src/(patcher|host|gpu)/")
|
||||||
|
|
||||||
|
# =========================================================================
|
||||||
|
# Target 1: WarcraftXL.dll (32-bit, injected) = SDK + runtime scripts
|
||||||
|
# runtime scripts live in scripts/*/src/*.cpp; the cross-target byte-transform a module shares with
|
||||||
|
# the host lives in scripts/*/shared/*.cpp. Both compile straight into the DLL (self-registering).
|
||||||
|
# =========================================================================
|
||||||
|
file(GLOB_RECURSE WXL_RUNTIME_SCRIPT CONFIGURE_DEPENDS
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/scripts/*/src/*.cpp"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/scripts/*/shared/*.cpp")
|
||||||
|
if(WXL_MODERN_ASSETS_EXCLUDE_REGEX)
|
||||||
|
list(FILTER WXL_RUNTIME_SCRIPT EXCLUDE REGEX "${WXL_MODERN_ASSETS_EXCLUDE_REGEX}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Vendored ImGui (core + dx9/win32 backends). Compiled in but DORMANT until a script wires it up.
|
||||||
|
file(GLOB WXL_IMGUI CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/deps/imgui/*.cpp")
|
||||||
|
|
||||||
|
# FlatBuffers runtime (flexbuffers string utils) for the host IPC client (runtime/storage).
|
||||||
|
set(WXL_FLATBUFFERS "${CMAKE_CURRENT_SOURCE_DIR}/deps/flatbuffers/src/util.cpp")
|
||||||
|
|
||||||
|
add_library(WarcraftXL SHARED ${WXL_CORE_SRC} ${WXL_RUNTIME_SCRIPT} ${WXL_IMGUI} ${WXL_FLATBUFFERS})
|
||||||
|
set_target_properties(WarcraftXL PROPERTIES OUTPUT_NAME "WarcraftXL" PREFIX "")
|
||||||
|
target_include_directories(WarcraftXL PRIVATE
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/deps/minhook/include"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/deps/imgui"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/deps/flatbuffers/include")
|
||||||
|
|
||||||
|
add_subdirectory(deps/minhook)
|
||||||
|
target_link_libraries(WarcraftXL PRIVATE minhook d3d9 d3dcompiler shell32 delayimp)
|
||||||
|
# D3D12 and the shader compiler are feature-path dependencies (post-fx, grass capture, liquid
|
||||||
|
# shaders), not boot dependencies. Delay-loading keeps the DLL loadable on machines without them;
|
||||||
|
# every call site resolves or guards availability before touching those paths.
|
||||||
|
target_link_options(WarcraftXL PRIVATE "/DELAYLOAD:d3d12.dll" "/DELAYLOAD:d3dcompiler_47.dll")
|
||||||
|
target_compile_definitions(WarcraftXL PRIVATE ${WXL_DEFS})
|
||||||
|
|
||||||
|
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${WXL_CORE_SRC} ${WXL_RUNTIME_SCRIPT})
|
||||||
|
|
||||||
|
# Deploy: copy the freshly linked DLL into the client folder after every build.
|
||||||
|
if(CLIENT_PATH)
|
||||||
|
add_custom_command(TARGET WarcraftXL POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:WarcraftXL>" "${CLIENT_PATH}/WarcraftXL.dll"
|
||||||
|
COMMENT "Deploy WarcraftXL.dll -> ${CLIENT_PATH}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Per-module CMake hook: a module may ship scripts/<m>/module.cmake to extend the WarcraftXL target
|
||||||
|
# (add a vendored library, extra include dirs, link libraries). The file runs with the target defined
|
||||||
|
# and ${CMAKE_CURRENT_LIST_DIR} pointing at the module folder. Optional; most modules need none.
|
||||||
|
file(GLOB WXL_MODULE_CMAKES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/scripts/*/module.cmake")
|
||||||
|
foreach(_wxl_module ${WXL_MODULE_CMAKES})
|
||||||
|
include("${_wxl_module}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# =========================================================================
|
||||||
|
# Target 2: wxl-patcher.exe = the offline PE patcher + patcher scripts
|
||||||
|
# =========================================================================
|
||||||
|
file(GLOB WXL_PATCHER_CORE CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/patcher/*.cpp")
|
||||||
|
file(GLOB_RECURSE WXL_PATCHER_SCRIPT CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/scripts/*/patcher/*.cpp")
|
||||||
|
|
||||||
|
# src/common/ compiles into every binary (leveled logger, env config, shared helpers): the
|
||||||
|
# patcher and proxy do not link core, and the host is another architecture, so the shared
|
||||||
|
# infrastructure is object-level, not a link dependency.
|
||||||
|
file(GLOB WXL_COMMON_SRC CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/common/*.cpp")
|
||||||
|
|
||||||
|
add_executable(wxl-patcher ${WXL_PATCHER_CORE} ${WXL_PATCHER_SCRIPT} ${WXL_COMMON_SRC})
|
||||||
|
set_target_properties(wxl-patcher PROPERTIES OUTPUT_NAME "wxl-patcher")
|
||||||
|
target_include_directories(wxl-patcher PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||||
|
target_compile_definitions(wxl-patcher PRIVATE ${WXL_DEFS})
|
||||||
|
|
||||||
|
# =========================================================================
|
||||||
|
# Target 3: d3d9.dll = the D3D9On12 proxy
|
||||||
|
# =========================================================================
|
||||||
|
file(GLOB WXL_GPU_SRC CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/gpu/*.cpp")
|
||||||
|
|
||||||
|
add_library(d3d9 SHARED ${WXL_GPU_SRC} ${WXL_COMMON_SRC})
|
||||||
|
set_target_properties(d3d9 PROPERTIES OUTPUT_NAME "d3d9" PREFIX "")
|
||||||
|
target_include_directories(d3d9 PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||||
|
target_link_libraries(d3d9 PRIVATE d3d12 dxgi dcomp d3dcompiler delayimp)
|
||||||
|
# The proxy must load on every machine Wow.exe runs on -- it shadows a static import of the exe, so
|
||||||
|
# a hard dependency of the proxy is a hard dependency of the game (loader failure 0xc0000142 on
|
||||||
|
# machines without D3D12). All On12/D3D12 machinery is delay-loaded; EnsureDevice() checks that
|
||||||
|
# d3d12.dll is actually present before the first delay-loaded call, else the proxy runs as a pure
|
||||||
|
# native pass-through.
|
||||||
|
target_link_options(d3d9 PRIVATE "/DEF:${CMAKE_CURRENT_SOURCE_DIR}/src/gpu/Proxy.def"
|
||||||
|
"/DELAYLOAD:d3d12.dll" "/DELAYLOAD:dxgi.dll" "/DELAYLOAD:dcomp.dll" "/DELAYLOAD:d3dcompiler_47.dll")
|
||||||
|
target_compile_definitions(d3d9 PRIVATE ${WXL_DEFS})
|
||||||
|
|
||||||
|
# Deploy: copy the freshly linked proxy into the client folder after every build.
|
||||||
|
if(CLIENT_PATH)
|
||||||
|
add_custom_command(TARGET d3d9 POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:d3d9>" "${CLIENT_PATH}/d3d9.dll"
|
||||||
|
COMMENT "Deploy d3d9.dll -> ${CLIENT_PATH}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 64-bit family (opt-in): WarcraftXLHost.exe = archive owner + IPC transport.
|
||||||
|
# Format-blind: src/host/ + the modules' scripts/*/host/ handlers + their scripts/*/shared/ transforms.
|
||||||
|
# StormLib + FlatBuffers (deps/). Requires an x64 toolchain.
|
||||||
|
# =============================================================================
|
||||||
|
if(WXL_BUILD_HOST AND CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
|
# StormLib (vendored) supplies MPQ reading. Static, read-only use; no install/tests.
|
||||||
|
set(STORM_SKIP_INSTALL ON CACHE BOOL "" FORCE)
|
||||||
|
set(STORM_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
||||||
|
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/deps/stormlib" "${CMAKE_BINARY_DIR}/stormlib")
|
||||||
|
|
||||||
|
file(GLOB_RECURSE WXL_HOST_CORE CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/host/*.cpp")
|
||||||
|
file(GLOB_RECURSE WXL_HOST_SCRIPT CONFIGURE_DEPENDS
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/scripts/*/host/*.cpp"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/scripts/*/shared/*.cpp")
|
||||||
|
if(WXL_MODERN_ASSETS_EXCLUDE_REGEX)
|
||||||
|
list(FILTER WXL_HOST_SCRIPT EXCLUDE REGEX "${WXL_MODERN_ASSETS_EXCLUDE_REGEX}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# The shared infrastructure (leveled logger, env config) compiles straight into the host too.
|
||||||
|
file(GLOB WXL_COMMON_SRC CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/common/*.cpp")
|
||||||
|
|
||||||
|
add_executable(WarcraftXLHost
|
||||||
|
${WXL_HOST_CORE}
|
||||||
|
${WXL_HOST_SCRIPT}
|
||||||
|
${WXL_COMMON_SRC}
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/deps/flatbuffers/src/util.cpp")
|
||||||
|
set_target_properties(WarcraftXLHost PROPERTIES OUTPUT_NAME "WarcraftXLHost")
|
||||||
|
target_include_directories(WarcraftXLHost PRIVATE
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/host"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/deps/flatbuffers/include"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/deps/stormlib/src")
|
||||||
|
target_link_libraries(WarcraftXLHost PRIVATE storm)
|
||||||
|
target_compile_definitions(WarcraftXLHost PRIVATE ${WXL_DEFS} WXL_HOST=1)
|
||||||
|
|
||||||
|
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${WXL_HOST_CORE} ${WXL_HOST_SCRIPT})
|
||||||
|
|
||||||
|
# Deploy the host into the client's Utils folder after build.
|
||||||
|
if(CLIENT_PATH)
|
||||||
|
add_custom_command(TARGET WarcraftXLHost POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory "${CLIENT_PATH}/Utils"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:WarcraftXLHost>" "${CLIENT_PATH}/Utils/WarcraftXLHost.exe"
|
||||||
|
COMMENT "Deploy WarcraftXLHost.exe -> ${CLIENT_PATH}/Utils")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# A 64-bit configure that did not ask for the host builds nothing; nudge toward the right flags.
|
||||||
|
if(CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT WXL_BUILD_HOST)
|
||||||
|
message(WARNING "x64 configure without -DWXL_BUILD_HOST=ON builds nothing; the 32-bit family needs -A Win32.")
|
||||||
|
endif()
|
||||||
Vendored
+674
@@ -0,0 +1,674 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The GNU General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
the GNU General Public License is intended to guarantee your freedom to
|
||||||
|
share and change all versions of a program--to make sure it remains free
|
||||||
|
software for all its users. We, the Free Software Foundation, use the
|
||||||
|
GNU General Public License for most of our software; it applies also to
|
||||||
|
any other work released this way by its authors. You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, 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
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you
|
||||||
|
these rights or asking you to surrender the rights. Therefore, you have
|
||||||
|
certain responsibilities if you distribute copies of the software, or if
|
||||||
|
you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
|
freedoms that you received. You must make sure that they, too, receive
|
||||||
|
or can get the source code. And you must show them these terms so they
|
||||||
|
know their rights.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
|
that there is no warranty for this free software. For both users' and
|
||||||
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
|
changed, so that their problems will not be attributed erroneously to
|
||||||
|
authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run
|
||||||
|
modified versions of the software inside them, although the manufacturer
|
||||||
|
can do so. This is fundamentally incompatible with the aim of
|
||||||
|
protecting users' freedom to change the software. The systematic
|
||||||
|
pattern of such abuse occurs in the area of products for individuals to
|
||||||
|
use, which is precisely where it is most unacceptable. Therefore, we
|
||||||
|
have designed this version of the GPL to prohibit the practice for those
|
||||||
|
products. If such problems arise substantially in other domains, we
|
||||||
|
stand ready to extend this provision to those domains in future versions
|
||||||
|
of the GPL, as needed to protect the freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents.
|
||||||
|
States should not allow patents to restrict development and use of
|
||||||
|
software on general-purpose computers, but in those that do, we wish to
|
||||||
|
avoid the special danger that patents applied to a free program could
|
||||||
|
make it effectively proprietary. To prevent this, the GPL assures that
|
||||||
|
patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If 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 convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU Affero General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the special requirements of the GNU Affero General Public License,
|
||||||
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU 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
|
||||||
|
Program specifies that a certain numbered version of the GNU General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "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 PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
state the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program does terminal interaction, make it output a short
|
||||||
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
|
<program> Copyright (C) <year> <name of author>
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, your program's commands
|
||||||
|
might be different; for a GUI interface, you would use an "about box".
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
|
For more information on this, and how to apply and follow the GNU GPL, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
The GNU General Public License does not permit incorporating your program
|
||||||
|
into proprietary programs. If your program is a subroutine library, you
|
||||||
|
may consider it more useful to permit linking proprietary applications with
|
||||||
|
the library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License. But first, please read
|
||||||
|
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||||
Vendored
+674
@@ -0,0 +1,674 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The GNU General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
the GNU General Public License is intended to guarantee your freedom to
|
||||||
|
share and change all versions of a program--to make sure it remains free
|
||||||
|
software for all its users. We, the Free Software Foundation, use the
|
||||||
|
GNU General Public License for most of our software; it applies also to
|
||||||
|
any other work released this way by its authors. You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, 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
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you
|
||||||
|
these rights or asking you to surrender the rights. Therefore, you have
|
||||||
|
certain responsibilities if you distribute copies of the software, or if
|
||||||
|
you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
|
freedoms that you received. You must make sure that they, too, receive
|
||||||
|
or can get the source code. And you must show them these terms so they
|
||||||
|
know their rights.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
|
that there is no warranty for this free software. For both users' and
|
||||||
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
|
changed, so that their problems will not be attributed erroneously to
|
||||||
|
authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run
|
||||||
|
modified versions of the software inside them, although the manufacturer
|
||||||
|
can do so. This is fundamentally incompatible with the aim of
|
||||||
|
protecting users' freedom to change the software. The systematic
|
||||||
|
pattern of such abuse occurs in the area of products for individuals to
|
||||||
|
use, which is precisely where it is most unacceptable. Therefore, we
|
||||||
|
have designed this version of the GPL to prohibit the practice for those
|
||||||
|
products. If such problems arise substantially in other domains, we
|
||||||
|
stand ready to extend this provision to those domains in future versions
|
||||||
|
of the GPL, as needed to protect the freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents.
|
||||||
|
States should not allow patents to restrict development and use of
|
||||||
|
software on general-purpose computers, but in those that do, we wish to
|
||||||
|
avoid the special danger that patents applied to a free program could
|
||||||
|
make it effectively proprietary. To prevent this, the GPL assures that
|
||||||
|
patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If 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 convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU Affero General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the special requirements of the GNU Affero General Public License,
|
||||||
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU 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
|
||||||
|
Program specifies that a certain numbered version of the GNU General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "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 PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
state the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program does terminal interaction, make it output a short
|
||||||
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
|
<program> Copyright (C) <year> <name of author>
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, your program's commands
|
||||||
|
might be different; for a GUI interface, you would use an "about box".
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
|
For more information on this, and how to apply and follow the GNU GPL, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
The GNU General Public License does not permit incorporating your program
|
||||||
|
into proprietary programs. If your program is a subroutine library, you
|
||||||
|
may consider it more useful to permit linking proprietary applications with
|
||||||
|
the library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License. But first, please read
|
||||||
|
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||||
Vendored
+126
@@ -0,0 +1,126 @@
|
|||||||
|
# WarcraftXL
|
||||||
|
|
||||||
|
**A modding framework for the World of Warcraft 3.3.5a (build 12340) client.**
|
||||||
|
|
||||||
|
WarcraftXL loads into the running client and gives mods a clean, typed way to talk to the engine -
|
||||||
|
the same idea as RED4ext for Cyberpunk 2077 or SKSE for Skyrim. The framework owns the hard,
|
||||||
|
repetitive parts (getting into the process, the hook engine, client offsets, engine bindings, an
|
||||||
|
event bus, file-format contracts); your mods - here called **modules / scripts** - own the actual features.
|
||||||
|
|
||||||
|
> **Core principle.** If something is needed everywhere and always works the same way, it belongs in
|
||||||
|
> the core. Anything that is a *feature* - a decision, an effect, an editor - is a module. The core
|
||||||
|
> stays small and reusable; the modules stay free to do whatever they want.
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
`WarcraftXL.dll` is the framework. It boots inside the client, brings up the hook engine, and raises
|
||||||
|
a set of events. Each module is a small self-contained unit under `scripts/` that subscribes to those
|
||||||
|
events and uses the core's bindings to read and drive the game. Drop a module in, rebuild, and it is
|
||||||
|
live - no separate injector, no patched data files.
|
||||||
|
|
||||||
|
The core is organised as four pillars, so a module never touches a raw address itself:
|
||||||
|
|
||||||
|
| Pillar | Namespace | What it gives a module |
|
||||||
|
|---|---|---|
|
||||||
|
| **Offsets** | `wxl::offsets` | The curated client addresses and struct layouts. Internal - modules never include these directly. |
|
||||||
|
| **Bindings** | `wxl::game` | Typed, zero-overhead calls into engine functions (`Native<Fn>(addr)(args...)`) plus an enumerable catalog of `{name, address, signature}`. |
|
||||||
|
| **Events** | `wxl::events` | A POD-dispatch event bus. A module subclasses `EventScript` and binds member functions with `on<&Self::OnEndScene>(Event::OnEndScene)`. |
|
||||||
|
| **Assets** | `wxl::asset` | In-memory contracts for the client's file formats (ADT, WMO, M2, WDT, WDL) so modules read structured data, not byte soup. |
|
||||||
|
|
||||||
|
A module looks like this - bind in the constructor, react in the handler:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class MyModule final : public wxl::events::EventScript {
|
||||||
|
public:
|
||||||
|
MyModule() { on<&MyModule::OnEndScene>(wxl::events::Event::OnEndScene); }
|
||||||
|
void OnEndScene(const wxl::events::EndSceneArgs& a) { /* draw, read world, edit... */ }
|
||||||
|
};
|
||||||
|
MyModule g_myModule; // file-scope instance self-registers at load
|
||||||
|
```
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
├── core/ Hook · Logger · Mem · Main process bring-up, hook engine, entry point
|
||||||
|
├── offsets/ engine/ · game/ client addresses + struct layouts (internal)
|
||||||
|
├── game/ camera · doodad · world · ui typed engine bindings (the wxl::game pillar)
|
||||||
|
│ m2 · wmo · adt · unit · gx ·
|
||||||
|
│ io · mem ...
|
||||||
|
├── events/ Event · EventScript the event bus + the module base class
|
||||||
|
├── asset/ adt · wmo · m2 · wdt · wdl file-format contracts
|
||||||
|
├── services/ asset higher-level services over the pillars
|
||||||
|
└── runtime/ RenderHooks per-frame / device hooks the events ride on
|
||||||
|
|
||||||
|
scripts/ the modules (each builds into WarcraftXL.dll)
|
||||||
|
├── wxl-mini-noggit an in-client map editor (ImGui + 3D gizmo): pick a doodad, move/rotate/scale it
|
||||||
|
├── wxl-unit-outline a unit outline / highlight effect
|
||||||
|
└── wxl-glue-unlock glue-screen unlock
|
||||||
|
|
||||||
|
deps/ vendored: MinHook, Dear ImGui + ImGuizmo, StormLib, FlatBuffers
|
||||||
|
```
|
||||||
|
|
||||||
|
Every address the bindings rely on lives in `src/offsets/`, named and annotated. The reasoning behind
|
||||||
|
each one is kept in the project's RE documentation - the code follows it.
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
The target client is a 32-bit process, so everything builds **Win32**.
|
||||||
|
|
||||||
|
**Requirements**
|
||||||
|
- CMake ≥ 3.25
|
||||||
|
- A Win32 C++17 toolchain (Visual Studio 2022 recommended)
|
||||||
|
- A legally-obtained 3.3.5a (12340) client
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cmake -B build
|
||||||
|
cmake --build build --config Release --target WarcraftXL
|
||||||
|
```
|
||||||
|
|
||||||
|
Output: `WarcraftXL.dll`. Vendored dependencies build with the project.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
1. Place `WarcraftXL.dll` next to `Wow.exe` and load it into the client (import-table entry / loader).
|
||||||
|
2. Launch. The framework writes a startup log on bootstrap - check it to confirm modules came up.
|
||||||
|
|
||||||
|
Each client process launches its own `WarcraftXLHost.exe` session (IPC named objects are scoped by
|
||||||
|
the Wow.exe PID), so multiple concurrent clients do not share a mailbox.
|
||||||
|
|
||||||
|
> Modifying a client binary is on you: work on a **copy**, keep an untouched backup, and only point
|
||||||
|
> this at a client and server you are permitted to modify and connect to.
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
Thanks to everyone who has helped shape WarcraftXL, with code, reverse-engineering, ideas, or feedback:
|
||||||
|
|
||||||
|
- [Furioz](https://github.com/Furioz420)
|
||||||
|
- [Tester](https://github.com/TesterWoWDev)
|
||||||
|
- [Duskhaven](https://git.duskhaven.net/Duskhaven)
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
**WarcraftXL is free, and it always will be - forever.** Nothing here is gated, and nothing ever
|
||||||
|
will be. Sponsoring is completely optional - just a way to support the project and the time behind
|
||||||
|
it, if you want to and can.
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/sponsors/iThorgrim"><img src="https://raw.githubusercontent.com/iThorgrim/ithorgrim/refs/heads/main/assets/sponsor.svg" alt="Sponsor iThorgrim" height="48"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## Legal
|
||||||
|
|
||||||
|
WarcraftXL is an **interoperability project**. It distributes no Blizzard code and no game assets, and
|
||||||
|
runs only against a client you supply and own, reading that client's own files at runtime.
|
||||||
|
Reverse-engineering is limited to what is necessary for interoperability.
|
||||||
|
|
||||||
|
World of Warcraft and Wrath of the Lich King are trademarks of Blizzard Entertainment. This project is
|
||||||
|
not affiliated with or endorsed by Blizzard.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Released under the **GNU General Public License v3.0** - see [LICENSE](LICENSE).
|
||||||
|
|
||||||
|
Bundles [MinHook](https://github.com/TsudaKageyu/minhook) (© Tsuda Kageyu, BSD 2-Clause),
|
||||||
|
[Dear ImGui](https://github.com/ocornut/imgui) + [ImGuizmo](https://github.com/CedricGuillemet/ImGuizmo),
|
||||||
|
and [StormLib](https://github.com/ladislav-zezula/StormLib) under `deps/`, with their licenses retained.
|
||||||
Vendored
+135
@@ -0,0 +1,135 @@
|
|||||||
|
#requires -Version 5.1
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Build + deploy WarcraftXL: WarcraftXL.dll (injected), d3d9.dll (proxy) and wxl-patcher.exe (32-bit).
|
||||||
|
|
||||||
|
.PARAMETER Config
|
||||||
|
Build configuration. Default: Release.
|
||||||
|
|
||||||
|
.PARAMETER ClientPath
|
||||||
|
Client directory to deploy into. Optional once it has been cached by a first run.
|
||||||
|
|
||||||
|
.PARAMETER Clean
|
||||||
|
Delete the build directory before configuring (forces a from-scratch build).
|
||||||
|
|
||||||
|
.PARAMETER AutoPatch
|
||||||
|
After the build, run wxl-patcher on the client's Wow.exe. The patcher is idempotent
|
||||||
|
(it skips an already-patched exe and backs the original up to Wow.exe.orig on first run).
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
.\build.ps1
|
||||||
|
.EXAMPLE
|
||||||
|
.\build.ps1 -ClientPath "D:\Path\To\Client" -Clean
|
||||||
|
.EXAMPLE
|
||||||
|
.\build.ps1 -AutoPatch
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[string]$Config = "Release",
|
||||||
|
[string]$ClientPath,
|
||||||
|
[switch]$Clean,
|
||||||
|
[switch]$AutoPatch = true,
|
||||||
|
[switch]$BuildHost
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
$root = $PSScriptRoot
|
||||||
|
$buildDir = Join-Path $root "build\dll"
|
||||||
|
$buildHostDir = Join-Path $root "build\host"
|
||||||
|
|
||||||
|
if (-not (Test-Path (Join-Path $root "CMakeLists.txt"))) {
|
||||||
|
throw "CMakeLists.txt is missing from '$root'. Place build.ps1 in the project root directory (next to CMakeLists.txt)."
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-CachedClientPath([string]$cacheDir) {
|
||||||
|
$cache = Join-Path $cacheDir "CMakeCache.txt"
|
||||||
|
if (Test-Path $cache) {
|
||||||
|
$hit = Select-String -Path $cache -Pattern '^CLIENT_PATH:PATH=(.+)$' | Select-Object -First 1
|
||||||
|
if ($hit) { return $hit.Matches[0].Groups[1].Value.Trim() }
|
||||||
|
}
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $ClientPath) {
|
||||||
|
$ClientPath = Get-CachedClientPath $buildDir
|
||||||
|
}
|
||||||
|
if (-not $ClientPath) {
|
||||||
|
throw "No client path is known. Run the command once with -ClientPath '<client folder>' (it will be stored in the CMake cache)."
|
||||||
|
}
|
||||||
|
if (-not (Test-Path $ClientPath)) {
|
||||||
|
throw "Client path not found: $ClientPath"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Project : $root"
|
||||||
|
Write-Host "Client : $ClientPath"
|
||||||
|
Write-Host "Config : $Config"
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
function Invoke-Native([string]$exe, [string[]]$cmdArgs) {
|
||||||
|
Write-Host ">> $exe $($cmdArgs -join ' ')" -ForegroundColor Cyan
|
||||||
|
$prev = $ErrorActionPreference
|
||||||
|
$ErrorActionPreference = "Continue"
|
||||||
|
try { & $exe @cmdArgs } finally { $ErrorActionPreference = $prev }
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw "Failure ($LASTEXITCODE): $exe $($cmdArgs -join ' ')" }
|
||||||
|
}
|
||||||
|
|
||||||
|
function Build-Dll {
|
||||||
|
Write-Host "=== WarcraftXL.dll (32-bit) ===" -ForegroundColor Green
|
||||||
|
|
||||||
|
if ($Clean -and (Test-Path $buildDir)) {
|
||||||
|
Write-Host "Clean $buildDir" -ForegroundColor Yellow
|
||||||
|
Remove-Item -Recurse -Force $buildDir
|
||||||
|
}
|
||||||
|
|
||||||
|
$needConfigure = $Clean `
|
||||||
|
-or $PSBoundParameters.ContainsKey('ClientPath') `
|
||||||
|
-or (-not (Test-Path (Join-Path $buildDir "CMakeCache.txt")))
|
||||||
|
if ($needConfigure) {
|
||||||
|
Invoke-Native "cmake" @("-S", $root, "-B", $buildDir, "-A", "Win32", "-DCLIENT_PATH=$ClientPath")
|
||||||
|
}
|
||||||
|
|
||||||
|
Invoke-Native "cmake" @("--build", $buildDir, "--config", $Config, "--parallel")
|
||||||
|
Write-Host ""
|
||||||
|
}
|
||||||
|
|
||||||
|
function Build-Host {
|
||||||
|
Write-Host "=== WarcraftXLHost.exe (64-bit) ===" -ForegroundColor Green
|
||||||
|
|
||||||
|
if ($Clean -and (Test-Path $buildHostDir)) {
|
||||||
|
Write-Host "Clean $buildHostDir" -ForegroundColor Yellow
|
||||||
|
Remove-Item -Recurse -Force $buildHostDir
|
||||||
|
}
|
||||||
|
|
||||||
|
$needConfigure = $Clean `
|
||||||
|
-or $PSBoundParameters.ContainsKey('ClientPath') `
|
||||||
|
-or (-not (Test-Path (Join-Path $buildHostDir "CMakeCache.txt")))
|
||||||
|
if ($needConfigure) {
|
||||||
|
Invoke-Native "cmake" @("-S", $root, "-B", $buildHostDir, "-A", "x64", "-DWXL_BUILD_HOST=ON", "-DCLIENT_PATH=$ClientPath")
|
||||||
|
}
|
||||||
|
|
||||||
|
Invoke-Native "cmake" @("--build", $buildHostDir, "--config", $Config, "--parallel")
|
||||||
|
Write-Host ""
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-AutoPatch {
|
||||||
|
$patcher = Join-Path $buildDir "$Config\wxl-patcher.exe"
|
||||||
|
if (-not (Test-Path $patcher)) { $patcher = Join-Path $ClientPath "wxl-patcher.exe" }
|
||||||
|
if (-not (Test-Path $patcher)) {
|
||||||
|
throw "wxl-patcher.exe not found. Build first (.\build.ps1)."
|
||||||
|
}
|
||||||
|
$wow = Join-Path $ClientPath "Wow.exe"
|
||||||
|
if (-not (Test-Path $wow)) { throw "Wow.exe not found: $wow" }
|
||||||
|
|
||||||
|
Write-Host "=== AutoPatch ===" -ForegroundColor Green
|
||||||
|
Invoke-Native $patcher @($wow)
|
||||||
|
Write-Host ""
|
||||||
|
}
|
||||||
|
|
||||||
|
$sw = [System.Diagnostics.Stopwatch]::StartNew()
|
||||||
|
|
||||||
|
Build-Dll
|
||||||
|
if ($BuildHost) { Build-Host }
|
||||||
|
if ($AutoPatch) { Invoke-AutoPatch }
|
||||||
|
|
||||||
|
$sw.Stop()
|
||||||
|
Write-Host "OK - build + deploy in $([int]$sw.Elapsed.TotalSeconds)s -> $ClientPath" -ForegroundColor Green
|
||||||
Vendored
+9
@@ -0,0 +1,9 @@
|
|||||||
|
Vendored third-party dependencies (self-contained).
|
||||||
|
|
||||||
|
Contents:
|
||||||
|
stormlib/ - MPQ archive access. Used by: host (MpqStore). Built via add_subdirectory.
|
||||||
|
flatbuffers/ - FlexBuffers payloads for the IPC contract. Used by: host + DLL (ipc/).
|
||||||
|
Header-only for our use plus src/util.cpp compiled into the host.
|
||||||
|
minhook/ - inline detour engine. Used by: DLL only (core/Hook). Wired with the DLL target.
|
||||||
|
|
||||||
|
These are the only external dependencies.
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
---
|
||||||
|
buildifier: latest
|
||||||
|
matrix:
|
||||||
|
bazel:
|
||||||
|
- 7.x
|
||||||
|
- 8.x
|
||||||
|
tasks:
|
||||||
|
verify_ubuntu2004:
|
||||||
|
platform: ubuntu2004
|
||||||
|
bazel: ${{ bazel }}
|
||||||
|
environment:
|
||||||
|
CC: clang
|
||||||
|
SWIFT_VERSION: "5.10"
|
||||||
|
SWIFT_HOME: "$HOME/swift-$SWIFT_VERSION"
|
||||||
|
PATH: "$PATH:$SWIFT_HOME/usr/bin"
|
||||||
|
shell_commands:
|
||||||
|
- "echo --- Downloading and extracting Swift $SWIFT_VERSION to $SWIFT_HOME"
|
||||||
|
- "mkdir $SWIFT_HOME"
|
||||||
|
- "curl https://download.swift.org/swift-${SWIFT_VERSION}-release/ubuntu2004/swift-${SWIFT_VERSION}-RELEASE/swift-${SWIFT_VERSION}-RELEASE-ubuntu20.04.tar.gz | tar xvz --strip-components=1 -C $SWIFT_HOME"
|
||||||
|
build_targets:
|
||||||
|
- "//..."
|
||||||
|
test_targets:
|
||||||
|
- "//..."
|
||||||
|
verify_ubuntu2204:
|
||||||
|
platform: ubuntu2204
|
||||||
|
bazel: ${{ bazel }}
|
||||||
|
environment:
|
||||||
|
CC: clang
|
||||||
|
SWIFT_VERSION: "5.10"
|
||||||
|
SWIFT_HOME: "$HOME/swift-$SWIFT_VERSION"
|
||||||
|
PATH: "$PATH:$SWIFT_HOME/usr/bin"
|
||||||
|
shell_commands:
|
||||||
|
- "echo --- Downloading and extracting Swift $SWIFT_VERSION to $SWIFT_HOME"
|
||||||
|
- "mkdir $SWIFT_HOME"
|
||||||
|
- "curl https://download.swift.org/swift-${SWIFT_VERSION}-release/ubuntu2204/swift-${SWIFT_VERSION}-RELEASE/swift-${SWIFT_VERSION}-RELEASE-ubuntu22.04.tar.gz | tar xvz --strip-components=1 -C $SWIFT_HOME"
|
||||||
|
build_targets:
|
||||||
|
- "//..."
|
||||||
|
test_targets:
|
||||||
|
- "//..."
|
||||||
|
test_module_cpp:
|
||||||
|
platform: ubuntu2204
|
||||||
|
bazel: ${{ bazel }}
|
||||||
|
working_directory: tests/bazel_repository_test_dir
|
||||||
|
build_targets:
|
||||||
|
- "//..."
|
||||||
|
test_module_ts:
|
||||||
|
platform: ubuntu2204
|
||||||
|
bazel: ${{ bazel }}
|
||||||
|
working_directory: tests/ts/bazel_repository_test_dir
|
||||||
|
test_targets:
|
||||||
|
- "//..."
|
||||||
|
verify_macos:
|
||||||
|
platform: macos
|
||||||
|
bazel: ${{ bazel }}
|
||||||
|
xcode_version: "15.2"
|
||||||
|
build_targets:
|
||||||
|
- "//:flatbuffers"
|
||||||
|
- "//:flatc"
|
||||||
|
test_targets:
|
||||||
|
- "//tests:flatbuffers_test"
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
ts/node_modules
|
||||||
|
|
||||||
|
# Test workspaces
|
||||||
|
tests/bazel_repository_test_dir
|
||||||
|
tests/ts/bazel_repository_test_dir
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
# We cannot use "common" here because the "version" command doesn't support
|
||||||
|
# --deleted_packages. We need to specify it for both build and query instead.
|
||||||
|
build --deleted_packages=tests/bazel_repository_test_dir,tests/ts/bazel_repository_test_dir
|
||||||
|
query --deleted_packages=tests/bazel_repository_test_dir,tests/ts/bazel_repository_test_dir
|
||||||
|
# Point tools such as coursier (used in rules_jvm_external) to Bazel's internal JDK
|
||||||
|
# suggested in https://github.com/bazelbuild/rules_jvm_external/issues/445
|
||||||
|
common --repo_env=JAVA_HOME=../bazel_tools/jdk
|
||||||
|
common --action_env=JAVA_HOME=../bazel_tools/jdk
|
||||||
|
# Workaround "Error: need --enable_runfiles on Windows for to support rules_js"
|
||||||
|
common:windows --enable_runfiles
|
||||||
|
# Swift is not required on Windows
|
||||||
|
common:windows --deleted_packages=swift
|
||||||
|
# Ignore warnings in external dependencies
|
||||||
|
build --per_file_copt=external/.*@-Wno-everything --host_per_file_copt=external/.*@-Wno-everything
|
||||||
|
# Honor the setting of `skipLibCheck` in the tsconfig.json file.
|
||||||
|
common --@aspect_rules_ts//ts:skipLibCheck=honor_tsconfig
|
||||||
|
# Use "tsc" as the transpiler when ts_project has no `transpiler` set.
|
||||||
|
common --@aspect_rules_ts//ts:default_to_tsc_transpiler
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
BasedOnStyle: Google
|
||||||
|
...
|
||||||
|
|
||||||
+347
@@ -0,0 +1,347 @@
|
|||||||
|
---
|
||||||
|
FormatStyle: "file"
|
||||||
|
WarningsAsErrors: "*"
|
||||||
|
HeaderFilterRegex: ".*"
|
||||||
|
Checks: "google-build-explicit-make-pair,
|
||||||
|
google-build-namespaces,
|
||||||
|
google-build-using-namespace,
|
||||||
|
google-default-arguments,
|
||||||
|
google-explicit-constructor,
|
||||||
|
google-global-names-in-headers,
|
||||||
|
google-objc-avoid-nsobject-new,
|
||||||
|
google-objc-avoid-throwing-exception,
|
||||||
|
google-objc-function-naming,
|
||||||
|
google-objc-global-variable-declaration,
|
||||||
|
google-readability-avoid-underscore-in-googletest-name,
|
||||||
|
google-readability-braces-around-statements,
|
||||||
|
google-readability-casting,
|
||||||
|
google-readability-function-size,
|
||||||
|
google-readability-namespace-comments,
|
||||||
|
google-runtime-int,
|
||||||
|
google-runtime-operator,
|
||||||
|
google-upgrade-googletest-case,
|
||||||
|
clang-analyzer-apiModeling.StdCLibraryFunctions,
|
||||||
|
clang-analyzer-apiModeling.TrustNonnull,
|
||||||
|
clang-analyzer-apiModeling.google.GTest,
|
||||||
|
clang-analyzer-apiModeling.llvm.CastValue,
|
||||||
|
clang-analyzer-apiModeling.llvm.ReturnValue,
|
||||||
|
clang-analyzer-core.CallAndMessage,
|
||||||
|
clang-analyzer-core.CallAndMessageModeling,
|
||||||
|
clang-analyzer-core.DivideZero,
|
||||||
|
clang-analyzer-core.DynamicTypePropagation,
|
||||||
|
clang-analyzer-core.NonNullParamChecker,
|
||||||
|
clang-analyzer-core.NonnilStringConstants,
|
||||||
|
clang-analyzer-core.NullDereference,
|
||||||
|
clang-analyzer-core.StackAddrEscapeBase,
|
||||||
|
clang-analyzer-core.StackAddressEscape,
|
||||||
|
clang-analyzer-core.UndefinedBinaryOperatorResult,
|
||||||
|
clang-analyzer-core.VLASize,
|
||||||
|
clang-analyzer-core.builtin.BuiltinFunctions,
|
||||||
|
clang-analyzer-core.builtin.NoReturnFunctions,
|
||||||
|
clang-analyzer-core.uninitialized.ArraySubscript,
|
||||||
|
clang-analyzer-core.uninitialized.Assign,
|
||||||
|
clang-analyzer-core.uninitialized.Branch,
|
||||||
|
clang-analyzer-core.uninitialized.CapturedBlockVariable,
|
||||||
|
clang-analyzer-core.uninitialized.UndefReturn,
|
||||||
|
clang-analyzer-cplusplus.InnerPointer,
|
||||||
|
clang-analyzer-cplusplus.Move,
|
||||||
|
clang-analyzer-cplusplus.NewDelete,
|
||||||
|
clang-analyzer-cplusplus.NewDeleteLeaks,
|
||||||
|
clang-analyzer-cplusplus.PlacementNew,
|
||||||
|
clang-analyzer-cplusplus.PureVirtualCall,
|
||||||
|
clang-analyzer-cplusplus.SelfAssignment,
|
||||||
|
clang-analyzer-cplusplus.SmartPtrModeling,
|
||||||
|
clang-analyzer-cplusplus.StringChecker,
|
||||||
|
clang-analyzer-cplusplus.VirtualCallModeling,
|
||||||
|
clang-analyzer-deadcode.DeadStores,
|
||||||
|
clang-analyzer-fuchsia.HandleChecker,
|
||||||
|
clang-analyzer-nullability.NullPassedToNonnull,
|
||||||
|
clang-analyzer-nullability.NullReturnedFromNonnull,
|
||||||
|
clang-analyzer-nullability.NullabilityBase,
|
||||||
|
clang-analyzer-nullability.NullableDereferenced,
|
||||||
|
clang-analyzer-nullability.NullablePassedToNonnull,
|
||||||
|
clang-analyzer-nullability.NullableReturnedFromNonnull,
|
||||||
|
clang-analyzer-optin.cplusplus.UninitializedObject,
|
||||||
|
clang-analyzer-optin.cplusplus.VirtualCall,
|
||||||
|
clang-analyzer-optin.mpi.MPI-Checker,
|
||||||
|
clang-analyzer-optin.osx.OSObjectCStyleCast,
|
||||||
|
clang-analyzer-optin.osx.cocoa.localizability.EmptyLocalizationContextChecker,
|
||||||
|
clang-analyzer-optin.osx.cocoa.localizability.NonLocalizedStringChecker,
|
||||||
|
clang-analyzer-optin.performance.GCDAntipattern,
|
||||||
|
clang-analyzer-optin.performance.Padding,
|
||||||
|
clang-analyzer-optin.portability.UnixAPI,
|
||||||
|
clang-analyzer-osx.API,
|
||||||
|
clang-analyzer-osx.MIG,
|
||||||
|
clang-analyzer-osx.NSOrCFErrorDerefChecker,
|
||||||
|
clang-analyzer-osx.NumberObjectConversion,
|
||||||
|
clang-analyzer-osx.OSObjectRetainCount,
|
||||||
|
clang-analyzer-osx.ObjCProperty,
|
||||||
|
clang-analyzer-osx.SecKeychainAPI,
|
||||||
|
clang-analyzer-osx.cocoa.AtSync,
|
||||||
|
clang-analyzer-osx.cocoa.AutoreleaseWrite,
|
||||||
|
clang-analyzer-osx.cocoa.ClassRelease,
|
||||||
|
clang-analyzer-osx.cocoa.Dealloc,
|
||||||
|
clang-analyzer-osx.cocoa.IncompatibleMethodTypes,
|
||||||
|
clang-analyzer-osx.cocoa.Loops,
|
||||||
|
clang-analyzer-osx.cocoa.MissingSuperCall,
|
||||||
|
clang-analyzer-osx.cocoa.NSAutoreleasePool,
|
||||||
|
clang-analyzer-osx.cocoa.NSError,
|
||||||
|
clang-analyzer-osx.cocoa.NilArg,
|
||||||
|
clang-analyzer-osx.cocoa.NonNilReturnValue,
|
||||||
|
clang-analyzer-osx.cocoa.ObjCGenerics,
|
||||||
|
clang-analyzer-osx.cocoa.RetainCount,
|
||||||
|
clang-analyzer-osx.cocoa.RetainCountBase,
|
||||||
|
clang-analyzer-osx.cocoa.RunLoopAutoreleaseLeak,
|
||||||
|
clang-analyzer-osx.cocoa.SelfInit,
|
||||||
|
clang-analyzer-osx.cocoa.SuperDealloc,
|
||||||
|
clang-analyzer-osx.cocoa.UnusedIvars,
|
||||||
|
clang-analyzer-osx.cocoa.VariadicMethodTypes,
|
||||||
|
clang-analyzer-osx.coreFoundation.CFError,
|
||||||
|
clang-analyzer-osx.coreFoundation.CFNumber,
|
||||||
|
clang-analyzer-osx.coreFoundation.CFRetainRelease,
|
||||||
|
clang-analyzer-osx.coreFoundation.containers.OutOfBounds,
|
||||||
|
clang-analyzer-osx.coreFoundation.containers.PointerSizedValues,
|
||||||
|
clang-analyzer-security.FloatLoopCounter,
|
||||||
|
clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,
|
||||||
|
clang-analyzer-security.insecureAPI.SecuritySyntaxChecker,
|
||||||
|
clang-analyzer-security.insecureAPI.UncheckedReturn,
|
||||||
|
clang-analyzer-security.insecureAPI.bcmp,
|
||||||
|
clang-analyzer-security.insecureAPI.bcopy,
|
||||||
|
clang-analyzer-security.insecureAPI.bzero,
|
||||||
|
clang-analyzer-security.insecureAPI.decodeValueOfObjCType,
|
||||||
|
clang-analyzer-security.insecureAPI.getpw,
|
||||||
|
clang-analyzer-security.insecureAPI.gets,
|
||||||
|
clang-analyzer-security.insecureAPI.mkstemp,
|
||||||
|
clang-analyzer-security.insecureAPI.mktemp,
|
||||||
|
clang-analyzer-security.insecureAPI.rand,
|
||||||
|
clang-analyzer-security.insecureAPI.strcpy,
|
||||||
|
clang-analyzer-security.insecureAPI.vfork,
|
||||||
|
clang-analyzer-unix.API,
|
||||||
|
clang-analyzer-unix.DynamicMemoryModeling,
|
||||||
|
clang-analyzer-unix.Malloc,
|
||||||
|
clang-analyzer-unix.MallocSizeof,
|
||||||
|
clang-analyzer-unix.MismatchedDeallocator,
|
||||||
|
clang-analyzer-unix.Vfork,
|
||||||
|
clang-analyzer-unix.cstring.BadSizeArg,
|
||||||
|
clang-analyzer-unix.cstring.CStringModeling,
|
||||||
|
clang-analyzer-unix.cstring.NullArg,
|
||||||
|
clang-analyzer-valist.CopyToSelf,
|
||||||
|
clang-analyzer-valist.Uninitialized,
|
||||||
|
clang-analyzer-valist.Unterminated,
|
||||||
|
clang-analyzer-valist.ValistBase,
|
||||||
|
clang-analyzer-webkit.NoUncountedMemberChecker,
|
||||||
|
clang-analyzer-webkit.RefCntblBaseVirtualDtor,
|
||||||
|
clang-analyzer-webkit.UncountedLambdaCapturesChecker,
|
||||||
|
|
||||||
|
################################################ Optional checks ################################################
|
||||||
|
|
||||||
|
#google-readability-todo,
|
||||||
|
#bugprone-argument-comment,
|
||||||
|
#bugprone-assert-side-effect,
|
||||||
|
#bugprone-bad-signal-to-kill-thread,
|
||||||
|
#bugprone-bool-pointer-implicit-conversion,
|
||||||
|
#bugprone-branch-clone,
|
||||||
|
#bugprone-copy-constructor-init,
|
||||||
|
#bugprone-dangling-handle,
|
||||||
|
#bugprone-dynamic-static-initializers,
|
||||||
|
#bugprone-easily-swappable-parameters,
|
||||||
|
#bugprone-exception-escape,
|
||||||
|
#bugprone-fold-init-type,
|
||||||
|
#bugprone-forward-declaration-namespace,
|
||||||
|
#bugprone-forwarding-reference-overload,
|
||||||
|
#bugprone-implicit-widening-of-multiplication-result,
|
||||||
|
#bugprone-inaccurate-erase,
|
||||||
|
#bugprone-incorrect-roundings,
|
||||||
|
#bugprone-infinite-loop,
|
||||||
|
#bugprone-integer-division,
|
||||||
|
#bugprone-lambda-function-name,
|
||||||
|
#bugprone-macro-parentheses,
|
||||||
|
#bugprone-macro-repeated-side-effects,
|
||||||
|
#bugprone-misplaced-operator-in-strlen-in-alloc,
|
||||||
|
#bugprone-misplaced-pointer-arithmetic-in-alloc,
|
||||||
|
#bugprone-misplaced-widening-cast,
|
||||||
|
#bugprone-move-forwarding-reference,
|
||||||
|
#bugprone-multiple-statement-macro,
|
||||||
|
#bugprone-narrowing-conversions,
|
||||||
|
#bugprone-no-escape,
|
||||||
|
#bugprone-not-null-terminated-result,
|
||||||
|
#bugprone-parent-virtual-call,
|
||||||
|
#bugprone-posix-return,
|
||||||
|
#bugprone-redundant-branch-condition,
|
||||||
|
#bugprone-reserved-identifier,
|
||||||
|
#bugprone-signal-handler,
|
||||||
|
#bugprone-signed-char-misuse,
|
||||||
|
#bugprone-sizeof-container,
|
||||||
|
#bugprone-sizeof-expression,
|
||||||
|
#bugprone-spuriously-wake-up-functions,
|
||||||
|
#bugprone-string-constructor,
|
||||||
|
#bugprone-string-integer-assignment,
|
||||||
|
#bugprone-string-literal-with-embedded-nul,
|
||||||
|
#bugprone-stringview-nullptr,
|
||||||
|
#bugprone-suspicious-enum-usage,
|
||||||
|
#bugprone-suspicious-include,
|
||||||
|
#bugprone-suspicious-memory-comparison,
|
||||||
|
#bugprone-suspicious-memset-usage,
|
||||||
|
#bugprone-suspicious-missing-comma,
|
||||||
|
#bugprone-suspicious-semicolon,
|
||||||
|
#bugprone-suspicious-string-compare,
|
||||||
|
#bugprone-swapped-arguments,
|
||||||
|
#bugprone-terminating-continue,
|
||||||
|
#bugprone-throw-keyword-missing,
|
||||||
|
#bugprone-too-small-loop-variable,
|
||||||
|
#bugprone-undefined-memory-manipulation,
|
||||||
|
#bugprone-undelegated-constructor,
|
||||||
|
#bugprone-unhandled-exception-at-new,
|
||||||
|
#bugprone-unhandled-self-assignment,
|
||||||
|
#bugprone-unused-raii,
|
||||||
|
#bugprone-unused-return-value,
|
||||||
|
#bugprone-use-after-move,
|
||||||
|
#bugprone-virtual-near-miss,
|
||||||
|
#cppcoreguidelines-avoid-c-arrays,
|
||||||
|
#cppcoreguidelines-avoid-goto,
|
||||||
|
#cppcoreguidelines-avoid-magic-numbers,
|
||||||
|
#cppcoreguidelines-avoid-non-const-global-variables,
|
||||||
|
#cppcoreguidelines-c-copy-assignment-signature,
|
||||||
|
#cppcoreguidelines-explicit-virtual-functions,
|
||||||
|
#cppcoreguidelines-init-variables,
|
||||||
|
#cppcoreguidelines-interfaces-global-init,
|
||||||
|
#cppcoreguidelines-macro-usage,
|
||||||
|
#cppcoreguidelines-narrowing-conversions,
|
||||||
|
#cppcoreguidelines-no-malloc,
|
||||||
|
#cppcoreguidelines-non-private-member-variables-in-classes,
|
||||||
|
#cppcoreguidelines-owning-memory,
|
||||||
|
#cppcoreguidelines-prefer-member-initializer,
|
||||||
|
#cppcoreguidelines-pro-bounds-array-to-pointer-decay,
|
||||||
|
#cppcoreguidelines-pro-bounds-constant-array-index,
|
||||||
|
#cppcoreguidelines-pro-bounds-pointer-arithmetic,
|
||||||
|
#cppcoreguidelines-pro-type-const-cast,
|
||||||
|
#cppcoreguidelines-pro-type-cstyle-cast,
|
||||||
|
#cppcoreguidelines-pro-type-member-init,
|
||||||
|
#cppcoreguidelines-pro-type-reinterpret-cast,
|
||||||
|
#cppcoreguidelines-pro-type-static-cast-downcast,
|
||||||
|
#cppcoreguidelines-pro-type-union-access,
|
||||||
|
#cppcoreguidelines-pro-type-vararg,
|
||||||
|
#cppcoreguidelines-slicing,
|
||||||
|
#cppcoreguidelines-special-member-functions,
|
||||||
|
#cppcoreguidelines-virtual-class-destructor,
|
||||||
|
#hicpp-avoid-c-arrays,
|
||||||
|
#hicpp-avoid-goto,
|
||||||
|
#hicpp-braces-around-statements,
|
||||||
|
#hicpp-deprecated-headers,
|
||||||
|
#hicpp-exception-baseclass,
|
||||||
|
#hicpp-explicit-conversions,
|
||||||
|
#hicpp-function-size,
|
||||||
|
#hicpp-invalid-access-moved,
|
||||||
|
#hicpp-member-init,
|
||||||
|
#hicpp-move-const-arg,
|
||||||
|
#hicpp-multiway-paths-covered,
|
||||||
|
#hicpp-named-parameter,
|
||||||
|
#hicpp-new-delete-operators,
|
||||||
|
#hicpp-no-array-decay,
|
||||||
|
#hicpp-no-assembler,
|
||||||
|
#hicpp-no-malloc,
|
||||||
|
#hicpp-noexcept-move,
|
||||||
|
#hicpp-signed-bitwise,
|
||||||
|
#hicpp-special-member-functions,
|
||||||
|
#hicpp-static-assert,
|
||||||
|
#hicpp-undelegated-constructor,
|
||||||
|
#hicpp-uppercase-literal-suffix,
|
||||||
|
#hicpp-use-auto,
|
||||||
|
#hicpp-use-emplace,
|
||||||
|
#hicpp-use-equals-default,
|
||||||
|
#hicpp-use-equals-delete,
|
||||||
|
#hicpp-use-noexcept,
|
||||||
|
#hicpp-use-nullptr,
|
||||||
|
#hicpp-use-override,
|
||||||
|
#hicpp-vararg,
|
||||||
|
#modernize-avoid-bind,
|
||||||
|
#modernize-avoid-c-arrays,
|
||||||
|
#modernize-concat-nested-namespaces,
|
||||||
|
#modernize-deprecated-headers,
|
||||||
|
#modernize-deprecated-ios-base-aliases,
|
||||||
|
#modernize-loop-convert,
|
||||||
|
#modernize-make-shared,
|
||||||
|
#modernize-make-unique,
|
||||||
|
#modernize-pass-by-value,
|
||||||
|
#modernize-raw-string-literal,
|
||||||
|
#modernize-redundant-void-arg,
|
||||||
|
#modernize-replace-auto-ptr,
|
||||||
|
#modernize-replace-disallow-copy-and-assign-macro,
|
||||||
|
#modernize-replace-random-shuffle,
|
||||||
|
#modernize-return-braced-init-list,
|
||||||
|
#modernize-shrink-to-fit,
|
||||||
|
#modernize-unary-static-assert,
|
||||||
|
#modernize-use-auto,
|
||||||
|
#modernize-use-bool-literals,
|
||||||
|
#modernize-use-default-member-init,
|
||||||
|
#modernize-use-emplace,
|
||||||
|
#modernize-use-equals-default,
|
||||||
|
#modernize-use-equals-delete,
|
||||||
|
#modernize-use-nodiscard,
|
||||||
|
#modernize-use-noexcept,
|
||||||
|
#modernize-use-nullptr,
|
||||||
|
#modernize-use-override,
|
||||||
|
#modernize-use-trailing-return-type,
|
||||||
|
#modernize-use-transparent-functors,
|
||||||
|
#modernize-use-uncaught-exceptions,
|
||||||
|
#modernize-use-using,
|
||||||
|
#performance-faster-string-find,
|
||||||
|
#performance-for-range-copy,
|
||||||
|
#performance-implicit-conversion-in-loop,
|
||||||
|
#performance-inefficient-algorithm,
|
||||||
|
#performance-inefficient-string-concatenation,
|
||||||
|
#performance-inefficient-vector-operation,
|
||||||
|
#performance-move-const-arg,
|
||||||
|
#performance-move-constructor-init,
|
||||||
|
#performance-no-automatic-move,
|
||||||
|
#performance-no-int-to-ptr,
|
||||||
|
#performance-noexcept-move-constructor,
|
||||||
|
#performance-trivially-destructible,
|
||||||
|
#performance-type-promotion-in-math-fn,
|
||||||
|
#performance-unnecessary-copy-initialization,
|
||||||
|
#performance-unnecessary-value-param,
|
||||||
|
#portability-restrict-system-includes,
|
||||||
|
#portability-simd-intrinsics,
|
||||||
|
#readability-avoid-const-params-in-decls,
|
||||||
|
#readability-braces-around-statements,
|
||||||
|
#readability-const-return-type,
|
||||||
|
#readability-container-contains,
|
||||||
|
#readability-container-data-pointer,
|
||||||
|
#readability-container-size-empty,
|
||||||
|
#readability-convert-member-functions-to-static,
|
||||||
|
#readability-delete-null-pointer,
|
||||||
|
#readability-duplicate-include,
|
||||||
|
#readability-else-after-return,
|
||||||
|
#readability-function-cognitive-complexity,
|
||||||
|
#readability-function-size,
|
||||||
|
#readability-identifier-length,
|
||||||
|
#readability-identifier-naming,
|
||||||
|
#readability-implicit-bool-conversion,
|
||||||
|
#readability-inconsistent-declaration-parameter-name,
|
||||||
|
#readability-isolate-declaration,
|
||||||
|
#readability-magic-numbers,
|
||||||
|
#readability-make-member-function-const,
|
||||||
|
#readability-misleading-indentation,
|
||||||
|
#readability-misplaced-array-index,
|
||||||
|
#readability-named-parameter,
|
||||||
|
#readability-non-const-parameter,
|
||||||
|
#readability-qualified-auto,
|
||||||
|
#readability-redundant-access-specifiers,
|
||||||
|
#readability-redundant-control-flow,
|
||||||
|
#readability-redundant-declaration,
|
||||||
|
#readability-redundant-function-ptr-dereference,
|
||||||
|
#readability-redundant-member-init,
|
||||||
|
#readability-redundant-preprocessor,
|
||||||
|
#readability-redundant-smartptr-get,
|
||||||
|
#readability-redundant-string-cstr,
|
||||||
|
#readability-redundant-string-init,
|
||||||
|
#readability-simplify-boolean-expr,
|
||||||
|
#readability-simplify-subscript-expr,
|
||||||
|
#readability-static-accessed-through-instance,
|
||||||
|
#readability-static-definition-in-anonymous-namespace,
|
||||||
|
#readability-string-compare,
|
||||||
|
#readability-suspicious-call-argument,
|
||||||
|
#readability-uniqueptr-delete-release,
|
||||||
|
#readability-uppercase-literal-suffix,
|
||||||
|
#readability-use-anyofallof
|
||||||
|
"
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
root = true
|
||||||
|
# Don't set line endings to avoid conflict with core.autocrlf flag.
|
||||||
|
# Line endings on checkout/checkin are controlled by .gitattributes file.
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# Set the default behavior, in case people don't have core.autocrlf set.
|
||||||
|
* text=auto
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# Default owner
|
||||||
|
* @dbaileychess derekbailey@google.com
|
||||||
|
|
||||||
|
# Prevent modification of this file
|
||||||
|
.github/CODEOWNERS @dbaileychess derekbailey@google.com
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
Thank you for submitting an issue!
|
||||||
|
|
||||||
|
Please make sure you include the names of the affected language(s), compiler version(s), operating system version(s), and FlatBuffers version(s) in your issue title.
|
||||||
|
|
||||||
|
This helps us get the correct maintainers to look at your issue. Here are examples of good titles:
|
||||||
|
|
||||||
|
- Crash when accessing FlatBuffer [C++, gcc 4.8, OS X, master]
|
||||||
|
- Flatc converts a protobuf 'bytes' field to 'string' in fbs schema file [all languages, FlatBuffers 1.4]
|
||||||
|
|
||||||
|
Include other details as appropriate.
|
||||||
|
|
||||||
|
Thanks!
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
name: 404 Doc
|
||||||
|
about: To fix broken documentation links
|
||||||
|
title: "[Doc 404]"
|
||||||
|
labels: documentation
|
||||||
|
assignees: dbaileychess
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Target URL:
|
||||||
|
[Optional] Source Site:
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
Thank you for submitting a PR!
|
||||||
|
|
||||||
|
Please delete this standard text once you've created your own description.
|
||||||
|
|
||||||
|
If you make changes to any of the code generators (`src/idl_gen*`) be sure to
|
||||||
|
[build](https://google.github.io/flatbuffers/flatbuffers_guide_building.html) your project, as it will generate code based on the changes. If necessary
|
||||||
|
the code generation script can be directly run (`scripts/generate_code.py`),
|
||||||
|
requires Python3. This allows us to better see the effect of the PR.
|
||||||
|
|
||||||
|
If your PR includes C++ code, please adhere to the
|
||||||
|
[Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html),
|
||||||
|
and don't forget we try to support older compilers (e.g. VS2010, GCC 4.6.3),
|
||||||
|
so only some C++11 support is available.
|
||||||
|
|
||||||
|
For any C++ changes, please make sure to run `sh scripts/clang-format-git.sh`
|
||||||
|
|
||||||
|
Include other details as appropriate.
|
||||||
|
|
||||||
|
Thanks!
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
# Configuration for Auto Labeler during pull request
|
||||||
|
#
|
||||||
|
# See https://github.com/actions/labeler for file format
|
||||||
|
# and https://github.com/google/flatbuffers/labels for a list of valid labels
|
||||||
|
#
|
||||||
|
# See .github/workflows/label.yml for Github Action workflow script
|
||||||
|
|
||||||
|
"c#":
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- '**/*.cs'
|
||||||
|
- 'net/**/*'
|
||||||
|
- 'tests/FlatBuffers.Test/**/*'
|
||||||
|
- 'tests/FlatBuffers.Benchmarks/**/*'
|
||||||
|
- 'src/idl_gen_csharp.cpp'
|
||||||
|
|
||||||
|
swift:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- '**/*.swift'
|
||||||
|
- 'swift/**/*'
|
||||||
|
- 'tests/swift/**'
|
||||||
|
- 'src/idl_gen_swift.cpp'
|
||||||
|
|
||||||
|
nim:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- '**/*.nim'
|
||||||
|
- 'nim/**/*'
|
||||||
|
- 'src/idl_gen_nim.cpp'
|
||||||
|
- 'src/bfbs_gen_nim.cpp'
|
||||||
|
|
||||||
|
javascript:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- '**/*.js'
|
||||||
|
- 'src/idl_gen_ts.cpp'
|
||||||
|
|
||||||
|
typescript:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- '**/*.ts'
|
||||||
|
- 'src/idl_gen_ts.cpp'
|
||||||
|
- 'grpc/flatbuffers-js-grpc/**/*.ts'
|
||||||
|
|
||||||
|
golang:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- '**/*.go'
|
||||||
|
- 'src/idl_gen_go.cpp'
|
||||||
|
|
||||||
|
python:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- '**/*.py'
|
||||||
|
- 'src/idl_gen_python.cpp'
|
||||||
|
|
||||||
|
java:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- '**/*.java'
|
||||||
|
- 'src/idl_gen_java.cpp'
|
||||||
|
|
||||||
|
kotlin:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- '**/*.kt'
|
||||||
|
- 'src/idl_gen_kotlin.cpp'
|
||||||
|
- 'src/idl_gen_kotlin_kmp.cpp'
|
||||||
|
|
||||||
|
lua:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- '**/*.lua'
|
||||||
|
- 'lua/**/*'
|
||||||
|
- 'src/bfbs_gen_lua.cpp'
|
||||||
|
|
||||||
|
lobster:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- '**/*.lobster'
|
||||||
|
- 'src/idl_gen_lobster.cpp'
|
||||||
|
|
||||||
|
php:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- '**/*.php'
|
||||||
|
- 'src/idl_gen_php.cpp'
|
||||||
|
|
||||||
|
rust:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- '**/*.rs'
|
||||||
|
- 'rust/**/*'
|
||||||
|
- 'src/idl_gen_rust.cpp'
|
||||||
|
|
||||||
|
dart:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- '**/*.dart'
|
||||||
|
- 'src/idl_gen_dart.cpp'
|
||||||
|
|
||||||
|
"c++":
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- '**/*.cc'
|
||||||
|
- '**/*.cpp'
|
||||||
|
- '**/*.h'
|
||||||
|
|
||||||
|
json:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- '**/*.json'
|
||||||
|
- 'src/idl_gen_json_schema.cpp'
|
||||||
|
|
||||||
|
codegen:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- 'src/**/*'
|
||||||
|
|
||||||
|
documentation:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- 'docs/**/*'
|
||||||
|
- '**/*.md'
|
||||||
|
|
||||||
|
CI:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- '.github/**/*'
|
||||||
|
- '.bazelci/**/*'
|
||||||
|
|
||||||
|
grpc:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- 'grpc/**/*'
|
||||||
|
- 'src/idl_gen_grpc.cpp'
|
||||||
@@ -0,0 +1,643 @@
|
|||||||
|
name: CI
|
||||||
|
permissions: read-all
|
||||||
|
|
||||||
|
on:
|
||||||
|
# For manual tests.
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "*" # new tag version, like `0.8.4` or else
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
schedule:
|
||||||
|
# Run daily at 4:45 A.M. to catch dependencies that break us.
|
||||||
|
- cron: '45 4 * * *'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-linux:
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
outputs:
|
||||||
|
digests-gcc: ${{ steps.hash-gcc.outputs.hashes }}
|
||||||
|
digests-clang: ${{ steps.hash-clang.outputs.hashes }}
|
||||||
|
name: Build Linux
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
cxx: [g++-13, clang++-18]
|
||||||
|
fail-fast: false
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: cmake
|
||||||
|
run: CXX=${{ matrix.cxx }} cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_STRICT_MODE=ON -DFLATBUFFERS_STATIC_FLATC=ON .
|
||||||
|
- name: build
|
||||||
|
run: make -j
|
||||||
|
- name: test
|
||||||
|
run: ./flattests
|
||||||
|
- name: make flatc executable
|
||||||
|
run: |
|
||||||
|
chmod +x flatc
|
||||||
|
./flatc --version
|
||||||
|
- name: upload build artifacts
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: Linux flatc binary ${{ matrix.cxx }}
|
||||||
|
path: flatc
|
||||||
|
# Below if only for release.
|
||||||
|
- name: Zip file
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
run: zip Linux.flatc.binary.${{ matrix.cxx }}.zip flatc
|
||||||
|
- name: Release zip file
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
with:
|
||||||
|
files: Linux.flatc.binary.${{ matrix.cxx }}.zip
|
||||||
|
- name: Generate SLSA subjects - clang
|
||||||
|
if: matrix.cxx == 'clang++-18' && startsWith(github.ref, 'refs/tags/')
|
||||||
|
id: hash-clang
|
||||||
|
run: echo "hashes=$(sha256sum Linux.flatc.binary.${{ matrix.cxx }}.zip | base64 -w0)" >> $GITHUB_OUTPUT
|
||||||
|
- name: Generate SLSA subjects - gcc
|
||||||
|
if: matrix.cxx == 'g++-13' && startsWith(github.ref, 'refs/tags/')
|
||||||
|
id: hash-gcc
|
||||||
|
run: echo "hashes=$(sha256sum Linux.flatc.binary.${{ matrix.cxx }}.zip | base64 -w0)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
build-linux-no-file-tests:
|
||||||
|
name: Build Linux with -DFLATBUFFERS_NO_FILE_TESTS
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: cmake
|
||||||
|
run: CXX=clang++-18 cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_STRICT_MODE=ON -DFLATBUFFERS_CXX_FLAGS="-DFLATBUFFERS_NO_FILE_TESTS" .
|
||||||
|
- name: build
|
||||||
|
run: make -j
|
||||||
|
- name: test
|
||||||
|
run: ./flattests
|
||||||
|
|
||||||
|
build-linux-out-of-source:
|
||||||
|
name: Build Linux with out-of-source build location
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: make build directory
|
||||||
|
run: mkdir build
|
||||||
|
- name: cmake
|
||||||
|
working-directory: build
|
||||||
|
run: >
|
||||||
|
CXX=clang++-18 cmake .. -G "Unix Makefiles" -DFLATBUFFERS_STRICT_MODE=ON
|
||||||
|
-DFLATBUFFERS_BUILD_CPP17=ON -DFLATBUFFERS_CPP_STD=17
|
||||||
|
- name: build
|
||||||
|
working-directory: build
|
||||||
|
run: make -j
|
||||||
|
- name: test
|
||||||
|
working-directory: build
|
||||||
|
run: pwd && ./flattests
|
||||||
|
- name: test C++17
|
||||||
|
working-directory: build
|
||||||
|
run: ./flattests_cpp17
|
||||||
|
|
||||||
|
build-linux-cpp-std:
|
||||||
|
name: Build Linux C++
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
std: [11, 14, 17, 20, 23]
|
||||||
|
cxx: [g++-13, clang++-18]
|
||||||
|
exclude:
|
||||||
|
# Clang++15 10.3.0 stdlibc++ doesn't fully support std 23
|
||||||
|
- cxx: clang++-18
|
||||||
|
std: 23
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: cmake
|
||||||
|
run: >
|
||||||
|
CXX=${{ matrix.cxx }} cmake -G "Unix Makefiles"
|
||||||
|
-DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_STRICT_MODE=ON
|
||||||
|
-DFLATBUFFERS_CPP_STD=${{ matrix.std }}
|
||||||
|
-DFLATBUFFERS_BUILD_CPP17=${{ matrix.std >= 17 && 'On' || 'Off'}}
|
||||||
|
- name: build
|
||||||
|
run: make -j
|
||||||
|
- name: test
|
||||||
|
run: ./flattests
|
||||||
|
- name: test C++17
|
||||||
|
if: matrix.std >= 17
|
||||||
|
run: ./flattests_cpp17
|
||||||
|
|
||||||
|
build-cpp-std:
|
||||||
|
name: Build Windows C++
|
||||||
|
runs-on: windows-2022
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
std: [11, 14, 17, 20, 23]
|
||||||
|
fail-fast: false
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: Add msbuild to PATH
|
||||||
|
uses: microsoft/setup-msbuild@v2
|
||||||
|
- name: cmake
|
||||||
|
run: >
|
||||||
|
cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=Release
|
||||||
|
-DFLATBUFFERS_STRICT_MODE=ON
|
||||||
|
-DFLATBUFFERS_CPP_STD=${{ matrix.std }}
|
||||||
|
-DFLATBUFFERS_BUILD_CPP17=${{ matrix.std >= 17 && 'On' || 'Off'}}
|
||||||
|
- name: build
|
||||||
|
run: msbuild.exe FlatBuffers.sln /p:Configuration=Release /p:Platform=x64
|
||||||
|
- name: test
|
||||||
|
run: Release\flattests.exe
|
||||||
|
- name: test C++17
|
||||||
|
if: matrix.std >= 17
|
||||||
|
run: Release\flattests_cpp17.exe
|
||||||
|
|
||||||
|
build-windows:
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
outputs:
|
||||||
|
digests: ${{ steps.hash.outputs.hashes }}
|
||||||
|
name: Build Windows 2022
|
||||||
|
runs-on: windows-2022
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: Add msbuild to PATH
|
||||||
|
uses: microsoft/setup-msbuild@v2
|
||||||
|
- name: cmake
|
||||||
|
run: cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_BUILD_CPP17=ON -DFLATBUFFERS_STRICT_MODE=ON .
|
||||||
|
- name: build
|
||||||
|
run: msbuild.exe FlatBuffers.sln /p:Configuration=Release /p:Platform=x64
|
||||||
|
- name: test
|
||||||
|
run: Release\flattests.exe
|
||||||
|
- name: upload build artifacts
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: Windows flatc binary
|
||||||
|
path: Release\flatc.exe
|
||||||
|
# Below if only for release.
|
||||||
|
- name: Zip file
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
run: move Release/flatc.exe . && Compress-Archive flatc.exe Windows.flatc.binary.zip
|
||||||
|
- name: Release binary
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
with:
|
||||||
|
files: Windows.flatc.binary.zip
|
||||||
|
- name: Generate SLSA subjects
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
id: hash
|
||||||
|
shell: bash
|
||||||
|
run: echo "hashes=$(sha256sum Windows.flatc.binary.zip | base64 -w0)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
build-dotnet-windows:
|
||||||
|
name: Build .NET Windows
|
||||||
|
runs-on: windows-2022
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
configuration: [
|
||||||
|
'',
|
||||||
|
'-p:UnsafeByteBuffer=true',
|
||||||
|
'-p:EnableSpanT=true,UnsafeByteBuffer=true'
|
||||||
|
]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: Setup .NET Core SDK
|
||||||
|
uses: actions/setup-dotnet@v5
|
||||||
|
with:
|
||||||
|
dotnet-version: '8.0.x'
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
cd tests\FlatBuffers.Test
|
||||||
|
dotnet new sln --force --name FlatBuffers.Test --format sln
|
||||||
|
dotnet sln FlatBuffers.Test.sln add FlatBuffers.Test.csproj
|
||||||
|
dotnet build -c Release ${{matrix.configuration}} FlatBuffers.Test.sln
|
||||||
|
- name: Run net6.0
|
||||||
|
run: |
|
||||||
|
cd tests\FlatBuffers.Test\bin\Release\net6.0
|
||||||
|
dir
|
||||||
|
.\FlatBuffers.Test.exe
|
||||||
|
- name: Run net8.0
|
||||||
|
run: |
|
||||||
|
cd tests\FlatBuffers.Test\bin\Release\net8.0
|
||||||
|
.\FlatBuffers.Test.exe
|
||||||
|
|
||||||
|
build-mac-intel:
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
outputs:
|
||||||
|
digests: ${{ steps.hash.outputs.hashes }}
|
||||||
|
name: Build Mac (for Intel)
|
||||||
|
runs-on: macos-15-intel
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: cmake
|
||||||
|
run: cmake -G "Xcode" -DCMAKE_OSX_ARCHITECTURES="x86_64" -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_STRICT_MODE=ON .
|
||||||
|
- name: build
|
||||||
|
run: xcodebuild -toolchain clang -configuration Release -target flattests
|
||||||
|
- name: check that the binary is x86_64
|
||||||
|
run: |
|
||||||
|
info=$(file Release/flatc)
|
||||||
|
echo $info
|
||||||
|
echo $info | grep "Mach-O 64-bit executable x86_64"
|
||||||
|
- name: test
|
||||||
|
run: Release/flattests
|
||||||
|
- name: make flatc executable
|
||||||
|
run: |
|
||||||
|
chmod +x Release/flatc
|
||||||
|
Release/flatc --version
|
||||||
|
- name: upload build artifacts
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: Mac flatc binary Intel
|
||||||
|
path: Release/flatc
|
||||||
|
# Below if only for release.
|
||||||
|
- name: Zip file
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
run: mv Release/flatc . && zip MacIntel.flatc.binary.zip flatc
|
||||||
|
- name: Release binary
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
with:
|
||||||
|
files: MacIntel.flatc.binary.zip
|
||||||
|
- name: Generate SLSA subjects
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
id: hash
|
||||||
|
run: echo "hashes=$(shasum -a 256 MacIntel.flatc.binary.zip | base64)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
build-mac-universal:
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
outputs:
|
||||||
|
digests: ${{ steps.hash.outputs.hashes }}
|
||||||
|
name: Build Mac (universal build)
|
||||||
|
runs-on: macos-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: cmake
|
||||||
|
run: cmake -G "Xcode" -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_STRICT_MODE=ON .
|
||||||
|
- name: build
|
||||||
|
run: xcodebuild -toolchain clang -configuration Release -target flattests
|
||||||
|
- name: check that the binary is "universal"
|
||||||
|
run: |
|
||||||
|
info=$(file Release/flatc)
|
||||||
|
echo $info
|
||||||
|
echo $info | grep "Mach-O universal binary with 2 architectures"
|
||||||
|
- name: test
|
||||||
|
run: Release/flattests
|
||||||
|
- name: make flatc executable
|
||||||
|
run: |
|
||||||
|
chmod +x Release/flatc
|
||||||
|
Release/flatc --version
|
||||||
|
- name: upload build artifacts
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: Mac flatc binary Universal
|
||||||
|
path: Release/flatc
|
||||||
|
# Below if only for release.
|
||||||
|
- name: Zip file
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
run: mv Release/flatc . && zip Mac.flatc.binary.zip flatc
|
||||||
|
- name: Release binary
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
with:
|
||||||
|
files: Mac.flatc.binary.zip
|
||||||
|
- name: Generate SLSA subjects
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
id: hash
|
||||||
|
run: echo "hashes=$(shasum -a 256 Mac.flatc.binary.zip | base64)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
build-android:
|
||||||
|
name: Build Android (on Linux)
|
||||||
|
if: false #disabled due to continual failure
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: set up Java
|
||||||
|
uses: actions/setup-java@v5
|
||||||
|
with:
|
||||||
|
distribution: temurin
|
||||||
|
java-version: 17
|
||||||
|
- name: set up Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v5
|
||||||
|
- name: set up flatc
|
||||||
|
run: |
|
||||||
|
cmake -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF -DFLATBUFFERS_STRICT_MODE=ON .
|
||||||
|
make -j
|
||||||
|
echo "${PWD}" >> $GITHUB_PATH
|
||||||
|
- name: build
|
||||||
|
working-directory: android
|
||||||
|
run: gradle clean build
|
||||||
|
|
||||||
|
build-generator:
|
||||||
|
name: Check Generated Code
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
cxx: [g++-13, clang++-18]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: cmake
|
||||||
|
run: CXX=${{ matrix.cxx }} cmake -G "Unix Makefiles" -DFLATBUFFERS_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_STRICT_MODE=ON . && make -j
|
||||||
|
- name: Generate
|
||||||
|
run: scripts/check_generate_code.py
|
||||||
|
- name: Generate gRPC
|
||||||
|
run: scripts/check-grpc-generated-code.py
|
||||||
|
|
||||||
|
build-generator-windows:
|
||||||
|
name: Check Generated Code on Windows
|
||||||
|
runs-on: windows-2022
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: Add msbuild to PATH
|
||||||
|
uses: microsoft/setup-msbuild@v2
|
||||||
|
- name: cmake
|
||||||
|
run: cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_BUILD_CPP17=ON -DFLATBUFFERS_STRICT_MODE=ON .
|
||||||
|
- name: build
|
||||||
|
run: msbuild.exe FlatBuffers.sln /p:Configuration=Release /p:Platform=x64
|
||||||
|
- name: Generate
|
||||||
|
run: python3 scripts/check_generate_code.py --flatc Release\flatc.exe
|
||||||
|
- name: Generate gRPC
|
||||||
|
run: python3 scripts/check-grpc-generated-code.py --flatc Release\flatc.exe
|
||||||
|
|
||||||
|
build-benchmarks:
|
||||||
|
name: Build Benchmarks (on Linux)
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
cxx: [g++-13]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: cmake
|
||||||
|
run: CXX=${{ matrix.cxx }} cmake -G "Unix Makefiles" -DFLATBUFFERS_CXX_FLAGS="-Wno-unused-parameter -fno-aligned-new" -DFLATBUFFERS_BUILD_BENCHMARKS=ON -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_STRICT_MODE=ON . && make -j
|
||||||
|
- name: Run benchmarks
|
||||||
|
run: ./flatbenchmark --benchmark_repetitions=5 --benchmark_display_aggregates_only=true --benchmark_out_format=console --benchmark_out=benchmarks/results_${{matrix.cxx}}
|
||||||
|
- name: Upload benchmarks results
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: Linux flatbenchmark results ${{matrix.cxx}}
|
||||||
|
path: benchmarks/results_${{matrix.cxx}}
|
||||||
|
|
||||||
|
build-java:
|
||||||
|
name: Build Java
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: test
|
||||||
|
working-directory: java
|
||||||
|
run: mvn test
|
||||||
|
|
||||||
|
build-kotlin-macos:
|
||||||
|
name: Build Kotlin MacOS
|
||||||
|
runs-on: macos-15
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
- name: set up Java
|
||||||
|
uses: actions/setup-java@v5
|
||||||
|
with:
|
||||||
|
distribution: temurin
|
||||||
|
java-version: 17
|
||||||
|
- name: set up Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v5
|
||||||
|
- name: Build flatc
|
||||||
|
run: |
|
||||||
|
cmake -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF .
|
||||||
|
make -j
|
||||||
|
echo "${PWD}" >> $GITHUB_PATH
|
||||||
|
- name: Build
|
||||||
|
working-directory: kotlin
|
||||||
|
run: ./gradlew clean iosSimulatorArm64Test macosX64Test macosArm64Test
|
||||||
|
|
||||||
|
build-kotlin-linux:
|
||||||
|
name: Build Kotlin Linux
|
||||||
|
if: false #disabled due to continual failure
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
- name: set up Java
|
||||||
|
uses: actions/setup-java@v5
|
||||||
|
with:
|
||||||
|
distribution: temurin
|
||||||
|
java-version: 17
|
||||||
|
- name: set up Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v5
|
||||||
|
- name: Build flatc
|
||||||
|
run: |
|
||||||
|
cmake -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF .
|
||||||
|
make -j
|
||||||
|
echo "${PWD}" >> $GITHUB_PATH
|
||||||
|
- name: Build
|
||||||
|
working-directory: kotlin
|
||||||
|
# we are using docker's version of gradle
|
||||||
|
# so no need for wrapper validation or user
|
||||||
|
# gradlew
|
||||||
|
run: gradle jvmMainClasses jvmTest jsTest jsBrowserTest
|
||||||
|
|
||||||
|
build-rust-linux:
|
||||||
|
name: Build Rust Linux
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: test
|
||||||
|
working-directory: tests
|
||||||
|
run: bash RustTest.sh
|
||||||
|
|
||||||
|
build-rust-windows:
|
||||||
|
name: Build Rust Windows
|
||||||
|
runs-on: windows-2022
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: test
|
||||||
|
working-directory: tests
|
||||||
|
run: ./RustTest.bat
|
||||||
|
|
||||||
|
build-python:
|
||||||
|
name: Build Python
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: flatc
|
||||||
|
# FIXME: make test script not rely on flatc
|
||||||
|
run: cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_INSTALL=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF -DFLATBUFFERS_STRICT_MODE=ON . && make -j
|
||||||
|
- name: test
|
||||||
|
working-directory: tests
|
||||||
|
run: bash PythonTest.sh
|
||||||
|
|
||||||
|
build-go:
|
||||||
|
name: Build Go
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: flatc
|
||||||
|
# FIXME: make test script not rely on flatc
|
||||||
|
run: cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_INSTALL=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF -DFLATBUFFERS_STRICT_MODE=ON . && make -j
|
||||||
|
- name: test
|
||||||
|
working-directory: tests
|
||||||
|
run: bash GoTest.sh
|
||||||
|
|
||||||
|
build-php:
|
||||||
|
name: Build PHP
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: flatc
|
||||||
|
# FIXME: make test script not rely on flatc
|
||||||
|
run: cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_INSTALL=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF -DFLATBUFFERS_STRICT_MODE=ON . && make -j
|
||||||
|
- name: test
|
||||||
|
working-directory: tests
|
||||||
|
run: |
|
||||||
|
php phpTest.php
|
||||||
|
sh phpUnionVectorTest.sh
|
||||||
|
|
||||||
|
build-swift:
|
||||||
|
name: Test Swift Linux
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
swift: ["6.0", "6.1", "6.2"]
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: swift-actions/setup-swift@v2
|
||||||
|
with:
|
||||||
|
swift-version: ${{ matrix.swift }}
|
||||||
|
- name: Get swift version
|
||||||
|
run: swift --version
|
||||||
|
- name: test
|
||||||
|
run: swift test
|
||||||
|
|
||||||
|
build-swift-windows:
|
||||||
|
name: Test swift windows
|
||||||
|
runs-on: windows-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: SwiftyLab/setup-swift@latest
|
||||||
|
with:
|
||||||
|
swift-version: '6.1'
|
||||||
|
- run: swift build
|
||||||
|
- run: swift test
|
||||||
|
|
||||||
|
build-swift-wasm:
|
||||||
|
name: Test Swift Wasm
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: swift-actions/setup-swift@v2
|
||||||
|
with:
|
||||||
|
swift-version: 6.2.1
|
||||||
|
- uses: bytecodealliance/actions/wasmtime/setup@v1
|
||||||
|
- name: Install Swift SDK
|
||||||
|
run: swift sdk install https://download.swift.org/swift-6.2.1-release/wasm-sdk/swift-6.2.1-RELEASE/swift-6.2.1-RELEASE_wasm.artifactbundle.tar.gz --checksum 482b9f95462b87bedfafca94a092cf9ec4496671ca13b43745097122d20f18af
|
||||||
|
- name: Test
|
||||||
|
working-directory: tests/swift/Wasm.tests
|
||||||
|
run: |
|
||||||
|
swift sdk list
|
||||||
|
swift build --build-tests --swift-sdk swift-6.2.1-RELEASE_wasm
|
||||||
|
wasmtime --dir . .build/wasm32-unknown-wasip1/debug/FlatBuffers.Test.Swift.WasmPackageTests.xctest --testing-library swift-testing
|
||||||
|
|
||||||
|
build-ts:
|
||||||
|
name: Build TS
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: flatc
|
||||||
|
# FIXME: make test script not rely on flatc
|
||||||
|
run: cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_INSTALL=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF . && make -j
|
||||||
|
- name: pnpm
|
||||||
|
run: npm install -g pnpm
|
||||||
|
- name: deps
|
||||||
|
run: pnpm i
|
||||||
|
- name: compile
|
||||||
|
run: pnpm compile
|
||||||
|
- name: test
|
||||||
|
working-directory: tests/ts
|
||||||
|
run: |
|
||||||
|
python3 TypeScriptTest.py
|
||||||
|
|
||||||
|
build-dart:
|
||||||
|
name: Build Dart
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: dart-lang/setup-dart@v1
|
||||||
|
with:
|
||||||
|
sdk: stable
|
||||||
|
- name: flatc
|
||||||
|
# FIXME: make test script not rely on flatc
|
||||||
|
run: cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_INSTALL=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF -DFLATBUFFERS_STRICT_MODE=ON . && make -j
|
||||||
|
- name: test
|
||||||
|
working-directory: tests
|
||||||
|
run: bash DartTest.sh
|
||||||
|
|
||||||
|
build-nim:
|
||||||
|
name: Build Nim
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: flatc
|
||||||
|
# FIXME: make test script not rely on flatc
|
||||||
|
run: cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_INSTALL=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF . && make -j
|
||||||
|
- uses: jiro4989/setup-nim-action@v2
|
||||||
|
- name: install library
|
||||||
|
working-directory: nim
|
||||||
|
run: nimble -y develop && nimble install
|
||||||
|
- name: test
|
||||||
|
working-directory: tests/nim
|
||||||
|
run: python3 testnim.py
|
||||||
|
|
||||||
|
bazel:
|
||||||
|
name: Bazel
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
# Explicitly use 8.5.1 until we can update or https://github.com/actions/runner-images/issues/13564 is fixed.
|
||||||
|
- name: Set env
|
||||||
|
run: >
|
||||||
|
echo "USE_BAZEL_VERSION=8.5.1" >> $GITHUB_ENV
|
||||||
|
- name: bazel build
|
||||||
|
run: >
|
||||||
|
bazel build
|
||||||
|
//:flatc
|
||||||
|
//:flatbuffers
|
||||||
|
//tests:flatbuffers_test
|
||||||
|
- name: bazel test
|
||||||
|
run: >
|
||||||
|
bazel test
|
||||||
|
//tests:flatbuffers_test
|
||||||
|
|
||||||
|
release-digests:
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
needs: [build-linux, build-windows, build-mac-intel, build-mac-universal]
|
||||||
|
outputs:
|
||||||
|
digests: ${{ steps.hash.outputs.digests }}
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- name: Merge results
|
||||||
|
id: hash
|
||||||
|
env:
|
||||||
|
LINUXGCC_DIGESTS: "${{ needs.build-linux.outputs.digests-gcc }}"
|
||||||
|
LINUXCLANG_DIGESTS: "${{ needs.build-linux.outputs.digests-clang }}"
|
||||||
|
MAC_DIGESTS: "${{ needs.build-mac-universal.outputs.digests }}"
|
||||||
|
MACINTEL_DIGESTS: "${{ needs.build-mac-intel.outputs.digests }}"
|
||||||
|
WINDOWS_DIGESTS: "${{ needs.build-windows.outputs.digests }}"
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
echo "$LINUXGCC_DIGESTS" | base64 -d > checksums.txt
|
||||||
|
echo "$LINUXCLANG_DIGESTS" | base64 -d >> checksums.txt
|
||||||
|
echo "$MAC_DIGESTS" | base64 -d >> checksums.txt
|
||||||
|
echo "$MACINTEL_DIGESTS" | base64 -d >> checksums.txt
|
||||||
|
echo "$WINDOWS_DIGESTS" | base64 -d >> checksums.txt
|
||||||
|
echo "digests=$(cat checksums.txt | base64 -w0)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
provenance:
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
needs: [release-digests]
|
||||||
|
permissions:
|
||||||
|
actions: read # To read the workflow path.
|
||||||
|
id-token: write # To sign the provenance.
|
||||||
|
contents: write # To add assets to a release.
|
||||||
|
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0
|
||||||
|
with:
|
||||||
|
base64-subjects: "${{ needs.release-digests.outputs.digests }}"
|
||||||
|
upload-assets: true # Optional: Upload to a new release
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
name: docs
|
||||||
|
on:
|
||||||
|
# For manual pushes.
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
# Pushes to main that touch the documentation directory.
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths:
|
||||||
|
- 'docs/**'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: Configure Git Credentials
|
||||||
|
run: |
|
||||||
|
git config user.name github-actions[bot]
|
||||||
|
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
|
||||||
|
- uses: actions/setup-python@v6
|
||||||
|
with:
|
||||||
|
python-version: 3.x
|
||||||
|
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
|
||||||
|
- uses: actions/cache@v5
|
||||||
|
with:
|
||||||
|
key: mkdocs-material-${{ env.cache_id }}
|
||||||
|
path: .cache
|
||||||
|
restore-keys: |
|
||||||
|
mkdocs-material-
|
||||||
|
- run: pip install mkdocs-material
|
||||||
|
- run: pip install mkdocs-redirects
|
||||||
|
- run: mkdocs gh-deploy --force -f docs/mkdocs.yml
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# This workflow will triage pull requests and apply a label based on the
|
||||||
|
# paths that are modified in the pull request.
|
||||||
|
#
|
||||||
|
# To use this workflow, you will need to set up a .github/labeler.yml
|
||||||
|
# file with configuration. For more information, see:
|
||||||
|
# https://github.com/actions/labeler
|
||||||
|
|
||||||
|
name: Labeler
|
||||||
|
permissions: read-all
|
||||||
|
|
||||||
|
on: [pull_request_target]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
label:
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/labeler@v6
|
||||||
|
with:
|
||||||
|
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
name: OSS-Fuzz
|
||||||
|
permissions: read-all
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths:
|
||||||
|
- include/**
|
||||||
|
- src/**
|
||||||
|
- tests/**.cpp
|
||||||
|
- tests/**.h
|
||||||
|
jobs:
|
||||||
|
Fuzzing:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Build Fuzzers
|
||||||
|
id: build
|
||||||
|
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
|
||||||
|
with:
|
||||||
|
oss-fuzz-project-name: 'flatbuffers'
|
||||||
|
language: c++
|
||||||
|
- name: Run Fuzzers
|
||||||
|
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
|
||||||
|
with:
|
||||||
|
oss-fuzz-project-name: 'flatbuffers'
|
||||||
|
language: c++
|
||||||
|
fuzz-seconds: 60
|
||||||
|
- name: Upload Crash
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
if: failure() && steps.build.outcome == 'success'
|
||||||
|
with:
|
||||||
|
name: artifacts
|
||||||
|
path: ./out/artifacts
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
name: Release
|
||||||
|
permissions: read-all
|
||||||
|
|
||||||
|
on:
|
||||||
|
# For manual tests.
|
||||||
|
workflow_dispatch:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish-npm:
|
||||||
|
name: Publish NPM
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: actions/setup-node@v6
|
||||||
|
with:
|
||||||
|
node-version: '20.x'
|
||||||
|
registry-url: 'https://registry.npmjs.org'
|
||||||
|
|
||||||
|
- run: npm publish
|
||||||
|
env:
|
||||||
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
|
|
||||||
|
publish-pypi:
|
||||||
|
name: Publish PyPi
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: ./python
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: actions/setup-python@v6
|
||||||
|
with:
|
||||||
|
python-version: '3.10'
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: |
|
||||||
|
python3 -m pip install --upgrade pip
|
||||||
|
python3 -m pip install build twine
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
python3 -m build .
|
||||||
|
|
||||||
|
- name: Upload to PyPi
|
||||||
|
run: |
|
||||||
|
python3 -m twine upload dist/*
|
||||||
|
env:
|
||||||
|
TWINE_USERNAME: __token__
|
||||||
|
TWINE_PASSWORD: ${{ secrets.TWINE_TOKEN }}
|
||||||
|
|
||||||
|
publish-nuget:
|
||||||
|
name: Publish NuGet
|
||||||
|
runs-on: windows-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: ./net/flatbuffers
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: actions/setup-dotnet@v5
|
||||||
|
with:
|
||||||
|
dotnet-version: '8.0.x'
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
dotnet build Google.FlatBuffers.csproj -c Release
|
||||||
|
|
||||||
|
- name: Pack
|
||||||
|
run: |
|
||||||
|
dotnet pack Google.FlatBuffers.csproj -c Release
|
||||||
|
|
||||||
|
- name: Upload to NuGet
|
||||||
|
run: |
|
||||||
|
dotnet nuget push .\bin\Release\Google.FlatBuffers.*.nupkg -k ${{ secrets.NUGET_API_KEY }} -s https://api.nuget.org/v3/index.json
|
||||||
|
|
||||||
|
publish-maven:
|
||||||
|
name: Publish Maven
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: ./java
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Set up Maven Central Repository
|
||||||
|
uses: actions/setup-java@v5
|
||||||
|
with:
|
||||||
|
java-version: '11'
|
||||||
|
distribution: 'adopt'
|
||||||
|
cache: 'maven'
|
||||||
|
server-id: ossrh
|
||||||
|
server-username: OSSRH_USERNAME
|
||||||
|
server-password: OSSRH_PASSWORD
|
||||||
|
gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }}
|
||||||
|
gpg-passphrase: MAVEN_GPG_PASSPHRASE # this needs to be an env var
|
||||||
|
|
||||||
|
- name: Publish Maven
|
||||||
|
run: mvn --batch-mode clean deploy
|
||||||
|
env:
|
||||||
|
OSSRH_USERNAME: ${{ secrets.OSSRH_USER_V2 }}
|
||||||
|
OSSRH_PASSWORD: ${{ secrets.OSSRH_TOKEN_V2 }}
|
||||||
|
MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
|
||||||
|
|
||||||
|
publish-maven-kotlin:
|
||||||
|
name: Publish Maven - Kotlin
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: ./kotlin
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: Set up Maven Central Repository
|
||||||
|
uses: actions/setup-java@v5
|
||||||
|
with:
|
||||||
|
java-version: '11'
|
||||||
|
distribution: 'adopt'
|
||||||
|
cache: 'maven'
|
||||||
|
server-id: ossrh
|
||||||
|
server-username: OSSRH_USERNAME
|
||||||
|
server-password: OSSRH_PASSWORD
|
||||||
|
gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }}
|
||||||
|
gpg-passphrase: MAVEN_GPG_PASSPHRASE # this needs to be an env var
|
||||||
|
|
||||||
|
- name: Publish Kotlin Library on Maven
|
||||||
|
run: ./gradlew publishAllPublicationsToSonatypeRepository
|
||||||
|
env:
|
||||||
|
OSSRH_USERNAME: ${{ secrets.OSSRH_USER_V2 }}
|
||||||
|
OSSRH_PASSWORD: ${{ secrets.OSSRH_TOKEN_V2 }}
|
||||||
|
MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
|
||||||
|
|
||||||
|
|
||||||
|
publish-crates:
|
||||||
|
name: Publish crates.io
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
override: true
|
||||||
|
|
||||||
|
- name: Publish Flatbuffers
|
||||||
|
uses: katyo/publish-crates@v2
|
||||||
|
with:
|
||||||
|
path: ./rust/flatbuffers
|
||||||
|
registry-token: ${{ secrets.CARGO_TOKEN }}
|
||||||
|
|
||||||
|
- name: Publish Flexbuffers
|
||||||
|
uses: katyo/publish-crates@v2
|
||||||
|
with:
|
||||||
|
path: ./rust/flexbuffers
|
||||||
|
registry-token: ${{ secrets.CARGO_TOKEN }}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
name: Mark stale issues and pull requests
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
on:
|
||||||
|
# For manual tests.
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: "30 20 * * *"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
stale:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/stale@v10
|
||||||
|
with:
|
||||||
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
operations-per-run: 500
|
||||||
|
exempt-all-milestones: true
|
||||||
|
remove-stale-when-updated: true
|
||||||
|
|
||||||
|
stale-issue-message: 'This issue is stale because it has been open 6 months with no activity. Please comment or label `not-stale`, or this will be closed in 14 days.'
|
||||||
|
close-issue-message: 'This issue was automatically closed due to no activity for 6 months plus the 14 day notice period.'
|
||||||
|
days-before-issue-stale: 182 # 6 months
|
||||||
|
days-before-issue-close: 14 # 2 weeks
|
||||||
|
exempt-issue-labels: not-stale
|
||||||
|
|
||||||
|
stale-pr-message: 'This pull request is stale because it has been open 6 months with no activity. Please comment or label `not-stale`, or this will be closed in 14 days.'
|
||||||
|
close-pr-message: 'This pull request was automatically closed due to no activity for 6 months plus the 14 day notice period.'
|
||||||
|
days-before-pr-stale: 182 # 6 months
|
||||||
|
days-before-pr-close: 14 # 2 week
|
||||||
|
exempt-pr-labels: not-stale
|
||||||
|
exempt-draft-pr: false
|
||||||
|
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
*_wire.txt
|
||||||
|
*_wire.bin
|
||||||
|
.DS_Store
|
||||||
|
**/.build
|
||||||
|
build
|
||||||
|
**/Packages
|
||||||
|
/*.xcodeproj
|
||||||
|
**/xcuserdata/
|
||||||
|
**/xcshareddata/
|
||||||
|
**/.swiftpm/
|
||||||
|
*.o
|
||||||
|
*.o.d
|
||||||
|
*.class
|
||||||
|
*.a
|
||||||
|
*.swp
|
||||||
|
*~
|
||||||
|
*.vcxproj
|
||||||
|
*.vcxproj.filters
|
||||||
|
*.vcxproj.user
|
||||||
|
*.sln
|
||||||
|
*.suo
|
||||||
|
*.opendb
|
||||||
|
*.keystore
|
||||||
|
**/.vs/**
|
||||||
|
**/bin/**
|
||||||
|
!tests/rust_usage_test/bin/**
|
||||||
|
**/gen/**
|
||||||
|
**/libs/**
|
||||||
|
**/obj/**
|
||||||
|
**/*.dir/**
|
||||||
|
**/CMakeFiles/**
|
||||||
|
**/cmake_install.cmake
|
||||||
|
**/install_manifest.txt
|
||||||
|
**/CMakeCache.txt
|
||||||
|
**/CMakeTestfile.cmake
|
||||||
|
**/CPackConfig.cmake
|
||||||
|
**/CPackSourceConfig.cmake
|
||||||
|
**/compile_commands.json
|
||||||
|
**/Debug/**
|
||||||
|
**/Release/**
|
||||||
|
**/RelWithDebInfo/**
|
||||||
|
**/x64/ #build artifacts from VS
|
||||||
|
build.xml
|
||||||
|
local.properties
|
||||||
|
project.properties
|
||||||
|
proguard-project.txt
|
||||||
|
linklint_results
|
||||||
|
Makefile
|
||||||
|
flatbenchmark
|
||||||
|
flatbenchmark.exe
|
||||||
|
flatc
|
||||||
|
flatc.exe
|
||||||
|
flathash
|
||||||
|
flathash.exe
|
||||||
|
flattests
|
||||||
|
flattests.exe
|
||||||
|
flattests_cpp17
|
||||||
|
flattests_cpp17.exe
|
||||||
|
flatsamplebinary
|
||||||
|
flatsamplebinary.exe
|
||||||
|
flatsampletext
|
||||||
|
flatsampletext.exe
|
||||||
|
flatsamplebfbs
|
||||||
|
flatsamplebfbs.exe
|
||||||
|
grpctest
|
||||||
|
grpctest.exe
|
||||||
|
snapshot.sh
|
||||||
|
tags
|
||||||
|
tests/dart_gen
|
||||||
|
tests/go_gen
|
||||||
|
tests/monsterdata_java_wire.mon
|
||||||
|
tests/monsterdata_java_wire_sp.mon
|
||||||
|
tests/monsterdata_go_wire.mon
|
||||||
|
tests/monsterdata_javascript_wire.mon
|
||||||
|
tests/monsterdata_lobster_wire.mon
|
||||||
|
tests/monsterdata_rust_wire.mon
|
||||||
|
tests/php/
|
||||||
|
CMakeLists.txt.user
|
||||||
|
CMakeScripts/**
|
||||||
|
CTestTestfile.cmake
|
||||||
|
flatbuffers-config-version.cmake
|
||||||
|
FlatBuffers.cbp
|
||||||
|
build/Xcode/FlatBuffers.xcodeproj/project.xcworkspace/**
|
||||||
|
build/Xcode/FlatBuffers.xcodeproj/xcuserdata/**
|
||||||
|
FlatBuffers.xcodeproj/
|
||||||
|
java/.idea
|
||||||
|
java/*.iml
|
||||||
|
.idea
|
||||||
|
*.iml
|
||||||
|
target
|
||||||
|
java/target
|
||||||
|
**/*.pyc
|
||||||
|
build/VS2010/FlatBuffers.sdf
|
||||||
|
build/VS2010/FlatBuffers.opensdf
|
||||||
|
build/VS2010/ipch/**/*.ipch
|
||||||
|
*.so
|
||||||
|
Testing/Temporary
|
||||||
|
.cproject
|
||||||
|
.settings/
|
||||||
|
.project
|
||||||
|
net/**/obj
|
||||||
|
node_modules/
|
||||||
|
android/.externalNativeBuild/
|
||||||
|
android/.gradle/
|
||||||
|
android/build/
|
||||||
|
samples/android/.externalNativeBuild/
|
||||||
|
samples/android/.gradle/
|
||||||
|
samples/android/build/
|
||||||
|
js/**/*.js
|
||||||
|
js/**/*.d.ts
|
||||||
|
mjs/**/*.js
|
||||||
|
mjs/**/*.d.ts
|
||||||
|
/bazel-bin
|
||||||
|
/bazel-flatbuffers
|
||||||
|
/bazel-genfiles
|
||||||
|
/bazel-out
|
||||||
|
/bazel-testlogs
|
||||||
|
.ninja_deps
|
||||||
|
.ninja_log
|
||||||
|
build.ninja
|
||||||
|
rules.ninja
|
||||||
|
.vscode
|
||||||
|
dart/.pub/
|
||||||
|
dart/.packages
|
||||||
|
dart/pubspec.lock
|
||||||
|
dart/.dart_tool/
|
||||||
|
dart/build/
|
||||||
|
dart/doc/api/
|
||||||
|
Cargo.lock
|
||||||
|
.corpus**
|
||||||
|
.seed**
|
||||||
|
.crash**
|
||||||
|
grpc/google/
|
||||||
|
**/Package.resolved
|
||||||
|
.clangd/**
|
||||||
|
package-lock.json
|
||||||
|
/*.ilk
|
||||||
|
/*.pdb
|
||||||
|
.clwb
|
||||||
|
yarn-error.log
|
||||||
|
.cache/
|
||||||
|
/flatbuffers.lib
|
||||||
|
.cmake/
|
||||||
|
**/dist
|
||||||
|
**/vendor
|
||||||
|
**/go.sum
|
||||||
|
flatbuffers.pc
|
||||||
|
**/FlatBuffers.Test.Swift.xcodeproj
|
||||||
|
**/html/**
|
||||||
|
**/latex/**
|
||||||
|
# https://cmake.org/cmake/help/latest/module/FetchContent.html#variable:FETCHCONTENT_BASE_DIR
|
||||||
|
cmake-build-debug/
|
||||||
|
_deps/
|
||||||
|
**/.gradle/**
|
||||||
|
kotlin/**/generated
|
||||||
|
MODULE.bazel.lock
|
||||||
|
|
||||||
|
# Ignore the generated docs
|
||||||
|
docs/site
|
||||||
|
|
||||||
|
# Ignore generated files
|
||||||
|
*.fbs.h
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
hoist=false
|
||||||
+202
@@ -0,0 +1,202 @@
|
|||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
load("@rules_cc//cc:defs.bzl", "cc_library")
|
||||||
|
|
||||||
|
package(
|
||||||
|
default_visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "distribution",
|
||||||
|
srcs = [
|
||||||
|
"BUILD.bazel",
|
||||||
|
] + glob([
|
||||||
|
"*.cc",
|
||||||
|
"*.h",
|
||||||
|
]),
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_library(
|
||||||
|
name = "namer",
|
||||||
|
hdrs = [
|
||||||
|
"idl_namer.h",
|
||||||
|
"namer.h",
|
||||||
|
],
|
||||||
|
strip_include_prefix = "/include",
|
||||||
|
visibility = ["//:__subpackages__"],
|
||||||
|
deps = ["//:runtime_cc"],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_library(
|
||||||
|
name = "python",
|
||||||
|
srcs = ["python.cc"],
|
||||||
|
hdrs = ["python.h"],
|
||||||
|
strip_include_prefix = "/include",
|
||||||
|
visibility = [
|
||||||
|
"//grpc:__subpackages__",
|
||||||
|
"//src:__subpackages__",
|
||||||
|
],
|
||||||
|
deps = [":namer"],
|
||||||
|
)
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
#ifndef FLATBUFFERS_INCLUDE_CODEGEN_IDL_NAMER_H_
|
||||||
|
#define FLATBUFFERS_INCLUDE_CODEGEN_IDL_NAMER_H_
|
||||||
|
|
||||||
|
#include "codegen/namer.h"
|
||||||
|
#include "flatbuffers/idl.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
// Provides Namer capabilities to types defined in the flatbuffers IDL.
|
||||||
|
class IdlNamer : public Namer {
|
||||||
|
public:
|
||||||
|
explicit IdlNamer(Config config, std::set<std::string> keywords)
|
||||||
|
: Namer(config, std::move(keywords)) {}
|
||||||
|
|
||||||
|
using Namer::Constant;
|
||||||
|
using Namer::Directories;
|
||||||
|
using Namer::Field;
|
||||||
|
using Namer::File;
|
||||||
|
using Namer::Function;
|
||||||
|
using Namer::Method;
|
||||||
|
using Namer::Namespace;
|
||||||
|
using Namer::NamespacedType;
|
||||||
|
using Namer::ObjectType;
|
||||||
|
using Namer::Type;
|
||||||
|
using Namer::Variable;
|
||||||
|
using Namer::Variant;
|
||||||
|
|
||||||
|
std::string Constant(const FieldDef& d) const { return Constant(d.name); }
|
||||||
|
|
||||||
|
// Types are always structs or enums so we can only expose these two
|
||||||
|
// overloads.
|
||||||
|
std::string Type(const StructDef& d) const { return Type(d.name); }
|
||||||
|
std::string Type(const EnumDef& d) const { return Type(d.name); }
|
||||||
|
|
||||||
|
std::string Function(const Definition& s) const { return Function(s.name); }
|
||||||
|
std::string Function(const std::string& prefix, const Definition& s) const {
|
||||||
|
return Function(prefix + s.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Field(const FieldDef& s) const { return Field(s.name); }
|
||||||
|
std::string Field(const FieldDef& d, const std::string& s) const {
|
||||||
|
return Field(d.name + "_" + s);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Variable(const FieldDef& s) const { return Variable(s.name); }
|
||||||
|
|
||||||
|
std::string Variable(const StructDef& s) const { return Variable(s.name); }
|
||||||
|
|
||||||
|
std::string Variant(const EnumVal& s) const { return Variant(s.name); }
|
||||||
|
|
||||||
|
std::string EnumVariant(const EnumDef& e, const EnumVal& v) const {
|
||||||
|
return Type(e) + config_.enum_variant_seperator + Variant(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ObjectType(const StructDef& d) const {
|
||||||
|
return ObjectType(d.name);
|
||||||
|
}
|
||||||
|
std::string ObjectType(const EnumDef& d) const { return ObjectType(d.name); }
|
||||||
|
|
||||||
|
std::string Method(const FieldDef& d, const std::string& suffix) const {
|
||||||
|
return Method(d.name, suffix);
|
||||||
|
}
|
||||||
|
std::string Method(const std::string& prefix, const StructDef& d) const {
|
||||||
|
return Method(prefix, d.name);
|
||||||
|
}
|
||||||
|
std::string Method(const std::string& prefix, const FieldDef& d) const {
|
||||||
|
return Method(prefix, d.name);
|
||||||
|
}
|
||||||
|
std::string Method(const std::string& prefix, const FieldDef& d,
|
||||||
|
const std::string& suffix) const {
|
||||||
|
return Method(prefix, d.name, suffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Namespace(const struct Namespace& ns) const {
|
||||||
|
return Namespace(ns.components);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string NamespacedEnumVariant(const EnumDef& e, const EnumVal& v) const {
|
||||||
|
return NamespacedString(e.defined_namespace, EnumVariant(e, v));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string NamespacedType(const Definition& def) const {
|
||||||
|
return NamespacedString(def.defined_namespace, Type(def.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string NamespacedObjectType(const Definition& def) const {
|
||||||
|
return NamespacedString(def.defined_namespace, ObjectType(def.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Directories(const struct Namespace& ns,
|
||||||
|
SkipDir skips = SkipDir::None,
|
||||||
|
Case input_case = Case::kUpperCamel) const {
|
||||||
|
return Directories(ns.components, skips, input_case);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Legacy fields do not really follow the usual config and should be
|
||||||
|
// considered for deprecation.
|
||||||
|
|
||||||
|
std::string LegacyRustNativeVariant(const EnumVal& v) const {
|
||||||
|
return ConvertCase(EscapeKeyword(v.name), Case::kUpperCamel);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string LegacyRustFieldOffsetName(const FieldDef& field) const {
|
||||||
|
return "VT_" + ConvertCase(EscapeKeyword(field.name), Case::kAllUpper);
|
||||||
|
}
|
||||||
|
std::string LegacyRustUnionTypeOffsetName(const FieldDef& field) const {
|
||||||
|
return "VT_" +
|
||||||
|
ConvertCase(EscapeKeyword(field.name + "_type"), Case::kAllUpper);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string LegacySwiftVariant(const EnumVal& ev) const {
|
||||||
|
auto name = ev.name;
|
||||||
|
if (isupper(name.front())) {
|
||||||
|
std::transform(name.begin(), name.end(), name.begin(), CharToLower);
|
||||||
|
}
|
||||||
|
return EscapeKeyword(ConvertCase(name, Case::kLowerCamel));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also used by Kotlin, lol.
|
||||||
|
std::string LegacyJavaMethod2(const std::string& prefix, const StructDef& sd,
|
||||||
|
const std::string& suffix) const {
|
||||||
|
return prefix + sd.name + suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string LegacyKotlinVariant(EnumVal& ev) const {
|
||||||
|
// Namer assumes the input case is snake case which is wrong...
|
||||||
|
return ConvertCase(EscapeKeyword(ev.name), Case::kLowerCamel);
|
||||||
|
}
|
||||||
|
// Kotlin methods escapes keywords after case conversion but before
|
||||||
|
// prefixing and suffixing.
|
||||||
|
std::string LegacyKotlinMethod(const std::string& prefix, const FieldDef& d,
|
||||||
|
const std::string& suffix) const {
|
||||||
|
return prefix + ConvertCase(EscapeKeyword(d.name), Case::kUpperCamel) +
|
||||||
|
suffix;
|
||||||
|
}
|
||||||
|
std::string LegacyKotlinMethod(const std::string& prefix, const StructDef& d,
|
||||||
|
const std::string& suffix) const {
|
||||||
|
return prefix + ConvertCase(EscapeKeyword(d.name), Case::kUpperCamel) +
|
||||||
|
suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a mix of snake case and keep casing, when Ts should be using
|
||||||
|
// lower camel case.
|
||||||
|
std::string LegacyTsMutateMethod(const FieldDef& d) {
|
||||||
|
return "mutate_" + d.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string LegacyRustUnionTypeMethod(const FieldDef& d) {
|
||||||
|
// assert d is a union
|
||||||
|
// d should convert case but not escape keywords due to historical reasons
|
||||||
|
return ConvertCase(d.name, config_.fields, Case::kLowerCamel) + "_type";
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string NamespacedString(const struct Namespace* ns,
|
||||||
|
const std::string& str) const {
|
||||||
|
std::string ret;
|
||||||
|
if (ns != nullptr) {
|
||||||
|
ret += Namespace(ns->components);
|
||||||
|
}
|
||||||
|
if (!ret.empty()) ret += config_.namespace_seperator;
|
||||||
|
return ret + str;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is a temporary helper function for code generators to call until all
|
||||||
|
// flag-overriding logic into flatc.cpp
|
||||||
|
inline Namer::Config WithFlagOptions(const Namer::Config& input,
|
||||||
|
const IDLOptions& opts,
|
||||||
|
const std::string& path) {
|
||||||
|
Namer::Config result = input;
|
||||||
|
result.object_prefix = opts.object_prefix;
|
||||||
|
result.object_suffix = opts.object_suffix;
|
||||||
|
result.output_path = path;
|
||||||
|
result.filename_suffix = opts.filename_suffix;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_INCLUDE_CODEGEN_IDL_NAMER_H_
|
||||||
@@ -0,0 +1,286 @@
|
|||||||
|
#ifndef FLATBUFFERS_INCLUDE_CODEGEN_NAMER_H_
|
||||||
|
#define FLATBUFFERS_INCLUDE_CODEGEN_NAMER_H_
|
||||||
|
|
||||||
|
#include "flatbuffers/util.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
// Options for Namer::File.
|
||||||
|
enum class SkipFile {
|
||||||
|
None = 0,
|
||||||
|
Suffix = 1,
|
||||||
|
Extension = 2,
|
||||||
|
SuffixAndExtension = 3,
|
||||||
|
};
|
||||||
|
inline SkipFile operator&(SkipFile a, SkipFile b) {
|
||||||
|
return static_cast<SkipFile>(static_cast<int>(a) & static_cast<int>(b));
|
||||||
|
}
|
||||||
|
// Options for Namer::Directories
|
||||||
|
enum class SkipDir {
|
||||||
|
None = 0,
|
||||||
|
// Skip prefixing the -o $output_path.
|
||||||
|
OutputPath = 1,
|
||||||
|
// Skip trailing path seperator.
|
||||||
|
TrailingPathSeperator = 2,
|
||||||
|
OutputPathAndTrailingPathSeparator = 3,
|
||||||
|
};
|
||||||
|
inline SkipDir operator&(SkipDir a, SkipDir b) {
|
||||||
|
return static_cast<SkipDir>(static_cast<int>(a) & static_cast<int>(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
// `Namer` applies style configuration to symbols in generated code. It manages
|
||||||
|
// casing, escapes keywords, and object API naming.
|
||||||
|
// TODO: Refactor all code generators to use this.
|
||||||
|
class Namer {
|
||||||
|
public:
|
||||||
|
struct Config {
|
||||||
|
// Symbols in code.
|
||||||
|
|
||||||
|
// Case style for flatbuffers-defined types.
|
||||||
|
// e.g. `class TableA {}`
|
||||||
|
Case types;
|
||||||
|
// Case style for flatbuffers-defined constants.
|
||||||
|
// e.g. `uint64_t ENUM_A_MAX`;
|
||||||
|
Case constants;
|
||||||
|
// Case style for flatbuffers-defined methods.
|
||||||
|
// e.g. `class TableA { int field_a(); }`
|
||||||
|
Case methods;
|
||||||
|
// Case style for flatbuffers-defined functions.
|
||||||
|
// e.g. `TableA* get_table_a_root()`;
|
||||||
|
Case functions;
|
||||||
|
// Case style for flatbuffers-defined fields.
|
||||||
|
// e.g. `struct Struct { int my_field; }`
|
||||||
|
Case fields;
|
||||||
|
// Case style for flatbuffers-defined variables.
|
||||||
|
// e.g. `int my_variable = 2`
|
||||||
|
Case variables;
|
||||||
|
// Case style for flatbuffers-defined variants.
|
||||||
|
// e.g. `enum class Enum { MyVariant, }`
|
||||||
|
Case variants;
|
||||||
|
// Seperator for qualified enum names.
|
||||||
|
// e.g. `Enum::MyVariant` uses `::`.
|
||||||
|
std::string enum_variant_seperator;
|
||||||
|
|
||||||
|
// Configures, when formatting code, whether symbols are checked against
|
||||||
|
// keywords and escaped before or after case conversion. It does not make
|
||||||
|
// sense to do so before, but its legacy behavior. :shrug:
|
||||||
|
// TODO(caspern): Deprecate.
|
||||||
|
enum class Escape {
|
||||||
|
BeforeConvertingCase,
|
||||||
|
AfterConvertingCase,
|
||||||
|
};
|
||||||
|
Escape escape_keywords;
|
||||||
|
|
||||||
|
// Namespaces
|
||||||
|
|
||||||
|
// e.g. `namespace my_namespace {}`
|
||||||
|
Case namespaces;
|
||||||
|
// The seperator between namespaces in a namespace path.
|
||||||
|
std::string namespace_seperator;
|
||||||
|
|
||||||
|
// Object API.
|
||||||
|
// Native versions flatbuffers types have this prefix.
|
||||||
|
// e.g. "" (it's usually empty string)
|
||||||
|
std::string object_prefix;
|
||||||
|
// Native versions flatbuffers types have this suffix.
|
||||||
|
// e.g. "T"
|
||||||
|
std::string object_suffix;
|
||||||
|
|
||||||
|
// Keywords.
|
||||||
|
// Prefix used to escape keywords. It is usually empty string.
|
||||||
|
std::string keyword_prefix;
|
||||||
|
// Suffix used to escape keywords. It is usually "_".
|
||||||
|
std::string keyword_suffix;
|
||||||
|
// The casing used for keywords when escaping. For most languages, keywords
|
||||||
|
// are case sensitive. PHP is an instance where some keywords are case
|
||||||
|
// insensitive.
|
||||||
|
enum class KeywordsCasing {
|
||||||
|
CaseSensitive,
|
||||||
|
CaseInsensitive,
|
||||||
|
};
|
||||||
|
KeywordsCasing keywords_casing;
|
||||||
|
|
||||||
|
// Files.
|
||||||
|
|
||||||
|
// Case style for filenames. e.g. `foo_bar_generated.rs`
|
||||||
|
Case filenames;
|
||||||
|
// Case style for directories, e.g. `output_files/foo_bar/baz/`
|
||||||
|
Case directories;
|
||||||
|
// The directory within which we will generate files.
|
||||||
|
std::string output_path;
|
||||||
|
// Suffix for generated file names, e.g. "_generated".
|
||||||
|
std::string filename_suffix;
|
||||||
|
// Extension for generated files, e.g. ".cpp" or ".rs".
|
||||||
|
std::string filename_extension;
|
||||||
|
};
|
||||||
|
Namer(Config config, std::set<std::string> keywords)
|
||||||
|
: config_(config), keywords_(std::move(keywords)) {}
|
||||||
|
|
||||||
|
virtual ~Namer() {}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::string Method(const T& s) const {
|
||||||
|
return Method(s.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string Method(const std::string& pre, const std::string& mid,
|
||||||
|
const std::string& suf) const {
|
||||||
|
return Format(pre + "_" + mid + "_" + suf, config_.methods);
|
||||||
|
}
|
||||||
|
virtual std::string Method(const std::string& pre,
|
||||||
|
const std::string& suf) const {
|
||||||
|
return Format(pre + "_" + suf, config_.methods);
|
||||||
|
}
|
||||||
|
virtual std::string Method(const std::string& s) const {
|
||||||
|
return Format(s, config_.methods);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string Constant(const std::string& s) const {
|
||||||
|
return Format(s, config_.constants);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string Function(const std::string& s) const {
|
||||||
|
return Format(s, config_.functions);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string Variable(const std::string& s) const {
|
||||||
|
return Format(s, config_.variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::string Variable(const std::string& p, const T& s) const {
|
||||||
|
return Format(p + "_" + s.name, config_.variables);
|
||||||
|
}
|
||||||
|
virtual std::string Variable(const std::string& p,
|
||||||
|
const std::string& s) const {
|
||||||
|
return Format(p + "_" + s, config_.variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string Namespace(const std::string& s) const {
|
||||||
|
return Format(s, config_.namespaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string Namespace(const std::vector<std::string>& ns) const {
|
||||||
|
std::string result;
|
||||||
|
for (auto it = ns.begin(); it != ns.end(); it++) {
|
||||||
|
if (it != ns.begin()) result += config_.namespace_seperator;
|
||||||
|
result += Namespace(*it);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string NamespacedType(const std::vector<std::string>& ns,
|
||||||
|
const std::string& s) const {
|
||||||
|
return (ns.empty() ? "" : (Namespace(ns) + config_.namespace_seperator)) +
|
||||||
|
Type(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns `filename` with the right casing, suffix, and extension.
|
||||||
|
virtual std::string File(const std::string& filename,
|
||||||
|
SkipFile skips = SkipFile::None) const {
|
||||||
|
const bool skip_suffix = (skips & SkipFile::Suffix) != SkipFile::None;
|
||||||
|
const bool skip_ext = (skips & SkipFile::Extension) != SkipFile::None;
|
||||||
|
return ConvertCase(filename, config_.filenames, Case::kUpperCamel) +
|
||||||
|
(skip_suffix ? "" : config_.filename_suffix) +
|
||||||
|
(skip_ext ? "" : config_.filename_extension);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
std::string File(const T& f, SkipFile skips = SkipFile::None) const {
|
||||||
|
return File(f.name, skips);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Formats `directories` prefixed with the output_path and joined with the
|
||||||
|
// right seperator. Output path prefixing and the trailing separator may be
|
||||||
|
// skiped using `skips`.
|
||||||
|
// Callers may want to use `EnsureDirExists` with the result.
|
||||||
|
// input_case is used to tell how to modify namespace. e.g. kUpperCamel will
|
||||||
|
// add a underscode between case changes, so MyGame turns into My_Game
|
||||||
|
// (depending also on the output_case).
|
||||||
|
virtual std::string Directories(const std::vector<std::string>& directories,
|
||||||
|
SkipDir skips = SkipDir::None,
|
||||||
|
Case input_case = Case::kUpperCamel) const {
|
||||||
|
const bool skip_output_path =
|
||||||
|
(skips & SkipDir::OutputPath) != SkipDir::None;
|
||||||
|
const bool skip_trailing_seperator =
|
||||||
|
(skips & SkipDir::TrailingPathSeperator) != SkipDir::None;
|
||||||
|
std::string result = skip_output_path ? "" : config_.output_path;
|
||||||
|
for (auto d = directories.begin(); d != directories.end(); d++) {
|
||||||
|
result += ConvertCase(*d, config_.directories, input_case);
|
||||||
|
result.push_back(kPathSeparator);
|
||||||
|
}
|
||||||
|
if (skip_trailing_seperator && !result.empty()) result.pop_back();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string NormalizeKeywordCase(const std::string& name) const {
|
||||||
|
if (config_.keywords_casing == Config::KeywordsCasing::CaseInsensitive) {
|
||||||
|
return ConvertCase(name, Case::kAllLower);
|
||||||
|
} else {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string EscapeKeyword(const std::string& name) const {
|
||||||
|
if (keywords_.find(NormalizeKeywordCase(name)) == keywords_.end()) {
|
||||||
|
return name;
|
||||||
|
} else {
|
||||||
|
return config_.keyword_prefix + name + config_.keyword_suffix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string Type(const std::string& s) const {
|
||||||
|
return Format(s, config_.types);
|
||||||
|
}
|
||||||
|
virtual std::string Type(const std::string& t, const std::string& s) const {
|
||||||
|
return Format(t + "_" + s, config_.types);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string ObjectType(const std::string& s) const {
|
||||||
|
return config_.object_prefix + Type(s) + config_.object_suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string Field(const std::string& s) const {
|
||||||
|
return Format(s, config_.fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string Variant(const std::string& s) const {
|
||||||
|
return Format(s, config_.variants);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string Format(const std::string& s, Case casing) const {
|
||||||
|
if (config_.escape_keywords == Config::Escape::BeforeConvertingCase) {
|
||||||
|
return ConvertCase(EscapeKeyword(s), casing, Case::kLowerCamel);
|
||||||
|
} else {
|
||||||
|
return EscapeKeyword(ConvertCase(s, casing, Case::kLowerCamel));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Denamespaces a string (e.g. The.Quick.Brown.Fox) by returning the last part
|
||||||
|
// after the `delimiter` (Fox) and placing the rest in `namespace_prefix`
|
||||||
|
// (The.Quick.Brown).
|
||||||
|
virtual std::string Denamespace(const std::string& s,
|
||||||
|
std::string& namespace_prefix,
|
||||||
|
const char delimiter = '.') const {
|
||||||
|
const size_t pos = s.find_last_of(delimiter);
|
||||||
|
if (pos == std::string::npos) {
|
||||||
|
namespace_prefix = "";
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
namespace_prefix = s.substr(0, pos);
|
||||||
|
return s.substr(pos + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same as above, but disregards the prefix.
|
||||||
|
virtual std::string Denamespace(const std::string& s,
|
||||||
|
const char delimiter = '.') const {
|
||||||
|
std::string prefix;
|
||||||
|
return Denamespace(s, prefix, delimiter);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Config config_;
|
||||||
|
const std::set<std::string> keywords_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_INCLUDE_CODEGEN_NAMER_H_
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
#include "codegen/python.h"
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
namespace python {
|
||||||
|
Version::Version(const std::string& version) {
|
||||||
|
std::stringstream ss(version);
|
||||||
|
char dot;
|
||||||
|
ss >> major >> dot >> minor >> dot >> micro;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Version::IsValid() const {
|
||||||
|
return (major == 0 || major == 2 || major == 3) && minor >= 0 && micro >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<std::string> Keywords(const Version& version) {
|
||||||
|
switch (version.major) {
|
||||||
|
case 2:
|
||||||
|
// https://docs.python.org/2/reference/lexical_analysis.html#keywords
|
||||||
|
return {
|
||||||
|
"and", "as", "assert", "break", "class", "continue", "def",
|
||||||
|
"del", "elif", "else", "except", "exec", "finally", "for",
|
||||||
|
"from", "global", "if", "import", "in", "is", "lambda",
|
||||||
|
"not", "or", "pass", "print", "raise", "return", "try",
|
||||||
|
"while", "with", "yield",
|
||||||
|
};
|
||||||
|
case 0:
|
||||||
|
case 3:
|
||||||
|
// https://docs.python.org/3/reference/lexical_analysis.html#keywords
|
||||||
|
return {
|
||||||
|
"and", "as", "assert", "async", "await", "break",
|
||||||
|
"class", "continue", "def", "del", "elif", "else",
|
||||||
|
"except", "False", "finally", "for", "from", "global",
|
||||||
|
"if", "import", "in", "is", "lambda", "None",
|
||||||
|
"nonlocal", "not", "or", "pass", "raise", "return",
|
||||||
|
"True", "try", "while", "with", "yield",
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const python::Import& python::Imports::Import(const std::string& module) {
|
||||||
|
python::Import import;
|
||||||
|
import.module = module;
|
||||||
|
imports.push_back(std::move(import));
|
||||||
|
return imports.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
const python::Import& python::Imports::Import(const std::string& module,
|
||||||
|
const std::string& name) {
|
||||||
|
python::Import import;
|
||||||
|
import.module = module;
|
||||||
|
import.name = name;
|
||||||
|
imports.push_back(std::move(import));
|
||||||
|
return imports.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
const python::Import& python::Imports::Export(const std::string& module) {
|
||||||
|
python::Import import;
|
||||||
|
import.module = module;
|
||||||
|
exports.push_back(std::move(import));
|
||||||
|
return exports.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
const python::Import& python::Imports::Export(const std::string& module,
|
||||||
|
const std::string& name) {
|
||||||
|
python::Import import;
|
||||||
|
import.module = module;
|
||||||
|
import.name = name;
|
||||||
|
exports.push_back(std::move(import));
|
||||||
|
return exports.back();
|
||||||
|
}
|
||||||
|
} // namespace python
|
||||||
|
} // namespace flatbuffers
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
#ifndef FLATBUFFERS_INCLUDE_CODEGEN_PYTHON_H_
|
||||||
|
#define FLATBUFFERS_INCLUDE_CODEGEN_PYTHON_H_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "codegen/namer.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
namespace python {
|
||||||
|
static const Namer::Config kConfig = {
|
||||||
|
/*types=*/Case::kKeep,
|
||||||
|
/*constants=*/Case::kScreamingSnake,
|
||||||
|
/*methods=*/Case::kUpperCamel,
|
||||||
|
/*functions=*/Case::kUpperCamel,
|
||||||
|
/*fields=*/Case::kLowerCamel,
|
||||||
|
/*variable=*/Case::kLowerCamel,
|
||||||
|
/*variants=*/Case::kKeep,
|
||||||
|
/*enum_variant_seperator=*/".",
|
||||||
|
/*escape_keywords=*/Namer::Config::Escape::AfterConvertingCase,
|
||||||
|
/*namespaces=*/Case::kKeep, // Packages in python.
|
||||||
|
/*namespace_seperator=*/".",
|
||||||
|
/*object_prefix=*/"",
|
||||||
|
/*object_suffix=*/"T",
|
||||||
|
/*keyword_prefix=*/"",
|
||||||
|
/*keyword_suffix=*/"_",
|
||||||
|
/*keywords_casing=*/Namer::Config::KeywordsCasing::CaseSensitive,
|
||||||
|
/*filenames=*/Case::kKeep,
|
||||||
|
/*directories=*/Case::kKeep,
|
||||||
|
/*output_path=*/"",
|
||||||
|
/*filename_suffix=*/"",
|
||||||
|
/*filename_extension=*/".py",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Namer::Config kStubConfig = {
|
||||||
|
/*types=*/Case::kKeep,
|
||||||
|
/*constants=*/Case::kScreamingSnake,
|
||||||
|
/*methods=*/Case::kUpperCamel,
|
||||||
|
/*functions=*/Case::kUpperCamel,
|
||||||
|
/*fields=*/Case::kLowerCamel,
|
||||||
|
/*variables=*/Case::kLowerCamel,
|
||||||
|
/*variants=*/Case::kKeep,
|
||||||
|
/*enum_variant_seperator=*/".",
|
||||||
|
/*escape_keywords=*/Namer::Config::Escape::AfterConvertingCase,
|
||||||
|
/*namespaces=*/Case::kKeep, // Packages in python.
|
||||||
|
/*namespace_seperator=*/".",
|
||||||
|
/*object_prefix=*/"",
|
||||||
|
/*object_suffix=*/"T",
|
||||||
|
/*keyword_prefix=*/"",
|
||||||
|
/*keyword_suffix=*/"_",
|
||||||
|
/*keywords_casing=*/Namer::Config::KeywordsCasing::CaseSensitive,
|
||||||
|
/*filenames=*/Case::kKeep,
|
||||||
|
/*directories=*/Case::kKeep,
|
||||||
|
/*output_path=*/"",
|
||||||
|
/*filename_suffix=*/"",
|
||||||
|
/*filename_extension=*/".pyi",
|
||||||
|
};
|
||||||
|
|
||||||
|
// `Version` represent a Python version.
|
||||||
|
//
|
||||||
|
// The zero value (i.e. `Version{}`) represents both Python2 and Python3.
|
||||||
|
//
|
||||||
|
// https://docs.python.org/3/faq/general.html#how-does-the-python-version-numbering-scheme-work
|
||||||
|
struct Version {
|
||||||
|
explicit Version(const std::string& version);
|
||||||
|
|
||||||
|
bool IsValid() const;
|
||||||
|
|
||||||
|
int16_t major = 0;
|
||||||
|
int16_t minor = 0;
|
||||||
|
int16_t micro = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::set<std::string> Keywords(const Version& version);
|
||||||
|
|
||||||
|
struct Import {
|
||||||
|
bool IsLocal() const { return module == "."; }
|
||||||
|
|
||||||
|
std::string module;
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Imports {
|
||||||
|
const python::Import& Import(const std::string& module);
|
||||||
|
const python::Import& Import(const std::string& module,
|
||||||
|
const std::string& name);
|
||||||
|
|
||||||
|
const python::Import& Export(const std::string& module);
|
||||||
|
const python::Import& Export(const std::string& module,
|
||||||
|
const std::string& name);
|
||||||
|
|
||||||
|
std::vector<python::Import> imports;
|
||||||
|
std::vector<python::Import> exports;
|
||||||
|
};
|
||||||
|
} // namespace python
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_INCLUDE_CODEGEN_PYTHON_H_
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_ALLOCATOR_H_
|
||||||
|
#define FLATBUFFERS_ALLOCATOR_H_
|
||||||
|
|
||||||
|
#include "flatbuffers/base.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
// Allocator interface. This is flatbuffers-specific and meant only for
|
||||||
|
// `vector_downward` usage.
|
||||||
|
class Allocator {
|
||||||
|
public:
|
||||||
|
virtual ~Allocator() {}
|
||||||
|
|
||||||
|
// Allocate `size` bytes of memory.
|
||||||
|
virtual uint8_t* allocate(size_t size) = 0;
|
||||||
|
|
||||||
|
// Deallocate `size` bytes of memory at `p` allocated by this allocator.
|
||||||
|
virtual void deallocate(uint8_t* p, size_t size) = 0;
|
||||||
|
|
||||||
|
// Reallocate `new_size` bytes of memory, replacing the old region of size
|
||||||
|
// `old_size` at `p`. In contrast to a normal realloc, this grows downwards,
|
||||||
|
// and is intended specifcally for `vector_downward` use.
|
||||||
|
// `in_use_back` and `in_use_front` indicate how much of `old_size` is
|
||||||
|
// actually in use at each end, and needs to be copied.
|
||||||
|
virtual uint8_t* reallocate_downward(uint8_t* old_p, size_t old_size,
|
||||||
|
size_t new_size, size_t in_use_back,
|
||||||
|
size_t in_use_front) {
|
||||||
|
FLATBUFFERS_ASSERT(new_size > old_size); // vector_downward only grows
|
||||||
|
uint8_t* new_p = allocate(new_size);
|
||||||
|
memcpy_downward(old_p, old_size, new_p, new_size, in_use_back,
|
||||||
|
in_use_front);
|
||||||
|
deallocate(old_p, old_size);
|
||||||
|
return new_p;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Called by `reallocate_downward` to copy memory from `old_p` of `old_size`
|
||||||
|
// to `new_p` of `new_size`. Only memory of size `in_use_front` and
|
||||||
|
// `in_use_back` will be copied from the front and back of the old memory
|
||||||
|
// allocation.
|
||||||
|
void memcpy_downward(uint8_t* old_p, size_t old_size, uint8_t* new_p,
|
||||||
|
size_t new_size, size_t in_use_back,
|
||||||
|
size_t in_use_front) {
|
||||||
|
memcpy(new_p + new_size - in_use_back, old_p + old_size - in_use_back,
|
||||||
|
in_use_back);
|
||||||
|
memcpy(new_p, old_p, in_use_front);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_ALLOCATOR_H_
|
||||||
@@ -0,0 +1,258 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_ARRAY_H_
|
||||||
|
#define FLATBUFFERS_ARRAY_H_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "flatbuffers/base.h"
|
||||||
|
#include "flatbuffers/stl_emulation.h"
|
||||||
|
#include "flatbuffers/vector.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
// This is used as a helper type for accessing arrays.
|
||||||
|
template <typename T, uint16_t length>
|
||||||
|
class Array {
|
||||||
|
// Array<T> can carry only POD data types (scalars or structs).
|
||||||
|
typedef typename flatbuffers::bool_constant<flatbuffers::is_scalar<T>::value>
|
||||||
|
scalar_tag;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef uint16_t size_type;
|
||||||
|
typedef typename IndirectHelper<T>::return_type return_type;
|
||||||
|
typedef VectorConstIterator<T, return_type, uoffset_t> const_iterator;
|
||||||
|
typedef VectorReverseIterator<const_iterator> const_reverse_iterator;
|
||||||
|
|
||||||
|
// If T is a non-pointer and a LE-scalar or a struct (!scalar_tag::value).
|
||||||
|
static FLATBUFFERS_CONSTEXPR bool is_span_observable =
|
||||||
|
!std::is_pointer<T>::value &&
|
||||||
|
((scalar_tag::value && (FLATBUFFERS_LITTLEENDIAN || sizeof(T) == 1)) ||
|
||||||
|
!scalar_tag::value);
|
||||||
|
|
||||||
|
FLATBUFFERS_CONSTEXPR uint16_t size() const { return length; }
|
||||||
|
|
||||||
|
return_type Get(uoffset_t i) const {
|
||||||
|
FLATBUFFERS_ASSERT(i < size());
|
||||||
|
return IndirectHelper<T>::Read(Data(), i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return_type operator[](uoffset_t i) const { return Get(i); }
|
||||||
|
|
||||||
|
// If this is a Vector of enums, T will be its storage type, not the enum
|
||||||
|
// type. This function makes it convenient to retrieve value with enum
|
||||||
|
// type E.
|
||||||
|
template <typename E>
|
||||||
|
E GetEnum(uoffset_t i) const {
|
||||||
|
return static_cast<E>(Get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator begin() const { return const_iterator(Data(), 0); }
|
||||||
|
const_iterator end() const { return const_iterator(Data(), size()); }
|
||||||
|
|
||||||
|
const_reverse_iterator rbegin() const {
|
||||||
|
return const_reverse_iterator(end());
|
||||||
|
}
|
||||||
|
const_reverse_iterator rend() const {
|
||||||
|
return const_reverse_iterator(begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator cbegin() const { return begin(); }
|
||||||
|
const_iterator cend() const { return end(); }
|
||||||
|
|
||||||
|
const_reverse_iterator crbegin() const { return rbegin(); }
|
||||||
|
const_reverse_iterator crend() const { return rend(); }
|
||||||
|
|
||||||
|
// Get a mutable pointer to elements inside this array.
|
||||||
|
// This method used to mutate arrays of structs followed by a @p Mutate
|
||||||
|
// operation. For primitive types use @p Mutate directly.
|
||||||
|
// @warning Assignments and reads to/from the dereferenced pointer are not
|
||||||
|
// automatically converted to the correct endianness.
|
||||||
|
typename flatbuffers::conditional<scalar_tag::value, void, T*>::type
|
||||||
|
GetMutablePointer(uoffset_t i) const {
|
||||||
|
FLATBUFFERS_ASSERT(i < size());
|
||||||
|
return const_cast<T*>(&data()[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change elements if you have a non-const pointer to this object.
|
||||||
|
void Mutate(uoffset_t i, const T& val) { MutateImpl(scalar_tag(), i, val); }
|
||||||
|
|
||||||
|
// The raw data in little endian format. Use with care.
|
||||||
|
const uint8_t* Data() const { return data_; }
|
||||||
|
|
||||||
|
uint8_t* Data() { return data_; }
|
||||||
|
|
||||||
|
// Similarly, but typed, much like std::vector::data
|
||||||
|
const T* data() const { return reinterpret_cast<const T*>(Data()); }
|
||||||
|
T* data() { return reinterpret_cast<T*>(Data()); }
|
||||||
|
|
||||||
|
// Copy data from a span with endian conversion.
|
||||||
|
// If this Array and the span overlap, the behavior is undefined.
|
||||||
|
void CopyFromSpan(flatbuffers::span<const T, length> src) {
|
||||||
|
const auto p1 = reinterpret_cast<const uint8_t*>(src.data());
|
||||||
|
const auto p2 = Data();
|
||||||
|
FLATBUFFERS_ASSERT(!(p1 >= p2 && p1 < (p2 + length)) &&
|
||||||
|
!(p2 >= p1 && p2 < (p1 + length)));
|
||||||
|
(void)p1;
|
||||||
|
(void)p2;
|
||||||
|
CopyFromSpanImpl(flatbuffers::bool_constant<is_span_observable>(), src);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void MutateImpl(flatbuffers::true_type, uoffset_t i, const T& val) {
|
||||||
|
FLATBUFFERS_ASSERT(i < size());
|
||||||
|
WriteScalar(data() + i, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MutateImpl(flatbuffers::false_type, uoffset_t i, const T& val) {
|
||||||
|
*(GetMutablePointer(i)) = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CopyFromSpanImpl(flatbuffers::true_type,
|
||||||
|
flatbuffers::span<const T, length> src) {
|
||||||
|
// Use std::memcpy() instead of std::copy() to avoid performance degradation
|
||||||
|
// due to aliasing if T is char or unsigned char.
|
||||||
|
// The size is known at compile time, so memcpy would be inlined.
|
||||||
|
std::memcpy(data(), src.data(), length * sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy data from flatbuffers::span with endian conversion.
|
||||||
|
void CopyFromSpanImpl(flatbuffers::false_type,
|
||||||
|
flatbuffers::span<const T, length> src) {
|
||||||
|
for (size_type k = 0; k < length; k++) {
|
||||||
|
Mutate(k, src[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This class is only used to access pre-existing data. Don't ever
|
||||||
|
// try to construct these manually.
|
||||||
|
// 'constexpr' allows us to use 'size()' at compile time.
|
||||||
|
// @note Must not use 'FLATBUFFERS_CONSTEXPR' here, as const is not allowed on
|
||||||
|
// a constructor.
|
||||||
|
#if defined(__cpp_constexpr)
|
||||||
|
constexpr Array();
|
||||||
|
#else
|
||||||
|
Array();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint8_t data_[length * sizeof(T)];
|
||||||
|
|
||||||
|
private:
|
||||||
|
// This class is a pointer. Copying will therefore create an invalid object.
|
||||||
|
// Private and unimplemented copy constructor.
|
||||||
|
Array(const Array&);
|
||||||
|
Array& operator=(const Array&);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Specialization for Array[struct] with access using Offset<void> pointer.
|
||||||
|
// This specialization used by idl_gen_text.cpp.
|
||||||
|
template <typename T, uint16_t length, template <typename> class OffsetT>
|
||||||
|
class Array<OffsetT<T>, length> {
|
||||||
|
static_assert(flatbuffers::is_same<T, void>::value, "unexpected type T");
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef const void* return_type;
|
||||||
|
typedef uint16_t size_type;
|
||||||
|
|
||||||
|
const uint8_t* Data() const { return data_; }
|
||||||
|
|
||||||
|
// Make idl_gen_text.cpp::PrintContainer happy.
|
||||||
|
return_type operator[](uoffset_t) const {
|
||||||
|
FLATBUFFERS_ASSERT(false);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// This class is only used to access pre-existing data.
|
||||||
|
Array();
|
||||||
|
Array(const Array&);
|
||||||
|
Array& operator=(const Array&);
|
||||||
|
|
||||||
|
uint8_t data_[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class U, uint16_t N>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<U, N> make_span(Array<U, N>& arr)
|
||||||
|
FLATBUFFERS_NOEXCEPT {
|
||||||
|
static_assert(
|
||||||
|
Array<U, N>::is_span_observable,
|
||||||
|
"wrong type U, only plain struct, LE-scalar, or byte types are allowed");
|
||||||
|
return span<U, N>(arr.data(), N);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class U, uint16_t N>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<const U, N> make_span(
|
||||||
|
const Array<U, N>& arr) FLATBUFFERS_NOEXCEPT {
|
||||||
|
static_assert(
|
||||||
|
Array<U, N>::is_span_observable,
|
||||||
|
"wrong type U, only plain struct, LE-scalar, or byte types are allowed");
|
||||||
|
return span<const U, N>(arr.data(), N);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class U, uint16_t N>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<uint8_t, sizeof(U) * N>
|
||||||
|
make_bytes_span(Array<U, N>& arr) FLATBUFFERS_NOEXCEPT {
|
||||||
|
static_assert(Array<U, N>::is_span_observable,
|
||||||
|
"internal error, Array<T> might hold only scalars or structs");
|
||||||
|
return span<uint8_t, sizeof(U) * N>(arr.Data(), sizeof(U) * N);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class U, uint16_t N>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<const uint8_t, sizeof(U) * N>
|
||||||
|
make_bytes_span(const Array<U, N>& arr) FLATBUFFERS_NOEXCEPT {
|
||||||
|
static_assert(Array<U, N>::is_span_observable,
|
||||||
|
"internal error, Array<T> might hold only scalars or structs");
|
||||||
|
return span<const uint8_t, sizeof(U) * N>(arr.Data(), sizeof(U) * N);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cast a raw T[length] to a raw flatbuffers::Array<T, length>
|
||||||
|
// without endian conversion. Use with care.
|
||||||
|
// TODO: move these Cast-methods to `internal` namespace.
|
||||||
|
template <typename T, uint16_t length>
|
||||||
|
Array<T, length>& CastToArray(T (&arr)[length]) {
|
||||||
|
return *reinterpret_cast<Array<T, length>*>(arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, uint16_t length>
|
||||||
|
const Array<T, length>& CastToArray(const T (&arr)[length]) {
|
||||||
|
return *reinterpret_cast<const Array<T, length>*>(arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename E, typename T, uint16_t length>
|
||||||
|
Array<E, length>& CastToArrayOfEnum(T (&arr)[length]) {
|
||||||
|
static_assert(sizeof(E) == sizeof(T), "invalid enum type E");
|
||||||
|
return *reinterpret_cast<Array<E, length>*>(arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename E, typename T, uint16_t length>
|
||||||
|
const Array<E, length>& CastToArrayOfEnum(const T (&arr)[length]) {
|
||||||
|
static_assert(sizeof(E) == sizeof(T), "invalid enum type E");
|
||||||
|
return *reinterpret_cast<const Array<E, length>*>(arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, uint16_t length>
|
||||||
|
bool operator==(const Array<T, length>& lhs,
|
||||||
|
const Array<T, length>& rhs) noexcept {
|
||||||
|
return std::addressof(lhs) == std::addressof(rhs) ||
|
||||||
|
(lhs.size() == rhs.size() &&
|
||||||
|
std::memcmp(lhs.Data(), rhs.Data(), rhs.size() * sizeof(T)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_ARRAY_H_
|
||||||
@@ -0,0 +1,503 @@
|
|||||||
|
#ifndef FLATBUFFERS_BASE_H_
|
||||||
|
#define FLATBUFFERS_BASE_H_
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
// If activate should be declared and included first.
|
||||||
|
#if defined(FLATBUFFERS_MEMORY_LEAK_TRACKING) && \
|
||||||
|
defined(_MSC_VER) && defined(_DEBUG)
|
||||||
|
// The _CRTDBG_MAP_ALLOC inside <crtdbg.h> will replace
|
||||||
|
// calloc/free (etc) to its debug version using #define directives.
|
||||||
|
#define _CRTDBG_MAP_ALLOC
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <crtdbg.h>
|
||||||
|
// Replace operator new by trace-enabled version.
|
||||||
|
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
|
||||||
|
#define new DEBUG_NEW
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(FLATBUFFERS_ASSERT)
|
||||||
|
#include <assert.h>
|
||||||
|
#define FLATBUFFERS_ASSERT assert
|
||||||
|
#elif defined(FLATBUFFERS_ASSERT_INCLUDE)
|
||||||
|
// Include file with forward declaration
|
||||||
|
#include FLATBUFFERS_ASSERT_INCLUDE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ARDUINO
|
||||||
|
#include <cstdint>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#if defined(ARDUINO) && !defined(ARDUINOSTL_M_H) && defined(__AVR__)
|
||||||
|
#include <utility.h>
|
||||||
|
#else
|
||||||
|
#include <utility>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <limits>
|
||||||
|
#include <iterator>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#if defined(__unix__) && !defined(FLATBUFFERS_LOCALE_INDEPENDENT)
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
#include <android/api-level.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__ICCARM__)
|
||||||
|
#include <intrinsics.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Note the __clang__ check is needed, because clang presents itself
|
||||||
|
// as an older GNUC compiler (4.2).
|
||||||
|
// Clang 3.3 and later implement all of the ISO C++ 2011 standard.
|
||||||
|
// Clang 3.4 and later implement all of the ISO C++ 2014 standard.
|
||||||
|
// http://clang.llvm.org/cxx_status.html
|
||||||
|
|
||||||
|
// Note the MSVC value '__cplusplus' may be incorrect:
|
||||||
|
// The '__cplusplus' predefined macro in the MSVC stuck at the value 199711L,
|
||||||
|
// indicating (erroneously!) that the compiler conformed to the C++98 Standard.
|
||||||
|
// This value should be correct starting from MSVC2017-15.7-Preview-3.
|
||||||
|
// The '__cplusplus' will be valid only if MSVC2017-15.7-P3 and the `/Zc:__cplusplus` switch is set.
|
||||||
|
// Workaround (for details see MSDN):
|
||||||
|
// Use the _MSC_VER and _MSVC_LANG definition instead of the __cplusplus for compatibility.
|
||||||
|
// The _MSVC_LANG macro reports the Standard version regardless of the '/Zc:__cplusplus' switch.
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
|
#define FLATBUFFERS_GCC (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
|
||||||
|
#else
|
||||||
|
#define FLATBUFFERS_GCC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
#define FLATBUFFERS_CLANG (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
|
||||||
|
#else
|
||||||
|
#define FLATBUFFERS_CLANG 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// @cond FLATBUFFERS_INTERNAL
|
||||||
|
#if __cplusplus <= 199711L && \
|
||||||
|
(!defined(_MSC_VER) || _MSC_VER < 1600) && \
|
||||||
|
(!defined(__GNUC__) || \
|
||||||
|
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40400))
|
||||||
|
#error A C++11 compatible compiler with support for the auto typing is \
|
||||||
|
required for FlatBuffers.
|
||||||
|
#error __cplusplus _MSC_VER __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__clang__) && \
|
||||||
|
defined(__GNUC__) && \
|
||||||
|
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40600)
|
||||||
|
// Backwards compatibility for g++ 4.4, and 4.5 which don't have the nullptr
|
||||||
|
// and constexpr keywords. Note the __clang__ check is needed, because clang
|
||||||
|
// presents itself as an older GNUC compiler.
|
||||||
|
#ifndef nullptr_t
|
||||||
|
const class nullptr_t {
|
||||||
|
public:
|
||||||
|
template<class T> inline operator T*() const { return 0; }
|
||||||
|
private:
|
||||||
|
void operator&() const;
|
||||||
|
} nullptr = {};
|
||||||
|
#endif
|
||||||
|
#ifndef constexpr
|
||||||
|
#define constexpr const
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// The wire format uses a little endian encoding (since that's efficient for
|
||||||
|
// the common platforms).
|
||||||
|
#if defined(__s390x__)
|
||||||
|
#define FLATBUFFERS_LITTLEENDIAN 0
|
||||||
|
#endif // __s390x__
|
||||||
|
#if !defined(FLATBUFFERS_LITTLEENDIAN)
|
||||||
|
#if defined(__GNUC__) || defined(__clang__) || defined(__ICCARM__)
|
||||||
|
#if (defined(__BIG_ENDIAN__) || \
|
||||||
|
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
|
||||||
|
#define FLATBUFFERS_LITTLEENDIAN 0
|
||||||
|
#else
|
||||||
|
#define FLATBUFFERS_LITTLEENDIAN 1
|
||||||
|
#endif // __BIG_ENDIAN__
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#if defined(_M_PPC)
|
||||||
|
#define FLATBUFFERS_LITTLEENDIAN 0
|
||||||
|
#else
|
||||||
|
#define FLATBUFFERS_LITTLEENDIAN 1
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#error Unable to determine endianness, define FLATBUFFERS_LITTLEENDIAN.
|
||||||
|
#endif
|
||||||
|
#endif // !defined(FLATBUFFERS_LITTLEENDIAN)
|
||||||
|
|
||||||
|
#define FLATBUFFERS_VERSION_MAJOR 25
|
||||||
|
#define FLATBUFFERS_VERSION_MINOR 12
|
||||||
|
#define FLATBUFFERS_VERSION_REVISION 19
|
||||||
|
#define FLATBUFFERS_STRING_EXPAND(X) #X
|
||||||
|
#define FLATBUFFERS_STRING(X) FLATBUFFERS_STRING_EXPAND(X)
|
||||||
|
namespace flatbuffers {
|
||||||
|
// Returns version as string "MAJOR.MINOR.REVISION".
|
||||||
|
const char* FLATBUFFERS_VERSION();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (!defined(_MSC_VER) || _MSC_VER > 1600) && \
|
||||||
|
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 407)) || \
|
||||||
|
defined(__clang__)
|
||||||
|
#define FLATBUFFERS_FINAL_CLASS final
|
||||||
|
#define FLATBUFFERS_OVERRIDE override
|
||||||
|
#define FLATBUFFERS_EXPLICIT_CPP11 explicit
|
||||||
|
#define FLATBUFFERS_VTABLE_UNDERLYING_TYPE : ::flatbuffers::voffset_t
|
||||||
|
#else
|
||||||
|
#define FLATBUFFERS_FINAL_CLASS
|
||||||
|
#define FLATBUFFERS_OVERRIDE
|
||||||
|
#define FLATBUFFERS_EXPLICIT_CPP11
|
||||||
|
#define FLATBUFFERS_VTABLE_UNDERLYING_TYPE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \
|
||||||
|
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) || \
|
||||||
|
(defined(__cpp_constexpr) && __cpp_constexpr >= 200704)
|
||||||
|
#define FLATBUFFERS_CONSTEXPR constexpr
|
||||||
|
#define FLATBUFFERS_CONSTEXPR_CPP11 constexpr
|
||||||
|
#define FLATBUFFERS_CONSTEXPR_DEFINED
|
||||||
|
#else
|
||||||
|
#define FLATBUFFERS_CONSTEXPR const
|
||||||
|
#define FLATBUFFERS_CONSTEXPR_CPP11
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(__cplusplus) && __cplusplus >= 201402L) || \
|
||||||
|
(defined(__cpp_constexpr) && __cpp_constexpr >= 201304)
|
||||||
|
#define FLATBUFFERS_CONSTEXPR_CPP14 FLATBUFFERS_CONSTEXPR_CPP11
|
||||||
|
#else
|
||||||
|
#define FLATBUFFERS_CONSTEXPR_CPP14
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(__GXX_EXPERIMENTAL_CXX0X__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) || \
|
||||||
|
(defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 190023026)) || \
|
||||||
|
defined(__clang__)
|
||||||
|
#define FLATBUFFERS_NOEXCEPT noexcept
|
||||||
|
#else
|
||||||
|
#define FLATBUFFERS_NOEXCEPT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// NOTE: the FLATBUFFERS_DELETE_FUNC macro may change the access mode to
|
||||||
|
// private, so be sure to put it at the end or reset access mode explicitly.
|
||||||
|
#if (!defined(_MSC_VER) || _MSC_FULL_VER >= 180020827) && \
|
||||||
|
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)) || \
|
||||||
|
defined(__clang__)
|
||||||
|
#define FLATBUFFERS_DELETE_FUNC(func) func = delete
|
||||||
|
#else
|
||||||
|
#define FLATBUFFERS_DELETE_FUNC(func) private: func
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \
|
||||||
|
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 409)) || \
|
||||||
|
defined(__clang__)
|
||||||
|
#define FLATBUFFERS_DEFAULT_DECLARATION
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Check if we can use template aliases
|
||||||
|
// Not possible if Microsoft Compiler before 2012
|
||||||
|
// Possible is the language feature __cpp_alias_templates is defined well
|
||||||
|
// Or possible if the C++ std is C+11 or newer
|
||||||
|
#if (defined(_MSC_VER) && _MSC_VER > 1700 /* MSVC2012 */) \
|
||||||
|
|| (defined(__cpp_alias_templates) && __cpp_alias_templates >= 200704) \
|
||||||
|
|| (defined(__cplusplus) && __cplusplus >= 201103L)
|
||||||
|
#define FLATBUFFERS_TEMPLATES_ALIASES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_HAS_STRING_VIEW
|
||||||
|
// Only provide flatbuffers::string_view if __has_include can be used
|
||||||
|
// to detect a header that provides an implementation
|
||||||
|
#if defined(__has_include)
|
||||||
|
// Check for std::string_view (in c++17)
|
||||||
|
#if __has_include(<string_view>) && (__cplusplus >= 201606 || (defined(_HAS_CXX17) && _HAS_CXX17))
|
||||||
|
#include <string_view>
|
||||||
|
namespace flatbuffers {
|
||||||
|
typedef std::string_view string_view;
|
||||||
|
}
|
||||||
|
#define FLATBUFFERS_HAS_STRING_VIEW 1
|
||||||
|
// Check for std::experimental::string_view (in c++14, compiler-dependent)
|
||||||
|
#elif __has_include(<experimental/string_view>) && (__cplusplus >= 201411)
|
||||||
|
#include <experimental/string_view>
|
||||||
|
namespace flatbuffers {
|
||||||
|
typedef std::experimental::string_view string_view;
|
||||||
|
}
|
||||||
|
#define FLATBUFFERS_HAS_STRING_VIEW 1
|
||||||
|
// Check for absl::string_view
|
||||||
|
#elif __has_include("absl/strings/string_view.h") && \
|
||||||
|
__has_include("absl/base/config.h") && \
|
||||||
|
(__cplusplus >= 201411)
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
#if !defined(ABSL_USES_STD_STRING_VIEW)
|
||||||
|
#include "absl/strings/string_view.h"
|
||||||
|
namespace flatbuffers {
|
||||||
|
typedef absl::string_view string_view;
|
||||||
|
}
|
||||||
|
#define FLATBUFFERS_HAS_STRING_VIEW 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif // __has_include
|
||||||
|
#endif // !FLATBUFFERS_HAS_STRING_VIEW
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_GENERAL_HEAP_ALLOC_OK
|
||||||
|
// Allow heap allocations to be used
|
||||||
|
#define FLATBUFFERS_GENERAL_HEAP_ALLOC_OK 1
|
||||||
|
#endif // !FLATBUFFERS_GENERAL_HEAP_ALLOC_OK
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_HAS_NEW_STRTOD
|
||||||
|
// Modern (C++11) strtod and strtof functions are available for use.
|
||||||
|
// 1) nan/inf strings as argument of strtod;
|
||||||
|
// 2) hex-float as argument of strtod/strtof.
|
||||||
|
#if (defined(_MSC_VER) && _MSC_VER >= 1900) || \
|
||||||
|
(defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 409)) || \
|
||||||
|
(defined(__clang__))
|
||||||
|
#define FLATBUFFERS_HAS_NEW_STRTOD 1
|
||||||
|
#endif
|
||||||
|
#endif // !FLATBUFFERS_HAS_NEW_STRTOD
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_LOCALE_INDEPENDENT
|
||||||
|
// Enable locale independent functions {strtof_l, strtod_l,strtoll_l,
|
||||||
|
// strtoull_l} on platforms that support them.
|
||||||
|
#if (defined(_MSC_VER) && _MSC_VER >= 1800) || \
|
||||||
|
(defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__>= 26) || \
|
||||||
|
(defined(_XOPEN_VERSION) && (_XOPEN_VERSION >= 700)) && \
|
||||||
|
!defined(__Fuchsia__)
|
||||||
|
#define FLATBUFFERS_LOCALE_INDEPENDENT 1
|
||||||
|
#else
|
||||||
|
#define FLATBUFFERS_LOCALE_INDEPENDENT 0
|
||||||
|
#endif
|
||||||
|
#endif // !FLATBUFFERS_LOCALE_INDEPENDENT
|
||||||
|
|
||||||
|
// Suppress Undefined Behavior Sanitizer (recoverable only). Usage:
|
||||||
|
// - FLATBUFFERS_SUPPRESS_UBSAN("undefined")
|
||||||
|
// - FLATBUFFERS_SUPPRESS_UBSAN("signed-integer-overflow")
|
||||||
|
#if defined(__clang__) && (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >=7))
|
||||||
|
#define FLATBUFFERS_SUPPRESS_UBSAN(type) __attribute__((no_sanitize(type)))
|
||||||
|
#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 409)
|
||||||
|
#define FLATBUFFERS_SUPPRESS_UBSAN(type) __attribute__((no_sanitize_undefined))
|
||||||
|
#else
|
||||||
|
#define FLATBUFFERS_SUPPRESS_UBSAN(type)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
// This is constexpr function used for checking compile-time constants.
|
||||||
|
// Avoid `#pragma warning(disable: 4127) // C4127: expression is constant`.
|
||||||
|
template<typename T> FLATBUFFERS_CONSTEXPR inline bool IsConstTrue(T t) {
|
||||||
|
return !!t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable C++ attribute [[]] if std:c++17 or higher.
|
||||||
|
#if ((__cplusplus >= 201703L) \
|
||||||
|
|| (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L)))
|
||||||
|
// All attributes unknown to an implementation are ignored without causing an error.
|
||||||
|
#define FLATBUFFERS_ATTRIBUTE(attr) attr
|
||||||
|
|
||||||
|
#define FLATBUFFERS_FALLTHROUGH() [[fallthrough]]
|
||||||
|
#else
|
||||||
|
#define FLATBUFFERS_ATTRIBUTE(attr)
|
||||||
|
|
||||||
|
#if FLATBUFFERS_CLANG >= 30800
|
||||||
|
#define FLATBUFFERS_FALLTHROUGH() [[clang::fallthrough]]
|
||||||
|
#elif FLATBUFFERS_GCC >= 70300
|
||||||
|
#define FLATBUFFERS_FALLTHROUGH() [[gnu::fallthrough]]
|
||||||
|
#else
|
||||||
|
#define FLATBUFFERS_FALLTHROUGH()
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// @endcond
|
||||||
|
|
||||||
|
/// @file
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
/// @cond FLATBUFFERS_INTERNAL
|
||||||
|
// Our default offset / size type, 32bit on purpose on 64bit systems.
|
||||||
|
// Also, using a consistent offset type maintains compatibility of serialized
|
||||||
|
// offset values between 32bit and 64bit systems.
|
||||||
|
typedef uint32_t uoffset_t;
|
||||||
|
typedef uint64_t uoffset64_t;
|
||||||
|
|
||||||
|
// Signed offsets for references that can go in both directions.
|
||||||
|
typedef int32_t soffset_t;
|
||||||
|
typedef int64_t soffset64_t;
|
||||||
|
|
||||||
|
// Offset/index used in v-tables, can be changed to uint8_t in
|
||||||
|
// format forks to save a bit of space if desired.
|
||||||
|
typedef uint16_t voffset_t;
|
||||||
|
|
||||||
|
typedef uintmax_t largest_scalar_t;
|
||||||
|
|
||||||
|
// In 32bits, this evaluates to 2GB - 1
|
||||||
|
#define FLATBUFFERS_MAX_BUFFER_SIZE (std::numeric_limits<::flatbuffers::soffset_t>::max)()
|
||||||
|
#define FLATBUFFERS_MAX_64_BUFFER_SIZE (std::numeric_limits<::flatbuffers::soffset64_t>::max)()
|
||||||
|
|
||||||
|
// The minimum size buffer that can be a valid flatbuffer.
|
||||||
|
// Includes the offset to the root table (uoffset_t), the offset to the vtable
|
||||||
|
// of the root table (soffset_t), the size of the vtable (uint16_t), and the
|
||||||
|
// size of the referring table (uint16_t).
|
||||||
|
#define FLATBUFFERS_MIN_BUFFER_SIZE sizeof(::flatbuffers::uoffset_t) + \
|
||||||
|
sizeof(::flatbuffers::soffset_t) + sizeof(uint16_t) + sizeof(uint16_t)
|
||||||
|
|
||||||
|
// We support aligning the contents of buffers up to this size.
|
||||||
|
#ifndef FLATBUFFERS_MAX_ALIGNMENT
|
||||||
|
#define FLATBUFFERS_MAX_ALIGNMENT 32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// @brief The length of a FlatBuffer file header.
|
||||||
|
static const size_t kFileIdentifierLength = 4;
|
||||||
|
|
||||||
|
inline bool VerifyAlignmentRequirements(size_t align, size_t min_align = 1) {
|
||||||
|
return (min_align <= align) && (align <= (FLATBUFFERS_MAX_ALIGNMENT)) &&
|
||||||
|
(align & (align - 1)) == 0; // must be power of 2
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable: 4127) // C4127: conditional expression is constant
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<typename T> T EndianSwap(T t) {
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#define FLATBUFFERS_BYTESWAP16 _byteswap_ushort
|
||||||
|
#define FLATBUFFERS_BYTESWAP32 _byteswap_ulong
|
||||||
|
#define FLATBUFFERS_BYTESWAP64 _byteswap_uint64
|
||||||
|
#elif defined(__ICCARM__)
|
||||||
|
#define FLATBUFFERS_BYTESWAP16 __REV16
|
||||||
|
#define FLATBUFFERS_BYTESWAP32 __REV
|
||||||
|
#define FLATBUFFERS_BYTESWAP64(x) \
|
||||||
|
((__REV(static_cast<uint32_t>(x >> 32U))) | (static_cast<uint64_t>(__REV(static_cast<uint32_t>(x)))) << 32U)
|
||||||
|
#else
|
||||||
|
#if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ < 408 && !defined(__clang__)
|
||||||
|
// __builtin_bswap16 was missing prior to GCC 4.8.
|
||||||
|
#define FLATBUFFERS_BYTESWAP16(x) \
|
||||||
|
static_cast<uint16_t>(__builtin_bswap32(static_cast<uint32_t>(x) << 16))
|
||||||
|
#else
|
||||||
|
#define FLATBUFFERS_BYTESWAP16 __builtin_bswap16
|
||||||
|
#endif
|
||||||
|
#define FLATBUFFERS_BYTESWAP32 __builtin_bswap32
|
||||||
|
#define FLATBUFFERS_BYTESWAP64 __builtin_bswap64
|
||||||
|
#endif
|
||||||
|
if (sizeof(T) == 1) { // Compile-time if-then's.
|
||||||
|
return t;
|
||||||
|
} else if (sizeof(T) == 2) {
|
||||||
|
union { T t; uint16_t i; } u = { t };
|
||||||
|
u.i = FLATBUFFERS_BYTESWAP16(u.i);
|
||||||
|
return u.t;
|
||||||
|
} else if (sizeof(T) == 4) {
|
||||||
|
union { T t; uint32_t i; } u = { t };
|
||||||
|
u.i = FLATBUFFERS_BYTESWAP32(u.i);
|
||||||
|
return u.t;
|
||||||
|
} else if (sizeof(T) == 8) {
|
||||||
|
union { T t; uint64_t i; } u = { t };
|
||||||
|
u.i = FLATBUFFERS_BYTESWAP64(u.i);
|
||||||
|
return u.t;
|
||||||
|
} else {
|
||||||
|
FLATBUFFERS_ASSERT(0);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T> T EndianScalar(T t) {
|
||||||
|
#if FLATBUFFERS_LITTLEENDIAN
|
||||||
|
return t;
|
||||||
|
#else
|
||||||
|
return EndianSwap(t);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
// UBSAN: C++ aliasing type rules, see std::bit_cast<> for details.
|
||||||
|
FLATBUFFERS_SUPPRESS_UBSAN("alignment")
|
||||||
|
T ReadScalar(const void *p) {
|
||||||
|
return EndianScalar(*reinterpret_cast<const T *>(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
// See https://github.com/google/flatbuffers/issues/5950
|
||||||
|
|
||||||
|
#if (FLATBUFFERS_GCC >= 100000) && (FLATBUFFERS_GCC < 110000)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wstringop-overflow"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
// UBSAN: C++ aliasing type rules, see std::bit_cast<> for details.
|
||||||
|
FLATBUFFERS_SUPPRESS_UBSAN("alignment")
|
||||||
|
void WriteScalar(void *p, T t) {
|
||||||
|
*reinterpret_cast<T *>(p) = EndianScalar(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> struct Offset;
|
||||||
|
template<typename T> FLATBUFFERS_SUPPRESS_UBSAN("alignment") void WriteScalar(void *p, Offset<T> t) {
|
||||||
|
*reinterpret_cast<uoffset_t *>(p) = EndianScalar(t.o);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (FLATBUFFERS_GCC >= 100000) && (FLATBUFFERS_GCC < 110000)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Computes how many bytes you'd have to pad to be able to write an
|
||||||
|
// "scalar_size" scalar if the buffer had grown to "buf_size" (downwards in
|
||||||
|
// memory).
|
||||||
|
FLATBUFFERS_SUPPRESS_UBSAN("unsigned-integer-overflow")
|
||||||
|
inline size_t PaddingBytes(size_t buf_size, size_t scalar_size) {
|
||||||
|
return ((~buf_size) + 1) & (scalar_size - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(_MSC_VER)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||||
|
#endif
|
||||||
|
// Generic 'operator==' with conditional specialisations.
|
||||||
|
// T e - new value of a scalar field.
|
||||||
|
// T def - default of scalar (is known at compile-time).
|
||||||
|
template<typename T> inline bool IsTheSameAs(T e, T def) { return e == def; }
|
||||||
|
#if !defined(_MSC_VER)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(FLATBUFFERS_NAN_DEFAULTS) && \
|
||||||
|
defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
|
||||||
|
// Like `operator==(e, def)` with weak NaN if T=(float|double).
|
||||||
|
template<typename T> inline bool IsFloatTheSameAs(T e, T def) {
|
||||||
|
return (e == def) || ((def != def) && (e != e));
|
||||||
|
}
|
||||||
|
template<> inline bool IsTheSameAs<float>(float e, float def) {
|
||||||
|
return IsFloatTheSameAs(e, def);
|
||||||
|
}
|
||||||
|
template<> inline bool IsTheSameAs<double>(double e, double def) {
|
||||||
|
return IsFloatTheSameAs(e, def);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Check 'v' is out of closed range [low; high].
|
||||||
|
// Workaround for GCC warning [-Werror=type-limits]:
|
||||||
|
// comparison is always true due to limited range of data type.
|
||||||
|
template<typename T>
|
||||||
|
inline bool IsOutRange(const T &v, const T &low, const T &high) {
|
||||||
|
return (v < low) || (high < v);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check 'v' is in closed range [low; high].
|
||||||
|
template<typename T>
|
||||||
|
inline bool IsInRange(const T &v, const T &low, const T &high) {
|
||||||
|
return !IsOutRange(v, low, high);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
#endif // FLATBUFFERS_BASE_H_
|
||||||
@@ -0,0 +1,225 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_BUFFER_H_
|
||||||
|
#define FLATBUFFERS_BUFFER_H_
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "flatbuffers/base.h"
|
||||||
|
#include "flatbuffers/stl_emulation.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
// Wrapper for uoffset_t to allow safe template specialization.
|
||||||
|
// Value is allowed to be 0 to indicate a null object (see e.g. AddOffset).
|
||||||
|
template <typename T = void>
|
||||||
|
struct Offset {
|
||||||
|
// The type of offset to use.
|
||||||
|
typedef uoffset_t offset_type;
|
||||||
|
|
||||||
|
offset_type o;
|
||||||
|
Offset() : o(0) {}
|
||||||
|
Offset(const offset_type _o) : o(_o) {}
|
||||||
|
Offset<> Union() const { return o; }
|
||||||
|
bool IsNull() const { return !o; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_specialisation_of_Offset : false_type {};
|
||||||
|
template <typename T>
|
||||||
|
struct is_specialisation_of_Offset<Offset<T>> : true_type {};
|
||||||
|
|
||||||
|
// Wrapper for uoffset64_t Offsets.
|
||||||
|
template <typename T = void>
|
||||||
|
struct Offset64 {
|
||||||
|
// The type of offset to use.
|
||||||
|
typedef uoffset64_t offset_type;
|
||||||
|
|
||||||
|
offset_type o;
|
||||||
|
Offset64() : o(0) {}
|
||||||
|
Offset64(const offset_type offset) : o(offset) {}
|
||||||
|
Offset64<> Union() const { return o; }
|
||||||
|
bool IsNull() const { return !o; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_specialisation_of_Offset64 : false_type {};
|
||||||
|
template <typename T>
|
||||||
|
struct is_specialisation_of_Offset64<Offset64<T>> : true_type {};
|
||||||
|
|
||||||
|
// Litmus check for ensuring the Offsets are the expected size.
|
||||||
|
static_assert(sizeof(Offset<>) == 4, "Offset has wrong size");
|
||||||
|
static_assert(sizeof(Offset64<>) == 8, "Offset64 has wrong size");
|
||||||
|
|
||||||
|
inline void EndianCheck() {
|
||||||
|
int endiantest = 1;
|
||||||
|
// If this fails, see FLATBUFFERS_LITTLEENDIAN above.
|
||||||
|
FLATBUFFERS_ASSERT(*reinterpret_cast<char*>(&endiantest) ==
|
||||||
|
FLATBUFFERS_LITTLEENDIAN);
|
||||||
|
(void)endiantest;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
FLATBUFFERS_CONSTEXPR size_t AlignOf() {
|
||||||
|
// clang-format off
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
return __alignof(T);
|
||||||
|
#else
|
||||||
|
#ifndef alignof
|
||||||
|
return __alignof__(T);
|
||||||
|
#else
|
||||||
|
return alignof(T);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lexicographically compare two strings (possibly containing nulls), and
|
||||||
|
// return true if the first is less than the second.
|
||||||
|
static inline bool StringLessThan(const char* a_data, uoffset_t a_size,
|
||||||
|
const char* b_data, uoffset_t b_size) {
|
||||||
|
const auto cmp = memcmp(a_data, b_data, (std::min)(a_size, b_size));
|
||||||
|
return cmp == 0 ? a_size < b_size : cmp < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When we read serialized data from memory, in the case of most scalars,
|
||||||
|
// we want to just read T, but in the case of Offset, we want to actually
|
||||||
|
// perform the indirection and return a pointer.
|
||||||
|
// The template specialization below does just that.
|
||||||
|
// It is wrapped in a struct since function templates can't overload on the
|
||||||
|
// return type like this.
|
||||||
|
// The typedef is for the convenience of callers of this function
|
||||||
|
// (avoiding the need for a trailing return decltype)
|
||||||
|
template <typename T, typename Enable = void>
|
||||||
|
struct IndirectHelper {
|
||||||
|
typedef T return_type;
|
||||||
|
typedef T mutable_return_type;
|
||||||
|
static const size_t element_stride = sizeof(T);
|
||||||
|
|
||||||
|
static return_type Read(const uint8_t* p, const size_t i) {
|
||||||
|
return EndianScalar((reinterpret_cast<const T*>(p))[i]);
|
||||||
|
}
|
||||||
|
static mutable_return_type Read(uint8_t* p, const size_t i) {
|
||||||
|
return reinterpret_cast<mutable_return_type>(
|
||||||
|
Read(const_cast<const uint8_t*>(p), i));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// For vector of Offsets.
|
||||||
|
template <typename T, template <typename> class OffsetT>
|
||||||
|
struct IndirectHelper<OffsetT<T>> {
|
||||||
|
typedef const T* return_type;
|
||||||
|
typedef T* mutable_return_type;
|
||||||
|
typedef typename OffsetT<T>::offset_type offset_type;
|
||||||
|
static const offset_type element_stride = sizeof(offset_type);
|
||||||
|
|
||||||
|
static return_type Read(const uint8_t* const p, const offset_type i) {
|
||||||
|
// Offsets are relative to themselves, so first update the pointer to
|
||||||
|
// point to the offset location.
|
||||||
|
const uint8_t* const offset_location = p + i * element_stride;
|
||||||
|
|
||||||
|
// Then read the scalar value of the offset (which may be 32 or 64-bits) and
|
||||||
|
// then determine the relative location from the offset location.
|
||||||
|
return reinterpret_cast<return_type>(
|
||||||
|
offset_location + ReadScalar<offset_type>(offset_location));
|
||||||
|
}
|
||||||
|
static mutable_return_type Read(uint8_t* const p, const offset_type i) {
|
||||||
|
// Offsets are relative to themselves, so first update the pointer to
|
||||||
|
// point to the offset location.
|
||||||
|
uint8_t* const offset_location = p + i * element_stride;
|
||||||
|
|
||||||
|
// Then read the scalar value of the offset (which may be 32 or 64-bits) and
|
||||||
|
// then determine the relative location from the offset location.
|
||||||
|
return reinterpret_cast<mutable_return_type>(
|
||||||
|
offset_location + ReadScalar<offset_type>(offset_location));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// For vector of structs.
|
||||||
|
template <typename T>
|
||||||
|
struct IndirectHelper<
|
||||||
|
T, typename std::enable_if<
|
||||||
|
!std::is_scalar<typename std::remove_pointer<T>::type>::value &&
|
||||||
|
!is_specialisation_of_Offset<T>::value &&
|
||||||
|
!is_specialisation_of_Offset64<T>::value>::type> {
|
||||||
|
private:
|
||||||
|
typedef typename std::remove_pointer<typename std::remove_cv<T>::type>::type
|
||||||
|
pointee_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef const pointee_type* return_type;
|
||||||
|
typedef pointee_type* mutable_return_type;
|
||||||
|
static const size_t element_stride = sizeof(pointee_type);
|
||||||
|
|
||||||
|
static return_type Read(const uint8_t* const p, const size_t i) {
|
||||||
|
// Structs are stored inline, relative to the first struct pointer.
|
||||||
|
return reinterpret_cast<return_type>(p + i * element_stride);
|
||||||
|
}
|
||||||
|
static mutable_return_type Read(uint8_t* const p, const size_t i) {
|
||||||
|
// Structs are stored inline, relative to the first struct pointer.
|
||||||
|
return reinterpret_cast<mutable_return_type>(p + i * element_stride);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief Get a pointer to the file_identifier section of the buffer.
|
||||||
|
/// @return Returns a const char pointer to the start of the file_identifier
|
||||||
|
/// characters in the buffer. The returned char * has length
|
||||||
|
/// 'flatbuffers::FlatBufferBuilder::kFileIdentifierLength'.
|
||||||
|
/// This function is UNDEFINED for FlatBuffers whose schema does not include
|
||||||
|
/// a file_identifier (likely points at padding or the start of a the root
|
||||||
|
/// vtable).
|
||||||
|
inline const char* GetBufferIdentifier(const void* buf,
|
||||||
|
bool size_prefixed = false) {
|
||||||
|
return reinterpret_cast<const char*>(buf) +
|
||||||
|
((size_prefixed) ? 2 * sizeof(uoffset_t) : sizeof(uoffset_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to see if the identifier in a buffer has the expected value.
|
||||||
|
inline bool BufferHasIdentifier(const void* buf, const char* identifier,
|
||||||
|
bool size_prefixed = false) {
|
||||||
|
return strncmp(GetBufferIdentifier(buf, size_prefixed), identifier,
|
||||||
|
flatbuffers::kFileIdentifierLength) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @cond FLATBUFFERS_INTERNAL
|
||||||
|
// Helpers to get a typed pointer to the root object contained in the buffer.
|
||||||
|
template <typename T>
|
||||||
|
T* GetMutableRoot(void* buf) {
|
||||||
|
if (!buf) return nullptr;
|
||||||
|
EndianCheck();
|
||||||
|
return reinterpret_cast<T*>(reinterpret_cast<uint8_t*>(buf) +
|
||||||
|
EndianScalar(*reinterpret_cast<uoffset_t*>(buf)));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename SizeT = uoffset_t>
|
||||||
|
T* GetMutableSizePrefixedRoot(void* buf) {
|
||||||
|
return GetMutableRoot<T>(reinterpret_cast<uint8_t*>(buf) + sizeof(SizeT));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
const T* GetRoot(const void* buf) {
|
||||||
|
return GetMutableRoot<T>(const_cast<void*>(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename SizeT = uoffset_t>
|
||||||
|
const T* GetSizePrefixedRoot(const void* buf) {
|
||||||
|
return GetRoot<T>(reinterpret_cast<const uint8_t*>(buf) + sizeof(SizeT));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_BUFFER_H_
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_BUFFER_REF_H_
|
||||||
|
#define FLATBUFFERS_BUFFER_REF_H_
|
||||||
|
|
||||||
|
#include "flatbuffers/base.h"
|
||||||
|
#include "flatbuffers/verifier.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
// Convenient way to bundle a buffer and its length, to pass it around
|
||||||
|
// typed by its root.
|
||||||
|
// A BufferRef does not own its buffer.
|
||||||
|
struct BufferRefBase {}; // for std::is_base_of
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct BufferRef : BufferRefBase {
|
||||||
|
BufferRef() : buf(nullptr), len(0), must_free(false) {}
|
||||||
|
BufferRef(uint8_t* _buf, uoffset_t _len)
|
||||||
|
: buf(_buf), len(_len), must_free(false) {}
|
||||||
|
|
||||||
|
~BufferRef() {
|
||||||
|
if (must_free) free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
const T* GetRoot() const { return flatbuffers::GetRoot<T>(buf); }
|
||||||
|
|
||||||
|
bool Verify() {
|
||||||
|
Verifier verifier(buf, len);
|
||||||
|
return verifier.VerifyBuffer<T>(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* buf;
|
||||||
|
uoffset_t len;
|
||||||
|
bool must_free;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_BUFFER_REF_H_
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_CODE_GENERATOR_H_
|
||||||
|
#define FLATBUFFERS_CODE_GENERATOR_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "flatbuffers/file_manager.h"
|
||||||
|
#include "flatbuffers/idl.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
struct CodeGenOptions {
|
||||||
|
std::string output_path;
|
||||||
|
FileSaver* file_saver{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
|
// A code generator interface for producing converting flatbuffer schema into
|
||||||
|
// code.
|
||||||
|
class CodeGenerator {
|
||||||
|
public:
|
||||||
|
virtual ~CodeGenerator() = default;
|
||||||
|
|
||||||
|
enum Status {
|
||||||
|
OK = 0,
|
||||||
|
ERROR = 1,
|
||||||
|
FAILED_VERIFICATION = 2,
|
||||||
|
NOT_IMPLEMENTED = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string status_detail;
|
||||||
|
|
||||||
|
// Generate code from the provided `parser`.
|
||||||
|
//
|
||||||
|
// DEPRECATED: prefer using the other overload of GenerateCode for bfbs.
|
||||||
|
virtual Status GenerateCode(const Parser& parser, const std::string& path,
|
||||||
|
const std::string& filename) = 0;
|
||||||
|
|
||||||
|
// Generate code from the provided `parser` and place it in the output.
|
||||||
|
virtual Status GenerateCodeString(const Parser& parser,
|
||||||
|
const std::string& filename,
|
||||||
|
std::string& output) {
|
||||||
|
(void)parser;
|
||||||
|
(void)filename;
|
||||||
|
(void)output;
|
||||||
|
return Status::NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate code from the provided `buffer` of given `length`. The buffer is a
|
||||||
|
// serialized reflection.fbs.
|
||||||
|
virtual Status GenerateCode(const uint8_t* buffer, int64_t length,
|
||||||
|
const CodeGenOptions& options) = 0;
|
||||||
|
|
||||||
|
virtual Status GenerateMakeRule(const Parser& parser, const std::string& path,
|
||||||
|
const std::string& filename,
|
||||||
|
std::string& output) = 0;
|
||||||
|
|
||||||
|
virtual Status GenerateGrpcCode(const Parser& parser, const std::string& path,
|
||||||
|
const std::string& filename) = 0;
|
||||||
|
|
||||||
|
virtual Status GenerateRootFile(const Parser& parser,
|
||||||
|
const std::string& path) = 0;
|
||||||
|
|
||||||
|
virtual bool IsSchemaOnly() const = 0;
|
||||||
|
|
||||||
|
virtual bool SupportsBfbsGeneration() const = 0;
|
||||||
|
|
||||||
|
virtual bool SupportsRootFileGeneration() const = 0;
|
||||||
|
|
||||||
|
virtual IDLOptions::Language Language() const = 0;
|
||||||
|
|
||||||
|
virtual std::string LanguageName() const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
CodeGenerator() = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Copying is not supported.
|
||||||
|
CodeGenerator(const CodeGenerator&) = delete;
|
||||||
|
CodeGenerator& operator=(const CodeGenerator&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_CODE_GENERATOR_H_
|
||||||
@@ -0,0 +1,238 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_CODE_GENERATORS_H_
|
||||||
|
#define FLATBUFFERS_CODE_GENERATORS_H_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "flatbuffers/idl.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
// Utility class to assist in generating code through use of text templates.
|
||||||
|
//
|
||||||
|
// Example code:
|
||||||
|
// CodeWriter code("\t");
|
||||||
|
// code.SetValue("NAME", "Foo");
|
||||||
|
// code += "void {{NAME}}() { printf("%s", "{{NAME}}"); }";
|
||||||
|
// code.SetValue("NAME", "Bar");
|
||||||
|
// code += "void {{NAME}}() { printf("%s", "{{NAME}}"); }";
|
||||||
|
// std::cout << code.ToString() << std::endl;
|
||||||
|
//
|
||||||
|
// Output:
|
||||||
|
// void Foo() { printf("%s", "Foo"); }
|
||||||
|
// void Bar() { printf("%s", "Bar"); }
|
||||||
|
class CodeWriter {
|
||||||
|
public:
|
||||||
|
CodeWriter(std::string pad = std::string())
|
||||||
|
: pad_(pad), cur_ident_lvl_(0), ignore_ident_(false) {}
|
||||||
|
|
||||||
|
// Clears the current "written" code.
|
||||||
|
void Clear() {
|
||||||
|
stream_.str("");
|
||||||
|
stream_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Associates a key with a value. All subsequent calls to operator+=, where
|
||||||
|
// the specified key is contained in {{ and }} delimiters will be replaced by
|
||||||
|
// the given value.
|
||||||
|
void SetValue(const std::string& key, const std::string& value) {
|
||||||
|
value_map_[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetValue(const std::string& key) const {
|
||||||
|
const auto it = value_map_.find(key);
|
||||||
|
return it == value_map_.end() ? "" : it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Appends the given text to the generated code as well as a newline
|
||||||
|
// character. Any text within {{ and }} delimiters is replaced by values
|
||||||
|
// previously stored in the CodeWriter by calling SetValue above. The newline
|
||||||
|
// will be suppressed if the text ends with the \\ character.
|
||||||
|
void operator+=(std::string text);
|
||||||
|
|
||||||
|
// Returns the current contents of the CodeWriter as a std::string.
|
||||||
|
std::string ToString() const { return stream_.str(); }
|
||||||
|
|
||||||
|
// Increase ident level for writing code
|
||||||
|
void IncrementIdentLevel() { cur_ident_lvl_++; }
|
||||||
|
// Decrease ident level for writing code
|
||||||
|
void DecrementIdentLevel() {
|
||||||
|
if (cur_ident_lvl_) cur_ident_lvl_--;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetPadding(const std::string& padding) { pad_ = padding; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<std::string, std::string> value_map_;
|
||||||
|
std::stringstream stream_;
|
||||||
|
std::string pad_;
|
||||||
|
int cur_ident_lvl_;
|
||||||
|
bool ignore_ident_;
|
||||||
|
|
||||||
|
// Add ident padding (tab or space) based on ident level
|
||||||
|
void AppendIdent(std::stringstream& stream);
|
||||||
|
};
|
||||||
|
|
||||||
|
class BaseGenerator {
|
||||||
|
public:
|
||||||
|
virtual bool generate() = 0;
|
||||||
|
|
||||||
|
static std::string NamespaceDir(const Parser& parser, const std::string& path,
|
||||||
|
const Namespace& ns,
|
||||||
|
const bool dasherize = false);
|
||||||
|
|
||||||
|
std::string GeneratedFileName(const std::string& path,
|
||||||
|
const std::string& file_name,
|
||||||
|
const IDLOptions& options) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
BaseGenerator(const Parser& parser, const std::string& path,
|
||||||
|
const std::string& file_name, std::string qualifying_start,
|
||||||
|
std::string qualifying_separator, std::string default_extension)
|
||||||
|
: parser_(parser),
|
||||||
|
path_(path),
|
||||||
|
file_name_(file_name),
|
||||||
|
qualifying_start_(qualifying_start),
|
||||||
|
qualifying_separator_(qualifying_separator),
|
||||||
|
default_extension_(default_extension) {}
|
||||||
|
virtual ~BaseGenerator() {}
|
||||||
|
|
||||||
|
// No copy/assign.
|
||||||
|
BaseGenerator& operator=(const BaseGenerator&);
|
||||||
|
BaseGenerator(const BaseGenerator&);
|
||||||
|
|
||||||
|
std::string NamespaceDir(const Namespace& ns,
|
||||||
|
const bool dasherize = false) const;
|
||||||
|
|
||||||
|
static const char* FlatBuffersGeneratedWarning();
|
||||||
|
|
||||||
|
static std::string FullNamespace(const char* separator, const Namespace& ns);
|
||||||
|
|
||||||
|
static std::string LastNamespacePart(const Namespace& ns);
|
||||||
|
|
||||||
|
// tracks the current namespace for early exit in WrapInNameSpace
|
||||||
|
// c++, java and csharp returns a different namespace from
|
||||||
|
// the following default (no early exit, always fully qualify),
|
||||||
|
// which works for js and php
|
||||||
|
virtual const Namespace* CurrentNameSpace() const { return nullptr; }
|
||||||
|
|
||||||
|
// Ensure that a type is prefixed with its namespace even within
|
||||||
|
// its own namespace to avoid conflict between generated method
|
||||||
|
// names and similarly named classes or structs
|
||||||
|
std::string WrapInNameSpace(const Namespace* ns,
|
||||||
|
const std::string& name) const;
|
||||||
|
|
||||||
|
std::string WrapInNameSpace(const Definition& def,
|
||||||
|
const std::string& suffix = "") const;
|
||||||
|
|
||||||
|
std::string GetNameSpace(const Definition& def) const;
|
||||||
|
|
||||||
|
const Parser& parser_;
|
||||||
|
const std::string& path_;
|
||||||
|
const std::string& file_name_;
|
||||||
|
const std::string qualifying_start_;
|
||||||
|
const std::string qualifying_separator_;
|
||||||
|
const std::string default_extension_;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CommentConfig {
|
||||||
|
const char* first_line;
|
||||||
|
const char* content_line_prefix;
|
||||||
|
const char* last_line;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void GenComment(const std::vector<std::string>& dc,
|
||||||
|
std::string* code_ptr, const CommentConfig* config,
|
||||||
|
const char* prefix = "");
|
||||||
|
|
||||||
|
class FloatConstantGenerator {
|
||||||
|
public:
|
||||||
|
virtual ~FloatConstantGenerator() {}
|
||||||
|
std::string GenFloatConstant(const FieldDef& field) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual std::string Value(double v, const std::string& src) const = 0;
|
||||||
|
virtual std::string Inf(double v) const = 0;
|
||||||
|
virtual std::string NaN(double v) const = 0;
|
||||||
|
|
||||||
|
virtual std::string Value(float v, const std::string& src) const = 0;
|
||||||
|
virtual std::string Inf(float v) const = 0;
|
||||||
|
virtual std::string NaN(float v) const = 0;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::string GenFloatConstantImpl(const FieldDef& field) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SimpleFloatConstantGenerator : public FloatConstantGenerator {
|
||||||
|
public:
|
||||||
|
SimpleFloatConstantGenerator(const char* nan_number,
|
||||||
|
const char* pos_inf_number,
|
||||||
|
const char* neg_inf_number);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string Value(double v,
|
||||||
|
const std::string& src) const FLATBUFFERS_OVERRIDE;
|
||||||
|
std::string Inf(double v) const FLATBUFFERS_OVERRIDE;
|
||||||
|
std::string NaN(double v) const FLATBUFFERS_OVERRIDE;
|
||||||
|
|
||||||
|
std::string Value(float v, const std::string& src) const FLATBUFFERS_OVERRIDE;
|
||||||
|
std::string Inf(float v) const FLATBUFFERS_OVERRIDE;
|
||||||
|
std::string NaN(float v) const FLATBUFFERS_OVERRIDE;
|
||||||
|
|
||||||
|
const std::string nan_number_;
|
||||||
|
const std::string pos_inf_number_;
|
||||||
|
const std::string neg_inf_number_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// C++, C#, Java like generator.
|
||||||
|
class TypedFloatConstantGenerator : public FloatConstantGenerator {
|
||||||
|
public:
|
||||||
|
TypedFloatConstantGenerator(const char* double_prefix,
|
||||||
|
const char* single_prefix, const char* nan_number,
|
||||||
|
const char* pos_inf_number,
|
||||||
|
const char* neg_inf_number = "");
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string Value(double v,
|
||||||
|
const std::string& src) const FLATBUFFERS_OVERRIDE;
|
||||||
|
std::string Inf(double v) const FLATBUFFERS_OVERRIDE;
|
||||||
|
|
||||||
|
std::string NaN(double v) const FLATBUFFERS_OVERRIDE;
|
||||||
|
|
||||||
|
std::string Value(float v, const std::string& src) const FLATBUFFERS_OVERRIDE;
|
||||||
|
std::string Inf(float v) const FLATBUFFERS_OVERRIDE;
|
||||||
|
std::string NaN(float v) const FLATBUFFERS_OVERRIDE;
|
||||||
|
|
||||||
|
std::string MakeNaN(const std::string& prefix) const;
|
||||||
|
std::string MakeInf(bool neg, const std::string& prefix) const;
|
||||||
|
|
||||||
|
const std::string double_prefix_;
|
||||||
|
const std::string single_prefix_;
|
||||||
|
const std::string nan_number_;
|
||||||
|
const std::string pos_inf_number_;
|
||||||
|
const std::string neg_inf_number_;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string JavaCSharpMakeRule(const bool java, const Parser& parser,
|
||||||
|
const std::string& path,
|
||||||
|
const std::string& file_name);
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_CODE_GENERATORS_H_
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_DEFAULT_ALLOCATOR_H_
|
||||||
|
#define FLATBUFFERS_DEFAULT_ALLOCATOR_H_
|
||||||
|
|
||||||
|
#include "flatbuffers/allocator.h"
|
||||||
|
#include "flatbuffers/base.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
// DefaultAllocator uses new/delete to allocate memory regions
|
||||||
|
class DefaultAllocator : public Allocator {
|
||||||
|
public:
|
||||||
|
uint8_t* allocate(size_t size) FLATBUFFERS_OVERRIDE {
|
||||||
|
return new uint8_t[size];
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate(uint8_t* p, size_t) FLATBUFFERS_OVERRIDE { delete[] p; }
|
||||||
|
|
||||||
|
static void dealloc(void* p, size_t) { delete[] static_cast<uint8_t*>(p); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// These functions allow for a null allocator to mean use the default allocator,
|
||||||
|
// as used by DetachedBuffer and vector_downward below.
|
||||||
|
// This is to avoid having a statically or dynamically allocated default
|
||||||
|
// allocator, or having to move it between the classes that may own it.
|
||||||
|
inline uint8_t* Allocate(Allocator* allocator, size_t size) {
|
||||||
|
return allocator ? allocator->allocate(size)
|
||||||
|
: DefaultAllocator().allocate(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Deallocate(Allocator* allocator, uint8_t* p, size_t size) {
|
||||||
|
if (allocator)
|
||||||
|
allocator->deallocate(p, size);
|
||||||
|
else
|
||||||
|
DefaultAllocator().deallocate(p, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint8_t* ReallocateDownward(Allocator* allocator, uint8_t* old_p,
|
||||||
|
size_t old_size, size_t new_size,
|
||||||
|
size_t in_use_back, size_t in_use_front) {
|
||||||
|
return allocator ? allocator->reallocate_downward(old_p, old_size, new_size,
|
||||||
|
in_use_back, in_use_front)
|
||||||
|
: DefaultAllocator().reallocate_downward(
|
||||||
|
old_p, old_size, new_size, in_use_back, in_use_front);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_DEFAULT_ALLOCATOR_H_
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_DETACHED_BUFFER_H_
|
||||||
|
#define FLATBUFFERS_DETACHED_BUFFER_H_
|
||||||
|
|
||||||
|
#include "flatbuffers/allocator.h"
|
||||||
|
#include "flatbuffers/base.h"
|
||||||
|
#include "flatbuffers/default_allocator.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
// DetachedBuffer is a finished flatbuffer memory region, detached from its
|
||||||
|
// builder. The original memory region and allocator are also stored so that
|
||||||
|
// the DetachedBuffer can manage the memory lifetime.
|
||||||
|
class DetachedBuffer {
|
||||||
|
public:
|
||||||
|
DetachedBuffer()
|
||||||
|
: allocator_(nullptr),
|
||||||
|
own_allocator_(false),
|
||||||
|
buf_(nullptr),
|
||||||
|
reserved_(0),
|
||||||
|
cur_(nullptr),
|
||||||
|
size_(0) {}
|
||||||
|
|
||||||
|
DetachedBuffer(Allocator* allocator, bool own_allocator, uint8_t* buf,
|
||||||
|
size_t reserved, uint8_t* cur, size_t sz)
|
||||||
|
: allocator_(allocator),
|
||||||
|
own_allocator_(own_allocator),
|
||||||
|
buf_(buf),
|
||||||
|
reserved_(reserved),
|
||||||
|
cur_(cur),
|
||||||
|
size_(sz) {}
|
||||||
|
|
||||||
|
DetachedBuffer(DetachedBuffer&& other) noexcept
|
||||||
|
: allocator_(other.allocator_),
|
||||||
|
own_allocator_(other.own_allocator_),
|
||||||
|
buf_(other.buf_),
|
||||||
|
reserved_(other.reserved_),
|
||||||
|
cur_(other.cur_),
|
||||||
|
size_(other.size_) {
|
||||||
|
other.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
DetachedBuffer& operator=(DetachedBuffer&& other) noexcept {
|
||||||
|
if (this == &other) return *this;
|
||||||
|
|
||||||
|
destroy();
|
||||||
|
|
||||||
|
allocator_ = other.allocator_;
|
||||||
|
own_allocator_ = other.own_allocator_;
|
||||||
|
buf_ = other.buf_;
|
||||||
|
reserved_ = other.reserved_;
|
||||||
|
cur_ = other.cur_;
|
||||||
|
size_ = other.size_;
|
||||||
|
|
||||||
|
other.reset();
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~DetachedBuffer() { destroy(); }
|
||||||
|
|
||||||
|
const uint8_t* data() const { return cur_; }
|
||||||
|
|
||||||
|
uint8_t* data() { return cur_; }
|
||||||
|
|
||||||
|
size_t size() const { return size_; }
|
||||||
|
|
||||||
|
uint8_t* begin() { return data(); }
|
||||||
|
const uint8_t* begin() const { return data(); }
|
||||||
|
uint8_t* end() { return data() + size(); }
|
||||||
|
const uint8_t* end() const { return data() + size(); }
|
||||||
|
|
||||||
|
// These may change access mode, leave these at end of public section
|
||||||
|
FLATBUFFERS_DELETE_FUNC(DetachedBuffer(const DetachedBuffer& other));
|
||||||
|
FLATBUFFERS_DELETE_FUNC(
|
||||||
|
DetachedBuffer& operator=(const DetachedBuffer& other));
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Allocator* allocator_;
|
||||||
|
bool own_allocator_;
|
||||||
|
uint8_t* buf_;
|
||||||
|
size_t reserved_;
|
||||||
|
uint8_t* cur_;
|
||||||
|
size_t size_;
|
||||||
|
|
||||||
|
inline void destroy() {
|
||||||
|
if (buf_) Deallocate(allocator_, buf_, reserved_);
|
||||||
|
if (own_allocator_ && allocator_) {
|
||||||
|
delete allocator_;
|
||||||
|
}
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void reset() {
|
||||||
|
allocator_ = nullptr;
|
||||||
|
own_allocator_ = false;
|
||||||
|
buf_ = nullptr;
|
||||||
|
reserved_ = 0;
|
||||||
|
cur_ = nullptr;
|
||||||
|
size_ = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_DETACHED_BUFFER_H_
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_FILE_MANAGER_H_
|
||||||
|
#define FLATBUFFERS_FILE_MANAGER_H_
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
// A File interface to write data to file by default or
|
||||||
|
// save only file names
|
||||||
|
class FileSaver {
|
||||||
|
public:
|
||||||
|
FileSaver() = default;
|
||||||
|
virtual ~FileSaver() = default;
|
||||||
|
|
||||||
|
virtual bool SaveFile(const char* name, const char* buf, size_t len,
|
||||||
|
bool binary) = 0;
|
||||||
|
|
||||||
|
bool SaveFile(const char* name, const std::string& buf, bool binary) {
|
||||||
|
return SaveFile(name, buf.c_str(), buf.size(), binary);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Finish() {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Copying is not supported.
|
||||||
|
FileSaver(const FileSaver&) = delete;
|
||||||
|
FileSaver& operator=(const FileSaver&) = delete;
|
||||||
|
// Rule of 5
|
||||||
|
FileSaver(FileSaver&&) = default;
|
||||||
|
FileSaver& operator=(FileSaver&&) = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RealFileSaver final : public FileSaver {
|
||||||
|
public:
|
||||||
|
bool SaveFile(const char* name, const char* buf, size_t len,
|
||||||
|
bool binary) final;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FileNameSaver final : public FileSaver {
|
||||||
|
public:
|
||||||
|
bool SaveFile(const char* name, const char* buf, size_t len,
|
||||||
|
bool binary) final;
|
||||||
|
|
||||||
|
void Finish() final;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::set<std::string> file_names_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_FILE_MANAGER_H_
|
||||||
+1518
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,284 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_H_
|
||||||
|
#define FLATBUFFERS_H_
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
// TODO: These includes are for mitigating the pains of users editing their
|
||||||
|
// source because they relied on flatbuffers.h to include everything for them.
|
||||||
|
#include "flatbuffers/array.h"
|
||||||
|
#include "flatbuffers/base.h"
|
||||||
|
#include "flatbuffers/buffer.h"
|
||||||
|
#include "flatbuffers/buffer_ref.h"
|
||||||
|
#include "flatbuffers/detached_buffer.h"
|
||||||
|
#include "flatbuffers/flatbuffer_builder.h"
|
||||||
|
#include "flatbuffers/stl_emulation.h"
|
||||||
|
#include "flatbuffers/string.h"
|
||||||
|
#include "flatbuffers/struct.h"
|
||||||
|
#include "flatbuffers/table.h"
|
||||||
|
#include "flatbuffers/vector.h"
|
||||||
|
#include "flatbuffers/vector_downward.h"
|
||||||
|
#include "flatbuffers/verifier.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
/// @brief This can compute the start of a FlatBuffer from a root pointer, i.e.
|
||||||
|
/// it is the opposite transformation of GetRoot().
|
||||||
|
/// This may be useful if you want to pass on a root and have the recipient
|
||||||
|
/// delete the buffer afterwards.
|
||||||
|
inline const uint8_t* GetBufferStartFromRootPointer(const void* root) {
|
||||||
|
auto table = reinterpret_cast<const Table*>(root);
|
||||||
|
auto vtable = table->GetVTable();
|
||||||
|
// Either the vtable is before the root or after the root.
|
||||||
|
auto start = (std::min)(vtable, reinterpret_cast<const uint8_t*>(root));
|
||||||
|
// Align to at least sizeof(uoffset_t).
|
||||||
|
start = reinterpret_cast<const uint8_t*>(reinterpret_cast<uintptr_t>(start) &
|
||||||
|
~(sizeof(uoffset_t) - 1));
|
||||||
|
// Additionally, there may be a file_identifier in the buffer, and the root
|
||||||
|
// offset. The buffer may have been aligned to any size between
|
||||||
|
// sizeof(uoffset_t) and FLATBUFFERS_MAX_ALIGNMENT (see "force_align").
|
||||||
|
// Sadly, the exact alignment is only known when constructing the buffer,
|
||||||
|
// since it depends on the presence of values with said alignment properties.
|
||||||
|
// So instead, we simply look at the next uoffset_t values (root,
|
||||||
|
// file_identifier, and alignment padding) to see which points to the root.
|
||||||
|
// None of the other values can "impersonate" the root since they will either
|
||||||
|
// be 0 or four ASCII characters.
|
||||||
|
static_assert(flatbuffers::kFileIdentifierLength == sizeof(uoffset_t),
|
||||||
|
"file_identifier is assumed to be the same size as uoffset_t");
|
||||||
|
for (auto possible_roots = FLATBUFFERS_MAX_ALIGNMENT / sizeof(uoffset_t) + 1;
|
||||||
|
possible_roots; possible_roots--) {
|
||||||
|
start -= sizeof(uoffset_t);
|
||||||
|
if (ReadScalar<uoffset_t>(start) + start ==
|
||||||
|
reinterpret_cast<const uint8_t*>(root))
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
// We didn't find the root, either the "root" passed isn't really a root,
|
||||||
|
// or the buffer is corrupt.
|
||||||
|
// Assert, because calling this function with bad data may cause reads
|
||||||
|
// outside of buffer boundaries.
|
||||||
|
FLATBUFFERS_ASSERT(false);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief This return the prefixed size of a FlatBuffer.
|
||||||
|
template <typename SizeT = uoffset_t>
|
||||||
|
inline SizeT GetPrefixedSize(const uint8_t* buf) {
|
||||||
|
return ReadScalar<SizeT>(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the total length of the buffer given a sized prefixed FlatBuffer.
|
||||||
|
//
|
||||||
|
// This includes the size of the prefix as well as the buffer:
|
||||||
|
//
|
||||||
|
// [size prefix][flatbuffer]
|
||||||
|
// |---------length--------|
|
||||||
|
template <typename SizeT = uoffset_t>
|
||||||
|
inline SizeT GetSizePrefixedBufferLength(const uint8_t* const buf) {
|
||||||
|
return ReadScalar<SizeT>(buf) + sizeof(SizeT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Base class for native objects (FlatBuffer data de-serialized into native
|
||||||
|
// C++ data structures).
|
||||||
|
// Contains no functionality, purely documentative.
|
||||||
|
struct NativeTable {};
|
||||||
|
|
||||||
|
/// @brief Function types to be used with resolving hashes into objects and
|
||||||
|
/// back again. The resolver gets a pointer to a field inside an object API
|
||||||
|
/// object that is of the type specified in the schema using the attribute
|
||||||
|
/// `cpp_type` (it is thus important whatever you write to this address
|
||||||
|
/// matches that type). The value of this field is initially null, so you
|
||||||
|
/// may choose to implement a delayed binding lookup using this function
|
||||||
|
/// if you wish. The resolver does the opposite lookup, for when the object
|
||||||
|
/// is being serialized again.
|
||||||
|
typedef uint64_t hash_value_t;
|
||||||
|
typedef std::function<void(void** pointer_adr, hash_value_t hash)>
|
||||||
|
resolver_function_t;
|
||||||
|
typedef std::function<hash_value_t(void* pointer)> rehasher_function_t;
|
||||||
|
|
||||||
|
// Helper function to test if a field is present, using any of the field
|
||||||
|
// enums in the generated code.
|
||||||
|
// `table` must be a generated table type. Since this is a template parameter,
|
||||||
|
// this is not typechecked to be a subclass of Table, so beware!
|
||||||
|
// Note: this function will return false for fields equal to the default
|
||||||
|
// value, since they're not stored in the buffer (unless force_defaults was
|
||||||
|
// used).
|
||||||
|
template <typename T>
|
||||||
|
bool IsFieldPresent(const T* table, typename T::FlatBuffersVTableOffset field) {
|
||||||
|
// Cast, since Table is a private baseclass of any table types.
|
||||||
|
return reinterpret_cast<const Table*>(table)->CheckField(
|
||||||
|
static_cast<voffset_t>(field));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility function for reverse lookups on the EnumNames*() functions
|
||||||
|
// (in the generated C++ code)
|
||||||
|
// names must be NULL terminated.
|
||||||
|
inline int LookupEnum(const char** names, const char* name) {
|
||||||
|
for (const char** p = names; *p; p++)
|
||||||
|
if (!strcmp(*p, name)) return static_cast<int>(p - names);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These macros allow us to layout a struct with a guarantee that they'll end
|
||||||
|
// up looking the same on different compilers and platforms.
|
||||||
|
// It does this by disallowing the compiler to do any padding, and then
|
||||||
|
// does padding itself by inserting extra padding fields that make every
|
||||||
|
// element aligned to its own size.
|
||||||
|
// Additionally, it manually sets the alignment of the struct as a whole,
|
||||||
|
// which is typically its largest element, or a custom size set in the schema
|
||||||
|
// by the force_align attribute.
|
||||||
|
// These are used in the generated code only.
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#define FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(alignment) \
|
||||||
|
__pragma(pack(1)) \
|
||||||
|
struct __declspec(align(alignment))
|
||||||
|
#define FLATBUFFERS_STRUCT_END(name, size) \
|
||||||
|
__pragma(pack()) \
|
||||||
|
static_assert(sizeof(name) == size, "compiler breaks packing rules")
|
||||||
|
#elif defined(__GNUC__) || defined(__clang__) || defined(__ICCARM__)
|
||||||
|
#define FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(alignment) \
|
||||||
|
_Pragma("pack(1)") \
|
||||||
|
struct __attribute__((aligned(alignment)))
|
||||||
|
#define FLATBUFFERS_STRUCT_END(name, size) \
|
||||||
|
_Pragma("pack()") \
|
||||||
|
static_assert(sizeof(name) == size, "compiler breaks packing rules")
|
||||||
|
#else
|
||||||
|
#error Unknown compiler, please define structure alignment macros
|
||||||
|
#endif
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// Minimal reflection via code generation.
|
||||||
|
// Besides full-fat reflection (see reflection.h) and parsing/printing by
|
||||||
|
// loading schemas (see idl.h), we can also have code generation for minimal
|
||||||
|
// reflection data which allows pretty-printing and other uses without needing
|
||||||
|
// a schema or a parser.
|
||||||
|
// Generate code with --reflect-types (types only) or --reflect-names (names
|
||||||
|
// also) to enable.
|
||||||
|
// See minireflect.h for utilities using this functionality.
|
||||||
|
|
||||||
|
// These types are organized slightly differently as the ones in idl.h.
|
||||||
|
enum SequenceType { ST_TABLE, ST_STRUCT, ST_UNION, ST_ENUM };
|
||||||
|
|
||||||
|
// Scalars have the same order as in idl.h
|
||||||
|
// clang-format off
|
||||||
|
#define FLATBUFFERS_GEN_ELEMENTARY_TYPES(ET) \
|
||||||
|
ET(ET_UTYPE) \
|
||||||
|
ET(ET_BOOL) \
|
||||||
|
ET(ET_CHAR) \
|
||||||
|
ET(ET_UCHAR) \
|
||||||
|
ET(ET_SHORT) \
|
||||||
|
ET(ET_USHORT) \
|
||||||
|
ET(ET_INT) \
|
||||||
|
ET(ET_UINT) \
|
||||||
|
ET(ET_LONG) \
|
||||||
|
ET(ET_ULONG) \
|
||||||
|
ET(ET_FLOAT) \
|
||||||
|
ET(ET_DOUBLE) \
|
||||||
|
ET(ET_STRING) \
|
||||||
|
ET(ET_SEQUENCE) // See SequenceType.
|
||||||
|
|
||||||
|
enum ElementaryType {
|
||||||
|
#define FLATBUFFERS_ET(E) E,
|
||||||
|
FLATBUFFERS_GEN_ELEMENTARY_TYPES(FLATBUFFERS_ET)
|
||||||
|
#undef FLATBUFFERS_ET
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const char * const *ElementaryTypeNames() {
|
||||||
|
static const char * const names[] = {
|
||||||
|
#define FLATBUFFERS_ET(E) #E,
|
||||||
|
FLATBUFFERS_GEN_ELEMENTARY_TYPES(FLATBUFFERS_ET)
|
||||||
|
#undef FLATBUFFERS_ET
|
||||||
|
};
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// Basic type info cost just 16bits per field!
|
||||||
|
// We're explicitly defining the signedness since the signedness of integer
|
||||||
|
// bitfields is otherwise implementation-defined and causes warnings on older
|
||||||
|
// GCC compilers.
|
||||||
|
struct TypeCode {
|
||||||
|
// ElementaryType
|
||||||
|
unsigned short base_type : 4;
|
||||||
|
// Either vector (in table) or array (in struct)
|
||||||
|
unsigned short is_repeating : 1;
|
||||||
|
// Index into type_refs below, or -1 for none.
|
||||||
|
signed short sequence_ref : 11;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(TypeCode) == 2, "TypeCode");
|
||||||
|
|
||||||
|
struct TypeTable;
|
||||||
|
|
||||||
|
// Signature of the static method present in each type.
|
||||||
|
typedef const TypeTable* (*TypeFunction)();
|
||||||
|
|
||||||
|
struct TypeTable {
|
||||||
|
SequenceType st;
|
||||||
|
size_t num_elems; // of type_codes, values, names (but not type_refs).
|
||||||
|
const TypeCode* type_codes; // num_elems count
|
||||||
|
const TypeFunction* type_refs; // less than num_elems entries (see TypeCode).
|
||||||
|
const int16_t* array_sizes; // less than num_elems entries (see TypeCode).
|
||||||
|
const int64_t* values; // Only set for non-consecutive enum/union or structs.
|
||||||
|
const char* const* names; // Only set if compiled with --reflect-names.
|
||||||
|
};
|
||||||
|
|
||||||
|
// String which identifies the current version of FlatBuffers.
|
||||||
|
inline const char* flatbuffers_version_string() {
|
||||||
|
return "FlatBuffers " FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MAJOR) "."
|
||||||
|
FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MINOR) "."
|
||||||
|
FLATBUFFERS_STRING(FLATBUFFERS_VERSION_REVISION);
|
||||||
|
}
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#define FLATBUFFERS_DEFINE_BITMASK_OPERATORS(E, T)\
|
||||||
|
inline FLATBUFFERS_CONSTEXPR_CPP11 E operator | (E lhs, E rhs){\
|
||||||
|
return E(T(lhs) | T(rhs));\
|
||||||
|
}\
|
||||||
|
inline FLATBUFFERS_CONSTEXPR_CPP11 E operator & (E lhs, E rhs){\
|
||||||
|
return E(T(lhs) & T(rhs));\
|
||||||
|
}\
|
||||||
|
inline FLATBUFFERS_CONSTEXPR_CPP11 E operator ^ (E lhs, E rhs){\
|
||||||
|
return E(T(lhs) ^ T(rhs));\
|
||||||
|
}\
|
||||||
|
inline FLATBUFFERS_CONSTEXPR_CPP11 E operator ~ (E lhs){\
|
||||||
|
return E(~T(lhs));\
|
||||||
|
}\
|
||||||
|
inline FLATBUFFERS_CONSTEXPR_CPP14 E operator |= (E &lhs, E rhs){\
|
||||||
|
lhs = lhs | rhs;\
|
||||||
|
return lhs;\
|
||||||
|
}\
|
||||||
|
inline FLATBUFFERS_CONSTEXPR_CPP14 E operator &= (E &lhs, E rhs){\
|
||||||
|
lhs = lhs & rhs;\
|
||||||
|
return lhs;\
|
||||||
|
}\
|
||||||
|
inline FLATBUFFERS_CONSTEXPR_CPP14 E operator ^= (E &lhs, E rhs){\
|
||||||
|
lhs = lhs ^ rhs;\
|
||||||
|
return lhs;\
|
||||||
|
}\
|
||||||
|
inline FLATBUFFERS_CONSTEXPR_CPP11 bool operator !(E rhs) \
|
||||||
|
{\
|
||||||
|
return !bool(T(rhs)); \
|
||||||
|
}
|
||||||
|
/// @endcond
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_H_
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_FLATC_H_
|
||||||
|
#define FLATBUFFERS_FLATC_H_
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <limits>
|
||||||
|
#include <list>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "flatbuffers/code_generator.h"
|
||||||
|
#include "flatbuffers/flatbuffers.h"
|
||||||
|
#include "flatbuffers/idl.h"
|
||||||
|
#include "flatbuffers/util.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
extern void LogCompilerWarn(const std::string& warn);
|
||||||
|
extern void LogCompilerError(const std::string& err);
|
||||||
|
|
||||||
|
struct FlatCOptions {
|
||||||
|
IDLOptions opts;
|
||||||
|
|
||||||
|
std::string program_name;
|
||||||
|
|
||||||
|
std::string output_path;
|
||||||
|
|
||||||
|
std::vector<std::string> filenames;
|
||||||
|
|
||||||
|
std::list<std::string> include_directories_storage;
|
||||||
|
std::vector<const char*> include_directories;
|
||||||
|
std::vector<const char*> conform_include_directories;
|
||||||
|
std::vector<bool> generator_enabled;
|
||||||
|
size_t binary_files_from = std::numeric_limits<size_t>::max();
|
||||||
|
std::string conform_to_schema;
|
||||||
|
std::string annotate_schema;
|
||||||
|
bool annotate_include_vector_contents = true;
|
||||||
|
bool any_generator = false;
|
||||||
|
bool print_make_rules = false;
|
||||||
|
bool raw_binary = false;
|
||||||
|
bool schema_binary = false;
|
||||||
|
bool grpc_enabled = false;
|
||||||
|
bool requires_bfbs = false;
|
||||||
|
bool file_names_only = false;
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<CodeGenerator>> generators;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FlatCOption {
|
||||||
|
std::string short_opt;
|
||||||
|
std::string long_opt;
|
||||||
|
std::string parameter;
|
||||||
|
std::string description;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FlatCompiler {
|
||||||
|
public:
|
||||||
|
typedef void (*WarnFn)(const FlatCompiler* flatc, const std::string& warn,
|
||||||
|
bool show_exe_name);
|
||||||
|
|
||||||
|
typedef void (*ErrorFn)(const FlatCompiler* flatc, const std::string& err,
|
||||||
|
bool usage, bool show_exe_name);
|
||||||
|
|
||||||
|
// Parameters required to initialize the FlatCompiler.
|
||||||
|
struct InitParams {
|
||||||
|
InitParams() : warn_fn(nullptr), error_fn(nullptr) {}
|
||||||
|
|
||||||
|
WarnFn warn_fn;
|
||||||
|
ErrorFn error_fn;
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit FlatCompiler(const InitParams& params) : params_(params) {}
|
||||||
|
|
||||||
|
bool RegisterCodeGenerator(const FlatCOption& option,
|
||||||
|
std::shared_ptr<CodeGenerator> code_generator);
|
||||||
|
|
||||||
|
int Compile(const FlatCOptions& options);
|
||||||
|
|
||||||
|
std::string GetShortUsageString(const std::string& program_name) const;
|
||||||
|
std::string GetUsageString(const std::string& program_name) const;
|
||||||
|
|
||||||
|
// Parse the FlatC options from command line arguments.
|
||||||
|
FlatCOptions ParseFromCommandLineArguments(int argc, const char** argv);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void ParseFile(flatbuffers::Parser& parser, const std::string& filename,
|
||||||
|
const std::string& contents,
|
||||||
|
const std::vector<const char*>& include_directories) const;
|
||||||
|
|
||||||
|
void LoadBinarySchema(Parser& parser, const std::string& filename,
|
||||||
|
const std::string& contents);
|
||||||
|
|
||||||
|
void Warn(const std::string& warn, bool show_exe_name = true) const;
|
||||||
|
|
||||||
|
void Error(const std::string& err, bool usage = true,
|
||||||
|
bool show_exe_name = true) const;
|
||||||
|
|
||||||
|
void AnnotateBinaries(const uint8_t* binary_schema,
|
||||||
|
uint64_t binary_schema_size,
|
||||||
|
const FlatCOptions& options);
|
||||||
|
|
||||||
|
void ValidateOptions(const FlatCOptions& options);
|
||||||
|
|
||||||
|
Parser GetConformParser(const FlatCOptions& options);
|
||||||
|
|
||||||
|
std::unique_ptr<Parser> GenerateCode(const FlatCOptions& options,
|
||||||
|
Parser& conform_parser);
|
||||||
|
|
||||||
|
std::map<std::string, std::shared_ptr<CodeGenerator>> code_generators_;
|
||||||
|
|
||||||
|
InitParams params_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_FLATC_H_
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_FLEX_FLAT_UTIL_H_
|
||||||
|
#define FLATBUFFERS_FLEX_FLAT_UTIL_H_
|
||||||
|
|
||||||
|
#include "flatbuffers/flatbuffers.h"
|
||||||
|
#include "flatbuffers/flexbuffers.h"
|
||||||
|
|
||||||
|
namespace flexbuffers {
|
||||||
|
|
||||||
|
// Verifies the `nested` flexbuffer within a flatbuffer vector is valid.
|
||||||
|
template <bool B>
|
||||||
|
inline bool VerifyNestedFlexBuffer(
|
||||||
|
const flatbuffers::Vector<uint8_t>* const nested,
|
||||||
|
flatbuffers::VerifierTemplate<B>& verifier) {
|
||||||
|
if (!nested) return true;
|
||||||
|
return verifier.Check(flexbuffers::VerifyBuffer(
|
||||||
|
nested->data(), nested->size(), verifier.GetFlexReuseTracker()));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace flexbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_FLEX_FLAT_UTIL_H_
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,303 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_GRPC_H_
|
||||||
|
#define FLATBUFFERS_GRPC_H_
|
||||||
|
|
||||||
|
// Helper functionality to glue FlatBuffers and GRPC.
|
||||||
|
|
||||||
|
#include "flatbuffers/flatbuffers.h"
|
||||||
|
#include "grpcpp/support/byte_buffer.h"
|
||||||
|
#include "grpcpp/support/slice.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
namespace grpc {
|
||||||
|
|
||||||
|
// Message is a typed wrapper around a buffer that manages the underlying
|
||||||
|
// `grpc_slice` and also provides flatbuffers-specific helpers such as `Verify`
|
||||||
|
// and `GetRoot`. Since it is backed by a `grpc_slice`, the underlying buffer
|
||||||
|
// is refcounted and ownership is be managed automatically.
|
||||||
|
template <class T>
|
||||||
|
class Message {
|
||||||
|
public:
|
||||||
|
Message() {}
|
||||||
|
|
||||||
|
Message(::grpc::Slice slice) : slice_(slice) {}
|
||||||
|
|
||||||
|
Message& operator=(const Message& other) = delete;
|
||||||
|
|
||||||
|
Message(Message&& other) = default;
|
||||||
|
|
||||||
|
Message(const Message& other) = delete;
|
||||||
|
|
||||||
|
Message& operator=(Message&& other) = default;
|
||||||
|
|
||||||
|
const uint8_t* mutable_data() const { return slice_.begin(); }
|
||||||
|
|
||||||
|
const uint8_t* data() const { return slice_.begin(); }
|
||||||
|
|
||||||
|
size_t size() const { return slice_.size(); }
|
||||||
|
|
||||||
|
bool Verify() const {
|
||||||
|
Verifier verifier(data(), size());
|
||||||
|
return verifier.VerifyBuffer<T>(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
T* GetMutableRoot() { return flatbuffers::GetMutableRoot<T>(mutable_data()); }
|
||||||
|
|
||||||
|
const T* GetRoot() const { return flatbuffers::GetRoot<T>(data()); }
|
||||||
|
|
||||||
|
// This is only intended for serializer use, or if you know what you're doing
|
||||||
|
const ::grpc::Slice& BorrowSlice() const { return slice_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
::grpc::Slice slice_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MessageBuilder;
|
||||||
|
|
||||||
|
// SliceAllocator is a gRPC-specific allocator that uses the `grpc_slice`
|
||||||
|
// refcounted slices to manage memory ownership. This makes it easy and
|
||||||
|
// efficient to transfer buffers to gRPC.
|
||||||
|
class SliceAllocator : public Allocator {
|
||||||
|
public:
|
||||||
|
SliceAllocator() {}
|
||||||
|
|
||||||
|
SliceAllocator(const SliceAllocator& other) = delete;
|
||||||
|
SliceAllocator& operator=(const SliceAllocator& other) = delete;
|
||||||
|
|
||||||
|
SliceAllocator(SliceAllocator&& other) {
|
||||||
|
// default-construct and swap idiom
|
||||||
|
swap(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
SliceAllocator& operator=(SliceAllocator&& other) {
|
||||||
|
// move-construct and swap idiom
|
||||||
|
SliceAllocator temp(std::move(other));
|
||||||
|
swap(temp);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(SliceAllocator& other) {
|
||||||
|
using std::swap;
|
||||||
|
swap(slice_, other.slice_);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~SliceAllocator() {}
|
||||||
|
|
||||||
|
virtual uint8_t* allocate(size_t size) override {
|
||||||
|
FLATBUFFERS_ASSERT(slice_.size() == 0);
|
||||||
|
slice_ = ::grpc::Slice(size);
|
||||||
|
return const_cast<uint8_t*>(slice_.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void deallocate(uint8_t* p, size_t size) override {
|
||||||
|
FLATBUFFERS_ASSERT(p == slice_.begin());
|
||||||
|
FLATBUFFERS_ASSERT(size == slice_.size());
|
||||||
|
slice_ = ::grpc::Slice();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual uint8_t* reallocate_downward(uint8_t* old_p, size_t old_size,
|
||||||
|
size_t new_size, size_t in_use_back,
|
||||||
|
size_t in_use_front) override {
|
||||||
|
FLATBUFFERS_ASSERT(old_p == slice_.begin());
|
||||||
|
FLATBUFFERS_ASSERT(old_size == slice_.size());
|
||||||
|
FLATBUFFERS_ASSERT(new_size > old_size);
|
||||||
|
::grpc::Slice old_slice = slice_;
|
||||||
|
::grpc::Slice new_slice = ::grpc::Slice(new_size);
|
||||||
|
uint8_t* new_p = const_cast<uint8_t*>(new_slice.begin());
|
||||||
|
memcpy_downward(old_p, old_size, new_p, new_size, in_use_back,
|
||||||
|
in_use_front);
|
||||||
|
slice_ = new_slice;
|
||||||
|
return const_cast<uint8_t*>(slice_.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
::grpc::Slice& get_slice(uint8_t* p, size_t size) {
|
||||||
|
FLATBUFFERS_ASSERT(p == slice_.begin());
|
||||||
|
FLATBUFFERS_ASSERT(size == slice_.size());
|
||||||
|
return slice_;
|
||||||
|
}
|
||||||
|
|
||||||
|
::grpc::Slice slice_;
|
||||||
|
|
||||||
|
friend class MessageBuilder;
|
||||||
|
};
|
||||||
|
|
||||||
|
// SliceAllocatorMember is a hack to ensure that the MessageBuilder's
|
||||||
|
// slice_allocator_ member is constructed before the FlatBufferBuilder, since
|
||||||
|
// the allocator is used in the FlatBufferBuilder ctor.
|
||||||
|
namespace detail {
|
||||||
|
struct SliceAllocatorMember {
|
||||||
|
SliceAllocator slice_allocator_;
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
// MessageBuilder is a gRPC-specific FlatBufferBuilder that uses SliceAllocator
|
||||||
|
// to allocate gRPC buffers.
|
||||||
|
class MessageBuilder : private detail::SliceAllocatorMember,
|
||||||
|
public FlatBufferBuilder {
|
||||||
|
public:
|
||||||
|
explicit MessageBuilder(uoffset_t initial_size = 1024)
|
||||||
|
: FlatBufferBuilder(initial_size, &slice_allocator_, false) {}
|
||||||
|
|
||||||
|
MessageBuilder(const MessageBuilder& other) = delete;
|
||||||
|
MessageBuilder& operator=(const MessageBuilder& other) = delete;
|
||||||
|
|
||||||
|
MessageBuilder(MessageBuilder&& other)
|
||||||
|
: FlatBufferBuilder(1024, &slice_allocator_, false) {
|
||||||
|
// Default construct and swap idiom.
|
||||||
|
Swap(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a MessageBuilder from a FlatBufferBuilder.
|
||||||
|
explicit MessageBuilder(FlatBufferBuilder&& src,
|
||||||
|
void (*dealloc)(void*,
|
||||||
|
size_t) = &DefaultAllocator::dealloc)
|
||||||
|
: FlatBufferBuilder(1024, &slice_allocator_, false) {
|
||||||
|
src.Swap(*this);
|
||||||
|
src.SwapBufAllocator(*this);
|
||||||
|
if (buf_.capacity()) {
|
||||||
|
uint8_t* buf = buf_.scratch_data(); // pointer to memory
|
||||||
|
size_t capacity = buf_.capacity(); // size of memory
|
||||||
|
slice_allocator_.slice_ = ::grpc::Slice(buf, capacity, dealloc);
|
||||||
|
} else {
|
||||||
|
slice_allocator_.slice_ = ::grpc::Slice();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Move-assign a FlatBufferBuilder to a MessageBuilder.
|
||||||
|
/// Only FlatBufferBuilder with default allocator (basically, nullptr) is
|
||||||
|
/// supported.
|
||||||
|
MessageBuilder& operator=(FlatBufferBuilder&& src) {
|
||||||
|
// Move construct a temporary and swap
|
||||||
|
MessageBuilder temp(std::move(src));
|
||||||
|
Swap(temp);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageBuilder& operator=(MessageBuilder&& other) {
|
||||||
|
// Move construct a temporary and swap
|
||||||
|
MessageBuilder temp(std::move(other));
|
||||||
|
Swap(temp);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Swap(MessageBuilder& other) {
|
||||||
|
slice_allocator_.swap(other.slice_allocator_);
|
||||||
|
FlatBufferBuilder::Swap(other);
|
||||||
|
// After swapping the FlatBufferBuilder, we swap back the allocator, which
|
||||||
|
// restores the original allocator back in place. This is necessary because
|
||||||
|
// MessageBuilder's allocator is its own member (SliceAllocatorMember). The
|
||||||
|
// allocator passed to FlatBufferBuilder::vector_downward must point to this
|
||||||
|
// member.
|
||||||
|
buf_.swap_allocator(other.buf_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Releases the ownership of the buffer pointer.
|
||||||
|
// Returns the size, offset, and the original grpc_slice that
|
||||||
|
// allocated the buffer. Also see grpc_slice_unref().
|
||||||
|
uint8_t* ReleaseRaw(size_t& size, size_t& offset, ::grpc::Slice& slice) {
|
||||||
|
uint8_t* buf = FlatBufferBuilder::ReleaseRaw(size, offset);
|
||||||
|
slice = slice_allocator_.slice_;
|
||||||
|
slice_allocator_.slice_ = ::grpc::Slice();
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
~MessageBuilder() {}
|
||||||
|
|
||||||
|
// GetMessage extracts the subslice of the buffer corresponding to the
|
||||||
|
// flatbuffers-encoded region and wraps it in a `Message<T>` to handle buffer
|
||||||
|
// ownership.
|
||||||
|
template <class T>
|
||||||
|
Message<T> GetMessage() {
|
||||||
|
auto buf_data = buf_.scratch_data(); // pointer to memory
|
||||||
|
auto buf_size = buf_.capacity(); // size of memory
|
||||||
|
auto msg_data = buf_.data(); // pointer to msg
|
||||||
|
auto msg_size = buf_.size(); // size of msg
|
||||||
|
// Do some sanity checks on data/size
|
||||||
|
FLATBUFFERS_ASSERT(msg_data);
|
||||||
|
FLATBUFFERS_ASSERT(msg_size);
|
||||||
|
FLATBUFFERS_ASSERT(msg_data >= buf_data);
|
||||||
|
FLATBUFFERS_ASSERT(msg_data + msg_size <= buf_data + buf_size);
|
||||||
|
// Calculate offsets from the buffer start
|
||||||
|
auto begin = msg_data - buf_data;
|
||||||
|
auto end = begin + msg_size;
|
||||||
|
// Get the slice we are working with (no refcount change)
|
||||||
|
::grpc::Slice slice = slice_allocator_.get_slice(buf_data, buf_size);
|
||||||
|
// Extract a subslice of the existing slice (increment refcount)
|
||||||
|
::grpc::Slice subslice = slice.sub(begin, end);
|
||||||
|
// Wrap the subslice in a `Message<T>`, but don't increment refcount
|
||||||
|
Message<T> msg(subslice);
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
Message<T> ReleaseMessage() {
|
||||||
|
Message<T> msg = GetMessage<T>();
|
||||||
|
Reset();
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// SliceAllocator slice_allocator_; // part of SliceAllocatorMember
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace grpc
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
namespace grpc {
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class SerializationTraits<flatbuffers::grpc::Message<T>> {
|
||||||
|
public:
|
||||||
|
static grpc::Status Serialize(const flatbuffers::grpc::Message<T>& msg,
|
||||||
|
ByteBuffer* buffer, bool* own_buffer) {
|
||||||
|
// Package the single slice into a `ByteBuffer`,
|
||||||
|
// incrementing the refcount in the process.
|
||||||
|
*buffer = ByteBuffer(&msg.BorrowSlice(), 1);
|
||||||
|
*own_buffer = true;
|
||||||
|
return grpc::Status::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deserialize by pulling the
|
||||||
|
static grpc::Status Deserialize(ByteBuffer* buf,
|
||||||
|
flatbuffers::grpc::Message<T>* msg) {
|
||||||
|
Slice slice;
|
||||||
|
if (!buf->TrySingleSlice(&slice).ok()) {
|
||||||
|
if (!buf->DumpToSingleSlice(&slice).ok()) {
|
||||||
|
buf->Clear();
|
||||||
|
return ::grpc::Status(::grpc::StatusCode::INTERNAL, "No payload");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*msg = flatbuffers::grpc::Message<T>(slice);
|
||||||
|
buf->Clear();
|
||||||
|
#if FLATBUFFERS_GRPC_DISABLE_AUTO_VERIFICATION
|
||||||
|
return ::grpc::Status::OK;
|
||||||
|
#else
|
||||||
|
if (msg->Verify()) {
|
||||||
|
return ::grpc::Status::OK;
|
||||||
|
} else {
|
||||||
|
return ::grpc::Status(::grpc::StatusCode::INTERNAL,
|
||||||
|
"Message verification failed");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace grpc
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_GRPC_H_
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_HASH_H_
|
||||||
|
#define FLATBUFFERS_HASH_H_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "flatbuffers/flatbuffers.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct FnvTraits {
|
||||||
|
static const T kFnvPrime;
|
||||||
|
static const T kOffsetBasis;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct FnvTraits<uint32_t> {
|
||||||
|
static const uint32_t kFnvPrime = 0x01000193;
|
||||||
|
static const uint32_t kOffsetBasis = 0x811C9DC5;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct FnvTraits<uint64_t> {
|
||||||
|
static const uint64_t kFnvPrime = 0x00000100000001b3ULL;
|
||||||
|
static const uint64_t kOffsetBasis = 0xcbf29ce484222645ULL;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T HashFnv1(const char* input) {
|
||||||
|
T hash = FnvTraits<T>::kOffsetBasis;
|
||||||
|
for (const char* c = input; *c; ++c) {
|
||||||
|
hash *= FnvTraits<T>::kFnvPrime;
|
||||||
|
hash ^= static_cast<unsigned char>(*c);
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T HashFnv1a(const char* input) {
|
||||||
|
T hash = FnvTraits<T>::kOffsetBasis;
|
||||||
|
for (const char* c = input; *c; ++c) {
|
||||||
|
hash ^= static_cast<unsigned char>(*c);
|
||||||
|
hash *= FnvTraits<T>::kFnvPrime;
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline uint16_t HashFnv1<uint16_t>(const char* input) {
|
||||||
|
uint32_t hash = HashFnv1<uint32_t>(input);
|
||||||
|
return (hash >> 16) ^ (hash & 0xffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline uint16_t HashFnv1a<uint16_t>(const char* input) {
|
||||||
|
uint32_t hash = HashFnv1a<uint32_t>(input);
|
||||||
|
return (hash >> 16) ^ (hash & 0xffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct NamedHashFunction {
|
||||||
|
const char* name;
|
||||||
|
|
||||||
|
typedef T (*HashFunction)(const char*);
|
||||||
|
HashFunction function;
|
||||||
|
};
|
||||||
|
|
||||||
|
const NamedHashFunction<uint16_t> kHashFunctions16[] = {
|
||||||
|
{"fnv1_16", HashFnv1<uint16_t>},
|
||||||
|
{"fnv1a_16", HashFnv1a<uint16_t>},
|
||||||
|
};
|
||||||
|
|
||||||
|
const NamedHashFunction<uint32_t> kHashFunctions32[] = {
|
||||||
|
{"fnv1_32", HashFnv1<uint32_t>},
|
||||||
|
{"fnv1a_32", HashFnv1a<uint32_t>},
|
||||||
|
};
|
||||||
|
|
||||||
|
const NamedHashFunction<uint64_t> kHashFunctions64[] = {
|
||||||
|
{"fnv1_64", HashFnv1<uint64_t>},
|
||||||
|
{"fnv1a_64", HashFnv1a<uint64_t>},
|
||||||
|
};
|
||||||
|
|
||||||
|
inline NamedHashFunction<uint16_t>::HashFunction FindHashFunction16(
|
||||||
|
const char* name) {
|
||||||
|
std::size_t size = sizeof(kHashFunctions16) / sizeof(kHashFunctions16[0]);
|
||||||
|
for (std::size_t i = 0; i < size; ++i) {
|
||||||
|
if (std::strcmp(name, kHashFunctions16[i].name) == 0) {
|
||||||
|
return kHashFunctions16[i].function;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline NamedHashFunction<uint32_t>::HashFunction FindHashFunction32(
|
||||||
|
const char* name) {
|
||||||
|
std::size_t size = sizeof(kHashFunctions32) / sizeof(kHashFunctions32[0]);
|
||||||
|
for (std::size_t i = 0; i < size; ++i) {
|
||||||
|
if (std::strcmp(name, kHashFunctions32[i].name) == 0) {
|
||||||
|
return kHashFunctions32[i].function;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline NamedHashFunction<uint64_t>::HashFunction FindHashFunction64(
|
||||||
|
const char* name) {
|
||||||
|
std::size_t size = sizeof(kHashFunctions64) / sizeof(kHashFunctions64[0]);
|
||||||
|
for (std::size_t i = 0; i < size; ++i) {
|
||||||
|
if (std::strcmp(name, kHashFunctions64[i].name) == 0) {
|
||||||
|
return kHashFunctions64[i].function;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_HASH_H_
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,441 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_MINIREFLECT_H_
|
||||||
|
#define FLATBUFFERS_MINIREFLECT_H_
|
||||||
|
|
||||||
|
#include "flatbuffers/flatbuffers.h"
|
||||||
|
#include "flatbuffers/util.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
// Utilities that can be used with the "mini reflection" tables present
|
||||||
|
// in generated code with --reflect-types (only types) or --reflect-names
|
||||||
|
// (also names).
|
||||||
|
// This allows basic reflection functionality such as pretty-printing
|
||||||
|
// that does not require the use of the schema parser or loading of binary
|
||||||
|
// schema files at runtime (reflection.h).
|
||||||
|
|
||||||
|
// For any of the functions below that take `const TypeTable *`, you pass
|
||||||
|
// `FooTypeTable()` if the type of the root is `Foo`.
|
||||||
|
|
||||||
|
// First, a generic iterator that can be used by multiple algorithms.
|
||||||
|
|
||||||
|
struct IterationVisitor {
|
||||||
|
// These mark the scope of a table or struct.
|
||||||
|
virtual void StartSequence() {}
|
||||||
|
virtual void EndSequence() {}
|
||||||
|
// Called for each field regardless of whether it is present or not.
|
||||||
|
// If not present, val == nullptr. set_idx is the index of all set fields.
|
||||||
|
virtual void Field(size_t /*field_idx*/, size_t /*set_idx*/,
|
||||||
|
ElementaryType /*type*/, bool /*is_vector*/,
|
||||||
|
const TypeTable* /*type_table*/, const char* /*name*/,
|
||||||
|
const uint8_t* /*val*/) {}
|
||||||
|
// Called for a value that is actually present, after a field, or as part
|
||||||
|
// of a vector.
|
||||||
|
virtual void UType(uint8_t, const char*) {}
|
||||||
|
virtual void Bool(bool) {}
|
||||||
|
virtual void Char(int8_t, const char*) {}
|
||||||
|
virtual void UChar(uint8_t, const char*) {}
|
||||||
|
virtual void Short(int16_t, const char*) {}
|
||||||
|
virtual void UShort(uint16_t, const char*) {}
|
||||||
|
virtual void Int(int32_t, const char*) {}
|
||||||
|
virtual void UInt(uint32_t, const char*) {}
|
||||||
|
virtual void Long(int64_t) {}
|
||||||
|
virtual void ULong(uint64_t) {}
|
||||||
|
virtual void Float(float) {}
|
||||||
|
virtual void Double(double) {}
|
||||||
|
virtual void String(const String*) {}
|
||||||
|
virtual void Unknown(const uint8_t*) {} // From a future version.
|
||||||
|
// These mark the scope of a vector.
|
||||||
|
virtual void StartVector() {}
|
||||||
|
virtual void EndVector() {}
|
||||||
|
virtual void Element(size_t /*i*/, ElementaryType /*type*/,
|
||||||
|
const TypeTable* /*type_table*/,
|
||||||
|
const uint8_t* /*val*/) {}
|
||||||
|
virtual ~IterationVisitor() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline size_t InlineSize(ElementaryType type, const TypeTable* type_table) {
|
||||||
|
switch (type) {
|
||||||
|
case ET_UTYPE:
|
||||||
|
case ET_BOOL:
|
||||||
|
case ET_CHAR:
|
||||||
|
case ET_UCHAR:
|
||||||
|
return 1;
|
||||||
|
case ET_SHORT:
|
||||||
|
case ET_USHORT:
|
||||||
|
return 2;
|
||||||
|
case ET_INT:
|
||||||
|
case ET_UINT:
|
||||||
|
case ET_FLOAT:
|
||||||
|
case ET_STRING:
|
||||||
|
return 4;
|
||||||
|
case ET_LONG:
|
||||||
|
case ET_ULONG:
|
||||||
|
case ET_DOUBLE:
|
||||||
|
return 8;
|
||||||
|
case ET_SEQUENCE:
|
||||||
|
switch (type_table->st) {
|
||||||
|
case ST_TABLE:
|
||||||
|
case ST_UNION:
|
||||||
|
return 4;
|
||||||
|
case ST_STRUCT:
|
||||||
|
return static_cast<size_t>(type_table->values[type_table->num_elems]);
|
||||||
|
default:
|
||||||
|
FLATBUFFERS_ASSERT(false);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
FLATBUFFERS_ASSERT(false);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int64_t LookupEnum(int64_t enum_val, const int64_t* values,
|
||||||
|
size_t num_values) {
|
||||||
|
if (!values) return enum_val;
|
||||||
|
for (size_t i = 0; i < num_values; i++) {
|
||||||
|
if (enum_val == values[i]) return static_cast<int64_t>(i);
|
||||||
|
}
|
||||||
|
return -1; // Unknown enum value.
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
const char* EnumName(T tval, const TypeTable* type_table) {
|
||||||
|
if (!type_table || !type_table->names) return nullptr;
|
||||||
|
auto i = LookupEnum(static_cast<int64_t>(tval), type_table->values,
|
||||||
|
type_table->num_elems);
|
||||||
|
if (i >= 0 && i < static_cast<int64_t>(type_table->num_elems)) {
|
||||||
|
return type_table->names[i];
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IterateObject(const uint8_t* obj, const TypeTable* type_table,
|
||||||
|
IterationVisitor* visitor);
|
||||||
|
|
||||||
|
inline void IterateValue(ElementaryType type, const uint8_t* val,
|
||||||
|
const TypeTable* type_table, const uint8_t* prev_val,
|
||||||
|
soffset_t vector_index, IterationVisitor* visitor) {
|
||||||
|
switch (type) {
|
||||||
|
case ET_UTYPE: {
|
||||||
|
auto tval = ReadScalar<uint8_t>(val);
|
||||||
|
visitor->UType(tval, EnumName(tval, type_table));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ET_BOOL: {
|
||||||
|
visitor->Bool(ReadScalar<uint8_t>(val) != 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ET_CHAR: {
|
||||||
|
auto tval = ReadScalar<int8_t>(val);
|
||||||
|
visitor->Char(tval, EnumName(tval, type_table));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ET_UCHAR: {
|
||||||
|
auto tval = ReadScalar<uint8_t>(val);
|
||||||
|
visitor->UChar(tval, EnumName(tval, type_table));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ET_SHORT: {
|
||||||
|
auto tval = ReadScalar<int16_t>(val);
|
||||||
|
visitor->Short(tval, EnumName(tval, type_table));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ET_USHORT: {
|
||||||
|
auto tval = ReadScalar<uint16_t>(val);
|
||||||
|
visitor->UShort(tval, EnumName(tval, type_table));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ET_INT: {
|
||||||
|
auto tval = ReadScalar<int32_t>(val);
|
||||||
|
visitor->Int(tval, EnumName(tval, type_table));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ET_UINT: {
|
||||||
|
auto tval = ReadScalar<uint32_t>(val);
|
||||||
|
visitor->UInt(tval, EnumName(tval, type_table));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ET_LONG: {
|
||||||
|
visitor->Long(ReadScalar<int64_t>(val));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ET_ULONG: {
|
||||||
|
visitor->ULong(ReadScalar<uint64_t>(val));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ET_FLOAT: {
|
||||||
|
visitor->Float(ReadScalar<float>(val));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ET_DOUBLE: {
|
||||||
|
visitor->Double(ReadScalar<double>(val));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ET_STRING: {
|
||||||
|
val += ReadScalar<uoffset_t>(val);
|
||||||
|
visitor->String(reinterpret_cast<const String*>(val));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ET_SEQUENCE: {
|
||||||
|
switch (type_table->st) {
|
||||||
|
case ST_TABLE:
|
||||||
|
val += ReadScalar<uoffset_t>(val);
|
||||||
|
IterateObject(val, type_table, visitor);
|
||||||
|
break;
|
||||||
|
case ST_STRUCT:
|
||||||
|
IterateObject(val, type_table, visitor);
|
||||||
|
break;
|
||||||
|
case ST_UNION: {
|
||||||
|
val += ReadScalar<uoffset_t>(val);
|
||||||
|
FLATBUFFERS_ASSERT(prev_val);
|
||||||
|
auto union_type = *prev_val; // Always a uint8_t.
|
||||||
|
if (vector_index >= 0) {
|
||||||
|
auto type_vec = reinterpret_cast<const Vector<uint8_t>*>(prev_val);
|
||||||
|
union_type = type_vec->Get(static_cast<uoffset_t>(vector_index));
|
||||||
|
}
|
||||||
|
auto type_code_idx =
|
||||||
|
LookupEnum(union_type, type_table->values, type_table->num_elems);
|
||||||
|
if (type_code_idx >= 0 &&
|
||||||
|
type_code_idx < static_cast<int32_t>(type_table->num_elems)) {
|
||||||
|
auto type_code = type_table->type_codes[type_code_idx];
|
||||||
|
switch (type_code.base_type) {
|
||||||
|
case ET_SEQUENCE: {
|
||||||
|
auto ref = type_table->type_refs[type_code.sequence_ref]();
|
||||||
|
IterateObject(val, ref, visitor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ET_STRING:
|
||||||
|
visitor->String(reinterpret_cast<const String*>(val));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
visitor->Unknown(val);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
visitor->Unknown(val);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ST_ENUM:
|
||||||
|
FLATBUFFERS_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
visitor->Unknown(val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void IterateObject(const uint8_t* obj, const TypeTable* type_table,
|
||||||
|
IterationVisitor* visitor) {
|
||||||
|
visitor->StartSequence();
|
||||||
|
const uint8_t* prev_val = nullptr;
|
||||||
|
size_t set_idx = 0;
|
||||||
|
size_t array_idx = 0;
|
||||||
|
for (size_t i = 0; i < type_table->num_elems; i++) {
|
||||||
|
auto type_code = type_table->type_codes[i];
|
||||||
|
auto type = static_cast<ElementaryType>(type_code.base_type);
|
||||||
|
auto is_repeating = type_code.is_repeating != 0;
|
||||||
|
auto ref_idx = type_code.sequence_ref;
|
||||||
|
const TypeTable* ref = nullptr;
|
||||||
|
if (ref_idx >= 0) {
|
||||||
|
ref = type_table->type_refs[ref_idx]();
|
||||||
|
}
|
||||||
|
auto name = type_table->names ? type_table->names[i] : nullptr;
|
||||||
|
const uint8_t* val = nullptr;
|
||||||
|
if (type_table->st == ST_TABLE) {
|
||||||
|
val = reinterpret_cast<const Table*>(obj)->GetAddressOf(
|
||||||
|
FieldIndexToOffset(static_cast<voffset_t>(i)));
|
||||||
|
} else {
|
||||||
|
val = obj + type_table->values[i];
|
||||||
|
}
|
||||||
|
visitor->Field(i, set_idx, type, is_repeating, ref, name, val);
|
||||||
|
if (val) {
|
||||||
|
set_idx++;
|
||||||
|
if (is_repeating) {
|
||||||
|
auto elem_ptr = val;
|
||||||
|
size_t size = 0;
|
||||||
|
if (type_table->st == ST_TABLE) {
|
||||||
|
// variable length vector
|
||||||
|
val += ReadScalar<uoffset_t>(val);
|
||||||
|
auto vec = reinterpret_cast<const Vector<uint8_t>*>(val);
|
||||||
|
elem_ptr = vec->Data();
|
||||||
|
size = vec->size();
|
||||||
|
} else {
|
||||||
|
// otherwise fixed size array
|
||||||
|
size = type_table->array_sizes[array_idx];
|
||||||
|
++array_idx;
|
||||||
|
}
|
||||||
|
visitor->StartVector();
|
||||||
|
for (size_t j = 0; j < size; j++) {
|
||||||
|
visitor->Element(j, type, ref, elem_ptr);
|
||||||
|
IterateValue(type, elem_ptr, ref, prev_val, static_cast<soffset_t>(j),
|
||||||
|
visitor);
|
||||||
|
elem_ptr += InlineSize(type, ref);
|
||||||
|
}
|
||||||
|
visitor->EndVector();
|
||||||
|
} else {
|
||||||
|
IterateValue(type, val, ref, prev_val, -1, visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev_val = val;
|
||||||
|
}
|
||||||
|
visitor->EndSequence();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void IterateFlatBuffer(const uint8_t* buffer,
|
||||||
|
const TypeTable* type_table,
|
||||||
|
IterationVisitor* callback) {
|
||||||
|
IterateObject(GetRoot<uint8_t>(buffer), type_table, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Outputting a Flatbuffer to a string. Tries to conform as close to JSON /
|
||||||
|
// the output generated by idl_gen_text.cpp.
|
||||||
|
|
||||||
|
struct ToStringVisitor : public IterationVisitor {
|
||||||
|
std::string s;
|
||||||
|
std::string d;
|
||||||
|
bool q;
|
||||||
|
std::string in;
|
||||||
|
size_t indent_level;
|
||||||
|
bool vector_delimited;
|
||||||
|
ToStringVisitor(std::string delimiter, bool quotes, std::string indent,
|
||||||
|
bool vdelimited = true)
|
||||||
|
: d(delimiter),
|
||||||
|
q(quotes),
|
||||||
|
in(indent),
|
||||||
|
indent_level(0),
|
||||||
|
vector_delimited(vdelimited) {}
|
||||||
|
ToStringVisitor(std::string delimiter)
|
||||||
|
: d(delimiter),
|
||||||
|
q(false),
|
||||||
|
in(""),
|
||||||
|
indent_level(0),
|
||||||
|
vector_delimited(true) {}
|
||||||
|
|
||||||
|
void append_indent() {
|
||||||
|
for (size_t i = 0; i < indent_level; i++) {
|
||||||
|
s += in;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartSequence() {
|
||||||
|
s += "{";
|
||||||
|
s += d;
|
||||||
|
indent_level++;
|
||||||
|
}
|
||||||
|
void EndSequence() {
|
||||||
|
s += d;
|
||||||
|
indent_level--;
|
||||||
|
append_indent();
|
||||||
|
s += "}";
|
||||||
|
}
|
||||||
|
void Field(size_t /*field_idx*/, size_t set_idx, ElementaryType /*type*/,
|
||||||
|
bool /*is_vector*/, const TypeTable* /*type_table*/,
|
||||||
|
const char* name, const uint8_t* val) {
|
||||||
|
if (!val) return;
|
||||||
|
if (set_idx) {
|
||||||
|
s += ",";
|
||||||
|
s += d;
|
||||||
|
}
|
||||||
|
append_indent();
|
||||||
|
if (name) {
|
||||||
|
if (q) s += "\"";
|
||||||
|
s += name;
|
||||||
|
if (q) s += "\"";
|
||||||
|
s += ": ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
void Named(T x, const char* name) {
|
||||||
|
if (name) {
|
||||||
|
if (q) s += "\"";
|
||||||
|
s += name;
|
||||||
|
if (q) s += "\"";
|
||||||
|
} else {
|
||||||
|
s += NumToString(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void UType(uint8_t x, const char* name) { Named(x, name); }
|
||||||
|
void Bool(bool x) { s += x ? "true" : "false"; }
|
||||||
|
void Char(int8_t x, const char* name) { Named(x, name); }
|
||||||
|
void UChar(uint8_t x, const char* name) { Named(x, name); }
|
||||||
|
void Short(int16_t x, const char* name) { Named(x, name); }
|
||||||
|
void UShort(uint16_t x, const char* name) { Named(x, name); }
|
||||||
|
void Int(int32_t x, const char* name) { Named(x, name); }
|
||||||
|
void UInt(uint32_t x, const char* name) { Named(x, name); }
|
||||||
|
void Long(int64_t x) { s += NumToString(x); }
|
||||||
|
void ULong(uint64_t x) { s += NumToString(x); }
|
||||||
|
void Float(float x) { s += NumToString(x); }
|
||||||
|
void Double(double x) { s += NumToString(x); }
|
||||||
|
void String(const struct String* str) {
|
||||||
|
EscapeString(str->c_str(), str->size(), &s, true, false);
|
||||||
|
}
|
||||||
|
void Unknown(const uint8_t*) { s += "(?)"; }
|
||||||
|
void StartVector() {
|
||||||
|
s += "[";
|
||||||
|
if (vector_delimited) {
|
||||||
|
s += d;
|
||||||
|
indent_level++;
|
||||||
|
append_indent();
|
||||||
|
} else {
|
||||||
|
s += " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void EndVector() {
|
||||||
|
if (vector_delimited) {
|
||||||
|
s += d;
|
||||||
|
indent_level--;
|
||||||
|
append_indent();
|
||||||
|
} else {
|
||||||
|
s += " ";
|
||||||
|
}
|
||||||
|
s += "]";
|
||||||
|
}
|
||||||
|
void Element(size_t i, ElementaryType /*type*/,
|
||||||
|
const TypeTable* /*type_table*/, const uint8_t* /*val*/) {
|
||||||
|
if (i) {
|
||||||
|
s += ",";
|
||||||
|
if (vector_delimited) {
|
||||||
|
s += d;
|
||||||
|
append_indent();
|
||||||
|
} else {
|
||||||
|
s += " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::string FlatBufferToString(const uint8_t* buffer,
|
||||||
|
const TypeTable* type_table,
|
||||||
|
bool multi_line = false,
|
||||||
|
bool vector_delimited = true,
|
||||||
|
const std::string& indent = "",
|
||||||
|
bool quotes = false) {
|
||||||
|
ToStringVisitor tostring_visitor(multi_line ? "\n" : " ", quotes, indent,
|
||||||
|
vector_delimited);
|
||||||
|
IterateFlatBuffer(buffer, type_table, &tostring_visitor);
|
||||||
|
return tostring_visitor.s;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_MINIREFLECT_H_
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_FLATC_PCH_H_
|
||||||
|
#define FLATBUFFERS_FLATC_PCH_H_
|
||||||
|
|
||||||
|
// stl
|
||||||
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
|
#include <functional>
|
||||||
|
#include <iostream>
|
||||||
|
#include <iterator>
|
||||||
|
#include <set>
|
||||||
|
#include <sstream>
|
||||||
|
#include <tuple>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
// flatbuffers
|
||||||
|
#include "flatbuffers/code_generators.h"
|
||||||
|
#include "flatbuffers/flatbuffers.h"
|
||||||
|
#include "flatbuffers/flexbuffers.h"
|
||||||
|
#include "flatbuffers/idl.h"
|
||||||
|
#include "flatbuffers/pch/pch.h"
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_FLATC_PCH_H_
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_PCH_H_
|
||||||
|
#define FLATBUFFERS_PCH_H_
|
||||||
|
|
||||||
|
// stl
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <limits>
|
||||||
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <stack>
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// flatbuffers
|
||||||
|
#include "flatbuffers/util.h"
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_PCH_H_
|
||||||
@@ -0,0 +1,530 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_REFLECTION_H_
|
||||||
|
#define FLATBUFFERS_REFLECTION_H_
|
||||||
|
|
||||||
|
// This is somewhat of a circular dependency because flatc (and thus this
|
||||||
|
// file) is needed to generate this header in the first place.
|
||||||
|
// Should normally not be a problem since it can be generated by the
|
||||||
|
// previous version of flatc whenever this code needs to change.
|
||||||
|
// See scripts/generate_code.py for generation.
|
||||||
|
#include "flatbuffers/reflection_generated.h"
|
||||||
|
|
||||||
|
// Helper functionality for reflection.
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
// ------------------------- GETTERS -------------------------
|
||||||
|
|
||||||
|
constexpr bool IsScalar(reflection::BaseType t) {
|
||||||
|
return t >= reflection::UType && t <= reflection::Double;
|
||||||
|
}
|
||||||
|
constexpr bool IsInteger(reflection::BaseType t) {
|
||||||
|
return t >= reflection::UType && t <= reflection::ULong;
|
||||||
|
}
|
||||||
|
constexpr bool IsFloat(reflection::BaseType t) {
|
||||||
|
return t == reflection::Float || t == reflection::Double;
|
||||||
|
}
|
||||||
|
constexpr bool IsLong(reflection::BaseType t) {
|
||||||
|
return t == reflection::Long || t == reflection::ULong;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This needs to correspond to the BaseType enum.
|
||||||
|
constexpr size_t kBaseTypeSize[] = {
|
||||||
|
0, // None
|
||||||
|
1, // UType
|
||||||
|
1, // Bool
|
||||||
|
1, // Byte
|
||||||
|
1, // UByte
|
||||||
|
2, // Short
|
||||||
|
2, // UShort
|
||||||
|
4, // Int
|
||||||
|
4, // UInt
|
||||||
|
8, // Long
|
||||||
|
8, // ULong
|
||||||
|
4, // Float
|
||||||
|
8, // Double
|
||||||
|
4, // String
|
||||||
|
4, // Vector
|
||||||
|
4, // Obj
|
||||||
|
4, // Union
|
||||||
|
0, // Array. Only used in structs. 0 was chosen to prevent out-of-bounds
|
||||||
|
// errors.
|
||||||
|
8, // Vector64
|
||||||
|
|
||||||
|
0 // MaxBaseType. This must be kept the last entry in this array.
|
||||||
|
};
|
||||||
|
static_assert(sizeof(kBaseTypeSize) / sizeof(size_t) ==
|
||||||
|
reflection::MaxBaseType + 1,
|
||||||
|
"Size of sizes[] array does not match the count of BaseType "
|
||||||
|
"enum values.");
|
||||||
|
|
||||||
|
// Size of a basic type, don't use with structs.
|
||||||
|
constexpr size_t GetTypeSize(reflection::BaseType base_type) {
|
||||||
|
return kBaseTypeSize[base_type];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same as above, but now correctly returns the size of a struct if
|
||||||
|
// the field (or vector element) is a struct.
|
||||||
|
inline size_t GetTypeSizeInline(reflection::BaseType base_type, int type_index,
|
||||||
|
const reflection::Schema& schema) {
|
||||||
|
if (base_type == reflection::Obj &&
|
||||||
|
schema.objects()->Get(type_index)->is_struct()) {
|
||||||
|
return schema.objects()->Get(type_index)->bytesize();
|
||||||
|
} else {
|
||||||
|
return GetTypeSize(base_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the root, regardless of what type it is.
|
||||||
|
inline Table* GetAnyRoot(uint8_t* const flatbuf) {
|
||||||
|
return GetMutableRoot<Table>(flatbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const Table* GetAnyRoot(const uint8_t* const flatbuf) {
|
||||||
|
return GetRoot<Table>(flatbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Table* GetAnySizePrefixedRoot(uint8_t* const flatbuf) {
|
||||||
|
return GetMutableSizePrefixedRoot<Table>(flatbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const Table* GetAnySizePrefixedRoot(const uint8_t* const flatbuf) {
|
||||||
|
return GetSizePrefixedRoot<Table>(flatbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a field's default, if you know it's an integer, and its exact type.
|
||||||
|
template <typename T>
|
||||||
|
T GetFieldDefaultI(const reflection::Field& field) {
|
||||||
|
FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type()));
|
||||||
|
return static_cast<T>(field.default_integer());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a field's default, if you know it's floating point and its exact type.
|
||||||
|
template <typename T>
|
||||||
|
T GetFieldDefaultF(const reflection::Field& field) {
|
||||||
|
FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type()));
|
||||||
|
return static_cast<T>(field.default_real());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a field, if you know it's an integer, and its exact type.
|
||||||
|
template <typename T>
|
||||||
|
T GetFieldI(const Table& table, const reflection::Field& field) {
|
||||||
|
FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type()));
|
||||||
|
return table.GetField<T>(field.offset(),
|
||||||
|
static_cast<T>(field.default_integer()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a field, if you know it's floating point and its exact type.
|
||||||
|
template <typename T>
|
||||||
|
T GetFieldF(const Table& table, const reflection::Field& field) {
|
||||||
|
FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type()));
|
||||||
|
return table.GetField<T>(field.offset(),
|
||||||
|
static_cast<T>(field.default_real()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a field, if you know it's a string.
|
||||||
|
inline const String* GetFieldS(const Table& table,
|
||||||
|
const reflection::Field& field) {
|
||||||
|
FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::String);
|
||||||
|
return table.GetPointer<const String*>(field.offset());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a field, if you know it's a vector.
|
||||||
|
template <typename T>
|
||||||
|
Vector<T>* GetFieldV(const Table& table, const reflection::Field& field) {
|
||||||
|
FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Vector &&
|
||||||
|
sizeof(T) == GetTypeSize(field.type()->element()));
|
||||||
|
return table.GetPointer<Vector<T>*>(field.offset());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a field, if you know it's a vector, generically.
|
||||||
|
// To actually access elements, use the return value together with
|
||||||
|
// field.type()->element() in any of GetAnyVectorElemI below etc.
|
||||||
|
inline VectorOfAny* GetFieldAnyV(const Table& table,
|
||||||
|
const reflection::Field& field) {
|
||||||
|
return table.GetPointer<VectorOfAny*>(field.offset());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a field, if you know it's a table.
|
||||||
|
inline Table* GetFieldT(const Table& table, const reflection::Field& field) {
|
||||||
|
FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj ||
|
||||||
|
field.type()->base_type() == reflection::Union);
|
||||||
|
return table.GetPointer<Table*>(field.offset());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a field, if you know it's a struct.
|
||||||
|
inline const Struct* GetFieldStruct(const Table& table,
|
||||||
|
const reflection::Field& field) {
|
||||||
|
// TODO: This does NOT check if the field is a table or struct, but we'd need
|
||||||
|
// access to the schema to check the is_struct flag.
|
||||||
|
FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj);
|
||||||
|
return table.GetStruct<const Struct*>(field.offset());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a structure's field, if you know it's a struct.
|
||||||
|
inline const Struct* GetFieldStruct(const Struct& structure,
|
||||||
|
const reflection::Field& field) {
|
||||||
|
FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj);
|
||||||
|
return structure.GetStruct<const Struct*>(field.offset());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raw helper functions used below: get any value in memory as a 64bit int, a
|
||||||
|
// double or a string.
|
||||||
|
// All scalars get static_cast to an int64_t, strings use strtoull, every other
|
||||||
|
// data type returns 0.
|
||||||
|
int64_t GetAnyValueI(reflection::BaseType type, const uint8_t* data);
|
||||||
|
// All scalars static cast to double, strings use strtod, every other data
|
||||||
|
// type is 0.0.
|
||||||
|
double GetAnyValueF(reflection::BaseType type, const uint8_t* data);
|
||||||
|
// All scalars converted using stringstream, strings as-is, and all other
|
||||||
|
// data types provide some level of debug-pretty-printing.
|
||||||
|
std::string GetAnyValueS(reflection::BaseType type, const uint8_t* data,
|
||||||
|
const reflection::Schema* schema, int type_index);
|
||||||
|
|
||||||
|
// Get any table field as a 64bit int, regardless of what type it is.
|
||||||
|
inline int64_t GetAnyFieldI(const Table& table,
|
||||||
|
const reflection::Field& field) {
|
||||||
|
auto field_ptr = table.GetAddressOf(field.offset());
|
||||||
|
return field_ptr ? GetAnyValueI(field.type()->base_type(), field_ptr)
|
||||||
|
: field.default_integer();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get any table field as a double, regardless of what type it is.
|
||||||
|
inline double GetAnyFieldF(const Table& table, const reflection::Field& field) {
|
||||||
|
auto field_ptr = table.GetAddressOf(field.offset());
|
||||||
|
return field_ptr ? GetAnyValueF(field.type()->base_type(), field_ptr)
|
||||||
|
: field.default_real();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get any table field as a string, regardless of what type it is.
|
||||||
|
// You may pass nullptr for the schema if you don't care to have fields that
|
||||||
|
// are of table type pretty-printed.
|
||||||
|
inline std::string GetAnyFieldS(const Table& table,
|
||||||
|
const reflection::Field& field,
|
||||||
|
const reflection::Schema* schema) {
|
||||||
|
auto field_ptr = table.GetAddressOf(field.offset());
|
||||||
|
return field_ptr ? GetAnyValueS(field.type()->base_type(), field_ptr, schema,
|
||||||
|
field.type()->index())
|
||||||
|
: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get any struct field as a 64bit int, regardless of what type it is.
|
||||||
|
inline int64_t GetAnyFieldI(const Struct& st, const reflection::Field& field) {
|
||||||
|
return GetAnyValueI(field.type()->base_type(),
|
||||||
|
st.GetAddressOf(field.offset()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get any struct field as a double, regardless of what type it is.
|
||||||
|
inline double GetAnyFieldF(const Struct& st, const reflection::Field& field) {
|
||||||
|
return GetAnyValueF(field.type()->base_type(),
|
||||||
|
st.GetAddressOf(field.offset()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get any struct field as a string, regardless of what type it is.
|
||||||
|
inline std::string GetAnyFieldS(const Struct& st,
|
||||||
|
const reflection::Field& field) {
|
||||||
|
return GetAnyValueS(field.type()->base_type(),
|
||||||
|
st.GetAddressOf(field.offset()), nullptr, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get any vector element as a 64bit int, regardless of what type it is.
|
||||||
|
inline int64_t GetAnyVectorElemI(const VectorOfAny* vec,
|
||||||
|
reflection::BaseType elem_type, size_t i) {
|
||||||
|
return GetAnyValueI(elem_type, vec->Data() + GetTypeSize(elem_type) * i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get any vector element as a double, regardless of what type it is.
|
||||||
|
inline double GetAnyVectorElemF(const VectorOfAny* vec,
|
||||||
|
reflection::BaseType elem_type, size_t i) {
|
||||||
|
return GetAnyValueF(elem_type, vec->Data() + GetTypeSize(elem_type) * i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get any vector element as a string, regardless of what type it is.
|
||||||
|
inline std::string GetAnyVectorElemS(const VectorOfAny* vec,
|
||||||
|
reflection::BaseType elem_type, size_t i) {
|
||||||
|
return GetAnyValueS(elem_type, vec->Data() + GetTypeSize(elem_type) * i,
|
||||||
|
nullptr, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a vector element that's a table/string/vector from a generic vector.
|
||||||
|
// Pass Table/String/VectorOfAny as template parameter.
|
||||||
|
// Warning: does no typechecking.
|
||||||
|
template <typename T>
|
||||||
|
T* GetAnyVectorElemPointer(const VectorOfAny* vec, size_t i) {
|
||||||
|
auto elem_ptr = vec->Data() + sizeof(uoffset_t) * i;
|
||||||
|
return reinterpret_cast<T*>(elem_ptr + ReadScalar<uoffset_t>(elem_ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the inline-address of a vector element. Useful for Structs (pass Struct
|
||||||
|
// as template arg), or being able to address a range of scalars in-line.
|
||||||
|
// Get elem_size from GetTypeSizeInline().
|
||||||
|
// Note: little-endian data on all platforms, use EndianScalar() instead of
|
||||||
|
// raw pointer access with scalars).
|
||||||
|
template <typename T>
|
||||||
|
T* GetAnyVectorElemAddressOf(const VectorOfAny* vec, size_t i,
|
||||||
|
size_t elem_size) {
|
||||||
|
return reinterpret_cast<T*>(vec->Data() + elem_size * i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Similarly, for elements of tables.
|
||||||
|
template <typename T>
|
||||||
|
T* GetAnyFieldAddressOf(const Table& table, const reflection::Field& field) {
|
||||||
|
return reinterpret_cast<T*>(table.GetAddressOf(field.offset()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Similarly, for elements of structs.
|
||||||
|
template <typename T>
|
||||||
|
T* GetAnyFieldAddressOf(const Struct& st, const reflection::Field& field) {
|
||||||
|
return reinterpret_cast<T*>(st.GetAddressOf(field.offset()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop over all the fields of the provided `object` and call `func` on each one
|
||||||
|
// in increasing order by their field->id(). If `reverse` is true, `func` is
|
||||||
|
// called in descending order
|
||||||
|
void ForAllFields(const reflection::Object* object, bool reverse,
|
||||||
|
std::function<void(const reflection::Field*)> func);
|
||||||
|
|
||||||
|
// ------------------------- SETTERS -------------------------
|
||||||
|
|
||||||
|
// Set any scalar field, if you know its exact type.
|
||||||
|
template <typename T>
|
||||||
|
bool SetField(Table* table, const reflection::Field& field, T val) {
|
||||||
|
reflection::BaseType type = field.type()->base_type();
|
||||||
|
if (!IsScalar(type)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(type));
|
||||||
|
T def;
|
||||||
|
if (IsInteger(type)) {
|
||||||
|
def = GetFieldDefaultI<T>(field);
|
||||||
|
} else {
|
||||||
|
FLATBUFFERS_ASSERT(IsFloat(type));
|
||||||
|
def = GetFieldDefaultF<T>(field);
|
||||||
|
}
|
||||||
|
return table->SetField(field.offset(), val, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raw helper functions used below: set any value in memory as a 64bit int, a
|
||||||
|
// double or a string.
|
||||||
|
// These work for all scalar values, but do nothing for other data types.
|
||||||
|
// To set a string, see SetString below.
|
||||||
|
void SetAnyValueI(reflection::BaseType type, uint8_t* data, int64_t val);
|
||||||
|
void SetAnyValueF(reflection::BaseType type, uint8_t* data, double val);
|
||||||
|
void SetAnyValueS(reflection::BaseType type, uint8_t* data, const char* val);
|
||||||
|
|
||||||
|
// Set any table field as a 64bit int, regardless of type what it is.
|
||||||
|
inline bool SetAnyFieldI(Table* table, const reflection::Field& field,
|
||||||
|
int64_t val) {
|
||||||
|
auto field_ptr = table->GetAddressOf(field.offset());
|
||||||
|
if (!field_ptr) return val == GetFieldDefaultI<int64_t>(field);
|
||||||
|
SetAnyValueI(field.type()->base_type(), field_ptr, val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set any table field as a double, regardless of what type it is.
|
||||||
|
inline bool SetAnyFieldF(Table* table, const reflection::Field& field,
|
||||||
|
double val) {
|
||||||
|
auto field_ptr = table->GetAddressOf(field.offset());
|
||||||
|
if (!field_ptr) return val == GetFieldDefaultF<double>(field);
|
||||||
|
SetAnyValueF(field.type()->base_type(), field_ptr, val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set any table field as a string, regardless of what type it is.
|
||||||
|
inline bool SetAnyFieldS(Table* table, const reflection::Field& field,
|
||||||
|
const char* val) {
|
||||||
|
auto field_ptr = table->GetAddressOf(field.offset());
|
||||||
|
if (!field_ptr) return false;
|
||||||
|
SetAnyValueS(field.type()->base_type(), field_ptr, val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set any struct field as a 64bit int, regardless of type what it is.
|
||||||
|
inline void SetAnyFieldI(Struct* st, const reflection::Field& field,
|
||||||
|
int64_t val) {
|
||||||
|
SetAnyValueI(field.type()->base_type(), st->GetAddressOf(field.offset()),
|
||||||
|
val);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set any struct field as a double, regardless of type what it is.
|
||||||
|
inline void SetAnyFieldF(Struct* st, const reflection::Field& field,
|
||||||
|
double val) {
|
||||||
|
SetAnyValueF(field.type()->base_type(), st->GetAddressOf(field.offset()),
|
||||||
|
val);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set any struct field as a string, regardless of type what it is.
|
||||||
|
inline void SetAnyFieldS(Struct* st, const reflection::Field& field,
|
||||||
|
const char* val) {
|
||||||
|
SetAnyValueS(field.type()->base_type(), st->GetAddressOf(field.offset()),
|
||||||
|
val);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set any vector element as a 64bit int, regardless of type what it is.
|
||||||
|
inline void SetAnyVectorElemI(VectorOfAny* vec, reflection::BaseType elem_type,
|
||||||
|
size_t i, int64_t val) {
|
||||||
|
SetAnyValueI(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set any vector element as a double, regardless of type what it is.
|
||||||
|
inline void SetAnyVectorElemF(VectorOfAny* vec, reflection::BaseType elem_type,
|
||||||
|
size_t i, double val) {
|
||||||
|
SetAnyValueF(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set any vector element as a string, regardless of type what it is.
|
||||||
|
inline void SetAnyVectorElemS(VectorOfAny* vec, reflection::BaseType elem_type,
|
||||||
|
size_t i, const char* val) {
|
||||||
|
SetAnyValueS(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------- RESIZING SETTERS -------------------------
|
||||||
|
|
||||||
|
// "smart" pointer for use with resizing vectors: turns a pointer inside
|
||||||
|
// a vector into a relative offset, such that it is not affected by resizes.
|
||||||
|
template <typename T, typename U>
|
||||||
|
class pointer_inside_vector {
|
||||||
|
public:
|
||||||
|
pointer_inside_vector(T* ptr, std::vector<U>& vec)
|
||||||
|
: offset_(reinterpret_cast<uint8_t*>(ptr) -
|
||||||
|
reinterpret_cast<uint8_t*>(vec.data())),
|
||||||
|
vec_(vec) {}
|
||||||
|
|
||||||
|
T* operator*() const {
|
||||||
|
return reinterpret_cast<T*>(reinterpret_cast<uint8_t*>(vec_.data()) +
|
||||||
|
offset_);
|
||||||
|
}
|
||||||
|
T* operator->() const { return operator*(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t offset_;
|
||||||
|
std::vector<U>& vec_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper to create the above easily without specifying template args.
|
||||||
|
template <typename T, typename U>
|
||||||
|
pointer_inside_vector<T, U> piv(T* ptr, std::vector<U>& vec) {
|
||||||
|
return pointer_inside_vector<T, U>(ptr, vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const char* UnionTypeFieldSuffix() { return "_type"; }
|
||||||
|
|
||||||
|
// Helper to figure out the actual table type a union refers to.
|
||||||
|
inline const reflection::Object& GetUnionType(
|
||||||
|
const reflection::Schema& schema, const reflection::Object& parent,
|
||||||
|
const reflection::Field& unionfield, const Table& table) {
|
||||||
|
auto enumdef = schema.enums()->Get(unionfield.type()->index());
|
||||||
|
// TODO: this is clumsy and slow, but no other way to find it?
|
||||||
|
auto type_field = parent.fields()->LookupByKey(
|
||||||
|
(unionfield.name()->str() + UnionTypeFieldSuffix()).c_str());
|
||||||
|
FLATBUFFERS_ASSERT(type_field);
|
||||||
|
auto union_type = GetFieldI<uint8_t>(table, *type_field);
|
||||||
|
auto enumval = enumdef->values()->LookupByKey(union_type);
|
||||||
|
return *schema.objects()->Get(enumval->union_type()->index());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Changes the contents of a string inside a FlatBuffer. FlatBuffer must
|
||||||
|
// live inside a std::vector so we can resize the buffer if needed.
|
||||||
|
// "str" must live inside "flatbuf" and may be invalidated after this call.
|
||||||
|
// If your FlatBuffer's root table is not the schema's root table, you should
|
||||||
|
// pass in your root_table type as well.
|
||||||
|
void SetString(const reflection::Schema& schema, const std::string& val,
|
||||||
|
const String* str, std::vector<uint8_t>* flatbuf,
|
||||||
|
const reflection::Object* root_table = nullptr);
|
||||||
|
|
||||||
|
// Resizes a flatbuffers::Vector inside a FlatBuffer. FlatBuffer must
|
||||||
|
// live inside a std::vector so we can resize the buffer if needed.
|
||||||
|
// "vec" must live inside "flatbuf" and may be invalidated after this call.
|
||||||
|
// If your FlatBuffer's root table is not the schema's root table, you should
|
||||||
|
// pass in your root_table type as well.
|
||||||
|
uint8_t* ResizeAnyVector(const reflection::Schema& schema, uoffset_t newsize,
|
||||||
|
const VectorOfAny* vec, uoffset_t num_elems,
|
||||||
|
uoffset_t elem_size, std::vector<uint8_t>* flatbuf,
|
||||||
|
const reflection::Object* root_table = nullptr);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void ResizeVector(const reflection::Schema& schema, uoffset_t newsize, T val,
|
||||||
|
const Vector<T>* vec, std::vector<uint8_t>* flatbuf,
|
||||||
|
const reflection::Object* root_table = nullptr) {
|
||||||
|
auto delta_elem = static_cast<int>(newsize) - static_cast<int>(vec->size());
|
||||||
|
auto newelems = ResizeAnyVector(
|
||||||
|
schema, newsize, reinterpret_cast<const VectorOfAny*>(vec), vec->size(),
|
||||||
|
static_cast<uoffset_t>(sizeof(T)), flatbuf, root_table);
|
||||||
|
// Set new elements to "val".
|
||||||
|
for (int i = 0; i < delta_elem; i++) {
|
||||||
|
auto loc = newelems + i * sizeof(T);
|
||||||
|
auto is_scalar = flatbuffers::is_scalar<T>::value;
|
||||||
|
if (is_scalar) {
|
||||||
|
WriteScalar(loc, val);
|
||||||
|
} else { // struct
|
||||||
|
*reinterpret_cast<T*>(loc) = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds any new data (in the form of a new FlatBuffer) to an existing
|
||||||
|
// FlatBuffer. This can be used when any of the above methods are not
|
||||||
|
// sufficient, in particular for adding new tables and new fields.
|
||||||
|
// This is potentially slightly less efficient than a FlatBuffer constructed
|
||||||
|
// in one piece, since the new FlatBuffer doesn't share any vtables with the
|
||||||
|
// existing one.
|
||||||
|
// The return value can now be set using Vector::MutateOffset or SetFieldT
|
||||||
|
// below.
|
||||||
|
const uint8_t* AddFlatBuffer(std::vector<uint8_t>& flatbuf,
|
||||||
|
const uint8_t* newbuf, size_t newlen);
|
||||||
|
|
||||||
|
inline bool SetFieldT(Table* table, const reflection::Field& field,
|
||||||
|
const uint8_t* val) {
|
||||||
|
FLATBUFFERS_ASSERT(sizeof(uoffset_t) ==
|
||||||
|
GetTypeSize(field.type()->base_type()));
|
||||||
|
return table->SetPointer(field.offset(), val);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------- COPYING -------------------------
|
||||||
|
|
||||||
|
// Generic copying of tables from a FlatBuffer into a FlatBuffer builder.
|
||||||
|
// Can be used to do any kind of merging/selecting you may want to do out
|
||||||
|
// of existing buffers. Also useful to reconstruct a whole buffer if the
|
||||||
|
// above resizing functionality has introduced garbage in a buffer you want
|
||||||
|
// to remove.
|
||||||
|
// Note: this does not deal with DAGs correctly. If the table passed forms a
|
||||||
|
// DAG, the copy will be a tree instead (with duplicates). Strings can be
|
||||||
|
// shared however, by passing true for use_string_pooling.
|
||||||
|
|
||||||
|
Offset<const Table*> CopyTable(FlatBufferBuilder& fbb,
|
||||||
|
const reflection::Schema& schema,
|
||||||
|
const reflection::Object& objectdef,
|
||||||
|
const Table& table,
|
||||||
|
bool use_string_pooling = false);
|
||||||
|
|
||||||
|
// Verifies the provided flatbuffer using reflection.
|
||||||
|
// root should point to the root type for this flatbuffer.
|
||||||
|
// buf should point to the start of flatbuffer data.
|
||||||
|
// length specifies the size of the flatbuffer data.
|
||||||
|
bool Verify(const reflection::Schema& schema, const reflection::Object& root,
|
||||||
|
const uint8_t* buf, size_t length, uoffset_t max_depth = 64,
|
||||||
|
uoffset_t max_tables = 1000000);
|
||||||
|
|
||||||
|
bool VerifySizePrefixed(const reflection::Schema& schema,
|
||||||
|
const reflection::Object& root, const uint8_t* buf,
|
||||||
|
size_t length, uoffset_t max_depth = 64,
|
||||||
|
uoffset_t max_tables = 1000000);
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_REFLECTION_H_
|
||||||
+1541
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_REGISTRY_H_
|
||||||
|
#define FLATBUFFERS_REGISTRY_H_
|
||||||
|
|
||||||
|
#include "flatbuffers/base.h"
|
||||||
|
#include "flatbuffers/idl.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
// Convenience class to easily parse or generate text for arbitrary FlatBuffers.
|
||||||
|
// Simply pre-populate it with all schema filenames that may be in use, and
|
||||||
|
// This class will look them up using the file_identifier declared in the
|
||||||
|
// schema.
|
||||||
|
class Registry {
|
||||||
|
public:
|
||||||
|
// Call this for all schemas that may be in use. The identifier has
|
||||||
|
// a function in the generated code, e.g. MonsterIdentifier().
|
||||||
|
void Register(const char* file_identifier, const char* schema_path) {
|
||||||
|
Schema schema;
|
||||||
|
schema.path_ = schema_path;
|
||||||
|
schemas_[file_identifier] = schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate text from an arbitrary FlatBuffer by looking up its
|
||||||
|
// file_identifier in the registry.
|
||||||
|
bool FlatBufferToText(const uint8_t* flatbuf, size_t len, std::string* dest) {
|
||||||
|
// Get the identifier out of the buffer.
|
||||||
|
// If the buffer is truncated, exit.
|
||||||
|
if (len < sizeof(uoffset_t) + kFileIdentifierLength) {
|
||||||
|
lasterror_ = "buffer truncated";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::string ident(
|
||||||
|
reinterpret_cast<const char*>(flatbuf) + sizeof(uoffset_t),
|
||||||
|
kFileIdentifierLength);
|
||||||
|
// Load and parse the schema.
|
||||||
|
Parser parser;
|
||||||
|
if (!LoadSchema(ident, &parser)) return false;
|
||||||
|
// Now we're ready to generate text.
|
||||||
|
auto err = GenText(parser, flatbuf, dest);
|
||||||
|
if (err) {
|
||||||
|
lasterror_ =
|
||||||
|
"unable to generate text for FlatBuffer binary: " + std::string(err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts a binary buffer to text using one of the schemas in the registry,
|
||||||
|
// use the file_identifier to indicate which.
|
||||||
|
// If DetachedBuffer::data() is null then parsing failed.
|
||||||
|
DetachedBuffer TextToFlatBuffer(const char* text,
|
||||||
|
const char* file_identifier) {
|
||||||
|
// Load and parse the schema.
|
||||||
|
Parser parser;
|
||||||
|
if (!LoadSchema(file_identifier, &parser)) return DetachedBuffer();
|
||||||
|
// Parse the text.
|
||||||
|
if (!parser.Parse(text)) {
|
||||||
|
lasterror_ = parser.error_;
|
||||||
|
return DetachedBuffer();
|
||||||
|
}
|
||||||
|
// We have a valid FlatBuffer. Detach it from the builder and return.
|
||||||
|
return parser.builder_.Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modify any parsing / output options used by the other functions.
|
||||||
|
void SetOptions(const IDLOptions& opts) { opts_ = opts; }
|
||||||
|
|
||||||
|
// If schemas used contain include statements, call this function for every
|
||||||
|
// directory the parser should search them for.
|
||||||
|
void AddIncludeDirectory(const char* path) { include_paths_.push_back(path); }
|
||||||
|
|
||||||
|
// Returns a human readable error if any of the above functions fail.
|
||||||
|
const std::string& GetLastError() { return lasterror_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool LoadSchema(const std::string& ident, Parser* parser) {
|
||||||
|
// Find the schema, if not, exit.
|
||||||
|
auto it = schemas_.find(ident);
|
||||||
|
if (it == schemas_.end()) {
|
||||||
|
// Don't attach the identifier, since it may not be human readable.
|
||||||
|
lasterror_ = "identifier for this buffer not in the registry";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto& schema = it->second;
|
||||||
|
// Load the schema from disk. If not, exit.
|
||||||
|
std::string schematext;
|
||||||
|
if (!LoadFile(schema.path_.c_str(), false, &schematext)) {
|
||||||
|
lasterror_ = "could not load schema: " + schema.path_;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Parse schema.
|
||||||
|
parser->opts = opts_;
|
||||||
|
if (!parser->Parse(schematext.c_str(), include_paths_.data(),
|
||||||
|
schema.path_.c_str())) {
|
||||||
|
lasterror_ = parser->error_;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Schema {
|
||||||
|
std::string path_;
|
||||||
|
// TODO(wvo) optionally cache schema file or parsed schema here.
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string lasterror_;
|
||||||
|
IDLOptions opts_;
|
||||||
|
std::vector<const char*> include_paths_;
|
||||||
|
std::map<std::string, Schema> schemas_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_REGISTRY_H_
|
||||||
@@ -0,0 +1,516 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_STL_EMULATION_H_
|
||||||
|
#define FLATBUFFERS_STL_EMULATION_H_
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#include "flatbuffers/base.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_USE_STD_OPTIONAL
|
||||||
|
// Detect C++17 compatible compiler.
|
||||||
|
// __cplusplus >= 201703L - a compiler has support of 'static inline' variables.
|
||||||
|
#if (defined(__cplusplus) && __cplusplus >= 201703L) \
|
||||||
|
|| (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
|
||||||
|
#define FLATBUFFERS_USE_STD_OPTIONAL 1
|
||||||
|
#else
|
||||||
|
#define FLATBUFFERS_USE_STD_OPTIONAL 0
|
||||||
|
#endif // (defined(__cplusplus) && __cplusplus >= 201703L) ...
|
||||||
|
#endif // FLATBUFFERS_USE_STD_OPTIONAL
|
||||||
|
|
||||||
|
#if FLATBUFFERS_USE_STD_OPTIONAL
|
||||||
|
#include <optional>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_USE_STD_SPAN
|
||||||
|
// Testing __cpp_lib_span requires including either <version> or <span>,
|
||||||
|
// both of which were added in C++20.
|
||||||
|
// See: https://en.cppreference.com/w/cpp/utility/feature_test
|
||||||
|
#if defined(__cplusplus) && __cplusplus >= 202002L \
|
||||||
|
|| (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
|
||||||
|
#if __has_include(<span>)
|
||||||
|
#define FLATBUFFERS_USE_STD_SPAN 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif // FLATBUFFERS_USE_STD_SPAN
|
||||||
|
|
||||||
|
#if defined(FLATBUFFERS_USE_STD_SPAN)
|
||||||
|
#include <array>
|
||||||
|
#include <span>
|
||||||
|
#else
|
||||||
|
// Disable non-trivial ctors if FLATBUFFERS_SPAN_MINIMAL defined.
|
||||||
|
#if !defined(FLATBUFFERS_TEMPLATES_ALIASES)
|
||||||
|
#define FLATBUFFERS_SPAN_MINIMAL
|
||||||
|
#else
|
||||||
|
// Enable implicit construction of a span<T,N> from a std::array<T,N>.
|
||||||
|
#include <array>
|
||||||
|
#endif
|
||||||
|
#endif // defined(FLATBUFFERS_USE_STD_SPAN)
|
||||||
|
|
||||||
|
// This header provides backwards compatibility for older versions of the STL.
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
#if defined(FLATBUFFERS_TEMPLATES_ALIASES)
|
||||||
|
template <typename T>
|
||||||
|
using numeric_limits = std::numeric_limits<T>;
|
||||||
|
#else
|
||||||
|
template <typename T> class numeric_limits :
|
||||||
|
public std::numeric_limits<T> {};
|
||||||
|
#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES)
|
||||||
|
|
||||||
|
#if defined(FLATBUFFERS_TEMPLATES_ALIASES)
|
||||||
|
template <typename T> using is_scalar = std::is_scalar<T>;
|
||||||
|
template <typename T, typename U> using is_same = std::is_same<T,U>;
|
||||||
|
template <typename T> using is_floating_point = std::is_floating_point<T>;
|
||||||
|
template <typename T> using is_unsigned = std::is_unsigned<T>;
|
||||||
|
template <typename T> using is_enum = std::is_enum<T>;
|
||||||
|
template <typename T> using make_unsigned = std::make_unsigned<T>;
|
||||||
|
template<bool B, class T, class F>
|
||||||
|
using conditional = std::conditional<B, T, F>;
|
||||||
|
template<class T, T v>
|
||||||
|
using integral_constant = std::integral_constant<T, v>;
|
||||||
|
template <bool B>
|
||||||
|
using bool_constant = integral_constant<bool, B>;
|
||||||
|
using true_type = std::true_type;
|
||||||
|
using false_type = std::false_type;
|
||||||
|
#else
|
||||||
|
// MSVC 2010 doesn't support C++11 aliases.
|
||||||
|
template <typename T> struct is_scalar : public std::is_scalar<T> {};
|
||||||
|
template <typename T, typename U> struct is_same : public std::is_same<T,U> {};
|
||||||
|
template <typename T> struct is_floating_point :
|
||||||
|
public std::is_floating_point<T> {};
|
||||||
|
template <typename T> struct is_unsigned : public std::is_unsigned<T> {};
|
||||||
|
template <typename T> struct is_enum : public std::is_enum<T> {};
|
||||||
|
template <typename T> struct make_unsigned : public std::make_unsigned<T> {};
|
||||||
|
template<bool B, class T, class F>
|
||||||
|
struct conditional : public std::conditional<B, T, F> {};
|
||||||
|
template<class T, T v>
|
||||||
|
struct integral_constant : public std::integral_constant<T, v> {};
|
||||||
|
template <bool B>
|
||||||
|
struct bool_constant : public integral_constant<bool, B> {};
|
||||||
|
typedef bool_constant<true> true_type;
|
||||||
|
typedef bool_constant<false> false_type;
|
||||||
|
#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES)
|
||||||
|
|
||||||
|
#if defined(FLATBUFFERS_TEMPLATES_ALIASES)
|
||||||
|
template <class T> using unique_ptr = std::unique_ptr<T>;
|
||||||
|
#else
|
||||||
|
// MSVC 2010 doesn't support C++11 aliases.
|
||||||
|
// We're manually "aliasing" the class here as we want to bring unique_ptr
|
||||||
|
// into the flatbuffers namespace. We have unique_ptr in the flatbuffers
|
||||||
|
// namespace we have a completely independent implementation (see below)
|
||||||
|
// for C++98 STL implementations.
|
||||||
|
template <class T> class unique_ptr : public std::unique_ptr<T> {
|
||||||
|
public:
|
||||||
|
unique_ptr() {}
|
||||||
|
explicit unique_ptr(T* p) : std::unique_ptr<T>(p) {}
|
||||||
|
unique_ptr(std::unique_ptr<T>&& u) { *this = std::move(u); }
|
||||||
|
unique_ptr(unique_ptr&& u) { *this = std::move(u); }
|
||||||
|
unique_ptr& operator=(std::unique_ptr<T>&& u) {
|
||||||
|
std::unique_ptr<T>::reset(u.release());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
unique_ptr& operator=(unique_ptr&& u) {
|
||||||
|
std::unique_ptr<T>::reset(u.release());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
unique_ptr& operator=(T* p) {
|
||||||
|
return std::unique_ptr<T>::operator=(p);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES)
|
||||||
|
|
||||||
|
#if FLATBUFFERS_USE_STD_OPTIONAL
|
||||||
|
template<class T>
|
||||||
|
using Optional = std::optional<T>;
|
||||||
|
using nullopt_t = std::nullopt_t;
|
||||||
|
inline constexpr nullopt_t nullopt = std::nullopt;
|
||||||
|
|
||||||
|
#else
|
||||||
|
// Limited implementation of Optional<T> type for a scalar T.
|
||||||
|
// This implementation limited by trivial types compatible with
|
||||||
|
// std::is_arithmetic<T> or std::is_enum<T> type traits.
|
||||||
|
|
||||||
|
// A tag to indicate an empty flatbuffers::optional<T>.
|
||||||
|
struct nullopt_t {
|
||||||
|
explicit FLATBUFFERS_CONSTEXPR_CPP11 nullopt_t(int) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(FLATBUFFERS_CONSTEXPR_DEFINED)
|
||||||
|
namespace internal {
|
||||||
|
template <class> struct nullopt_holder {
|
||||||
|
static constexpr nullopt_t instance_ = nullopt_t(0);
|
||||||
|
};
|
||||||
|
template<class Dummy>
|
||||||
|
constexpr nullopt_t nullopt_holder<Dummy>::instance_;
|
||||||
|
}
|
||||||
|
static constexpr const nullopt_t &nullopt = internal::nullopt_holder<void>::instance_;
|
||||||
|
|
||||||
|
#else
|
||||||
|
namespace internal {
|
||||||
|
template <class> struct nullopt_holder {
|
||||||
|
static const nullopt_t instance_;
|
||||||
|
};
|
||||||
|
template<class Dummy>
|
||||||
|
const nullopt_t nullopt_holder<Dummy>::instance_ = nullopt_t(0);
|
||||||
|
}
|
||||||
|
static const nullopt_t &nullopt = internal::nullopt_holder<void>::instance_;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
class Optional FLATBUFFERS_FINAL_CLASS {
|
||||||
|
// Non-scalar 'T' would extremely complicated Optional<T>.
|
||||||
|
// Use is_scalar<T> checking because flatbuffers flatbuffers::is_arithmetic<T>
|
||||||
|
// isn't implemented.
|
||||||
|
static_assert(flatbuffers::is_scalar<T>::value, "unexpected type T");
|
||||||
|
|
||||||
|
public:
|
||||||
|
~Optional() {}
|
||||||
|
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 Optional() FLATBUFFERS_NOEXCEPT
|
||||||
|
: value_(), has_value_(false) {}
|
||||||
|
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 Optional(nullopt_t) FLATBUFFERS_NOEXCEPT
|
||||||
|
: value_(), has_value_(false) {}
|
||||||
|
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 Optional(T val) FLATBUFFERS_NOEXCEPT
|
||||||
|
: value_(val), has_value_(true) {}
|
||||||
|
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 Optional(const Optional &other) FLATBUFFERS_NOEXCEPT
|
||||||
|
: value_(other.value_), has_value_(other.has_value_) {}
|
||||||
|
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP14 Optional &operator=(const Optional &other) FLATBUFFERS_NOEXCEPT {
|
||||||
|
value_ = other.value_;
|
||||||
|
has_value_ = other.has_value_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP14 Optional &operator=(nullopt_t) FLATBUFFERS_NOEXCEPT {
|
||||||
|
value_ = T();
|
||||||
|
has_value_ = false;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP14 Optional &operator=(T val) FLATBUFFERS_NOEXCEPT {
|
||||||
|
value_ = val;
|
||||||
|
has_value_ = true;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() FLATBUFFERS_NOEXCEPT {
|
||||||
|
*this = nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(Optional &other) FLATBUFFERS_NOEXCEPT {
|
||||||
|
std::swap(value_, other.value_);
|
||||||
|
std::swap(has_value_, other.has_value_);
|
||||||
|
}
|
||||||
|
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 FLATBUFFERS_EXPLICIT_CPP11 operator bool() const FLATBUFFERS_NOEXCEPT {
|
||||||
|
return has_value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 bool has_value() const FLATBUFFERS_NOEXCEPT {
|
||||||
|
return has_value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 const T& operator*() const FLATBUFFERS_NOEXCEPT {
|
||||||
|
return value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const T& value() const {
|
||||||
|
FLATBUFFERS_ASSERT(has_value());
|
||||||
|
return value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
T value_or(T default_value) const FLATBUFFERS_NOEXCEPT {
|
||||||
|
return has_value() ? value_ : default_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T value_;
|
||||||
|
bool has_value_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional<T>& opt, nullopt_t) FLATBUFFERS_NOEXCEPT {
|
||||||
|
return !opt;
|
||||||
|
}
|
||||||
|
template<class T>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(nullopt_t, const Optional<T>& opt) FLATBUFFERS_NOEXCEPT {
|
||||||
|
return !opt;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, class U>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional<T>& lhs, const U& rhs) FLATBUFFERS_NOEXCEPT {
|
||||||
|
return static_cast<bool>(lhs) && (*lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, class U>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const T& lhs, const Optional<U>& rhs) FLATBUFFERS_NOEXCEPT {
|
||||||
|
return static_cast<bool>(rhs) && (lhs == *rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, class U>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional<T>& lhs, const Optional<U>& rhs) FLATBUFFERS_NOEXCEPT {
|
||||||
|
return static_cast<bool>(lhs) != static_cast<bool>(rhs)
|
||||||
|
? false
|
||||||
|
: !static_cast<bool>(lhs) ? true : (*lhs == *rhs);
|
||||||
|
}
|
||||||
|
#endif // FLATBUFFERS_USE_STD_OPTIONAL
|
||||||
|
|
||||||
|
|
||||||
|
// Very limited and naive partial implementation of C++20 std::span<T,Extent>.
|
||||||
|
#if defined(FLATBUFFERS_USE_STD_SPAN)
|
||||||
|
inline constexpr std::size_t dynamic_extent = std::dynamic_extent;
|
||||||
|
template<class T, std::size_t Extent = std::dynamic_extent>
|
||||||
|
using span = std::span<T, Extent>;
|
||||||
|
|
||||||
|
#else // !defined(FLATBUFFERS_USE_STD_SPAN)
|
||||||
|
FLATBUFFERS_CONSTEXPR std::size_t dynamic_extent = static_cast<std::size_t>(-1);
|
||||||
|
|
||||||
|
// Exclude this code if MSVC2010 or non-STL Android is active.
|
||||||
|
// The non-STL Android doesn't have `std::is_convertible` required for SFINAE.
|
||||||
|
#if !defined(FLATBUFFERS_SPAN_MINIMAL)
|
||||||
|
namespace internal {
|
||||||
|
// This is SFINAE helper class for checking of a common condition:
|
||||||
|
// > This overload only participates in overload resolution
|
||||||
|
// > Check whether a pointer to an array of From can be converted
|
||||||
|
// > to a pointer to an array of To.
|
||||||
|
// This helper is used for checking of 'From -> const From'.
|
||||||
|
template<class To, std::size_t Extent, class From, std::size_t N>
|
||||||
|
struct is_span_convertible {
|
||||||
|
using type =
|
||||||
|
typename std::conditional<std::is_convertible<From (*)[], To (*)[]>::value
|
||||||
|
&& (Extent == dynamic_extent || N == Extent),
|
||||||
|
int, void>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct SpanIterator {
|
||||||
|
// TODO: upgrade to std::random_access_iterator_tag.
|
||||||
|
using iterator_category = std::forward_iterator_tag;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using value_type = typename std::remove_cv<T>::type;
|
||||||
|
using reference = T&;
|
||||||
|
using pointer = T*;
|
||||||
|
|
||||||
|
// Convince MSVC compiler that this iterator is trusted (it is verified).
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
using _Unchecked_type = pointer;
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
SpanIterator(pointer ptr) : ptr_(ptr) {}
|
||||||
|
reference operator*() const { return *ptr_; }
|
||||||
|
pointer operator->() { return ptr_; }
|
||||||
|
SpanIterator& operator++() { ptr_++; return *this; }
|
||||||
|
SpanIterator operator++(int) { auto tmp = *this; ++(*this); return tmp; }
|
||||||
|
|
||||||
|
friend bool operator== (const SpanIterator& lhs, const SpanIterator& rhs) { return lhs.ptr_ == rhs.ptr_; }
|
||||||
|
friend bool operator!= (const SpanIterator& lhs, const SpanIterator& rhs) { return lhs.ptr_ != rhs.ptr_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
pointer ptr_;
|
||||||
|
};
|
||||||
|
} // namespace internal
|
||||||
|
#endif // !defined(FLATBUFFERS_SPAN_MINIMAL)
|
||||||
|
|
||||||
|
// T - element type; must be a complete type that is not an abstract
|
||||||
|
// class type.
|
||||||
|
// Extent - the number of elements in the sequence, or dynamic.
|
||||||
|
template<class T, std::size_t Extent = dynamic_extent>
|
||||||
|
class span FLATBUFFERS_FINAL_CLASS {
|
||||||
|
public:
|
||||||
|
typedef T element_type;
|
||||||
|
typedef T& reference;
|
||||||
|
typedef const T& const_reference;
|
||||||
|
typedef T* pointer;
|
||||||
|
typedef const T* const_pointer;
|
||||||
|
typedef std::size_t size_type;
|
||||||
|
|
||||||
|
static FLATBUFFERS_CONSTEXPR size_type extent = Extent;
|
||||||
|
|
||||||
|
// Returns the number of elements in the span.
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 size_type size() const FLATBUFFERS_NOEXCEPT {
|
||||||
|
return count_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the size of the sequence in bytes.
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11
|
||||||
|
size_type size_bytes() const FLATBUFFERS_NOEXCEPT {
|
||||||
|
return size() * sizeof(element_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks if the span is empty.
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 bool empty() const FLATBUFFERS_NOEXCEPT {
|
||||||
|
return size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a pointer to the beginning of the sequence.
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 pointer data() const FLATBUFFERS_NOEXCEPT {
|
||||||
|
return data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(FLATBUFFERS_SPAN_MINIMAL)
|
||||||
|
using Iterator = internal::SpanIterator<T>;
|
||||||
|
|
||||||
|
Iterator begin() const { return Iterator(data()); }
|
||||||
|
Iterator end() const { return Iterator(data() + size()); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Returns a reference to the idx-th element of the sequence.
|
||||||
|
// The behavior is undefined if the idx is greater than or equal to size().
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 reference operator[](size_type idx) const {
|
||||||
|
return data()[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 span(const span &other) FLATBUFFERS_NOEXCEPT
|
||||||
|
: data_(other.data_), count_(other.count_) {}
|
||||||
|
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP14 span &operator=(const span &other)
|
||||||
|
FLATBUFFERS_NOEXCEPT {
|
||||||
|
data_ = other.data_;
|
||||||
|
count_ = other.count_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limited implementation of
|
||||||
|
// `template <class It> constexpr std::span(It first, size_type count);`.
|
||||||
|
//
|
||||||
|
// Constructs a span that is a view over the range [first, first + count);
|
||||||
|
// the resulting span has: data() == first and size() == count.
|
||||||
|
// The behavior is undefined if [first, first + count) is not a valid range,
|
||||||
|
// or if (extent != flatbuffers::dynamic_extent && count != extent).
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11
|
||||||
|
explicit span(pointer first, size_type count) FLATBUFFERS_NOEXCEPT
|
||||||
|
: data_ (Extent == dynamic_extent ? first : (Extent == count ? first : nullptr)),
|
||||||
|
count_(Extent == dynamic_extent ? count : (Extent == count ? Extent : 0)) {
|
||||||
|
// Make span empty if the count argument is incompatible with span<T,N>.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclude this code if MSVC2010 is active. The MSVC2010 isn't C++11
|
||||||
|
// compliant, it doesn't support default template arguments for functions.
|
||||||
|
#if defined(FLATBUFFERS_SPAN_MINIMAL)
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 span() FLATBUFFERS_NOEXCEPT : data_(nullptr),
|
||||||
|
count_(0) {
|
||||||
|
static_assert(extent == 0 || extent == dynamic_extent, "invalid span");
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
// Constructs an empty span whose data() == nullptr and size() == 0.
|
||||||
|
// This overload only participates in overload resolution if
|
||||||
|
// extent == 0 || extent == flatbuffers::dynamic_extent.
|
||||||
|
// A dummy template argument N is need dependency for SFINAE.
|
||||||
|
template<std::size_t N = 0,
|
||||||
|
typename internal::is_span_convertible<element_type, Extent, element_type, (N - N)>::type = 0>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 span() FLATBUFFERS_NOEXCEPT : data_(nullptr),
|
||||||
|
count_(0) {
|
||||||
|
static_assert(extent == 0 || extent == dynamic_extent, "invalid span");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructs a span that is a view over the array arr; the resulting span
|
||||||
|
// has size() == N and data() == std::data(arr). These overloads only
|
||||||
|
// participate in overload resolution if
|
||||||
|
// extent == std::dynamic_extent || N == extent is true and
|
||||||
|
// std::remove_pointer_t<decltype(std::data(arr))>(*)[]
|
||||||
|
// is convertible to element_type (*)[].
|
||||||
|
template<std::size_t N,
|
||||||
|
typename internal::is_span_convertible<element_type, Extent, element_type, N>::type = 0>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 span(element_type (&arr)[N]) FLATBUFFERS_NOEXCEPT
|
||||||
|
: data_(arr), count_(N) {}
|
||||||
|
|
||||||
|
template<class U, std::size_t N,
|
||||||
|
typename internal::is_span_convertible<element_type, Extent, U, N>::type = 0>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 span(std::array<U, N> &arr) FLATBUFFERS_NOEXCEPT
|
||||||
|
: data_(arr.data()), count_(N) {}
|
||||||
|
|
||||||
|
//template<class U, std::size_t N,
|
||||||
|
// int = 0>
|
||||||
|
//FLATBUFFERS_CONSTEXPR_CPP11 span(std::array<U, N> &arr) FLATBUFFERS_NOEXCEPT
|
||||||
|
// : data_(arr.data()), count_(N) {}
|
||||||
|
|
||||||
|
template<class U, std::size_t N,
|
||||||
|
typename internal::is_span_convertible<element_type, Extent, U, N>::type = 0>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 span(const std::array<U, N> &arr) FLATBUFFERS_NOEXCEPT
|
||||||
|
: data_(arr.data()), count_(N) {}
|
||||||
|
|
||||||
|
// Converting constructor from another span s;
|
||||||
|
// the resulting span has size() == s.size() and data() == s.data().
|
||||||
|
// This overload only participates in overload resolution
|
||||||
|
// if extent == std::dynamic_extent || N == extent is true and U (*)[]
|
||||||
|
// is convertible to element_type (*)[].
|
||||||
|
template<class U, std::size_t N,
|
||||||
|
typename internal::is_span_convertible<element_type, Extent, U, N>::type = 0>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 span(const flatbuffers::span<U, N> &s) FLATBUFFERS_NOEXCEPT
|
||||||
|
: span(s.data(), s.size()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // !defined(FLATBUFFERS_SPAN_MINIMAL)
|
||||||
|
|
||||||
|
private:
|
||||||
|
// This is a naive implementation with 'count_' member even if (Extent != dynamic_extent).
|
||||||
|
pointer const data_;
|
||||||
|
size_type count_;
|
||||||
|
};
|
||||||
|
#endif // defined(FLATBUFFERS_USE_STD_SPAN)
|
||||||
|
|
||||||
|
#if !defined(FLATBUFFERS_SPAN_MINIMAL)
|
||||||
|
template<class ElementType, std::size_t Extent>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11
|
||||||
|
flatbuffers::span<ElementType, Extent> make_span(ElementType(&arr)[Extent]) FLATBUFFERS_NOEXCEPT {
|
||||||
|
return span<ElementType, Extent>(arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ElementType, std::size_t Extent>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11
|
||||||
|
flatbuffers::span<const ElementType, Extent> make_span(const ElementType(&arr)[Extent]) FLATBUFFERS_NOEXCEPT {
|
||||||
|
return span<const ElementType, Extent>(arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ElementType, std::size_t Extent>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11
|
||||||
|
flatbuffers::span<ElementType, Extent> make_span(std::array<ElementType, Extent> &arr) FLATBUFFERS_NOEXCEPT {
|
||||||
|
return span<ElementType, Extent>(arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ElementType, std::size_t Extent>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11
|
||||||
|
flatbuffers::span<const ElementType, Extent> make_span(const std::array<ElementType, Extent> &arr) FLATBUFFERS_NOEXCEPT {
|
||||||
|
return span<const ElementType, Extent>(arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ElementType, std::size_t Extent>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11
|
||||||
|
flatbuffers::span<ElementType, dynamic_extent> make_span(ElementType *first, std::size_t count) FLATBUFFERS_NOEXCEPT {
|
||||||
|
return span<ElementType, dynamic_extent>(first, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ElementType, std::size_t Extent>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11
|
||||||
|
flatbuffers::span<const ElementType, dynamic_extent> make_span(const ElementType *first, std::size_t count) FLATBUFFERS_NOEXCEPT {
|
||||||
|
return span<const ElementType, dynamic_extent>(first, count);
|
||||||
|
}
|
||||||
|
#endif // !defined(FLATBUFFERS_SPAN_MINIMAL)
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_STL_EMULATION_H_
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_STRING_H_
|
||||||
|
#define FLATBUFFERS_STRING_H_
|
||||||
|
|
||||||
|
#include "flatbuffers/base.h"
|
||||||
|
#include "flatbuffers/vector.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
struct String : public Vector<char> {
|
||||||
|
const char* c_str() const { return reinterpret_cast<const char*>(Data()); }
|
||||||
|
std::string str() const { return std::string(c_str(), size()); }
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#ifdef FLATBUFFERS_HAS_STRING_VIEW
|
||||||
|
flatbuffers::string_view string_view() const {
|
||||||
|
return flatbuffers::string_view(c_str(), size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* implicit */
|
||||||
|
operator flatbuffers::string_view() const {
|
||||||
|
return flatbuffers::string_view(c_str(), size());
|
||||||
|
}
|
||||||
|
#endif // FLATBUFFERS_HAS_STRING_VIEW
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
bool operator<(const String& o) const {
|
||||||
|
return StringLessThan(this->data(), this->size(), o.data(), o.size());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convenience function to get std::string from a String returning an empty
|
||||||
|
// string on null pointer.
|
||||||
|
static inline std::string GetString(const String* str) {
|
||||||
|
return str ? str->str() : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convenience function to get char* from a String returning an empty string on
|
||||||
|
// null pointer.
|
||||||
|
static inline const char* GetCstring(const String* str) {
|
||||||
|
return str ? str->c_str() : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef FLATBUFFERS_HAS_STRING_VIEW
|
||||||
|
// Convenience function to get string_view from a String returning an empty
|
||||||
|
// string_view on null pointer.
|
||||||
|
static inline flatbuffers::string_view GetStringView(const String* str) {
|
||||||
|
return str ? str->string_view() : flatbuffers::string_view();
|
||||||
|
}
|
||||||
|
#endif // FLATBUFFERS_HAS_STRING_VIEW
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_STRING_H_
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_STRUCT_H_
|
||||||
|
#define FLATBUFFERS_STRUCT_H_
|
||||||
|
|
||||||
|
#include "flatbuffers/base.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
// "structs" are flat structures that do not have an offset table, thus
|
||||||
|
// always have all members present and do not support forwards/backwards
|
||||||
|
// compatible extensions.
|
||||||
|
|
||||||
|
class Struct FLATBUFFERS_FINAL_CLASS {
|
||||||
|
public:
|
||||||
|
template <typename T>
|
||||||
|
T GetField(uoffset_t o) const {
|
||||||
|
return ReadScalar<T>(&data_[o]);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T GetStruct(uoffset_t o) const {
|
||||||
|
return reinterpret_cast<T>(&data_[o]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* GetAddressOf(uoffset_t o) const { return &data_[o]; }
|
||||||
|
uint8_t* GetAddressOf(uoffset_t o) { return &data_[o]; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// private constructor & copy constructor: you obtain instances of this
|
||||||
|
// class by pointing to existing data only
|
||||||
|
Struct();
|
||||||
|
Struct(const Struct&);
|
||||||
|
Struct& operator=(const Struct&);
|
||||||
|
|
||||||
|
uint8_t data_[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_STRUCT_H_
|
||||||
@@ -0,0 +1,263 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_TABLE_H_
|
||||||
|
#define FLATBUFFERS_TABLE_H_
|
||||||
|
|
||||||
|
#include "flatbuffers/base.h"
|
||||||
|
#include "flatbuffers/vector.h"
|
||||||
|
#include "flatbuffers/verifier.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
// "tables" use an offset table (possibly shared) that allows fields to be
|
||||||
|
// omitted and added at will, but uses an extra indirection to read.
|
||||||
|
class Table {
|
||||||
|
public:
|
||||||
|
const uint8_t* GetVTable() const {
|
||||||
|
return data_ - ReadScalar<soffset_t>(data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This gets the field offset for any of the functions below it, or 0
|
||||||
|
// if the field was not present.
|
||||||
|
voffset_t GetOptionalFieldOffset(voffset_t field) const {
|
||||||
|
// The vtable offset is always at the start.
|
||||||
|
auto vtable = GetVTable();
|
||||||
|
// The first element is the size of the vtable (fields + type id + itself).
|
||||||
|
auto vtsize = ReadScalar<voffset_t>(vtable);
|
||||||
|
// If the field we're accessing is outside the vtable, we're reading older
|
||||||
|
// data, so it's the same as if the offset was 0 (not present).
|
||||||
|
return field < vtsize ? ReadScalar<voffset_t>(vtable + field) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T GetField(voffset_t field, T defaultval) const {
|
||||||
|
auto field_offset = GetOptionalFieldOffset(field);
|
||||||
|
return field_offset ? ReadScalar<T>(data_ + field_offset) : defaultval;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P, typename OffsetSize = uoffset_t>
|
||||||
|
P GetPointer(voffset_t field) {
|
||||||
|
auto field_offset = GetOptionalFieldOffset(field);
|
||||||
|
auto p = data_ + field_offset;
|
||||||
|
return field_offset ? reinterpret_cast<P>(p + ReadScalar<OffsetSize>(p))
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
template <typename P, typename OffsetSize = uoffset_t>
|
||||||
|
P GetPointer(voffset_t field) const {
|
||||||
|
return const_cast<Table*>(this)->GetPointer<P, OffsetSize>(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P>
|
||||||
|
P GetPointer64(voffset_t field) {
|
||||||
|
return GetPointer<P, uoffset64_t>(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P>
|
||||||
|
P GetPointer64(voffset_t field) const {
|
||||||
|
return GetPointer<P, uoffset64_t>(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P, typename SizeT = uoffset_t,
|
||||||
|
typename OffsetSize = uoffset_t>
|
||||||
|
const Vector<P, SizeT>* GetVectorPointerOrEmpty(voffset_t field) const {
|
||||||
|
auto* ptr = GetPointer<const Vector<P, SizeT>*, OffsetSize>(field);
|
||||||
|
return ptr ? ptr : EmptyVector<P, SizeT>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P, typename SizeT = uoffset_t>
|
||||||
|
const Vector<P, SizeT>* GetVectorPointer64OrEmpty(voffset_t field) const {
|
||||||
|
return GetVectorPointerOrEmpty<P, SizeT, uoffset64_t>(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P, typename SizeT = uoffset_t,
|
||||||
|
typename OffsetSize = uoffset_t>
|
||||||
|
Vector<P, SizeT>* GetMutableVectorPointerOrEmpty(voffset_t field) {
|
||||||
|
auto* ptr = GetPointer<Vector<P, SizeT>*, OffsetSize>(field);
|
||||||
|
// This is a const_cast, but safe, since all mutable operations on an
|
||||||
|
// empty vector are NOPs.
|
||||||
|
return ptr ? ptr : const_cast<Vector<P, SizeT>*>(EmptyVector<P, SizeT>());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P, typename SizeT = uoffset_t>
|
||||||
|
Vector<P, SizeT>* GetMutableVectorPointer64OrEmpty(voffset_t field) {
|
||||||
|
return GetMutableVectorPointerOrEmpty<P, SizeT, uoffset64_t>(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P>
|
||||||
|
P GetStruct(voffset_t field) const {
|
||||||
|
auto field_offset = GetOptionalFieldOffset(field);
|
||||||
|
auto p = const_cast<uint8_t*>(data_ + field_offset);
|
||||||
|
return field_offset ? reinterpret_cast<P>(p) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Raw, typename Face>
|
||||||
|
flatbuffers::Optional<Face> GetOptional(voffset_t field) const {
|
||||||
|
auto field_offset = GetOptionalFieldOffset(field);
|
||||||
|
auto p = data_ + field_offset;
|
||||||
|
return field_offset ? Optional<Face>(static_cast<Face>(ReadScalar<Raw>(p)))
|
||||||
|
: Optional<Face>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool SetField(voffset_t field, T val, T def) {
|
||||||
|
auto field_offset = GetOptionalFieldOffset(field);
|
||||||
|
if (!field_offset) return IsTheSameAs(val, def);
|
||||||
|
WriteScalar(data_ + field_offset, val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
bool SetField(voffset_t field, T val) {
|
||||||
|
auto field_offset = GetOptionalFieldOffset(field);
|
||||||
|
if (!field_offset) return false;
|
||||||
|
WriteScalar(data_ + field_offset, val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SetPointer(voffset_t field, const uint8_t* val) {
|
||||||
|
auto field_offset = GetOptionalFieldOffset(field);
|
||||||
|
if (!field_offset) return false;
|
||||||
|
WriteScalar(data_ + field_offset,
|
||||||
|
static_cast<uoffset_t>(val - (data_ + field_offset)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* GetAddressOf(voffset_t field) {
|
||||||
|
auto field_offset = GetOptionalFieldOffset(field);
|
||||||
|
return field_offset ? data_ + field_offset : nullptr;
|
||||||
|
}
|
||||||
|
const uint8_t* GetAddressOf(voffset_t field) const {
|
||||||
|
return const_cast<Table*>(this)->GetAddressOf(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckField(voffset_t field) const {
|
||||||
|
return GetOptionalFieldOffset(field) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the vtable of this table.
|
||||||
|
// Call this once per table, followed by VerifyField once per field.
|
||||||
|
template <bool B>
|
||||||
|
bool VerifyTableStart(VerifierTemplate<B>& verifier) const {
|
||||||
|
return verifier.VerifyTableStart(data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify a particular field.
|
||||||
|
template <typename T, bool B>
|
||||||
|
bool VerifyField(const VerifierTemplate<B>& verifier, voffset_t field,
|
||||||
|
size_t align) const {
|
||||||
|
// Calling GetOptionalFieldOffset should be safe now thanks to
|
||||||
|
// VerifyTable().
|
||||||
|
auto field_offset = GetOptionalFieldOffset(field);
|
||||||
|
// Check the actual field.
|
||||||
|
return !field_offset ||
|
||||||
|
verifier.template VerifyField<T>(data_, field_offset, align);
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyField for required fields.
|
||||||
|
template <typename T, bool B>
|
||||||
|
bool VerifyFieldRequired(const VerifierTemplate<B>& verifier, voffset_t field,
|
||||||
|
size_t align) const {
|
||||||
|
auto field_offset = GetOptionalFieldOffset(field);
|
||||||
|
return verifier.Check(field_offset != 0) &&
|
||||||
|
verifier.template VerifyField<T>(data_, field_offset, align);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Versions for offsets.
|
||||||
|
template <typename OffsetT = uoffset_t, bool B = false>
|
||||||
|
bool VerifyOffset(const VerifierTemplate<B>& verifier,
|
||||||
|
voffset_t field) const {
|
||||||
|
auto field_offset = GetOptionalFieldOffset(field);
|
||||||
|
return !field_offset ||
|
||||||
|
verifier.template VerifyOffset<OffsetT>(data_, field_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OffsetT = uoffset_t, bool B = false>
|
||||||
|
bool VerifyOffsetRequired(const VerifierTemplate<B>& verifier,
|
||||||
|
voffset_t field) const {
|
||||||
|
auto field_offset = GetOptionalFieldOffset(field);
|
||||||
|
return verifier.Check(field_offset != 0) &&
|
||||||
|
verifier.template VerifyOffset<OffsetT>(data_, field_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool B>
|
||||||
|
bool VerifyOffset64(const VerifierTemplate<B>& verifier,
|
||||||
|
voffset_t field) const {
|
||||||
|
return VerifyOffset<uoffset64_t>(verifier, field);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool B>
|
||||||
|
bool VerifyOffset64Required(const VerifierTemplate<B>& verifier,
|
||||||
|
voffset_t field) const {
|
||||||
|
return VerifyOffsetRequired<uoffset64_t>(verifier, field);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify a string that may have a default value.
|
||||||
|
template <typename OffsetT = uoffset_t>
|
||||||
|
bool VerifyStringWithDefault(const Verifier& verifier,
|
||||||
|
voffset_t field) const {
|
||||||
|
auto field_offset = GetOptionalFieldOffset(field);
|
||||||
|
return field_offset == 0 ||
|
||||||
|
verifier.VerifyString(GetPointer<const String*, OffsetT>(field));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify a vector that has a default empty value.
|
||||||
|
template <typename P, typename SizeT = uoffset_t,
|
||||||
|
typename OffsetSize = uoffset_t>
|
||||||
|
bool VerifyVectorWithDefault(const Verifier& verifier,
|
||||||
|
voffset_t field) const {
|
||||||
|
auto field_offset = GetOptionalFieldOffset(field);
|
||||||
|
return field_offset == 0 ||
|
||||||
|
verifier.VerifyVector(
|
||||||
|
GetPointer<const Vector<P, SizeT>*, OffsetSize>(field));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P, typename SizeT = uoffset_t>
|
||||||
|
bool VerifyVector64WithDefault(const Verifier& verifier,
|
||||||
|
voffset_t field) const {
|
||||||
|
return VerifyVectorWithDefault<P, SizeT, uoffset64_t>(verifier, field);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
template <typename T, typename SizeT = uoffset_t>
|
||||||
|
static const Vector<T, SizeT>* EmptyVector() {
|
||||||
|
static const SizeT empty_vector_length = 0;
|
||||||
|
return reinterpret_cast<const Vector<T, SizeT>*>(&empty_vector_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// private constructor & copy constructor: you obtain instances of this
|
||||||
|
// class by pointing to existing data only
|
||||||
|
Table();
|
||||||
|
Table(const Table& other);
|
||||||
|
Table& operator=(const Table&);
|
||||||
|
|
||||||
|
uint8_t data_[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
// This specialization allows avoiding warnings like:
|
||||||
|
// MSVC C4800: type: forcing value to bool 'true' or 'false'.
|
||||||
|
template <>
|
||||||
|
inline flatbuffers::Optional<bool> Table::GetOptional<uint8_t, bool>(
|
||||||
|
voffset_t field) const {
|
||||||
|
auto field_offset = GetOptionalFieldOffset(field);
|
||||||
|
auto p = data_ + field_offset;
|
||||||
|
return field_offset ? Optional<bool>(ReadScalar<uint8_t>(p) != 0)
|
||||||
|
: Optional<bool>();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_TABLE_H_
|
||||||
@@ -0,0 +1,781 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_UTIL_H_
|
||||||
|
#define FLATBUFFERS_UTIL_H_
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "flatbuffers/base.h"
|
||||||
|
#include "flatbuffers/stl_emulation.h"
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_PREFER_PRINTF
|
||||||
|
#include <iomanip>
|
||||||
|
#include <sstream>
|
||||||
|
#else // FLATBUFFERS_PREFER_PRINTF
|
||||||
|
#include <float.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif // FLATBUFFERS_PREFER_PRINTF
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <limits>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
// @locale-independent functions for ASCII characters set.
|
||||||
|
|
||||||
|
// Fast checking that character lies in closed range: [a <= x <= b]
|
||||||
|
// using one compare (conditional branch) operator.
|
||||||
|
inline bool check_ascii_range(char x, char a, char b) {
|
||||||
|
FLATBUFFERS_ASSERT(a <= b);
|
||||||
|
// (Hacker's Delight): `a <= x <= b` <=> `(x-a) <={u} (b-a)`.
|
||||||
|
// The x, a, b will be promoted to int and subtracted without overflow.
|
||||||
|
return static_cast<unsigned int>(x - a) <= static_cast<unsigned int>(b - a);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case-insensitive isalpha
|
||||||
|
inline bool is_alpha(char c) {
|
||||||
|
// ASCII only: alpha to upper case => reset bit 0x20 (~0x20 = 0xDF).
|
||||||
|
return check_ascii_range(c & 0xDF, 'a' & 0xDF, 'z' & 0xDF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for uppercase alpha
|
||||||
|
inline bool is_alpha_upper(char c) { return check_ascii_range(c, 'A', 'Z'); }
|
||||||
|
|
||||||
|
// Check (case-insensitive) that `c` is equal to alpha.
|
||||||
|
inline bool is_alpha_char(char c, char alpha) {
|
||||||
|
FLATBUFFERS_ASSERT(is_alpha(alpha));
|
||||||
|
// ASCII only: alpha to upper case => reset bit 0x20 (~0x20 = 0xDF).
|
||||||
|
return ((c & 0xDF) == (alpha & 0xDF));
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://en.cppreference.com/w/cpp/string/byte/isxdigit
|
||||||
|
// isdigit and isxdigit are the only standard narrow character classification
|
||||||
|
// functions that are not affected by the currently installed C locale. although
|
||||||
|
// some implementations (e.g. Microsoft in 1252 codepage) may classify
|
||||||
|
// additional single-byte characters as digits.
|
||||||
|
inline bool is_digit(char c) { return check_ascii_range(c, '0', '9'); }
|
||||||
|
|
||||||
|
inline bool is_xdigit(char c) {
|
||||||
|
// Replace by look-up table.
|
||||||
|
return is_digit(c) || check_ascii_range(c & 0xDF, 'a' & 0xDF, 'f' & 0xDF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case-insensitive isalnum
|
||||||
|
inline bool is_alnum(char c) { return is_alpha(c) || is_digit(c); }
|
||||||
|
|
||||||
|
inline char CharToUpper(char c) {
|
||||||
|
return static_cast<char>(::toupper(static_cast<unsigned char>(c)));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char CharToLower(char c) {
|
||||||
|
return static_cast<char>(::tolower(static_cast<unsigned char>(c)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// @end-locale-independent functions for ASCII character set
|
||||||
|
|
||||||
|
#ifdef FLATBUFFERS_PREFER_PRINTF
|
||||||
|
template <typename T>
|
||||||
|
size_t IntToDigitCount(T t) {
|
||||||
|
size_t digit_count = 0;
|
||||||
|
// Count the sign for negative numbers
|
||||||
|
if (t < 0) digit_count++;
|
||||||
|
// Count a single 0 left of the dot for fractional numbers
|
||||||
|
if (-1 < t && t < 1) digit_count++;
|
||||||
|
// Count digits until fractional part
|
||||||
|
T eps = std::numeric_limits<T>::epsilon();
|
||||||
|
while (t <= (-1 + eps) || (1 - eps) <= t) {
|
||||||
|
t /= 10;
|
||||||
|
digit_count++;
|
||||||
|
}
|
||||||
|
return digit_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
size_t NumToStringWidth(T t, int precision = 0) {
|
||||||
|
size_t string_width = IntToDigitCount(t);
|
||||||
|
// Count the dot for floating point numbers
|
||||||
|
if (precision) string_width += (precision + 1);
|
||||||
|
return string_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::string NumToStringImplWrapper(T t, const char* fmt, int precision = 0) {
|
||||||
|
size_t string_width = NumToStringWidth(t, precision);
|
||||||
|
std::string s(string_width, 0x00);
|
||||||
|
// Allow snprintf to use std::string trailing null to detect buffer overflow
|
||||||
|
snprintf(const_cast<char*>(s.data()), (s.size() + 1), fmt, string_width, t);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
#endif // FLATBUFFERS_PREFER_PRINTF
|
||||||
|
|
||||||
|
// Convert an integer or floating point value to a string.
|
||||||
|
// In contrast to std::stringstream, "char" values are
|
||||||
|
// converted to a string of digits, and we don't use scientific notation.
|
||||||
|
template <typename T>
|
||||||
|
std::string NumToString(T t) {
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_PREFER_PRINTF
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << t;
|
||||||
|
return ss.str();
|
||||||
|
#else // FLATBUFFERS_PREFER_PRINTF
|
||||||
|
auto v = static_cast<long long>(t);
|
||||||
|
return NumToStringImplWrapper(v, "%.*lld");
|
||||||
|
#endif // FLATBUFFERS_PREFER_PRINTF
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
// Avoid char types used as character data.
|
||||||
|
template <>
|
||||||
|
inline std::string NumToString<signed char>(signed char t) {
|
||||||
|
return NumToString(static_cast<int>(t));
|
||||||
|
}
|
||||||
|
template <>
|
||||||
|
inline std::string NumToString<unsigned char>(unsigned char t) {
|
||||||
|
return NumToString(static_cast<int>(t));
|
||||||
|
}
|
||||||
|
template <>
|
||||||
|
inline std::string NumToString<char>(char t) {
|
||||||
|
return NumToString(static_cast<int>(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special versions for floats/doubles.
|
||||||
|
template <typename T>
|
||||||
|
std::string FloatToString(T t, int precision) {
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_PREFER_PRINTF
|
||||||
|
// to_string() prints different numbers of digits for floats depending on
|
||||||
|
// platform and isn't available on Android, so we use stringstream
|
||||||
|
std::stringstream ss;
|
||||||
|
// Use std::fixed to suppress scientific notation.
|
||||||
|
ss << std::fixed;
|
||||||
|
// Default precision is 6, we want that to be higher for doubles.
|
||||||
|
ss << std::setprecision(precision);
|
||||||
|
ss << t;
|
||||||
|
auto s = ss.str();
|
||||||
|
#else // FLATBUFFERS_PREFER_PRINTF
|
||||||
|
auto v = static_cast<double>(t);
|
||||||
|
auto s = NumToStringImplWrapper(v, "%0.*f", precision);
|
||||||
|
#endif // FLATBUFFERS_PREFER_PRINTF
|
||||||
|
// clang-format on
|
||||||
|
// Sadly, std::fixed turns "1" into "1.00000", so here we undo that.
|
||||||
|
auto p = s.find_last_not_of('0');
|
||||||
|
if (p != std::string::npos) {
|
||||||
|
// Strip trailing zeroes. If it is a whole number, keep one zero.
|
||||||
|
s.resize(p + (s[p] == '.' ? 2 : 1));
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline std::string NumToString<double>(double t) {
|
||||||
|
return FloatToString(t, 12);
|
||||||
|
}
|
||||||
|
template <>
|
||||||
|
inline std::string NumToString<float>(float t) {
|
||||||
|
return FloatToString(t, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert an integer value to a hexadecimal string.
|
||||||
|
// The returned string length is always xdigits long, prefixed by 0 digits.
|
||||||
|
// For example, IntToStringHex(0x23, 8) returns the string "00000023".
|
||||||
|
inline std::string IntToStringHex(int i, int xdigits) {
|
||||||
|
FLATBUFFERS_ASSERT(i >= 0);
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_PREFER_PRINTF
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << std::setw(xdigits) << std::setfill('0') << std::hex << std::uppercase
|
||||||
|
<< i;
|
||||||
|
return ss.str();
|
||||||
|
#else // FLATBUFFERS_PREFER_PRINTF
|
||||||
|
return NumToStringImplWrapper(i, "%.*X", xdigits);
|
||||||
|
#endif // FLATBUFFERS_PREFER_PRINTF
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
// Use locale independent functions {strtod_l, strtof_l, strtoll_l, strtoull_l}.
|
||||||
|
#if defined(FLATBUFFERS_LOCALE_INDEPENDENT) && (FLATBUFFERS_LOCALE_INDEPENDENT > 0)
|
||||||
|
class ClassicLocale {
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
typedef _locale_t locale_type;
|
||||||
|
#else
|
||||||
|
typedef locale_t locale_type; // POSIX.1-2008 locale_t type
|
||||||
|
#endif
|
||||||
|
ClassicLocale();
|
||||||
|
~ClassicLocale();
|
||||||
|
locale_type locale_;
|
||||||
|
static ClassicLocale instance_;
|
||||||
|
public:
|
||||||
|
static locale_type Get() { return instance_.locale_; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define __strtoull_impl(s, pe, b) _strtoui64_l(s, pe, b, ClassicLocale::Get())
|
||||||
|
#define __strtoll_impl(s, pe, b) _strtoi64_l(s, pe, b, ClassicLocale::Get())
|
||||||
|
#define __strtod_impl(s, pe) _strtod_l(s, pe, ClassicLocale::Get())
|
||||||
|
#define __strtof_impl(s, pe) _strtof_l(s, pe, ClassicLocale::Get())
|
||||||
|
#else
|
||||||
|
#define __strtoull_impl(s, pe, b) strtoull_l(s, pe, b, ClassicLocale::Get())
|
||||||
|
#define __strtoll_impl(s, pe, b) strtoll_l(s, pe, b, ClassicLocale::Get())
|
||||||
|
#define __strtod_impl(s, pe) strtod_l(s, pe, ClassicLocale::Get())
|
||||||
|
#define __strtof_impl(s, pe) strtof_l(s, pe, ClassicLocale::Get())
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define __strtod_impl(s, pe) strtod(s, pe)
|
||||||
|
#define __strtof_impl(s, pe) static_cast<float>(strtod(s, pe))
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define __strtoull_impl(s, pe, b) _strtoui64(s, pe, b)
|
||||||
|
#define __strtoll_impl(s, pe, b) _strtoi64(s, pe, b)
|
||||||
|
#else
|
||||||
|
#define __strtoull_impl(s, pe, b) strtoull(s, pe, b)
|
||||||
|
#define __strtoll_impl(s, pe, b) strtoll(s, pe, b)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline void strtoval_impl(int64_t *val, const char *str, char **endptr,
|
||||||
|
int base) {
|
||||||
|
*val = __strtoll_impl(str, endptr, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void strtoval_impl(uint64_t *val, const char *str, char **endptr,
|
||||||
|
int base) {
|
||||||
|
*val = __strtoull_impl(str, endptr, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void strtoval_impl(double *val, const char *str, char **endptr) {
|
||||||
|
*val = __strtod_impl(str, endptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// UBSAN: double to float is safe if numeric_limits<float>::is_iec559 is true.
|
||||||
|
FLATBUFFERS_SUPPRESS_UBSAN("float-cast-overflow")
|
||||||
|
inline void strtoval_impl(float *val, const char *str, char **endptr) {
|
||||||
|
*val = __strtof_impl(str, endptr);
|
||||||
|
}
|
||||||
|
#undef __strtoull_impl
|
||||||
|
#undef __strtoll_impl
|
||||||
|
#undef __strtod_impl
|
||||||
|
#undef __strtof_impl
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// Adaptor for strtoull()/strtoll().
|
||||||
|
// Flatbuffers accepts numbers with any count of leading zeros (-009 is -9),
|
||||||
|
// while strtoll with base=0 interprets first leading zero as octal prefix.
|
||||||
|
// In future, it is possible to add prefixed 0b0101.
|
||||||
|
// 1) Checks errno code for overflow condition (out of range).
|
||||||
|
// 2) If base <= 0, function try to detect base of number by prefix.
|
||||||
|
//
|
||||||
|
// Return value (like strtoull and strtoll, but reject partial result):
|
||||||
|
// - If successful, an integer value corresponding to the str is returned.
|
||||||
|
// - If full string conversion can't be performed, 0 is returned.
|
||||||
|
// - If the converted value falls out of range of corresponding return type, a
|
||||||
|
// range error occurs. In this case value MAX(T)/MIN(T) is returned.
|
||||||
|
template <typename T>
|
||||||
|
inline bool StringToIntegerImpl(T* val, const char* const str,
|
||||||
|
const int base = 0,
|
||||||
|
const bool check_errno = true) {
|
||||||
|
// T is int64_t or uint64_T
|
||||||
|
FLATBUFFERS_ASSERT(str);
|
||||||
|
if (base <= 0) {
|
||||||
|
auto s = str;
|
||||||
|
while (*s && !is_digit(*s)) s++;
|
||||||
|
if (s[0] == '0' && is_alpha_char(s[1], 'X'))
|
||||||
|
return StringToIntegerImpl(val, str, 16, check_errno);
|
||||||
|
// if a prefix not match, try base=10
|
||||||
|
return StringToIntegerImpl(val, str, 10, check_errno);
|
||||||
|
} else {
|
||||||
|
if (check_errno) errno = 0; // clear thread-local errno
|
||||||
|
auto endptr = str;
|
||||||
|
strtoval_impl(val, str, const_cast<char**>(&endptr), base);
|
||||||
|
if ((*endptr != '\0') || (endptr == str)) {
|
||||||
|
*val = 0; // erase partial result
|
||||||
|
return false; // invalid string
|
||||||
|
}
|
||||||
|
// errno is out-of-range, return MAX/MIN
|
||||||
|
if (check_errno && errno) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline bool StringToFloatImpl(T* val, const char* const str) {
|
||||||
|
// Type T must be either float or double.
|
||||||
|
FLATBUFFERS_ASSERT(str && val);
|
||||||
|
auto end = str;
|
||||||
|
strtoval_impl(val, str, const_cast<char**>(&end));
|
||||||
|
auto done = (end != str) && (*end == '\0');
|
||||||
|
if (!done) *val = 0; // erase partial result
|
||||||
|
if (done && std::isnan(*val)) {
|
||||||
|
*val = std::numeric_limits<T>::quiet_NaN();
|
||||||
|
}
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert a string to an instance of T.
|
||||||
|
// Return value (matched with StringToInteger64Impl and strtod):
|
||||||
|
// - If successful, a numeric value corresponding to the str is returned.
|
||||||
|
// - If full string conversion can't be performed, 0 is returned.
|
||||||
|
// - If the converted value falls out of range of corresponding return type, a
|
||||||
|
// range error occurs. In this case value MAX(T)/MIN(T) is returned.
|
||||||
|
template <typename T>
|
||||||
|
inline bool StringToNumber(const char* s, T* val) {
|
||||||
|
// Assert on `unsigned long` and `signed long` on LP64.
|
||||||
|
// If it is necessary, it could be solved with flatbuffers::enable_if<B,T>.
|
||||||
|
static_assert(sizeof(T) < sizeof(int64_t), "unexpected type T");
|
||||||
|
FLATBUFFERS_ASSERT(s && val);
|
||||||
|
int64_t i64;
|
||||||
|
// The errno check isn't needed, will return MAX/MIN on overflow.
|
||||||
|
if (StringToIntegerImpl(&i64, s, 0, false)) {
|
||||||
|
const int64_t max = (flatbuffers::numeric_limits<T>::max)();
|
||||||
|
const int64_t min = flatbuffers::numeric_limits<T>::lowest();
|
||||||
|
if (i64 > max) {
|
||||||
|
*val = static_cast<T>(max);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (i64 < min) {
|
||||||
|
// For unsigned types return max to distinguish from
|
||||||
|
// "no conversion can be performed" when 0 is returned.
|
||||||
|
*val = static_cast<T>(flatbuffers::is_unsigned<T>::value ? max : min);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*val = static_cast<T>(i64);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*val = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline bool StringToNumber<int64_t>(const char* str, int64_t* val) {
|
||||||
|
return StringToIntegerImpl(val, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline bool StringToNumber<uint64_t>(const char* str, uint64_t* val) {
|
||||||
|
if (!StringToIntegerImpl(val, str)) return false;
|
||||||
|
// The strtoull accepts negative numbers:
|
||||||
|
// If the minus sign was part of the input sequence, the numeric value
|
||||||
|
// calculated from the sequence of digits is negated as if by unary minus
|
||||||
|
// in the result type, which applies unsigned integer wraparound rules.
|
||||||
|
// Fix this behaviour (except -0).
|
||||||
|
if (*val) {
|
||||||
|
auto s = str;
|
||||||
|
while (*s && !is_digit(*s)) s++;
|
||||||
|
s = (s > str) ? (s - 1) : s; // step back to one symbol
|
||||||
|
if (*s == '-') {
|
||||||
|
// For unsigned types return the max to distinguish from
|
||||||
|
// "no conversion can be performed".
|
||||||
|
*val = (flatbuffers::numeric_limits<uint64_t>::max)();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline bool StringToNumber(const char* s, float* val) {
|
||||||
|
return StringToFloatImpl(val, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline bool StringToNumber(const char* s, double* val) {
|
||||||
|
return StringToFloatImpl(val, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int64_t StringToInt(const char* s, int base = 10) {
|
||||||
|
int64_t val;
|
||||||
|
return StringToIntegerImpl(&val, s, base) ? val : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t StringToUInt(const char* s, int base = 10) {
|
||||||
|
uint64_t val;
|
||||||
|
return StringToIntegerImpl(&val, s, base) ? val : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool StringIsFlatbufferNan(const std::string& s) {
|
||||||
|
return s == "nan" || s == "+nan" || s == "-nan";
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool StringIsFlatbufferPositiveInfinity(const std::string& s) {
|
||||||
|
return s == "inf" || s == "+inf" || s == "infinity" || s == "+infinity";
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool StringIsFlatbufferNegativeInfinity(const std::string& s) {
|
||||||
|
return s == "-inf" || s == "-infinity";
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef bool (*LoadFileFunction)(const char* filename, bool binary,
|
||||||
|
std::string* dest);
|
||||||
|
typedef bool (*FileExistsFunction)(const char* filename);
|
||||||
|
|
||||||
|
LoadFileFunction SetLoadFileFunction(LoadFileFunction load_file_function);
|
||||||
|
|
||||||
|
FileExistsFunction SetFileExistsFunction(
|
||||||
|
FileExistsFunction file_exists_function);
|
||||||
|
|
||||||
|
// Check if file "name" exists.
|
||||||
|
bool FileExists(const char* name);
|
||||||
|
|
||||||
|
// Check if "name" exists and it is also a directory.
|
||||||
|
bool DirExists(const char* name);
|
||||||
|
|
||||||
|
// Load file "name" into "buf" returning true if successful
|
||||||
|
// false otherwise. If "binary" is false data is read
|
||||||
|
// using ifstream's text mode, otherwise data is read with
|
||||||
|
// no transcoding.
|
||||||
|
bool LoadFile(const char* name, bool binary, std::string* buf);
|
||||||
|
|
||||||
|
// Save data "buf" of length "len" bytes into a file
|
||||||
|
// "name" returning true if successful, false otherwise.
|
||||||
|
// If "binary" is false data is written using ifstream's
|
||||||
|
// text mode, otherwise data is written with no
|
||||||
|
// transcoding.
|
||||||
|
// NOTE: this function is deprecated in favor of FileSaver class,
|
||||||
|
// but left here for compatibility.
|
||||||
|
bool SaveFile(const char* name, const char* buf, size_t len, bool binary);
|
||||||
|
|
||||||
|
// Save data "buf" into file "name" returning true if
|
||||||
|
// successful, false otherwise. If "binary" is false
|
||||||
|
// data is written using ifstream's text mode, otherwise
|
||||||
|
// data is written with no transcoding.
|
||||||
|
// NOTE: this function is deprecated in favor of FileSaver class,
|
||||||
|
// but left here for compatibility.
|
||||||
|
inline bool SaveFile(const char* name, const std::string& buf, bool binary) {
|
||||||
|
return SaveFile(name, buf.c_str(), buf.size(), binary);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functionality for minimalistic portable path handling.
|
||||||
|
|
||||||
|
// The functions below behave correctly regardless of whether posix ('/') or
|
||||||
|
// Windows ('/' or '\\') separators are used.
|
||||||
|
|
||||||
|
// Any new separators inserted are always posix.
|
||||||
|
FLATBUFFERS_CONSTEXPR char kPathSeparator = '/';
|
||||||
|
|
||||||
|
// Returns the path with the extension, if any, removed.
|
||||||
|
std::string StripExtension(const std::string& filepath);
|
||||||
|
|
||||||
|
// Returns the extension, if any.
|
||||||
|
std::string GetExtension(const std::string& filepath);
|
||||||
|
|
||||||
|
// Return the last component of the path, after the last separator.
|
||||||
|
std::string StripPath(const std::string& filepath);
|
||||||
|
|
||||||
|
// Strip the last component of the path + separator.
|
||||||
|
std::string StripFileName(const std::string& filepath);
|
||||||
|
|
||||||
|
std::string StripPrefix(const std::string& filepath,
|
||||||
|
const std::string& prefix_to_remove);
|
||||||
|
|
||||||
|
// Concatenates a path with a filename, regardless of whether the path
|
||||||
|
// ends in a separator or not.
|
||||||
|
std::string ConCatPathFileName(const std::string& path,
|
||||||
|
const std::string& filename);
|
||||||
|
|
||||||
|
// Replaces any '\\' separators with '/'
|
||||||
|
std::string PosixPath(const char* path);
|
||||||
|
std::string PosixPath(const std::string& path);
|
||||||
|
|
||||||
|
// This function ensure a directory exists, by recursively
|
||||||
|
// creating dirs for any parts of the path that don't exist yet.
|
||||||
|
void EnsureDirExists(const std::string& filepath);
|
||||||
|
|
||||||
|
// Obtains the relative or absolute path.
|
||||||
|
std::string FilePath(const std::string& project, const std::string& filePath,
|
||||||
|
bool absolute);
|
||||||
|
|
||||||
|
// Obtains the absolute path from any other path.
|
||||||
|
// Returns the input path if the absolute path couldn't be resolved.
|
||||||
|
std::string AbsolutePath(const std::string& filepath);
|
||||||
|
|
||||||
|
// Returns files relative to the --project_root path, prefixed with `//`.
|
||||||
|
std::string RelativeToRootPath(const std::string& project,
|
||||||
|
const std::string& filepath);
|
||||||
|
|
||||||
|
// To and from UTF-8 unicode conversion functions
|
||||||
|
|
||||||
|
// Convert a unicode code point into a UTF-8 representation by appending it
|
||||||
|
// to a string. Returns the number of bytes generated.
|
||||||
|
inline int ToUTF8(uint32_t ucc, std::string* out) {
|
||||||
|
FLATBUFFERS_ASSERT(!(ucc & 0x80000000)); // Top bit can't be set.
|
||||||
|
// 6 possible encodings: http://en.wikipedia.org/wiki/UTF-8
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
// Max bits this encoding can represent.
|
||||||
|
uint32_t max_bits = 6 + i * 5 + static_cast<int>(!i);
|
||||||
|
if (ucc < (1u << max_bits)) { // does it fit?
|
||||||
|
// Remaining bits not encoded in the first byte, store 6 bits each
|
||||||
|
uint32_t remain_bits = i * 6;
|
||||||
|
// Store first byte:
|
||||||
|
(*out) += static_cast<char>((0xFE << (max_bits - remain_bits)) |
|
||||||
|
(ucc >> remain_bits));
|
||||||
|
// Store remaining bytes:
|
||||||
|
for (int j = i - 1; j >= 0; j--) {
|
||||||
|
(*out) += static_cast<char>(((ucc >> (j * 6)) & 0x3F) | 0x80);
|
||||||
|
}
|
||||||
|
return i + 1; // Return the number of bytes added.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FLATBUFFERS_ASSERT(0); // Impossible to arrive here.
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts whatever prefix of the incoming string corresponds to a valid
|
||||||
|
// UTF-8 sequence into a unicode code. The incoming pointer will have been
|
||||||
|
// advanced past all bytes parsed.
|
||||||
|
// returns -1 upon corrupt UTF-8 encoding (ignore the incoming pointer in
|
||||||
|
// this case).
|
||||||
|
inline int FromUTF8(const char** in) {
|
||||||
|
int len = 0;
|
||||||
|
// Count leading 1 bits.
|
||||||
|
for (int mask = 0x80; mask >= 0x04; mask >>= 1) {
|
||||||
|
if (**in & mask) {
|
||||||
|
len++;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((static_cast<unsigned char>(**in) << len) & 0x80)
|
||||||
|
return -1; // Bit after leading 1's must be 0.
|
||||||
|
if (!len) return *(*in)++;
|
||||||
|
// UTF-8 encoded values with a length are between 2 and 4 bytes.
|
||||||
|
if (len < 2 || len > 4) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// Grab initial bits of the code.
|
||||||
|
int ucc = *(*in)++ & ((1 << (7 - len)) - 1);
|
||||||
|
for (int i = 0; i < len - 1; i++) {
|
||||||
|
if ((**in & 0xC0) != 0x80) return -1; // Upper bits must 1 0.
|
||||||
|
ucc <<= 6;
|
||||||
|
ucc |= *(*in)++ & 0x3F; // Grab 6 more bits of the code.
|
||||||
|
}
|
||||||
|
// UTF-8 cannot encode values between 0xD800 and 0xDFFF (reserved for
|
||||||
|
// UTF-16 surrogate pairs).
|
||||||
|
if (ucc >= 0xD800 && ucc <= 0xDFFF) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// UTF-8 must represent code points in their shortest possible encoding.
|
||||||
|
switch (len) {
|
||||||
|
case 2:
|
||||||
|
// Two bytes of UTF-8 can represent code points from U+0080 to U+07FF.
|
||||||
|
if (ucc < 0x0080 || ucc > 0x07FF) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
// Three bytes of UTF-8 can represent code points from U+0800 to U+FFFF.
|
||||||
|
if (ucc < 0x0800 || ucc > 0xFFFF) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
// Four bytes of UTF-8 can represent code points from U+10000 to U+10FFFF.
|
||||||
|
if (ucc < 0x10000 || ucc > 0x10FFFF) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ucc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_PREFER_PRINTF
|
||||||
|
// Wraps a string to a maximum length, inserting new lines where necessary. Any
|
||||||
|
// existing whitespace will be collapsed down to a single space. A prefix or
|
||||||
|
// suffix can be provided, which will be inserted before or after a wrapped
|
||||||
|
// line, respectively.
|
||||||
|
inline std::string WordWrap(const std::string in, size_t max_length,
|
||||||
|
const std::string wrapped_line_prefix,
|
||||||
|
const std::string wrapped_line_suffix) {
|
||||||
|
std::istringstream in_stream(in);
|
||||||
|
std::string wrapped, line, word;
|
||||||
|
|
||||||
|
in_stream >> word;
|
||||||
|
line = word;
|
||||||
|
|
||||||
|
while (in_stream >> word) {
|
||||||
|
if ((line.length() + 1 + word.length() + wrapped_line_suffix.length()) <
|
||||||
|
max_length) {
|
||||||
|
line += " " + word;
|
||||||
|
} else {
|
||||||
|
wrapped += line + wrapped_line_suffix + "\n";
|
||||||
|
line = wrapped_line_prefix + word;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wrapped += line;
|
||||||
|
|
||||||
|
return wrapped;
|
||||||
|
}
|
||||||
|
#endif // !FLATBUFFERS_PREFER_PRINTF
|
||||||
|
|
||||||
|
inline bool EscapeString(const char* s, size_t length, std::string* _text,
|
||||||
|
bool allow_non_utf8, bool natural_utf8) {
|
||||||
|
std::string& text = *_text;
|
||||||
|
text += "\"";
|
||||||
|
for (uoffset_t i = 0; i < length; i++) {
|
||||||
|
char c = s[i];
|
||||||
|
switch (c) {
|
||||||
|
case '\n':
|
||||||
|
text += "\\n";
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
text += "\\t";
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
text += "\\r";
|
||||||
|
break;
|
||||||
|
case '\b':
|
||||||
|
text += "\\b";
|
||||||
|
break;
|
||||||
|
case '\f':
|
||||||
|
text += "\\f";
|
||||||
|
break;
|
||||||
|
case '\"':
|
||||||
|
text += "\\\"";
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
text += "\\\\";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (c >= ' ' && c <= '~') {
|
||||||
|
text += c;
|
||||||
|
} else {
|
||||||
|
// Not printable ASCII data. Let's see if it's valid UTF-8 first:
|
||||||
|
const char* utf8 = s + i;
|
||||||
|
int ucc = FromUTF8(&utf8);
|
||||||
|
if (ucc < 0) {
|
||||||
|
if (allow_non_utf8) {
|
||||||
|
text += "\\x";
|
||||||
|
text += IntToStringHex(static_cast<uint8_t>(c), 2);
|
||||||
|
} else {
|
||||||
|
// There are two cases here:
|
||||||
|
//
|
||||||
|
// 1) We reached here by parsing an IDL file. In that case,
|
||||||
|
// we previously checked for non-UTF-8, so we shouldn't reach
|
||||||
|
// here.
|
||||||
|
//
|
||||||
|
// 2) We reached here by someone calling GenText()
|
||||||
|
// on a previously-serialized flatbuffer. The data might have
|
||||||
|
// non-UTF-8 Strings, or might be corrupt.
|
||||||
|
//
|
||||||
|
// In both cases, we have to give up and inform the caller
|
||||||
|
// they have no JSON.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (natural_utf8) {
|
||||||
|
// utf8 points to past all utf-8 bytes parsed
|
||||||
|
text.append(s + i, static_cast<size_t>(utf8 - s - i));
|
||||||
|
} else if (ucc <= 0xFFFF) {
|
||||||
|
// Parses as Unicode within JSON's \uXXXX range, so use that.
|
||||||
|
text += "\\u";
|
||||||
|
text += IntToStringHex(ucc, 4);
|
||||||
|
} else if (ucc <= 0x10FFFF) {
|
||||||
|
// Encode Unicode SMP values to a surrogate pair using two \u
|
||||||
|
// escapes.
|
||||||
|
uint32_t base = ucc - 0x10000;
|
||||||
|
auto high_surrogate = (base >> 10) + 0xD800;
|
||||||
|
auto low_surrogate = (base & 0x03FF) + 0xDC00;
|
||||||
|
text += "\\u";
|
||||||
|
text += IntToStringHex(high_surrogate, 4);
|
||||||
|
text += "\\u";
|
||||||
|
text += IntToStringHex(low_surrogate, 4);
|
||||||
|
}
|
||||||
|
// Skip past characters recognized.
|
||||||
|
i = static_cast<uoffset_t>(utf8 - s - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
text += "\"";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string BufferToHexText(const void* buffer, size_t buffer_size,
|
||||||
|
size_t max_length,
|
||||||
|
const std::string& wrapped_line_prefix,
|
||||||
|
const std::string& wrapped_line_suffix) {
|
||||||
|
std::string text = wrapped_line_prefix;
|
||||||
|
size_t start_offset = 0;
|
||||||
|
const char* s = reinterpret_cast<const char*>(buffer);
|
||||||
|
for (size_t i = 0; s && i < buffer_size; i++) {
|
||||||
|
// Last iteration or do we have more?
|
||||||
|
bool have_more = i + 1 < buffer_size;
|
||||||
|
text += "0x";
|
||||||
|
text += IntToStringHex(static_cast<uint8_t>(s[i]), 2);
|
||||||
|
if (have_more) {
|
||||||
|
text += ',';
|
||||||
|
}
|
||||||
|
// If we have more to process and we reached max_length
|
||||||
|
if (have_more &&
|
||||||
|
text.size() + wrapped_line_suffix.size() >= start_offset + max_length) {
|
||||||
|
text += wrapped_line_suffix;
|
||||||
|
text += '\n';
|
||||||
|
start_offset = text.size();
|
||||||
|
text += wrapped_line_prefix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
text += wrapped_line_suffix;
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove paired quotes in a string: "text"|'text' -> text.
|
||||||
|
std::string RemoveStringQuotes(const std::string& s);
|
||||||
|
|
||||||
|
// Change th global C-locale to locale with name <locale_name>.
|
||||||
|
// Returns an actual locale name in <_value>, useful if locale_name is "" or
|
||||||
|
// null.
|
||||||
|
bool SetGlobalTestLocale(const char* locale_name,
|
||||||
|
std::string* _value = nullptr);
|
||||||
|
|
||||||
|
// Read (or test) a value of environment variable.
|
||||||
|
bool ReadEnvironmentVariable(const char* var_name,
|
||||||
|
std::string* _value = nullptr);
|
||||||
|
|
||||||
|
enum class Case {
|
||||||
|
kUnknown = 0,
|
||||||
|
// TheQuickBrownFox
|
||||||
|
kUpperCamel = 1,
|
||||||
|
// theQuickBrownFox
|
||||||
|
kLowerCamel = 2,
|
||||||
|
// the_quick_brown_fox
|
||||||
|
kSnake = 3,
|
||||||
|
// THE_QUICK_BROWN_FOX
|
||||||
|
kScreamingSnake = 4,
|
||||||
|
// THEQUICKBROWNFOX
|
||||||
|
kAllUpper = 5,
|
||||||
|
// thequickbrownfox
|
||||||
|
kAllLower = 6,
|
||||||
|
// the-quick-brown-fox
|
||||||
|
kDasher = 7,
|
||||||
|
// THEQuiCKBr_ownFox (or whatever you want, we won't change it)
|
||||||
|
kKeep = 8,
|
||||||
|
// the_quick_brown_fox123 (as opposed to the_quick_brown_fox_123)
|
||||||
|
kSnake2 = 9,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert the `input` string of case `input_case` to the specified
|
||||||
|
// `output_case`.
|
||||||
|
std::string ConvertCase(const std::string& input, Case output_case,
|
||||||
|
Case input_case = Case::kSnake);
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_UTIL_H_
|
||||||
@@ -0,0 +1,455 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_VECTOR_H_
|
||||||
|
#define FLATBUFFERS_VECTOR_H_
|
||||||
|
|
||||||
|
#include "flatbuffers/base.h"
|
||||||
|
#include "flatbuffers/buffer.h"
|
||||||
|
#include "flatbuffers/stl_emulation.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
struct String;
|
||||||
|
|
||||||
|
// An STL compatible iterator implementation for Vector below, effectively
|
||||||
|
// calling Get() for every element.
|
||||||
|
template <typename T, typename IT, typename Data = uint8_t*,
|
||||||
|
typename SizeT = uoffset_t>
|
||||||
|
struct VectorIterator {
|
||||||
|
typedef std::random_access_iterator_tag iterator_category;
|
||||||
|
typedef IT value_type;
|
||||||
|
typedef ptrdiff_t difference_type;
|
||||||
|
typedef IT* pointer;
|
||||||
|
typedef IT& reference;
|
||||||
|
|
||||||
|
static const SizeT element_stride = IndirectHelper<T>::element_stride;
|
||||||
|
|
||||||
|
VectorIterator(Data data, SizeT i) : data_(data + element_stride * i) {}
|
||||||
|
VectorIterator(const VectorIterator& other) : data_(other.data_) {}
|
||||||
|
VectorIterator() : data_(nullptr) {}
|
||||||
|
|
||||||
|
VectorIterator& operator=(const VectorIterator& other) {
|
||||||
|
data_ = other.data_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VectorIterator& operator=(VectorIterator&& other) {
|
||||||
|
data_ = other.data_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const VectorIterator& other) const {
|
||||||
|
return data_ == other.data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const VectorIterator& other) const {
|
||||||
|
return data_ != other.data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const VectorIterator& other) const {
|
||||||
|
return data_ < other.data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator>(const VectorIterator& other) const {
|
||||||
|
return data_ > other.data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<=(const VectorIterator& other) const {
|
||||||
|
return !(data_ > other.data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator>=(const VectorIterator& other) const {
|
||||||
|
return !(data_ < other.data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
difference_type operator-(const VectorIterator& other) const {
|
||||||
|
return (data_ - other.data_) / element_stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: return type is incompatible with the standard
|
||||||
|
// `reference operator*()`.
|
||||||
|
IT operator*() const { return IndirectHelper<T>::Read(data_, 0); }
|
||||||
|
|
||||||
|
// Note: return type is incompatible with the standard
|
||||||
|
// `pointer operator->()`.
|
||||||
|
IT operator->() const { return IndirectHelper<T>::Read(data_, 0); }
|
||||||
|
|
||||||
|
VectorIterator& operator++() {
|
||||||
|
data_ += element_stride;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VectorIterator operator++(int) {
|
||||||
|
VectorIterator temp(data_, 0);
|
||||||
|
data_ += element_stride;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
VectorIterator operator+(const SizeT& offset) const {
|
||||||
|
return VectorIterator(data_ + offset * element_stride, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
VectorIterator& operator+=(const SizeT& offset) {
|
||||||
|
data_ += offset * element_stride;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VectorIterator& operator--() {
|
||||||
|
data_ -= element_stride;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VectorIterator operator--(int) {
|
||||||
|
VectorIterator temp(data_, 0);
|
||||||
|
data_ -= element_stride;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
VectorIterator operator-(const SizeT& offset) const {
|
||||||
|
return VectorIterator(data_ - offset * element_stride, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
VectorIterator& operator-=(const SizeT& offset) {
|
||||||
|
data_ -= offset * element_stride;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Data data_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename IT, typename SizeT = uoffset_t>
|
||||||
|
using VectorConstIterator = VectorIterator<T, IT, const uint8_t*, SizeT>;
|
||||||
|
|
||||||
|
template <typename Iterator>
|
||||||
|
struct VectorReverseIterator : public std::reverse_iterator<Iterator> {
|
||||||
|
explicit VectorReverseIterator(Iterator iter)
|
||||||
|
: std::reverse_iterator<Iterator>(iter) {}
|
||||||
|
|
||||||
|
// Note: return type is incompatible with the standard
|
||||||
|
// `reference operator*()`.
|
||||||
|
typename Iterator::value_type operator*() const {
|
||||||
|
auto tmp = std::reverse_iterator<Iterator>::current;
|
||||||
|
return *--tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: return type is incompatible with the standard
|
||||||
|
// `pointer operator->()`.
|
||||||
|
typename Iterator::value_type operator->() const {
|
||||||
|
auto tmp = std::reverse_iterator<Iterator>::current;
|
||||||
|
return *--tmp;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is used as a helper type for accessing vectors.
|
||||||
|
// Vector::data() assumes the vector elements start after the length field.
|
||||||
|
template <typename T, typename SizeT = uoffset_t>
|
||||||
|
class Vector {
|
||||||
|
public:
|
||||||
|
typedef VectorIterator<T, typename IndirectHelper<T>::mutable_return_type,
|
||||||
|
uint8_t*, SizeT>
|
||||||
|
iterator;
|
||||||
|
typedef VectorConstIterator<T, typename IndirectHelper<T>::return_type, SizeT>
|
||||||
|
const_iterator;
|
||||||
|
typedef VectorReverseIterator<iterator> reverse_iterator;
|
||||||
|
typedef VectorReverseIterator<const_iterator> const_reverse_iterator;
|
||||||
|
|
||||||
|
typedef typename flatbuffers::bool_constant<flatbuffers::is_scalar<T>::value>
|
||||||
|
scalar_tag;
|
||||||
|
|
||||||
|
static FLATBUFFERS_CONSTEXPR bool is_span_observable =
|
||||||
|
scalar_tag::value && !std::is_pointer<T>::value &&
|
||||||
|
(FLATBUFFERS_LITTLEENDIAN || sizeof(T) == 1);
|
||||||
|
|
||||||
|
SizeT size() const { return EndianScalar(length_); }
|
||||||
|
|
||||||
|
// Returns true if the vector is empty.
|
||||||
|
//
|
||||||
|
// This just provides another standardized method that is expected of vectors.
|
||||||
|
bool empty() const { return size() == 0; }
|
||||||
|
|
||||||
|
// Deprecated: use size(). Here for backwards compatibility.
|
||||||
|
FLATBUFFERS_ATTRIBUTE([[deprecated("use size() instead")]])
|
||||||
|
SizeT Length() const { return size(); }
|
||||||
|
|
||||||
|
typedef SizeT size_type;
|
||||||
|
typedef typename IndirectHelper<T>::return_type return_type;
|
||||||
|
typedef typename IndirectHelper<T>::mutable_return_type mutable_return_type;
|
||||||
|
typedef return_type value_type;
|
||||||
|
|
||||||
|
return_type Get(SizeT i) const {
|
||||||
|
FLATBUFFERS_ASSERT(i < size());
|
||||||
|
return IndirectHelper<T>::Read(Data(), i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return_type operator[](SizeT i) const { return Get(i); }
|
||||||
|
|
||||||
|
// If this is a Vector of enums, T will be its storage type, not the enum
|
||||||
|
// type. This function makes it convenient to retrieve value with enum
|
||||||
|
// type E.
|
||||||
|
template <typename E>
|
||||||
|
E GetEnum(SizeT i) const {
|
||||||
|
return static_cast<E>(Get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this a vector of unions, this does the cast for you. There's no check
|
||||||
|
// to make sure this is the right type!
|
||||||
|
template <typename U>
|
||||||
|
const U* GetAs(SizeT i) const {
|
||||||
|
return reinterpret_cast<const U*>(Get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this a vector of unions, this does the cast for you. There's no check
|
||||||
|
// to make sure this is actually a string!
|
||||||
|
const String* GetAsString(SizeT i) const {
|
||||||
|
return reinterpret_cast<const String*>(Get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
const void* GetStructFromOffset(size_t o) const {
|
||||||
|
return reinterpret_cast<const void*>(Data() + o);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator begin() { return iterator(Data(), 0); }
|
||||||
|
const_iterator begin() const { return const_iterator(Data(), 0); }
|
||||||
|
|
||||||
|
iterator end() { return iterator(Data(), size()); }
|
||||||
|
const_iterator end() const { return const_iterator(Data(), size()); }
|
||||||
|
|
||||||
|
reverse_iterator rbegin() { return reverse_iterator(end()); }
|
||||||
|
const_reverse_iterator rbegin() const {
|
||||||
|
return const_reverse_iterator(end());
|
||||||
|
}
|
||||||
|
|
||||||
|
reverse_iterator rend() { return reverse_iterator(begin()); }
|
||||||
|
const_reverse_iterator rend() const {
|
||||||
|
return const_reverse_iterator(begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator cbegin() const { return begin(); }
|
||||||
|
|
||||||
|
const_iterator cend() const { return end(); }
|
||||||
|
|
||||||
|
const_reverse_iterator crbegin() const { return rbegin(); }
|
||||||
|
|
||||||
|
const_reverse_iterator crend() const { return rend(); }
|
||||||
|
|
||||||
|
// Change elements if you have a non-const pointer to this object.
|
||||||
|
// Scalars only. See reflection.h, and the documentation.
|
||||||
|
void Mutate(SizeT i, const T& val) {
|
||||||
|
FLATBUFFERS_ASSERT(i < size());
|
||||||
|
WriteScalar(data() + i, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change an element of a vector of tables (or strings).
|
||||||
|
// "val" points to the new table/string, as you can obtain from
|
||||||
|
// e.g. reflection::AddFlatBuffer().
|
||||||
|
void MutateOffset(SizeT i, const uint8_t* val) {
|
||||||
|
FLATBUFFERS_ASSERT(i < size());
|
||||||
|
static_assert(sizeof(T) == sizeof(SizeT), "Unrelated types");
|
||||||
|
WriteScalar(data() + i,
|
||||||
|
static_cast<SizeT>(val - (Data() + i * sizeof(SizeT))));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a mutable pointer to tables/strings inside this vector.
|
||||||
|
mutable_return_type GetMutableObject(SizeT i) const {
|
||||||
|
FLATBUFFERS_ASSERT(i < size());
|
||||||
|
return const_cast<mutable_return_type>(IndirectHelper<T>::Read(Data(), i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// The raw data in little endian format. Use with care.
|
||||||
|
const uint8_t* Data() const {
|
||||||
|
return reinterpret_cast<const uint8_t*>(&length_ + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* Data() { return reinterpret_cast<uint8_t*>(&length_ + 1); }
|
||||||
|
|
||||||
|
// Similarly, but typed, much like std::vector::data
|
||||||
|
const T* data() const { return reinterpret_cast<const T*>(Data()); }
|
||||||
|
T* data() { return reinterpret_cast<T*>(Data()); }
|
||||||
|
|
||||||
|
template <typename K>
|
||||||
|
return_type LookupByKey(K key) const {
|
||||||
|
void* search_result = std::bsearch(
|
||||||
|
&key, Data(), size(), IndirectHelper<T>::element_stride, KeyCompare<K>);
|
||||||
|
|
||||||
|
if (!search_result) {
|
||||||
|
return nullptr; // Key not found.
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* element = reinterpret_cast<const uint8_t*>(search_result);
|
||||||
|
|
||||||
|
return IndirectHelper<T>::Read(element, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename K>
|
||||||
|
mutable_return_type MutableLookupByKey(K key) {
|
||||||
|
return const_cast<mutable_return_type>(LookupByKey(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// This class is only used to access pre-existing data. Don't ever
|
||||||
|
// try to construct these manually.
|
||||||
|
Vector();
|
||||||
|
|
||||||
|
SizeT length_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// This class is a pointer. Copying will therefore create an invalid object.
|
||||||
|
// Private and unimplemented copy constructor.
|
||||||
|
Vector(const Vector&);
|
||||||
|
Vector& operator=(const Vector&);
|
||||||
|
|
||||||
|
template <typename K>
|
||||||
|
static int KeyCompare(const void* ap, const void* bp) {
|
||||||
|
const K* key = reinterpret_cast<const K*>(ap);
|
||||||
|
const uint8_t* data = reinterpret_cast<const uint8_t*>(bp);
|
||||||
|
auto table = IndirectHelper<T>::Read(data, 0);
|
||||||
|
|
||||||
|
// std::bsearch compares with the operands transposed, so we negate the
|
||||||
|
// result here.
|
||||||
|
return -table->KeyCompareWithValue(*key);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using Vector64 = Vector<T, uoffset64_t>;
|
||||||
|
|
||||||
|
template <class U>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<U> make_span(Vector<U>& vec)
|
||||||
|
FLATBUFFERS_NOEXCEPT {
|
||||||
|
static_assert(Vector<U>::is_span_observable,
|
||||||
|
"wrong type U, only LE-scalar, or byte types are allowed");
|
||||||
|
return span<U>(vec.data(), vec.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class U>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<const U> make_span(
|
||||||
|
const Vector<U>& vec) FLATBUFFERS_NOEXCEPT {
|
||||||
|
static_assert(Vector<U>::is_span_observable,
|
||||||
|
"wrong type U, only LE-scalar, or byte types are allowed");
|
||||||
|
return span<const U>(vec.data(), vec.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class U>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<uint8_t> make_bytes_span(
|
||||||
|
Vector<U>& vec) FLATBUFFERS_NOEXCEPT {
|
||||||
|
static_assert(Vector<U>::scalar_tag::value,
|
||||||
|
"wrong type U, only LE-scalar, or byte types are allowed");
|
||||||
|
return span<uint8_t>(vec.Data(), vec.size() * sizeof(U));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class U>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<const uint8_t> make_bytes_span(
|
||||||
|
const Vector<U>& vec) FLATBUFFERS_NOEXCEPT {
|
||||||
|
static_assert(Vector<U>::scalar_tag::value,
|
||||||
|
"wrong type U, only LE-scalar, or byte types are allowed");
|
||||||
|
return span<const uint8_t>(vec.Data(), vec.size() * sizeof(U));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if FLATBUFFERS_LITTLEENDIAN
|
||||||
|
|
||||||
|
template <class U>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<U> make_structs_span(
|
||||||
|
Vector<const U*>& vec) FLATBUFFERS_NOEXCEPT {
|
||||||
|
return span<U>(reinterpret_cast<U*>(vec.data()), vec.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class U>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<const U> make_structs_span(
|
||||||
|
const Vector<const U*>& vec) FLATBUFFERS_NOEXCEPT {
|
||||||
|
return span<const U>(reinterpret_cast<const U*>(vec.data()), vec.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Convenient helper functions to get a span of any vector, regardless
|
||||||
|
// of whether it is null or not (the field is not set).
|
||||||
|
template <class U>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<U> make_span(Vector<U>* ptr)
|
||||||
|
FLATBUFFERS_NOEXCEPT {
|
||||||
|
static_assert(Vector<U>::is_span_observable,
|
||||||
|
"wrong type U, only LE-scalar, or byte types are allowed");
|
||||||
|
return ptr ? make_span(*ptr) : span<U>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class U>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<const U> make_span(
|
||||||
|
const Vector<U>* ptr) FLATBUFFERS_NOEXCEPT {
|
||||||
|
static_assert(Vector<U>::is_span_observable,
|
||||||
|
"wrong type U, only LE-scalar, or byte types are allowed");
|
||||||
|
return ptr ? make_span(*ptr) : span<const U>();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if FLATBUFFERS_LITTLEENDIAN
|
||||||
|
|
||||||
|
template <class U>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<U> make_structs_span(
|
||||||
|
Vector<const U*>* ptr) FLATBUFFERS_NOEXCEPT {
|
||||||
|
return ptr ? make_span(*ptr) : span<U>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class U>
|
||||||
|
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<const U> make_structs_span(
|
||||||
|
const Vector<const U*>* ptr) FLATBUFFERS_NOEXCEPT {
|
||||||
|
return ptr ? make_span(*ptr) : span<const U>();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Represent a vector much like the template above, but in this case we
|
||||||
|
// don't know what the element types are (used with reflection.h).
|
||||||
|
class VectorOfAny {
|
||||||
|
public:
|
||||||
|
uoffset_t size() const { return EndianScalar(length_); }
|
||||||
|
|
||||||
|
const uint8_t* Data() const {
|
||||||
|
return reinterpret_cast<const uint8_t*>(&length_ + 1);
|
||||||
|
}
|
||||||
|
uint8_t* Data() { return reinterpret_cast<uint8_t*>(&length_ + 1); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
VectorOfAny();
|
||||||
|
|
||||||
|
uoffset_t length_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
VectorOfAny(const VectorOfAny&);
|
||||||
|
VectorOfAny& operator=(const VectorOfAny&);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename U>
|
||||||
|
Vector<Offset<T>>* VectorCast(Vector<Offset<U>>* ptr) {
|
||||||
|
static_assert(std::is_base_of<T, U>::value, "Unrelated types");
|
||||||
|
return reinterpret_cast<Vector<Offset<T>>*>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U>
|
||||||
|
const Vector<Offset<T>>* VectorCast(const Vector<Offset<U>>* ptr) {
|
||||||
|
static_assert(std::is_base_of<T, U>::value, "Unrelated types");
|
||||||
|
return reinterpret_cast<const Vector<Offset<T>>*>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convenient helper function to get the length of any vector, regardless
|
||||||
|
// of whether it is null or not (the field is not set).
|
||||||
|
template <typename T>
|
||||||
|
static inline size_t VectorLength(const Vector<T>* v) {
|
||||||
|
return v ? v->size() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_VERIFIER_H_
|
||||||
@@ -0,0 +1,298 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_VECTOR_DOWNWARD_H_
|
||||||
|
#define FLATBUFFERS_VECTOR_DOWNWARD_H_
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "flatbuffers/base.h"
|
||||||
|
#include "flatbuffers/default_allocator.h"
|
||||||
|
#include "flatbuffers/detached_buffer.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
// This is a minimal replication of std::vector<uint8_t> functionality,
|
||||||
|
// except growing from higher to lower addresses. i.e. push_back() inserts data
|
||||||
|
// in the lowest address in the vector.
|
||||||
|
// Since this vector leaves the lower part unused, we support a "scratch-pad"
|
||||||
|
// that can be stored there for temporary data, to share the allocated space.
|
||||||
|
// Essentially, this supports 2 std::vectors in a single buffer.
|
||||||
|
template <typename SizeT = uoffset_t>
|
||||||
|
class vector_downward {
|
||||||
|
public:
|
||||||
|
explicit vector_downward(size_t initial_size, Allocator* allocator,
|
||||||
|
bool own_allocator, size_t buffer_minalign,
|
||||||
|
const SizeT max_size = FLATBUFFERS_MAX_BUFFER_SIZE)
|
||||||
|
: allocator_(allocator),
|
||||||
|
own_allocator_(own_allocator),
|
||||||
|
initial_size_(initial_size),
|
||||||
|
max_size_(max_size),
|
||||||
|
buffer_minalign_(buffer_minalign),
|
||||||
|
reserved_(0),
|
||||||
|
size_(0),
|
||||||
|
buf_(nullptr),
|
||||||
|
cur_(nullptr),
|
||||||
|
scratch_(nullptr) {}
|
||||||
|
|
||||||
|
vector_downward(vector_downward&& other) noexcept
|
||||||
|
// clang-format on
|
||||||
|
: allocator_(other.allocator_),
|
||||||
|
own_allocator_(other.own_allocator_),
|
||||||
|
initial_size_(other.initial_size_),
|
||||||
|
max_size_(other.max_size_),
|
||||||
|
buffer_minalign_(other.buffer_minalign_),
|
||||||
|
reserved_(other.reserved_),
|
||||||
|
size_(other.size_),
|
||||||
|
buf_(other.buf_),
|
||||||
|
cur_(other.cur_),
|
||||||
|
scratch_(other.scratch_) {
|
||||||
|
// No change in other.allocator_
|
||||||
|
// No change in other.initial_size_
|
||||||
|
// No change in other.buffer_minalign_
|
||||||
|
other.own_allocator_ = false;
|
||||||
|
other.reserved_ = 0;
|
||||||
|
other.buf_ = nullptr;
|
||||||
|
other.cur_ = nullptr;
|
||||||
|
other.scratch_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector_downward& operator=(vector_downward&& other) noexcept {
|
||||||
|
// Move construct a temporary and swap idiom
|
||||||
|
vector_downward temp(std::move(other));
|
||||||
|
swap(temp);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~vector_downward() {
|
||||||
|
clear_buffer();
|
||||||
|
clear_allocator();
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
clear_buffer();
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
if (buf_) {
|
||||||
|
cur_ = buf_ + reserved_;
|
||||||
|
} else {
|
||||||
|
reserved_ = 0;
|
||||||
|
cur_ = nullptr;
|
||||||
|
}
|
||||||
|
size_ = 0;
|
||||||
|
clear_scratch();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_scratch() { scratch_ = buf_; }
|
||||||
|
|
||||||
|
void clear_allocator() {
|
||||||
|
if (own_allocator_ && allocator_) {
|
||||||
|
delete allocator_;
|
||||||
|
}
|
||||||
|
allocator_ = nullptr;
|
||||||
|
own_allocator_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_buffer() {
|
||||||
|
if (buf_) Deallocate(allocator_, buf_, reserved_);
|
||||||
|
buf_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Relinquish the pointer to the caller.
|
||||||
|
uint8_t* release_raw(size_t& allocated_bytes, size_t& offset) {
|
||||||
|
auto* buf = buf_;
|
||||||
|
allocated_bytes = reserved_;
|
||||||
|
offset = vector_downward::offset();
|
||||||
|
|
||||||
|
// release_raw only relinquishes the buffer ownership.
|
||||||
|
// Does not deallocate or reset the allocator. Destructor will do that.
|
||||||
|
buf_ = nullptr;
|
||||||
|
clear();
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Relinquish the pointer to the caller.
|
||||||
|
DetachedBuffer release() {
|
||||||
|
// allocator ownership (if any) is transferred to DetachedBuffer.
|
||||||
|
DetachedBuffer fb(allocator_, own_allocator_, buf_, reserved_, cur_,
|
||||||
|
size());
|
||||||
|
if (own_allocator_) {
|
||||||
|
allocator_ = nullptr;
|
||||||
|
own_allocator_ = false;
|
||||||
|
}
|
||||||
|
buf_ = nullptr;
|
||||||
|
clear();
|
||||||
|
return fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ensure_space(size_t len) {
|
||||||
|
FLATBUFFERS_ASSERT(cur_ >= scratch_ && scratch_ >= buf_);
|
||||||
|
// If the length is larger than the unused part of the buffer, we need to
|
||||||
|
// grow.
|
||||||
|
if (len > unused_buffer_size()) {
|
||||||
|
reallocate(len);
|
||||||
|
}
|
||||||
|
FLATBUFFERS_ASSERT(size() < max_size_);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint8_t* make_space(size_t len) {
|
||||||
|
if (len) {
|
||||||
|
ensure_space(len);
|
||||||
|
cur_ -= len;
|
||||||
|
size_ += static_cast<SizeT>(len);
|
||||||
|
}
|
||||||
|
return cur_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns nullptr if using the DefaultAllocator.
|
||||||
|
Allocator* get_custom_allocator() { return allocator_; }
|
||||||
|
|
||||||
|
// The current offset into the buffer.
|
||||||
|
size_t offset() const { return cur_ - buf_; }
|
||||||
|
|
||||||
|
// The total size of the vector (both the buffer and scratch parts).
|
||||||
|
inline SizeT size() const { return size_; }
|
||||||
|
|
||||||
|
// The size of the buffer part of the vector that is currently unused.
|
||||||
|
SizeT unused_buffer_size() const {
|
||||||
|
return static_cast<SizeT>(cur_ - scratch_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The size of the scratch part of the vector.
|
||||||
|
SizeT scratch_size() const { return static_cast<SizeT>(scratch_ - buf_); }
|
||||||
|
|
||||||
|
size_t capacity() const { return reserved_; }
|
||||||
|
|
||||||
|
uint8_t* data() const {
|
||||||
|
FLATBUFFERS_ASSERT(cur_);
|
||||||
|
return cur_;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* scratch_data() const {
|
||||||
|
FLATBUFFERS_ASSERT(buf_);
|
||||||
|
return buf_;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* scratch_end() const {
|
||||||
|
FLATBUFFERS_ASSERT(scratch_);
|
||||||
|
return scratch_;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* data_at(size_t offset) const { return buf_ + reserved_ - offset; }
|
||||||
|
|
||||||
|
void push(const uint8_t* bytes, size_t num) {
|
||||||
|
if (num > 0) {
|
||||||
|
memcpy(make_space(num), bytes, num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specialized version of push() that avoids memcpy call for small data.
|
||||||
|
template <typename T>
|
||||||
|
void push_small(const T& little_endian_t) {
|
||||||
|
make_space(sizeof(T));
|
||||||
|
*reinterpret_cast<T*>(cur_) = little_endian_t;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void scratch_push_small(const T& t) {
|
||||||
|
ensure_space(sizeof(T));
|
||||||
|
*reinterpret_cast<T*>(scratch_) = t;
|
||||||
|
scratch_ += sizeof(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fill() is most frequently called with small byte counts (<= 4),
|
||||||
|
// which is why we're using loops rather than calling memset.
|
||||||
|
void fill(size_t zero_pad_bytes) {
|
||||||
|
make_space(zero_pad_bytes);
|
||||||
|
for (size_t i = 0; i < zero_pad_bytes; i++) cur_[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version for when we know the size is larger.
|
||||||
|
// Precondition: zero_pad_bytes > 0
|
||||||
|
void fill_big(size_t zero_pad_bytes) {
|
||||||
|
memset(make_space(zero_pad_bytes), 0, zero_pad_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop(size_t bytes_to_remove) {
|
||||||
|
cur_ += bytes_to_remove;
|
||||||
|
size_ -= static_cast<SizeT>(bytes_to_remove);
|
||||||
|
}
|
||||||
|
|
||||||
|
void scratch_pop(size_t bytes_to_remove) { scratch_ -= bytes_to_remove; }
|
||||||
|
|
||||||
|
void swap(vector_downward& other) {
|
||||||
|
using std::swap;
|
||||||
|
swap(allocator_, other.allocator_);
|
||||||
|
swap(own_allocator_, other.own_allocator_);
|
||||||
|
swap(initial_size_, other.initial_size_);
|
||||||
|
swap(buffer_minalign_, other.buffer_minalign_);
|
||||||
|
swap(reserved_, other.reserved_);
|
||||||
|
swap(size_, other.size_);
|
||||||
|
swap(max_size_, other.max_size_);
|
||||||
|
swap(buf_, other.buf_);
|
||||||
|
swap(cur_, other.cur_);
|
||||||
|
swap(scratch_, other.scratch_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap_allocator(vector_downward& other) {
|
||||||
|
using std::swap;
|
||||||
|
swap(allocator_, other.allocator_);
|
||||||
|
swap(own_allocator_, other.own_allocator_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// You shouldn't really be copying instances of this class.
|
||||||
|
FLATBUFFERS_DELETE_FUNC(vector_downward(const vector_downward&));
|
||||||
|
FLATBUFFERS_DELETE_FUNC(vector_downward& operator=(const vector_downward&));
|
||||||
|
|
||||||
|
Allocator* allocator_;
|
||||||
|
bool own_allocator_;
|
||||||
|
size_t initial_size_;
|
||||||
|
|
||||||
|
// The maximum size the vector can be.
|
||||||
|
SizeT max_size_;
|
||||||
|
size_t buffer_minalign_;
|
||||||
|
size_t reserved_;
|
||||||
|
SizeT size_;
|
||||||
|
uint8_t* buf_;
|
||||||
|
uint8_t* cur_; // Points at location between empty (below) and used (above).
|
||||||
|
uint8_t* scratch_; // Points to the end of the scratchpad in use.
|
||||||
|
|
||||||
|
void reallocate(size_t len) {
|
||||||
|
auto old_reserved = reserved_;
|
||||||
|
auto old_size = size();
|
||||||
|
auto old_scratch_size = scratch_size();
|
||||||
|
reserved_ +=
|
||||||
|
(std::max)(len, old_reserved ? old_reserved / 2 : initial_size_);
|
||||||
|
reserved_ = (reserved_ + buffer_minalign_ - 1) & ~(buffer_minalign_ - 1);
|
||||||
|
if (buf_) {
|
||||||
|
buf_ = ReallocateDownward(allocator_, buf_, old_reserved, reserved_,
|
||||||
|
old_size, old_scratch_size);
|
||||||
|
} else {
|
||||||
|
buf_ = Allocate(allocator_, reserved_);
|
||||||
|
}
|
||||||
|
cur_ = buf_ + reserved_ - old_size;
|
||||||
|
scratch_ = buf_ + old_scratch_size;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_VECTOR_DOWNWARD_H_
|
||||||
@@ -0,0 +1,370 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_VERIFIER_H_
|
||||||
|
#define FLATBUFFERS_VERIFIER_H_
|
||||||
|
|
||||||
|
#include "flatbuffers/base.h"
|
||||||
|
#include "flatbuffers/vector.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
// Helper class to verify the integrity of a FlatBuffer
|
||||||
|
template <bool TrackVerifierBufferSize>
|
||||||
|
class VerifierTemplate FLATBUFFERS_FINAL_CLASS {
|
||||||
|
public:
|
||||||
|
struct Options {
|
||||||
|
// The maximum nesting of tables and vectors before we call it invalid.
|
||||||
|
uoffset_t max_depth = 64;
|
||||||
|
// The maximum number of tables we will verify before we call it invalid.
|
||||||
|
uoffset_t max_tables = 1000000;
|
||||||
|
// If true, verify all data is aligned.
|
||||||
|
bool check_alignment = true;
|
||||||
|
// If true, run verifier on nested flatbuffers
|
||||||
|
bool check_nested_flatbuffers = true;
|
||||||
|
// The maximum size of a buffer.
|
||||||
|
size_t max_size = FLATBUFFERS_MAX_BUFFER_SIZE;
|
||||||
|
// Use assertions to check for errors.
|
||||||
|
bool assert = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit VerifierTemplate(const uint8_t* const buf, const size_t buf_len,
|
||||||
|
const Options& opts)
|
||||||
|
: buf_(buf), size_(buf_len), opts_(opts) {
|
||||||
|
FLATBUFFERS_ASSERT(size_ < opts.max_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated API, please construct with VerifierTemplate::Options.
|
||||||
|
VerifierTemplate(const uint8_t* const buf, const size_t buf_len,
|
||||||
|
const uoffset_t max_depth = 64,
|
||||||
|
const uoffset_t max_tables = 1000000,
|
||||||
|
const bool check_alignment = true)
|
||||||
|
: VerifierTemplate(buf, buf_len, [&] {
|
||||||
|
Options opts;
|
||||||
|
opts.max_depth = max_depth;
|
||||||
|
opts.max_tables = max_tables;
|
||||||
|
opts.check_alignment = check_alignment;
|
||||||
|
return opts;
|
||||||
|
}()) {}
|
||||||
|
|
||||||
|
// Central location where any verification failures register.
|
||||||
|
bool Check(const bool ok) const {
|
||||||
|
// clang-format off
|
||||||
|
#ifdef FLATBUFFERS_DEBUG_VERIFICATION_FAILURE
|
||||||
|
if (opts_.assert) { FLATBUFFERS_ASSERT(ok); }
|
||||||
|
#endif
|
||||||
|
// clang-format on
|
||||||
|
if (TrackVerifierBufferSize) {
|
||||||
|
if (!ok) {
|
||||||
|
upper_bound_ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify any range within the buffer.
|
||||||
|
bool Verify(const size_t elem, const size_t elem_len) const {
|
||||||
|
if (TrackVerifierBufferSize) {
|
||||||
|
auto upper_bound = elem + elem_len;
|
||||||
|
if (upper_bound_ < upper_bound) {
|
||||||
|
upper_bound_ = upper_bound;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Check(elem_len < size_ && elem <= size_ - elem_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VerifyAlignment(const size_t elem, const size_t align) const {
|
||||||
|
return Check((elem & (align - 1)) == 0 || !opts_.check_alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify a range indicated by sizeof(T).
|
||||||
|
template <typename T>
|
||||||
|
bool Verify(const size_t elem) const {
|
||||||
|
return VerifyAlignment(elem, sizeof(T)) && Verify(elem, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VerifyFromPointer(const uint8_t* const p, const size_t len) {
|
||||||
|
return Verify(static_cast<size_t>(p - buf_), len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify relative to a known-good base pointer.
|
||||||
|
bool VerifyFieldStruct(const uint8_t* const base, const voffset_t elem_off,
|
||||||
|
const size_t elem_len, const size_t align) const {
|
||||||
|
const auto f = static_cast<size_t>(base - buf_) + elem_off;
|
||||||
|
return VerifyAlignment(f, align) && Verify(f, elem_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool VerifyField(const uint8_t* const base, const voffset_t elem_off,
|
||||||
|
const size_t align) const {
|
||||||
|
const auto f = static_cast<size_t>(base - buf_) + elem_off;
|
||||||
|
return VerifyAlignment(f, align) && Verify(f, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify a pointer (may be NULL) of a table type.
|
||||||
|
template <typename T>
|
||||||
|
bool VerifyTable(const T* const table) {
|
||||||
|
return !table || table->Verify(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify a pointer (may be NULL) of any vector type.
|
||||||
|
template <int&..., typename T, typename LenT>
|
||||||
|
bool VerifyVector(const Vector<T, LenT>* const vec) const {
|
||||||
|
return !vec || VerifyVectorOrString<LenT>(
|
||||||
|
reinterpret_cast<const uint8_t*>(vec), sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify a pointer (may be NULL) of a vector to struct.
|
||||||
|
template <int&..., typename T, typename LenT>
|
||||||
|
bool VerifyVector(const Vector<const T*, LenT>* const vec) const {
|
||||||
|
return VerifyVector(reinterpret_cast<const Vector<T, LenT>*>(vec));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify a pointer (may be NULL) to string.
|
||||||
|
bool VerifyString(const String* const str) const {
|
||||||
|
size_t end;
|
||||||
|
return !str || (VerifyVectorOrString<uoffset_t>(
|
||||||
|
reinterpret_cast<const uint8_t*>(str), 1, &end) &&
|
||||||
|
Verify(end, 1) && // Must have terminator
|
||||||
|
Check(buf_[end] == '\0')); // Terminating byte must be 0.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Common code between vectors and strings.
|
||||||
|
template <typename LenT = uoffset_t>
|
||||||
|
bool VerifyVectorOrString(const uint8_t* const vec, const size_t elem_size,
|
||||||
|
size_t* const end = nullptr) const {
|
||||||
|
const auto vec_offset = static_cast<size_t>(vec - buf_);
|
||||||
|
// Check we can read the size field.
|
||||||
|
if (!Verify<LenT>(vec_offset)) return false;
|
||||||
|
// Check the whole array. If this is a string, the byte past the array must
|
||||||
|
// be 0.
|
||||||
|
const LenT size = ReadScalar<LenT>(vec);
|
||||||
|
const auto max_elems = opts_.max_size / elem_size;
|
||||||
|
if (!Check(size < max_elems))
|
||||||
|
return false; // Protect against byte_size overflowing.
|
||||||
|
const auto byte_size = sizeof(LenT) + elem_size * size;
|
||||||
|
if (end) *end = vec_offset + byte_size;
|
||||||
|
return Verify(vec_offset, byte_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special case for string contents, after the above has been called.
|
||||||
|
bool VerifyVectorOfStrings(const Vector<Offset<String>>* const vec) const {
|
||||||
|
if (vec) {
|
||||||
|
for (uoffset_t i = 0; i < vec->size(); i++) {
|
||||||
|
if (!VerifyString(vec->Get(i))) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special case for table contents, after the above has been called.
|
||||||
|
template <typename T>
|
||||||
|
bool VerifyVectorOfTables(const Vector<Offset<T>>* const vec) {
|
||||||
|
if (vec) {
|
||||||
|
for (uoffset_t i = 0; i < vec->size(); i++) {
|
||||||
|
if (!vec->Get(i)->Verify(*this)) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
FLATBUFFERS_SUPPRESS_UBSAN("unsigned-integer-overflow")
|
||||||
|
bool VerifyTableStart(const uint8_t* const table) {
|
||||||
|
// Check the vtable offset.
|
||||||
|
const auto tableo = static_cast<size_t>(table - buf_);
|
||||||
|
if (!Verify<soffset_t>(tableo)) return false;
|
||||||
|
// This offset may be signed, but doing the subtraction unsigned always
|
||||||
|
// gives the result we want.
|
||||||
|
const auto vtableo =
|
||||||
|
tableo - static_cast<size_t>(ReadScalar<soffset_t>(table));
|
||||||
|
// Check the vtable size field, then check vtable fits in its entirety.
|
||||||
|
if (!(VerifyComplexity() && Verify<voffset_t>(vtableo) &&
|
||||||
|
VerifyAlignment(ReadScalar<voffset_t>(buf_ + vtableo),
|
||||||
|
sizeof(voffset_t))))
|
||||||
|
return false;
|
||||||
|
const auto vsize = ReadScalar<voffset_t>(buf_ + vtableo);
|
||||||
|
return Check((vsize & 1) == 0) && Verify(vtableo, vsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool VerifyBufferFromStart(const char* const identifier, const size_t start) {
|
||||||
|
// Buffers have to be of some size to be valid. The reason it is a runtime
|
||||||
|
// check instead of static_assert, is that nested flatbuffers go through
|
||||||
|
// this call and their size is determined at runtime.
|
||||||
|
if (!Check(size_ >= FLATBUFFERS_MIN_BUFFER_SIZE)) return false;
|
||||||
|
|
||||||
|
// If an identifier is provided, check that we have a buffer
|
||||||
|
if (identifier && !Check((size_ >= 2 * sizeof(flatbuffers::uoffset_t) &&
|
||||||
|
BufferHasIdentifier(buf_ + start, identifier)))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call T::Verify, which must be in the generated code for this type.
|
||||||
|
const auto o = VerifyOffset<uoffset_t>(start);
|
||||||
|
if (!Check(o != 0)) return false;
|
||||||
|
if (!(reinterpret_cast<const T*>(buf_ + start + o)->Verify(*this))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (TrackVerifierBufferSize) {
|
||||||
|
if (GetComputedSize() == 0) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, int&..., typename SizeT>
|
||||||
|
bool VerifyNestedFlatBuffer(const Vector<uint8_t, SizeT>* const buf,
|
||||||
|
const char* const identifier) {
|
||||||
|
// Caller opted out of this.
|
||||||
|
if (!opts_.check_nested_flatbuffers) return true;
|
||||||
|
|
||||||
|
// An empty buffer is OK as it indicates not present.
|
||||||
|
if (!buf) return true;
|
||||||
|
|
||||||
|
// If there is a nested buffer, it must be greater than the min size.
|
||||||
|
if (!Check(buf->size() >= FLATBUFFERS_MIN_BUFFER_SIZE)) return false;
|
||||||
|
|
||||||
|
VerifierTemplate<TrackVerifierBufferSize> nested_verifier(
|
||||||
|
buf->data(), buf->size(), opts_);
|
||||||
|
return nested_verifier.VerifyBuffer<T>(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify this whole buffer, starting with root type T.
|
||||||
|
template <typename T>
|
||||||
|
bool VerifyBuffer() {
|
||||||
|
return VerifyBuffer<T>(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool VerifyBuffer(const char* const identifier) {
|
||||||
|
return VerifyBufferFromStart<T>(identifier, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename SizeT = uoffset_t>
|
||||||
|
bool VerifySizePrefixedBuffer(const char* const identifier) {
|
||||||
|
return Verify<SizeT>(0U) &&
|
||||||
|
// Ensure the prefixed size is within the bounds of the provided
|
||||||
|
// length.
|
||||||
|
Check(ReadScalar<SizeT>(buf_) + sizeof(SizeT) <= size_) &&
|
||||||
|
VerifyBufferFromStart<T>(identifier, sizeof(SizeT));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OffsetT = uoffset_t, typename SOffsetT = soffset_t>
|
||||||
|
size_t VerifyOffset(const size_t start) const {
|
||||||
|
if (!Verify<OffsetT>(start)) return 0;
|
||||||
|
const auto o = ReadScalar<OffsetT>(buf_ + start);
|
||||||
|
// May not point to itself.
|
||||||
|
if (!Check(o != 0)) return 0;
|
||||||
|
// Can't wrap around larger than the max size.
|
||||||
|
if (!Check(static_cast<SOffsetT>(o) >= 0)) return 0;
|
||||||
|
// Must be inside the buffer to create a pointer from it (pointer outside
|
||||||
|
// buffer is UB).
|
||||||
|
if (!Verify(start + o, 1)) return 0;
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OffsetT = uoffset_t>
|
||||||
|
size_t VerifyOffset(const uint8_t* const base, const voffset_t start) const {
|
||||||
|
return VerifyOffset<OffsetT>(static_cast<size_t>(base - buf_) + start);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called at the start of a table to increase counters measuring data
|
||||||
|
// structure depth and amount, and possibly bails out with false if limits set
|
||||||
|
// by the constructor have been hit. Needs to be balanced with EndTable().
|
||||||
|
bool VerifyComplexity() {
|
||||||
|
depth_++;
|
||||||
|
num_tables_++;
|
||||||
|
return Check(depth_ <= opts_.max_depth && num_tables_ <= opts_.max_tables);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called at the end of a table to pop the depth count.
|
||||||
|
bool EndTable() {
|
||||||
|
depth_--;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the message size in bytes.
|
||||||
|
//
|
||||||
|
// This should only be called after first calling VerifyBuffer or
|
||||||
|
// VerifySizePrefixedBuffer.
|
||||||
|
//
|
||||||
|
// This method should only be called for VerifierTemplate instances
|
||||||
|
// where the TrackVerifierBufferSize template parameter is true,
|
||||||
|
// i.e. for SizeVerifier. For instances where TrackVerifierBufferSize
|
||||||
|
// is false, this fails at runtime or returns zero.
|
||||||
|
size_t GetComputedSize() const {
|
||||||
|
if (TrackVerifierBufferSize) {
|
||||||
|
uintptr_t size = upper_bound_;
|
||||||
|
// Align the size to uoffset_t
|
||||||
|
size = (size - 1 + sizeof(uoffset_t)) & ~(sizeof(uoffset_t) - 1);
|
||||||
|
return (size > size_) ? 0 : size;
|
||||||
|
}
|
||||||
|
// Must use SizeVerifier, or (deprecated) turn on
|
||||||
|
// FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE, for this to work.
|
||||||
|
(void)upper_bound_;
|
||||||
|
FLATBUFFERS_ASSERT(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t>* GetFlexReuseTracker() { return flex_reuse_tracker_; }
|
||||||
|
|
||||||
|
void SetFlexReuseTracker(std::vector<uint8_t>* const rt) {
|
||||||
|
flex_reuse_tracker_ = rt;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const uint8_t* buf_;
|
||||||
|
const size_t size_;
|
||||||
|
const Options opts_;
|
||||||
|
|
||||||
|
mutable size_t upper_bound_ = 0;
|
||||||
|
|
||||||
|
uoffset_t depth_ = 0;
|
||||||
|
uoffset_t num_tables_ = 0;
|
||||||
|
std::vector<uint8_t>* flex_reuse_tracker_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Specialization for 64-bit offsets.
|
||||||
|
template <>
|
||||||
|
template <>
|
||||||
|
inline size_t VerifierTemplate<false>::VerifyOffset<uoffset64_t>(
|
||||||
|
const size_t start) const {
|
||||||
|
return VerifyOffset<uoffset64_t, soffset64_t>(start);
|
||||||
|
}
|
||||||
|
template <>
|
||||||
|
template <>
|
||||||
|
inline size_t VerifierTemplate<true>::VerifyOffset<uoffset64_t>(
|
||||||
|
const size_t start) const {
|
||||||
|
return VerifyOffset<uoffset64_t, soffset64_t>(start);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instance of VerifierTemplate that supports GetComputedSize().
|
||||||
|
using SizeVerifier = VerifierTemplate</*TrackVerifierBufferSize = */ true>;
|
||||||
|
|
||||||
|
// The FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE build configuration macro is
|
||||||
|
// deprecated, and should not be defined, since it is easy to misuse in ways
|
||||||
|
// that result in ODR violations. Rather than using Verifier and defining
|
||||||
|
// FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE, please use SizeVerifier instead.
|
||||||
|
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE // Deprecated, see above.
|
||||||
|
using Verifier = SizeVerifier;
|
||||||
|
#else
|
||||||
|
// Instance of VerifierTemplate that is slightly faster, but does not
|
||||||
|
// support GetComputedSize().
|
||||||
|
using Verifier = VerifierTemplate</*TrackVerifierBufferSize = */ false>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_VERIFIER_H_
|
||||||
+492
@@ -0,0 +1,492 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
// Dont't remove `format off`, it prevent reordering of win-includes.
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#if defined(__MINGW32__) || defined(__MINGW64__) || defined(__CYGWIN__) || \
|
||||||
|
defined(__QNXNTO__)
|
||||||
|
# define _POSIX_C_SOURCE 200809L
|
||||||
|
# define _XOPEN_SOURCE 700L
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) || defined(__CYGWIN__)
|
||||||
|
# ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
# endif
|
||||||
|
# ifndef NOMINMAX
|
||||||
|
# define NOMINMAX
|
||||||
|
# endif
|
||||||
|
# ifdef _MSC_VER
|
||||||
|
# include <crtdbg.h>
|
||||||
|
# endif
|
||||||
|
# include <windows.h> // Must be included before <direct.h>
|
||||||
|
# ifndef __CYGWIN__
|
||||||
|
# include <direct.h>
|
||||||
|
# endif
|
||||||
|
# include <winbase.h>
|
||||||
|
# undef interface // This is also important because of reasons
|
||||||
|
#endif
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#include "flatbuffers/util.h"
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <clocale>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <fstream>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include "flatbuffers/base.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
static bool FileExistsRaw(const char* name) {
|
||||||
|
std::ifstream ifs(name);
|
||||||
|
return ifs.good();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool LoadFileRaw(const char* name, bool binary, std::string* buf) {
|
||||||
|
if (DirExists(name)) return false;
|
||||||
|
std::ifstream ifs(name, binary ? std::ifstream::binary : std::ifstream::in);
|
||||||
|
if (!ifs.is_open()) return false;
|
||||||
|
if (binary) {
|
||||||
|
// The fastest way to read a file into a string.
|
||||||
|
ifs.seekg(0, std::ios::end);
|
||||||
|
auto size = ifs.tellg();
|
||||||
|
(*buf).resize(static_cast<size_t>(size));
|
||||||
|
ifs.seekg(0, std::ios::beg);
|
||||||
|
ifs.read(&(*buf)[0], (*buf).size());
|
||||||
|
} else {
|
||||||
|
// This is slower, but works correctly on all platforms for text files.
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << ifs.rdbuf();
|
||||||
|
*buf = oss.str();
|
||||||
|
}
|
||||||
|
return !ifs.bad();
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadFileFunction g_load_file_function = LoadFileRaw;
|
||||||
|
FileExistsFunction g_file_exists_function = FileExistsRaw;
|
||||||
|
|
||||||
|
static std::string ToCamelCase(const std::string& input, bool is_upper) {
|
||||||
|
std::string s;
|
||||||
|
for (size_t i = 0; i < input.length(); i++) {
|
||||||
|
if (!i && input[i] == '_') {
|
||||||
|
s += input[i];
|
||||||
|
// we ignore leading underscore but make following
|
||||||
|
// alphabet char upper.
|
||||||
|
if (i + 1 < input.length() && is_alpha(input[i + 1]))
|
||||||
|
s += CharToUpper(input[++i]);
|
||||||
|
} else if (!i)
|
||||||
|
s += is_upper ? CharToUpper(input[i]) : CharToLower(input[i]);
|
||||||
|
else if (input[i] == '_' && i + 1 < input.length())
|
||||||
|
s += CharToUpper(input[++i]);
|
||||||
|
else
|
||||||
|
s += input[i];
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string ToSnakeCase(const std::string& input, bool screaming) {
|
||||||
|
std::string s;
|
||||||
|
for (size_t i = 0; i < input.length(); i++) {
|
||||||
|
if (i == 0) {
|
||||||
|
s += screaming ? CharToUpper(input[i]) : CharToLower(input[i]);
|
||||||
|
} else if (input[i] == '_') {
|
||||||
|
s += '_';
|
||||||
|
} else if (!islower(input[i])) {
|
||||||
|
// Prevent duplicate underscores for Upper_Snake_Case strings
|
||||||
|
// and UPPERCASE strings.
|
||||||
|
if (islower(input[i - 1]) ||
|
||||||
|
(isdigit(input[i - 1]) && !isdigit(input[i]))) {
|
||||||
|
s += '_';
|
||||||
|
}
|
||||||
|
s += screaming ? CharToUpper(input[i]) : CharToLower(input[i]);
|
||||||
|
} else {
|
||||||
|
s += screaming ? CharToUpper(input[i]) : input[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ToAll(const std::string& input,
|
||||||
|
std::function<char(const char)> transform) {
|
||||||
|
std::string s;
|
||||||
|
for (size_t i = 0; i < input.length(); i++) {
|
||||||
|
s += transform(input[i]);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CamelToSnake(const std::string& input) {
|
||||||
|
std::string s;
|
||||||
|
for (size_t i = 0; i < input.length(); i++) {
|
||||||
|
if (i == 0) {
|
||||||
|
s += CharToLower(input[i]);
|
||||||
|
} else if (input[i] == '_') {
|
||||||
|
s += '_';
|
||||||
|
} else if (!islower(input[i])) {
|
||||||
|
// Prevent duplicate underscores for Upper_Snake_Case strings
|
||||||
|
// and UPPERCASE strings.
|
||||||
|
if (islower(input[i - 1]) ||
|
||||||
|
(isdigit(input[i - 1]) && !isdigit(input[i]))) {
|
||||||
|
s += '_';
|
||||||
|
}
|
||||||
|
s += CharToLower(input[i]);
|
||||||
|
} else {
|
||||||
|
s += input[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string DasherToSnake(const std::string& input) {
|
||||||
|
std::string s;
|
||||||
|
for (size_t i = 0; i < input.length(); i++) {
|
||||||
|
if (input[i] == '-') {
|
||||||
|
s += "_";
|
||||||
|
} else {
|
||||||
|
s += input[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ToDasher(const std::string& input) {
|
||||||
|
std::string s;
|
||||||
|
char p = 0;
|
||||||
|
for (size_t i = 0; i < input.length(); i++) {
|
||||||
|
char const& c = input[i];
|
||||||
|
if (c == '_') {
|
||||||
|
if (i > 0 && p != kPathSeparator &&
|
||||||
|
// The following is a special case to ignore digits after a _. This is
|
||||||
|
// because ThisExample3 would be converted to this_example_3 in the
|
||||||
|
// CamelToSnake conversion, and then dasher would do this-example-3,
|
||||||
|
// but it expects this-example3.
|
||||||
|
!(i + 1 < input.length() && isdigit(input[i + 1])))
|
||||||
|
s += "-";
|
||||||
|
} else {
|
||||||
|
s += c;
|
||||||
|
}
|
||||||
|
p = c;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts foo_bar_123baz_456 to foo_bar123_baz456
|
||||||
|
std::string SnakeToSnake2(const std::string& s) {
|
||||||
|
if (s.length() <= 1) return s;
|
||||||
|
std::string result;
|
||||||
|
result.reserve(s.size());
|
||||||
|
for (size_t i = 0; i < s.length() - 1; i++) {
|
||||||
|
if (s[i] == '_' && isdigit(s[i + 1])) {
|
||||||
|
continue; // Move the `_` until after the digits.
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push_back(s[i]);
|
||||||
|
|
||||||
|
if (isdigit(s[i]) && isalpha(s[i + 1]) && islower(s[i + 1])) {
|
||||||
|
result.push_back('_');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.push_back(s.back());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool LoadFile(const char* name, bool binary, std::string* buf) {
|
||||||
|
FLATBUFFERS_ASSERT(g_load_file_function);
|
||||||
|
return g_load_file_function(name, binary, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileExists(const char* name) {
|
||||||
|
FLATBUFFERS_ASSERT(g_file_exists_function);
|
||||||
|
return g_file_exists_function(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DirExists(const char* name) {
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define flatbuffers_stat _stat
|
||||||
|
#define FLATBUFFERS_S_IFDIR _S_IFDIR
|
||||||
|
#else
|
||||||
|
#define flatbuffers_stat stat
|
||||||
|
#define FLATBUFFERS_S_IFDIR S_IFDIR
|
||||||
|
#endif
|
||||||
|
// clang-format on
|
||||||
|
struct flatbuffers_stat file_info;
|
||||||
|
if (flatbuffers_stat(name, &file_info) != 0) return false;
|
||||||
|
return (file_info.st_mode & FLATBUFFERS_S_IFDIR) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadFileFunction SetLoadFileFunction(LoadFileFunction load_file_function) {
|
||||||
|
LoadFileFunction previous_function = g_load_file_function;
|
||||||
|
g_load_file_function = load_file_function ? load_file_function : LoadFileRaw;
|
||||||
|
return previous_function;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileExistsFunction SetFileExistsFunction(
|
||||||
|
FileExistsFunction file_exists_function) {
|
||||||
|
FileExistsFunction previous_function = g_file_exists_function;
|
||||||
|
g_file_exists_function =
|
||||||
|
file_exists_function ? file_exists_function : FileExistsRaw;
|
||||||
|
return previous_function;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SaveFile(const char* name, const char* buf, size_t len, bool binary) {
|
||||||
|
std::ofstream ofs(name, binary ? std::ofstream::binary : std::ofstream::out);
|
||||||
|
if (!ofs.is_open()) return false;
|
||||||
|
ofs.write(buf, len);
|
||||||
|
return !ofs.bad();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We internally store paths in posix format ('/'). Paths supplied
|
||||||
|
// by the user should go through PosixPath to ensure correct behavior
|
||||||
|
// on Windows when paths are string-compared.
|
||||||
|
|
||||||
|
static const char kPathSeparatorWindows = '\\';
|
||||||
|
static const char* PathSeparatorSet = "\\/"; // Intentionally no ':'
|
||||||
|
|
||||||
|
std::string StripExtension(const std::string& filepath) {
|
||||||
|
size_t i = filepath.find_last_of('.');
|
||||||
|
return i != std::string::npos ? filepath.substr(0, i) : filepath;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetExtension(const std::string& filepath) {
|
||||||
|
size_t i = filepath.find_last_of('.');
|
||||||
|
return i != std::string::npos ? filepath.substr(i + 1) : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string StripPath(const std::string& filepath) {
|
||||||
|
size_t i = filepath.find_last_of(PathSeparatorSet);
|
||||||
|
return i != std::string::npos ? filepath.substr(i + 1) : filepath;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string StripFileName(const std::string& filepath) {
|
||||||
|
size_t i = filepath.find_last_of(PathSeparatorSet);
|
||||||
|
return i != std::string::npos ? filepath.substr(0, i) : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string StripPrefix(const std::string& filepath,
|
||||||
|
const std::string& prefix_to_remove) {
|
||||||
|
if (!strncmp(filepath.c_str(), prefix_to_remove.c_str(),
|
||||||
|
prefix_to_remove.size())) {
|
||||||
|
return filepath.substr(prefix_to_remove.size());
|
||||||
|
}
|
||||||
|
return filepath;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ConCatPathFileName(const std::string& path,
|
||||||
|
const std::string& filename) {
|
||||||
|
std::string filepath = path;
|
||||||
|
if (filepath.length()) {
|
||||||
|
char& filepath_last_character = filepath.back();
|
||||||
|
if (filepath_last_character == kPathSeparatorWindows) {
|
||||||
|
filepath_last_character = kPathSeparator;
|
||||||
|
} else if (filepath_last_character != kPathSeparator) {
|
||||||
|
filepath += kPathSeparator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filepath += filename;
|
||||||
|
// Ignore './' at the start of filepath.
|
||||||
|
if (filepath[0] == '.' && filepath[1] == kPathSeparator) {
|
||||||
|
filepath.erase(0, 2);
|
||||||
|
}
|
||||||
|
return filepath;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PosixPath(const char* path) {
|
||||||
|
std::string p = path;
|
||||||
|
std::replace(p.begin(), p.end(), '\\', '/');
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
std::string PosixPath(const std::string& path) {
|
||||||
|
return PosixPath(path.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnsureDirExists(const std::string& filepath) {
|
||||||
|
auto parent = StripFileName(filepath);
|
||||||
|
if (parent.length()) EnsureDirExists(parent);
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
(void)_mkdir(filepath.c_str());
|
||||||
|
#else
|
||||||
|
mkdir(filepath.c_str(), S_IRWXU|S_IRGRP|S_IXGRP);
|
||||||
|
#endif
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string FilePath(const std::string& project, const std::string& filePath,
|
||||||
|
bool absolute) {
|
||||||
|
return (absolute) ? AbsolutePath(filePath)
|
||||||
|
: RelativeToRootPath(project, filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AbsolutePath(const std::string& filepath) {
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
#ifdef FLATBUFFERS_NO_ABSOLUTE_PATH_RESOLUTION
|
||||||
|
return filepath;
|
||||||
|
#else
|
||||||
|
#if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) || defined(__CYGWIN__)
|
||||||
|
char abs_path[MAX_PATH];
|
||||||
|
return GetFullPathNameA(filepath.c_str(), MAX_PATH, abs_path, nullptr)
|
||||||
|
#else
|
||||||
|
char *abs_path_temp = realpath(filepath.c_str(), nullptr);
|
||||||
|
bool success = abs_path_temp != nullptr;
|
||||||
|
std::string abs_path;
|
||||||
|
if(success) {
|
||||||
|
abs_path = abs_path_temp;
|
||||||
|
free(abs_path_temp);
|
||||||
|
}
|
||||||
|
return success
|
||||||
|
#endif
|
||||||
|
? abs_path
|
||||||
|
: filepath;
|
||||||
|
#endif // FLATBUFFERS_NO_ABSOLUTE_PATH_RESOLUTION
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string RelativeToRootPath(const std::string& project,
|
||||||
|
const std::string& filepath) {
|
||||||
|
std::string absolute_project = PosixPath(AbsolutePath(project));
|
||||||
|
if (absolute_project.back() != '/') absolute_project += "/";
|
||||||
|
std::string absolute_filepath = PosixPath(AbsolutePath(filepath));
|
||||||
|
|
||||||
|
// Find the first character where they disagree.
|
||||||
|
// The previous directory is the lowest common ancestor;
|
||||||
|
const char* a = absolute_project.c_str();
|
||||||
|
const char* b = absolute_filepath.c_str();
|
||||||
|
size_t common_prefix_len = 0;
|
||||||
|
while (*a != '\0' && *b != '\0' && *a == *b) {
|
||||||
|
if (*a == '/') common_prefix_len = a - absolute_project.c_str();
|
||||||
|
a++;
|
||||||
|
b++;
|
||||||
|
}
|
||||||
|
// the number of ../ to prepend to b depends on the number of remaining
|
||||||
|
// directories in A.
|
||||||
|
const char* suffix = absolute_project.c_str() + common_prefix_len;
|
||||||
|
size_t num_up = 0;
|
||||||
|
while (*suffix != '\0')
|
||||||
|
if (*suffix++ == '/') num_up++;
|
||||||
|
num_up--; // last one is known to be '/'.
|
||||||
|
std::string result = "//";
|
||||||
|
for (size_t i = 0; i < num_up; i++) result += "../";
|
||||||
|
result += absolute_filepath.substr(common_prefix_len + 1);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locale-independent code.
|
||||||
|
#if defined(FLATBUFFERS_LOCALE_INDEPENDENT) && \
|
||||||
|
(FLATBUFFERS_LOCALE_INDEPENDENT > 0)
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
// Allocate locale instance at startup of application.
|
||||||
|
ClassicLocale ClassicLocale::instance_;
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
ClassicLocale::ClassicLocale()
|
||||||
|
: locale_(_create_locale(LC_ALL, "C")) {}
|
||||||
|
ClassicLocale::~ClassicLocale() { _free_locale(locale_); }
|
||||||
|
#else
|
||||||
|
ClassicLocale::ClassicLocale()
|
||||||
|
: locale_(newlocale(LC_ALL, "C", nullptr)) {}
|
||||||
|
ClassicLocale::~ClassicLocale() { freelocale(locale_); }
|
||||||
|
#endif
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#endif // !FLATBUFFERS_LOCALE_INDEPENDENT
|
||||||
|
|
||||||
|
std::string RemoveStringQuotes(const std::string& s) {
|
||||||
|
auto ch = *s.c_str();
|
||||||
|
return ((s.size() >= 2) && (ch == '\"' || ch == '\'') && (ch == s.back()))
|
||||||
|
? s.substr(1, s.length() - 2)
|
||||||
|
: s;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SetGlobalTestLocale(const char* locale_name, std::string* _value) {
|
||||||
|
const auto the_locale = setlocale(LC_ALL, locale_name);
|
||||||
|
if (!the_locale) return false;
|
||||||
|
if (_value) *_value = std::string(the_locale);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadEnvironmentVariable(const char* var_name, std::string* _value) {
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
__pragma(warning(disable : 4996)); // _CRT_SECURE_NO_WARNINGS
|
||||||
|
#endif
|
||||||
|
auto env_str = std::getenv(var_name);
|
||||||
|
if (!env_str) return false;
|
||||||
|
if (_value) *_value = std::string(env_str);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ConvertCase(const std::string& input, Case output_case,
|
||||||
|
Case input_case) {
|
||||||
|
if (output_case == Case::kKeep) return input;
|
||||||
|
// The output cases expect snake_case inputs, so if we don't have that input
|
||||||
|
// format, try to convert to snake_case.
|
||||||
|
switch (input_case) {
|
||||||
|
case Case::kLowerCamel:
|
||||||
|
case Case::kUpperCamel:
|
||||||
|
return ConvertCase(CamelToSnake(input), output_case);
|
||||||
|
case Case::kDasher:
|
||||||
|
return ConvertCase(DasherToSnake(input), output_case);
|
||||||
|
case Case::kKeep:
|
||||||
|
printf("WARNING: Converting from kKeep case.\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
case Case::kSnake:
|
||||||
|
case Case::kScreamingSnake:
|
||||||
|
case Case::kAllLower:
|
||||||
|
case Case::kAllUpper:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (output_case) {
|
||||||
|
case Case::kUpperCamel:
|
||||||
|
return ToCamelCase(input, true);
|
||||||
|
case Case::kLowerCamel:
|
||||||
|
return ToCamelCase(input, false);
|
||||||
|
case Case::kSnake:
|
||||||
|
return input;
|
||||||
|
case Case::kScreamingSnake:
|
||||||
|
return ToSnakeCase(input, true);
|
||||||
|
case Case::kAllUpper:
|
||||||
|
return ToAll(input, CharToUpper);
|
||||||
|
case Case::kAllLower:
|
||||||
|
return ToAll(input, CharToLower);
|
||||||
|
case Case::kDasher:
|
||||||
|
return ToDasher(input);
|
||||||
|
case Case::kSnake2:
|
||||||
|
return SnakeToSnake2(input);
|
||||||
|
default:
|
||||||
|
case Case::kUnknown:
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
+3423
File diff suppressed because it is too large
Load Diff
+343
@@ -0,0 +1,343 @@
|
|||||||
|
// https://github.com/CedricGuillemet/ImGuizmo
|
||||||
|
// v1.92.5 WIP
|
||||||
|
//
|
||||||
|
// The MIT License(MIT)
|
||||||
|
//
|
||||||
|
// Copyright(c) 2016-2026 Cedric Guillemet and contributors
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// -------------------------------------------------------------------------------------------
|
||||||
|
// History :
|
||||||
|
// 2026/05/03 v1.9 release. CMake build system, vcpkg support, many fixes and new features from contributors.
|
||||||
|
// 2019/11/03 View gizmo
|
||||||
|
// 2016/09/11 Behind camera culling. Scaling Delta matrix not multiplied by source matrix scales. local/world rotation and translation fixed. Display message is incorrect (X: ... Y:...) in local mode.
|
||||||
|
// 2016/09/09 Hatched negative axis. Snapping. Documentation update.
|
||||||
|
// 2016/09/04 Axis switch and translation plan autohiding. Scale transform stability improved
|
||||||
|
// 2016/09/01 Mogwai changed to Manipulate. Draw debug cube. Fixed inverted scale. Mixing scale and translation/rotation gives bad results.
|
||||||
|
// 2016/08/31 First version
|
||||||
|
//
|
||||||
|
// -------------------------------------------------------------------------------------------
|
||||||
|
// Future (no order):
|
||||||
|
//
|
||||||
|
// - Multi view
|
||||||
|
// - display rotation/translation/scale infos in local/world space and not only local
|
||||||
|
// - finish local/world matrix application
|
||||||
|
// - OPERATION as bitmask
|
||||||
|
//
|
||||||
|
// -------------------------------------------------------------------------------------------
|
||||||
|
// Example
|
||||||
|
#if 0
|
||||||
|
void EditTransform(const Camera& camera, matrix_t& matrix)
|
||||||
|
{
|
||||||
|
static ImGuizmo::OPERATION mCurrentGizmoOperation(ImGuizmo::ROTATE);
|
||||||
|
static ImGuizmo::MODE mCurrentGizmoMode(ImGuizmo::WORLD);
|
||||||
|
if (ImGui::IsKeyPressed(90))
|
||||||
|
mCurrentGizmoOperation = ImGuizmo::TRANSLATE;
|
||||||
|
if (ImGui::IsKeyPressed(69))
|
||||||
|
mCurrentGizmoOperation = ImGuizmo::ROTATE;
|
||||||
|
if (ImGui::IsKeyPressed(82)) // r Key
|
||||||
|
mCurrentGizmoOperation = ImGuizmo::SCALE;
|
||||||
|
if (ImGui::RadioButton("Translate", mCurrentGizmoOperation == ImGuizmo::TRANSLATE))
|
||||||
|
mCurrentGizmoOperation = ImGuizmo::TRANSLATE;
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::RadioButton("Rotate", mCurrentGizmoOperation == ImGuizmo::ROTATE))
|
||||||
|
mCurrentGizmoOperation = ImGuizmo::ROTATE;
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::RadioButton("Scale", mCurrentGizmoOperation == ImGuizmo::SCALE))
|
||||||
|
mCurrentGizmoOperation = ImGuizmo::SCALE;
|
||||||
|
float matrixTranslation[3], matrixRotation[3], matrixScale[3];
|
||||||
|
ImGuizmo::DecomposeMatrixToComponents(matrix.m16, matrixTranslation, matrixRotation, matrixScale);
|
||||||
|
ImGui::InputFloat3("Tr", matrixTranslation, 3);
|
||||||
|
ImGui::InputFloat3("Rt", matrixRotation, 3);
|
||||||
|
ImGui::InputFloat3("Sc", matrixScale, 3);
|
||||||
|
ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, matrix.m16);
|
||||||
|
|
||||||
|
if (mCurrentGizmoOperation != ImGuizmo::SCALE)
|
||||||
|
{
|
||||||
|
if (ImGui::RadioButton("Local", mCurrentGizmoMode == ImGuizmo::LOCAL))
|
||||||
|
mCurrentGizmoMode = ImGuizmo::LOCAL;
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::RadioButton("World", mCurrentGizmoMode == ImGuizmo::WORLD))
|
||||||
|
mCurrentGizmoMode = ImGuizmo::WORLD;
|
||||||
|
}
|
||||||
|
static bool useSnap(false);
|
||||||
|
if (ImGui::IsKeyPressed(83))
|
||||||
|
useSnap = !useSnap;
|
||||||
|
ImGui::Checkbox("", &useSnap);
|
||||||
|
ImGui::SameLine();
|
||||||
|
vec_t snap;
|
||||||
|
switch (mCurrentGizmoOperation)
|
||||||
|
{
|
||||||
|
case ImGuizmo::TRANSLATE:
|
||||||
|
snap = config.mSnapTranslation;
|
||||||
|
ImGui::InputFloat3("Snap", &snap.x);
|
||||||
|
break;
|
||||||
|
case ImGuizmo::ROTATE:
|
||||||
|
snap = config.mSnapRotation;
|
||||||
|
ImGui::InputFloat("Angle Snap", &snap.x);
|
||||||
|
break;
|
||||||
|
case ImGuizmo::SCALE:
|
||||||
|
snap = config.mSnapScale;
|
||||||
|
ImGui::InputFloat("Scale Snap", &snap.x);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y);
|
||||||
|
ImGuizmo::Manipulate(camera.mView.m16, camera.mProjection.m16, mCurrentGizmoOperation, mCurrentGizmoMode, matrix.m16, NULL, useSnap ? &snap.x : NULL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef USE_IMGUI_API
|
||||||
|
#include "imconfig.h"
|
||||||
|
#endif
|
||||||
|
#ifndef IMGUI_API
|
||||||
|
#define IMGUI_API
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef IMGUIZMO_NAMESPACE
|
||||||
|
#define IMGUIZMO_NAMESPACE ImGuizmo
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct ImGuiWindow;
|
||||||
|
|
||||||
|
namespace IMGUIZMO_NAMESPACE
|
||||||
|
{
|
||||||
|
// call inside your own window and before Manipulate() in order to draw gizmo to that window.
|
||||||
|
// Or pass a specific ImDrawList to draw to (e.g. ImGui::GetForegroundDrawList()).
|
||||||
|
IMGUI_API void SetDrawlist(ImDrawList* drawlist = nullptr);
|
||||||
|
|
||||||
|
// call BeginFrame right after ImGui_XXXX_NewFrame();
|
||||||
|
IMGUI_API void BeginFrame();
|
||||||
|
|
||||||
|
// this is necessary because when imguizmo is compiled into a dll, and imgui into another
|
||||||
|
// globals are not shared between them.
|
||||||
|
// More details at https://stackoverflow.com/questions/19373061/what-happens-to-global-and-static-variables-in-a-shared-library-when-it-is-dynam
|
||||||
|
// expose method to set imgui context
|
||||||
|
IMGUI_API void SetImGuiContext(ImGuiContext* ctx);
|
||||||
|
|
||||||
|
// return true if mouse cursor is over any gizmo control (axis, plan or screen component)
|
||||||
|
IMGUI_API bool IsOver();
|
||||||
|
|
||||||
|
// return true if mouse IsOver or if the gizmo is in moving state
|
||||||
|
IMGUI_API bool IsUsing();
|
||||||
|
|
||||||
|
// return true if the view gizmo is in moving state
|
||||||
|
IMGUI_API bool IsUsingViewManipulate();
|
||||||
|
// only check if your mouse is over the view manipulator - no matter whether it's active or not
|
||||||
|
IMGUI_API bool IsViewManipulateHovered();
|
||||||
|
|
||||||
|
// return true if any gizmo is in moving state
|
||||||
|
IMGUI_API bool IsUsingAny();
|
||||||
|
|
||||||
|
// enable/disable the gizmo. Stay in the state until next call to Enable.
|
||||||
|
// gizmo is rendered with gray half transparent color when disabled
|
||||||
|
IMGUI_API void Enable(bool enable);
|
||||||
|
|
||||||
|
// helper functions for manualy editing translation/rotation/scale with an input float
|
||||||
|
// translation, rotation and scale float points to 3 floats each
|
||||||
|
// Angles are in degrees (more suitable for human editing)
|
||||||
|
// example:
|
||||||
|
// float matrixTranslation[3], matrixRotation[3], matrixScale[3];
|
||||||
|
// ImGuizmo::DecomposeMatrixToComponents(gizmoMatrix.m16, matrixTranslation, matrixRotation, matrixScale);
|
||||||
|
// ImGui::InputFloat3("Tr", matrixTranslation, 3);
|
||||||
|
// ImGui::InputFloat3("Rt", matrixRotation, 3);
|
||||||
|
// ImGui::InputFloat3("Sc", matrixScale, 3);
|
||||||
|
// ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, gizmoMatrix.m16);
|
||||||
|
//
|
||||||
|
// These functions have some numerical stability issues for now. Use with caution.
|
||||||
|
IMGUI_API void DecomposeMatrixToComponents(const float* matrix, float* translation, float* rotation, float* scale);
|
||||||
|
IMGUI_API void RecomposeMatrixFromComponents(const float* translation, const float* rotation, const float* scale, float* matrix);
|
||||||
|
|
||||||
|
IMGUI_API void SetRect(float x, float y, float width, float height);
|
||||||
|
// default is false
|
||||||
|
IMGUI_API void SetOrthographic(bool isOrthographic);
|
||||||
|
|
||||||
|
// Render coordinate system axes (red X, green Y and blue Z). Usefull for debug/tests
|
||||||
|
IMGUI_API void DrawAxes(const float* view, const float* projection, const float* matrices, int matrixCount);
|
||||||
|
// Render a cube with face color corresponding to face normal. Usefull for debug/tests
|
||||||
|
IMGUI_API void DrawCubes(const float* view, const float* projection, const float* matrices, int matrixCount);
|
||||||
|
IMGUI_API void DrawGrid(const float* view, const float* projection, const float* matrix, const float gridSize);
|
||||||
|
// Render grid with customizable major line step and amount of segments between major lines.
|
||||||
|
// NOTE(m.wlasiuk) : calling this function with majorStep = 1.0f and subdivision = 1 is equivalent to DrawGrid in terms of the end result but performs more calculations
|
||||||
|
IMGUI_API void DrawGridCustom(const float* view, const float* projection, const float* matrix, const float gridSize, const float majorStep, const unsigned int subdivision);
|
||||||
|
// Render grid with customizable major line step and amount of segments between major lines and with possibility to set custom colors for major, minor and center lines
|
||||||
|
IMGUI_API void DrawGridCustomColor(const float* view, const float* projection, const float* matrix, const float gridSize, const float majorStep, const unsigned int subdivision, const ImU32 majorCol, const ImU32 minorCol, const ImU32 centerCol);
|
||||||
|
|
||||||
|
// call it when you want a gizmo
|
||||||
|
// Needs view and projection matrices.
|
||||||
|
// matrix parameter is the source matrix (where will be gizmo be drawn) and might be transformed by the function. Return deltaMatrix is optional
|
||||||
|
// translation is applied in world space
|
||||||
|
enum OPERATION
|
||||||
|
{
|
||||||
|
TRANSLATE_X = (1u << 0),
|
||||||
|
TRANSLATE_Y = (1u << 1),
|
||||||
|
TRANSLATE_Z = (1u << 2),
|
||||||
|
ROTATE_X = (1u << 3),
|
||||||
|
ROTATE_Y = (1u << 4),
|
||||||
|
ROTATE_Z = (1u << 5),
|
||||||
|
ROTATE_SCREEN = (1u << 6),
|
||||||
|
SCALE_X = (1u << 7),
|
||||||
|
SCALE_Y = (1u << 8),
|
||||||
|
SCALE_Z = (1u << 9),
|
||||||
|
BOUNDS = (1u << 10),
|
||||||
|
SCALE_XU = (1u << 11),
|
||||||
|
SCALE_YU = (1u << 12),
|
||||||
|
SCALE_ZU = (1u << 13),
|
||||||
|
|
||||||
|
TRANSLATE = TRANSLATE_X | TRANSLATE_Y | TRANSLATE_Z,
|
||||||
|
ROTATE = ROTATE_X | ROTATE_Y | ROTATE_Z | ROTATE_SCREEN,
|
||||||
|
SCALE = SCALE_X | SCALE_Y | SCALE_Z,
|
||||||
|
SCALEU = SCALE_XU | SCALE_YU | SCALE_ZU, // universal
|
||||||
|
UNIVERSAL = TRANSLATE | ROTATE | SCALEU
|
||||||
|
};
|
||||||
|
|
||||||
|
inline OPERATION operator|(OPERATION lhs, OPERATION rhs)
|
||||||
|
{
|
||||||
|
return static_cast<OPERATION>(static_cast<int>(lhs) | static_cast<int>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
enum MODE
|
||||||
|
{
|
||||||
|
LOCAL,
|
||||||
|
WORLD
|
||||||
|
};
|
||||||
|
|
||||||
|
IMGUI_API bool Manipulate(const float* view, const float* projection, OPERATION operation, MODE mode, float* matrix, float* deltaMatrix = NULL, const float* snap = NULL, const float* localBounds = NULL, const float* boundsSnap = NULL);
|
||||||
|
//
|
||||||
|
// Please note that this cubeview is patented by Autodesk : https://patents.google.com/patent/US7782319B2/en
|
||||||
|
// It seems to be a defensive patent in the US. I don't think it will bring troubles using it as
|
||||||
|
// other software are using the same mechanics. But just in case, you are now warned!
|
||||||
|
//
|
||||||
|
IMGUI_API void ViewManipulate(float* view, float length, ImVec2 position, ImVec2 size, ImU32 backgroundColor);
|
||||||
|
|
||||||
|
// use this version if you did not call Manipulate before and you are just using ViewManipulate
|
||||||
|
IMGUI_API void ViewManipulate(float* view, const float* projection, OPERATION operation, MODE mode, float* matrix, float length, ImVec2 position, ImVec2 size, ImU32 backgroundColor);
|
||||||
|
|
||||||
|
IMGUI_API void SetAlternativeWindow(ImGuiWindow* window);
|
||||||
|
|
||||||
|
[[deprecated("Use PushID/PopID instead.")]]
|
||||||
|
IMGUI_API void SetID(int id);
|
||||||
|
|
||||||
|
// ID stack/scopes
|
||||||
|
// Read the FAQ (docs/FAQ.md or http://dearimgui.org/faq) for more details about how ID are handled in dear imgui.
|
||||||
|
// - Those questions are answered and impacted by understanding of the ID stack system:
|
||||||
|
// - "Q: Why is my widget not reacting when I click on it?"
|
||||||
|
// - "Q: How can I have widgets with an empty label?"
|
||||||
|
// - "Q: How can I have multiple widgets with the same label?"
|
||||||
|
// - Short version: ID are hashes of the entire ID stack. If you are creating widgets in a loop you most likely
|
||||||
|
// want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them.
|
||||||
|
// - You can also use the "Label##foobar" syntax within widget label to distinguish them from each others.
|
||||||
|
// - In this header file we use the "label"/"name" terminology to denote a string that will be displayed + used as an ID,
|
||||||
|
// whereas "str_id" denote a string that is only used as an ID and not normally displayed.
|
||||||
|
IMGUI_API void PushID(const char* str_id); // push string into the ID stack (will hash string).
|
||||||
|
IMGUI_API void PushID(const char* str_id_begin, const char* str_id_end); // push string into the ID stack (will hash string).
|
||||||
|
IMGUI_API void PushID(const void* ptr_id); // push pointer into the ID stack (will hash pointer).
|
||||||
|
IMGUI_API void PushID(int int_id); // push integer into the ID stack (will hash integer).
|
||||||
|
IMGUI_API void PopID(); // pop from the ID stack.
|
||||||
|
IMGUI_API ImGuiID GetID(const char* str_id); // calculate unique ID (hash of whole ID stack + given parameter). e.g. if you want to query into ImGuiStorage yourself
|
||||||
|
IMGUI_API ImGuiID GetID(const char* str_id_begin, const char* str_id_end);
|
||||||
|
IMGUI_API ImGuiID GetID(const void* ptr_id);
|
||||||
|
|
||||||
|
// return true if the cursor is over the operation's gizmo
|
||||||
|
IMGUI_API bool IsOver(OPERATION op);
|
||||||
|
IMGUI_API void SetGizmoSizeClipSpace(float value);
|
||||||
|
|
||||||
|
// Handle type used by the translate/rotate/scale gizmos.
|
||||||
|
enum MOVETYPE
|
||||||
|
{
|
||||||
|
MT_NONE,
|
||||||
|
MT_MOVE_X,
|
||||||
|
MT_MOVE_Y,
|
||||||
|
MT_MOVE_Z,
|
||||||
|
MT_MOVE_YZ,
|
||||||
|
MT_MOVE_ZX,
|
||||||
|
MT_MOVE_XY,
|
||||||
|
MT_MOVE_SCREEN,
|
||||||
|
MT_ROTATE_X,
|
||||||
|
MT_ROTATE_Y,
|
||||||
|
MT_ROTATE_Z,
|
||||||
|
MT_ROTATE_SCREEN,
|
||||||
|
MT_SCALE_X,
|
||||||
|
MT_SCALE_Y,
|
||||||
|
MT_SCALE_Z,
|
||||||
|
MT_SCALE_XYZ
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns which handle is actively being dragged, or MT_NONE.
|
||||||
|
IMGUI_API MOVETYPE GetActiveHandleType();
|
||||||
|
// Returns which handle is currently hovered, or MT_NONE.
|
||||||
|
IMGUI_API MOVETYPE GetHoveredHandleType();
|
||||||
|
// Aliases matching the MOVETYPE enum name.
|
||||||
|
IMGUI_API MOVETYPE GetActiveMoveType();
|
||||||
|
IMGUI_API MOVETYPE GetHoveredMoveType();
|
||||||
|
|
||||||
|
// Allow axis to flip
|
||||||
|
// When true (default), the guizmo axis flip for better visibility
|
||||||
|
// When false, they always stay along the positive world/local axis
|
||||||
|
IMGUI_API void AllowAxisFlip(bool value);
|
||||||
|
|
||||||
|
// Configure the limit where axis are hidden
|
||||||
|
IMGUI_API void SetAxisLimit(float value);
|
||||||
|
// Set an axis mask to permanently hide a given axis (true -> hidden, false -> shown)
|
||||||
|
IMGUI_API void SetAxisMask(bool x, bool y, bool z);
|
||||||
|
// Configure the limit where planes are hiden
|
||||||
|
IMGUI_API void SetPlaneLimit(float value);
|
||||||
|
// from a x,y,z point in space and using Manipulation view/projection matrix, check if mouse is in pixel radius distance of that projected point
|
||||||
|
IMGUI_API bool IsOver(float* position, float pixelRadius);
|
||||||
|
|
||||||
|
enum COLOR
|
||||||
|
{
|
||||||
|
DIRECTION_X, // directionColor[0]
|
||||||
|
DIRECTION_Y, // directionColor[1]
|
||||||
|
DIRECTION_Z, // directionColor[2]
|
||||||
|
PLANE_X, // planeColor[0]
|
||||||
|
PLANE_Y, // planeColor[1]
|
||||||
|
PLANE_Z, // planeColor[2]
|
||||||
|
SELECTION, // selectionColor
|
||||||
|
INACTIVE, // inactiveColor
|
||||||
|
TRANSLATION_LINE, // translationLineColor
|
||||||
|
SCALE_LINE,
|
||||||
|
ROTATION_USING_BORDER,
|
||||||
|
ROTATION_USING_FILL,
|
||||||
|
HATCHED_AXIS_LINES,
|
||||||
|
TEXT,
|
||||||
|
TEXT_SHADOW,
|
||||||
|
COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Style
|
||||||
|
{
|
||||||
|
IMGUI_API Style();
|
||||||
|
|
||||||
|
float TranslationLineThickness; // Thickness of lines for translation gizmo
|
||||||
|
float TranslationLineArrowSize; // Size of arrow at the end of lines for translation gizmo
|
||||||
|
float RotationLineThickness; // Thickness of lines for rotation gizmo
|
||||||
|
float RotationOuterLineThickness; // Thickness of line surrounding the rotation gizmo
|
||||||
|
float ScaleLineThickness; // Thickness of lines for scale gizmo
|
||||||
|
float ScaleLineCircleSize; // Size of circle at the end of lines for scale gizmo
|
||||||
|
float HatchedAxisLineThickness; // Thickness of hatched axis lines
|
||||||
|
float CenterCircleSize; // Size of circle at the center of the translate/scale gizmo
|
||||||
|
|
||||||
|
ImVec4 Colors[COLOR::COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
IMGUI_API Style& GetStyle();
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2016 Cedric Guillemet
|
||||||
|
|
||||||
|
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.
|
||||||
+149
@@ -0,0 +1,149 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// DEAR IMGUI COMPILE-TIME OPTIONS
|
||||||
|
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
|
||||||
|
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)
|
||||||
|
// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
|
||||||
|
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
|
||||||
|
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
|
||||||
|
// Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//---- Define assertion handler. Defaults to calling assert().
|
||||||
|
// - If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
|
||||||
|
// - Compiling with NDEBUG will usually strip out assert() to nothing, which is NOT recommended because we use asserts to notify of programmer mistakes.
|
||||||
|
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
|
||||||
|
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
|
||||||
|
|
||||||
|
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
|
||||||
|
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
|
||||||
|
// - Windows DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
|
||||||
|
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
|
||||||
|
//#define IMGUI_API __declspec(dllexport) // MSVC Windows: DLL export
|
||||||
|
//#define IMGUI_API __declspec(dllimport) // MSVC Windows: DLL import
|
||||||
|
//#define IMGUI_API __attribute__((visibility("default"))) // GCC/Clang: override visibility when set is hidden
|
||||||
|
|
||||||
|
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.
|
||||||
|
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||||
|
|
||||||
|
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
|
||||||
|
// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.
|
||||||
|
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
|
||||||
|
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
|
||||||
|
//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowIDStackToolWindow() will be empty.
|
||||||
|
|
||||||
|
//---- Don't implement some functions to reduce linkage requirements.
|
||||||
|
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
|
||||||
|
//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
|
||||||
|
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
|
||||||
|
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME).
|
||||||
|
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
|
||||||
|
//#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS // Don't implement default platform_io.Platform_OpenInShellFn() handler (Win32: ShellExecute(), require shell32.lib/.a, Mac/Linux: use system("")).
|
||||||
|
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
|
||||||
|
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
|
||||||
|
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
|
||||||
|
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
|
||||||
|
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
|
||||||
|
//#define IMGUI_DISABLE_DEFAULT_FONT // Disable default embedded fonts (ProggyClean + ProggyForever). Remove ~9 KB + ~14 KB from output binary. AddFontDefaultXXX() functions will assert.
|
||||||
|
//#define IMGUI_DISABLE_DEFAULT_FONT_BITMAP // Disable default embedded bitmap font (ProggyClean). Remove ~9 KB from output binary. AddFontDefaultBitmap() will assert.
|
||||||
|
//#define IMGUI_DISABLE_DEFAULT_FONT_VECTOR // Disable default embedded vector font (ProggyForever), Remove ~14 KB from output binary. AddFontDefaultVector() will assert.
|
||||||
|
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
|
||||||
|
|
||||||
|
//---- Enable Test Engine / Automation features.
|
||||||
|
//#define IMGUI_ENABLE_TEST_ENGINE // Enable imgui_test_engine hooks. Generally set automatically by include "imgui_te_config.h", see Test Engine for details.
|
||||||
|
|
||||||
|
//---- Include imgui_user.h at the end of imgui.h as a convenience
|
||||||
|
// May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included.
|
||||||
|
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
||||||
|
//#define IMGUI_USER_H_FILENAME "my_folder/my_imgui_user.h"
|
||||||
|
|
||||||
|
//---- Pack vertex colors as BGRA8 instead of RGBA8 (to avoid converting from one to another). Need dedicated backend support.
|
||||||
|
//#define IMGUI_USE_BGRA_PACKED_COLOR
|
||||||
|
|
||||||
|
//---- Use legacy CRC32-adler tables (used before 1.91.6), in order to preserve old .ini data that you cannot afford to invalidate.
|
||||||
|
//#define IMGUI_USE_LEGACY_CRC32_ADLER
|
||||||
|
|
||||||
|
//---- Use 32-bit for ImWchar (default is 16-bit) to support Unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
|
||||||
|
//#define IMGUI_USE_WCHAR32
|
||||||
|
|
||||||
|
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
|
||||||
|
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
|
||||||
|
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
|
||||||
|
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
|
||||||
|
//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if IMGUI_USE_STB_SPRINTF is defined.
|
||||||
|
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
|
||||||
|
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
||||||
|
//#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION // only disabled if IMGUI_USE_STB_SPRINTF is defined.
|
||||||
|
|
||||||
|
//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
|
||||||
|
// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.
|
||||||
|
//#define IMGUI_USE_STB_SPRINTF
|
||||||
|
|
||||||
|
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
|
||||||
|
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
|
||||||
|
// Note that imgui_freetype.cpp may be used _without_ this define, if you manually call ImFontAtlas::SetFontLoader(). The define is simply a convenience.
|
||||||
|
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
|
||||||
|
//#define IMGUI_ENABLE_FREETYPE
|
||||||
|
|
||||||
|
//---- Use FreeType + plutosvg or lunasvg to render OpenType SVG fonts (SVGinOT)
|
||||||
|
// Only works in combination with IMGUI_ENABLE_FREETYPE.
|
||||||
|
// - plutosvg is currently easier to install, as e.g. it is part of vcpkg. It will support more fonts and may load them faster. See misc/freetype/README for instructions.
|
||||||
|
// - Both require headers to be available in the include path + program to be linked with the library code (not provided).
|
||||||
|
// - (note: lunasvg implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
|
||||||
|
//#define IMGUI_ENABLE_FREETYPE_PLUTOSVG
|
||||||
|
//#define IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||||
|
|
||||||
|
//---- Use stb_truetype to build and rasterize the font atlas (default)
|
||||||
|
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
|
||||||
|
//#define IMGUI_ENABLE_STB_TRUETYPE
|
||||||
|
|
||||||
|
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
|
||||||
|
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
|
||||||
|
/*
|
||||||
|
#define IM_VEC2_CLASS_EXTRA \
|
||||||
|
constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \
|
||||||
|
operator MyVec2() const { return MyVec2(x,y); }
|
||||||
|
|
||||||
|
#define IM_VEC4_CLASS_EXTRA \
|
||||||
|
constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \
|
||||||
|
operator MyVec4() const { return MyVec4(x,y,z,w); }
|
||||||
|
*/
|
||||||
|
//---- ...Or use Dear ImGui's own very basic math operators.
|
||||||
|
//#define IMGUI_DEFINE_MATH_OPERATORS
|
||||||
|
|
||||||
|
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
|
||||||
|
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
|
||||||
|
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
|
||||||
|
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
|
||||||
|
//#define ImDrawIdx unsigned int
|
||||||
|
|
||||||
|
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
|
||||||
|
//struct ImDrawList;
|
||||||
|
//struct ImDrawCmd;
|
||||||
|
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
|
||||||
|
//#define ImDrawCallback MyImDrawCallback
|
||||||
|
|
||||||
|
//---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase)
|
||||||
|
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
|
||||||
|
//#define IM_DEBUG_BREAK IM_ASSERT(0)
|
||||||
|
//#define IM_DEBUG_BREAK __debugbreak()
|
||||||
|
|
||||||
|
//---- Debug Tools: Enable highlight ID conflicts _before_ hovering items. When io.ConfigDebugHighlightIdConflicts is set.
|
||||||
|
// (THIS WILL SLOW DOWN DEAR IMGUI. Only use occasionally and disable after use)
|
||||||
|
//#define IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS
|
||||||
|
|
||||||
|
//---- Debug Tools: Enable slower asserts
|
||||||
|
//#define IMGUI_DEBUG_PARANOID
|
||||||
|
|
||||||
|
//---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files)
|
||||||
|
/*
|
||||||
|
namespace ImGui
|
||||||
|
{
|
||||||
|
void MyFunction(const char* name, MyMatrix44* mtx);
|
||||||
|
}
|
||||||
|
*/
|
||||||
+18385
File diff suppressed because it is too large
Load Diff
Vendored
+4256
File diff suppressed because it is too large
Load Diff
+6809
File diff suppressed because it is too large
Load Diff
+491
@@ -0,0 +1,491 @@
|
|||||||
|
// dear imgui: Renderer Backend for DirectX9
|
||||||
|
// This needs to be used along with a Platform Backend (e.g. Win32)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
|
||||||
|
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||||
|
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||||
|
// [X] Renderer: IMGUI_USE_BGRA_PACKED_COLOR support, as this is the optimal color encoding for DirectX9.
|
||||||
|
|
||||||
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// Learn about Dear ImGui:
|
||||||
|
// - FAQ https://dearimgui.com/faq
|
||||||
|
// - Getting Started https://dearimgui.com/getting-started
|
||||||
|
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||||
|
// - Introduction, links and more at the top of imgui.cpp
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378)
|
||||||
|
// 2026-03-19: Fixed issue in ImGui_ImplDX9_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295, #9310)
|
||||||
|
// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
|
||||||
|
// 2025-06-11: DirectX9: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas.
|
||||||
|
// 2024-10-07: DirectX9: Changed default texture sampler to Clamp instead of Repeat/Wrap.
|
||||||
|
// 2024-02-12: DirectX9: Using RGBA format when supported by the driver to avoid CPU side conversion. (#6575)
|
||||||
|
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
|
||||||
|
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||||
|
// 2021-06-25: DirectX9: Explicitly disable texture state stages after >= 1.
|
||||||
|
// 2021-05-19: DirectX9: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||||
|
// 2021-04-23: DirectX9: Explicitly setting up more graphics states to increase compatibility with unusual non-default states.
|
||||||
|
// 2021-03-18: DirectX9: Calling IDirect3DStateBlock9::Capture() after CreateStateBlock() as a workaround for state restoring issues (see #3857).
|
||||||
|
// 2021-03-03: DirectX9: Added support for IMGUI_USE_BGRA_PACKED_COLOR in user's imconfig file.
|
||||||
|
// 2021-02-18: DirectX9: Change blending equation to preserve alpha in output buffer.
|
||||||
|
// 2019-05-29: DirectX9: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||||
|
// 2019-04-30: DirectX9: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||||
|
// 2019-03-29: Misc: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects().
|
||||||
|
// 2019-01-16: Misc: Disabled fog before drawing UI's. Fixes issue #2288.
|
||||||
|
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||||
|
// 2018-06-08: Misc: Extracted imgui_impl_dx9.cpp/.h away from the old combined DX9+Win32 example.
|
||||||
|
// 2018-06-08: DirectX9: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||||
|
// 2018-05-07: Render: Saving/restoring Transform because they don't seem to be included in the StateBlock. Setting shading mode to Gouraud.
|
||||||
|
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself.
|
||||||
|
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#ifndef IMGUI_DISABLE
|
||||||
|
#include "imgui_impl_dx9.h"
|
||||||
|
|
||||||
|
// DirectX
|
||||||
|
#include <d3d9.h>
|
||||||
|
|
||||||
|
// Clang/GCC warnings with -Weverything
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
|
||||||
|
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// DirectX data
|
||||||
|
struct ImGui_ImplDX9_Data
|
||||||
|
{
|
||||||
|
LPDIRECT3DDEVICE9 pd3dDevice;
|
||||||
|
LPDIRECT3DVERTEXBUFFER9 pVB;
|
||||||
|
LPDIRECT3DINDEXBUFFER9 pIB;
|
||||||
|
int VertexBufferSize;
|
||||||
|
int IndexBufferSize;
|
||||||
|
bool HasRgbaSupport;
|
||||||
|
|
||||||
|
ImGui_ImplDX9_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CUSTOMVERTEX
|
||||||
|
{
|
||||||
|
float pos[3];
|
||||||
|
D3DCOLOR col;
|
||||||
|
float uv[2];
|
||||||
|
};
|
||||||
|
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
|
||||||
|
|
||||||
|
#ifdef IMGUI_USE_BGRA_PACKED_COLOR
|
||||||
|
#define IMGUI_COL_TO_DX9_ARGB(_COL) (_COL)
|
||||||
|
#else
|
||||||
|
#define IMGUI_COL_TO_DX9_ARGB(_COL) (((_COL) & 0xFF00FF00) | (((_COL) & 0xFF0000) >> 16) | (((_COL) & 0xFF) << 16))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||||
|
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||||
|
static ImGui_ImplDX9_Data* ImGui_ImplDX9_GetBackendData()
|
||||||
|
{
|
||||||
|
return ImGui::GetCurrentContext() ? (ImGui_ImplDX9_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data)
|
||||||
|
{
|
||||||
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
|
|
||||||
|
// Setup viewport
|
||||||
|
D3DVIEWPORT9 vp;
|
||||||
|
vp.X = vp.Y = 0;
|
||||||
|
vp.Width = (DWORD)draw_data->DisplaySize.x;
|
||||||
|
vp.Height = (DWORD)draw_data->DisplaySize.y;
|
||||||
|
vp.MinZ = 0.0f;
|
||||||
|
vp.MaxZ = 1.0f;
|
||||||
|
|
||||||
|
LPDIRECT3DDEVICE9 device = bd->pd3dDevice;
|
||||||
|
device->SetViewport(&vp);
|
||||||
|
|
||||||
|
// Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient), bilinear sampling.
|
||||||
|
device->SetPixelShader(nullptr);
|
||||||
|
device->SetVertexShader(nullptr);
|
||||||
|
device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
|
||||||
|
device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
|
||||||
|
device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
|
||||||
|
device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
|
||||||
|
device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
||||||
|
device->SetRenderState(D3DRS_ZENABLE, FALSE);
|
||||||
|
device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
||||||
|
device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
|
||||||
|
device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
|
||||||
|
device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
|
||||||
|
device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
|
||||||
|
device->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE);
|
||||||
|
device->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA);
|
||||||
|
device->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
|
||||||
|
device->SetRenderState(D3DRS_FOGENABLE, FALSE);
|
||||||
|
device->SetRenderState(D3DRS_RANGEFOGENABLE, FALSE);
|
||||||
|
device->SetRenderState(D3DRS_SPECULARENABLE, FALSE);
|
||||||
|
device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
|
||||||
|
device->SetRenderState(D3DRS_CLIPPING, TRUE);
|
||||||
|
device->SetRenderState(D3DRS_LIGHTING, FALSE);
|
||||||
|
device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
||||||
|
device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||||
|
device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
|
||||||
|
device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
|
||||||
|
device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
||||||
|
device->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
|
||||||
|
device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
|
||||||
|
device->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
|
||||||
|
device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
||||||
|
device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
||||||
|
device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
|
||||||
|
device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
|
||||||
|
|
||||||
|
// Setup orthographic projection matrix
|
||||||
|
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||||
|
// Being agnostic of whether <d3dx9.h> or <DirectXMath.h> can be used, we aren't relying on D3DXMatrixIdentity()/D3DXMatrixOrthoOffCenterLH() or DirectX::XMMatrixIdentity()/DirectX::XMMatrixOrthographicOffCenterLH()
|
||||||
|
{
|
||||||
|
float L = draw_data->DisplayPos.x + 0.5f;
|
||||||
|
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x + 0.5f;
|
||||||
|
float T = draw_data->DisplayPos.y + 0.5f;
|
||||||
|
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y + 0.5f;
|
||||||
|
D3DMATRIX mat_identity = { { { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } } };
|
||||||
|
D3DMATRIX mat_projection =
|
||||||
|
{ { {
|
||||||
|
2.0f/(R-L), 0.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 2.0f/(T-B), 0.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 0.5f, 0.0f,
|
||||||
|
(L+R)/(L-R), (T+B)/(B-T), 0.5f, 1.0f
|
||||||
|
} } };
|
||||||
|
device->SetTransform(D3DTS_WORLD, &mat_identity);
|
||||||
|
device->SetTransform(D3DTS_VIEW, &mat_identity);
|
||||||
|
device->SetTransform(D3DTS_PROJECTION, &mat_projection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw callbacks
|
||||||
|
static void ImGui_ImplDX9_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way.
|
||||||
|
static void ImGui_ImplDX9_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); }
|
||||||
|
static void ImGui_ImplDX9_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); }
|
||||||
|
|
||||||
|
// Render function.
|
||||||
|
void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
|
||||||
|
{
|
||||||
|
// Avoid rendering when minimized
|
||||||
|
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
|
LPDIRECT3DDEVICE9 device = bd->pd3dDevice;
|
||||||
|
|
||||||
|
// Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do.
|
||||||
|
// (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates).
|
||||||
|
if (draw_data->Textures != nullptr)
|
||||||
|
for (ImTextureData* tex : *draw_data->Textures)
|
||||||
|
if (tex->Status != ImTextureStatus_OK)
|
||||||
|
ImGui_ImplDX9_UpdateTexture(tex);
|
||||||
|
|
||||||
|
// Create and grow buffers if needed
|
||||||
|
if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount)
|
||||||
|
{
|
||||||
|
if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }
|
||||||
|
bd->VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
||||||
|
if (device->CreateVertexBuffer((UINT)bd->VertexBufferSize * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &bd->pVB, nullptr) < 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount)
|
||||||
|
{
|
||||||
|
if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
|
||||||
|
bd->IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
||||||
|
if (device->CreateIndexBuffer((UINT)bd->IndexBufferSize * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &bd->pIB, nullptr) < 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backup the DX9 state
|
||||||
|
IDirect3DStateBlock9* state_block = nullptr;
|
||||||
|
if (device->CreateStateBlock(D3DSBT_ALL, &state_block) < 0)
|
||||||
|
return;
|
||||||
|
if (state_block->Capture() < 0)
|
||||||
|
{
|
||||||
|
state_block->Release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backup the DX9 transform (DX9 documentation suggests that it is included in the StateBlock but it doesn't appear to)
|
||||||
|
D3DMATRIX last_world, last_view, last_projection;
|
||||||
|
device->GetTransform(D3DTS_WORLD, &last_world);
|
||||||
|
device->GetTransform(D3DTS_VIEW, &last_view);
|
||||||
|
device->GetTransform(D3DTS_PROJECTION, &last_projection);
|
||||||
|
|
||||||
|
// Allocate buffers
|
||||||
|
CUSTOMVERTEX* vtx_dst;
|
||||||
|
ImDrawIdx* idx_dst;
|
||||||
|
if (bd->pVB->Lock(0, (UINT)(draw_data->TotalVtxCount * sizeof(CUSTOMVERTEX)), (void**)&vtx_dst, D3DLOCK_DISCARD) < 0)
|
||||||
|
{
|
||||||
|
state_block->Release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (bd->pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void**)&idx_dst, D3DLOCK_DISCARD) < 0)
|
||||||
|
{
|
||||||
|
bd->pVB->Unlock();
|
||||||
|
state_block->Release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy and convert all vertices into a single contiguous buffer, convert colors to DX9 default format.
|
||||||
|
// FIXME-OPT: This is a minor waste of resource, the ideal is to use imconfig.h and
|
||||||
|
// 1) to avoid repacking colors: #define IMGUI_USE_BGRA_PACKED_COLOR
|
||||||
|
// 2) to avoid repacking vertices: #define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; }
|
||||||
|
for (const ImDrawList* draw_list : draw_data->CmdLists)
|
||||||
|
{
|
||||||
|
const ImDrawVert* vtx_src = draw_list->VtxBuffer.Data;
|
||||||
|
for (int i = 0; i < draw_list->VtxBuffer.Size; i++)
|
||||||
|
{
|
||||||
|
vtx_dst->pos[0] = vtx_src->pos.x;
|
||||||
|
vtx_dst->pos[1] = vtx_src->pos.y;
|
||||||
|
vtx_dst->pos[2] = 0.0f;
|
||||||
|
vtx_dst->col = IMGUI_COL_TO_DX9_ARGB(vtx_src->col);
|
||||||
|
vtx_dst->uv[0] = vtx_src->uv.x;
|
||||||
|
vtx_dst->uv[1] = vtx_src->uv.y;
|
||||||
|
vtx_dst++;
|
||||||
|
vtx_src++;
|
||||||
|
}
|
||||||
|
memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||||
|
idx_dst += draw_list->IdxBuffer.Size;
|
||||||
|
}
|
||||||
|
bd->pVB->Unlock();
|
||||||
|
bd->pIB->Unlock();
|
||||||
|
device->SetStreamSource(0, bd->pVB, 0, sizeof(CUSTOMVERTEX));
|
||||||
|
device->SetIndices(bd->pIB);
|
||||||
|
device->SetFVF(D3DFVF_CUSTOMVERTEX);
|
||||||
|
|
||||||
|
// Setup desired DX state
|
||||||
|
ImGui_ImplDX9_SetupRenderState(draw_data);
|
||||||
|
|
||||||
|
// Render command lists
|
||||||
|
// (Because we merged all buffers into a single one, we maintain our own offset into them)
|
||||||
|
int global_vtx_offset = 0;
|
||||||
|
int global_idx_offset = 0;
|
||||||
|
ImVec2 clip_off = draw_data->DisplayPos;
|
||||||
|
for (const ImDrawList* draw_list : draw_data->CmdLists)
|
||||||
|
{
|
||||||
|
for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++)
|
||||||
|
{
|
||||||
|
const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i];
|
||||||
|
if (pcmd->UserCallback != nullptr)
|
||||||
|
{
|
||||||
|
// User callback, registered via ImDrawList::AddCallback()
|
||||||
|
if (pcmd->UserCallback == ImGui_ImplDX9_DrawCallback_ResetRenderState)
|
||||||
|
ImGui_ImplDX9_SetupRenderState(draw_data);
|
||||||
|
else
|
||||||
|
pcmd->UserCallback(draw_list, pcmd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
|
||||||
|
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
|
||||||
|
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Apply scissor/clipping rectangle
|
||||||
|
const RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
|
||||||
|
device->SetScissorRect(&r);
|
||||||
|
|
||||||
|
// Bind texture, Draw
|
||||||
|
const LPDIRECT3DTEXTURE9 texture = (LPDIRECT3DTEXTURE9)pcmd->GetTexID();
|
||||||
|
device->SetTexture(0, texture);
|
||||||
|
device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, pcmd->VtxOffset + global_vtx_offset, 0, (UINT)draw_list->VtxBuffer.Size, pcmd->IdxOffset + global_idx_offset, pcmd->ElemCount / 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
global_idx_offset += draw_list->IdxBuffer.Size;
|
||||||
|
global_vtx_offset += draw_list->VtxBuffer.Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore the DX9 transform
|
||||||
|
device->SetTransform(D3DTS_WORLD, &last_world);
|
||||||
|
device->SetTransform(D3DTS_VIEW, &last_view);
|
||||||
|
device->SetTransform(D3DTS_PROJECTION, &last_projection);
|
||||||
|
|
||||||
|
// Restore the DX9 state
|
||||||
|
state_block->Apply();
|
||||||
|
state_block->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ImGui_ImplDX9_CheckFormatSupport(LPDIRECT3DDEVICE9 pDevice, D3DFORMAT format)
|
||||||
|
{
|
||||||
|
LPDIRECT3D9 pd3d = nullptr;
|
||||||
|
if (pDevice->GetDirect3D(&pd3d) != D3D_OK)
|
||||||
|
return false;
|
||||||
|
D3DDEVICE_CREATION_PARAMETERS param = {};
|
||||||
|
D3DDISPLAYMODE mode = {};
|
||||||
|
if (pDevice->GetCreationParameters(¶m) != D3D_OK || pDevice->GetDisplayMode(0, &mode) != D3D_OK)
|
||||||
|
{
|
||||||
|
pd3d->Release();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Font texture should support linear filter, color blend and write to render-target
|
||||||
|
bool support = (pd3d->CheckDeviceFormat(param.AdapterOrdinal, param.DeviceType, mode.Format, D3DUSAGE_DYNAMIC | D3DUSAGE_QUERY_FILTER | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, format)) == D3D_OK;
|
||||||
|
pd3d->Release();
|
||||||
|
return support;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert RGBA32 to BGRA32 (because RGBA32 is not well supported by DX9 devices)
|
||||||
|
static void ImGui_ImplDX9_CopyTextureRegion(bool tex_use_colors, const ImU32* src, int src_pitch, ImU32* dst, int dst_pitch, int w, int h)
|
||||||
|
{
|
||||||
|
#ifndef IMGUI_USE_BGRA_PACKED_COLOR
|
||||||
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
|
const bool convert_rgba_to_bgra = (!bd->HasRgbaSupport && tex_use_colors);
|
||||||
|
#else
|
||||||
|
const bool convert_rgba_to_bgra = false;
|
||||||
|
IM_UNUSED(tex_use_colors);
|
||||||
|
#endif
|
||||||
|
for (int y = 0; y < h; y++)
|
||||||
|
{
|
||||||
|
const ImU32* src_p = (const ImU32*)(const void*)((const unsigned char*)src + src_pitch * y);
|
||||||
|
ImU32* dst_p = (ImU32*)(void*)((unsigned char*)dst + dst_pitch * y);
|
||||||
|
if (convert_rgba_to_bgra)
|
||||||
|
for (int x = w; x > 0; x--, src_p++, dst_p++) // Convert copy
|
||||||
|
*dst_p = IMGUI_COL_TO_DX9_ARGB(*src_p);
|
||||||
|
else
|
||||||
|
memcpy(dst_p, src_p, w * 4); // Raw copy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplDX9_UpdateTexture(ImTextureData* tex)
|
||||||
|
{
|
||||||
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
|
|
||||||
|
if (tex->Status == ImTextureStatus_WantCreate)
|
||||||
|
{
|
||||||
|
// Create and upload new texture to graphics system
|
||||||
|
//IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height);
|
||||||
|
IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr);
|
||||||
|
IM_ASSERT(tex->Format == ImTextureFormat_RGBA32);
|
||||||
|
LPDIRECT3DTEXTURE9 dx_tex = nullptr;
|
||||||
|
HRESULT hr = bd->pd3dDevice->CreateTexture(tex->Width, tex->Height, 1, D3DUSAGE_DYNAMIC, bd->HasRgbaSupport ? D3DFMT_A8B8G8R8 : D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &dx_tex, nullptr);
|
||||||
|
if (hr < 0)
|
||||||
|
{
|
||||||
|
IM_ASSERT(hr >= 0 && "Backend failed to create texture!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3DLOCKED_RECT locked_rect;
|
||||||
|
if (dx_tex->LockRect(0, &locked_rect, nullptr, 0) == D3D_OK)
|
||||||
|
{
|
||||||
|
ImGui_ImplDX9_CopyTextureRegion(tex->UseColors, (ImU32*)tex->GetPixels(), tex->Width * 4, (ImU32*)locked_rect.pBits, (ImU32)locked_rect.Pitch, tex->Width, tex->Height);
|
||||||
|
dx_tex->UnlockRect(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store identifiers
|
||||||
|
tex->SetTexID((ImTextureID)(intptr_t)dx_tex);
|
||||||
|
tex->SetStatus(ImTextureStatus_OK);
|
||||||
|
}
|
||||||
|
else if (tex->Status == ImTextureStatus_WantUpdates)
|
||||||
|
{
|
||||||
|
// Update selected blocks. We only ever write to textures regions which have never been used before!
|
||||||
|
// This backend choose to use tex->Updates[] but you can use tex->UpdateRect to upload a single region.
|
||||||
|
LPDIRECT3DTEXTURE9 backend_tex = (LPDIRECT3DTEXTURE9)(intptr_t)tex->TexID;
|
||||||
|
RECT update_rect = { (LONG)tex->UpdateRect.x, (LONG)tex->UpdateRect.y, (LONG)(tex->UpdateRect.x + tex->UpdateRect.w), (LONG)(tex->UpdateRect.y + tex->UpdateRect.h) };
|
||||||
|
D3DLOCKED_RECT locked_rect;
|
||||||
|
if (backend_tex->LockRect(0, &locked_rect, &update_rect, 0) == D3D_OK)
|
||||||
|
for (ImTextureRect& r : tex->Updates)
|
||||||
|
ImGui_ImplDX9_CopyTextureRegion(tex->UseColors, (ImU32*)tex->GetPixelsAt(r.x, r.y), tex->Width * 4,
|
||||||
|
(ImU32*)locked_rect.pBits + (r.x - update_rect.left) + (r.y - update_rect.top) * (locked_rect.Pitch / 4), (int)locked_rect.Pitch, r.w, r.h);
|
||||||
|
backend_tex->UnlockRect(0);
|
||||||
|
tex->SetStatus(ImTextureStatus_OK);
|
||||||
|
}
|
||||||
|
else if (tex->Status == ImTextureStatus_WantDestroy)
|
||||||
|
{
|
||||||
|
if (tex->TexID != ImTextureID_Invalid)
|
||||||
|
if (LPDIRECT3DTEXTURE9 backend_tex = (LPDIRECT3DTEXTURE9)tex->TexID)
|
||||||
|
{
|
||||||
|
IM_ASSERT(tex->TexID == (ImTextureID)(intptr_t)backend_tex);
|
||||||
|
backend_tex->Release();
|
||||||
|
|
||||||
|
// Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running)
|
||||||
|
tex->SetTexID(ImTextureID_Invalid);
|
||||||
|
}
|
||||||
|
tex->SetStatus(ImTextureStatus_Destroyed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplDX9_CreateDeviceObjects()
|
||||||
|
{
|
||||||
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
|
if (!bd || !bd->pd3dDevice)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplDX9_InvalidateDeviceObjects()
|
||||||
|
{
|
||||||
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
|
if (!bd || !bd->pd3dDevice)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Destroy all textures
|
||||||
|
for (ImTextureData* tex : ImGui::GetPlatformIO().Textures)
|
||||||
|
if (tex->RefCount == 1)
|
||||||
|
{
|
||||||
|
tex->SetStatus(ImTextureStatus_WantDestroy);
|
||||||
|
ImGui_ImplDX9_UpdateTexture(tex);
|
||||||
|
}
|
||||||
|
if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }
|
||||||
|
if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplDX9_NewFrame()
|
||||||
|
{
|
||||||
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
|
IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplDX9_Init()?");
|
||||||
|
IM_UNUSED(bd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool ImGui_ImplDX9_Init(IDirect3DDevice9* device)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IMGUI_CHECKVERSION();
|
||||||
|
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGui_ImplDX9_Data* bd = IM_NEW(ImGui_ImplDX9_Data)();
|
||||||
|
io.BackendRendererUserData = (void*)bd;
|
||||||
|
io.BackendRendererName = "imgui_impl_dx9";
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
|
||||||
|
|
||||||
|
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||||
|
platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = 4096;
|
||||||
|
platform_io.DrawCallback_ResetRenderState = ImGui_ImplDX9_DrawCallback_ResetRenderState;
|
||||||
|
platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplDX9_DrawCallback_SetSamplerLinear;
|
||||||
|
platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplDX9_DrawCallback_SetSamplerNearest;
|
||||||
|
|
||||||
|
bd->pd3dDevice = device;
|
||||||
|
bd->pd3dDevice->AddRef();
|
||||||
|
bd->HasRgbaSupport = ImGui_ImplDX9_CheckFormatSupport(bd->pd3dDevice, D3DFMT_A8B8G8R8);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplDX9_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
|
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||||
|
|
||||||
|
ImGui_ImplDX9_InvalidateDeviceObjects();
|
||||||
|
if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
|
||||||
|
|
||||||
|
io.BackendRendererName = nullptr;
|
||||||
|
io.BackendRendererUserData = nullptr;
|
||||||
|
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
|
||||||
|
platform_io.ClearRendererHandlers();
|
||||||
|
IM_DELETE(bd);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#endif // #ifndef IMGUI_DISABLE
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
// dear imgui: Renderer Backend for DirectX9
|
||||||
|
// This needs to be used along with a Platform Backend (e.g. Win32)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
|
||||||
|
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||||
|
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||||
|
// [X] Renderer: IMGUI_USE_BGRA_PACKED_COLOR support, as this is the optimal color encoding for DirectX9.
|
||||||
|
|
||||||
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// Learn about Dear ImGui:
|
||||||
|
// - FAQ https://dearimgui.com/faq
|
||||||
|
// - Getting Started https://dearimgui.com/getting-started
|
||||||
|
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||||
|
// - Introduction, links and more at the top of imgui.cpp
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
#ifndef IMGUI_DISABLE
|
||||||
|
|
||||||
|
struct IDirect3DDevice9;
|
||||||
|
|
||||||
|
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplDX9_Init(IDirect3DDevice9* device);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX9_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX9_NewFrame();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data);
|
||||||
|
|
||||||
|
// Use if you want to reset your rendering device without losing Dear ImGui state.
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplDX9_CreateDeviceObjects();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX9_InvalidateDeviceObjects();
|
||||||
|
|
||||||
|
// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually.
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX9_UpdateTexture(ImTextureData* tex);
|
||||||
|
|
||||||
|
#endif // #ifndef IMGUI_DISABLE
|
||||||
+1008
File diff suppressed because it is too large
Load Diff
+53
@@ -0,0 +1,53 @@
|
|||||||
|
// dear imgui: Platform Backend for Windows (standard windows API for 32-bits AND 64-bits applications)
|
||||||
|
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui)
|
||||||
|
// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen.
|
||||||
|
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values are obsolete since 1.87 and not supported since 1.91.5]
|
||||||
|
// [X] Platform: Gamepad support.
|
||||||
|
// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||||
|
|
||||||
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// Learn about Dear ImGui:
|
||||||
|
// - FAQ https://dearimgui.com/faq
|
||||||
|
// - Getting Started https://dearimgui.com/getting-started
|
||||||
|
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||||
|
// - Introduction, links and more at the top of imgui.cpp
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
#ifndef IMGUI_DISABLE
|
||||||
|
|
||||||
|
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd);
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplWin32_InitForOpenGL(void* hwnd);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame();
|
||||||
|
|
||||||
|
// Win32 message handler your application needs to call.
|
||||||
|
// - Intentionally commented out in a '#if 0' block to avoid dragging dependencies on <windows.h> from this helper.
|
||||||
|
// - You should COPY the line below into your .cpp code to forward declare the function and then you can call it.
|
||||||
|
// - Call from your application's message handler. Keep calling your message handler unless this function returns TRUE.
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// DPI-related helpers (optional)
|
||||||
|
// - Use to enable DPI awareness without having to create an application manifest.
|
||||||
|
// - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps.
|
||||||
|
// - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc.
|
||||||
|
// but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime,
|
||||||
|
// neither of which we want to require the user to have. So we dynamically select and load those functions to avoid dependencies.
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplWin32_EnableDpiAwareness();
|
||||||
|
IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd); // HWND hwnd
|
||||||
|
IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); // HMONITOR monitor
|
||||||
|
|
||||||
|
// Transparency related helpers (optional) [experimental]
|
||||||
|
// - Use to enable alpha compositing transparency with the desktop.
|
||||||
|
// - Use together with e.g. clearing your framebuffer with zero-alpha.
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd); // HWND hwnd
|
||||||
|
|
||||||
|
#endif // #ifndef IMGUI_DISABLE
|
||||||
+4027
File diff suppressed because it is too large
Load Diff
+4665
File diff suppressed because it is too large
Load Diff
+10992
File diff suppressed because it is too large
Load Diff
+627
@@ -0,0 +1,627 @@
|
|||||||
|
// [DEAR IMGUI]
|
||||||
|
// This is a slightly modified version of stb_rect_pack.h 1.01.
|
||||||
|
// Grep for [DEAR IMGUI] to find the changes.
|
||||||
|
//
|
||||||
|
// stb_rect_pack.h - v1.01 - public domain - rectangle packing
|
||||||
|
// Sean Barrett 2014
|
||||||
|
//
|
||||||
|
// Useful for e.g. packing rectangular textures into an atlas.
|
||||||
|
// Does not do rotation.
|
||||||
|
//
|
||||||
|
// Before #including,
|
||||||
|
//
|
||||||
|
// #define STB_RECT_PACK_IMPLEMENTATION
|
||||||
|
//
|
||||||
|
// in the file that you want to have the implementation.
|
||||||
|
//
|
||||||
|
// Not necessarily the awesomest packing method, but better than
|
||||||
|
// the totally naive one in stb_truetype (which is primarily what
|
||||||
|
// this is meant to replace).
|
||||||
|
//
|
||||||
|
// Has only had a few tests run, may have issues.
|
||||||
|
//
|
||||||
|
// More docs to come.
|
||||||
|
//
|
||||||
|
// No memory allocations; uses qsort() and assert() from stdlib.
|
||||||
|
// Can override those by defining STBRP_SORT and STBRP_ASSERT.
|
||||||
|
//
|
||||||
|
// This library currently uses the Skyline Bottom-Left algorithm.
|
||||||
|
//
|
||||||
|
// Please note: better rectangle packers are welcome! Please
|
||||||
|
// implement them to the same API, but with a different init
|
||||||
|
// function.
|
||||||
|
//
|
||||||
|
// Credits
|
||||||
|
//
|
||||||
|
// Library
|
||||||
|
// Sean Barrett
|
||||||
|
// Minor features
|
||||||
|
// Martins Mozeiko
|
||||||
|
// github:IntellectualKitty
|
||||||
|
//
|
||||||
|
// Bugfixes / warning fixes
|
||||||
|
// Jeremy Jaussaud
|
||||||
|
// Fabian Giesen
|
||||||
|
//
|
||||||
|
// Version history:
|
||||||
|
//
|
||||||
|
// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section
|
||||||
|
// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
|
||||||
|
// 0.99 (2019-02-07) warning fixes
|
||||||
|
// 0.11 (2017-03-03) return packing success/fail result
|
||||||
|
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
|
||||||
|
// 0.09 (2016-08-27) fix compiler warnings
|
||||||
|
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
|
||||||
|
// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
|
||||||
|
// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
|
||||||
|
// 0.05: added STBRP_ASSERT to allow replacing assert
|
||||||
|
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
|
||||||
|
// 0.01: initial release
|
||||||
|
//
|
||||||
|
// LICENSE
|
||||||
|
//
|
||||||
|
// See end of file for license information.
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// INCLUDE SECTION
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef STB_INCLUDE_STB_RECT_PACK_H
|
||||||
|
#define STB_INCLUDE_STB_RECT_PACK_H
|
||||||
|
|
||||||
|
#define STB_RECT_PACK_VERSION 1
|
||||||
|
|
||||||
|
#ifdef STBRP_STATIC
|
||||||
|
#define STBRP_DEF static
|
||||||
|
#else
|
||||||
|
#define STBRP_DEF extern
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct stbrp_context stbrp_context;
|
||||||
|
typedef struct stbrp_node stbrp_node;
|
||||||
|
typedef struct stbrp_rect stbrp_rect;
|
||||||
|
|
||||||
|
typedef int stbrp_coord;
|
||||||
|
|
||||||
|
#define STBRP__MAXVAL 0x7fffffff
|
||||||
|
// Mostly for internal use, but this is the maximum supported coordinate value.
|
||||||
|
|
||||||
|
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
|
||||||
|
// Assign packed locations to rectangles. The rectangles are of type
|
||||||
|
// 'stbrp_rect' defined below, stored in the array 'rects', and there
|
||||||
|
// are 'num_rects' many of them.
|
||||||
|
//
|
||||||
|
// Rectangles which are successfully packed have the 'was_packed' flag
|
||||||
|
// set to a non-zero value and 'x' and 'y' store the minimum location
|
||||||
|
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
|
||||||
|
// if you imagine y increasing downwards). Rectangles which do not fit
|
||||||
|
// have the 'was_packed' flag set to 0.
|
||||||
|
//
|
||||||
|
// You should not try to access the 'rects' array from another thread
|
||||||
|
// while this function is running, as the function temporarily reorders
|
||||||
|
// the array while it executes.
|
||||||
|
//
|
||||||
|
// To pack into another rectangle, you need to call stbrp_init_target
|
||||||
|
// again. To continue packing into the same rectangle, you can call
|
||||||
|
// this function again. Calling this multiple times with multiple rect
|
||||||
|
// arrays will probably produce worse packing results than calling it
|
||||||
|
// a single time with the full rectangle array, but the option is
|
||||||
|
// available.
|
||||||
|
//
|
||||||
|
// The function returns 1 if all of the rectangles were successfully
|
||||||
|
// packed and 0 otherwise.
|
||||||
|
|
||||||
|
struct stbrp_rect
|
||||||
|
{
|
||||||
|
// reserved for your use:
|
||||||
|
int id;
|
||||||
|
|
||||||
|
// input:
|
||||||
|
stbrp_coord w, h;
|
||||||
|
|
||||||
|
// output:
|
||||||
|
stbrp_coord x, y;
|
||||||
|
int was_packed; // non-zero if valid packing
|
||||||
|
|
||||||
|
}; // 16 bytes, nominally
|
||||||
|
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
|
||||||
|
// Initialize a rectangle packer to:
|
||||||
|
// pack a rectangle that is 'width' by 'height' in dimensions
|
||||||
|
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
|
||||||
|
//
|
||||||
|
// You must call this function every time you start packing into a new target.
|
||||||
|
//
|
||||||
|
// There is no "shutdown" function. The 'nodes' memory must stay valid for
|
||||||
|
// the following stbrp_pack_rects() call (or calls), but can be freed after
|
||||||
|
// the call (or calls) finish.
|
||||||
|
//
|
||||||
|
// Note: to guarantee best results, either:
|
||||||
|
// 1. make sure 'num_nodes' >= 'width'
|
||||||
|
// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
|
||||||
|
//
|
||||||
|
// If you don't do either of the above things, widths will be quantized to multiples
|
||||||
|
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
|
||||||
|
//
|
||||||
|
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
|
||||||
|
// may run out of temporary storage and be unable to pack some rectangles.
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
|
||||||
|
// Optionally call this function after init but before doing any packing to
|
||||||
|
// change the handling of the out-of-temp-memory scenario, described above.
|
||||||
|
// If you call init again, this will be reset to the default (false).
|
||||||
|
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
|
||||||
|
// Optionally select which packing heuristic the library should use. Different
|
||||||
|
// heuristics will produce better/worse results for different data sets.
|
||||||
|
// If you call init again, this will be reset to the default.
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
STBRP_HEURISTIC_Skyline_default=0,
|
||||||
|
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
|
||||||
|
STBRP_HEURISTIC_Skyline_BF_sortHeight
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// the details of the following structures don't matter to you, but they must
|
||||||
|
// be visible so you can handle the memory allocations for them
|
||||||
|
|
||||||
|
struct stbrp_node
|
||||||
|
{
|
||||||
|
stbrp_coord x,y;
|
||||||
|
stbrp_node *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct stbrp_context
|
||||||
|
{
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int align;
|
||||||
|
int init_mode;
|
||||||
|
int heuristic;
|
||||||
|
int num_nodes;
|
||||||
|
stbrp_node *active_head;
|
||||||
|
stbrp_node *free_head;
|
||||||
|
stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// IMPLEMENTATION SECTION
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifdef STB_RECT_PACK_IMPLEMENTATION
|
||||||
|
#ifndef STBRP_SORT
|
||||||
|
#include <stdlib.h>
|
||||||
|
#define STBRP_SORT qsort
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STBRP_ASSERT
|
||||||
|
#include <assert.h>
|
||||||
|
#define STBRP_ASSERT assert
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define STBRP__NOTUSED(v) (void)(v)
|
||||||
|
#define STBRP__CDECL __cdecl
|
||||||
|
#else
|
||||||
|
#define STBRP__NOTUSED(v) (void)sizeof(v)
|
||||||
|
#define STBRP__CDECL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
STBRP__INIT_skyline = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
|
||||||
|
{
|
||||||
|
switch (context->init_mode) {
|
||||||
|
case STBRP__INIT_skyline:
|
||||||
|
STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
|
||||||
|
context->heuristic = heuristic;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
STBRP_ASSERT(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
|
||||||
|
{
|
||||||
|
if (allow_out_of_mem)
|
||||||
|
// if it's ok to run out of memory, then don't bother aligning them;
|
||||||
|
// this gives better packing, but may fail due to OOM (even though
|
||||||
|
// the rectangles easily fit). @TODO a smarter approach would be to only
|
||||||
|
// quantize once we've hit OOM, then we could get rid of this parameter.
|
||||||
|
context->align = 1;
|
||||||
|
else {
|
||||||
|
// if it's not ok to run out of memory, then quantize the widths
|
||||||
|
// so that num_nodes is always enough nodes.
|
||||||
|
//
|
||||||
|
// I.e. num_nodes * align >= width
|
||||||
|
// align >= width / num_nodes
|
||||||
|
// align = ceil(width/num_nodes)
|
||||||
|
|
||||||
|
context->align = (context->width + context->num_nodes-1) / context->num_nodes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i < num_nodes-1; ++i)
|
||||||
|
nodes[i].next = &nodes[i+1];
|
||||||
|
nodes[i].next = NULL;
|
||||||
|
context->init_mode = STBRP__INIT_skyline;
|
||||||
|
context->heuristic = STBRP_HEURISTIC_Skyline_default;
|
||||||
|
context->free_head = &nodes[0];
|
||||||
|
context->active_head = &context->extra[0];
|
||||||
|
context->width = width;
|
||||||
|
context->height = height;
|
||||||
|
context->num_nodes = num_nodes;
|
||||||
|
stbrp_setup_allow_out_of_mem(context, 0);
|
||||||
|
|
||||||
|
// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
|
||||||
|
context->extra[0].x = 0;
|
||||||
|
context->extra[0].y = 0;
|
||||||
|
context->extra[0].next = &context->extra[1];
|
||||||
|
context->extra[1].x = (stbrp_coord) width;
|
||||||
|
context->extra[1].y = (1<<30);
|
||||||
|
context->extra[1].next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find minimum y position if it starts at x1
|
||||||
|
static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
|
||||||
|
{
|
||||||
|
stbrp_node *node = first;
|
||||||
|
int x1 = x0 + width;
|
||||||
|
int min_y, visited_width, waste_area;
|
||||||
|
|
||||||
|
STBRP__NOTUSED(c);
|
||||||
|
|
||||||
|
STBRP_ASSERT(first->x <= x0);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// skip in case we're past the node
|
||||||
|
while (node->next->x <= x0)
|
||||||
|
++node;
|
||||||
|
#else
|
||||||
|
STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
|
||||||
|
#endif
|
||||||
|
|
||||||
|
STBRP_ASSERT(node->x <= x0);
|
||||||
|
|
||||||
|
min_y = 0;
|
||||||
|
waste_area = 0;
|
||||||
|
visited_width = 0;
|
||||||
|
while (node->x < x1) {
|
||||||
|
if (node->y > min_y) {
|
||||||
|
// raise min_y higher.
|
||||||
|
// we've accounted for all waste up to min_y,
|
||||||
|
// but we'll now add more waste for everything we've visited
|
||||||
|
waste_area += visited_width * (node->y - min_y);
|
||||||
|
min_y = node->y;
|
||||||
|
// the first time through, visited_width might be reduced
|
||||||
|
if (node->x < x0)
|
||||||
|
visited_width += node->next->x - x0;
|
||||||
|
else
|
||||||
|
visited_width += node->next->x - node->x;
|
||||||
|
} else {
|
||||||
|
// add waste area
|
||||||
|
int under_width = node->next->x - node->x;
|
||||||
|
if (under_width + visited_width > width)
|
||||||
|
under_width = width - visited_width;
|
||||||
|
waste_area += under_width * (min_y - node->y);
|
||||||
|
visited_width += under_width;
|
||||||
|
}
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pwaste = waste_area;
|
||||||
|
return min_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int x,y;
|
||||||
|
stbrp_node **prev_link;
|
||||||
|
} stbrp__findresult;
|
||||||
|
|
||||||
|
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
|
||||||
|
{
|
||||||
|
int best_waste = (1<<30), best_x, best_y = (1 << 30);
|
||||||
|
stbrp__findresult fr;
|
||||||
|
stbrp_node **prev, *node, *tail, **best = NULL;
|
||||||
|
|
||||||
|
// align to multiple of c->align
|
||||||
|
width = (width + c->align - 1);
|
||||||
|
width -= width % c->align;
|
||||||
|
STBRP_ASSERT(width % c->align == 0);
|
||||||
|
|
||||||
|
// if it can't possibly fit, bail immediately
|
||||||
|
if (width > c->width || height > c->height) {
|
||||||
|
fr.prev_link = NULL;
|
||||||
|
fr.x = fr.y = 0;
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = c->active_head;
|
||||||
|
prev = &c->active_head;
|
||||||
|
while (node->x + width <= c->width) {
|
||||||
|
int y,waste;
|
||||||
|
y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
|
||||||
|
if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
|
||||||
|
// bottom left
|
||||||
|
if (y < best_y) {
|
||||||
|
best_y = y;
|
||||||
|
best = prev;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// best-fit
|
||||||
|
if (y + height <= c->height) {
|
||||||
|
// can only use it if it first vertically
|
||||||
|
if (y < best_y || (y == best_y && waste < best_waste)) {
|
||||||
|
best_y = y;
|
||||||
|
best_waste = waste;
|
||||||
|
best = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev = &node->next;
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
best_x = (best == NULL) ? 0 : (*best)->x;
|
||||||
|
|
||||||
|
// if doing best-fit (BF), we also have to try aligning right edge to each node position
|
||||||
|
//
|
||||||
|
// e.g, if fitting
|
||||||
|
//
|
||||||
|
// ____________________
|
||||||
|
// |____________________|
|
||||||
|
//
|
||||||
|
// into
|
||||||
|
//
|
||||||
|
// | |
|
||||||
|
// | ____________|
|
||||||
|
// |____________|
|
||||||
|
//
|
||||||
|
// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
|
||||||
|
//
|
||||||
|
// This makes BF take about 2x the time
|
||||||
|
|
||||||
|
if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
|
||||||
|
tail = c->active_head;
|
||||||
|
node = c->active_head;
|
||||||
|
prev = &c->active_head;
|
||||||
|
// find first node that's admissible
|
||||||
|
while (tail->x < width)
|
||||||
|
tail = tail->next;
|
||||||
|
while (tail) {
|
||||||
|
int xpos = tail->x - width;
|
||||||
|
int y,waste;
|
||||||
|
STBRP_ASSERT(xpos >= 0);
|
||||||
|
// find the left position that matches this
|
||||||
|
while (node->next->x <= xpos) {
|
||||||
|
prev = &node->next;
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
|
||||||
|
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
|
||||||
|
if (y + height <= c->height) {
|
||||||
|
if (y <= best_y) {
|
||||||
|
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
|
||||||
|
best_x = xpos;
|
||||||
|
//STBRP_ASSERT(y <= best_y); [DEAR IMGUI]
|
||||||
|
best_y = y;
|
||||||
|
best_waste = waste;
|
||||||
|
best = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tail = tail->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fr.prev_link = best;
|
||||||
|
fr.x = best_x;
|
||||||
|
fr.y = best_y;
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
|
||||||
|
{
|
||||||
|
// find best position according to heuristic
|
||||||
|
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
|
||||||
|
stbrp_node *node, *cur;
|
||||||
|
|
||||||
|
// bail if:
|
||||||
|
// 1. it failed
|
||||||
|
// 2. the best node doesn't fit (we don't always check this)
|
||||||
|
// 3. we're out of memory
|
||||||
|
if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
|
||||||
|
res.prev_link = NULL;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// on success, create new node
|
||||||
|
node = context->free_head;
|
||||||
|
node->x = (stbrp_coord) res.x;
|
||||||
|
node->y = (stbrp_coord) (res.y + height);
|
||||||
|
|
||||||
|
context->free_head = node->next;
|
||||||
|
|
||||||
|
// insert the new node into the right starting point, and
|
||||||
|
// let 'cur' point to the remaining nodes needing to be
|
||||||
|
// stitched back in
|
||||||
|
|
||||||
|
cur = *res.prev_link;
|
||||||
|
if (cur->x < res.x) {
|
||||||
|
// preserve the existing one, so start testing with the next one
|
||||||
|
stbrp_node *next = cur->next;
|
||||||
|
cur->next = node;
|
||||||
|
cur = next;
|
||||||
|
} else {
|
||||||
|
*res.prev_link = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// from here, traverse cur and free the nodes, until we get to one
|
||||||
|
// that shouldn't be freed
|
||||||
|
while (cur->next && cur->next->x <= res.x + width) {
|
||||||
|
stbrp_node *next = cur->next;
|
||||||
|
// move the current node to the free list
|
||||||
|
cur->next = context->free_head;
|
||||||
|
context->free_head = cur;
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// stitch the list back in
|
||||||
|
node->next = cur;
|
||||||
|
|
||||||
|
if (cur->x < res.x + width)
|
||||||
|
cur->x = (stbrp_coord) (res.x + width);
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
cur = context->active_head;
|
||||||
|
while (cur->x < context->width) {
|
||||||
|
STBRP_ASSERT(cur->x < cur->next->x);
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
STBRP_ASSERT(cur->next == NULL);
|
||||||
|
|
||||||
|
{
|
||||||
|
int count=0;
|
||||||
|
cur = context->active_head;
|
||||||
|
while (cur) {
|
||||||
|
cur = cur->next;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
cur = context->free_head;
|
||||||
|
while (cur) {
|
||||||
|
cur = cur->next;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
STBRP_ASSERT(count == context->num_nodes+2);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||||
|
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||||
|
if (p->h > q->h)
|
||||||
|
return -1;
|
||||||
|
if (p->h < q->h)
|
||||||
|
return 1;
|
||||||
|
return (p->w > q->w) ? -1 : (p->w < q->w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||||
|
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||||
|
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
|
||||||
|
}
|
||||||
|
|
||||||
|
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
|
||||||
|
{
|
||||||
|
int i, all_rects_packed = 1;
|
||||||
|
|
||||||
|
// we use the 'was_packed' field internally to allow sorting/unsorting
|
||||||
|
for (i=0; i < num_rects; ++i) {
|
||||||
|
rects[i].was_packed = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort according to heuristic
|
||||||
|
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
|
||||||
|
|
||||||
|
for (i=0; i < num_rects; ++i) {
|
||||||
|
if (rects[i].w == 0 || rects[i].h == 0) {
|
||||||
|
rects[i].x = rects[i].y = 0; // empty rect needs no space
|
||||||
|
} else {
|
||||||
|
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
|
||||||
|
if (fr.prev_link) {
|
||||||
|
rects[i].x = (stbrp_coord) fr.x;
|
||||||
|
rects[i].y = (stbrp_coord) fr.y;
|
||||||
|
} else {
|
||||||
|
rects[i].x = rects[i].y = STBRP__MAXVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsort
|
||||||
|
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
|
||||||
|
|
||||||
|
// set was_packed flags and all_rects_packed status
|
||||||
|
for (i=0; i < num_rects; ++i) {
|
||||||
|
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
|
||||||
|
if (!rects[i].was_packed)
|
||||||
|
all_rects_packed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the all_rects_packed status
|
||||||
|
return all_rects_packed;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
This software is available under 2 licenses -- choose whichever you prefer.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
ALTERNATIVE A - MIT License
|
||||||
|
Copyright (c) 2017 Sean Barrett
|
||||||
|
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.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||||
|
software, either in source code form or as a compiled binary, for any purpose,
|
||||||
|
commercial or non-commercial, and by any means.
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||||
|
software dedicate any and all copyright interest in the software to the public
|
||||||
|
domain. We make this dedication for the benefit of the public at large and to
|
||||||
|
the detriment of our heirs and successors. We intend this dedication to be an
|
||||||
|
overt act of relinquishment in perpetuity of all present and future rights to
|
||||||
|
this software under copyright law.
|
||||||
|
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 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.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
+1527
File diff suppressed because it is too large
Load Diff
+5085
File diff suppressed because it is too large
Load Diff
+26
@@ -0,0 +1,26 @@
|
|||||||
|
# EditorConfig is awesome: http://EditorConfig.org
|
||||||
|
|
||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# Windows-style newlines with a newline ending every file
|
||||||
|
[*]
|
||||||
|
end_of_line = crlf
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
# 4 space indentation
|
||||||
|
[*.{c,h,def}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
# Trim trailing whitespaces
|
||||||
|
[*.{c,h,def,txt}]
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
# UTF-8 with BOM
|
||||||
|
[*.{c,h,def,txt}]
|
||||||
|
charset=utf-8-bom
|
||||||
|
|
||||||
|
# C/C++ code formatting
|
||||||
|
[*.{c,h}]
|
||||||
|
cpp_space_pointer_reference_alignment = right
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
name: Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
branches: [ "master" ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
# Path to the solution file relative to the root of the project.
|
||||||
|
SOLUTION_FILE_PATH: build/VC17/MinHookVC17.sln
|
||||||
|
|
||||||
|
# Configuration type to build.
|
||||||
|
# You can convert this to a build matrix if you need coverage of multiple configuration types.
|
||||||
|
# https://docs.github.com/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
|
||||||
|
BUILD_CONFIGURATION: Release
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: windows-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Add MSBuild to PATH
|
||||||
|
uses: microsoft/setup-msbuild@v2
|
||||||
|
|
||||||
|
- name: Build Win32
|
||||||
|
# Add additional options to the MSBuild command line here (like platform or verbosity level).
|
||||||
|
# See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference
|
||||||
|
run: msbuild /m /p:Configuration=${{ env.BUILD_CONFIGURATION }} /p:Platform="Win32" ${{ env.SOLUTION_FILE_PATH }}
|
||||||
|
|
||||||
|
- name: Build x64
|
||||||
|
# Add additional options to the MSBuild command line here (like platform or verbosity level).
|
||||||
|
# See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference
|
||||||
|
run: msbuild /m /p:Configuration=${{ env.BUILD_CONFIGURATION }} /p:Platform="x64" ${{ env.SOLUTION_FILE_PATH }}
|
||||||
|
|
||||||
|
- name: Collect artifacts
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir "${{ runner.temp }}/artifacts"
|
||||||
|
mv "build/VC17/bin/${{ env.BUILD_CONFIGURATION }}" "${{ runner.temp }}/artifacts/bin"
|
||||||
|
mv "build/VC17/lib/${{ env.BUILD_CONFIGURATION }}" "${{ runner.temp }}/artifacts/lib"
|
||||||
|
cp -r include "${{ runner.temp }}/artifacts/include"
|
||||||
|
|
||||||
|
- name: Package bin
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: MinHook_bin
|
||||||
|
path: |
|
||||||
|
${{ runner.temp }}/artifacts/bin/
|
||||||
|
${{ runner.temp }}/artifacts/include/
|
||||||
|
|
||||||
|
- name: Package lib
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: MinHook_lib
|
||||||
|
path: |
|
||||||
|
${{ runner.temp }}/artifacts/lib/
|
||||||
|
${{ runner.temp }}/artifacts/include/
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#OS junk files
|
||||||
|
[Tt]humbs.db
|
||||||
|
*.DS_Store
|
||||||
|
|
||||||
|
#Visual Studio files
|
||||||
|
*.[Oo]bj
|
||||||
|
*.user
|
||||||
|
*.aps
|
||||||
|
*.pch
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*.ncb
|
||||||
|
*.suo
|
||||||
|
*.tlb
|
||||||
|
*.tlh
|
||||||
|
*.bak
|
||||||
|
*.[Cc]ache
|
||||||
|
*.ilk
|
||||||
|
*.log
|
||||||
|
*.sbr
|
||||||
|
*.sdf
|
||||||
|
*.opensdf
|
||||||
|
*.unsuccessfulbuild
|
||||||
|
ipch/
|
||||||
|
obj/
|
||||||
|
[Ll]ib
|
||||||
|
[Bb]in
|
||||||
|
[Dd]ebug*/
|
||||||
|
[Rr]elease*/
|
||||||
|
Ankh.NoLoad
|
||||||
|
*.VC.db
|
||||||
|
.vs/
|
||||||
|
|
||||||
|
#GCC files
|
||||||
|
*.o
|
||||||
|
*.d
|
||||||
|
*.res
|
||||||
|
*.dll
|
||||||
|
*.a
|
||||||
|
|
||||||
|
#Visual Studio Code files
|
||||||
|
.vscode/
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
Tsuda Kageyu <tsuda.kageyu@gmail.com>
|
||||||
|
Creator, maintainer
|
||||||
|
|
||||||
|
Michael Maltsev <leahcimmar@gmail.com>
|
||||||
|
Added "Queue" functions. A lot of bug fixes.
|
||||||
|
|
||||||
|
Andrey Unis <uniskz@gmail.com>
|
||||||
|
Rewrote the hook engine in plain C.
|
||||||
+141
@@ -0,0 +1,141 @@
|
|||||||
|
# MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||||
|
# Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
#
|
||||||
|
# 1. Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||||
|
# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.0...3.5)
|
||||||
|
|
||||||
|
project(minhook LANGUAGES C)
|
||||||
|
|
||||||
|
include(CMakePackageConfigHelpers)
|
||||||
|
|
||||||
|
set(MINHOOK_MAJOR_VERSION 1)
|
||||||
|
set(MINHOOK_MINOR_VERSION 3)
|
||||||
|
set(MINHOOK_PATCH_VERSION 3)
|
||||||
|
set(MINHOOK_VERSION ${MINHOOK_MAJOR_VERSION}.${MINHOOK_MINOR_VERSION}.${MINHOOK_PATCH_VERSION})
|
||||||
|
|
||||||
|
################
|
||||||
|
# BUILD #
|
||||||
|
################
|
||||||
|
|
||||||
|
option(BUILD_SHARED_LIBS "build shared version" OFF)
|
||||||
|
|
||||||
|
set(SOURCES_MINHOOK
|
||||||
|
"src/buffer.c"
|
||||||
|
"src/hook.c"
|
||||||
|
"src/trampoline.c"
|
||||||
|
)
|
||||||
|
|
||||||
|
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
|
set(SOURCES_HDE "src/hde/hde64.c")
|
||||||
|
else()
|
||||||
|
set(SOURCES_HDE "src/hde/hde32.c")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(BUILD_SHARED_LIBS)
|
||||||
|
set(RESOURCES
|
||||||
|
"dll_resources/MinHook.rc"
|
||||||
|
"dll_resources/MinHook.def"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_library(minhook ${SOURCES_MINHOOK} ${SOURCES_HDE} ${RESOURCES})
|
||||||
|
|
||||||
|
target_include_directories(minhook PUBLIC
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/>
|
||||||
|
$<INSTALL_INTERFACE:include>
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(minhook PRIVATE "src/")
|
||||||
|
target_include_directories(minhook PRIVATE "src/hde/")
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set_target_properties(minhook PROPERTIES PREFIX "")
|
||||||
|
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
|
set_target_properties(minhook PROPERTIES DEBUG_POSTFIX ".x64d")
|
||||||
|
set_target_properties(minhook PROPERTIES RELEASE_POSTFIX ".x64")
|
||||||
|
set_target_properties(minhook PROPERTIES RELWITHDEBINFO_POSTFIX ".x64")
|
||||||
|
set_target_properties(minhook PROPERTIES MINSIZEREL_POSTFIX ".x64")
|
||||||
|
else()
|
||||||
|
set_target_properties(minhook PROPERTIES DEBUG_POSTFIX ".x32d")
|
||||||
|
set_target_properties(minhook PROPERTIES RELEASE_POSTFIX ".x32")
|
||||||
|
set_target_properties(minhook PROPERTIES RELWITHDEBINFO_POSTFIX ".x32")
|
||||||
|
set_target_properties(minhook PROPERTIES MINSIZEREL_POSTFIX ".x32")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set_target_properties(minhook PROPERTIES PREFIX "lib")
|
||||||
|
set_target_properties(minhook PROPERTIES POSTFIX "")
|
||||||
|
set_target_properties(minhook PROPERTIES DEBUG_POSTFIX "d")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
################
|
||||||
|
# CMAKE CONFIG #
|
||||||
|
################
|
||||||
|
|
||||||
|
configure_package_config_file(
|
||||||
|
"cmake/minhook-config.cmake.in"
|
||||||
|
"minhook-config.cmake"
|
||||||
|
INSTALL_DESTINATION
|
||||||
|
"share/minhook"
|
||||||
|
)
|
||||||
|
|
||||||
|
write_basic_package_version_file(
|
||||||
|
"minhook-config-version.cmake"
|
||||||
|
VERSION
|
||||||
|
${MINHOOK_VERSION}
|
||||||
|
COMPATIBILITY
|
||||||
|
AnyNewerVersion
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/minhook-config.cmake"
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/minhook-config-version.cmake"
|
||||||
|
DESTINATION
|
||||||
|
"share/minhook"
|
||||||
|
)
|
||||||
|
|
||||||
|
###################
|
||||||
|
# INSTALL #
|
||||||
|
###################
|
||||||
|
|
||||||
|
install(TARGETS minhook
|
||||||
|
EXPORT minhook-targets
|
||||||
|
RUNTIME DESTINATION "bin"
|
||||||
|
ARCHIVE DESTINATION "lib"
|
||||||
|
LIBRARY DESTINATION "lib"
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
EXPORT
|
||||||
|
minhook-targets
|
||||||
|
NAMESPACE
|
||||||
|
minhook::
|
||||||
|
DESTINATION
|
||||||
|
"share/minhook"
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
DIRECTORY include DESTINATION .
|
||||||
|
)
|
||||||
+81
@@ -0,0 +1,81 @@
|
|||||||
|
MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||||
|
Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||||
|
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
Portions of this software are Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||||
|
================================================================================
|
||||||
|
Hacker Disassembler Engine 32 C
|
||||||
|
Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Hacker Disassembler Engine 64 C
|
||||||
|
Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
+94
@@ -0,0 +1,94 @@
|
|||||||
|
# MinHook
|
||||||
|
|
||||||
|
[](https://opensource.org/licenses/BSD-2-Clause)
|
||||||
|
|
||||||
|
The Minimalistic x86/x64 API Hooking Library for Windows
|
||||||
|
|
||||||
|
https://www.codeproject.com/articles/MinHook-The-Minimalistic-x-x-API-Hooking-Libra
|
||||||
|
|
||||||
|
### Version history
|
||||||
|
|
||||||
|
- **v1.3.4 - 28 Mar 2025**
|
||||||
|
* Improved error handling for enumerating and suspending threads.
|
||||||
|
* Visual Studio 2022 support.
|
||||||
|
* CMake support.
|
||||||
|
* Fixed compilation with Clang.
|
||||||
|
* Fixed compilation as C++ code.
|
||||||
|
|
||||||
|
- **v1.3.3 - 8 Jan 2017**
|
||||||
|
* Added a helper function ```MH_CreateHookApiEx```. (Thanks to asm256)
|
||||||
|
* Support Visual Studio 2017 RC.
|
||||||
|
|
||||||
|
- **v1.3.2.1 - 9 Nov 2015** (Nuget package only)
|
||||||
|
* Fixed an insufficient support for Visual Studio 2015.
|
||||||
|
|
||||||
|
- **v1.3.2 - 1 Nov 2015**
|
||||||
|
* Support Visual Studio 2015.
|
||||||
|
* Support MinGW.
|
||||||
|
|
||||||
|
- **v1.3.2-beta3 - 21 Jul 2015** (Nuget package only)
|
||||||
|
* Support MinGW. (Experimental)
|
||||||
|
|
||||||
|
- **v1.3.2-beta2 - 18 May 2015**
|
||||||
|
* Fixed some subtle bugs. (Thanks to RaMMicHaeL)
|
||||||
|
* Added a helper function ```MH_StatusToString```. (Thanks to Jan Klass)
|
||||||
|
|
||||||
|
- **v1.3.2-beta - 12 May 2015**
|
||||||
|
* Fixed a possible thread deadlock in x64 mode. (Thanks to Aleh Kazakevich)
|
||||||
|
* Reduced the footprint a little more.
|
||||||
|
* Support Visual Studio 2015 RC. (Experimental)
|
||||||
|
|
||||||
|
- **v1.3.1.1 - 7 Apr 2015** (Nuget package only)
|
||||||
|
* Support for WDK8.0 and 8.1.
|
||||||
|
|
||||||
|
- **v1.3.1 - 19 Mar 2015**
|
||||||
|
* No major changes from v1.3.1-beta.
|
||||||
|
|
||||||
|
- **v1.3.1-beta - 11 Mar 2015**
|
||||||
|
* Added a helper function ```MH_CreateHookApi```. (Thanks to uniskz).
|
||||||
|
* Fixed a false memory leak reported by some tools.
|
||||||
|
* Fixed a degradated compatibility issue.
|
||||||
|
|
||||||
|
- **v1.3 - 13 Sep 2014**
|
||||||
|
* No major changes from v1.3-beta3.
|
||||||
|
|
||||||
|
- **v1.3-beta3 - 31 Jul 2014**
|
||||||
|
* Fixed some small bugs.
|
||||||
|
* Improved the memory management.
|
||||||
|
|
||||||
|
- **v1.3-beta2 - 21 Jul 2014**
|
||||||
|
* Changed the parameters to Windows-friendly types. (void* to LPVOID)
|
||||||
|
* Fixed some small bugs.
|
||||||
|
* Reorganized the source files.
|
||||||
|
* Reduced the footprint a little more.
|
||||||
|
|
||||||
|
- **v1.3-beta - 17 Jul 2014**
|
||||||
|
* Rewrote in plain C to reduce the footprint and memory usage. (suggested by Andrey Unis)
|
||||||
|
* Simplified the overall code base to make it more readable and maintainable.
|
||||||
|
* Changed the license from 3-clause to 2-clause BSD License.
|
||||||
|
|
||||||
|
- **v1.2 - 28 Sep 2013**
|
||||||
|
* Removed boost dependency ([jarredholman](https://github.com/jarredholman/minhook)).
|
||||||
|
* Fixed a small bug in the GetRelativeBranchDestination function ([pillbug99](http://www.codeproject.com/Messages/4058892/Small-Bug-Found.aspx)).
|
||||||
|
* Added the ```MH_RemoveHook``` function, which removes a hook created with the ```MH_CreateHook``` function.
|
||||||
|
* Added the following functions to enable or disable multiple hooks in one go: ```MH_QueueEnableHook```, ```MH_QueueDisableHook```, ```MH_ApplyQueued```. This is the preferred way of handling multiple hooks as every call to `MH_EnableHook` or `MH_DisableHook` suspends and resumes all threads.
|
||||||
|
* Made the functions ```MH_EnableHook``` and ```MH_DisableHook``` enable/disable all created hooks when the ```MH_ALL_HOOKS``` parameter is passed. This, too, is an efficient way of handling multiple hooks.
|
||||||
|
* If the target function is too small to be patched with a jump, MinHook tries to place the jump above the function. If that fails as well, the ```MH_CreateHook``` function returns ```MH_ERROR_UNSUPPORTED_FUNCTION```. This fixes an issue of hooking the LoadLibraryExW function on Windows 7 x64 ([reported by Obble](http://www.codeproject.com/Messages/4578613/Re-Bug-LoadLibraryExW-hook-fails-on-windows-2008-r.aspx)).
|
||||||
|
|
||||||
|
- **v1.1 - 26 Nov 2009**
|
||||||
|
* Changed the interface to create a hook and a trampoline function in one go to prevent the detour function from being called before the trampoline function is created. ([reported by xliqz](http://www.codeproject.com/Messages/3280374/Unsafe.aspx))
|
||||||
|
* Shortened the function names from ```MinHook_*``` to ```MH_*``` to make them handier.
|
||||||
|
|
||||||
|
- **v1.0 - 22 Nov 2009**
|
||||||
|
* Initial release.
|
||||||
|
|
||||||
|
### Building MinHook - Using vcpkg
|
||||||
|
|
||||||
|
You can download and install MinHook using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:
|
||||||
|
|
||||||
|
git clone https://github.com/microsoft/vcpkg
|
||||||
|
.\vcpkg\bootstrap-vcpkg.bat
|
||||||
|
.\vcpkg\vcpkg integrate install
|
||||||
|
.\vcpkg\vcpkg install minhook
|
||||||
|
|
||||||
|
The MinHook port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||||
|
# Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
#
|
||||||
|
# 1. Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||||
|
# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
set(MINHOOK_MAJOR_VERSION "@MINHOOK_MAJOR_VERSION@")
|
||||||
|
set(MINHOOK_MINOR_VERSION "@MINHOOK_MINOR_VERSION@")
|
||||||
|
set(MINHOOK_PATCH_VERSION "@MINHOOK_PATCH_VERSION@")
|
||||||
|
set(MINHOOK_VERSION "@MINHOOK_VERSION@")
|
||||||
|
|
||||||
|
@PACKAGE_INIT@
|
||||||
|
|
||||||
|
set(MINHOOK_FOUND ON)
|
||||||
|
|
||||||
|
set_and_check(MINHOOK_INCLUDE_DIRS "${PACKAGE_PREFIX_DIR}/include/")
|
||||||
|
set_and_check(MINHOOK_LIBRARY_DIRS "${PACKAGE_PREFIX_DIR}/lib")
|
||||||
|
|
||||||
|
include("${PACKAGE_PREFIX_DIR}/share/minhook/minhook-targets.cmake")
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
EXPORTS
|
||||||
|
MH_Initialize
|
||||||
|
MH_Uninitialize
|
||||||
|
|
||||||
|
MH_CreateHook
|
||||||
|
MH_CreateHookApi
|
||||||
|
MH_CreateHookApiEx
|
||||||
|
MH_RemoveHook
|
||||||
|
MH_EnableHook
|
||||||
|
MH_DisableHook
|
||||||
|
MH_QueueEnableHook
|
||||||
|
MH_QueueDisableHook
|
||||||
|
MH_ApplyQueued
|
||||||
|
MH_StatusToString
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
1 VERSIONINFO
|
||||||
|
FILEVERSION 1,3,4,0
|
||||||
|
PRODUCTVERSION 1,3,4,0
|
||||||
|
FILEFLAGSMASK 0x17L
|
||||||
|
#ifdef _DEBUG
|
||||||
|
FILEFLAGS 0x1L
|
||||||
|
#else
|
||||||
|
FILEFLAGS 0x0L
|
||||||
|
#endif
|
||||||
|
FILEOS 0x4L
|
||||||
|
FILETYPE 0x2L
|
||||||
|
FILESUBTYPE 0x0L
|
||||||
|
BEGIN
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
BEGIN
|
||||||
|
BLOCK "040904b0"
|
||||||
|
BEGIN
|
||||||
|
VALUE "CompanyName", "Tsuda Kageyu"
|
||||||
|
VALUE "FileDescription", "MinHook - The Minimalistic API Hook Library for x64/x86"
|
||||||
|
VALUE "FileVersion", "1.3.4.0"
|
||||||
|
VALUE "InternalName", "MinHookD"
|
||||||
|
VALUE "LegalCopyright", "Copyright (C) 2009-2017 Tsuda Kageyu. All rights reserved."
|
||||||
|
VALUE "LegalTrademarks", "Tsuda Kageyu"
|
||||||
|
VALUE "ProductName", "MinHook DLL"
|
||||||
|
VALUE "ProductVersion", "1.3.4.0"
|
||||||
|
END
|
||||||
|
END
|
||||||
|
BLOCK "VarFileInfo"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Translation", 0x409, 1200
|
||||||
|
END
|
||||||
|
END
|
||||||
+185
@@ -0,0 +1,185 @@
|
|||||||
|
/*
|
||||||
|
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||||
|
* Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||||
|
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__)
|
||||||
|
#error MinHook supports only x86 and x64 systems.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
// MinHook Error Codes.
|
||||||
|
typedef enum MH_STATUS
|
||||||
|
{
|
||||||
|
// Unknown error. Should not be returned.
|
||||||
|
MH_UNKNOWN = -1,
|
||||||
|
|
||||||
|
// Successful.
|
||||||
|
MH_OK = 0,
|
||||||
|
|
||||||
|
// MinHook is already initialized.
|
||||||
|
MH_ERROR_ALREADY_INITIALIZED,
|
||||||
|
|
||||||
|
// MinHook is not initialized yet, or already uninitialized.
|
||||||
|
MH_ERROR_NOT_INITIALIZED,
|
||||||
|
|
||||||
|
// The hook for the specified target function is already created.
|
||||||
|
MH_ERROR_ALREADY_CREATED,
|
||||||
|
|
||||||
|
// The hook for the specified target function is not created yet.
|
||||||
|
MH_ERROR_NOT_CREATED,
|
||||||
|
|
||||||
|
// The hook for the specified target function is already enabled.
|
||||||
|
MH_ERROR_ENABLED,
|
||||||
|
|
||||||
|
// The hook for the specified target function is not enabled yet, or already
|
||||||
|
// disabled.
|
||||||
|
MH_ERROR_DISABLED,
|
||||||
|
|
||||||
|
// The specified pointer is invalid. It points the address of non-allocated
|
||||||
|
// and/or non-executable region.
|
||||||
|
MH_ERROR_NOT_EXECUTABLE,
|
||||||
|
|
||||||
|
// The specified target function cannot be hooked.
|
||||||
|
MH_ERROR_UNSUPPORTED_FUNCTION,
|
||||||
|
|
||||||
|
// Failed to allocate memory.
|
||||||
|
MH_ERROR_MEMORY_ALLOC,
|
||||||
|
|
||||||
|
// Failed to change the memory protection.
|
||||||
|
MH_ERROR_MEMORY_PROTECT,
|
||||||
|
|
||||||
|
// The specified module is not loaded.
|
||||||
|
MH_ERROR_MODULE_NOT_FOUND,
|
||||||
|
|
||||||
|
// The specified function is not found.
|
||||||
|
MH_ERROR_FUNCTION_NOT_FOUND
|
||||||
|
}
|
||||||
|
MH_STATUS;
|
||||||
|
|
||||||
|
// Can be passed as a parameter to MH_EnableHook, MH_DisableHook,
|
||||||
|
// MH_QueueEnableHook or MH_QueueDisableHook.
|
||||||
|
#define MH_ALL_HOOKS NULL
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Initialize the MinHook library. You must call this function EXACTLY ONCE
|
||||||
|
// at the beginning of your program.
|
||||||
|
MH_STATUS WINAPI MH_Initialize(VOID);
|
||||||
|
|
||||||
|
// Uninitialize the MinHook library. You must call this function EXACTLY
|
||||||
|
// ONCE at the end of your program.
|
||||||
|
MH_STATUS WINAPI MH_Uninitialize(VOID);
|
||||||
|
|
||||||
|
// Creates a hook for the specified target function, in disabled state.
|
||||||
|
// Parameters:
|
||||||
|
// pTarget [in] A pointer to the target function, which will be
|
||||||
|
// overridden by the detour function.
|
||||||
|
// pDetour [in] A pointer to the detour function, which will override
|
||||||
|
// the target function.
|
||||||
|
// ppOriginal [out] A pointer to the trampoline function, which will be
|
||||||
|
// used to call the original target function.
|
||||||
|
// This parameter can be NULL.
|
||||||
|
MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal);
|
||||||
|
|
||||||
|
// Creates a hook for the specified API function, in disabled state.
|
||||||
|
// Parameters:
|
||||||
|
// pszModule [in] A pointer to the loaded module name which contains the
|
||||||
|
// target function.
|
||||||
|
// pszProcName [in] A pointer to the target function name, which will be
|
||||||
|
// overridden by the detour function.
|
||||||
|
// pDetour [in] A pointer to the detour function, which will override
|
||||||
|
// the target function.
|
||||||
|
// ppOriginal [out] A pointer to the trampoline function, which will be
|
||||||
|
// used to call the original target function.
|
||||||
|
// This parameter can be NULL.
|
||||||
|
MH_STATUS WINAPI MH_CreateHookApi(
|
||||||
|
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal);
|
||||||
|
|
||||||
|
// Creates a hook for the specified API function, in disabled state.
|
||||||
|
// Parameters:
|
||||||
|
// pszModule [in] A pointer to the loaded module name which contains the
|
||||||
|
// target function.
|
||||||
|
// pszProcName [in] A pointer to the target function name, which will be
|
||||||
|
// overridden by the detour function.
|
||||||
|
// pDetour [in] A pointer to the detour function, which will override
|
||||||
|
// the target function.
|
||||||
|
// ppOriginal [out] A pointer to the trampoline function, which will be
|
||||||
|
// used to call the original target function.
|
||||||
|
// This parameter can be NULL.
|
||||||
|
// ppTarget [out] A pointer to the target function, which will be used
|
||||||
|
// with other functions.
|
||||||
|
// This parameter can be NULL.
|
||||||
|
MH_STATUS WINAPI MH_CreateHookApiEx(
|
||||||
|
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget);
|
||||||
|
|
||||||
|
// Removes an already created hook.
|
||||||
|
// Parameters:
|
||||||
|
// pTarget [in] A pointer to the target function.
|
||||||
|
MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget);
|
||||||
|
|
||||||
|
// Enables an already created hook.
|
||||||
|
// Parameters:
|
||||||
|
// pTarget [in] A pointer to the target function.
|
||||||
|
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||||
|
// enabled in one go.
|
||||||
|
MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget);
|
||||||
|
|
||||||
|
// Disables an already created hook.
|
||||||
|
// Parameters:
|
||||||
|
// pTarget [in] A pointer to the target function.
|
||||||
|
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||||
|
// disabled in one go.
|
||||||
|
MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget);
|
||||||
|
|
||||||
|
// Queues to enable an already created hook.
|
||||||
|
// Parameters:
|
||||||
|
// pTarget [in] A pointer to the target function.
|
||||||
|
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||||
|
// queued to be enabled.
|
||||||
|
MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget);
|
||||||
|
|
||||||
|
// Queues to disable an already created hook.
|
||||||
|
// Parameters:
|
||||||
|
// pTarget [in] A pointer to the target function.
|
||||||
|
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||||
|
// queued to be disabled.
|
||||||
|
MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget);
|
||||||
|
|
||||||
|
// Applies all queued changes in one go.
|
||||||
|
MH_STATUS WINAPI MH_ApplyQueued(VOID);
|
||||||
|
|
||||||
|
// Translates the MH_STATUS to its name as a string.
|
||||||
|
const char *WINAPI MH_StatusToString(MH_STATUS status);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+312
@@ -0,0 +1,312 @@
|
|||||||
|
/*
|
||||||
|
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||||
|
* Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||||
|
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include "buffer.h"
|
||||||
|
|
||||||
|
// Size of each memory block. (= page size of VirtualAlloc)
|
||||||
|
#define MEMORY_BLOCK_SIZE 0x1000
|
||||||
|
|
||||||
|
// Max range for seeking a memory block. (= 1024MB)
|
||||||
|
#define MAX_MEMORY_RANGE 0x40000000
|
||||||
|
|
||||||
|
// Memory protection flags to check the executable address.
|
||||||
|
#define PAGE_EXECUTE_FLAGS \
|
||||||
|
(PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)
|
||||||
|
|
||||||
|
// Memory slot.
|
||||||
|
typedef struct _MEMORY_SLOT
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct _MEMORY_SLOT *pNext;
|
||||||
|
UINT8 buffer[MEMORY_SLOT_SIZE];
|
||||||
|
};
|
||||||
|
} MEMORY_SLOT, *PMEMORY_SLOT;
|
||||||
|
|
||||||
|
// Memory block info. Placed at the head of each block.
|
||||||
|
typedef struct _MEMORY_BLOCK
|
||||||
|
{
|
||||||
|
struct _MEMORY_BLOCK *pNext;
|
||||||
|
PMEMORY_SLOT pFree; // First element of the free slot list.
|
||||||
|
UINT usedCount;
|
||||||
|
} MEMORY_BLOCK, *PMEMORY_BLOCK;
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// Global Variables:
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// First element of the memory block list.
|
||||||
|
static PMEMORY_BLOCK g_pMemoryBlocks;
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
VOID InitializeBuffer(VOID)
|
||||||
|
{
|
||||||
|
// Nothing to do for now.
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
VOID UninitializeBuffer(VOID)
|
||||||
|
{
|
||||||
|
PMEMORY_BLOCK pBlock = g_pMemoryBlocks;
|
||||||
|
g_pMemoryBlocks = NULL;
|
||||||
|
|
||||||
|
while (pBlock)
|
||||||
|
{
|
||||||
|
PMEMORY_BLOCK pNext = pBlock->pNext;
|
||||||
|
VirtualFree(pBlock, 0, MEM_RELEASE);
|
||||||
|
pBlock = pNext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
#if defined(_M_X64) || defined(__x86_64__)
|
||||||
|
static LPVOID FindPrevFreeRegion(LPVOID pAddress, LPVOID pMinAddr, DWORD dwAllocationGranularity)
|
||||||
|
{
|
||||||
|
ULONG_PTR tryAddr = (ULONG_PTR)pAddress;
|
||||||
|
|
||||||
|
// Round down to the allocation granularity.
|
||||||
|
tryAddr -= tryAddr % dwAllocationGranularity;
|
||||||
|
|
||||||
|
// Start from the previous allocation granularity multiply.
|
||||||
|
tryAddr -= dwAllocationGranularity;
|
||||||
|
|
||||||
|
while (tryAddr >= (ULONG_PTR)pMinAddr)
|
||||||
|
{
|
||||||
|
MEMORY_BASIC_INFORMATION mbi;
|
||||||
|
if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (mbi.State == MEM_FREE)
|
||||||
|
return (LPVOID)tryAddr;
|
||||||
|
|
||||||
|
if ((ULONG_PTR)mbi.AllocationBase < dwAllocationGranularity)
|
||||||
|
break;
|
||||||
|
|
||||||
|
tryAddr = (ULONG_PTR)mbi.AllocationBase - dwAllocationGranularity;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
#if defined(_M_X64) || defined(__x86_64__)
|
||||||
|
static LPVOID FindNextFreeRegion(LPVOID pAddress, LPVOID pMaxAddr, DWORD dwAllocationGranularity)
|
||||||
|
{
|
||||||
|
ULONG_PTR tryAddr = (ULONG_PTR)pAddress;
|
||||||
|
|
||||||
|
// Round down to the allocation granularity.
|
||||||
|
tryAddr -= tryAddr % dwAllocationGranularity;
|
||||||
|
|
||||||
|
// Start from the next allocation granularity multiply.
|
||||||
|
tryAddr += dwAllocationGranularity;
|
||||||
|
|
||||||
|
while (tryAddr <= (ULONG_PTR)pMaxAddr)
|
||||||
|
{
|
||||||
|
MEMORY_BASIC_INFORMATION mbi;
|
||||||
|
if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (mbi.State == MEM_FREE)
|
||||||
|
return (LPVOID)tryAddr;
|
||||||
|
|
||||||
|
tryAddr = (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize;
|
||||||
|
|
||||||
|
// Round up to the next allocation granularity.
|
||||||
|
tryAddr += dwAllocationGranularity - 1;
|
||||||
|
tryAddr -= tryAddr % dwAllocationGranularity;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
static PMEMORY_BLOCK GetMemoryBlock(LPVOID pOrigin)
|
||||||
|
{
|
||||||
|
PMEMORY_BLOCK pBlock;
|
||||||
|
#if defined(_M_X64) || defined(__x86_64__)
|
||||||
|
ULONG_PTR minAddr;
|
||||||
|
ULONG_PTR maxAddr;
|
||||||
|
|
||||||
|
SYSTEM_INFO si;
|
||||||
|
GetSystemInfo(&si);
|
||||||
|
minAddr = (ULONG_PTR)si.lpMinimumApplicationAddress;
|
||||||
|
maxAddr = (ULONG_PTR)si.lpMaximumApplicationAddress;
|
||||||
|
|
||||||
|
// pOrigin ± 512MB
|
||||||
|
if ((ULONG_PTR)pOrigin > MAX_MEMORY_RANGE && minAddr < (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE)
|
||||||
|
minAddr = (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE;
|
||||||
|
|
||||||
|
if (maxAddr > (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE)
|
||||||
|
maxAddr = (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE;
|
||||||
|
|
||||||
|
// Make room for MEMORY_BLOCK_SIZE bytes.
|
||||||
|
maxAddr -= MEMORY_BLOCK_SIZE - 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Look the registered blocks for a reachable one.
|
||||||
|
for (pBlock = g_pMemoryBlocks; pBlock != NULL; pBlock = pBlock->pNext)
|
||||||
|
{
|
||||||
|
#if defined(_M_X64) || defined(__x86_64__)
|
||||||
|
// Ignore the blocks too far.
|
||||||
|
if ((ULONG_PTR)pBlock < minAddr || (ULONG_PTR)pBlock >= maxAddr)
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
// The block has at least one unused slot.
|
||||||
|
if (pBlock->pFree != NULL)
|
||||||
|
return pBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_M_X64) || defined(__x86_64__)
|
||||||
|
// Alloc a new block above if not found.
|
||||||
|
{
|
||||||
|
LPVOID pAlloc = pOrigin;
|
||||||
|
while ((ULONG_PTR)pAlloc >= minAddr)
|
||||||
|
{
|
||||||
|
pAlloc = FindPrevFreeRegion(pAlloc, (LPVOID)minAddr, si.dwAllocationGranularity);
|
||||||
|
if (pAlloc == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
pBlock = (PMEMORY_BLOCK)VirtualAlloc(
|
||||||
|
pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||||
|
if (pBlock != NULL)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alloc a new block below if not found.
|
||||||
|
if (pBlock == NULL)
|
||||||
|
{
|
||||||
|
LPVOID pAlloc = pOrigin;
|
||||||
|
while ((ULONG_PTR)pAlloc <= maxAddr)
|
||||||
|
{
|
||||||
|
pAlloc = FindNextFreeRegion(pAlloc, (LPVOID)maxAddr, si.dwAllocationGranularity);
|
||||||
|
if (pAlloc == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
pBlock = (PMEMORY_BLOCK)VirtualAlloc(
|
||||||
|
pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||||
|
if (pBlock != NULL)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// In x86 mode, a memory block can be placed anywhere.
|
||||||
|
pBlock = (PMEMORY_BLOCK)VirtualAlloc(
|
||||||
|
NULL, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (pBlock != NULL)
|
||||||
|
{
|
||||||
|
// Build a linked list of all the slots.
|
||||||
|
PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBlock + 1;
|
||||||
|
pBlock->pFree = NULL;
|
||||||
|
pBlock->usedCount = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
pSlot->pNext = pBlock->pFree;
|
||||||
|
pBlock->pFree = pSlot;
|
||||||
|
pSlot++;
|
||||||
|
} while ((ULONG_PTR)pSlot - (ULONG_PTR)pBlock <= MEMORY_BLOCK_SIZE - MEMORY_SLOT_SIZE);
|
||||||
|
|
||||||
|
pBlock->pNext = g_pMemoryBlocks;
|
||||||
|
g_pMemoryBlocks = pBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
LPVOID AllocateBuffer(LPVOID pOrigin)
|
||||||
|
{
|
||||||
|
PMEMORY_SLOT pSlot;
|
||||||
|
PMEMORY_BLOCK pBlock = GetMemoryBlock(pOrigin);
|
||||||
|
if (pBlock == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Remove an unused slot from the list.
|
||||||
|
pSlot = pBlock->pFree;
|
||||||
|
pBlock->pFree = pSlot->pNext;
|
||||||
|
pBlock->usedCount++;
|
||||||
|
#ifdef _DEBUG
|
||||||
|
// Fill the slot with INT3 for debugging.
|
||||||
|
memset(pSlot, 0xCC, sizeof(MEMORY_SLOT));
|
||||||
|
#endif
|
||||||
|
return pSlot;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
VOID FreeBuffer(LPVOID pBuffer)
|
||||||
|
{
|
||||||
|
PMEMORY_BLOCK pBlock = g_pMemoryBlocks;
|
||||||
|
PMEMORY_BLOCK pPrev = NULL;
|
||||||
|
ULONG_PTR pTargetBlock = ((ULONG_PTR)pBuffer / MEMORY_BLOCK_SIZE) * MEMORY_BLOCK_SIZE;
|
||||||
|
|
||||||
|
while (pBlock != NULL)
|
||||||
|
{
|
||||||
|
if ((ULONG_PTR)pBlock == pTargetBlock)
|
||||||
|
{
|
||||||
|
PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBuffer;
|
||||||
|
#ifdef _DEBUG
|
||||||
|
// Clear the released slot for debugging.
|
||||||
|
memset(pSlot, 0x00, sizeof(MEMORY_SLOT));
|
||||||
|
#endif
|
||||||
|
// Restore the released slot to the list.
|
||||||
|
pSlot->pNext = pBlock->pFree;
|
||||||
|
pBlock->pFree = pSlot;
|
||||||
|
pBlock->usedCount--;
|
||||||
|
|
||||||
|
// Free if unused.
|
||||||
|
if (pBlock->usedCount == 0)
|
||||||
|
{
|
||||||
|
if (pPrev)
|
||||||
|
pPrev->pNext = pBlock->pNext;
|
||||||
|
else
|
||||||
|
g_pMemoryBlocks = pBlock->pNext;
|
||||||
|
|
||||||
|
VirtualFree(pBlock, 0, MEM_RELEASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pPrev = pBlock;
|
||||||
|
pBlock = pBlock->pNext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
BOOL IsExecutableAddress(LPVOID pAddress)
|
||||||
|
{
|
||||||
|
MEMORY_BASIC_INFORMATION mi;
|
||||||
|
VirtualQuery(pAddress, &mi, sizeof(mi));
|
||||||
|
|
||||||
|
return (mi.State == MEM_COMMIT && (mi.Protect & PAGE_EXECUTE_FLAGS));
|
||||||
|
}
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||||
|
* Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||||
|
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Size of each memory slot.
|
||||||
|
#if defined(_M_X64) || defined(__x86_64__)
|
||||||
|
#define MEMORY_SLOT_SIZE 64
|
||||||
|
#else
|
||||||
|
#define MEMORY_SLOT_SIZE 32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
VOID InitializeBuffer(VOID);
|
||||||
|
VOID UninitializeBuffer(VOID);
|
||||||
|
LPVOID AllocateBuffer(LPVOID pOrigin);
|
||||||
|
VOID FreeBuffer(LPVOID pBuffer);
|
||||||
|
BOOL IsExecutableAddress(LPVOID pAddress);
|
||||||
+324
@@ -0,0 +1,324 @@
|
|||||||
|
/*
|
||||||
|
* Hacker Disassembler Engine 32 C
|
||||||
|
* Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(_M_IX86) || defined(__i386__)
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "hde32.h"
|
||||||
|
#include "table32.h"
|
||||||
|
|
||||||
|
unsigned int hde32_disasm(const void *code, hde32s *hs)
|
||||||
|
{
|
||||||
|
uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0;
|
||||||
|
uint8_t *ht = hde32_table, m_mod, m_reg, m_rm, disp_size = 0;
|
||||||
|
|
||||||
|
memset(hs, 0, sizeof(hde32s));
|
||||||
|
|
||||||
|
for (x = 16; x; x--)
|
||||||
|
switch (c = *p++) {
|
||||||
|
case 0xf3:
|
||||||
|
hs->p_rep = c;
|
||||||
|
pref |= PRE_F3;
|
||||||
|
break;
|
||||||
|
case 0xf2:
|
||||||
|
hs->p_rep = c;
|
||||||
|
pref |= PRE_F2;
|
||||||
|
break;
|
||||||
|
case 0xf0:
|
||||||
|
hs->p_lock = c;
|
||||||
|
pref |= PRE_LOCK;
|
||||||
|
break;
|
||||||
|
case 0x26: case 0x2e: case 0x36:
|
||||||
|
case 0x3e: case 0x64: case 0x65:
|
||||||
|
hs->p_seg = c;
|
||||||
|
pref |= PRE_SEG;
|
||||||
|
break;
|
||||||
|
case 0x66:
|
||||||
|
hs->p_66 = c;
|
||||||
|
pref |= PRE_66;
|
||||||
|
break;
|
||||||
|
case 0x67:
|
||||||
|
hs->p_67 = c;
|
||||||
|
pref |= PRE_67;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto pref_done;
|
||||||
|
}
|
||||||
|
pref_done:
|
||||||
|
|
||||||
|
hs->flags = (uint32_t)pref << 23;
|
||||||
|
|
||||||
|
if (!pref)
|
||||||
|
pref |= PRE_NONE;
|
||||||
|
|
||||||
|
if ((hs->opcode = c) == 0x0f) {
|
||||||
|
hs->opcode2 = c = *p++;
|
||||||
|
ht += DELTA_OPCODES;
|
||||||
|
} else if (c >= 0xa0 && c <= 0xa3) {
|
||||||
|
if (pref & PRE_67)
|
||||||
|
pref |= PRE_66;
|
||||||
|
else
|
||||||
|
pref &= ~PRE_66;
|
||||||
|
}
|
||||||
|
|
||||||
|
opcode = c;
|
||||||
|
cflags = ht[ht[opcode / 4] + (opcode % 4)];
|
||||||
|
|
||||||
|
if (cflags == C_ERROR) {
|
||||||
|
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
||||||
|
cflags = 0;
|
||||||
|
if ((opcode & -3) == 0x24)
|
||||||
|
cflags++;
|
||||||
|
}
|
||||||
|
|
||||||
|
x = 0;
|
||||||
|
if (cflags & C_GROUP) {
|
||||||
|
uint16_t t;
|
||||||
|
t = *(uint16_t *)(ht + (cflags & 0x7f));
|
||||||
|
cflags = (uint8_t)t;
|
||||||
|
x = (uint8_t)(t >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hs->opcode2) {
|
||||||
|
ht = hde32_table + DELTA_PREFIXES;
|
||||||
|
if (ht[ht[opcode / 4] + (opcode % 4)] & pref)
|
||||||
|
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cflags & C_MODRM) {
|
||||||
|
hs->flags |= F_MODRM;
|
||||||
|
hs->modrm = c = *p++;
|
||||||
|
hs->modrm_mod = m_mod = c >> 6;
|
||||||
|
hs->modrm_rm = m_rm = c & 7;
|
||||||
|
hs->modrm_reg = m_reg = (c & 0x3f) >> 3;
|
||||||
|
|
||||||
|
if (x && ((x << m_reg) & 0x80))
|
||||||
|
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
||||||
|
|
||||||
|
if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) {
|
||||||
|
uint8_t t = opcode - 0xd9;
|
||||||
|
if (m_mod == 3) {
|
||||||
|
ht = hde32_table + DELTA_FPU_MODRM + t*8;
|
||||||
|
t = ht[m_reg] << m_rm;
|
||||||
|
} else {
|
||||||
|
ht = hde32_table + DELTA_FPU_REG;
|
||||||
|
t = ht[t] << m_reg;
|
||||||
|
}
|
||||||
|
if (t & 0x80)
|
||||||
|
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pref & PRE_LOCK) {
|
||||||
|
if (m_mod == 3) {
|
||||||
|
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
||||||
|
} else {
|
||||||
|
uint8_t *table_end, op = opcode;
|
||||||
|
if (hs->opcode2) {
|
||||||
|
ht = hde32_table + DELTA_OP2_LOCK_OK;
|
||||||
|
table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;
|
||||||
|
} else {
|
||||||
|
ht = hde32_table + DELTA_OP_LOCK_OK;
|
||||||
|
table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;
|
||||||
|
op &= -2;
|
||||||
|
}
|
||||||
|
for (; ht != table_end; ht++)
|
||||||
|
if (*ht++ == op) {
|
||||||
|
if (!((*ht << m_reg) & 0x80))
|
||||||
|
goto no_lock_error;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
||||||
|
no_lock_error:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hs->opcode2) {
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x20: case 0x22:
|
||||||
|
m_mod = 3;
|
||||||
|
if (m_reg > 4 || m_reg == 1)
|
||||||
|
goto error_operand;
|
||||||
|
else
|
||||||
|
goto no_error_operand;
|
||||||
|
case 0x21: case 0x23:
|
||||||
|
m_mod = 3;
|
||||||
|
if (m_reg == 4 || m_reg == 5)
|
||||||
|
goto error_operand;
|
||||||
|
else
|
||||||
|
goto no_error_operand;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x8c:
|
||||||
|
if (m_reg > 5)
|
||||||
|
goto error_operand;
|
||||||
|
else
|
||||||
|
goto no_error_operand;
|
||||||
|
case 0x8e:
|
||||||
|
if (m_reg == 1 || m_reg > 5)
|
||||||
|
goto error_operand;
|
||||||
|
else
|
||||||
|
goto no_error_operand;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_mod == 3) {
|
||||||
|
uint8_t *table_end;
|
||||||
|
if (hs->opcode2) {
|
||||||
|
ht = hde32_table + DELTA_OP2_ONLY_MEM;
|
||||||
|
table_end = ht + sizeof(hde32_table) - DELTA_OP2_ONLY_MEM;
|
||||||
|
} else {
|
||||||
|
ht = hde32_table + DELTA_OP_ONLY_MEM;
|
||||||
|
table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;
|
||||||
|
}
|
||||||
|
for (; ht != table_end; ht += 2)
|
||||||
|
if (*ht++ == opcode) {
|
||||||
|
if ((*ht++ & pref) && !((*ht << m_reg) & 0x80))
|
||||||
|
goto error_operand;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
goto no_error_operand;
|
||||||
|
} else if (hs->opcode2) {
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x50: case 0xd7: case 0xf7:
|
||||||
|
if (pref & (PRE_NONE | PRE_66))
|
||||||
|
goto error_operand;
|
||||||
|
break;
|
||||||
|
case 0xd6:
|
||||||
|
if (pref & (PRE_F2 | PRE_F3))
|
||||||
|
goto error_operand;
|
||||||
|
break;
|
||||||
|
case 0xc5:
|
||||||
|
goto error_operand;
|
||||||
|
}
|
||||||
|
goto no_error_operand;
|
||||||
|
} else
|
||||||
|
goto no_error_operand;
|
||||||
|
|
||||||
|
error_operand:
|
||||||
|
hs->flags |= F_ERROR | F_ERROR_OPERAND;
|
||||||
|
no_error_operand:
|
||||||
|
|
||||||
|
c = *p++;
|
||||||
|
if (m_reg <= 1) {
|
||||||
|
if (opcode == 0xf6)
|
||||||
|
cflags |= C_IMM8;
|
||||||
|
else if (opcode == 0xf7)
|
||||||
|
cflags |= C_IMM_P66;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (m_mod) {
|
||||||
|
case 0:
|
||||||
|
if (pref & PRE_67) {
|
||||||
|
if (m_rm == 6)
|
||||||
|
disp_size = 2;
|
||||||
|
} else
|
||||||
|
if (m_rm == 5)
|
||||||
|
disp_size = 4;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
disp_size = 1;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
disp_size = 2;
|
||||||
|
if (!(pref & PRE_67))
|
||||||
|
disp_size <<= 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_mod != 3 && m_rm == 4 && !(pref & PRE_67)) {
|
||||||
|
hs->flags |= F_SIB;
|
||||||
|
p++;
|
||||||
|
hs->sib = c;
|
||||||
|
hs->sib_scale = c >> 6;
|
||||||
|
hs->sib_index = (c & 0x3f) >> 3;
|
||||||
|
if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))
|
||||||
|
disp_size = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
p--;
|
||||||
|
switch (disp_size) {
|
||||||
|
case 1:
|
||||||
|
hs->flags |= F_DISP8;
|
||||||
|
hs->disp.disp8 = *p;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
hs->flags |= F_DISP16;
|
||||||
|
hs->disp.disp16 = *(uint16_t *)p;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
hs->flags |= F_DISP32;
|
||||||
|
hs->disp.disp32 = *(uint32_t *)p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p += disp_size;
|
||||||
|
} else if (pref & PRE_LOCK)
|
||||||
|
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
||||||
|
|
||||||
|
if (cflags & C_IMM_P66) {
|
||||||
|
if (cflags & C_REL32) {
|
||||||
|
if (pref & PRE_66) {
|
||||||
|
hs->flags |= F_IMM16 | F_RELATIVE;
|
||||||
|
hs->imm.imm16 = *(uint16_t *)p;
|
||||||
|
p += 2;
|
||||||
|
goto disasm_done;
|
||||||
|
}
|
||||||
|
goto rel32_ok;
|
||||||
|
}
|
||||||
|
if (pref & PRE_66) {
|
||||||
|
hs->flags |= F_IMM16;
|
||||||
|
hs->imm.imm16 = *(uint16_t *)p;
|
||||||
|
p += 2;
|
||||||
|
} else {
|
||||||
|
hs->flags |= F_IMM32;
|
||||||
|
hs->imm.imm32 = *(uint32_t *)p;
|
||||||
|
p += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cflags & C_IMM16) {
|
||||||
|
if (hs->flags & F_IMM32) {
|
||||||
|
hs->flags |= F_IMM16;
|
||||||
|
hs->disp.disp16 = *(uint16_t *)p;
|
||||||
|
} else if (hs->flags & F_IMM16) {
|
||||||
|
hs->flags |= F_2IMM16;
|
||||||
|
hs->disp.disp16 = *(uint16_t *)p;
|
||||||
|
} else {
|
||||||
|
hs->flags |= F_IMM16;
|
||||||
|
hs->imm.imm16 = *(uint16_t *)p;
|
||||||
|
}
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
if (cflags & C_IMM8) {
|
||||||
|
hs->flags |= F_IMM8;
|
||||||
|
hs->imm.imm8 = *p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cflags & C_REL32) {
|
||||||
|
rel32_ok:
|
||||||
|
hs->flags |= F_IMM32 | F_RELATIVE;
|
||||||
|
hs->imm.imm32 = *(uint32_t *)p;
|
||||||
|
p += 4;
|
||||||
|
} else if (cflags & C_REL8) {
|
||||||
|
hs->flags |= F_IMM8 | F_RELATIVE;
|
||||||
|
hs->imm.imm8 = *p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
disasm_done:
|
||||||
|
|
||||||
|
if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) {
|
||||||
|
hs->flags |= F_ERROR | F_ERROR_LENGTH;
|
||||||
|
hs->len = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (unsigned int)hs->len;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // defined(_M_IX86) || defined(__i386__)
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user